Merge branch 'ecc-devel-mpg' into development
diff --git a/ChangeLog b/ChangeLog
index c1b6c88..59a43dc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,63 @@
 PolarSSL ChangeLog
 
-= Version Master
+= Development
+Changes
+   * Introduced separate SSL Ciphersuites module that is based on
+     Cipher and MD information
+   * Internals for SSL module adapted to have separate IV pointer that is
+     dynamically set (Better support for hardware acceleration)
+
+= Version 1.2.6 released 2013-03-11
+Bugfix
+   * Fixed memory leak in ssl_free() and ssl_reset() for active session
+   * Corrected GCM counter incrementation to use only 32-bits instead of
+     128-bits (found by Yawning Angel)
+   * Fixes for 64-bit compilation with MS Visual Studio
+   * Fixed net_bind() for specified IP addresses on little endian systems
+   * Fixed assembly code for ARM (Thumb and regular) for some compilers
+
+Changes
+   * Internally split up rsa_pkcs1_encrypt(), rsa_pkcs1_decrypt(),
+     rsa_pkcs1_sign() and rsa_pkcs1_verify() to separate PKCS#1 v1.5 and
+     PKCS#1 v2.1 functions
+   * Added support for custom labels when using rsa_rsaes_oaep_encrypt()
+     or rsa_rsaes_oaep_decrypt()
+   * Re-added handling for SSLv2 Client Hello when the define
+     POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO is set
+   * The SSL session cache module (ssl_cache) now also retains peer_cert
+     information (not the entire chain)
+
+Security
+   * Removed further timing differences during SSL message decryption in
+     ssl_decrypt_buf()
+   * Removed timing differences due to bad padding from
+     rsa_rsaes_pkcs1_v15_decrypt() and rsa_pkcs1_decrypt() for PKCS#1 v1.5
+     operations
+
+= Version 1.2.5 released 2013-02-02
+Changes
+   * Allow enabling of dummy error_strerror() to support some use-cases
+   * Debug messages about padding errors during SSL message decryption are
+     disabled by default and can be enabled with POLARSSL_SSL_DEBUG_ALL 
+   * Sending of security-relevant alert messages that do not break
+     interoperability can be switched on/off with the flag
+     POLARSSL_SSL_ALL_ALERT_MESSAGES
+
+Security
+   * Removed timing differences during SSL message decryption in
+     ssl_decrypt_buf() due to badly formatted padding
+
+= Version 1.2.4 released 2013-01-25
+Changes
+   * More advanced SSL ciphersuite representation and moved to more dynamic
+     SSL core
+   * Added ssl_handshake_step() to allow single stepping the handshake process
+
 Bugfix
    * Memory leak when using RSA_PKCS_V21 operations fixed
    * Handle future version properly in ssl_write_certificate_request()
+   * Correctly handle CertificateRequest message in client for <= TLS 1.1
+     without DN list
 
 = Version 1.2.3 released 2012-11-26
 Bugfix
@@ -101,6 +155,30 @@
    * Fixed potential memory zeroization on miscrafted RSA key (found by Eloi
      Vanderbeken)
 
+= Version 1.1.5 released on 2013-01-16
+Bugfix
+   * Fixed MPI assembly for SPARC64 platform
+   * Handle existence of OpenSSL Trust Extensions at end of X.509 DER blob
+   * mpi_add_abs() now correctly handles adding short numbers to long numbers
+     with carry rollover
+   * Moved mpi_inv_mod() outside POLARSSL_GENPRIME
+   * Prevent reading over buffer boundaries on X509 certificate parsing
+   * mpi_exp_mod() now correctly handles negative base numbers (Closes ticket
+     #52)
+   * Fixed possible segfault in mpi_shift_r() (found by Manuel
+     Pégourié-Gonnard)
+   * Allow R and A to point to same mpi in mpi_div_mpi (found by Manuel
+     Pégourié-Gonnard)
+   * Added max length check for rsa_pkcs1_sign with PKCS#1 v2.1
+   * Memory leak when using RSA_PKCS_V21 operations fixed
+   * Handle encryption with private key and decryption with public key as per
+     RFC 2313
+   * Fixes for MSVC6
+
+Security
+   * Fixed potential memory zeroization on miscrafted RSA key (found by Eloi
+     Vanderbeken)
+
 = Version 1.1.4 released on 2012-05-31
 Bugfix
    * Correctly handle empty SSL/TLS packets (Found by James Yonan)
@@ -164,12 +242,12 @@
      management (Closes ticket #44)
    * Changed the used random function pointer to more flexible format. Renamed
      havege_rand() to havege_random() to prevent mistakes. Lots of changes as
-	 a consequence in library code and programs
+     a consequence in library code and programs
    * Moved all examples programs to use the new entropy and CTR_DRBG
    * Added permissive certificate parsing to x509parse_crt() and
      x509parse_crtfile(). With permissive parsing the parsing does not stop on
-	 encountering a parse-error. Beware that the meaning of return values has
-	 changed!
+     encountering a parse-error. Beware that the meaning of return values has
+     changed!
    * All error codes are now negative. Even on mermory failures and IO errors.
 
 Bugfix
@@ -205,7 +283,7 @@
 Features
    * Added additional Cipher Block Modes to symmetric ciphers
      (AES CTR, Camellia CTR, XTEA CBC) including the option to
-	 enable and disable individual modes when needed
+     enable and disable individual modes when needed
    * Functions requiring File System functions can now be disabled
      by undefining POLARSSL_FS_IO
    * A error_strerror function() has been added to translate between
@@ -217,22 +295,22 @@
 Changes
    * Major argument / variable rewrite. Introduced use of size_t
      instead of int for buffer lengths and loop variables for
-	 better unsigned / signed use. Renamed internal bigint types
-	 t_int and t_dbl to t_uint and t_udbl in the process
+     better unsigned / signed use. Renamed internal bigint types
+     t_int and t_dbl to t_uint and t_udbl in the process
    * mpi_init() and mpi_free() now only accept a single MPI
      argument and do not accept variable argument lists anymore.
    * The error codes have been remapped and combining error codes
      is now done with a PLUS instead of an OR as error codes
-	 used are negative.
+     used are negative.
    * Changed behaviour of net_read(), ssl_fetch_input() and ssl_recv().
      net_recv() now returns 0 on EOF instead of
-	 POLARSSL_ERR_NET_CONN_RESET. ssl_fetch_input() returns
-	 POLARSSL_ERR_SSL_CONN_EOF on an EOF from its f_recv() function.
-	 ssl_read() returns 0 if a POLARSSL_ERR_SSL_CONN_EOF is received
-	 after the handshake.
+     POLARSSL_ERR_NET_CONN_RESET. ssl_fetch_input() returns
+     POLARSSL_ERR_SSL_CONN_EOF on an EOF from its f_recv() function.
+     ssl_read() returns 0 if a POLARSSL_ERR_SSL_CONN_EOF is received
+     after the handshake.
    * Network functions now return POLARSSL_ERR_NET_WANT_READ or
      POLARSSL_ERR_NET_WANT_WRITE instead of the ambiguous
-	 POLARSSL_ERR_NET_TRY_AGAIN
+     POLARSSL_ERR_NET_TRY_AGAIN
 
 = Version 0.99-pre4 released on 2011-04-01
 Features
@@ -248,12 +326,12 @@
      displays actual bit size of the value.
    * x509parse_key() (and as a consequence x509parse_keyfile()) 
      does not zeroize memory in advance anymore. Use rsa_init()
-	 before parsing a key or keyfile!
+     before parsing a key or keyfile!
 
 Bugfix
    * Debug output of MPI's now the same independent of underlying
      platform (32-bit / 64-bit) (Fixes ticket #19, found by Mads
-	 Kiilerich and Mihai Militaru)
+     Kiilerich and Mihai Militaru)
    * Fixed bug in ssl_write() when flushing old data (Fixed ticket
      #18, found by Nikolay Epifanov)
    * Fixed proper handling of RSASSA-PSS verification with variable
@@ -270,7 +348,7 @@
 Changes
    * Parsing of PEM files moved to separate module (Fixes 
      ticket #13). Also possible to remove PEM support for
-	 systems only using DER encoding
+     systems only using DER encoding
 
 Bugfixes
    * Corrected parsing of UTCTime dates before 1990 and
@@ -282,12 +360,12 @@
    * Replaced the expired test certificates
    * Do not bail out if no client certificate specified. Try
      to negotiate anonymous connection (Fixes ticket #12,
-	 found by Boris Krasnovskiy)
+     found by Boris Krasnovskiy)
 
 Security fixes
    * Fixed a possible Man-in-the-Middle attack on the
      Diffie Hellman key exchange (thanks to Larry Highsmith,
-	 Subreption LLC)
+     Subreption LLC)
 
 = Version 0.99-pre1 released on 2011-01-30
 Features
@@ -315,9 +393,9 @@
      the existing date check
    * The ciphers member of ssl_context and the cipher member
      of ssl_session have been renamed to ciphersuites and
-	 ciphersuite respectively. This clarifies the difference
-	 with the generic cipher layer and is better naming
-	 altogether
+     ciphersuite respectively. This clarifies the difference
+     with the generic cipher layer and is better naming
+     altogether
 
 = Version 0.14.0 released on 2010-08-16
 Features
@@ -331,8 +409,8 @@
    * Made Makefile cleaner
    * Removed dependency on rand() in rsa_pkcs1_encrypt().
      Now using random fuction provided to function and
-	 changed the prototype of rsa_pkcs1_encrypt(),
-	 rsa_init() and rsa_gen_key().
+     changed the prototype of rsa_pkcs1_encrypt(),
+     rsa_init() and rsa_gen_key().
    * Some SSL defines were renamed in order to avoid
      future confusion
 
diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h
index 9824692..dc98951 100644
--- a/doxygen/input/doc_mainpage.h
+++ b/doxygen/input/doc_mainpage.h
@@ -4,7 +4,7 @@
  */
 
 /**
- * @mainpage PolarSSL v1.2.3 source code documentation
+ * @mainpage PolarSSL v1.2.6 source code documentation
  * 
  * This documentation describes the internal structure of PolarSSL.  It was
  * automatically generated from specially formatted comment blocks in
diff --git a/doxygen/polarssl.doxyfile b/doxygen/polarssl.doxyfile
index cd5eef3..5fbc133 100644
--- a/doxygen/polarssl.doxyfile
+++ b/doxygen/polarssl.doxyfile
@@ -25,7 +25,7 @@
 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded
 # by quotes) that should identify the project.
 
-PROJECT_NAME           = "PolarSSL v1.2.3"
+PROJECT_NAME           = "PolarSSL v1.2.6"
 
 # The PROJECT_NUMBER tag can be used to enter a project or revision number.
 # This could be handy for archiving the generated documentation or
diff --git a/include/polarssl/base64.h b/include/polarssl/base64.h
index 883215d..fb0d753 100644
--- a/include/polarssl/base64.h
+++ b/include/polarssl/base64.h
@@ -63,8 +63,8 @@
  * \param slen     amount of data to be decoded
  *
  * \return         0 if successful, POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL, or
- *                 POLARSSL_ERR_BASE64_INVALID_DATA if the input data is not
- *                 correct. *dlen is always updated to reflect the amount
+ *                 POLARSSL_ERR_BASE64_INVALID_CHARACTER if the input data is
+ *                 not correct. *dlen is always updated to reflect the amount
  *                 of data that has (or would have) been written.
  *
  * \note           Call this function with *dlen = 0 to obtain the
diff --git a/include/polarssl/bignum.h b/include/polarssl/bignum.h
index ce29ca3..e02db3f 100644
--- a/include/polarssl/bignum.h
+++ b/include/polarssl/bignum.h
@@ -42,6 +42,7 @@
 typedef UINT16 uint16_t;
 #endif
 typedef  INT32  int32_t;
+typedef  INT64  int64_t;
 typedef UINT32 uint32_t;
 typedef UINT64 uint64_t;
 #else
@@ -77,7 +78,7 @@
 
 /*
  * Maximum size of MPIs allowed in bits and bytes for user-MPIs.
- * ( Default: 512 bytes => 4096 bits, Maximum: 1024 bytes => 8192 bits )
+ * ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits )
  *
  * Note: Calculations can results temporarily in larger MPIs. So the number
  * of limbs required (POLARSSL_MPI_MAX_LIMBS) is higher.
@@ -122,7 +123,7 @@
 typedef uint32_t t_udbl;
 #define POLARSSL_HAVE_UDBL
 #else
-  #if ( defined(__MSC_VER) && defined(_M_AMD64) )
+  #if ( defined(_MSC_VER) && defined(_M_AMD64) )
     typedef  int64_t t_sint;
     typedef uint64_t t_uint;
   #else
diff --git a/include/polarssl/bn_mul.h b/include/polarssl/bn_mul.h
index ae6e2d6..6bb511d 100644
--- a/include/polarssl/bn_mul.h
+++ b/include/polarssl/bn_mul.h
@@ -551,75 +551,97 @@
 #if defined(__thumb__)
 
 #define MULADDC_INIT                            \
-    asm( "ldr    r0, %0         " :: "m" (s));  \
-    asm( "ldr    r1, %0         " :: "m" (d));  \
-    asm( "ldr    r2, %0         " :: "m" (c));  \
-    asm( "ldr    r3, %0         " :: "m" (b));  \
-    asm( "lsr    r7, r3, #16    "           );  \
-    asm( "mov    r9, r7         "           );  \
-    asm( "lsl    r7, r3, #16    "           );  \
-    asm( "lsr    r7, r7, #16    "           );  \
-    asm( "mov    r8, r7         "           );
+    asm(                                        \
+         "                                      \
+            ldr    r0, %3;                      \
+            ldr    r1, %4;                      \
+            ldr    r2, %5;                      \
+            ldr    r3, %6;                      \
+            lsr    r7, r3, #16;                 \
+            mov    r9, r7;                      \
+            lsl    r7, r3, #16;                 \
+            lsr    r7, r7, #16;                 \
+            mov    r8, r7;                      \
+         "
 
 #define MULADDC_CORE                            \
-    asm( "ldmia  r0!, {r6}      " );            \
-    asm( "lsr    r7, r6, #16    " );            \
-    asm( "lsl    r6, r6, #16    " );            \
-    asm( "lsr    r6, r6, #16    " );            \
-    asm( "mov    r4, r8         " );            \
-    asm( "mul    r4, r6         " );            \
-    asm( "mov    r3, r9         " );            \
-    asm( "mul    r6, r3         " );            \
-    asm( "mov    r5, r9         " );            \
-    asm( "mul    r5, r7         " );            \
-    asm( "mov    r3, r8         " );            \
-    asm( "mul    r7, r3         " );            \
-    asm( "lsr    r3, r6, #16    " );            \
-    asm( "add    r5, r5, r3     " );            \
-    asm( "lsr    r3, r7, #16    " );            \
-    asm( "add    r5, r5, r3     " );            \
-    asm( "add    r4, r4, r2     " );            \
-    asm( "mov    r2, #0         " );            \
-    asm( "adc    r5, r2         " );            \
-    asm( "lsl    r3, r6, #16    " );            \
-    asm( "add    r4, r4, r3     " );            \
-    asm( "adc    r5, r2         " );            \
-    asm( "lsl    r3, r7, #16    " );            \
-    asm( "add    r4, r4, r3     " );            \
-    asm( "adc    r5, r2         " );            \
-    asm( "ldr    r3, [r1]       " );            \
-    asm( "add    r4, r4, r3     " );            \
-    asm( "adc    r2, r5         " );            \
-    asm( "stmia  r1!, {r4}      " );
+         "                                      \
+            ldmia  r0!, {r6};                   \
+            lsr    r7, r6, #16;                 \
+            lsl    r6, r6, #16;                 \
+            lsr    r6, r6, #16;                 \
+            mov    r4, r8;                      \
+            mul    r4, r6;                      \
+            mov    r3, r9;                      \
+            mul    r6, r3;                      \
+            mov    r5, r9;                      \
+            mul    r5, r7;                      \
+            mov    r3, r8;                      \
+            mul    r7, r3;                      \
+            lsr    r3, r6, #16;                 \
+            add    r5, r5, r3;                  \
+            lsr    r3, r7, #16;                 \
+            add    r5, r5, r3;                  \
+            add    r4, r4, r2;                  \
+            mov    r2, #0;                      \
+            adc    r5, r2;                      \
+            lsl    r3, r6, #16;                 \
+            add    r4, r4, r3;                  \
+            adc    r5, r2;                      \
+            lsl    r3, r7, #16;                 \
+            add    r4, r4, r3;                  \
+            adc    r5, r2;                      \
+            ldr    r3, [r1];                    \
+            add    r4, r4, r3;                  \
+            adc    r2, r5;                      \
+            stmia  r1!, {r4};                   \
+         "
 
 #define MULADDC_STOP                            \
-    asm( "str    r2, %0         " : "=m" (c));  \
-    asm( "str    r1, %0         " : "=m" (d));  \
-    asm( "str    r0, %0         " : "=m" (s) :: \
-    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+         "                                      \
+            str    r2, %0;                      \
+            str    r1, %1;                      \
+            str    r0, %2;                      \
+         "                                      \
+         : "=m" (c),  "=m" (d), "=m" (s)        \
+         : "m" (s), "m" (d), "m" (c), "m" (b)   \
+         : "r0", "r1", "r2", "r3", "r4", "r5",  \
+           "r6", "r7", "r8", "r9"               \
+         );
 
 #else
 
 #define MULADDC_INIT                            \
-    asm( "ldr    r0, %0         " :: "m" (s));  \
-    asm( "ldr    r1, %0         " :: "m" (d));  \
-    asm( "ldr    r2, %0         " :: "m" (c));  \
-    asm( "ldr    r3, %0         " :: "m" (b));
+    asm(                                        \
+         "                                     \
+            ldr    r0, %3;                      \
+            ldr    r1, %4;                      \
+            ldr    r2, %5;                      \
+            ldr    r3, %6;                      \
+         "
 
 #define MULADDC_CORE                            \
-    asm( "ldr    r4, [r0], #4   " );            \
-    asm( "mov    r5, #0         " );            \
-    asm( "ldr    r6, [r1]       " );            \
-    asm( "umlal  r2, r5, r3, r4 " );            \
-    asm( "adds   r7, r6, r2     " );            \
-    asm( "adc    r2, r5, #0     " );            \
-    asm( "str    r7, [r1], #4   " );
+         "                                      \
+            ldr    r4, [r0], #4;                \
+            mov    r5, #0;                      \
+            ldr    r6, [r1];                    \
+            umlal  r2, r5, r3, r4;              \
+            adds   r7, r6, r2;                  \
+            adc    r2, r5, #0;                  \
+            str    r7, [r1], #4;                \
+         "
 
 #define MULADDC_STOP                            \
-    asm( "str    r2, %0         " : "=m" (c));  \
-    asm( "str    r1, %0         " : "=m" (d));  \
-    asm( "str    r0, %0         " : "=m" (s) :: \
-    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" );
+         "                                      \
+            str    r2, %0;                      \
+            str    r1, %1;                      \
+            str    r0, %2;                      \
+         "                                      \
+         : "=m" (c),  "=m" (d), "=m" (s)        \
+         : "m" (s), "m" (d), "m" (c), "m" (b)   \
+         : "r0", "r1", "r2", "r3", "r4", "r5",  \
+           "r6", "r7"                           \
+         );
 
 #endif /* Thumb */
 
diff --git a/include/polarssl/cipher.h b/include/polarssl/cipher.h
index 8224128..2ffdf66 100644
--- a/include/polarssl/cipher.h
+++ b/include/polarssl/cipher.h
@@ -5,7 +5,7 @@
  *
  * \author Adriaan de Jong <dejong@fox-it.com>
  *
- *  Copyright (C) 2006-2012, Brainspark B.V.
+ *  Copyright (C) 2006-2013, Brainspark B.V.
  *
  *  This file is part of PolarSSL (http://www.polarssl.org)
  *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
@@ -54,6 +54,7 @@
     POLARSSL_CIPHER_ID_3DES,
     POLARSSL_CIPHER_ID_CAMELLIA,
     POLARSSL_CIPHER_ID_BLOWFISH,
+    POLARSSL_CIPHER_ID_ARC4,
 } cipher_id_t;
 
 typedef enum {
@@ -68,6 +69,8 @@
     POLARSSL_CIPHER_AES_128_CTR,
     POLARSSL_CIPHER_AES_192_CTR,
     POLARSSL_CIPHER_AES_256_CTR,
+    POLARSSL_CIPHER_AES_128_GCM,
+    POLARSSL_CIPHER_AES_256_GCM,
     POLARSSL_CIPHER_CAMELLIA_128_CBC,
     POLARSSL_CIPHER_CAMELLIA_192_CBC,
     POLARSSL_CIPHER_CAMELLIA_256_CBC,
@@ -83,6 +86,7 @@
     POLARSSL_CIPHER_BLOWFISH_CBC,
     POLARSSL_CIPHER_BLOWFISH_CFB64,
     POLARSSL_CIPHER_BLOWFISH_CTR,
+    POLARSSL_CIPHER_ARC4_128,
 } cipher_type_t;
 
 typedef enum {
@@ -92,6 +96,8 @@
     POLARSSL_MODE_CFB,
     POLARSSL_MODE_OFB,
     POLARSSL_MODE_CTR,
+    POLARSSL_MODE_GCM,
+    POLARSSL_MODE_STREAM,
 } cipher_mode_t;
 
 typedef enum {
@@ -351,10 +357,10 @@
  */
 static inline int cipher_get_key_size ( const cipher_context_t *ctx )
 {
-    if( NULL == ctx )
+    if( NULL == ctx || NULL == ctx->cipher_info )
         return POLARSSL_KEY_LENGTH_NONE;
 
-    return ctx->key_length;
+    return ctx->cipher_info->key_length;
 }
 
 /**
@@ -448,7 +454,6 @@
  */
 int cipher_finish( cipher_context_t *ctx, unsigned char *output, size_t *olen);
 
-
 /**
  * \brief          Checkup routine
  *
diff --git a/include/polarssl/cipher_wrap.h b/include/polarssl/cipher_wrap.h
index 4abbc4e..4dabb44 100644
--- a/include/polarssl/cipher_wrap.h
+++ b/include/polarssl/cipher_wrap.h
@@ -5,7 +5,7 @@
  *
  * \author Adriaan de Jong <dejong@fox-it.com>
  *
- *  Copyright (C) 2006-2012, Brainspark B.V.
+ *  Copyright (C) 2006-2013, Brainspark B.V.
  *
  *  This file is part of PolarSSL (http://www.polarssl.org)
  *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
@@ -54,6 +54,11 @@
 extern const cipher_info_t aes_256_ctr_info;
 #endif /* POLARSSL_CIPHER_MODE_CTR */
 
+#if defined(POLARSSL_GCM_C)
+extern const cipher_info_t aes_128_gcm_info;
+extern const cipher_info_t aes_256_gcm_info;
+#endif /* POLARSSL_GCM_C */
+
 #endif /* defined(POLARSSL_AES_C) */
 
 #if defined(POLARSSL_CAMELLIA_C)
@@ -96,6 +101,10 @@
 #endif /* POLARSSL_CIPHER_MODE_CTR */
 #endif /* defined(POLARSSL_BLOWFISH_C) */
 
+#if defined(POLARSSL_ARC4_C)
+extern const cipher_info_t arc4_128_info;
+#endif /* defined(POLARSSL_ARC4_C) */
+
 #if defined(POLARSSL_CIPHER_NULL_CIPHER)
 extern const cipher_info_t null_cipher_info;
 #endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */
diff --git a/include/polarssl/config.h b/include/polarssl/config.h
index fcdce0b..7640a96 100644
--- a/include/polarssl/config.h
+++ b/include/polarssl/config.h
@@ -161,6 +161,17 @@
  */
 
 /**
+ * \def POLARSSL_ERROR_STRERROR_DUMMY
+ *
+ * Enable a dummy error function to make use of error_strerror() in
+ * third party libraries easier.
+ *
+ * Disable if you run into name conflicts and want to really remove the
+ * error_strerror()
+ */
+#define POLARSSL_ERROR_STRERROR_DUMMY
+
+/**
  * \def POLARSSL_GENPRIME
  *
  * Requires: POLARSSL_BIGNUM_C, POLARSSL_RSA_C
@@ -228,6 +239,36 @@
 #define POLARSSL_SELF_TEST
 
 /**
+ * \def POLARSSL_SSL_ALL_ALERT_MESSAGES
+ *
+ * Enable sending of alert messages in case of encountered errors as per RFC.
+ * If you choose not to send the alert messages, PolarSSL can still communicate
+ * with other servers, only debugging of failures is harder.
+ *
+ * The advantage of not sending alert messages, is that no information is given
+ * about reasons for failures thus preventing adversaries of gaining intel.
+ *
+ * Enable sending of all alert messages
+ */
+#define POLARSSL_SSL_ALERT_MESSAGES
+
+/**
+ * \def POLARSSL_SSL_DEBUG_ALL
+ *
+ * Enable the debug messages in SSL module for all issues.
+ * Debug messages have been disabled in some places to prevent timing
+ * attacks due to (unbalanced) debugging function calls.
+ *
+ * If you need all error reporting you should enable this during debugging,
+ * but remove this for production servers that should log as well.
+ *
+ * Uncomment this macro to report all debug messages on errors introducing
+ * a timing side-channel.
+ *
+#define POLARSSL_SSL_DEBUG_ALL
+ */
+
+/**
  * \def POLARSSL_SSL_HW_RECORD_ACCEL
  *
  * Enable hooking functions in SSL module for hardware acceleration of
@@ -238,6 +279,16 @@
  */
 
 /**
+ * \def POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO
+ *
+ * Enable support for receiving and parsing SSLv2 Client Hello messages for the
+ * SSL Server module (POLARSSL_SSL_SRV_C)
+ *
+ * Comment this macro to disable support for SSLv2 Client Hello messages.
+ */
+#define POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO
+
+/**
  * \def POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
  *
  * If set, the X509 parser will not break-off when parsing an X509 certificate
@@ -294,6 +345,8 @@
  *      TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
  *      TLS_RSA_WITH_AES_128_GCM_SHA256
  *      TLS_RSA_WITH_AES_256_GCM_SHA384
+ *
+ * PEM uses AES for decrypting encrypted keys.
  */
 #define POLARSSL_AES_C
 
@@ -445,12 +498,15 @@
  * Enable the DES block cipher.
  *
  * Module:  library/des.c
- * Caller:  library/ssl_tls.c
+ * Caller:  library/pem.c
+ *          library/ssl_tls.c
  *
  * This module enables the following ciphersuites (if other requisites are
  * enabled as well):
  *      TLS_RSA_WITH_3DES_EDE_CBC_SHA
  *      TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
+ *
+ * PEM uses DES/3DES for decrypting encrypted keys.
  */
 #define POLARSSL_DES_C
 
@@ -617,10 +673,12 @@
  * Enable the MD5 hash algorithm
  *
  * Module:  library/md5.c
- * Caller:  library/ssl_tls.c
+ * Caller:  library/pem.c
+ *          library/ssl_tls.c
  *          library/x509parse.c
  *
  * This module is required for SSL/TLS and X.509.
+ * PEM uses MD5 for decrypting encrypted keys.
  */
 #define POLARSSL_MD5_C
 
diff --git a/include/polarssl/md.h b/include/polarssl/md.h
index 88596cb..b81ebf1 100644
--- a/include/polarssl/md.h
+++ b/include/polarssl/md.h
@@ -111,6 +111,8 @@
     /** Free the given context */
     void (*ctx_free_func)( void *ctx );
 
+    /** Internal use only */
+    void (*process_func)( void *ctx, const unsigned char *input );
 } md_info_t;
 
 /**
@@ -347,6 +349,9 @@
                 const unsigned char *input, size_t ilen,
                 unsigned char *output );
 
+/* Internal use */
+int md_process( md_context_t *ctx, const unsigned char *data );
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/polarssl/md2.h b/include/polarssl/md2.h
index 1f60470..02a0a10 100644
--- a/include/polarssl/md2.h
+++ b/include/polarssl/md2.h
@@ -146,6 +146,9 @@
  */
 int md2_self_test( int verbose );
 
+/* Internal use */
+void md2_process( md2_context *ctx );
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/polarssl/md4.h b/include/polarssl/md4.h
index 641edf1..4791fb1 100644
--- a/include/polarssl/md4.h
+++ b/include/polarssl/md4.h
@@ -152,6 +152,9 @@
  */
 int md4_self_test( int verbose );
 
+/* Internal use */
+void md4_process( md4_context *ctx, const unsigned char data[64] );
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/polarssl/md5.h b/include/polarssl/md5.h
index 2e97c2b..b0611e2 100644
--- a/include/polarssl/md5.h
+++ b/include/polarssl/md5.h
@@ -154,6 +154,9 @@
  */
 int md5_self_test( int verbose );
 
+/* Internal use */
+void md5_process( md5_context *ctx, const unsigned char data[64] );
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/polarssl/rsa.h b/include/polarssl/rsa.h
index 3a822cb..f9a0220 100644
--- a/include/polarssl/rsa.h
+++ b/include/polarssl/rsa.h
@@ -255,7 +255,9 @@
                  unsigned char *output );
 
 /**
- * \brief          Add the message padding, then do an RSA operation
+ * \brief          Generic wrapper to perform a PKCS#1 encryption using the
+ *                 mode from the context. Add the message padding, then do an
+ *                 RSA operation.
  *
  * \param ctx      RSA context
  * \param f_rng    RNG function (Needed for padding and PKCS#1 v2.1 encoding)
@@ -278,7 +280,59 @@
                        unsigned char *output );
 
 /**
- * \brief          Do an RSA operation, then remove the message padding
+ * \brief          Perform a PKCS#1 v1.5 encryption (RSAES-PKCS1-v1_5-ENCRYPT)
+ *
+ * \param ctx      RSA context
+ * \param f_rng    RNG function (Needed for padding)
+ * \param p_rng    RNG parameter
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param ilen     contains the plaintext length
+ * \param input    buffer holding the data to be encrypted
+ * \param output   buffer that will hold the ciphertext
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The output buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_rsaes_pkcs1_v15_encrypt( rsa_context *ctx,
+                                 int (*f_rng)(void *, unsigned char *, size_t),
+                                 void *p_rng,
+                                 int mode, size_t ilen,
+                                 const unsigned char *input,
+                                 unsigned char *output );
+
+/**
+ * \brief          Perform a PKCS#1 v2.1 OAEP encryption (RSAES-OAEP-ENCRYPT)
+ *
+ * \param ctx      RSA context
+ * \param f_rng    RNG function (Needed for padding and PKCS#1 v2.1 encoding)
+ * \param p_rng    RNG parameter
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param label    buffer holding the custom label to use
+ * \param label_len contains the label length
+ * \param ilen     contains the plaintext length
+ * \param input    buffer holding the data to be encrypted
+ * \param output   buffer that will hold the ciphertext
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The output buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_rsaes_oaep_encrypt( rsa_context *ctx,
+                            int (*f_rng)(void *, unsigned char *, size_t),
+                            void *p_rng,
+                            int mode,
+                            const unsigned char *label, size_t label_len,
+                            size_t ilen,
+                            const unsigned char *input,
+                            unsigned char *output );
+
+/**
+ * \brief          Generic wrapper to perform a PKCS#1 decryption using the
+ *                 mode from the context. Do an RSA operation, then remove
+ *                 the message padding
  *
  * \param ctx      RSA context
  * \param mode     RSA_PUBLIC or RSA_PRIVATE
@@ -300,7 +354,57 @@
                        size_t output_max_len );
 
 /**
- * \brief          Do a private RSA to sign a message digest
+ * \brief          Perform a PKCS#1 v1.5 decryption (RSAES-PKCS1-v1_5-DECRYPT)
+ *
+ * \param ctx      RSA context
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param olen     will contain the plaintext length
+ * \param input    buffer holding the encrypted data
+ * \param output   buffer that will hold the plaintext
+ * \param output_max_len    maximum length of the output buffer
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The output buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise
+ *                 an error is thrown.
+ */
+int rsa_rsaes_pkcs1_v15_decrypt( rsa_context *ctx,
+                                 int mode, size_t *olen,
+                                 const unsigned char *input,
+                                 unsigned char *output,
+                                 size_t output_max_len );
+
+/**
+ * \brief          Perform a PKCS#1 v2.1 OAEP decryption (RSAES-OAEP-DECRYPT)
+ *
+ * \param ctx      RSA context
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param label    buffer holding the custom label to use
+ * \param label_len contains the label length
+ * \param olen     will contain the plaintext length
+ * \param input    buffer holding the encrypted data
+ * \param output   buffer that will hold the plaintext
+ * \param output_max_len    maximum length of the output buffer
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The output buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise
+ *                 an error is thrown.
+ */
+int rsa_rsaes_oaep_decrypt( rsa_context *ctx,
+                            int mode,
+                            const unsigned char *label, size_t label_len,
+                            size_t *olen,
+                            const unsigned char *input,
+                            unsigned char *output,
+                            size_t output_max_len );
+
+/**
+ * \brief          Generic wrapper to perform a PKCS#1 signature using the
+ *                 mode from the context. Do a private RSA operation to sign
+ *                 a message digest
  *
  * \param ctx      RSA context
  * \param f_rng    RNG function (Needed for PKCS#1 v2.1 encoding)
@@ -333,7 +437,65 @@
                     unsigned char *sig );
 
 /**
- * \brief          Do a public RSA and check the message digest
+ * \brief          Perform a PKCS#1 v1.5 signature (RSASSA-PKCS1-v1_5-SIGN)
+ *
+ * \param ctx      RSA context
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param hash_id  SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
+ * \param hashlen  message digest length (for SIG_RSA_RAW only)
+ * \param hash     buffer holding the message digest
+ * \param sig      buffer that will hold the ciphertext
+ *
+ * \return         0 if the signing operation was successful,
+ *                 or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The "sig" buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_rsassa_pkcs1_v15_sign( rsa_context *ctx,
+                               int mode,
+                               int hash_id,
+                               unsigned int hashlen,
+                               const unsigned char *hash,
+                               unsigned char *sig );
+
+/**
+ * \brief          Perform a PKCS#1 v2.1 PSS signature (RSASSA-PSS-SIGN)
+ *
+ * \param ctx      RSA context
+ * \param f_rng    RNG function (Needed for PKCS#1 v2.1 encoding)
+ * \param p_rng    RNG parameter
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param hash_id  SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
+ * \param hashlen  message digest length (for SIG_RSA_RAW only)
+ * \param hash     buffer holding the message digest
+ * \param sig      buffer that will hold the ciphertext
+ *
+ * \return         0 if the signing operation was successful,
+ *                 or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The "sig" buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ *
+ * \note           In case of PKCS#1 v2.1 encoding keep in mind that
+ *                 the hash_id in the RSA context is the one used for the
+ *                 encoding. hash_id in the function call is the type of hash
+ *                 that is encoded. According to RFC 3447 it is advised to
+ *                 keep both hashes the same.
+ */
+int rsa_rsassa_pss_sign( rsa_context *ctx,
+                         int (*f_rng)(void *, unsigned char *, size_t),
+                         void *p_rng,
+                         int mode,
+                         int hash_id,
+                         unsigned int hashlen,
+                         const unsigned char *hash,
+                         unsigned char *sig );
+
+/**
+ * \brief          Generic wrapper to perform a PKCS#1 verification using the
+ *                 mode from the context. Do a public RSA operation and check
+ *                 the message digest
  *
  * \param ctx      points to an RSA public key
  * \param mode     RSA_PUBLIC or RSA_PRIVATE
@@ -362,6 +524,59 @@
                       unsigned char *sig );
 
 /**
+ * \brief          Perform a PKCS#1 v1.5 verification (RSASSA-PKCS1-v1_5-VERIFY)
+ *
+ * \param ctx      points to an RSA public key
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param hash_id  SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
+ * \param hashlen  message digest length (for SIG_RSA_RAW only)
+ * \param hash     buffer holding the message digest
+ * \param sig      buffer holding the ciphertext
+ *
+ * \return         0 if the verify operation was successful,
+ *                 or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The "sig" buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_rsassa_pkcs1_v15_verify( rsa_context *ctx,
+                                 int mode,
+                                 int hash_id,
+                                 unsigned int hashlen,
+                                 const unsigned char *hash,
+                                 unsigned char *sig );
+
+/**
+ * \brief          Perform a PKCS#1 v2.1 PSS verification (RSASSA-PSS-VERIFY)
+ * \brief          Do a public RSA and check the message digest
+ *
+ * \param ctx      points to an RSA public key
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param hash_id  SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
+ * \param hashlen  message digest length (for SIG_RSA_RAW only)
+ * \param hash     buffer holding the message digest
+ * \param sig      buffer holding the ciphertext
+ *
+ * \return         0 if the verify operation was successful,
+ *                 or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The "sig" buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ *
+ * \note           In case of PKCS#1 v2.1 encoding keep in mind that
+ *                 the hash_id in the RSA context is the one used for the
+ *                 verification. hash_id in the function call is the type of hash
+ *                 that is verified. According to RFC 3447 it is advised to
+ *                 keep both hashes the same.
+ */
+int rsa_rsassa_pss_verify( rsa_context *ctx,
+                           int mode,
+                           int hash_id,
+                           unsigned int hashlen,
+                           const unsigned char *hash,
+                           unsigned char *sig );
+
+/**
  * \brief          Free the components of an RSA key
  *
  * \param ctx      RSA Context to free
diff --git a/include/polarssl/sha1.h b/include/polarssl/sha1.h
index 45ffadc..48da246 100644
--- a/include/polarssl/sha1.h
+++ b/include/polarssl/sha1.h
@@ -152,6 +152,9 @@
  */
 int sha1_self_test( int verbose );
 
+/* Internal use */
+void sha1_process( sha1_context *ctx, const unsigned char data[64] );
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/polarssl/sha2.h b/include/polarssl/sha2.h
index 054988d..39d9347 100644
--- a/include/polarssl/sha2.h
+++ b/include/polarssl/sha2.h
@@ -160,6 +160,9 @@
  */
 int sha2_self_test( int verbose );
 
+/* Internal use */
+void sha2_process( sha2_context *ctx, const unsigned char data[64] );
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/polarssl/sha4.h b/include/polarssl/sha4.h
index 6aae124..5563676 100644
--- a/include/polarssl/sha4.h
+++ b/include/polarssl/sha4.h
@@ -161,6 +161,9 @@
  */
 int sha4_self_test( int verbose );
 
+/* Internal use */
+void sha4_process( sha4_context *ctx, const unsigned char data[128] );
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h
index e5d9eb7..756441c 100644
--- a/include/polarssl/ssl.h
+++ b/include/polarssl/ssl.h
@@ -3,7 +3,7 @@
  *
  * \brief SSL/TLS functions.
  *
- *  Copyright (C) 2006-2012, Brainspark B.V.
+ *  Copyright (C) 2006-2013, Brainspark B.V.
  *
  *  This file is part of PolarSSL (http://www.polarssl.org)
  *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
@@ -37,6 +37,7 @@
 #include "sha4.h"
 #include "x509.h"
 #include "config.h"
+#include "ssl_ciphersuites.h"
 
 #if defined(POLARSSL_DHM_C)
 #include "dhm.h"
@@ -323,6 +324,8 @@
     /*
      * Session specific crypto layer
      */
+    const ssl_ciphersuite_t *ciphersuite_info;
+                                        /*!<  Chosen cipersuite_info  */
     unsigned int keylen;                /*!<  symmetric key length    */
     size_t minlen;                      /*!<  min. ciphertext length  */
     size_t ivlen;                       /*!<  IV length               */
@@ -332,8 +335,12 @@
     unsigned char iv_enc[16];           /*!<  IV (encryption)         */
     unsigned char iv_dec[16];           /*!<  IV (decryption)         */
 
-    unsigned char mac_enc[32];          /*!<  MAC (encryption)        */
-    unsigned char mac_dec[32];          /*!<  MAC (decryption)        */
+    /* Needed only for SSL v3.0 secret */
+    unsigned char mac_enc[32];          /*!<  SSL v3.0 secret (enc)   */
+    unsigned char mac_dec[32];          /*!<  SSL v3.0 secret (dec)   */
+
+    md_context_t md_ctx_enc;            /*!<  MAC (encryption)        */
+    md_context_t md_ctx_dec;            /*!<  MAC (decryption)        */
 
     uint32_t ctx_enc[136];              /*!<  encryption context      */
     uint32_t ctx_dec[136];              /*!<  decryption context      */
@@ -448,7 +455,8 @@
      */
     unsigned char *in_ctr;      /*!< 64-bit incoming message counter  */
     unsigned char *in_hdr;      /*!< 5-byte record header (in_ctr+8)  */
-    unsigned char *in_msg;      /*!< the message contents (in_hdr+5)  */
+    unsigned char *in_iv;       /*!< ivlen-byte IV (in_hdr+5)         */
+    unsigned char *in_msg;      /*!< message contents (in_iv+ivlen)   */
     unsigned char *in_offt;     /*!< read offset in application data  */
 
     int in_msgtype;             /*!< record header: message type      */
@@ -463,7 +471,8 @@
      */
     unsigned char *out_ctr;     /*!< 64-bit outgoing message counter  */
     unsigned char *out_hdr;     /*!< 5-byte record header (out_ctr+8) */
-    unsigned char *out_msg;     /*!< the message contents (out_hdr+32)*/
+    unsigned char *out_iv;      /*!< ivlen-byte IV (out_hdr+5)        */
+    unsigned char *out_msg;     /*!< message contents (out_iv+ivlen)  */
 
     int out_msgtype;            /*!< record header: message type      */
     size_t out_msglen;          /*!< record header: message length    */
@@ -518,13 +527,19 @@
 extern "C" {
 #endif
 
-extern const int ssl_default_ciphersuites[];
-
 #if defined(POLARSSL_SSL_HW_RECORD_ACCEL)
+
+#define SSL_CHANNEL_OUTBOUND    0
+#define SSL_CHANNEL_INBOUND     1
+
 extern int (*ssl_hw_record_init)(ssl_context *ssl,
                 const unsigned char *key_enc, const unsigned char *key_dec,
+                size_t keylen,
                 const unsigned char *iv_enc,  const unsigned char *iv_dec,
-                const unsigned char *mac_enc, const unsigned char *mac_dec);
+                size_t ivlen,
+                const unsigned char *mac_enc, const unsigned char *mac_dec,
+                size_t maclen);
+extern int (*ssl_hw_record_activate)(ssl_context *ssl, int direction);
 extern int (*ssl_hw_record_reset)(ssl_context *ssl);
 extern int (*ssl_hw_record_write)(ssl_context *ssl);
 extern int (*ssl_hw_record_read)(ssl_context *ssl);
@@ -537,10 +552,7 @@
  * \return              a statically allocated array of ciphersuites, the last
  *                      entry is 0.
  */
-static inline const int *ssl_list_ciphersuites( void )
-{
-    return ssl_default_ciphersuites;
-}
+const int *ssl_list_ciphersuites( void );
 
 /**
  * \brief               Return the name of the ciphersuite associated with the given
@@ -971,6 +983,20 @@
 int ssl_handshake( ssl_context *ssl );
 
 /**
+ * \brief          Perform a single step of the SSL handshake
+ *
+ *                 Note: the state of the context (ssl->state) will be at
+ *                 the following state after execution of this function.
+ *                 Do not call this function if state is SSL_HANDSHAKE_OVER.
+ *
+ * \param ssl      SSL context
+ *
+ * \return         0 if successful, POLARSSL_ERR_NET_WANT_READ,
+ *                 POLARSSL_ERR_NET_WANT_WRITE, or a specific SSL error code.
+ */
+int ssl_handshake_step( ssl_context *ssl );
+
+/**
  * \brief          Perform an SSL renegotiation on the running connection
  *
  * \param ssl      SSL context
@@ -1061,8 +1087,8 @@
 /*
  * Internal functions (do not call directly)
  */
-int ssl_handshake_client( ssl_context *ssl );
-int ssl_handshake_server( ssl_context *ssl );
+int ssl_handshake_client_step( ssl_context *ssl );
+int ssl_handshake_server_step( ssl_context *ssl );
 void ssl_handshake_wrapup( ssl_context *ssl );
 
 int ssl_send_fatal_handshake_failure( ssl_context *ssl );
diff --git a/include/polarssl/ssl_cache.h b/include/polarssl/ssl_cache.h
index 85e0ed1..10cff20 100644
--- a/include/polarssl/ssl_cache.h
+++ b/include/polarssl/ssl_cache.h
@@ -46,6 +46,7 @@
 {
     time_t timestamp;           /*!< entry timestamp    */
     ssl_session session;        /*!< entry session      */
+    x509_buf peer_cert;         /*!< entry peer_cert    */
     ssl_cache_entry *next;      /*!< chain pointer      */
 };
 
diff --git a/include/polarssl/ssl_ciphersuites.h b/include/polarssl/ssl_ciphersuites.h
new file mode 100644
index 0000000..62a928e
--- /dev/null
+++ b/include/polarssl/ssl_ciphersuites.h
@@ -0,0 +1,76 @@
+/**
+ * \file ssl_ciphersuites.h
+ *
+ * \brief SSL Ciphersuites for PolarSSL
+ *
+ *  Copyright (C) 2006-2013, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  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 POLARSSL_SSL_CIPHERSUITES_H
+#define POLARSSL_SSL_CIPHERSUITES_H
+
+#include "cipher.h"
+#include "md.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    POLARSSL_KEY_EXCHANGE_NONE = 0,
+    POLARSSL_KEY_EXCHANGE_RSA,
+    POLARSSL_KEY_EXCHANGE_DHE_RSA
+} key_exchange_type_t;
+
+typedef struct _ssl_ciphersuite_t ssl_ciphersuite_t;
+
+#define POLARSSL_CIPHERSUITE_WEAK   0x01
+
+/**
+ * \brief   This structure is used for storing ciphersuite information
+ */
+struct _ssl_ciphersuite_t
+{
+    int id;
+    const char * name;
+
+    cipher_type_t cipher;
+    md_type_t mac;
+    key_exchange_type_t key_exchange;
+
+    int min_major_ver;
+    int min_minor_ver;
+    int max_major_ver;
+    int max_minor_ver;
+
+    unsigned char flags;
+};
+
+const int *ssl_ciphersuites_list( void );
+
+const ssl_ciphersuite_t *ssl_ciphersuite_from_string( const char *ciphersuite_name );
+const ssl_ciphersuite_t *ssl_ciphersuite_from_id( int ciphersuite_id );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ssl_ciphersuites.h */
diff --git a/include/polarssl/version.h b/include/polarssl/version.h
index 0aadd9e..4f73ee2 100644
--- a/include/polarssl/version.h
+++ b/include/polarssl/version.h
@@ -39,16 +39,16 @@
  */
 #define POLARSSL_VERSION_MAJOR  1
 #define POLARSSL_VERSION_MINOR  2
-#define POLARSSL_VERSION_PATCH  3
+#define POLARSSL_VERSION_PATCH  6
 
 /**
  * The single version number has the following structure:
  *    MMNNPP00
  *    Major version | Minor version | Patch version
  */
-#define POLARSSL_VERSION_NUMBER         0x01020300
-#define POLARSSL_VERSION_STRING         "1.2.3"
-#define POLARSSL_VERSION_STRING_FULL    "PolarSSL 1.2.3"
+#define POLARSSL_VERSION_NUMBER         0x01020600
+#define POLARSSL_VERSION_STRING         "1.2.6"
+#define POLARSSL_VERSION_STRING_FULL    "PolarSSL 1.2.6"
 
 #if defined(POLARSSL_VERSION_C)
 
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 6bc46e0..c96a42a 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -39,6 +39,7 @@
      sha2.c
      sha4.c
      ssl_cache.c
+     ssl_ciphersuites.c
      ssl_cli.c 
      ssl_srv.c 
      ssl_tls.c
@@ -60,7 +61,7 @@
 else(NOT USE_SHARED_POLARSSL_LIBRARY)
 
 add_library(polarssl SHARED ${src})
-set_target_properties(polarssl PROPERTIES VERSION 1.2.3 SOVERSION 2)
+set_target_properties(polarssl PROPERTIES VERSION 1.2.6 SOVERSION 2)
 
 endif(NOT USE_SHARED_POLARSSL_LIBRARY)
 
diff --git a/library/Makefile b/library/Makefile
index c3cd451..1d3a38a 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -49,7 +49,7 @@
 		pkcs11.o								\
 		rsa.o		sha1.o		sha2.o			\
 		sha4.o		ssl_cache.o	ssl_cli.o		\
-		ssl_srv.o								\
+		ssl_srv.o   ssl_ciphersuites.o			\
 		ssl_tls.o	timing.o	version.o		\
 		x509parse.o	x509write.o	xtea.o
 
diff --git a/library/bignum.c b/library/bignum.c
index f2608c1..d9845da 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -1372,7 +1372,7 @@
     t_uint z = 1;
     mpi U;
 
-    U.n = U.s = z;
+    U.n = U.s = (int) z;
     U.p = &z;
 
     mpi_montmul( A, &U, N, mm, T );
diff --git a/library/cipher.c b/library/cipher.c
index f20cc73..2a2d782 100644
--- a/library/cipher.c
+++ b/library/cipher.c
@@ -5,7 +5,7 @@
  *
  * \author Adriaan de Jong <dejong@fox-it.com>
  *
- *  Copyright (C) 2006-2012, Brainspark B.V.
+ *  Copyright (C) 2006-2013, Brainspark B.V.
  *
  *  This file is part of PolarSSL (http://www.polarssl.org)
  *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
@@ -142,6 +142,13 @@
             return &aes_256_ctr_info;
 #endif /* defined(POLARSSL_CIPHER_MODE_CTR) */
 
+#if defined(POLARSSL_GCM_C)
+        case POLARSSL_CIPHER_AES_128_GCM:
+            return &aes_128_gcm_info;
+        case POLARSSL_CIPHER_AES_256_GCM:
+            return &aes_256_gcm_info;
+#endif /* defined(POLARSSL_GCM_C) */
+
 #endif
 
 #if defined(POLARSSL_CAMELLIA_C)
@@ -181,6 +188,11 @@
             return &des_ede3_cbc_info;
 #endif
 
+#if defined(POLARSSL_ARC4_C)
+        case POLARSSL_CIPHER_ARC4_128:
+            return &arc4_128_info;
+#endif
+
 #if defined(POLARSSL_BLOWFISH_C)
         case POLARSSL_CIPHER_BLOWFISH_CBC:
             return &blowfish_cbc_info;
@@ -374,19 +386,28 @@
     int ret;
     size_t copy_len = 0;
 
-    if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen ||
-        input == output )
+    *olen = 0;
+
+    if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen )
     {
         return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA;
     }
 
-    *olen = 0;
+    if( input == output &&
+       ( ctx->unprocessed_len != 0 || ilen % cipher_get_block_size( ctx ) ) )
+    {
+        return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA;
+    }
 
 #if defined(POLARSSL_CIPHER_NULL_CIPHER)
     if( ctx->cipher_info->mode == POLARSSL_MODE_NULL )
     {
-        memcpy( output, input, ilen );
         *olen = ilen;
+
+        if( output == input )
+            return( 0 );
+
+        memcpy( output, input, ilen );
         return 0;
     }
 #endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */
@@ -465,6 +486,7 @@
         return 0;
     }
 
+#if defined(POLARSSL_CIPHER_MODE_CFB)
     if( ctx->cipher_info->mode == POLARSSL_MODE_CFB )
     {
         if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx,
@@ -478,7 +500,9 @@
 
         return 0;
     }
+#endif
 
+#if defined(POLARSSL_CIPHER_MODE_CTR)
     if( ctx->cipher_info->mode == POLARSSL_MODE_CTR )
     {
         if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx,
@@ -492,6 +516,7 @@
 
         return 0;
     }
+#endif
 
     return POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE;
 }
diff --git a/library/cipher_wrap.c b/library/cipher_wrap.c
index 6b85903..7ee2178 100644
--- a/library/cipher_wrap.c
+++ b/library/cipher_wrap.c
@@ -1,11 +1,11 @@
 /**
- * \file md_wrap.c
+ * \file cipher_wrap.c
  * 
  * \brief Generic cipher wrapper for PolarSSL
  *
  * \author Adriaan de Jong <dejong@fox-it.com>
  *
- *  Copyright (C) 2006-2012, Brainspark B.V.
+ *  Copyright (C) 2006-2013, Brainspark B.V.
  *
  *  This file is part of PolarSSL (http://www.polarssl.org)
  *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
@@ -53,13 +53,13 @@
 
 #if defined(POLARSSL_AES_C)
 
-int aes_crypt_cbc_wrap( void *ctx, operation_t operation, size_t length,
+static int aes_crypt_cbc_wrap( void *ctx, operation_t operation, size_t length,
         unsigned char *iv, const unsigned char *input, unsigned char *output )
 {
     return aes_crypt_cbc( (aes_context *) ctx, operation, length, iv, input, output );
 }
 
-int aes_crypt_cfb128_wrap( void *ctx, operation_t operation, size_t length,
+static int aes_crypt_cfb128_wrap( void *ctx, operation_t operation, size_t length,
         size_t *iv_off, unsigned char *iv, const unsigned char *input, unsigned char *output )
 {
 #if defined(POLARSSL_CIPHER_MODE_CFB)
@@ -77,7 +77,7 @@
 #endif
 }
 
-int aes_crypt_ctr_wrap( void *ctx, size_t length,
+static int aes_crypt_ctr_wrap( void *ctx, size_t length,
         size_t *nc_off, unsigned char *nonce_counter, unsigned char *stream_block,
         const unsigned char *input, unsigned char *output )
 {
@@ -97,12 +97,12 @@
 #endif
 }
 
-int aes_setkey_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
+static int aes_setkey_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
 {
     return aes_setkey_dec( (aes_context *) ctx, key, key_length );
 }
 
-int aes_setkey_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
+static int aes_setkey_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
 {
     return aes_setkey_enc( (aes_context *) ctx, key, key_length );
 }
@@ -222,17 +222,39 @@
 };
 #endif /* POLARSSL_CIPHER_MODE_CTR */
 
+#if defined(POLARSSL_GCM_C)
+const cipher_info_t aes_128_gcm_info = {
+    POLARSSL_CIPHER_AES_128_GCM,
+    POLARSSL_MODE_GCM,
+    128,
+    "AES-128-GCM",
+    16,
+    16,
+    &aes_info
+};
+
+const cipher_info_t aes_256_gcm_info = {
+    POLARSSL_CIPHER_AES_256_GCM,
+    POLARSSL_MODE_GCM,
+    256,
+    "AES-256-GCM",
+    16,
+    16,
+    &aes_info
+};
+#endif /* POLARSSL_GCM_C */
+
 #endif
 
 #if defined(POLARSSL_CAMELLIA_C)
 
-int camellia_crypt_cbc_wrap( void *ctx, operation_t operation, size_t length,
+static int camellia_crypt_cbc_wrap( void *ctx, operation_t operation, size_t length,
         unsigned char *iv, const unsigned char *input, unsigned char *output )
 {
     return camellia_crypt_cbc( (camellia_context *) ctx, operation, length, iv, input, output );
 }
 
-int camellia_crypt_cfb128_wrap( void *ctx, operation_t operation, size_t length,
+static int camellia_crypt_cfb128_wrap( void *ctx, operation_t operation, size_t length,
         size_t *iv_off, unsigned char *iv, const unsigned char *input, unsigned char *output )
 {
 #if defined(POLARSSL_CIPHER_MODE_CFB)
@@ -250,7 +272,7 @@
 #endif
 }
 
-int camellia_crypt_ctr_wrap( void *ctx, size_t length,
+static int camellia_crypt_ctr_wrap( void *ctx, size_t length,
         size_t *nc_off, unsigned char *nonce_counter, unsigned char *stream_block,
         const unsigned char *input, unsigned char *output )
 {
@@ -270,12 +292,12 @@
 #endif
 }
 
-int camellia_setkey_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
+static int camellia_setkey_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
 {
     return camellia_setkey_dec( (camellia_context *) ctx, key, key_length );
 }
 
-int camellia_setkey_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
+static int camellia_setkey_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
 {
     return camellia_setkey_enc( (camellia_context *) ctx, key, key_length );
 }
@@ -399,19 +421,19 @@
 
 #if defined(POLARSSL_DES_C)
 
-int des_crypt_cbc_wrap( void *ctx, operation_t operation, size_t length,
+static int des_crypt_cbc_wrap( void *ctx, operation_t operation, size_t length,
         unsigned char *iv, const unsigned char *input, unsigned char *output )
 {
     return des_crypt_cbc( (des_context *) ctx, operation, length, iv, input, output );
 }
 
-int des3_crypt_cbc_wrap( void *ctx, operation_t operation, size_t length,
+static int des3_crypt_cbc_wrap( void *ctx, operation_t operation, size_t length,
         unsigned char *iv, const unsigned char *input, unsigned char *output )
 {
     return des3_crypt_cbc( (des3_context *) ctx, operation, length, iv, input, output );
 }
 
-int des_crypt_cfb128_wrap( void *ctx, operation_t operation, size_t length,
+static int des_crypt_cfb128_wrap( void *ctx, operation_t operation, size_t length,
         size_t *iv_off, unsigned char *iv, const unsigned char *input, unsigned char *output )
 {
     ((void) ctx);
@@ -425,7 +447,7 @@
     return POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE;
 }
 
-int des_crypt_ctr_wrap( void *ctx, size_t length,
+static int des_crypt_ctr_wrap( void *ctx, size_t length,
         size_t *nc_off, unsigned char *nonce_counter, unsigned char *stream_block,
         const unsigned char *input, unsigned char *output )
 {
@@ -440,43 +462,42 @@
     return POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE;
 }
 
-
-int des_setkey_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
+static int des_setkey_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
 {
     ((void) key_length);
 
     return des_setkey_dec( (des_context *) ctx, key );
 }
 
-int des_setkey_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
+static int des_setkey_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
 {
     ((void) key_length);
 
     return des_setkey_enc( (des_context *) ctx, key );
 }
 
-int des3_set2key_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
+static int des3_set2key_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
 {
     ((void) key_length);
 
     return des3_set2key_dec( (des3_context *) ctx, key );
 }
 
-int des3_set2key_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
+static int des3_set2key_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
 {
     ((void) key_length);
 
     return des3_set2key_enc( (des3_context *) ctx, key );
 }
 
-int des3_set3key_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
+static int des3_set3key_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
 {
     ((void) key_length);
 
     return des3_set3key_dec( (des3_context *) ctx, key );
 }
 
-int des3_set3key_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
+static int des3_set3key_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
 {
     ((void) key_length);
 
@@ -564,13 +585,13 @@
 
 #if defined(POLARSSL_BLOWFISH_C)
 
-int blowfish_crypt_cbc_wrap( void *ctx, operation_t operation, size_t length,
+static int blowfish_crypt_cbc_wrap( void *ctx, operation_t operation, size_t length,
         unsigned char *iv, const unsigned char *input, unsigned char *output )
 {
     return blowfish_crypt_cbc( (blowfish_context *) ctx, operation, length, iv, input, output );
 }
 
-int blowfish_crypt_cfb64_wrap( void *ctx, operation_t operation, size_t length,
+static int blowfish_crypt_cfb64_wrap( void *ctx, operation_t operation, size_t length,
         size_t *iv_off, unsigned char *iv, const unsigned char *input, unsigned char *output )
 {
 #if defined(POLARSSL_CIPHER_MODE_CFB)
@@ -588,7 +609,7 @@
 #endif
 }
 
-int blowfish_crypt_ctr_wrap( void *ctx, size_t length,
+static int blowfish_crypt_ctr_wrap( void *ctx, size_t length,
         size_t *nc_off, unsigned char *nonce_counter, unsigned char *stream_block,
         const unsigned char *input, unsigned char *output )
 {
@@ -608,12 +629,12 @@
 #endif
 }
 
-int blowfish_setkey_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
+static int blowfish_setkey_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
 {
     return blowfish_setkey( (blowfish_context *) ctx, key, key_length );
 }
 
-int blowfish_setkey_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
+static int blowfish_setkey_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length )
 {
     return blowfish_setkey( (blowfish_context *) ctx, key, key_length );
 }
@@ -674,6 +695,40 @@
 #endif /* POLARSSL_CIPHER_MODE_CTR */
 #endif /* POLARSSL_BLOWFISH_C */
 
+#if defined(POLARSSL_ARC4_C)
+static void * arc4_ctx_alloc( void )
+{
+    return (void *) 1;
+}
+
+
+static void arc4_ctx_free( void *ctx )
+{
+    ((void) ctx);
+}
+
+const cipher_base_t arc4_base_info = {
+    POLARSSL_CIPHER_ID_ARC4,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    arc4_ctx_alloc,
+    arc4_ctx_free
+};
+
+const cipher_info_t arc4_128_info = {
+    POLARSSL_CIPHER_ARC4_128,
+    POLARSSL_MODE_STREAM,
+    128,
+    "ARC4-128",
+    0,
+    1,
+    &arc4_base_info
+};
+#endif /* POLARSSL_ARC4_C */
+
 #if defined(POLARSSL_CIPHER_NULL_CIPHER)
 static void * null_ctx_alloc( void )
 {
@@ -702,7 +757,7 @@
     POLARSSL_MODE_NULL,
     0,
     "NULL",
-    1,
+    0,
     1,
     &null_base_info
 };
diff --git a/library/error.c b/library/error.c
index 1e96ebb..1a8457b 100644
--- a/library/error.c
+++ b/library/error.c
@@ -564,4 +564,22 @@
     snprintf( buf, buflen, "UNKNOWN ERROR CODE (%04X)", use_ret );
 }
 
+#else /* POLARSSL_ERROR_C */
+
+#if defined(POLARSSL_ERROR_STRERROR_DUMMY)
+
+#include <string.h>
+
+/*
+ * Provide an non-function in case POLARSSL_ERROR_C is not defined
+ */
+void error_strerror( int ret, char *buf, size_t buflen )
+{
+    ((void) ret);
+
+    if( buflen > 0 )
+        buf[0] = '\0';
+}
+
+#endif /* POLARSSL_ERROR_STRERROR_DUMMY */
 #endif /* POLARSSL_ERROR_C */
diff --git a/library/gcm.c b/library/gcm.c
index c91598c..7d79f1a 100644
--- a/library/gcm.c
+++ b/library/gcm.c
@@ -193,23 +193,14 @@
     size_t use_len;
     size_t orig_len = length * 8;
     size_t orig_add_len = add_len * 8;
-    unsigned char **xor_p;
 
     memset( y, 0x00, 16 );
     memset( work_buf, 0x00, 16 );
     memset( tag, 0x00, tag_len );
     memset( buf, 0x00, 16 );
 
-    if( ( mode == GCM_DECRYPT && output <= input && ( input - output ) < 8 ) ||
-        ( output > input && (size_t) ( output - input ) < length ) )
-    {
+    if( output > input && (size_t) ( output - input ) < length )
         return( POLARSSL_ERR_GCM_BAD_INPUT );
-    }
-
-    if( mode == GCM_ENCRYPT )
-        xor_p = (unsigned char **) &out_p;
-    else
-        xor_p = (unsigned char **) &p;
 
     if( iv_len == 12 )
     {
@@ -263,7 +254,7 @@
     {
         use_len = ( length < 16 ) ? length : 16;
 
-        for( i = 16; i > 0; i-- )
+        for( i = 16; i > 12; i-- )
             if( ++y[i - 1] != 0 )
                 break;
 
@@ -271,8 +262,11 @@
 
         for( i = 0; i < use_len; i++ )
         {
+            if( mode == GCM_DECRYPT )
+                buf[i] ^= p[i];
             out_p[i] = ectr[i] ^ p[i];
-            buf[i] ^= (*xor_p)[i];
+            if( mode == GCM_ENCRYPT )
+                buf[i] ^= out_p[i];
         }
         
         gcm_mult( ctx, buf, buf );
diff --git a/library/md.c b/library/md.c
index 96065c9..07a93ec 100644
--- a/library/md.c
+++ b/library/md.c
@@ -294,4 +294,14 @@
     return 0;
 }
 
+int md_process( md_context_t *ctx, const unsigned char *data )
+{
+    if( ctx == NULL || ctx->md_info == NULL )
+        return POLARSSL_ERR_MD_BAD_INPUT_DATA;
+
+    ctx->md_info->process_func( ctx->md_ctx, data );
+
+    return 0;
+}
+
 #endif
diff --git a/library/md2.c b/library/md2.c
index 954aa07..73abdfa 100644
--- a/library/md2.c
+++ b/library/md2.c
@@ -80,7 +80,7 @@
     ctx->left = 0;
 }
 
-static void md2_process( md2_context *ctx )
+void md2_process( md2_context *ctx )
 {
     int i, j;
     unsigned char t = 0;
diff --git a/library/md4.c b/library/md4.c
index 82adcd8..6012526 100644
--- a/library/md4.c
+++ b/library/md4.c
@@ -76,7 +76,7 @@
     ctx->state[3] = 0x10325476;
 }
 
-static void md4_process( md4_context *ctx, const unsigned char data[64] )
+void md4_process( md4_context *ctx, const unsigned char data[64] )
 {
     uint32_t X[16], A, B, C, D;
 
diff --git a/library/md5.c b/library/md5.c
index 298f1fa..b2ee10b 100644
--- a/library/md5.c
+++ b/library/md5.c
@@ -75,7 +75,7 @@
     ctx->state[3] = 0x10325476;
 }
 
-static void md5_process( md5_context *ctx, const unsigned char data[64] )
+void md5_process( md5_context *ctx, const unsigned char data[64] )
 {
     uint32_t X[16], A, B, C, D;
 
diff --git a/library/md_wrap.c b/library/md_wrap.c
index f276db5..5f64df7 100644
--- a/library/md_wrap.c
+++ b/library/md_wrap.c
@@ -117,6 +117,13 @@
     free( ctx );
 }
 
+static void md2_process_wrap( void *ctx, const unsigned char *data )
+{
+    ((void) data);
+
+    md2_process( (md2_context *) ctx );
+}
+
 const md_info_t md2_info = {
     POLARSSL_MD_MD2,
     "MD2",
@@ -133,28 +140,29 @@
     md2_hmac,
     md2_ctx_alloc,
     md2_ctx_free,
+    md2_process_wrap,
 };
 
 #endif
 
 #if defined(POLARSSL_MD4_C)
 
-void md4_starts_wrap( void *ctx )
+static void md4_starts_wrap( void *ctx )
 {
     md4_starts( (md4_context *) ctx );
 }
 
-void md4_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
+static void md4_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
 {
     md4_update( (md4_context *) ctx, input, ilen );
 }
 
-void md4_finish_wrap( void *ctx, unsigned char *output )
+static void md4_finish_wrap( void *ctx, unsigned char *output )
 {
     md4_finish( (md4_context *) ctx, output );
 }
 
-int md4_file_wrap( const char *path, unsigned char *output )
+static int md4_file_wrap( const char *path, unsigned char *output )
 {
 #if defined(POLARSSL_FS_IO)
     return md4_file( path, output );
@@ -165,36 +173,41 @@
 #endif
 }
 
-void md4_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen )
+static void md4_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen )
 {
     md4_hmac_starts( (md4_context *) ctx, key, keylen );
 }
 
-void md4_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
+static void md4_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
 {
     md4_hmac_update( (md4_context *) ctx, input, ilen );
 }
 
-void md4_hmac_finish_wrap( void *ctx, unsigned char *output )
+static void md4_hmac_finish_wrap( void *ctx, unsigned char *output )
 {
     md4_hmac_finish( (md4_context *) ctx, output );
 }
 
-void md4_hmac_reset_wrap( void *ctx )
+static void md4_hmac_reset_wrap( void *ctx )
 {
     md4_hmac_reset( (md4_context *) ctx );
 }
 
-void *md4_ctx_alloc( void )
+static void *md4_ctx_alloc( void )
 {
     return malloc( sizeof( md4_context ) );
 }
 
-void md4_ctx_free( void *ctx )
+static void md4_ctx_free( void *ctx )
 {
     free( ctx );
 }
 
+static void md4_process_wrap( void *ctx, const unsigned char *data )
+{
+    md4_process( (md4_context *) ctx, data );
+}
+
 const md_info_t md4_info = {
     POLARSSL_MD_MD4,
     "MD4",
@@ -211,6 +224,7 @@
     md4_hmac,
     md4_ctx_alloc,
     md4_ctx_free,
+    md4_process_wrap,
 };
 
 #endif
@@ -273,6 +287,11 @@
     free( ctx );
 }
 
+static void md5_process_wrap( void *ctx, const unsigned char *data )
+{
+    md5_process( (md5_context *) ctx, data );
+}
+
 const md_info_t md5_info = {
     POLARSSL_MD_MD5,
     "MD5",
@@ -289,28 +308,29 @@
     md5_hmac,
     md5_ctx_alloc,
     md5_ctx_free,
+    md5_process_wrap,
 };
 
 #endif
 
 #if defined(POLARSSL_SHA1_C)
 
-void sha1_starts_wrap( void *ctx )
+static void sha1_starts_wrap( void *ctx )
 {
     sha1_starts( (sha1_context *) ctx );
 }
 
-void sha1_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
+static void sha1_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
 {
     sha1_update( (sha1_context *) ctx, input, ilen );
 }
 
-void sha1_finish_wrap( void *ctx, unsigned char *output )
+static void sha1_finish_wrap( void *ctx, unsigned char *output )
 {
     sha1_finish( (sha1_context *) ctx, output );
 }
 
-int sha1_file_wrap( const char *path, unsigned char *output )
+static int sha1_file_wrap( const char *path, unsigned char *output )
 {
 #if defined(POLARSSL_FS_IO)
     return sha1_file( path, output );
@@ -321,36 +341,41 @@
 #endif
 }
 
-void sha1_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen )
+static void sha1_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen )
 {
     sha1_hmac_starts( (sha1_context *) ctx, key, keylen );
 }
 
-void sha1_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
+static void sha1_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
 {
     sha1_hmac_update( (sha1_context *) ctx, input, ilen );
 }
 
-void sha1_hmac_finish_wrap( void *ctx, unsigned char *output )
+static void sha1_hmac_finish_wrap( void *ctx, unsigned char *output )
 {
     sha1_hmac_finish( (sha1_context *) ctx, output );
 }
 
-void sha1_hmac_reset_wrap( void *ctx )
+static void sha1_hmac_reset_wrap( void *ctx )
 {
     sha1_hmac_reset( (sha1_context *) ctx );
 }
 
-void * sha1_ctx_alloc( void )
+static void * sha1_ctx_alloc( void )
 {
     return malloc( sizeof( sha1_context ) );
 }
 
-void sha1_ctx_free( void *ctx )
+static void sha1_ctx_free( void *ctx )
 {
     free( ctx );
 }
 
+static void sha1_process_wrap( void *ctx, const unsigned char *data )
+{
+    sha1_process( (sha1_context *) ctx, data );
+}
+
 const md_info_t sha1_info = {
     POLARSSL_MD_SHA1,
     "SHA1",
@@ -367,6 +392,7 @@
     sha1_hmac,
     sha1_ctx_alloc,
     sha1_ctx_free,
+    sha1_process_wrap,
 };
 
 #endif
@@ -376,28 +402,28 @@
  */
 #if defined(POLARSSL_SHA2_C)
 
-void sha224_starts_wrap( void *ctx )
+static void sha224_starts_wrap( void *ctx )
 {
     sha2_starts( (sha2_context *) ctx, 1 );
 }
 
-void sha224_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
+static void sha224_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
 {
     sha2_update( (sha2_context *) ctx, input, ilen );
 }
 
-void sha224_finish_wrap( void *ctx, unsigned char *output )
+static void sha224_finish_wrap( void *ctx, unsigned char *output )
 {
     sha2_finish( (sha2_context *) ctx, output );
 }
 
-void sha224_wrap( const unsigned char *input, size_t ilen,
+static void sha224_wrap( const unsigned char *input, size_t ilen,
                     unsigned char *output )
 {
     sha2( input, ilen, output, 1 );
 }
 
-int sha224_file_wrap( const char *path, unsigned char *output )
+static int sha224_file_wrap( const char *path, unsigned char *output )
 {
 #if defined(POLARSSL_FS_IO)
     return sha2_file( path, output, 1 );
@@ -408,43 +434,48 @@
 #endif
 }
 
-void sha224_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen )
+static void sha224_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen )
 {
     sha2_hmac_starts( (sha2_context *) ctx, key, keylen, 1 );
 }
 
-void sha224_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
+static void sha224_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
 {
     sha2_hmac_update( (sha2_context *) ctx, input, ilen );
 }
 
-void sha224_hmac_finish_wrap( void *ctx, unsigned char *output )
+static void sha224_hmac_finish_wrap( void *ctx, unsigned char *output )
 {
     sha2_hmac_finish( (sha2_context *) ctx, output );
 }
 
-void sha224_hmac_reset_wrap( void *ctx )
+static void sha224_hmac_reset_wrap( void *ctx )
 {
     sha2_hmac_reset( (sha2_context *) ctx );
 }
 
-void sha224_hmac_wrap( const unsigned char *key, size_t keylen,
+static void sha224_hmac_wrap( const unsigned char *key, size_t keylen,
         const unsigned char *input, size_t ilen,
         unsigned char *output )
 {
     sha2_hmac( key, keylen, input, ilen, output, 1 );
 }
 
-void * sha224_ctx_alloc( void )
+static void * sha224_ctx_alloc( void )
 {
     return malloc( sizeof( sha2_context ) );
 }
 
-void sha224_ctx_free( void *ctx )
+static void sha224_ctx_free( void *ctx )
 {
     free( ctx );
 }
 
+static void sha224_process_wrap( void *ctx, const unsigned char *data )
+{
+    sha2_process( (sha2_context *) ctx, data );
+}
+
 const md_info_t sha224_info = {
     POLARSSL_MD_SHA224,
     "SHA224",
@@ -461,30 +492,31 @@
     sha224_hmac_wrap,
     sha224_ctx_alloc,
     sha224_ctx_free,
+    sha224_process_wrap,
 };
 
-void sha256_starts_wrap( void *ctx )
+static void sha256_starts_wrap( void *ctx )
 {
     sha2_starts( (sha2_context *) ctx, 0 );
 }
 
-void sha256_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
+static void sha256_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
 {
     sha2_update( (sha2_context *) ctx, input, ilen );
 }
 
-void sha256_finish_wrap( void *ctx, unsigned char *output )
+static void sha256_finish_wrap( void *ctx, unsigned char *output )
 {
     sha2_finish( (sha2_context *) ctx, output );
 }
 
-void sha256_wrap( const unsigned char *input, size_t ilen,
+static void sha256_wrap( const unsigned char *input, size_t ilen,
                     unsigned char *output )
 {
     sha2( input, ilen, output, 0 );
 }
 
-int sha256_file_wrap( const char *path, unsigned char *output )
+static int sha256_file_wrap( const char *path, unsigned char *output )
 {
 #if defined(POLARSSL_FS_IO)
     return sha2_file( path, output, 0 );
@@ -495,43 +527,48 @@
 #endif
 }
 
-void sha256_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen )
+static void sha256_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen )
 {
     sha2_hmac_starts( (sha2_context *) ctx, key, keylen, 0 );
 }
 
-void sha256_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
+static void sha256_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
 {
     sha2_hmac_update( (sha2_context *) ctx, input, ilen );
 }
 
-void sha256_hmac_finish_wrap( void *ctx, unsigned char *output )
+static void sha256_hmac_finish_wrap( void *ctx, unsigned char *output )
 {
     sha2_hmac_finish( (sha2_context *) ctx, output );
 }
 
-void sha256_hmac_reset_wrap( void *ctx )
+static void sha256_hmac_reset_wrap( void *ctx )
 {
     sha2_hmac_reset( (sha2_context *) ctx );
 }
 
-void sha256_hmac_wrap( const unsigned char *key, size_t keylen,
+static void sha256_hmac_wrap( const unsigned char *key, size_t keylen,
         const unsigned char *input, size_t ilen,
         unsigned char *output )
 {
     sha2_hmac( key, keylen, input, ilen, output, 0 );
 }
 
-void * sha256_ctx_alloc( void )
+static void * sha256_ctx_alloc( void )
 {
     return malloc( sizeof( sha2_context ) );
 }
 
-void sha256_ctx_free( void *ctx )
+static void sha256_ctx_free( void *ctx )
 {
     free( ctx );
 }
 
+static void sha256_process_wrap( void *ctx, const unsigned char *data )
+{
+    sha2_process( (sha2_context *) ctx, data );
+}
+
 const md_info_t sha256_info = {
     POLARSSL_MD_SHA256,
     "SHA256",
@@ -548,34 +585,35 @@
     sha256_hmac_wrap,
     sha256_ctx_alloc,
     sha256_ctx_free,
+    sha256_process_wrap,
 };
 
 #endif
 
 #if defined(POLARSSL_SHA4_C)
 
-void sha384_starts_wrap( void *ctx )
+static void sha384_starts_wrap( void *ctx )
 {
     sha4_starts( (sha4_context *) ctx, 1 );
 }
 
-void sha384_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
+static void sha384_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
 {
     sha4_update( (sha4_context *) ctx, input, ilen );
 }
 
-void sha384_finish_wrap( void *ctx, unsigned char *output )
+static void sha384_finish_wrap( void *ctx, unsigned char *output )
 {
     sha4_finish( (sha4_context *) ctx, output );
 }
 
-void sha384_wrap( const unsigned char *input, size_t ilen,
+static void sha384_wrap( const unsigned char *input, size_t ilen,
                     unsigned char *output )
 {
     sha4( input, ilen, output, 1 );
 }
 
-int sha384_file_wrap( const char *path, unsigned char *output )
+static int sha384_file_wrap( const char *path, unsigned char *output )
 {
 #if defined(POLARSSL_FS_IO)
     return sha4_file( path, output, 1 );
@@ -586,43 +624,48 @@
 #endif
 }
 
-void sha384_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen )
+static void sha384_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen )
 {
     sha4_hmac_starts( (sha4_context *) ctx, key, keylen, 1 );
 }
 
-void sha384_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
+static void sha384_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
 {
     sha4_hmac_update( (sha4_context *) ctx, input, ilen );
 }
 
-void sha384_hmac_finish_wrap( void *ctx, unsigned char *output )
+static void sha384_hmac_finish_wrap( void *ctx, unsigned char *output )
 {
     sha4_hmac_finish( (sha4_context *) ctx, output );
 }
 
-void sha384_hmac_reset_wrap( void *ctx )
+static void sha384_hmac_reset_wrap( void *ctx )
 {
     sha4_hmac_reset( (sha4_context *) ctx );
 }
 
-void sha384_hmac_wrap( const unsigned char *key, size_t keylen,
+static void sha384_hmac_wrap( const unsigned char *key, size_t keylen,
         const unsigned char *input, size_t ilen,
         unsigned char *output )
 {
     sha4_hmac( key, keylen, input, ilen, output, 1 );
 }
 
-void * sha384_ctx_alloc( void )
+static void * sha384_ctx_alloc( void )
 {
     return malloc( sizeof( sha4_context ) );
 }
 
-void sha384_ctx_free( void *ctx )
+static void sha384_ctx_free( void *ctx )
 {
     free( ctx );
 }
 
+static void sha384_process_wrap( void *ctx, const unsigned char *data )
+{
+    sha4_process( (sha4_context *) ctx, data );
+}
+
 const md_info_t sha384_info = {
     POLARSSL_MD_SHA384,
     "SHA384",
@@ -639,30 +682,31 @@
     sha384_hmac_wrap,
     sha384_ctx_alloc,
     sha384_ctx_free,
+    sha384_process_wrap,
 };
 
-void sha512_starts_wrap( void *ctx )
+static void sha512_starts_wrap( void *ctx )
 {
     sha4_starts( (sha4_context *) ctx, 0 );
 }
 
-void sha512_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
+static void sha512_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
 {
     sha4_update( (sha4_context *) ctx, input, ilen );
 }
 
-void sha512_finish_wrap( void *ctx, unsigned char *output )
+static void sha512_finish_wrap( void *ctx, unsigned char *output )
 {
     sha4_finish( (sha4_context *) ctx, output );
 }
 
-void sha512_wrap( const unsigned char *input, size_t ilen,
+static void sha512_wrap( const unsigned char *input, size_t ilen,
                     unsigned char *output )
 {
     sha4( input, ilen, output, 0 );
 }
 
-int sha512_file_wrap( const char *path, unsigned char *output )
+static int sha512_file_wrap( const char *path, unsigned char *output )
 {
 #if defined(POLARSSL_FS_IO)
     return sha4_file( path, output, 0 );
@@ -673,43 +717,48 @@
 #endif
 }
 
-void sha512_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen )
+static void sha512_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen )
 {
     sha4_hmac_starts( (sha4_context *) ctx, key, keylen, 0 );
 }
 
-void sha512_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
+static void sha512_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen )
 {
     sha4_hmac_update( (sha4_context *) ctx, input, ilen );
 }
 
-void sha512_hmac_finish_wrap( void *ctx, unsigned char *output )
+static void sha512_hmac_finish_wrap( void *ctx, unsigned char *output )
 {
     sha4_hmac_finish( (sha4_context *) ctx, output );
 }
 
-void sha512_hmac_reset_wrap( void *ctx )
+static void sha512_hmac_reset_wrap( void *ctx )
 {
     sha4_hmac_reset( (sha4_context *) ctx );
 }
 
-void sha512_hmac_wrap( const unsigned char *key, size_t keylen,
+static void sha512_hmac_wrap( const unsigned char *key, size_t keylen,
         const unsigned char *input, size_t ilen,
         unsigned char *output )
 {
     sha4_hmac( key, keylen, input, ilen, output, 0 );
 }
 
-void * sha512_ctx_alloc( void )
+static void * sha512_ctx_alloc( void )
 {
     return malloc( sizeof( sha4_context ) );
 }
 
-void sha512_ctx_free( void *ctx )
+static void sha512_ctx_free( void *ctx )
 {
     free( ctx );
 }
 
+static void sha512_process_wrap( void *ctx, const unsigned char *data )
+{
+    sha4_process( (sha4_context *) ctx, data );
+}
+
 const md_info_t sha512_info = {
     POLARSSL_MD_SHA512,
     "SHA512",
@@ -726,6 +775,7 @@
     sha512_hmac_wrap,
     sha512_ctx_alloc,
     sha512_ctx_free,
+    sha512_process_wrap,
 };
 
 #endif
diff --git a/library/net.c b/library/net.c
index fedde16..7a1818d 100644
--- a/library/net.c
+++ b/library/net.c
@@ -90,12 +90,20 @@
  */
 #if defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN
 #define POLARSSL_HTONS(n) (n)
+#define POLARSSL_HTONL(n) (n)
 #else
-#define POLARSSL_HTONS(n) (((((unsigned short)(n) & 0xFF)) << 8) | (((unsigned short)(n) & 0xFF00) >> 8))
+#define POLARSSL_HTONS(n) ((((unsigned short)(n) & 0xFF      ) << 8 ) | \
+                           (((unsigned short)(n) & 0xFF00    ) >> 8 ))
+#define POLARSSL_HTONL(n) ((((unsigned long )(n) & 0xFF      ) << 24) | \
+                           (((unsigned long )(n) & 0xFF00    ) << 8 ) | \
+                           (((unsigned long )(n) & 0xFF0000  ) >> 8 ) | \
+                           (((unsigned long )(n) & 0xFF000000) >> 24))
 #endif
 
 unsigned short net_htons(unsigned short n);
+unsigned long  net_htonl(unsigned long  n);
 #define net_htons(n) POLARSSL_HTONS(n)
+#define net_htonl(n) POLARSSL_HTONL(n)
 
 /*
  * Initiate a TCP connection with host:port
@@ -171,7 +179,7 @@
     setsockopt( *fd, SOL_SOCKET, SO_REUSEADDR,
                 (const char *) &n, sizeof( n ) );
 
-    server_addr.sin_addr.s_addr = INADDR_ANY;
+    server_addr.sin_addr.s_addr = net_htonl( INADDR_ANY );
     server_addr.sin_family      = AF_INET;
     server_addr.sin_port        = net_htons( port );
 
@@ -185,11 +193,11 @@
                 break;
 
         if( n == 4 )
-            server_addr.sin_addr.s_addr =
+            server_addr.sin_addr.s_addr = net_htonl(
                 ( (uint32_t) c[0] << 24 ) |
                 ( (uint32_t) c[1] << 16 ) |
                 ( (uint32_t) c[2] <<  8 ) |
-                ( (uint32_t) c[3]       );
+                ( (uint32_t) c[3]       ) );
     }
 
     if( bind( *fd, (struct sockaddr *) &server_addr,
diff --git a/library/rsa.c b/library/rsa.c
index ee6ca01..e53d9a2 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -361,6 +361,140 @@
 }
 #endif
 
+#if defined(POLARSSL_PKCS1_V21)
+/*
+ * Implementation of the PKCS#1 v2.1 RSAES-OAEP-ENCRYPT function
+ */
+int rsa_rsaes_oaep_encrypt( rsa_context *ctx,
+                            int (*f_rng)(void *, unsigned char *, size_t),
+                            void *p_rng,
+                            int mode,
+                            const unsigned char *label, size_t label_len,
+                            size_t ilen,
+                            const unsigned char *input,
+                            unsigned char *output )
+{
+    size_t olen;
+    int ret;
+    unsigned char *p = output;
+    unsigned int hlen;
+    const md_info_t *md_info;
+    md_context_t md_ctx;
+
+    if( ctx->padding != RSA_PKCS_V21 || f_rng == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    md_info = md_info_from_type( ctx->hash_id );
+
+    if( md_info == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    olen = ctx->len;
+    hlen = md_get_size( md_info );
+
+    if( olen < ilen + 2 * hlen + 2 || f_rng == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    memset( output, 0, olen );
+
+    *p++ = 0;
+
+    // Generate a random octet string seed
+    //
+    if( ( ret = f_rng( p_rng, p, hlen ) ) != 0 )
+        return( POLARSSL_ERR_RSA_RNG_FAILED + ret );
+
+    p += hlen;
+
+    // Construct DB
+    //
+    md( md_info, label, label_len, p );
+    p += hlen;
+    p += olen - 2 * hlen - 2 - ilen;
+    *p++ = 1;
+    memcpy( p, input, ilen );
+
+    md_init_ctx( &md_ctx, md_info );
+
+    // maskedDB: Apply dbMask to DB
+    //
+    mgf_mask( output + hlen + 1, olen - hlen - 1, output + 1, hlen,
+               &md_ctx );
+
+    // maskedSeed: Apply seedMask to seed
+    //
+    mgf_mask( output + 1, hlen, output + hlen + 1, olen - hlen - 1,
+               &md_ctx );
+
+    md_free_ctx( &md_ctx );
+
+    return( ( mode == RSA_PUBLIC )
+            ? rsa_public(  ctx, output, output )
+            : rsa_private( ctx, output, output ) );
+}
+#endif /* POLARSSL_PKCS1_V21 */
+
+/*
+ * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-ENCRYPT function
+ */
+int rsa_rsaes_pkcs1_v15_encrypt( rsa_context *ctx,
+                                 int (*f_rng)(void *, unsigned char *, size_t),
+                                 void *p_rng,
+                                 int mode, size_t ilen,
+                                 const unsigned char *input,
+                                 unsigned char *output )
+{
+    size_t nb_pad, olen;
+    int ret;
+    unsigned char *p = output;
+
+    if( ctx->padding != RSA_PKCS_V15 || f_rng == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    olen = ctx->len;
+
+    if( olen < ilen + 11 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    nb_pad = olen - 3 - ilen;
+
+    *p++ = 0;
+    if( mode == RSA_PUBLIC )
+    {
+        *p++ = RSA_CRYPT;
+
+        while( nb_pad-- > 0 )
+        {
+            int rng_dl = 100;
+
+            do {
+                ret = f_rng( p_rng, p, 1 );
+            } while( *p == 0 && --rng_dl && ret == 0 );
+
+            // Check if RNG failed to generate data
+            //
+            if( rng_dl == 0 || ret != 0)
+                return POLARSSL_ERR_RSA_RNG_FAILED + ret;
+
+            p++;
+        }
+    }
+    else
+    {
+        *p++ = RSA_SIGN;
+
+        while( nb_pad-- > 0 )
+            *p++ = 0xFF;
+    }
+
+    *p++ = 0;
+    memcpy( p, input, ilen );
+
+    return( ( mode == RSA_PUBLIC )
+            ? rsa_public(  ctx, output, output )
+            : rsa_private( ctx, output, output ) );
+}
+
 /*
  * Add the message padding, then do an RSA operation
  */
@@ -371,139 +505,46 @@
                        const unsigned char *input,
                        unsigned char *output )
 {
-    size_t nb_pad, olen;
-    int ret;
-    unsigned char *p = output;
-#if defined(POLARSSL_PKCS1_V21)
-    unsigned int hlen;
-    const md_info_t *md_info;
-    md_context_t md_ctx;
-#endif
-
-    olen = ctx->len;
-
-    if( f_rng == NULL )
-        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
-
     switch( ctx->padding )
     {
         case RSA_PKCS_V15:
+            return rsa_rsaes_pkcs1_v15_encrypt( ctx, f_rng, p_rng, mode, ilen,
+                                                input, output );
 
-            if( olen < ilen + 11 )
-                return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
-
-            nb_pad = olen - 3 - ilen;
-
-            *p++ = 0;
-            if( mode == RSA_PUBLIC )
-            {
-                *p++ = RSA_CRYPT;
-
-                while( nb_pad-- > 0 )
-                {
-                    int rng_dl = 100;
-
-                    do {
-                        ret = f_rng( p_rng, p, 1 );
-                    } while( *p == 0 && --rng_dl && ret == 0 );
-
-                    // Check if RNG failed to generate data
-                    //
-                    if( rng_dl == 0 || ret != 0)
-                        return POLARSSL_ERR_RSA_RNG_FAILED + ret;
-
-                    p++;
-                }
-            }
-            else
-            {
-                *p++ = RSA_SIGN;
-
-                while( nb_pad-- > 0 )
-                    *p++ = 0xFF;
-            }
-
-            *p++ = 0;
-            memcpy( p, input, ilen );
-            break;
-        
 #if defined(POLARSSL_PKCS1_V21)
         case RSA_PKCS_V21:
-
-            md_info = md_info_from_type( ctx->hash_id );
-            if( md_info == NULL )
-                return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
-
-            hlen = md_get_size( md_info );
-
-            if( olen < ilen + 2 * hlen + 2 || f_rng == NULL )
-                return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
-
-            memset( output, 0, olen );
-
-            *p++ = 0;
-
-            // Generate a random octet string seed
-            //
-            if( ( ret = f_rng( p_rng, p, hlen ) ) != 0 )
-                return( POLARSSL_ERR_RSA_RNG_FAILED + ret );
-
-            p += hlen;
-
-            // Construct DB
-            //
-            md( md_info, p, 0, p );
-            p += hlen;
-            p += olen - 2 * hlen - 2 - ilen;
-            *p++ = 1;
-            memcpy( p, input, ilen ); 
-
-            md_init_ctx( &md_ctx, md_info );
-
-            // maskedDB: Apply dbMask to DB
-            //
-            mgf_mask( output + hlen + 1, olen - hlen - 1, output + 1, hlen,  
-                       &md_ctx );
-
-            // maskedSeed: Apply seedMask to seed
-            //
-            mgf_mask( output + 1, hlen, output + hlen + 1, olen - hlen - 1,  
-                       &md_ctx );
-
-            md_free_ctx( &md_ctx );
-            break;
+            return rsa_rsaes_oaep_encrypt( ctx, f_rng, p_rng, mode, NULL, 0,
+                                           ilen, input, output );
 #endif
 
         default:
-
             return( POLARSSL_ERR_RSA_INVALID_PADDING );
     }
-
-    return( ( mode == RSA_PUBLIC )
-            ? rsa_public(  ctx, output, output )
-            : rsa_private( ctx, output, output ) );
 }
 
+#if defined(POLARSSL_PKCS1_V21)
 /*
- * Do an RSA operation, then remove the message padding
+ * Implementation of the PKCS#1 v2.1 RSAES-OAEP-DECRYPT function
  */
-int rsa_pkcs1_decrypt( rsa_context *ctx,
-                       int mode, size_t *olen,
-                       const unsigned char *input,
-                       unsigned char *output,
-                       size_t output_max_len)
+int rsa_rsaes_oaep_decrypt( rsa_context *ctx,
+                            int mode, 
+                            const unsigned char *label, size_t label_len,
+                            size_t *olen,
+                            const unsigned char *input,
+                            unsigned char *output,
+                            size_t output_max_len )
 {
     int ret;
     size_t ilen;
     unsigned char *p;
-    unsigned char bt;
     unsigned char buf[POLARSSL_MPI_MAX_SIZE];
-#if defined(POLARSSL_PKCS1_V21)
     unsigned char lhash[POLARSSL_MD_MAX_SIZE];
     unsigned int hlen;
     const md_info_t *md_info;
     md_context_t md_ctx;
-#endif
+
+    if( ctx->padding != RSA_PKCS_V21 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
 
     ilen = ctx->len;
 
@@ -519,97 +560,49 @@
 
     p = buf;
 
-    switch( ctx->padding )
-    {
-        case RSA_PKCS_V15:
+    if( *p++ != 0 )
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
 
-            if( *p++ != 0 )
-                return( POLARSSL_ERR_RSA_INVALID_PADDING );
-            
-            bt = *p++;
-            if( ( bt != RSA_CRYPT && mode == RSA_PRIVATE ) ||
-                ( bt != RSA_SIGN && mode == RSA_PUBLIC ) )
-            {
-                return( POLARSSL_ERR_RSA_INVALID_PADDING );
-            }
+    md_info = md_info_from_type( ctx->hash_id );
+    if( md_info == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
 
-            if( bt == RSA_CRYPT )
-            {
-                while( *p != 0 && p < buf + ilen - 1 )
-                    p++;
+    hlen = md_get_size( md_info );
 
-                if( *p != 0 || p >= buf + ilen - 1 )
-                    return( POLARSSL_ERR_RSA_INVALID_PADDING );
+    md_init_ctx( &md_ctx, md_info );
 
-                p++;
-            }
-            else
-            {
-                while( *p == 0xFF && p < buf + ilen - 1 )
-                    p++;
+    // Generate lHash
+    //
+    md( md_info, label, label_len, lhash );
 
-                if( *p != 0 || p >= buf + ilen - 1 )
-                    return( POLARSSL_ERR_RSA_INVALID_PADDING );
+    // seed: Apply seedMask to maskedSeed
+    //
+    mgf_mask( buf + 1, hlen, buf + hlen + 1, ilen - hlen - 1,
+               &md_ctx );
 
-                p++;
-            }
+    // DB: Apply dbMask to maskedDB
+    //
+    mgf_mask( buf + hlen + 1, ilen - hlen - 1, buf + 1, hlen,
+               &md_ctx );
 
-            break;
+    p += hlen;
+    md_free_ctx( &md_ctx );
 
-#if defined(POLARSSL_PKCS1_V21)
-        case RSA_PKCS_V21:
-            
-            if( *p++ != 0 )
-                return( POLARSSL_ERR_RSA_INVALID_PADDING );
+    // Check validity
+    //
+    if( memcmp( lhash, p, hlen ) != 0 )
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
 
-            md_info = md_info_from_type( ctx->hash_id );
-            if( md_info == NULL )
-                return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
-                
-            hlen = md_get_size( md_info );
+    p += hlen;
 
-            md_init_ctx( &md_ctx, md_info );
-            
-            // Generate lHash
-            //
-            md( md_info, lhash, 0, lhash );
+    while( *p == 0 && p < buf + ilen )
+        p++;
 
-            // seed: Apply seedMask to maskedSeed
-            //
-            mgf_mask( buf + 1, hlen, buf + hlen + 1, ilen - hlen - 1,
-                       &md_ctx );
+    if( p == buf + ilen )
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
 
-            // DB: Apply dbMask to maskedDB
-            //
-            mgf_mask( buf + hlen + 1, ilen - hlen - 1, buf + 1, hlen,  
-                       &md_ctx );
-
-            p += hlen;
-            md_free_ctx( &md_ctx );
-
-            // Check validity
-            //
-            if( memcmp( lhash, p, hlen ) != 0 )
-                return( POLARSSL_ERR_RSA_INVALID_PADDING );
-
-            p += hlen;
-
-            while( *p == 0 && p < buf + ilen )
-                p++;
-
-            if( p == buf + ilen )
-                return( POLARSSL_ERR_RSA_INVALID_PADDING );
-
-            if( *p++ != 0x01 )
-                return( POLARSSL_ERR_RSA_INVALID_PADDING );
-
-            break;
-#endif
-
-        default:
-
-            return( POLARSSL_ERR_RSA_INVALID_PADDING );
-    }
+    if( *p++ != 0x01 )
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
 
     if (ilen - (p - buf) > output_max_len)
         return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE );
@@ -619,6 +612,367 @@
 
     return( 0 );
 }
+#endif /* POLARSSL_PKCS1_V21 */
+
+/*
+ * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function
+ */
+int rsa_rsaes_pkcs1_v15_decrypt( rsa_context *ctx,
+                                 int mode, size_t *olen,
+                                 const unsigned char *input,
+                                 unsigned char *output,
+                                 size_t output_max_len)
+{
+    int ret, correct = 1;
+    size_t ilen, pad_count = 0;
+    unsigned char *p, *q;
+    unsigned char bt;
+    unsigned char buf[POLARSSL_MPI_MAX_SIZE];
+
+    if( ctx->padding != RSA_PKCS_V15 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    ilen = ctx->len;
+
+    if( ilen < 16 || ilen > sizeof( buf ) )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    ret = ( mode == RSA_PUBLIC )
+          ? rsa_public(  ctx, input, buf )
+          : rsa_private( ctx, input, buf );
+
+    if( ret != 0 )
+        return( ret );
+
+    p = buf;
+
+    if( *p++ != 0 )
+        correct = 0;
+
+    bt = *p++;
+    if( ( bt != RSA_CRYPT && mode == RSA_PRIVATE ) ||
+        ( bt != RSA_SIGN && mode == RSA_PUBLIC ) )
+    {
+        correct = 0;
+    }
+
+    if( bt == RSA_CRYPT )
+    {
+        while( *p != 0 && p < buf + ilen - 1 )
+            pad_count += ( *p++ != 0 );
+
+        correct &= ( *p == 0 && p < buf + ilen - 1 );
+
+        q = p;
+
+        // Also pass over all other bytes to reduce timing differences
+        //
+        while ( q < buf + ilen - 1 )
+            pad_count += ( *q++ != 0 );
+
+        // Prevent compiler optimization of pad_count
+        //
+        correct |= pad_count & 0x100000; /* Always 0 unless 1M bit keys */
+        p++;
+    }
+    else
+    {
+        while( *p == 0xFF && p < buf + ilen - 1 )
+            pad_count += ( *p++ == 0xFF );
+
+        correct &= ( *p == 0 && p < buf + ilen - 1 );
+
+        q = p;
+
+        // Also pass over all other bytes to reduce timing differences
+        //
+        while ( q < buf + ilen - 1 )
+            pad_count += ( *q++ != 0 );
+
+        // Prevent compiler optimization of pad_count
+        //
+        correct |= pad_count & 0x100000; /* Always 0 unless 1M bit keys */
+        p++;
+    }
+
+    if( correct == 0 )
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
+
+    if (ilen - (p - buf) > output_max_len)
+        return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE );
+
+    *olen = ilen - (p - buf);
+    memcpy( output, p, *olen );
+
+    return( 0 );
+}
+
+/*
+ * Do an RSA operation, then remove the message padding
+ */
+int rsa_pkcs1_decrypt( rsa_context *ctx,
+                       int mode, size_t *olen,
+                       const unsigned char *input,
+                       unsigned char *output,
+                       size_t output_max_len)
+{
+    switch( ctx->padding )
+    {
+        case RSA_PKCS_V15:
+            return rsa_rsaes_pkcs1_v15_decrypt( ctx, mode, olen, input, output,
+                                                output_max_len );
+
+#if defined(POLARSSL_PKCS1_V21)
+        case RSA_PKCS_V21:
+            return rsa_rsaes_oaep_decrypt( ctx, mode, NULL, 0, olen, input,
+                                           output, output_max_len );
+#endif
+
+        default:
+            return( POLARSSL_ERR_RSA_INVALID_PADDING );
+    }
+}
+
+#if defined(POLARSSL_PKCS1_V21)
+/*
+ * Implementation of the PKCS#1 v2.1 RSASSA-PSS-SIGN function
+ */
+int rsa_rsassa_pss_sign( rsa_context *ctx,
+                         int (*f_rng)(void *, unsigned char *, size_t),
+                         void *p_rng,
+                         int mode,
+                         int hash_id,
+                         unsigned int hashlen,
+                         const unsigned char *hash,
+                         unsigned char *sig )
+{
+    size_t olen;
+    unsigned char *p = sig;
+    unsigned char salt[POLARSSL_MD_MAX_SIZE];
+    unsigned int slen, hlen, offset = 0;
+    int ret;
+    size_t msb;
+    const md_info_t *md_info;
+    md_context_t md_ctx;
+
+    if( ctx->padding != RSA_PKCS_V21 || f_rng == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    olen = ctx->len;
+
+    switch( hash_id )
+    {
+        case SIG_RSA_MD2:
+        case SIG_RSA_MD4:
+        case SIG_RSA_MD5:
+            hashlen = 16;
+            break;
+
+        case SIG_RSA_SHA1:
+            hashlen = 20;
+            break;
+
+        case SIG_RSA_SHA224:
+            hashlen = 28;
+            break;
+
+        case SIG_RSA_SHA256:
+            hashlen = 32;
+            break;
+
+        case SIG_RSA_SHA384:
+            hashlen = 48;
+            break;
+
+        case SIG_RSA_SHA512:
+            hashlen = 64;
+            break;
+
+        default:
+            return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    md_info = md_info_from_type( ctx->hash_id );
+    if( md_info == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    hlen = md_get_size( md_info );
+    slen = hlen;
+
+    if( olen < hlen + slen + 2 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    memset( sig, 0, olen );
+
+    msb = mpi_msb( &ctx->N ) - 1;
+
+    // Generate salt of length slen
+    //
+    if( ( ret = f_rng( p_rng, salt, slen ) ) != 0 )
+        return( POLARSSL_ERR_RSA_RNG_FAILED + ret );
+
+    // Note: EMSA-PSS encoding is over the length of N - 1 bits
+    //
+    msb = mpi_msb( &ctx->N ) - 1;
+    p += olen - hlen * 2 - 2;
+    *p++ = 0x01;
+    memcpy( p, salt, slen );
+    p += slen;
+
+    md_init_ctx( &md_ctx, md_info );
+
+    // Generate H = Hash( M' )
+    //
+    md_starts( &md_ctx );
+    md_update( &md_ctx, p, 8 );
+    md_update( &md_ctx, hash, hashlen );
+    md_update( &md_ctx, salt, slen );
+    md_finish( &md_ctx, p );
+
+    // Compensate for boundary condition when applying mask
+    //
+    if( msb % 8 == 0 )
+        offset = 1;
+
+    // maskedDB: Apply dbMask to DB
+    //
+    mgf_mask( sig + offset, olen - hlen - 1 - offset, p, hlen, &md_ctx );
+
+    md_free_ctx( &md_ctx );
+
+    msb = mpi_msb( &ctx->N ) - 1;
+    sig[0] &= 0xFF >> ( olen * 8 - msb );
+
+    p += hlen;
+    *p++ = 0xBC;
+
+    return( ( mode == RSA_PUBLIC )
+            ? rsa_public(  ctx, sig, sig )
+            : rsa_private( ctx, sig, sig ) );
+}
+#endif /* POLARSSL_PKCS1_V21 */
+
+/*
+ * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-V1_5-SIGN function
+ */
+/*
+ * Do an RSA operation to sign the message digest
+ */
+int rsa_rsassa_pkcs1_v15_sign( rsa_context *ctx,
+                               int mode,
+                               int hash_id,
+                               unsigned int hashlen,
+                               const unsigned char *hash,
+                               unsigned char *sig )
+{
+    size_t nb_pad, olen;
+    unsigned char *p = sig;
+
+    if( ctx->padding != RSA_PKCS_V15 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    olen = ctx->len;
+
+    switch( hash_id )
+    {
+        case SIG_RSA_RAW:
+            nb_pad = olen - 3 - hashlen;
+            break;
+
+        case SIG_RSA_MD2:
+        case SIG_RSA_MD4:
+        case SIG_RSA_MD5:
+            nb_pad = olen - 3 - 34;
+            break;
+
+        case SIG_RSA_SHA1:
+            nb_pad = olen - 3 - 35;
+            break;
+
+        case SIG_RSA_SHA224:
+            nb_pad = olen - 3 - 47;
+            break;
+
+        case SIG_RSA_SHA256:
+            nb_pad = olen - 3 - 51;
+            break;
+
+        case SIG_RSA_SHA384:
+            nb_pad = olen - 3 - 67;
+            break;
+
+        case SIG_RSA_SHA512:
+            nb_pad = olen - 3 - 83;
+            break;
+
+
+        default:
+            return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    if( ( nb_pad < 8 ) || ( nb_pad > olen ) )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    *p++ = 0;
+    *p++ = RSA_SIGN;
+    memset( p, 0xFF, nb_pad );
+    p += nb_pad;
+    *p++ = 0;
+
+    switch( hash_id )
+    {
+        case SIG_RSA_RAW:
+            memcpy( p, hash, hashlen );
+            break;
+
+        case SIG_RSA_MD2:
+            memcpy( p, ASN1_HASH_MDX, 18 );
+            memcpy( p + 18, hash, 16 );
+            p[13] = 2; break;
+
+        case SIG_RSA_MD4:
+            memcpy( p, ASN1_HASH_MDX, 18 );
+            memcpy( p + 18, hash, 16 );
+            p[13] = 4; break;
+
+        case SIG_RSA_MD5:
+            memcpy( p, ASN1_HASH_MDX, 18 );
+            memcpy( p + 18, hash, 16 );
+            p[13] = 5; break;
+
+        case SIG_RSA_SHA1:
+            memcpy( p, ASN1_HASH_SHA1, 15 );
+            memcpy( p + 15, hash, 20 );
+            break;
+
+        case SIG_RSA_SHA224:
+            memcpy( p, ASN1_HASH_SHA2X, 19 );
+            memcpy( p + 19, hash, 28 );
+            p[1] += 28; p[14] = 4; p[18] += 28; break;
+
+        case SIG_RSA_SHA256:
+            memcpy( p, ASN1_HASH_SHA2X, 19 );
+            memcpy( p + 19, hash, 32 );
+            p[1] += 32; p[14] = 1; p[18] += 32; break;
+
+        case SIG_RSA_SHA384:
+            memcpy( p, ASN1_HASH_SHA2X, 19 );
+            memcpy( p + 19, hash, 48 );
+            p[1] += 48; p[14] = 2; p[18] += 48; break;
+
+        case SIG_RSA_SHA512:
+            memcpy( p, ASN1_HASH_SHA2X, 19 );
+            memcpy( p + 19, hash, 64 );
+            p[1] += 64; p[14] = 3; p[18] += 64; break;
+
+        default:
+            return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    return( ( mode == RSA_PUBLIC )
+            ? rsa_public(  ctx, sig, sig )
+            : rsa_private( ctx, sig, sig ) );
+}
 
 /*
  * Do an RSA operation to sign the message digest
@@ -632,250 +986,48 @@
                     const unsigned char *hash,
                     unsigned char *sig )
 {
-    size_t nb_pad, olen;
-    unsigned char *p = sig;
-#if defined(POLARSSL_PKCS1_V21)
-    unsigned char salt[POLARSSL_MD_MAX_SIZE];
-    unsigned int slen, hlen, offset = 0;
-    int ret;
-    size_t msb;
-    const md_info_t *md_info;
-    md_context_t md_ctx;
-#else
-    (void) f_rng;
-    (void) p_rng;
-#endif
-
-    olen = ctx->len;
-
     switch( ctx->padding )
     {
         case RSA_PKCS_V15:
-
-            switch( hash_id )
-            {
-                case SIG_RSA_RAW:
-                    nb_pad = olen - 3 - hashlen;
-                    break;
-
-                case SIG_RSA_MD2:
-                case SIG_RSA_MD4:
-                case SIG_RSA_MD5:
-                    nb_pad = olen - 3 - 34;
-                    break;
-
-                case SIG_RSA_SHA1:
-                    nb_pad = olen - 3 - 35;
-                    break;
-
-                case SIG_RSA_SHA224:
-                    nb_pad = olen - 3 - 47;
-                    break;
-
-                case SIG_RSA_SHA256:
-                    nb_pad = olen - 3 - 51;
-                    break;
-
-                case SIG_RSA_SHA384:
-                    nb_pad = olen - 3 - 67;
-                    break;
-
-                case SIG_RSA_SHA512:
-                    nb_pad = olen - 3 - 83;
-                    break;
-
-
-                default:
-                    return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
-            }
-
-            if( ( nb_pad < 8 ) || ( nb_pad > olen ) )
-                return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
-
-            *p++ = 0;
-            *p++ = RSA_SIGN;
-            memset( p, 0xFF, nb_pad );
-            p += nb_pad;
-            *p++ = 0;
-
-            switch( hash_id )
-            {
-                case SIG_RSA_RAW:
-                    memcpy( p, hash, hashlen );
-                    break;
-
-                case SIG_RSA_MD2:
-                    memcpy( p, ASN1_HASH_MDX, 18 );
-                    memcpy( p + 18, hash, 16 );
-                    p[13] = 2; break;
-
-                case SIG_RSA_MD4:
-                    memcpy( p, ASN1_HASH_MDX, 18 );
-                    memcpy( p + 18, hash, 16 );
-                    p[13] = 4; break;
-
-                case SIG_RSA_MD5:
-                    memcpy( p, ASN1_HASH_MDX, 18 );
-                    memcpy( p + 18, hash, 16 );
-                    p[13] = 5; break;
-
-                case SIG_RSA_SHA1:
-                    memcpy( p, ASN1_HASH_SHA1, 15 );
-                    memcpy( p + 15, hash, 20 );
-                    break;
-
-                case SIG_RSA_SHA224:
-                    memcpy( p, ASN1_HASH_SHA2X, 19 );
-                    memcpy( p + 19, hash, 28 );
-                    p[1] += 28; p[14] = 4; p[18] += 28; break;
-
-                case SIG_RSA_SHA256:
-                    memcpy( p, ASN1_HASH_SHA2X, 19 );
-                    memcpy( p + 19, hash, 32 );
-                    p[1] += 32; p[14] = 1; p[18] += 32; break;
-
-                case SIG_RSA_SHA384:
-                    memcpy( p, ASN1_HASH_SHA2X, 19 );
-                    memcpy( p + 19, hash, 48 );
-                    p[1] += 48; p[14] = 2; p[18] += 48; break;
-
-                case SIG_RSA_SHA512:
-                    memcpy( p, ASN1_HASH_SHA2X, 19 );
-                    memcpy( p + 19, hash, 64 );
-                    p[1] += 64; p[14] = 3; p[18] += 64; break;
-
-                default:
-                    return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
-            }
-
-            break;
+            return rsa_rsassa_pkcs1_v15_sign( ctx, mode, hash_id,
+                                              hashlen, hash, sig );
 
 #if defined(POLARSSL_PKCS1_V21)
         case RSA_PKCS_V21:
-
-            if( f_rng == NULL )
-                return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
-
-            switch( hash_id )
-            {
-                case SIG_RSA_MD2:
-                case SIG_RSA_MD4:
-                case SIG_RSA_MD5:
-                    hashlen = 16;
-                    break;
-
-                case SIG_RSA_SHA1:
-                    hashlen = 20;
-                    break;
-
-                case SIG_RSA_SHA224:
-                    hashlen = 28;
-                    break;
-
-                case SIG_RSA_SHA256:
-                    hashlen = 32;
-                    break;
-
-                case SIG_RSA_SHA384:
-                    hashlen = 48;
-                    break;
-
-                case SIG_RSA_SHA512:
-                    hashlen = 64;
-                    break;
-
-                default:
-                    return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
-            }
-
-            md_info = md_info_from_type( ctx->hash_id );
-            if( md_info == NULL )
-                return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
-                
-            hlen = md_get_size( md_info );
-            slen = hlen;
-
-            if( olen < hlen + slen + 2 )
-                return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
-
-            memset( sig, 0, olen );
-
-            msb = mpi_msb( &ctx->N ) - 1;
-
-            // Generate salt of length slen
-            //
-            if( ( ret = f_rng( p_rng, salt, slen ) ) != 0 )
-                return( POLARSSL_ERR_RSA_RNG_FAILED + ret );
-
-            // Note: EMSA-PSS encoding is over the length of N - 1 bits
-            //
-            msb = mpi_msb( &ctx->N ) - 1;
-            p += olen - hlen * 2 - 2;
-            *p++ = 0x01;
-            memcpy( p, salt, slen );
-            p += slen;
-
-            md_init_ctx( &md_ctx, md_info );
-
-            // Generate H = Hash( M' )
-            //
-            md_starts( &md_ctx );
-            md_update( &md_ctx, p, 8 );
-            md_update( &md_ctx, hash, hashlen );
-            md_update( &md_ctx, salt, slen );
-            md_finish( &md_ctx, p );
-
-            // Compensate for boundary condition when applying mask
-            //
-            if( msb % 8 == 0 )
-                offset = 1;
-
-            // maskedDB: Apply dbMask to DB
-            //
-            mgf_mask( sig + offset, olen - hlen - 1 - offset, p, hlen, &md_ctx );
-
-            md_free_ctx( &md_ctx );
-
-            msb = mpi_msb( &ctx->N ) - 1;
-            sig[0] &= 0xFF >> ( olen * 8 - msb );
-
-            p += hlen;
-            *p++ = 0xBC;
-            break;
+            return rsa_rsassa_pss_sign( ctx, f_rng, p_rng, mode, hash_id,
+                                        hashlen, hash, sig );
 #endif
 
         default:
-
             return( POLARSSL_ERR_RSA_INVALID_PADDING );
     }
-
-    return( ( mode == RSA_PUBLIC )
-            ? rsa_public(  ctx, sig, sig )
-            : rsa_private( ctx, sig, sig ) );
 }
 
+#if defined(POLARSSL_PKCS1_V21)
 /*
- * Do an RSA operation and check the message digest
+ * Implementation of the PKCS#1 v2.1 RSASSA-PSS-VERIFY function
  */
-int rsa_pkcs1_verify( rsa_context *ctx,
-                      int mode,
-                      int hash_id,
-                      unsigned int hashlen,
-                      const unsigned char *hash,
-                      unsigned char *sig )
+int rsa_rsassa_pss_verify( rsa_context *ctx,
+                           int mode,
+                           int hash_id,
+                           unsigned int hashlen,
+                           const unsigned char *hash,
+                           unsigned char *sig )
 {
     int ret;
-    size_t len, siglen;
-    unsigned char *p, c;
+    size_t siglen;
+    unsigned char *p;
     unsigned char buf[POLARSSL_MPI_MAX_SIZE];
-#if defined(POLARSSL_PKCS1_V21)
     unsigned char result[POLARSSL_MD_MAX_SIZE];
     unsigned char zeros[8];
     unsigned int hlen;
     size_t slen, msb;
     const md_info_t *md_info;
     md_context_t md_ctx;
-#endif
+
+    if( ctx->padding != RSA_PKCS_V21 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
     siglen = ctx->len;
 
     if( siglen < 16 || siglen > sizeof( buf ) )
@@ -890,189 +1042,235 @@
 
     p = buf;
 
-    switch( ctx->padding )
+    if( buf[siglen - 1] != 0xBC )
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
+
+    switch( hash_id )
     {
-        case RSA_PKCS_V15:
-
-            if( *p++ != 0 || *p++ != RSA_SIGN )
-                return( POLARSSL_ERR_RSA_INVALID_PADDING );
-
-            while( *p != 0 )
-            {
-                if( p >= buf + siglen - 1 || *p != 0xFF )
-                    return( POLARSSL_ERR_RSA_INVALID_PADDING );
-                p++;
-            }
-            p++;
-
-            len = siglen - ( p - buf );
-
-            if( len == 33 && hash_id == SIG_RSA_SHA1 )
-            {
-                if( memcmp( p, ASN1_HASH_SHA1_ALT, 13 ) == 0 &&
-                        memcmp( p + 13, hash, 20 ) == 0 )
-                    return( 0 );
-                else
-                    return( POLARSSL_ERR_RSA_VERIFY_FAILED );
-            }
-            if( len == 34 )
-            {
-                c = p[13];
-                p[13] = 0;
-
-                if( memcmp( p, ASN1_HASH_MDX, 18 ) != 0 )
-                    return( POLARSSL_ERR_RSA_VERIFY_FAILED );
-
-                if( ( c == 2 && hash_id == SIG_RSA_MD2 ) ||
-                        ( c == 4 && hash_id == SIG_RSA_MD4 ) ||
-                        ( c == 5 && hash_id == SIG_RSA_MD5 ) )
-                {
-                    if( memcmp( p + 18, hash, 16 ) == 0 ) 
-                        return( 0 );
-                    else
-                        return( POLARSSL_ERR_RSA_VERIFY_FAILED );
-                }
-            }
-
-            if( len == 35 && hash_id == SIG_RSA_SHA1 )
-            {
-                if( memcmp( p, ASN1_HASH_SHA1, 15 ) == 0 &&
-                        memcmp( p + 15, hash, 20 ) == 0 )
-                    return( 0 );
-                else
-                    return( POLARSSL_ERR_RSA_VERIFY_FAILED );
-            }
-            if( ( len == 19 + 28 && p[14] == 4 && hash_id == SIG_RSA_SHA224 ) ||
-                    ( len == 19 + 32 && p[14] == 1 && hash_id == SIG_RSA_SHA256 ) ||
-                    ( len == 19 + 48 && p[14] == 2 && hash_id == SIG_RSA_SHA384 ) ||
-                    ( len == 19 + 64 && p[14] == 3 && hash_id == SIG_RSA_SHA512 ) )
-            {
-                c = p[1] - 17;
-                p[1] = 17;
-                p[14] = 0;
-
-                if( p[18] == c &&
-                        memcmp( p, ASN1_HASH_SHA2X, 18 ) == 0 &&
-                        memcmp( p + 19, hash, c ) == 0 )
-                    return( 0 );
-                else
-                    return( POLARSSL_ERR_RSA_VERIFY_FAILED );
-            }
-
-            if( len == hashlen && hash_id == SIG_RSA_RAW )
-            {
-                if( memcmp( p, hash, hashlen ) == 0 )
-                    return( 0 );
-                else
-                    return( POLARSSL_ERR_RSA_VERIFY_FAILED );
-            }
-
+        case SIG_RSA_MD2:
+        case SIG_RSA_MD4:
+        case SIG_RSA_MD5:
+            hashlen = 16;
             break;
 
-#if defined(POLARSSL_PKCS1_V21)
-        case RSA_PKCS_V21:
-            
-            if( buf[siglen - 1] != 0xBC )
-                return( POLARSSL_ERR_RSA_INVALID_PADDING );
+        case SIG_RSA_SHA1:
+            hashlen = 20;
+            break;
 
-            switch( hash_id )
-            {
-                case SIG_RSA_MD2:
-                case SIG_RSA_MD4:
-                case SIG_RSA_MD5:
-                    hashlen = 16;
-                    break;
+        case SIG_RSA_SHA224:
+            hashlen = 28;
+            break;
 
-                case SIG_RSA_SHA1:
-                    hashlen = 20;
-                    break;
+        case SIG_RSA_SHA256:
+            hashlen = 32;
+            break;
 
-                case SIG_RSA_SHA224:
-                    hashlen = 28;
-                    break;
+        case SIG_RSA_SHA384:
+            hashlen = 48;
+            break;
 
-                case SIG_RSA_SHA256:
-                    hashlen = 32;
-                    break;
+        case SIG_RSA_SHA512:
+            hashlen = 64;
+            break;
 
-                case SIG_RSA_SHA384:
-                    hashlen = 48;
-                    break;
+        default:
+            return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
 
-                case SIG_RSA_SHA512:
-                    hashlen = 64;
-                    break;
+    md_info = md_info_from_type( ctx->hash_id );
+    if( md_info == NULL )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
 
-                default:
-                    return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
-            }
+    hlen = md_get_size( md_info );
+    slen = siglen - hlen - 1;
 
-            md_info = md_info_from_type( ctx->hash_id );
-            if( md_info == NULL )
-                return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
-                
-            hlen = md_get_size( md_info );
-            slen = siglen - hlen - 1;
+    memset( zeros, 0, 8 );
 
-            memset( zeros, 0, 8 );
+    // Note: EMSA-PSS verification is over the length of N - 1 bits
+    //
+    msb = mpi_msb( &ctx->N ) - 1;
 
-            // Note: EMSA-PSS verification is over the length of N - 1 bits
-            //
-            msb = mpi_msb( &ctx->N ) - 1;
+    // Compensate for boundary condition when applying mask
+    //
+    if( msb % 8 == 0 )
+    {
+        p++;
+        siglen -= 1;
+    }
+    if( buf[0] >> ( 8 - siglen * 8 + msb ) )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
 
-            // Compensate for boundary condition when applying mask
-            //
-            if( msb % 8 == 0 )
-            {
-                p++;
-                siglen -= 1;
-            }
-            if( buf[0] >> ( 8 - siglen * 8 + msb ) )
-                return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+    md_init_ctx( &md_ctx, md_info );
 
-            md_init_ctx( &md_ctx, md_info );
+    mgf_mask( p, siglen - hlen - 1, p + siglen - hlen - 1, hlen, &md_ctx );
 
-            mgf_mask( p, siglen - hlen - 1, p + siglen - hlen - 1, hlen, &md_ctx );
+    buf[0] &= 0xFF >> ( siglen * 8 - msb );
 
-            buf[0] &= 0xFF >> ( siglen * 8 - msb );
+    while( *p == 0 && p < buf + siglen )
+        p++;
 
-            while( *p == 0 && p < buf + siglen )
-                p++;
+    if( p == buf + siglen ||
+        *p++ != 0x01 )
+    {
+        md_free_ctx( &md_ctx );
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
+    }
 
-            if( p == buf + siglen ||
-                *p++ != 0x01 )
-            {
-                md_free_ctx( &md_ctx );
-                return( POLARSSL_ERR_RSA_INVALID_PADDING );
-            }
+    slen -= p - buf;
 
-            slen -= p - buf;
+    // Generate H = Hash( M' )
+    //
+    md_starts( &md_ctx );
+    md_update( &md_ctx, zeros, 8 );
+    md_update( &md_ctx, hash, hashlen );
+    md_update( &md_ctx, p, slen );
+    md_finish( &md_ctx, result );
 
-            // Generate H = Hash( M' )
-            //
-            md_starts( &md_ctx );
-            md_update( &md_ctx, zeros, 8 );
-            md_update( &md_ctx, hash, hashlen );
-            md_update( &md_ctx, p, slen );
-            md_finish( &md_ctx, result );
+    md_free_ctx( &md_ctx );
 
-            md_free_ctx( &md_ctx );
+    if( memcmp( p + slen, result, hlen ) == 0 )
+        return( 0 );
+    else
+        return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+}
+#endif /* POLARSSL_PKCS1_V21 */
 
-            if( memcmp( p + slen, result, hlen ) == 0 )
+/*
+ * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function
+ */
+int rsa_rsassa_pkcs1_v15_verify( rsa_context *ctx,
+                                 int mode,
+                                 int hash_id,
+                                 unsigned int hashlen,
+                                 const unsigned char *hash,
+                                 unsigned char *sig )
+{
+    int ret;
+    size_t len, siglen;
+    unsigned char *p, c;
+    unsigned char buf[POLARSSL_MPI_MAX_SIZE];
+
+    if( ctx->padding != RSA_PKCS_V15 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    siglen = ctx->len;
+
+    if( siglen < 16 || siglen > sizeof( buf ) )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    ret = ( mode == RSA_PUBLIC )
+          ? rsa_public(  ctx, sig, buf )
+          : rsa_private( ctx, sig, buf );
+
+    if( ret != 0 )
+        return( ret );
+
+    p = buf;
+
+    if( *p++ != 0 || *p++ != RSA_SIGN )
+        return( POLARSSL_ERR_RSA_INVALID_PADDING );
+
+    while( *p != 0 )
+    {
+        if( p >= buf + siglen - 1 || *p != 0xFF )
+            return( POLARSSL_ERR_RSA_INVALID_PADDING );
+        p++;
+    }
+    p++;
+
+    len = siglen - ( p - buf );
+
+    if( len == 33 && hash_id == SIG_RSA_SHA1 )
+    {
+        if( memcmp( p, ASN1_HASH_SHA1_ALT, 13 ) == 0 &&
+                memcmp( p + 13, hash, 20 ) == 0 )
+            return( 0 );
+        else
+            return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+    }
+    if( len == 34 )
+    {
+        c = p[13];
+        p[13] = 0;
+
+        if( memcmp( p, ASN1_HASH_MDX, 18 ) != 0 )
+            return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+
+        if( ( c == 2 && hash_id == SIG_RSA_MD2 ) ||
+                ( c == 4 && hash_id == SIG_RSA_MD4 ) ||
+                ( c == 5 && hash_id == SIG_RSA_MD5 ) )
+        {
+            if( memcmp( p + 18, hash, 16 ) == 0 )
                 return( 0 );
             else
                 return( POLARSSL_ERR_RSA_VERIFY_FAILED );
-#endif
+        }
+    }
 
-        default:
+    if( len == 35 && hash_id == SIG_RSA_SHA1 )
+    {
+        if( memcmp( p, ASN1_HASH_SHA1, 15 ) == 0 &&
+                memcmp( p + 15, hash, 20 ) == 0 )
+            return( 0 );
+        else
+            return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+    }
+    if( ( len == 19 + 28 && p[14] == 4 && hash_id == SIG_RSA_SHA224 ) ||
+            ( len == 19 + 32 && p[14] == 1 && hash_id == SIG_RSA_SHA256 ) ||
+            ( len == 19 + 48 && p[14] == 2 && hash_id == SIG_RSA_SHA384 ) ||
+            ( len == 19 + 64 && p[14] == 3 && hash_id == SIG_RSA_SHA512 ) )
+    {
+        c = p[1] - 17;
+        p[1] = 17;
+        p[14] = 0;
 
-            return( POLARSSL_ERR_RSA_INVALID_PADDING );
+        if( p[18] == c &&
+                memcmp( p, ASN1_HASH_SHA2X, 18 ) == 0 &&
+                memcmp( p + 19, hash, c ) == 0 )
+            return( 0 );
+        else
+            return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+    }
+
+    if( len == hashlen && hash_id == SIG_RSA_RAW )
+    {
+        if( memcmp( p, hash, hashlen ) == 0 )
+            return( 0 );
+        else
+            return( POLARSSL_ERR_RSA_VERIFY_FAILED );
     }
 
     return( POLARSSL_ERR_RSA_INVALID_PADDING );
 }
 
 /*
+ * Do an RSA operation and check the message digest
+ */
+int rsa_pkcs1_verify( rsa_context *ctx,
+                      int mode,
+                      int hash_id,
+                      unsigned int hashlen,
+                      const unsigned char *hash,
+                      unsigned char *sig )
+{
+    switch( ctx->padding )
+    {
+        case RSA_PKCS_V15:
+            return rsa_rsassa_pkcs1_v15_verify( ctx, mode, hash_id,
+                                                hashlen, hash, sig );
+
+#if defined(POLARSSL_PKCS1_V21)
+        case RSA_PKCS_V21:
+            return rsa_rsassa_pss_verify( ctx, mode, hash_id,
+                                          hashlen, hash, sig );
+#endif
+
+        default:
+            return( POLARSSL_ERR_RSA_INVALID_PADDING );
+    }
+}
+
+/*
  * Free the components of an RSA key
  */
 void rsa_free( rsa_context *ctx )
diff --git a/library/sha1.c b/library/sha1.c
index b0b6e43..1e82580 100644
--- a/library/sha1.c
+++ b/library/sha1.c
@@ -76,7 +76,7 @@
     ctx->state[4] = 0xC3D2E1F0;
 }
 
-static void sha1_process( sha1_context *ctx, const unsigned char data[64] )
+void sha1_process( sha1_context *ctx, const unsigned char data[64] )
 {
     uint32_t temp, W[16], A, B, C, D, E;
 
diff --git a/library/sha2.c b/library/sha2.c
index 0245f31..af3a6ee 100644
--- a/library/sha2.c
+++ b/library/sha2.c
@@ -97,7 +97,7 @@
     ctx->is224 = is224;
 }
 
-static void sha2_process( sha2_context *ctx, const unsigned char data[64] )
+void sha2_process( sha2_context *ctx, const unsigned char data[64] )
 {
     uint32_t temp1, temp2, W[64];
     uint32_t A, B, C, D, E, F, G, H;
diff --git a/library/sha4.c b/library/sha4.c
index 6361a54..556cc4f 100644
--- a/library/sha4.c
+++ b/library/sha4.c
@@ -152,7 +152,7 @@
     ctx->is384 = is384;
 }
 
-static void sha4_process( sha4_context *ctx, const unsigned char data[128] )
+void sha4_process( sha4_context *ctx, const unsigned char data[128] )
 {
     int i;
     uint64_t temp1, temp2, W[80];
diff --git a/library/ssl_cache.c b/library/ssl_cache.c
index ab948d6..f5686be 100644
--- a/library/ssl_cache.c
+++ b/library/ssl_cache.c
@@ -71,6 +71,26 @@
             continue;
 
         memcpy( session->master, entry->session.master, 48 );
+
+        /*
+         * Restore peer certificate (without rest of the original chain)
+         */
+        if( entry->peer_cert.p != NULL )
+        {
+            session->peer_cert = (x509_cert *) malloc( sizeof(x509_cert) );
+            if( session->peer_cert == NULL )
+                return( 1 );
+
+            memset( session->peer_cert, 0, sizeof(x509_cert) );
+            if( x509parse_crt( session->peer_cert, entry->peer_cert.p,
+                               entry->peer_cert.len ) != 0 )
+            {
+                free( session->peer_cert );
+                session->peer_cert = NULL;
+                return( 1 );
+            }
+        }
+
         return( 0 );
     }
 
@@ -119,15 +139,20 @@
         if( old != NULL && count >= cache->max_entries )
         {
             cur = old;
-            memset( &cur->session, 0, sizeof( ssl_session ) );
+            memset( &cur->session, 0, sizeof(ssl_session) );
+            if( cur->peer_cert.p != NULL )
+            {
+                free( cur->peer_cert.p );
+                memset( &cur->peer_cert, 0, sizeof(x509_buf) );
+            }
         }
         else
         {
-            cur = (ssl_cache_entry *) malloc( sizeof( ssl_cache_entry ) );
+            cur = (ssl_cache_entry *) malloc( sizeof(ssl_cache_entry) );
             if( cur == NULL )
                 return( 1 );
 
-            memset( cur, 0, sizeof( ssl_cache_entry ) );
+            memset( cur, 0, sizeof(ssl_cache_entry) );
 
             if( prv == NULL )
                 cache->chain = cur;
@@ -140,9 +165,21 @@
 
     memcpy( &cur->session, session, sizeof( ssl_session ) );
     
-    // Do not include peer_cert in cache entry
-    //
-    cur->session.peer_cert = NULL;
+    /*
+     * Store peer certificate
+     */
+    if( session->peer_cert != NULL )
+    {
+        cur->peer_cert.p = (unsigned char *) malloc( session->peer_cert->raw.len );
+        if( cur->peer_cert.p == NULL )
+            return( 1 );
+
+        memcpy( cur->peer_cert.p, session->peer_cert->raw.p,
+                session->peer_cert->raw.len );
+        cur->peer_cert.len = session->peer_cert->raw.len;
+
+        cur->session.peer_cert = NULL;
+    }
 
     return( 0 );
 }
@@ -173,6 +210,10 @@
         cur = cur->next;
 
         ssl_session_free( &prv->session );
+
+        if( prv->peer_cert.p != NULL )
+            free( prv->peer_cert.p );
+
         free( prv );
     }
 }
diff --git a/library/ssl_ciphersuites.c b/library/ssl_ciphersuites.c
new file mode 100644
index 0000000..0218194
--- /dev/null
+++ b/library/ssl_ciphersuites.c
@@ -0,0 +1,408 @@
+/**
+ * \file ssl_ciphersuites.c
+ *
+ * \brief SSL ciphersuites for PolarSSL
+ *
+ *  Copyright (C) 2006-2013, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_SSL_TLS_C)
+
+#include "polarssl/ssl_ciphersuites.h"
+#include "polarssl/ssl.h"
+
+#include <stdlib.h>
+
+const int supported_ciphersuites[] =
+{
+#if defined(POLARSSL_DHM_C)
+#if defined(POLARSSL_AES_C)
+#if defined(POLARSSL_SHA2_C)
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+#endif /* POLARSSL_SHA2_C */
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA4_C)
+    TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+#endif
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+#if defined(POLARSSL_SHA2_C)
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+#endif /* POLARSSL_SHA2_C */
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C)
+    TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+#endif
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+#endif /* POLARSSL_AES_C */
+#if defined(POLARSSL_CAMELLIA_C)
+#if defined(POLARSSL_SHA2_C)
+    TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+#endif /* POLARSSL_SHA2_C */
+    TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
+#if defined(POLARSSL_SHA2_C)
+    TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+#endif /* POLARSSL_SHA2_C */
+    TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
+#endif /* POLARSSL_CAMELLIA_C */
+#if defined(POLARSSL_DES_C)
+    TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+#endif
+#endif /* POLARSSL_DHM_C */
+
+#if defined(POLARSSL_AES_C)
+#if defined(POLARSSL_SHA2_C)
+    TLS_RSA_WITH_AES_256_CBC_SHA256,
+#endif /* POLARSSL_SHA2_C */
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA4_C)
+    TLS_RSA_WITH_AES_256_GCM_SHA384,
+#endif
+    TLS_RSA_WITH_AES_256_CBC_SHA,
+#endif /* POLARSSL_AES_C */
+#if defined(POLARSSL_CAMELLIA_C)
+#if defined(POLARSSL_SHA2_C)
+    TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+#endif /* POLARSSL_SHA2_C */
+    TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
+#endif /* POLARSSL_CAMELLIA_C */
+#if defined(POLARSSL_AES_C)
+#if defined(POLARSSL_SHA2_C)
+    TLS_RSA_WITH_AES_128_CBC_SHA256,
+#endif /* POLARSSL_SHA2_C */
+#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C)
+    TLS_RSA_WITH_AES_128_GCM_SHA256,
+#endif /* POLARSSL_SHA2_C */
+    TLS_RSA_WITH_AES_128_CBC_SHA,
+#endif /* POLARSSL_AES_C */
+#if defined(POLARSSL_CAMELLIA_C)
+#if defined(POLARSSL_SHA2_C)
+    TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+#endif /* POLARSSL_SHA2_C */
+    TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
+#endif /* POLARSSL_CAMELLIA_C */
+#if defined(POLARSSL_DES_C)
+    TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+#endif /* POLARSSL_DES_C */
+#if defined(POLARSSL_ARC4_C)
+    TLS_RSA_WITH_RC4_128_SHA,
+    TLS_RSA_WITH_RC4_128_MD5,
+#endif /* POLARSSL_ARC4_C */
+#if defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES)
+#if defined(POLARSSL_DES_C)
+#if defined(POLARSSL_DHM_C)
+    TLS_DHE_RSA_WITH_DES_CBC_SHA,
+#endif /* POLARSSL_DHM_C */
+    TLS_RSA_WITH_DES_CBC_SHA,
+#endif /* POLARSSL_DES_C */
+#if defined(POLARSSL_CIPHER_NULL_CIPHER)
+#if defined(POLARSSL_SHA2_C)
+    TLS_RSA_WITH_NULL_SHA256,
+#endif
+    TLS_RSA_WITH_NULL_SHA,
+    TLS_RSA_WITH_NULL_MD5,
+#endif /* POLARSSL_CIPHER_NULL_CIPHER */
+#endif /* POLARSSL_ENABLE_WEAK_CIPHERSUITES */
+    0
+};
+
+static const ssl_ciphersuite_t ciphersuite_definitions[] =
+{
+#if defined(POLARSSL_ARC4_C)
+    { TLS_RSA_WITH_RC4_128_MD5, "TLS-RSA-WITH-RC4-128-MD5",
+      POLARSSL_CIPHER_ARC4_128, POLARSSL_MD_MD5, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+
+    { TLS_RSA_WITH_RC4_128_SHA, "TLS-RSA-WITH-RC4-128-SHA",
+      POLARSSL_CIPHER_ARC4_128, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_ARC4_C */
+
+#if defined(POLARSSL_DHM_C)
+#if defined(POLARSSL_AES_C)
+#if defined(POLARSSL_SHA4_C) && defined(POLARSSL_GCM_C)
+    { TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
+      POLARSSL_CIPHER_AES_256_GCM, POLARSSL_MD_SHA384, POLARSSL_KEY_EXCHANGE_DHE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_SHA4_C && POLARSSL_GCM_C */
+
+#if defined(POLARSSL_SHA2_C)
+#if defined(POLARSSL_GCM_C)
+    { TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
+      POLARSSL_CIPHER_AES_128_GCM, POLARSSL_MD_SHA256, POLARSSL_KEY_EXCHANGE_DHE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_GCM_C */
+
+    { TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
+      POLARSSL_CIPHER_AES_128_CBC, POLARSSL_MD_SHA256, POLARSSL_KEY_EXCHANGE_DHE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+
+    { TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
+      POLARSSL_CIPHER_AES_256_CBC, POLARSSL_MD_SHA256, POLARSSL_KEY_EXCHANGE_DHE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_SHA2_C */
+
+    { TLS_DHE_RSA_WITH_AES_128_CBC_SHA, "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
+      POLARSSL_CIPHER_AES_128_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_DHE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+
+    { TLS_DHE_RSA_WITH_AES_256_CBC_SHA, "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
+      POLARSSL_CIPHER_AES_256_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_DHE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_AES_C */
+
+#if defined(POLARSSL_CAMELLIA_C)
+#if defined(POLARSSL_SHA2_C)
+    { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
+      POLARSSL_CIPHER_CAMELLIA_128_CBC, POLARSSL_MD_SHA256, POLARSSL_KEY_EXCHANGE_DHE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+
+    { TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
+      POLARSSL_CIPHER_CAMELLIA_256_CBC, POLARSSL_MD_SHA256, POLARSSL_KEY_EXCHANGE_DHE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_SHA2_C */
+
+    { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
+      POLARSSL_CIPHER_CAMELLIA_128_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_DHE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+
+    { TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
+      POLARSSL_CIPHER_CAMELLIA_256_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_DHE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_CAMELLIA_C */
+
+#if defined(POLARSSL_DES_C)
+    { TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
+      POLARSSL_CIPHER_DES_EDE3_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_DHE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_DES_C */
+#endif /* POLARSSL_DHM_C */
+
+#if defined(POLARSSL_AES_C)
+#if defined(POLARSSL_SHA4_C) && defined(POLARSSL_GCM_C)
+    { TLS_RSA_WITH_AES_256_GCM_SHA384, "TLS-RSA-WITH-AES-256-GCM-SHA384",
+      POLARSSL_CIPHER_AES_256_GCM, POLARSSL_MD_SHA384, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_SHA4_C && POLARSSL_GCM_C */
+
+#if defined(POLARSSL_SHA2_C)
+#if defined(POLARSSL_GCM_C)
+    { TLS_RSA_WITH_AES_128_GCM_SHA256, "TLS-RSA-WITH-AES-128-GCM-SHA256",
+      POLARSSL_CIPHER_AES_128_GCM, POLARSSL_MD_SHA256, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_GCM_C */
+
+    { TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS-RSA-WITH-AES-128-CBC-SHA256",
+      POLARSSL_CIPHER_AES_128_CBC, POLARSSL_MD_SHA256, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+
+    { TLS_RSA_WITH_AES_256_CBC_SHA256, "TLS-RSA-WITH-AES-256-CBC-SHA256",
+      POLARSSL_CIPHER_AES_256_CBC, POLARSSL_MD_SHA256, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_SHA2_C */
+
+    { TLS_RSA_WITH_AES_128_CBC_SHA, "TLS-RSA-WITH-AES-128-CBC-SHA",
+      POLARSSL_CIPHER_AES_128_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+
+    { TLS_RSA_WITH_AES_256_CBC_SHA, "TLS-RSA-WITH-AES-256-CBC-SHA",
+      POLARSSL_CIPHER_AES_256_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_AES_C */
+
+#if defined(POLARSSL_CAMELLIA_C)
+#if defined(POLARSSL_SHA2_C)
+    { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
+      POLARSSL_CIPHER_CAMELLIA_128_CBC, POLARSSL_MD_SHA256, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+
+    { TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
+      POLARSSL_CIPHER_CAMELLIA_256_CBC, POLARSSL_MD_SHA256, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_SHA2_C */
+
+    { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
+      POLARSSL_CIPHER_CAMELLIA_128_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+
+    { TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
+      POLARSSL_CIPHER_CAMELLIA_256_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_CAMELLIA_C */
+
+#if defined(POLARSSL_DES_C)
+    { TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
+      POLARSSL_CIPHER_DES_EDE3_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_DES_C */
+
+#if defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES)
+#if defined(POLARSSL_CIPHER_NULL_CIPHER)
+    { TLS_RSA_WITH_NULL_MD5, "TLS-RSA-WITH-NULL-MD5",
+      POLARSSL_CIPHER_NULL, POLARSSL_MD_MD5, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      POLARSSL_CIPHERSUITE_WEAK },
+
+    { TLS_RSA_WITH_NULL_SHA, "TLS-RSA-WITH-NULL-SHA",
+      POLARSSL_CIPHER_NULL, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      POLARSSL_CIPHERSUITE_WEAK },
+
+    { TLS_RSA_WITH_NULL_SHA256, "TLS-RSA-WITH-NULL-SHA256",
+      POLARSSL_CIPHER_NULL, POLARSSL_MD_SHA256, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      POLARSSL_CIPHERSUITE_WEAK },
+#endif /* POLARSSL_CIPHER_NULL_CIPHER */
+
+#if defined(POLARSSL_DES_C)
+#if defined(POLARSSL_DHM_C)
+    { TLS_DHE_RSA_WITH_DES_CBC_SHA, "TLS-DHE-RSA-WITH-DES-CBC-SHA",
+      POLARSSL_CIPHER_DES_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_DHE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      POLARSSL_CIPHERSUITE_WEAK },
+#endif /* POLARSSL_DHM_C */
+
+    { TLS_RSA_WITH_DES_CBC_SHA, "TLS-RSA-WITH-DES-CBC-SHA",
+      POLARSSL_CIPHER_DES_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_RSA,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      POLARSSL_CIPHERSUITE_WEAK },
+#endif /* POLARSSL_DES_C */
+
+#endif /* POLARSSL_ENABLE_WEAK_CIPHERSUITES */
+
+    { 0, "", 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+const int *ssl_list_ciphersuites( void )
+{
+    return supported_ciphersuites;
+};
+
+const ssl_ciphersuite_t *ssl_ciphersuite_from_string( const char *ciphersuite_name )
+{
+    const ssl_ciphersuite_t *cur = ciphersuite_definitions;
+
+    if( NULL == ciphersuite_name )
+        return( NULL );
+
+    while( cur->id != 0 )
+    {
+        if( 0 == strcasecmp( cur->name, ciphersuite_name ) )
+            return( cur );
+
+        cur++;
+    }
+
+    return( NULL );
+}
+
+const ssl_ciphersuite_t *ssl_ciphersuite_from_id( int ciphersuite )
+{
+    const ssl_ciphersuite_t *cur = ciphersuite_definitions;
+
+    while( cur->id != 0 )
+    {
+        if( cur->id == ciphersuite )
+            return( cur );
+
+        cur++;
+    }
+
+    return( NULL );
+}
+
+const char *ssl_get_ciphersuite_name( const int ciphersuite_id )
+{
+    const ssl_ciphersuite_t *cur;
+
+    cur = ssl_ciphersuite_from_id( ciphersuite_id );
+
+    if( cur == NULL )
+        return( "unknown" );
+
+    return( cur->name );
+}
+
+int ssl_get_ciphersuite_id( const char *ciphersuite_name )
+{
+    const ssl_ciphersuite_t *cur;
+
+    cur = ssl_ciphersuite_from_string( ciphersuite_name );
+
+    if( cur == NULL )
+        return( 0 );
+
+    return( cur->id );
+}
+
+#endif
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index a716710..c426fa8 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -1,7 +1,7 @@
 /*
  *  SSLv3/TLSv1 client-side functions
  *
- *  Copyright (C) 2006-2012, Brainspark B.V.
+ *  Copyright (C) 2006-2013, Brainspark B.V.
  *
  *  This file is part of PolarSSL (http://www.polarssl.org)
  *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
@@ -473,6 +473,14 @@
      * Initialize update checksum functions
      */
     ssl_optimize_checksum( ssl, i );
+    ssl->transform_negotiate->ciphersuite_info = ssl_ciphersuite_from_id( i );
+
+    if( ssl->transform_negotiate->ciphersuite_info == NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "ciphersuite info for %02x not found",
+                          ssl->ciphersuites[i] ) );
+        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+    }
 
     SSL_DEBUG_MSG( 3, ( "server hello, session id len.: %d", n ) );
     SSL_DEBUG_BUF( 3,   "server hello, session id", buf + 39, n );
@@ -636,18 +644,8 @@
 
     SSL_DEBUG_MSG( 2, ( "=> parse server key exchange" ) );
 
-    if( ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_DES_CBC_SHA &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 )
+    if( ssl->transform_negotiate->ciphersuite_info->key_exchange !=
+        POLARSSL_KEY_EXCHANGE_DHE_RSA )
     {
         SSL_DEBUG_MSG( 2, ( "<= skip parse server key exchange" ) );
         ssl->state++;
@@ -894,7 +892,7 @@
 {
     int ret;
     unsigned char *buf, *p;
-    size_t n = 0;
+    size_t n = 0, m = 0;
     size_t cert_type_len = 0, sig_alg_len = 0, dn_len = 0;
 
     SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) );
@@ -976,6 +974,7 @@
                       | ( buf[6 + n]       ) );
 
         p = buf + 7 + n;
+        m += 2;
         n += sig_alg_len;
 
         if( ssl->in_hslen < 6 + n )
@@ -985,11 +984,11 @@
         }
     } 
 
-    dn_len = ( ( buf[7 + n] <<  8 )
-             | ( buf[8 + n]       ) );
+    dn_len = ( ( buf[5 + m + n] <<  8 )
+             | ( buf[6 + m + n]       ) );
 
     n += dn_len;
-    if( ssl->in_hslen != 9 + n )
+    if( ssl->in_hslen != 7 + m + n )
     {
         SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
@@ -1043,18 +1042,8 @@
 
     SSL_DEBUG_MSG( 2, ( "=> write client key exchange" ) );
 
-    if( ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_DES_CBC_SHA ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 )
+    if( ssl->transform_negotiate->ciphersuite_info->key_exchange ==
+        POLARSSL_KEY_EXCHANGE_DHE_RSA )
     {
 #if !defined(POLARSSL_DHM_C)
         SSL_DEBUG_MSG( 1, ( "support for dhm in not available" ) );
@@ -1273,121 +1262,113 @@
 }
 
 /*
- * SSL handshake -- client side
+ * SSL handshake -- client side -- single step
  */
-int ssl_handshake_client( ssl_context *ssl )
+int ssl_handshake_client_step( ssl_context *ssl )
 {
     int ret = 0;
 
-    SSL_DEBUG_MSG( 2, ( "=> handshake client" ) );
+    if( ssl->state == SSL_HANDSHAKE_OVER )
+        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
 
-    while( ssl->state != SSL_HANDSHAKE_OVER )
+    SSL_DEBUG_MSG( 2, ( "client state: %d", ssl->state ) );
+
+    if( ( ret = ssl_flush_output( ssl ) ) != 0 )
+        return( ret );
+
+    switch( ssl->state )
     {
-        SSL_DEBUG_MSG( 2, ( "client state: %d", ssl->state ) );
-
-        if( ( ret = ssl_flush_output( ssl ) ) != 0 )
+        case SSL_HELLO_REQUEST:
+            ssl->state = SSL_CLIENT_HELLO;
             break;
 
-        switch( ssl->state )
-        {
-            case SSL_HELLO_REQUEST:
-                ssl->state = SSL_CLIENT_HELLO;
-                break;
+       /*
+        *  ==>   ClientHello
+        */
+       case SSL_CLIENT_HELLO:
+           ret = ssl_write_client_hello( ssl );
+           break;
 
-            /*
-             *  ==>   ClientHello
-             */
-            case SSL_CLIENT_HELLO:
-                ret = ssl_write_client_hello( ssl );
-                break;
+       /*
+        *  <==   ServerHello
+        *        Certificate
+        *      ( ServerKeyExchange  )
+        *      ( CertificateRequest )
+        *        ServerHelloDone
+        */
+       case SSL_SERVER_HELLO:
+           ret = ssl_parse_server_hello( ssl );
+           break;
 
-            /*
-             *  <==   ServerHello
-             *        Certificate
-             *      ( ServerKeyExchange  )
-             *      ( CertificateRequest )
-             *        ServerHelloDone
-             */
-            case SSL_SERVER_HELLO:
-                ret = ssl_parse_server_hello( ssl );
-                break;
+       case SSL_SERVER_CERTIFICATE:
+           ret = ssl_parse_certificate( ssl );
+           break;
 
-            case SSL_SERVER_CERTIFICATE:
-                ret = ssl_parse_certificate( ssl );
-                break;
+       case SSL_SERVER_KEY_EXCHANGE:
+           ret = ssl_parse_server_key_exchange( ssl );
+           break;
 
-            case SSL_SERVER_KEY_EXCHANGE:
-                ret = ssl_parse_server_key_exchange( ssl );
-                break;
+       case SSL_CERTIFICATE_REQUEST:
+           ret = ssl_parse_certificate_request( ssl );
+           break;
 
-            case SSL_CERTIFICATE_REQUEST:
-                ret = ssl_parse_certificate_request( ssl );
-                break;
+       case SSL_SERVER_HELLO_DONE:
+           ret = ssl_parse_server_hello_done( ssl );
+           break;
 
-            case SSL_SERVER_HELLO_DONE:
-                ret = ssl_parse_server_hello_done( ssl );
-                break;
+       /*
+        *  ==> ( Certificate/Alert  )
+        *        ClientKeyExchange
+        *      ( CertificateVerify  )
+        *        ChangeCipherSpec
+        *        Finished
+        */
+       case SSL_CLIENT_CERTIFICATE:
+           ret = ssl_write_certificate( ssl );
+           break;
 
-            /*
-             *  ==> ( Certificate/Alert  )
-             *        ClientKeyExchange
-             *      ( CertificateVerify  )
-             *        ChangeCipherSpec
-             *        Finished
-             */
-            case SSL_CLIENT_CERTIFICATE:
-                ret = ssl_write_certificate( ssl );
-                break;
+       case SSL_CLIENT_KEY_EXCHANGE:
+           ret = ssl_write_client_key_exchange( ssl );
+           break;
 
-            case SSL_CLIENT_KEY_EXCHANGE:
-                ret = ssl_write_client_key_exchange( ssl );
-                break;
+       case SSL_CERTIFICATE_VERIFY:
+           ret = ssl_write_certificate_verify( ssl );
+           break;
 
-            case SSL_CERTIFICATE_VERIFY:
-                ret = ssl_write_certificate_verify( ssl );
-                break;
+       case SSL_CLIENT_CHANGE_CIPHER_SPEC:
+           ret = ssl_write_change_cipher_spec( ssl );
+           break;
 
-            case SSL_CLIENT_CHANGE_CIPHER_SPEC:
-                ret = ssl_write_change_cipher_spec( ssl );
-                break;
+       case SSL_CLIENT_FINISHED:
+           ret = ssl_write_finished( ssl );
+           break;
 
-            case SSL_CLIENT_FINISHED:
-                ret = ssl_write_finished( ssl );
-                break;
+       /*
+        *  <==   ChangeCipherSpec
+        *        Finished
+        */
+       case SSL_SERVER_CHANGE_CIPHER_SPEC:
+           ret = ssl_parse_change_cipher_spec( ssl );
+           break;
 
-            /*
-             *  <==   ChangeCipherSpec
-             *        Finished
-             */
-            case SSL_SERVER_CHANGE_CIPHER_SPEC:
-                ret = ssl_parse_change_cipher_spec( ssl );
-                break;
+       case SSL_SERVER_FINISHED:
+           ret = ssl_parse_finished( ssl );
+           break;
 
-            case SSL_SERVER_FINISHED:
-                ret = ssl_parse_finished( ssl );
-                break;
+       case SSL_FLUSH_BUFFERS:
+           SSL_DEBUG_MSG( 2, ( "handshake: done" ) );
+           ssl->state = SSL_HANDSHAKE_WRAPUP;
+           break;
 
-            case SSL_FLUSH_BUFFERS:
-                SSL_DEBUG_MSG( 2, ( "handshake: done" ) );
-                ssl->state = SSL_HANDSHAKE_WRAPUP;
-                break;
+       case SSL_HANDSHAKE_WRAPUP:
+           ssl_handshake_wrapup( ssl );
+           break;
 
-            case SSL_HANDSHAKE_WRAPUP:
-                ssl_handshake_wrapup( ssl );
-                break;
-
-            default:
-                SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) );
-                return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
-        }
-
-        if( ret != 0 )
-            break;
-    }
-
-    SSL_DEBUG_MSG( 2, ( "<= handshake client" ) );
+       default:
+           SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) );
+           return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+   }
 
     return( ret );
 }
-
 #endif
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 3825393..c5788ac 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -1,7 +1,7 @@
 /*
  *  SSLv3/TLSv1 server-side functions
  *
- *  Copyright (C) 2006-2012, Brainspark B.V.
+ *  Copyright (C) 2006-2013, Brainspark B.V.
  *
  *  This file is part of PolarSSL (http://www.polarssl.org)
  *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
@@ -191,6 +191,216 @@
     return( 0 );
 }
 
+#if defined(POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
+static int ssl_parse_client_hello_v2( ssl_context *ssl )
+{
+    int ret;
+    unsigned int i, j;
+    size_t n;
+    unsigned int ciph_len, sess_len, chal_len;
+    unsigned char *buf, *p;
+
+    SSL_DEBUG_MSG( 2, ( "=> parse client hello v2" ) );
+
+    if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE )
+    {
+        SSL_DEBUG_MSG( 1, ( "client hello v2 illegal for renegotiation" ) );
+
+        if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 )
+            return( ret );
+
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+
+    buf = ssl->in_hdr;
+
+    SSL_DEBUG_BUF( 4, "record header", buf, 5 );
+
+    SSL_DEBUG_MSG( 3, ( "client hello v2, message type: %d",
+                   buf[2] ) );
+    SSL_DEBUG_MSG( 3, ( "client hello v2, message len.: %d",
+                   ( ( buf[0] & 0x7F ) << 8 ) | buf[1] ) );
+    SSL_DEBUG_MSG( 3, ( "client hello v2, max. version: [%d:%d]",
+                   buf[3], buf[4] ) );
+
+    /*
+     * SSLv2 Client Hello
+     *
+     * Record layer:
+     *     0  .   1   message length
+     *
+     * SSL layer:
+     *     2  .   2   message type
+     *     3  .   4   protocol version
+     */
+    if( buf[2] != SSL_HS_CLIENT_HELLO ||
+        buf[3] != SSL_MAJOR_VERSION_3 )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+
+    n = ( ( buf[0] << 8 ) | buf[1] ) & 0x7FFF;
+
+    if( n < 17 || n > 512 )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+
+    ssl->major_ver = SSL_MAJOR_VERSION_3;
+    ssl->minor_ver = ( buf[4] <= SSL_MINOR_VERSION_3 )
+                     ? buf[4]  : SSL_MINOR_VERSION_3;
+
+    if( ssl->minor_ver < ssl->min_minor_ver )
+    {
+        SSL_DEBUG_MSG( 1, ( "client only supports ssl smaller than minimum"
+                            " [%d:%d] < [%d:%d]", ssl->major_ver, ssl->minor_ver,
+                            ssl->min_major_ver, ssl->min_minor_ver ) );
+
+        ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL,
+                                     SSL_ALERT_MSG_PROTOCOL_VERSION );
+        return( POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION );
+    }
+
+    ssl->max_major_ver = buf[3];
+    ssl->max_minor_ver = buf[4];
+
+    if( ( ret = ssl_fetch_input( ssl, 2 + n ) ) != 0 )
+    {
+        SSL_DEBUG_RET( 1, "ssl_fetch_input", ret );
+        return( ret );
+    }
+
+    ssl->handshake->update_checksum( ssl, buf + 2, n );
+
+    buf = ssl->in_msg;
+    n = ssl->in_left - 5;
+
+    /*
+     *    0  .   1   ciphersuitelist length
+     *    2  .   3   session id length
+     *    4  .   5   challenge length
+     *    6  .  ..   ciphersuitelist
+     *   ..  .  ..   session id
+     *   ..  .  ..   challenge
+     */
+    SSL_DEBUG_BUF( 4, "record contents", buf, n );
+
+    ciph_len = ( buf[0] << 8 ) | buf[1];
+    sess_len = ( buf[2] << 8 ) | buf[3];
+    chal_len = ( buf[4] << 8 ) | buf[5];
+
+    SSL_DEBUG_MSG( 3, ( "ciph_len: %d, sess_len: %d, chal_len: %d",
+                   ciph_len, sess_len, chal_len ) );
+
+    /*
+     * Make sure each parameter length is valid
+     */
+    if( ciph_len < 3 || ( ciph_len % 3 ) != 0 )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+
+    if( sess_len > 32 )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+
+    if( chal_len < 8 || chal_len > 32 )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+
+    if( n != 6 + ciph_len + sess_len + chal_len )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+
+    SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist",
+                   buf + 6, ciph_len );
+    SSL_DEBUG_BUF( 3, "client hello, session id",
+                   buf + 6 + ciph_len, sess_len );
+    SSL_DEBUG_BUF( 3, "client hello, challenge",
+                   buf + 6 + ciph_len + sess_len, chal_len );
+
+    p = buf + 6 + ciph_len;
+    ssl->session_negotiate->length = sess_len;
+    memset( ssl->session_negotiate->id, 0, sizeof( ssl->session_negotiate->id ) );
+    memcpy( ssl->session_negotiate->id, p, ssl->session_negotiate->length );
+
+    p += sess_len;
+    memset( ssl->handshake->randbytes, 0, 64 );
+    memcpy( ssl->handshake->randbytes + 32 - chal_len, p, chal_len );
+
+    /*
+     * Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV
+     */
+    for( i = 0, p = buf + 6; i < ciph_len; i += 3, p += 3 )
+    {
+        if( p[0] == 0 && p[1] == 0 && p[2] == SSL_EMPTY_RENEGOTIATION_INFO )
+        {
+            SSL_DEBUG_MSG( 3, ( "received TLS_EMPTY_RENEGOTIATION_INFO " ) );
+            if( ssl->renegotiation == SSL_RENEGOTIATION )
+            {
+                SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV during renegotiation" ) );
+
+                if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 )
+                    return( ret );
+
+                return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+            }
+            ssl->secure_renegotiation = SSL_SECURE_RENEGOTIATION;
+            break;
+        }
+    }
+
+    for( i = 0; ssl->ciphersuites[i] != 0; i++ )
+    {
+        for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 )
+        {
+            if( p[0] == 0 &&
+                p[1] == 0 &&
+                p[2] == ssl->ciphersuites[i] )
+                goto have_ciphersuite_v2;
+        }
+    }
+
+    SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) );
+
+    return( POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN );
+
+have_ciphersuite_v2:
+    ssl->session_negotiate->ciphersuite = ssl->ciphersuites[i];
+    ssl_optimize_checksum( ssl, ssl->session_negotiate->ciphersuite );
+
+    /*
+     * SSLv2 Client Hello relevant renegotiation security checks
+     */
+    if( ssl->secure_renegotiation == SSL_LEGACY_RENEGOTIATION &&
+        ssl->allow_legacy_renegotiation == SSL_LEGACY_BREAK_HANDSHAKE )
+    {
+        SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) );
+
+        if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 )
+            return( ret );
+
+        return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+
+    ssl->in_left = 0;
+    ssl->state++;
+
+    SSL_DEBUG_MSG( 2, ( "<= parse client hello v2" ) );
+
+    return( 0 );
+}
+#endif /* POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO */
+
 static int ssl_parse_client_hello( ssl_context *ssl )
 {
     int ret;
@@ -214,6 +424,11 @@
 
     buf = ssl->in_hdr;
 
+#if defined(POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
+    if( ( buf[0] & 0x80 ) != 0 )
+        return ssl_parse_client_hello_v2( ssl );
+#endif
+
     SSL_DEBUG_BUF( 4, "record header", buf, 5 );
 
     SSL_DEBUG_MSG( 3, ( "client hello v3, message type: %d",
@@ -443,6 +658,16 @@
 
 have_ciphersuite:
     ssl->session_negotiate->ciphersuite = ssl->ciphersuites[i];
+    ssl->transform_negotiate->ciphersuite_info =
+        ssl_ciphersuite_from_id( ssl->ciphersuites[i] );
+
+    if( ssl->transform_negotiate->ciphersuite_info == NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "ciphersuite info for %02x not found",
+                          ssl->ciphersuites[i] ) );
+        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+    }
+
     ssl_optimize_checksum( ssl, ssl->session_negotiate->ciphersuite );
 
     ext = buf + 44 + sess_len + ciph_len + comp_len;
@@ -796,18 +1021,8 @@
 
     SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) );
 
-    if( ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_DES_CBC_SHA &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 &&
-        ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 )
+    if( ssl->transform_negotiate->ciphersuite_info->key_exchange !=
+        POLARSSL_KEY_EXCHANGE_DHE_RSA )
     {
         SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) );
         ssl->state++;
@@ -1073,18 +1288,8 @@
         return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE );
     }
 
-    if( ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_DES_CBC_SHA ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ||
-        ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 )
+    if( ssl->transform_negotiate->ciphersuite_info->key_exchange ==
+        POLARSSL_KEY_EXCHANGE_DHE_RSA )
     {
 #if !defined(POLARSSL_DHM_C)
         SSL_DEBUG_MSG( 1, ( "support for dhm is not available" ) );
@@ -1293,121 +1498,113 @@
 }
 
 /*
- * SSL handshake -- server side
+ * SSL handshake -- server side -- single step
  */
-int ssl_handshake_server( ssl_context *ssl )
+int ssl_handshake_server_step( ssl_context *ssl )
 {
     int ret = 0;
 
-    SSL_DEBUG_MSG( 2, ( "=> handshake server" ) );
+    if( ssl->state == SSL_HANDSHAKE_OVER )
+        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
 
-    while( ssl->state != SSL_HANDSHAKE_OVER )
+    SSL_DEBUG_MSG( 2, ( "server state: %d", ssl->state ) );
+
+    if( ( ret = ssl_flush_output( ssl ) ) != 0 )
+        return( ret );
+
+    switch( ssl->state )
     {
-        SSL_DEBUG_MSG( 2, ( "server state: %d", ssl->state ) );
-
-        if( ( ret = ssl_flush_output( ssl ) ) != 0 )
+        case SSL_HELLO_REQUEST:
+            ssl->state = SSL_CLIENT_HELLO;
             break;
 
-        switch( ssl->state )
-        {
-            case SSL_HELLO_REQUEST:
-                ssl->state = SSL_CLIENT_HELLO;
-                break;
-
-            /*
-             *  <==   ClientHello
-             */
-            case SSL_CLIENT_HELLO:
-                ret = ssl_parse_client_hello( ssl );
-                break;
-
-            /*
-             *  ==>   ServerHello
-             *        Certificate
-             *      ( ServerKeyExchange  )
-             *      ( CertificateRequest )
-             *        ServerHelloDone
-             */
-            case SSL_SERVER_HELLO:
-                ret = ssl_write_server_hello( ssl );
-                break;
-
-            case SSL_SERVER_CERTIFICATE:
-                ret = ssl_write_certificate( ssl );
-                break;
-
-            case SSL_SERVER_KEY_EXCHANGE:
-                ret = ssl_write_server_key_exchange( ssl );
-                break;
-
-            case SSL_CERTIFICATE_REQUEST:
-                ret = ssl_write_certificate_request( ssl );
-                break;
-
-            case SSL_SERVER_HELLO_DONE:
-                ret = ssl_write_server_hello_done( ssl );
-                break;
-
-            /*
-             *  <== ( Certificate/Alert  )
-             *        ClientKeyExchange
-             *      ( CertificateVerify  )
-             *        ChangeCipherSpec
-             *        Finished
-             */
-            case SSL_CLIENT_CERTIFICATE:
-                ret = ssl_parse_certificate( ssl );
-                break;
-
-            case SSL_CLIENT_KEY_EXCHANGE:
-                ret = ssl_parse_client_key_exchange( ssl );
-                break;
-
-            case SSL_CERTIFICATE_VERIFY:
-                ret = ssl_parse_certificate_verify( ssl );
-                break;
-
-            case SSL_CLIENT_CHANGE_CIPHER_SPEC:
-                ret = ssl_parse_change_cipher_spec( ssl );
-                break;
-
-            case SSL_CLIENT_FINISHED:
-                ret = ssl_parse_finished( ssl );
-                break;
-
-            /*
-             *  ==>   ChangeCipherSpec
-             *        Finished
-             */
-            case SSL_SERVER_CHANGE_CIPHER_SPEC:
-                ret = ssl_write_change_cipher_spec( ssl );
-                break;
-
-            case SSL_SERVER_FINISHED:
-                ret = ssl_write_finished( ssl );
-                break;
-
-            case SSL_FLUSH_BUFFERS:
-                SSL_DEBUG_MSG( 2, ( "handshake: done" ) );
-                ssl->state = SSL_HANDSHAKE_WRAPUP;
-                break;
-
-            case SSL_HANDSHAKE_WRAPUP:
-                ssl_handshake_wrapup( ssl );
-                break;
-
-            default:
-                SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) );
-                return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
-        }
-
-        if( ret != 0 )
+        /*
+         *  <==   ClientHello
+         */
+        case SSL_CLIENT_HELLO:
+            ret = ssl_parse_client_hello( ssl );
             break;
+
+        /*
+         *  ==>   ServerHello
+         *        Certificate
+         *      ( ServerKeyExchange  )
+         *      ( CertificateRequest )
+         *        ServerHelloDone
+         */
+        case SSL_SERVER_HELLO:
+            ret = ssl_write_server_hello( ssl );
+            break;
+
+        case SSL_SERVER_CERTIFICATE:
+            ret = ssl_write_certificate( ssl );
+            break;
+
+        case SSL_SERVER_KEY_EXCHANGE:
+            ret = ssl_write_server_key_exchange( ssl );
+            break;
+
+        case SSL_CERTIFICATE_REQUEST:
+            ret = ssl_write_certificate_request( ssl );
+            break;
+
+        case SSL_SERVER_HELLO_DONE:
+            ret = ssl_write_server_hello_done( ssl );
+            break;
+
+        /*
+         *  <== ( Certificate/Alert  )
+         *        ClientKeyExchange
+         *      ( CertificateVerify  )
+         *        ChangeCipherSpec
+         *        Finished
+         */
+        case SSL_CLIENT_CERTIFICATE:
+            ret = ssl_parse_certificate( ssl );
+            break;
+
+        case SSL_CLIENT_KEY_EXCHANGE:
+            ret = ssl_parse_client_key_exchange( ssl );
+            break;
+
+        case SSL_CERTIFICATE_VERIFY:
+            ret = ssl_parse_certificate_verify( ssl );
+            break;
+
+        case SSL_CLIENT_CHANGE_CIPHER_SPEC:
+            ret = ssl_parse_change_cipher_spec( ssl );
+            break;
+
+        case SSL_CLIENT_FINISHED:
+            ret = ssl_parse_finished( ssl );
+            break;
+
+        /*
+         *  ==>   ChangeCipherSpec
+         *        Finished
+         */
+        case SSL_SERVER_CHANGE_CIPHER_SPEC:
+            ret = ssl_write_change_cipher_spec( ssl );
+            break;
+
+        case SSL_SERVER_FINISHED:
+            ret = ssl_write_finished( ssl );
+            break;
+
+        case SSL_FLUSH_BUFFERS:
+            SSL_DEBUG_MSG( 2, ( "handshake: done" ) );
+            ssl->state = SSL_HANDSHAKE_WRAPUP;
+            break;
+
+        case SSL_HANDSHAKE_WRAPUP:
+            ssl_handshake_wrapup( ssl );
+            break;
+
+        default:
+            SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) );
+            return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
     }
 
-    SSL_DEBUG_MSG( 2, ( "<= handshake server" ) );
-
     return( ret );
 }
-
 #endif
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index e0a64ab..08880be 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -1,7 +1,7 @@
 /*
  *  SSLv3/TLSv1 shared functions
  *
- *  Copyright (C) 2006-2012, Brainspark B.V.
+ *  Copyright (C) 2006-2013, Brainspark B.V.
  *
  *  This file is part of PolarSSL (http://www.polarssl.org)
  *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
@@ -57,8 +57,12 @@
 #if defined(POLARSSL_SSL_HW_RECORD_ACCEL)
 int (*ssl_hw_record_init)(ssl_context *ssl,
                        const unsigned char *key_enc, const unsigned char *key_dec,
+                       size_t keylen,
                        const unsigned char *iv_enc,  const unsigned char *iv_dec,
-                       const unsigned char *mac_enc, const unsigned char *mac_dec) = NULL;
+                       size_t ivlen,
+                       const unsigned char *mac_enc, const unsigned char *mac_dec,
+                       size_t maclen) = NULL;
+int (*ssl_hw_record_activate)(ssl_context *ssl, int direction) = NULL;
 int (*ssl_hw_record_reset)(ssl_context *ssl) = NULL;
 int (*ssl_hw_record_write)(ssl_context *ssl) = NULL;
 int (*ssl_hw_record_read)(ssl_context *ssl) = NULL;
@@ -298,13 +302,34 @@
     unsigned char keyblk[256];
     unsigned char *key1;
     unsigned char *key2;
+    unsigned char *mac_enc;
+    unsigned char *mac_dec;
     unsigned int iv_copy_len;
+    const cipher_info_t *cipher_info;
+    const md_info_t *md_info;
+
     ssl_session *session = ssl->session_negotiate;
     ssl_transform *transform = ssl->transform_negotiate;
     ssl_handshake_params *handshake = ssl->handshake;
 
     SSL_DEBUG_MSG( 2, ( "=> derive keys" ) );
 
+    cipher_info = cipher_info_from_type( transform->ciphersuite_info->cipher );
+    if( cipher_info == NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "cipher info for %d not found", 
+                            transform->ciphersuite_info->cipher ) );
+        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+    }
+
+    md_info = md_info_from_type( transform->ciphersuite_info->mac );
+    if( md_info == NULL )
+    {
+        SSL_DEBUG_MSG( 1, ( "md info for %d not found", 
+                            transform->ciphersuite_info->mac ) );
+        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+    }
+
     /*
      * Set appropriate PRF function and other SSL / TLS / TLS1.2 functions
      */
@@ -394,130 +419,38 @@
     /*
      * Determine the appropriate key, IV and MAC length.
      */
-    switch( session->ciphersuite )
+
+    if( cipher_info->mode == POLARSSL_MODE_GCM )
     {
-#if defined(POLARSSL_ARC4_C)
-        case TLS_RSA_WITH_RC4_128_MD5:
-            transform->keylen = 16; transform->minlen = 16;
-            transform->ivlen  =  0; transform->maclen = 16;
-            break;
+        transform->keylen = cipher_info->key_length;
+        transform->keylen /= 8;
+        transform->minlen = 1;
+        transform->ivlen = 12;
+        transform->fixed_ivlen = 4;
+        transform->maclen = 0;
+    }
+    else
+    {
+        if( md_info->type != POLARSSL_MD_NONE )
+        {
+            md_init_ctx( &transform->md_ctx_enc, md_info );
+            md_init_ctx( &transform->md_ctx_dec, md_info );
 
-        case TLS_RSA_WITH_RC4_128_SHA:
-            transform->keylen = 16; transform->minlen = 20;
-            transform->ivlen  =  0; transform->maclen = 20;
-            break;
-#endif
+            transform->maclen = md_get_size( md_info );
+        }
 
-#if defined(POLARSSL_DES_C)
-        case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
-        case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
-            transform->keylen = 24; transform->minlen = 24;
-            transform->ivlen  =  8; transform->maclen = 20;
-            break;
-#endif
+        transform->keylen = cipher_info->key_length;
+        transform->keylen /= 8;
+        transform->ivlen = cipher_info->iv_size;
 
-#if defined(POLARSSL_AES_C)
-        case TLS_RSA_WITH_AES_128_CBC_SHA:
-        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
-            transform->keylen = 16; transform->minlen = 32;
-            transform->ivlen  = 16; transform->maclen = 20;
-            break;
-
-        case TLS_RSA_WITH_AES_256_CBC_SHA:
-        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
-            transform->keylen = 32; transform->minlen = 32;
-            transform->ivlen  = 16; transform->maclen = 20;
-            break;
-
-#if defined(POLARSSL_SHA2_C)
-        case TLS_RSA_WITH_AES_128_CBC_SHA256:
-        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
-            transform->keylen = 16; transform->minlen = 32;
-            transform->ivlen  = 16; transform->maclen = 32;
-            break;
-
-        case TLS_RSA_WITH_AES_256_CBC_SHA256:
-        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
-            transform->keylen = 32; transform->minlen = 32;
-            transform->ivlen  = 16; transform->maclen = 32;
-            break;
-#endif
-#if defined(POLARSSL_GCM_C)
-        case TLS_RSA_WITH_AES_128_GCM_SHA256:
-        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
-            transform->keylen = 16; transform->minlen = 1;
-            transform->ivlen  = 12; transform->maclen = 0;
-            transform->fixed_ivlen = 4;
-            break;
-
-        case TLS_RSA_WITH_AES_256_GCM_SHA384:
-        case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
-            transform->keylen = 32; transform->minlen = 1;
-            transform->ivlen  = 12; transform->maclen = 0;
-            transform->fixed_ivlen = 4;
-            break;
-#endif
-#endif
-
-#if defined(POLARSSL_CAMELLIA_C)
-        case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
-        case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
-            transform->keylen = 16; transform->minlen = 32;
-            transform->ivlen  = 16; transform->maclen = 20;
-            break;
-
-        case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
-        case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
-            transform->keylen = 32; transform->minlen = 32;
-            transform->ivlen  = 16; transform->maclen = 20;
-            break;
-
-#if defined(POLARSSL_SHA2_C)
-        case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
-        case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
-            transform->keylen = 16; transform->minlen = 32;
-            transform->ivlen  = 16; transform->maclen = 32;
-            break;
-
-        case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
-        case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
-            transform->keylen = 32; transform->minlen = 32;
-            transform->ivlen  = 16; transform->maclen = 32;
-            break;
-#endif
-#endif
-
-#if defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES)
-#if defined(POLARSSL_CIPHER_NULL_CIPHER)
-        case TLS_RSA_WITH_NULL_MD5:
-            transform->keylen = 0; transform->minlen = 0;
-            transform->ivlen  = 0; transform->maclen = 16;
-            break;
-
-        case TLS_RSA_WITH_NULL_SHA:
-            transform->keylen = 0; transform->minlen = 0;
-            transform->ivlen  = 0; transform->maclen = 20;
-            break;
-
-        case TLS_RSA_WITH_NULL_SHA256:
-            transform->keylen = 0; transform->minlen = 0;
-            transform->ivlen  = 0; transform->maclen = 32;
-            break;
-#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */
-
-#if defined(POLARSSL_DES_C)
-        case TLS_RSA_WITH_DES_CBC_SHA:
-        case TLS_DHE_RSA_WITH_DES_CBC_SHA:
-            transform->keylen =  8; transform->minlen = 8;
-            transform->ivlen  =  8; transform->maclen = 20;
-            break;
-#endif
-#endif /* defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES) */
-
-        default:
-            SSL_DEBUG_MSG( 1, ( "ciphersuite %s is not available",
-                           ssl_get_ciphersuite_name( session->ciphersuite ) ) );
-            return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+        transform->minlen = transform->keylen;
+        if( transform->minlen < transform->maclen )
+        {
+            if( cipher_info->mode == POLARSSL_MODE_STREAM )
+                transform->minlen = transform->maclen;
+            else
+                transform->minlen += transform->keylen;
+        }
     }
 
     SSL_DEBUG_MSG( 3, ( "keylen: %d, minlen: %d, ivlen: %d, maclen: %d",
@@ -532,9 +465,8 @@
         key1 = keyblk + transform->maclen * 2;
         key2 = keyblk + transform->maclen * 2 + transform->keylen;
 
-        memcpy( transform->mac_enc, keyblk,  transform->maclen );
-        memcpy( transform->mac_dec, keyblk + transform->maclen,
-                transform->maclen );
+        mac_enc = keyblk;
+        mac_dec = keyblk + transform->maclen;
 
         /*
          * This is not used in TLS v1.1.
@@ -550,9 +482,8 @@
         key1 = keyblk + transform->maclen * 2 + transform->keylen;
         key2 = keyblk + transform->maclen * 2;
 
-        memcpy( transform->mac_dec, keyblk,  transform->maclen );
-        memcpy( transform->mac_enc, keyblk + transform->maclen,
-                transform->maclen );
+        mac_enc = keyblk + transform->maclen;
+        mac_dec = keyblk;
 
         /*
          * This is not used in TLS v1.1.
@@ -564,6 +495,17 @@
                 iv_copy_len );
     }
 
+    if( ssl->minor_ver == SSL_MINOR_VERSION_0 )
+    {
+        memcpy( transform->mac_enc, mac_enc, transform->maclen );
+        memcpy( transform->mac_dec, mac_dec, transform->maclen );
+    }
+    else
+    {
+        md_hmac_starts( &transform->md_ctx_enc, mac_enc, transform->maclen );
+        md_hmac_starts( &transform->md_ctx_dec, mac_dec, transform->maclen );
+    }
+
 #if defined(POLARSSL_SSL_HW_RECORD_ACCEL)
     if( ssl_hw_record_init != NULL)
     {
@@ -571,9 +513,11 @@
 
         SSL_DEBUG_MSG( 2, ( "going for ssl_hw_record_init()" ) );
 
-        if( ( ret = ssl_hw_record_init( ssl, key1, key2, transform->iv_enc,
-                                        transform->iv_dec, transform->mac_enc,
-                                        transform->mac_dec ) ) != 0 )
+        if( ( ret = ssl_hw_record_init( ssl, key1, key2, transform->keylen,
+                                        transform->iv_enc, transform->iv_dec,
+                                        iv_copy_len,
+                                        mac_enc, mac_dec,
+                                        transform->maclen ) ) != 0 )
         {
             SSL_DEBUG_RET( 1, "ssl_hw_record_init", ret );
             return POLARSSL_ERR_SSL_HW_ACCEL_FAILED;
@@ -581,11 +525,10 @@
     }
 #endif
 
-    switch( session->ciphersuite )
+    switch( cipher_info->type )
     {
 #if defined(POLARSSL_ARC4_C)
-        case TLS_RSA_WITH_RC4_128_MD5:
-        case TLS_RSA_WITH_RC4_128_SHA:
+        case POLARSSL_CIPHER_ARC4_128:
             arc4_setup( (arc4_context *) transform->ctx_enc, key1,
                         transform->keylen );
             arc4_setup( (arc4_context *) transform->ctx_dec, key2,
@@ -594,79 +537,51 @@
 #endif
 
 #if defined(POLARSSL_DES_C)
-        case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
-        case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
-            des3_set3key_enc( (des3_context *) transform->ctx_enc, key1 );
-            des3_set3key_dec( (des3_context *) transform->ctx_dec, key2 );
-            break;
+        case POLARSSL_CIPHER_DES_EDE3_CBC:
+             des3_set3key_enc( (des3_context *) transform->ctx_enc, key1 );
+             des3_set3key_dec( (des3_context *) transform->ctx_dec, key2 );
+             break;
 #endif
 
 #if defined(POLARSSL_AES_C)
-        case TLS_RSA_WITH_AES_128_CBC_SHA:
-        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
-        case TLS_RSA_WITH_AES_128_CBC_SHA256:
-        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
-            aes_setkey_enc( (aes_context *) transform->ctx_enc, key1, 128 );
-            aes_setkey_dec( (aes_context *) transform->ctx_dec, key2, 128 );
+        case POLARSSL_CIPHER_AES_128_CBC:
+        case POLARSSL_CIPHER_AES_256_CBC:
+            aes_setkey_enc( (aes_context*) transform->ctx_enc, key1,
+                            cipher_info->key_length );
+            aes_setkey_dec( (aes_context*) transform->ctx_dec, key2,
+                            cipher_info->key_length );
             break;
-
-        case TLS_RSA_WITH_AES_256_CBC_SHA:
-        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
-        case TLS_RSA_WITH_AES_256_CBC_SHA256:
-        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
-            aes_setkey_enc( (aes_context *) transform->ctx_enc, key1, 256 );
-            aes_setkey_dec( (aes_context *) transform->ctx_dec, key2, 256 );
-            break;
-
-#if defined(POLARSSL_GCM_C)
-        case TLS_RSA_WITH_AES_128_GCM_SHA256:
-        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
-            gcm_init( (gcm_context *) transform->ctx_enc, key1, 128 );
-            gcm_init( (gcm_context *) transform->ctx_dec, key2, 128 );
-            break;
-
-        case TLS_RSA_WITH_AES_256_GCM_SHA384:
-        case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
-            gcm_init( (gcm_context *) transform->ctx_enc, key1, 256 );
-            gcm_init( (gcm_context *) transform->ctx_dec, key2, 256 );
-            break;
-#endif
 #endif
 
 #if defined(POLARSSL_CAMELLIA_C)
-        case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
-        case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
-        case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
-        case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
-            camellia_setkey_enc( (camellia_context *) transform->ctx_enc, key1, 128 );
-            camellia_setkey_dec( (camellia_context *) transform->ctx_dec, key2, 128 );
-            break;
-
-        case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
-        case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
-        case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
-        case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
-            camellia_setkey_enc( (camellia_context *) transform->ctx_enc, key1, 256 );
-            camellia_setkey_dec( (camellia_context *) transform->ctx_dec, key2, 256 );
+        case POLARSSL_CIPHER_CAMELLIA_128_CBC:
+        case POLARSSL_CIPHER_CAMELLIA_256_CBC:
+            camellia_setkey_enc( (camellia_context*) transform->ctx_enc, key1,
+                                 cipher_info->key_length );
+            camellia_setkey_dec( (camellia_context*) transform->ctx_dec, key2,
+                                 cipher_info->key_length );
             break;
 #endif
 
-#if defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES)
-#if defined(POLARSSL_CIPHER_NULL_CIPHER)
-        case TLS_RSA_WITH_NULL_MD5:
-        case TLS_RSA_WITH_NULL_SHA:
-        case TLS_RSA_WITH_NULL_SHA256:
-            break;
-#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */
-
 #if defined(POLARSSL_DES_C)
-        case TLS_RSA_WITH_DES_CBC_SHA:
-        case TLS_DHE_RSA_WITH_DES_CBC_SHA:
+        case POLARSSL_CIPHER_DES_CBC:
             des_setkey_enc( (des_context *) transform->ctx_enc, key1 );
             des_setkey_dec( (des_context *) transform->ctx_dec, key2 );
             break;
 #endif
-#endif /* defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES) */
+
+#if defined(POLARSSL_GCM_C)
+        case POLARSSL_CIPHER_AES_128_GCM:
+        case POLARSSL_CIPHER_AES_256_GCM:
+            gcm_init( (gcm_context *) transform->ctx_enc, key1,
+                      cipher_info->key_length );
+            gcm_init( (gcm_context *) transform->ctx_dec, key2,
+                      cipher_info->key_length );
+            break;
+#endif
+
+        case POLARSSL_CIPHER_NULL:
+            break;
 
         default:
             return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
@@ -793,91 +708,42 @@
 /*
  * SSLv3.0 MAC functions
  */
-static void ssl_mac_md5( unsigned char *secret,
-                         unsigned char *buf, size_t len,
-                         unsigned char *ctr, int type )
+static void ssl_mac( md_context_t *md_ctx, unsigned char *secret,
+                     unsigned char *buf, size_t len,
+                     unsigned char *ctr, int type )
 {
     unsigned char header[11];
     unsigned char padding[48];
-    md5_context md5;
+    int padlen = 0;
+    int md_size = md_get_size( md_ctx->md_info );
+    int md_type = md_get_type( md_ctx->md_info );
+
+    if( md_type == POLARSSL_MD_MD5 )
+        padlen = 48;
+    else if( md_type == POLARSSL_MD_SHA1 )
+        padlen = 40;
+    else if( md_type == POLARSSL_MD_SHA256 )
+        padlen = 32;
 
     memcpy( header, ctr, 8 );
     header[ 8] = (unsigned char)  type;
     header[ 9] = (unsigned char)( len >> 8 );
     header[10] = (unsigned char)( len      );
 
-    memset( padding, 0x36, 48 );
-    md5_starts( &md5 );
-    md5_update( &md5, secret,  16 );
-    md5_update( &md5, padding, 48 );
-    md5_update( &md5, header,  11 );
-    md5_update( &md5, buf,  len );
-    md5_finish( &md5, buf + len );
+    memset( padding, 0x36, padlen );
+    md_starts( md_ctx );
+    md_update( md_ctx, secret,  md_size );
+    md_update( md_ctx, padding, padlen  );
+    md_update( md_ctx, header,  11      );
+    md_update( md_ctx, buf,     len     );
+    md_finish( md_ctx, buf +    len     );
 
-    memset( padding, 0x5C, 48 );
-    md5_starts( &md5 );
-    md5_update( &md5, secret,  16 );
-    md5_update( &md5, padding, 48 );
-    md5_update( &md5, buf + len, 16 );
-    md5_finish( &md5, buf + len );
-}
-
-static void ssl_mac_sha1( unsigned char *secret,
-                          unsigned char *buf, size_t len,
-                          unsigned char *ctr, int type )
-{
-    unsigned char header[11];
-    unsigned char padding[40];
-    sha1_context sha1;
-
-    memcpy( header, ctr, 8 );
-    header[ 8] = (unsigned char)  type;
-    header[ 9] = (unsigned char)( len >> 8 );
-    header[10] = (unsigned char)( len      );
-
-    memset( padding, 0x36, 40 );
-    sha1_starts( &sha1 );
-    sha1_update( &sha1, secret,  20 );
-    sha1_update( &sha1, padding, 40 );
-    sha1_update( &sha1, header,  11 );
-    sha1_update( &sha1, buf,  len );
-    sha1_finish( &sha1, buf + len );
-
-    memset( padding, 0x5C, 40 );
-    sha1_starts( &sha1 );
-    sha1_update( &sha1, secret,  20 );
-    sha1_update( &sha1, padding, 40 );
-    sha1_update( &sha1, buf + len, 20 );
-    sha1_finish( &sha1, buf + len );
-}
-
-static void ssl_mac_sha2( unsigned char *secret,
-                          unsigned char *buf, size_t len,
-                          unsigned char *ctr, int type )
-{
-    unsigned char header[11];
-    unsigned char padding[32];
-    sha2_context sha2;
-
-    memcpy( header, ctr, 8 );
-    header[ 8] = (unsigned char)  type;
-    header[ 9] = (unsigned char)( len >> 8 );
-    header[10] = (unsigned char)( len      );
-
-    memset( padding, 0x36, 32 );
-    sha2_starts( &sha2, 0 );
-    sha2_update( &sha2, secret,  32 );
-    sha2_update( &sha2, padding, 32 );
-    sha2_update( &sha2, header,  11 );
-    sha2_update( &sha2, buf,  len );
-    sha2_finish( &sha2, buf + len );
-
-    memset( padding, 0x5C, 32 );
-    sha2_starts( &sha2, 0 );
-    sha2_update( &sha2, secret,  32 );
-    sha2_update( &sha2, padding, 32 );
-    sha2_update( &sha2, buf + len, 32 );
-    sha2_finish( &sha2, buf + len );
+    memset( padding, 0x5C, padlen );
+    md_starts( md_ctx );
+    md_update( md_ctx, secret,    md_size );
+    md_update( md_ctx, padding,   padlen  );
+    md_update( md_ctx, buf + len, md_size );
+    md_finish( md_ctx, buf + len          );
 }
 
 /*
@@ -894,60 +760,19 @@
      */
     if( ssl->minor_ver == SSL_MINOR_VERSION_0 )
     {
-        if( ssl->transform_out->maclen == 16 )
-             ssl_mac_md5( ssl->transform_out->mac_enc,
-                          ssl->out_msg, ssl->out_msglen,
-                          ssl->out_ctr, ssl->out_msgtype );
-        else if( ssl->transform_out->maclen == 20 )
-            ssl_mac_sha1( ssl->transform_out->mac_enc,
-                          ssl->out_msg, ssl->out_msglen,
-                          ssl->out_ctr, ssl->out_msgtype );
-        else if( ssl->transform_out->maclen == 32 )
-            ssl_mac_sha2( ssl->transform_out->mac_enc,
-                          ssl->out_msg, ssl->out_msglen,
-                          ssl->out_ctr, ssl->out_msgtype );
-        else if( ssl->transform_out->maclen != 0 )
-        {
-            SSL_DEBUG_MSG( 1, ( "invalid MAC len: %d",
-                                ssl->transform_out->maclen ) );
-            return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
-        }
+        ssl_mac( &ssl->transform_out->md_ctx_enc,
+                  ssl->transform_out->mac_enc,
+                  ssl->out_msg, ssl->out_msglen,
+                  ssl->out_ctr, ssl->out_msgtype );
     }
     else
     {
-        if( ssl->transform_out->maclen == 16 )
-        {
-            md5_context ctx;
-            md5_hmac_starts( &ctx, ssl->transform_out->mac_enc, 16 );
-            md5_hmac_update( &ctx, ssl->out_ctr, 13 );
-            md5_hmac_update( &ctx, ssl->out_msg, ssl->out_msglen );
-            md5_hmac_finish( &ctx, ssl->out_msg + ssl->out_msglen );
-            memset( &ctx, 0, sizeof(md5_context));
-        }
-        else if( ssl->transform_out->maclen == 20 )
-        {
-            sha1_context ctx;
-            sha1_hmac_starts( &ctx, ssl->transform_out->mac_enc, 20 );
-            sha1_hmac_update( &ctx, ssl->out_ctr, 13 );
-            sha1_hmac_update( &ctx, ssl->out_msg, ssl->out_msglen );
-            sha1_hmac_finish( &ctx, ssl->out_msg + ssl->out_msglen );
-            memset( &ctx, 0, sizeof(sha1_context));
-        }
-        else if( ssl->transform_out->maclen == 32 )
-        {
-            sha2_context ctx;
-            sha2_hmac_starts( &ctx, ssl->transform_out->mac_enc, 32, 0 );
-            sha2_hmac_update( &ctx, ssl->out_ctr, 13 );
-            sha2_hmac_update( &ctx, ssl->out_msg, ssl->out_msglen );
-            sha2_hmac_finish( &ctx, ssl->out_msg + ssl->out_msglen );
-            memset( &ctx, 0, sizeof(sha2_context));
-        }
-        else if( ssl->transform_out->maclen != 0 )
-        {
-            SSL_DEBUG_MSG( 1, ( "invalid MAC len: %d",
-                                ssl->transform_out->maclen ) );
-            return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
-        }
+        md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_ctr, 13 );
+        md_hmac_update( &ssl->transform_out->md_ctx_enc,
+                         ssl->out_msg, ssl->out_msglen );
+        md_hmac_finish( &ssl->transform_out->md_ctx_enc,
+                         ssl->out_msg + ssl->out_msglen );
+        md_hmac_reset( &ssl->transform_out->md_ctx_enc );
     }
 
     SSL_DEBUG_BUF( 4, "computed mac",
@@ -955,7 +780,15 @@
 
     ssl->out_msglen += ssl->transform_out->maclen;
 
-    if( ssl->transform_out->ivlen == 0 )
+#if defined(POLARSSL_CIPHER_NULL_CIPHER)
+    if( ssl->transform_out->ciphersuite_info->cipher == POLARSSL_CIPHER_NULL )
+    {
+        padlen = 0;
+    }
+    else
+#endif /* POLARSSL_CIPHER_NULL_CIPHER */
+#if defined(POLARSSL_ARC4_C)
+    if( ssl->transform_out->ciphersuite_info->cipher == POLARSSL_CIPHER_ARC4_128 )
     {
         padlen = 0;
 
@@ -966,25 +799,15 @@
         SSL_DEBUG_BUF( 4, "before encrypt: output payload",
                        ssl->out_msg, ssl->out_msglen );
 
-#if defined(POLARSSL_ARC4_C)
-        if( ssl->session_out->ciphersuite == TLS_RSA_WITH_RC4_128_MD5 ||
-            ssl->session_out->ciphersuite == TLS_RSA_WITH_RC4_128_SHA )
-        {
-            arc4_crypt( (arc4_context *) ssl->transform_out->ctx_enc,
-                        ssl->out_msglen, ssl->out_msg,
-                        ssl->out_msg );
-        } else
-#endif
-#if defined(POLARSSL_CIPHER_NULL_CIPHER)
-        if( ssl->session_out->ciphersuite == TLS_RSA_WITH_NULL_MD5 ||
-            ssl->session_out->ciphersuite == TLS_RSA_WITH_NULL_SHA ||
-            ssl->session_out->ciphersuite == TLS_RSA_WITH_NULL_SHA256 )
-        {
-        } else
-#endif
-        return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+        arc4_crypt( (arc4_context *) ssl->transform_out->ctx_enc,
+                    ssl->out_msglen, ssl->out_msg,
+                    ssl->out_msg );
     }
-    else if( ssl->transform_out->ivlen == 12 )
+    else
+#endif /* POLARSSL_ARC4_C */
+#if defined(POLARSSL_GCM_C)
+    if( ssl->transform_out->ciphersuite_info->cipher == POLARSSL_CIPHER_AES_128_GCM ||
+        ssl->transform_out->ciphersuite_info->cipher == POLARSSL_CIPHER_AES_256_GCM )
     {
         size_t enc_msglen;
         unsigned char *enc_msg;
@@ -1004,68 +827,51 @@
         SSL_DEBUG_BUF( 4, "additional data used for AEAD",
                        add_data, 13 );
 
-#if defined(POLARSSL_AES_C) && defined(POLARSSL_GCM_C)
-
-        if( ssl->session_out->ciphersuite == TLS_RSA_WITH_AES_128_GCM_SHA256 ||
-            ssl->session_out->ciphersuite == TLS_RSA_WITH_AES_256_GCM_SHA384 ||
-            ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ||
-            ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 )
-        {
-            /*
-             * Generate IV
-             */
-            ret = ssl->f_rng( ssl->p_rng,
-                        ssl->transform_out->iv_enc + ssl->transform_out->fixed_ivlen,
-                        ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen );
-            if( ret != 0 )
-                return( ret );
-
-            /*
-             * Shift message for ivlen bytes and prepend IV
-             */
-            memmove( ssl->out_msg + ssl->transform_out->ivlen -
-                     ssl->transform_out->fixed_ivlen,
-                     ssl->out_msg, ssl->out_msglen );
-            memcpy( ssl->out_msg,
+        /*
+         * Generate IV
+         */
+        ret = ssl->f_rng( ssl->p_rng,
                     ssl->transform_out->iv_enc + ssl->transform_out->fixed_ivlen,
-                    ssl->transform_out->ivlen  - ssl->transform_out->fixed_ivlen );
+                    ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen );
+        if( ret != 0 )
+            return( ret );
 
-            /*
-             * Fix pointer positions and message length with added IV
-             */
-            enc_msg = ssl->out_msg + ssl->transform_out->ivlen -
-                      ssl->transform_out->fixed_ivlen;
-            enc_msglen = ssl->out_msglen;
-            ssl->out_msglen += ssl->transform_out->ivlen -
-                               ssl->transform_out->fixed_ivlen;
+        memcpy( ssl->out_iv,
+                ssl->transform_out->iv_enc + ssl->transform_out->fixed_ivlen,
+                ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen );
 
-            SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, "
-                                "including %d bytes of padding",
-                           ssl->out_msglen, 0 ) );
+        /*
+         * Fix pointer positions and message length with added IV
+         */
+        enc_msg = ssl->out_msg;
+        enc_msglen = ssl->out_msglen;
+        ssl->out_msglen += ssl->transform_out->ivlen -
+                           ssl->transform_out->fixed_ivlen;
 
-            SSL_DEBUG_BUF( 4, "before encrypt: output payload",
-                           ssl->out_msg, ssl->out_msglen );
+        SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, "
+                            "including %d bytes of padding",
+                       ssl->out_msglen, 0 ) );
 
-            /*
-             * Adjust for tag
-             */
-            ssl->out_msglen += 16;
-            
-            gcm_crypt_and_tag( (gcm_context *) ssl->transform_out->ctx_enc,
-                    GCM_ENCRYPT, enc_msglen,
-                    ssl->transform_out->iv_enc, ssl->transform_out->ivlen,
-                    add_data, 13,
-                    enc_msg, enc_msg,
-                    16, enc_msg + enc_msglen );
+        SSL_DEBUG_BUF( 4, "before encrypt: output payload",
+                       ssl->out_msg, ssl->out_msglen );
 
-            SSL_DEBUG_BUF( 4, "after encrypt: tag",
-                           enc_msg + enc_msglen, 16 );
+        /*
+         * Adjust for tag
+         */
+        ssl->out_msglen += 16;
 
-        } else
-#endif
-        return( ret );
+        gcm_crypt_and_tag( (gcm_context *) ssl->transform_out->ctx_enc,
+                GCM_ENCRYPT, enc_msglen,
+                ssl->transform_out->iv_enc, ssl->transform_out->ivlen,
+                add_data, 13,
+                enc_msg, enc_msg,
+                16, enc_msg + enc_msglen );
+
+        SSL_DEBUG_BUF( 4, "after encrypt: tag",
+                       enc_msg + enc_msglen, 16 );
     }
     else
+#endif /* POLARSSL_GCM_C */
     {
         unsigned char *enc_msg;
         size_t enc_msglen;
@@ -1097,18 +903,13 @@
             if( ret != 0 )
                 return( ret );
 
-            /*
-             * Shift message for ivlen bytes and prepend IV
-             */
-            memmove( ssl->out_msg + ssl->transform_out->ivlen, ssl->out_msg,
-                     ssl->out_msglen );
-            memcpy( ssl->out_msg, ssl->transform_out->iv_enc,
+            memcpy( ssl->out_iv, ssl->transform_out->iv_enc,
                     ssl->transform_out->ivlen );
 
             /*
              * Fix pointer positions and message length with added IV
              */
-            enc_msg = ssl->out_msg + ssl->transform_out->ivlen;
+            enc_msg = ssl->out_msg;
             enc_msglen = ssl->out_msglen;
             ssl->out_msglen += ssl->transform_out->ivlen;
         }
@@ -1118,62 +919,35 @@
                        ssl->out_msglen, ssl->transform_out->ivlen, padlen + 1 ) );
 
         SSL_DEBUG_BUF( 4, "before encrypt: output payload",
-                       ssl->out_msg, ssl->out_msglen );
+                       ssl->out_iv, ssl->out_msglen );
 
-        switch( ssl->transform_out->ivlen )
+        switch( ssl->transform_out->ciphersuite_info->cipher )
         {
-#if defined(POLARSSL_DES_C)
-            case  8:
-#if defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES)
-                if( ssl->session_out->ciphersuite == TLS_RSA_WITH_DES_CBC_SHA ||
-                    ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_DES_CBC_SHA )
-                {
-                    des_crypt_cbc( (des_context *) ssl->transform_out->ctx_enc,
-                                   DES_ENCRYPT, enc_msglen,
-                                   ssl->transform_out->iv_enc, enc_msg, enc_msg );
-                }
-                else
-#endif
-                    des3_crypt_cbc( (des3_context *) ssl->transform_out->ctx_enc,
-                                    DES_ENCRYPT, enc_msglen,
+            case POLARSSL_CIPHER_DES_CBC:
+                des_crypt_cbc( (des_context *) ssl->transform_out->ctx_enc,
+                               DES_ENCRYPT, enc_msglen,
+                               ssl->transform_out->iv_enc, enc_msg, enc_msg );
+                break;
+
+            case POLARSSL_CIPHER_DES_EDE3_CBC:
+                des3_crypt_cbc( (des3_context *) ssl->transform_out->ctx_enc,
+                               DES_ENCRYPT, enc_msglen,
+                               ssl->transform_out->iv_enc, enc_msg, enc_msg );
+                break;
+
+            case POLARSSL_CIPHER_AES_128_CBC:
+            case POLARSSL_CIPHER_AES_256_CBC:
+                aes_crypt_cbc( (aes_context *) ssl->transform_out->ctx_enc,
+                               AES_ENCRYPT, enc_msglen,
+                               ssl->transform_out->iv_enc, enc_msg, enc_msg );
+                break;
+
+            case POLARSSL_CIPHER_CAMELLIA_128_CBC:
+            case POLARSSL_CIPHER_CAMELLIA_256_CBC:
+                camellia_crypt_cbc( (camellia_context *) ssl->transform_out->ctx_enc,
+                                    CAMELLIA_ENCRYPT, enc_msglen,
                                     ssl->transform_out->iv_enc, enc_msg, enc_msg );
                 break;
-#endif
-
-            case 16:
-#if defined(POLARSSL_AES_C)
-        if ( ssl->session_out->ciphersuite == TLS_RSA_WITH_AES_128_CBC_SHA ||
-             ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA ||
-             ssl->session_out->ciphersuite == TLS_RSA_WITH_AES_256_CBC_SHA ||
-             ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA ||
-             ssl->session_out->ciphersuite == TLS_RSA_WITH_AES_128_CBC_SHA256 ||
-             ssl->session_out->ciphersuite == TLS_RSA_WITH_AES_256_CBC_SHA256 ||
-             ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ||
-             ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 )
-        {
-                    aes_crypt_cbc( (aes_context *) ssl->transform_out->ctx_enc,
-                        AES_ENCRYPT, enc_msglen,
-                        ssl->transform_out->iv_enc, enc_msg, enc_msg);
-                    break;
-        }
-#endif
-
-#if defined(POLARSSL_CAMELLIA_C)
-        if ( ssl->session_out->ciphersuite == TLS_RSA_WITH_CAMELLIA_128_CBC_SHA ||
-             ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA ||
-             ssl->session_out->ciphersuite == TLS_RSA_WITH_CAMELLIA_256_CBC_SHA ||
-             ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA ||
-             ssl->session_out->ciphersuite == TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 ||
-             ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 ||
-             ssl->session_out->ciphersuite == TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 ||
-             ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 )
-        {
-                    camellia_crypt_cbc( (camellia_context *) ssl->transform_out->ctx_enc,
-                        CAMELLIA_ENCRYPT, enc_msglen,
-                        ssl->transform_out->iv_enc, enc_msg, enc_msg );
-                    break;
-        }
-#endif
 
             default:
                 return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
@@ -1196,7 +970,7 @@
 
 static int ssl_decrypt_buf( ssl_context *ssl )
 {
-    size_t i, padlen;
+    size_t i, padlen = 0, correct = 1;
     unsigned char tmp[POLARSSL_SSL_MAX_MAC_SIZE];
 
     SSL_DEBUG_MSG( 2, ( "=> decrypt buf" ) );
@@ -1208,28 +982,27 @@
         return( POLARSSL_ERR_SSL_INVALID_MAC );
     }
 
-    if( ssl->transform_in->ivlen == 0 )
+#if defined(POLARSSL_CIPHER_NULL_CIPHER)
+    if( ssl->transform_in->ciphersuite_info->cipher == POLARSSL_CIPHER_NULL )
     {
-#if defined(POLARSSL_ARC4_C)
         padlen = 0;
-        if( ssl->session_in->ciphersuite == TLS_RSA_WITH_RC4_128_MD5 ||
-            ssl->session_in->ciphersuite == TLS_RSA_WITH_RC4_128_SHA )
-        {
-            arc4_crypt( (arc4_context *) ssl->transform_in->ctx_dec,
+    }
+    else
+#endif /* POLARSSL_CIPHER_NULL_CIPHER */
+#if defined(POLARSSL_ARC4_C)
+    if( ssl->transform_in->ciphersuite_info->cipher == POLARSSL_CIPHER_ARC4_128 )
+    {
+        padlen = 0;
+
+        arc4_crypt( (arc4_context *) ssl->transform_in->ctx_dec,
                     ssl->in_msglen, ssl->in_msg,
                     ssl->in_msg );
-        } else
-#endif
-#if defined(POLARSSL_CIPHER_NULL_CIPHER)
-        if( ssl->session_in->ciphersuite == TLS_RSA_WITH_NULL_MD5 ||
-            ssl->session_in->ciphersuite == TLS_RSA_WITH_NULL_SHA ||
-            ssl->session_in->ciphersuite == TLS_RSA_WITH_NULL_SHA256 )
-        {
-        } else
-#endif
-        return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
     }
-    else if( ssl->transform_in->ivlen == 12 )
+    else
+#endif /* POLARSSL_ARC4_C */
+#if defined(POLARSSL_GCM_C)
+    if( ssl->transform_in->ciphersuite_info->cipher == POLARSSL_CIPHER_AES_128_GCM ||
+        ssl->transform_in->ciphersuite_info->cipher == POLARSSL_CIPHER_AES_256_GCM )
     {
         unsigned char *dec_msg;
         unsigned char *dec_msg_result;
@@ -1239,69 +1012,60 @@
 
         padlen = 0;
 
-#if defined(POLARSSL_AES_C) && defined(POLARSSL_GCM_C)
-        if( ssl->session_in->ciphersuite == TLS_RSA_WITH_AES_128_GCM_SHA256 ||
-            ssl->session_in->ciphersuite == TLS_RSA_WITH_AES_256_GCM_SHA384 ||
-            ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ||
-            ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 )
+        dec_msglen = ssl->in_msglen - ( ssl->transform_in->ivlen -
+                                        ssl->transform_in->fixed_ivlen );
+        dec_msglen -= 16;
+        dec_msg = ssl->in_msg;
+        dec_msg_result = ssl->in_msg;
+        ssl->in_msglen = dec_msglen;
+
+        memcpy( add_data, ssl->in_ctr, 8 );
+        add_data[8]  = ssl->in_msgtype;
+        add_data[9]  = ssl->major_ver;
+        add_data[10] = ssl->minor_ver;
+        add_data[11] = ( ssl->in_msglen >> 8 ) & 0xFF;
+        add_data[12] = ssl->in_msglen & 0xFF;
+
+        SSL_DEBUG_BUF( 4, "additional data used for AEAD",
+                       add_data, 13 );
+
+        memcpy( ssl->transform_in->iv_dec + ssl->transform_in->fixed_ivlen,
+                ssl->in_iv,
+                ssl->transform_in->ivlen - ssl->transform_in->fixed_ivlen );
+
+        SSL_DEBUG_BUF( 4, "IV used", ssl->transform_in->iv_dec,
+                                     ssl->transform_in->ivlen );
+        SSL_DEBUG_BUF( 4, "TAG used", dec_msg + dec_msglen, 16 );
+
+        ret = gcm_auth_decrypt( (gcm_context *) ssl->transform_in->ctx_dec,
+                                 dec_msglen,
+                                 ssl->transform_in->iv_dec,
+                                 ssl->transform_in->ivlen,
+                                 add_data, 13,
+                                 dec_msg + dec_msglen, 16,
+                                 dec_msg, dec_msg_result );
+
+        if( ret != 0 )
         {
-            dec_msglen = ssl->in_msglen - ( ssl->transform_in->ivlen -
-                                            ssl->transform_in->fixed_ivlen );
-            dec_msglen -= 16;
-            dec_msg = ssl->in_msg + ( ssl->transform_in->ivlen -
-                                      ssl->transform_in->fixed_ivlen );
-            dec_msg_result = ssl->in_msg;
-            ssl->in_msglen = dec_msglen;
+            SSL_DEBUG_MSG( 1, ( "AEAD decrypt failed on validation (ret = -0x%02x)",
+                                -ret ) );
 
-            memcpy( add_data, ssl->in_ctr, 8 );
-            add_data[8]  = ssl->in_msgtype;
-            add_data[9]  = ssl->major_ver;
-            add_data[10] = ssl->minor_ver;
-            add_data[11] = ( ssl->in_msglen >> 8 ) & 0xFF;
-            add_data[12] = ssl->in_msglen & 0xFF;
-
-            SSL_DEBUG_BUF( 4, "additional data used for AEAD",
-                           add_data, 13 );
-
-            memcpy( ssl->transform_in->iv_dec + ssl->transform_in->fixed_ivlen,
-                    ssl->in_msg,
-                    ssl->transform_in->ivlen - ssl->transform_in->fixed_ivlen );
-
-            SSL_DEBUG_BUF( 4, "IV used", ssl->transform_in->iv_dec,
-                                         ssl->transform_in->ivlen );
-            SSL_DEBUG_BUF( 4, "TAG used", dec_msg + dec_msglen, 16 );
-
-            memcpy( ssl->transform_in->iv_dec + ssl->transform_in->fixed_ivlen,
-                    ssl->in_msg,
-                    ssl->transform_in->ivlen - ssl->transform_in->fixed_ivlen );
-
-            ret = gcm_auth_decrypt( (gcm_context *) ssl->transform_in->ctx_dec,
-                                     dec_msglen,
-                                     ssl->transform_in->iv_dec,
-                                     ssl->transform_in->ivlen,
-                                     add_data, 13,
-                                     dec_msg + dec_msglen, 16,
-                                     dec_msg, dec_msg_result );
-            
-            if( ret != 0 )
-            {
-                SSL_DEBUG_MSG( 1, ( "AEAD decrypt failed on validation (ret = -0x%02x)",
-                                    -ret ) );
-
-                return( POLARSSL_ERR_SSL_INVALID_MAC );
-            }
-        } else
-#endif
-        return( ret );
+            return( POLARSSL_ERR_SSL_INVALID_MAC );
+        }
     }
     else
+#endif /* POLARSSL_GCM_C */
     {
+        /*
+         * Decrypt and check the padding
+         */
         unsigned char *dec_msg;
         unsigned char *dec_msg_result;
         size_t dec_msglen;
+        size_t minlen = 0;
 
         /*
-         * Decrypt and check the padding
+         * Check immediate ciphertext sanity
          */
         if( ssl->in_msglen % ssl->transform_in->ivlen != 0 )
         {
@@ -1310,6 +1074,17 @@
             return( POLARSSL_ERR_SSL_INVALID_MAC );
         }
 
+        if( ssl->minor_ver >= SSL_MINOR_VERSION_2 )
+            minlen += ssl->transform_in->ivlen;
+
+        if( ssl->in_msglen < minlen + ssl->transform_in->ivlen ||
+            ssl->in_msglen < minlen + ssl->transform_in->maclen + 1 )
+        {
+            SSL_DEBUG_MSG( 1, ( "msglen (%d) < max( ivlen(%d), maclen (%d) + 1 ) ( + expl IV )",
+                           ssl->in_msglen, ssl->transform_in->ivlen, ssl->transform_in->maclen ) );
+            return( POLARSSL_ERR_SSL_INVALID_MAC );
+        }
+
         dec_msglen = ssl->in_msglen;
         dec_msg = ssl->in_msg;
         dec_msg_result = ssl->in_msg;
@@ -1319,68 +1094,40 @@
          */
         if( ssl->minor_ver >= SSL_MINOR_VERSION_2 )
         {
-            dec_msg += ssl->transform_in->ivlen;
             dec_msglen -= ssl->transform_in->ivlen;
             ssl->in_msglen -= ssl->transform_in->ivlen;
 
             for( i = 0; i < ssl->transform_in->ivlen; i++ )
-                ssl->transform_in->iv_dec[i] = ssl->in_msg[i];
+                ssl->transform_in->iv_dec[i] = ssl->in_iv[i];
         }
 
-        switch( ssl->transform_in->ivlen )
+        switch( ssl->transform_in->ciphersuite_info->cipher )
         {
-#if defined(POLARSSL_DES_C)
-            case  8:
-#if defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES)
-                if( ssl->session_in->ciphersuite == TLS_RSA_WITH_DES_CBC_SHA ||
-                    ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_DES_CBC_SHA )
-                {
-                    des_crypt_cbc( (des_context *) ssl->transform_in->ctx_dec,
-                                   DES_DECRYPT, dec_msglen,
-                                   ssl->transform_in->iv_dec, dec_msg, dec_msg_result );
-                }
-                else
-#endif
-                    des3_crypt_cbc( (des3_context *) ssl->transform_in->ctx_dec,
-                        DES_DECRYPT, dec_msglen,
-                        ssl->transform_in->iv_dec, dec_msg, dec_msg_result );
+            case POLARSSL_CIPHER_DES_CBC:
+                des_crypt_cbc( (des_context *) ssl->transform_in->ctx_dec,
+                               DES_DECRYPT, dec_msglen,
+                               ssl->transform_in->iv_dec, dec_msg, dec_msg_result );
                 break;
-#endif
 
-            case 16:
-#if defined(POLARSSL_AES_C)
-        if ( ssl->session_in->ciphersuite == TLS_RSA_WITH_AES_128_CBC_SHA ||
-             ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA ||
-             ssl->session_in->ciphersuite == TLS_RSA_WITH_AES_256_CBC_SHA ||
-             ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA ||
-             ssl->session_in->ciphersuite == TLS_RSA_WITH_AES_128_CBC_SHA256 ||
-             ssl->session_in->ciphersuite == TLS_RSA_WITH_AES_256_CBC_SHA256 ||
-             ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ||
-             ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 )
-        {
-                    aes_crypt_cbc( (aes_context *) ssl->transform_in->ctx_dec,
-                       AES_DECRYPT, dec_msglen,
-                       ssl->transform_in->iv_dec, dec_msg, dec_msg_result );
-                    break;
-        }
-#endif
+            case POLARSSL_CIPHER_DES_EDE3_CBC:
+                des3_crypt_cbc( (des3_context *) ssl->transform_in->ctx_dec,
+                               DES_DECRYPT, dec_msglen,
+                               ssl->transform_in->iv_dec, dec_msg, dec_msg_result );
+                break;
 
-#if defined(POLARSSL_CAMELLIA_C)
-        if ( ssl->session_in->ciphersuite == TLS_RSA_WITH_CAMELLIA_128_CBC_SHA ||
-             ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA ||
-             ssl->session_in->ciphersuite == TLS_RSA_WITH_CAMELLIA_256_CBC_SHA ||
-             ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA ||
-             ssl->session_in->ciphersuite == TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 ||
-             ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 ||
-             ssl->session_in->ciphersuite == TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 ||
-             ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 )
-        {
-                    camellia_crypt_cbc( (camellia_context *) ssl->transform_in->ctx_dec,
-                       CAMELLIA_DECRYPT, dec_msglen,
-                       ssl->transform_in->iv_dec, dec_msg, dec_msg_result );
-                    break;
-        }
-#endif
+            case POLARSSL_CIPHER_AES_128_CBC:
+            case POLARSSL_CIPHER_AES_256_CBC:
+                aes_crypt_cbc( (aes_context *) ssl->transform_in->ctx_dec,
+                               AES_DECRYPT, dec_msglen,
+                               ssl->transform_in->iv_dec, dec_msg, dec_msg_result );
+                break;
+
+            case POLARSSL_CIPHER_CAMELLIA_128_CBC:
+            case POLARSSL_CIPHER_CAMELLIA_256_CBC:
+                camellia_crypt_cbc( (camellia_context *) ssl->transform_in->ctx_dec,
+                                    CAMELLIA_DECRYPT, dec_msglen,
+                                    ssl->transform_in->iv_dec, dec_msg, dec_msg_result );
+                break;
 
             default:
                 return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
@@ -1388,31 +1135,51 @@
 
         padlen = 1 + ssl->in_msg[ssl->in_msglen - 1];
 
+        if( ssl->in_msglen < ssl->transform_in->maclen + padlen )
+        {
+#if defined(POLARSSL_SSL_DEBUG_ALL)
+            SSL_DEBUG_MSG( 1, ( "msglen (%d) < maclen (%d) + padlen (%d)",
+                        ssl->in_msglen, ssl->transform_in->maclen, padlen ) );
+#endif
+            padlen = 0;
+            correct = 0;
+        }
+
         if( ssl->minor_ver == SSL_MINOR_VERSION_0 )
         {
             if( padlen > ssl->transform_in->ivlen )
             {
+#if defined(POLARSSL_SSL_DEBUG_ALL)
                 SSL_DEBUG_MSG( 1, ( "bad padding length: is %d, "
                                     "should be no more than %d",
                                padlen, ssl->transform_in->ivlen ) );
-                padlen = 0;
+#endif
+                correct = 0;
             }
         }
         else
         {
             /*
-             * TLSv1: always check the padding
+             * TLSv1+: always check the padding up to the first failure
+             * and fake check up to 256 bytes of padding
              */
+            size_t pad_count = 0, fake_pad_count = 0;
+            size_t padding_idx = ssl->in_msglen - padlen - 1;
+
             for( i = 1; i <= padlen; i++ )
-            {
-                if( ssl->in_msg[ssl->in_msglen - i] != padlen - 1 )
-                {
-                    SSL_DEBUG_MSG( 1, ( "bad padding byte: should be "
-                                        "%02x, but is %02x", padlen - 1,
-                                   ssl->in_msg[ssl->in_msglen - i] ) );
-                    padlen = 0;
-                }
-            }
+                pad_count += ( ssl->in_msg[padding_idx + i] == padlen - 1 );
+
+            for( ; i <= 256; i++ )
+                fake_pad_count += ( ssl->in_msg[padding_idx + i] == padlen - 1 );
+
+            correct &= ( pad_count == padlen ); /* Only 1 on correct padding */
+            correct &= ( pad_count + fake_pad_count < 512 ); /* Always 1 */
+
+#if defined(POLARSSL_SSL_DEBUG_ALL)
+            if( padlen > 0 && correct == 0)
+                SSL_DEBUG_MSG( 1, ( "bad padding byte detected" ) );
+#endif
+            padlen &= correct * 0x1FF;
         }
     }
 
@@ -1422,61 +1189,50 @@
     /*
      * Always compute the MAC (RFC4346, CBCTIME).
      */
-    if( ssl->in_msglen < ssl->transform_in->maclen + padlen )
-    {
-        SSL_DEBUG_MSG( 1, ( "msglen (%d) < maclen (%d) + padlen (%d)",
-                    ssl->in_msglen, ssl->transform_in->maclen, padlen ) );
-        return( POLARSSL_ERR_SSL_INVALID_MAC );
-    }
-
     ssl->in_msglen -= ( ssl->transform_in->maclen + padlen );
 
     ssl->in_hdr[3] = (unsigned char)( ssl->in_msglen >> 8 );
     ssl->in_hdr[4] = (unsigned char)( ssl->in_msglen      );
 
-    memcpy( tmp, ssl->in_msg + ssl->in_msglen, POLARSSL_SSL_MAX_MAC_SIZE );
+    memcpy( tmp, ssl->in_msg + ssl->in_msglen, ssl->transform_in->maclen );
 
     if( ssl->minor_ver == SSL_MINOR_VERSION_0 )
     {
-        if( ssl->transform_in->maclen == 16 )
-             ssl_mac_md5( ssl->transform_in->mac_dec,
-                          ssl->in_msg, ssl->in_msglen,
-                          ssl->in_ctr, ssl->in_msgtype );
-        else if( ssl->transform_in->maclen == 20 )
-            ssl_mac_sha1( ssl->transform_in->mac_dec,
-                          ssl->in_msg, ssl->in_msglen,
-                          ssl->in_ctr, ssl->in_msgtype );
-        else if( ssl->transform_in->maclen == 32 )
-            ssl_mac_sha2( ssl->transform_in->mac_dec,
-                          ssl->in_msg, ssl->in_msglen,
-                          ssl->in_ctr, ssl->in_msgtype );
-        else if( ssl->transform_in->maclen != 0 )
-        {
-            SSL_DEBUG_MSG( 1, ( "invalid MAC len: %d",
-                                ssl->transform_in->maclen ) );
-            return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
-        }
+        ssl_mac( &ssl->transform_in->md_ctx_dec,
+                  ssl->transform_in->mac_dec,
+                  ssl->in_msg, ssl->in_msglen,
+                  ssl->in_ctr, ssl->in_msgtype );
     }
     else
     {
-        if( ssl->transform_in->maclen == 16 )
-             md5_hmac( ssl->transform_in->mac_dec, 16,
-                       ssl->in_ctr,  ssl->in_msglen + 13,
-                       ssl->in_msg + ssl->in_msglen );
-        else if( ssl->transform_in->maclen == 20 )
-            sha1_hmac( ssl->transform_in->mac_dec, 20,
-                       ssl->in_ctr,  ssl->in_msglen + 13,
-                       ssl->in_msg + ssl->in_msglen );
-        else if( ssl->transform_in->maclen == 32 )
-            sha2_hmac( ssl->transform_in->mac_dec, 32,
-                       ssl->in_ctr,  ssl->in_msglen + 13,
-                       ssl->in_msg + ssl->in_msglen, 0 );
-        else if( ssl->transform_in->maclen != 0 )
-        {
-            SSL_DEBUG_MSG( 1, ( "invalid MAC len: %d",
-                                ssl->transform_in->maclen ) );
-            return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
-        }
+        /*
+         * Process MAC and always update for padlen afterwards to make
+         * total time independent of padlen
+         *
+         * extra_run compensates MAC check for padlen 
+         *
+         * Known timing attacks:
+         *  - Lucky Thirteen (http://www.isg.rhul.ac.uk/tls/TLStiming.pdf)
+         *
+         * We use ( ( Lx + 8 ) / 64 ) to handle 'negative Lx' values
+         * correctly. (We round down instead of up, so -56 is the correct
+         * value for our calculations instead of -55)
+         */
+        int j, extra_run = 0;
+        extra_run = ( 13 + ssl->in_msglen + padlen + 8 ) / 64 -
+                    ( 13 + ssl->in_msglen          + 8 ) / 64;
+
+        extra_run &= correct * 0xFF;
+
+        md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_ctr, 13 );
+        md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_msg,
+                         ssl->in_msglen );
+        md_hmac_finish( &ssl->transform_in->md_ctx_dec,
+                         ssl->in_msg + ssl->in_msglen );
+        for( j = 0; j < extra_run; j++ )
+            md_process( &ssl->transform_in->md_ctx_dec, ssl->in_msg );
+
+        md_hmac_reset( &ssl->transform_in->md_ctx_dec );
     }
 
     SSL_DEBUG_BUF( 4, "message  mac", tmp, ssl->transform_in->maclen );
@@ -1486,16 +1242,16 @@
     if( memcmp( tmp, ssl->in_msg + ssl->in_msglen,
                      ssl->transform_in->maclen ) != 0 )
     {
+#if defined(POLARSSL_SSL_DEBUG_ALL)
         SSL_DEBUG_MSG( 1, ( "message mac does not match" ) );
-        return( POLARSSL_ERR_SSL_INVALID_MAC );
+#endif
+        correct = 0;
     }
 
     /*
-     * Finally check the padding length; bad padding
-     * will produce the same error as an invalid MAC.
+     * Finally check the correct flag
      */
-    if( ssl->transform_in->ivlen != 0 && ssl->transform_in->ivlen != 12 &&
-        padlen == 0 )
+    if( correct == 0 )
         return( POLARSSL_ERR_SSL_INVALID_MAC );
 
     if( ssl->in_msglen == 0 )
@@ -1680,22 +1436,7 @@
         SSL_DEBUG_MSG( 2, ( "message length: %d, out_left: %d",
                        5 + ssl->out_msglen, ssl->out_left ) );
 
-        if( ssl->out_msglen < ssl->out_left )
-        {
-            size_t header_left = ssl->out_left - ssl->out_msglen;
-
-            buf = ssl->out_hdr + 5 - header_left;
-            ret = ssl->f_send( ssl->p_send, buf, header_left );
-            
-            SSL_DEBUG_RET( 2, "ssl->f_send (header)", ret );
-
-            if( ret <= 0 )
-                return( ret );
-
-            ssl->out_left -= ret;
-        }
-        
-        buf = ssl->out_msg + ssl->out_msglen - ssl->out_left;
+        buf = ssl->out_hdr + 5 + ssl->out_msglen - ssl->out_left;
         ret = ssl->f_send( ssl->p_send, buf, ssl->out_left );
 
         SSL_DEBUG_RET( 2, "ssl->f_send", ret );
@@ -1755,7 +1496,9 @@
             SSL_DEBUG_RET( 1, "ssl_hw_record_write", ret );
             return POLARSSL_ERR_SSL_HW_ACCEL_FAILED;
         }
-        done = 1;
+
+        if( ret == 0 )
+            done = 1;
     }
 #endif
     if( !done )
@@ -1786,10 +1529,8 @@
                        ssl->out_hdr[0], ssl->out_hdr[1], ssl->out_hdr[2],
                      ( ssl->out_hdr[3] << 8 ) | ssl->out_hdr[4] ) );
 
-        SSL_DEBUG_BUF( 4, "output record header sent to network",
-                       ssl->out_hdr, 5 );
         SSL_DEBUG_BUF( 4, "output record sent to network",
-                       ssl->out_hdr + 32, ssl->out_msglen );
+                       ssl->out_hdr, 5 + ssl->out_msglen );
     }
 
     if( ( ret = ssl_flush_output( ssl ) ) != 0 )
@@ -1809,6 +1550,9 @@
 
     SSL_DEBUG_MSG( 2, ( "=> read record" ) );
 
+    SSL_DEBUG_BUF( 4, "input record from network",
+                   ssl->in_hdr, 5 + ssl->in_msglen );
+
     if( ssl->in_hslen != 0 &&
         ssl->in_hslen < ssl->in_msglen )
     {
@@ -1936,13 +1680,23 @@
             SSL_DEBUG_RET( 1, "ssl_hw_record_read", ret );
             return POLARSSL_ERR_SSL_HW_ACCEL_FAILED;
         }
-        done = 1;
+
+        if( ret == 0 )
+            done = 1;
     }
 #endif
     if( !done && ssl->transform_in != NULL )
     {
         if( ( ret = ssl_decrypt_buf( ssl ) ) != 0 )
         {
+#if defined(POLARSSL_SSL_ALERT_MESSAGES)
+            if( ret == POLARSSL_ERR_SSL_INVALID_MAC )
+            {
+                ssl_send_alert_message( ssl,
+                                        SSL_ALERT_LEVEL_FATAL,
+                                        SSL_ALERT_MSG_BAD_RECORD_MAC );
+            }
+#endif
             SSL_DEBUG_RET( 1, "ssl_decrypt_buf", ret );
             return( ret );
         }
@@ -2710,6 +2464,17 @@
 
     SSL_DEBUG_MSG( 2, ( "=> write finished" ) );
 
+    /*
+     * Set the out_msg pointer to the correct location based on IV length
+     */
+    if( ssl->minor_ver >= SSL_MINOR_VERSION_2 )
+    {
+        ssl->out_msg = ssl->out_iv + ssl->transform_negotiate->ivlen -
+                       ssl->transform_negotiate->fixed_ivlen;
+    }
+    else
+        ssl->out_msg = ssl->out_iv;
+
     ssl->handshake->calc_finished( ssl, ssl->out_msg + 4, ssl->endpoint );
 
     // TODO TLS/1.2 Hash length is determined by cipher suite (Page 63)
@@ -2744,6 +2509,17 @@
     ssl->session_out = ssl->session_negotiate;
     memset( ssl->out_ctr, 0, 8 );
 
+#if defined(POLARSSL_SSL_HW_RECORD_ACCEL)
+    if( ssl_hw_record_activate != NULL)
+    {
+        if( ( ret = ssl_hw_record_activate( ssl, SSL_CHANNEL_OUTBOUND ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_hw_record_activate", ret );
+            return( POLARSSL_ERR_SSL_HW_ACCEL_FAILED );
+        }
+    }
+#endif
+
     if( ( ret = ssl_write_record( ssl ) ) != 0 )
     {
         SSL_DEBUG_RET( 1, "ssl_write_record", ret );
@@ -2773,6 +2549,28 @@
     ssl->session_in = ssl->session_negotiate;
     memset( ssl->in_ctr, 0, 8 );
 
+    /*
+     * Set the in_msg pointer to the correct location based on IV length
+     */
+    if( ssl->minor_ver >= SSL_MINOR_VERSION_2 )
+    {
+        ssl->in_msg = ssl->in_iv + ssl->transform_negotiate->ivlen -
+                      ssl->transform_negotiate->fixed_ivlen;
+    }
+    else
+        ssl->in_msg = ssl->in_iv;
+
+#if defined(POLARSSL_SSL_HW_RECORD_ACCEL)
+    if( ssl_hw_record_activate != NULL)
+    {
+        if( ( ret = ssl_hw_record_activate( ssl, SSL_CHANNEL_INBOUND ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_hw_record_activate", ret );
+            return( POLARSSL_ERR_SSL_HW_ACCEL_FAILED );
+        }
+    }
+#endif
+
     if( ( ret = ssl_read_record( ssl ) ) != 0 )
     {
         SSL_DEBUG_RET( 1, "ssl_read_record", ret );
@@ -2882,7 +2680,7 @@
     ssl->min_major_ver = SSL_MAJOR_VERSION_3;
     ssl->min_minor_ver = SSL_MINOR_VERSION_0;
 
-    ssl->ciphersuites = ssl_default_ciphersuites;
+    ssl->ciphersuites = ssl_list_ciphersuites();
 
 #if defined(POLARSSL_DHM_C)
     if( ( ret = mpi_read_string( &ssl->dhm_P, 16,
@@ -2900,6 +2698,7 @@
      */
     ssl->in_ctr = (unsigned char *) malloc( len );
     ssl->in_hdr = ssl->in_ctr +  8;
+    ssl->in_iv  = ssl->in_ctr + 13;
     ssl->in_msg = ssl->in_ctr + 13;
 
     if( ssl->in_ctr == NULL )
@@ -2910,7 +2709,8 @@
 
     ssl->out_ctr = (unsigned char *) malloc( len );
     ssl->out_hdr = ssl->out_ctr +  8;
-    ssl->out_msg = ssl->out_ctr + 40;
+    ssl->out_iv  = ssl->out_ctr + 13;
+    ssl->out_msg = ssl->out_ctr + 13;
 
     if( ssl->out_ctr == NULL )
     {
@@ -2949,6 +2749,7 @@
 
     ssl->in_offt = NULL;
 
+    ssl->in_msg = ssl->in_ctr + 13;
     ssl->in_msgtype = 0;
     ssl->in_msglen = 0;
     ssl->in_left = 0;
@@ -2956,6 +2757,7 @@
     ssl->in_hslen = 0;
     ssl->nb_zero = 0;
 
+    ssl->out_msg = ssl->out_ctr + 13;
     ssl->out_msgtype = 0;
     ssl->out_msglen = 0;
     ssl->out_left = 0;
@@ -2970,7 +2772,7 @@
     if( ssl_hw_record_reset != NULL)
     {
         SSL_DEBUG_MSG( 2, ( "going for ssl_hw_record_reset()" ) );
-        if( ssl_hw_record_reset( ssl ) != 0 )
+        if( ( ret = ssl_hw_record_reset( ssl ) ) != 0 )
         {
             SSL_DEBUG_RET( 1, "ssl_hw_record_reset", ret );
             return( POLARSSL_ERR_SSL_HW_ACCEL_FAILED );
@@ -2985,6 +2787,13 @@
         ssl->transform = NULL;
     }
 
+    if( ssl->session )
+    {
+        ssl_session_free( ssl->session );
+        free( ssl->session );
+        ssl->session = NULL;
+    }
+
     if( ( ret = ssl_handshake_init( ssl ) ) != 0 )
         return( ret );
 
@@ -3191,220 +3000,11 @@
     return( ssl->verify_result );
 }
 
-const char *ssl_get_ciphersuite_name( const int ciphersuite_id )
-{
-    switch( ciphersuite_id )
-    {
-#if defined(POLARSSL_ARC4_C)
-        case TLS_RSA_WITH_RC4_128_MD5:
-            return( "TLS-RSA-WITH-RC4-128-MD5" );
-
-        case TLS_RSA_WITH_RC4_128_SHA:
-            return( "TLS-RSA-WITH-RC4-128-SHA" );
-#endif
-
-#if defined(POLARSSL_DES_C)
-        case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
-            return( "TLS-RSA-WITH-3DES-EDE-CBC-SHA" );
-
-        case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
-            return( "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA" );
-#endif
-
-#if defined(POLARSSL_AES_C)
-        case TLS_RSA_WITH_AES_128_CBC_SHA:
-            return( "TLS-RSA-WITH-AES-128-CBC-SHA" );
-
-        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
-            return( "TLS-DHE-RSA-WITH-AES-128-CBC-SHA" );
-
-        case TLS_RSA_WITH_AES_256_CBC_SHA:
-            return( "TLS-RSA-WITH-AES-256-CBC-SHA" );
-
-        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
-            return( "TLS-DHE-RSA-WITH-AES-256-CBC-SHA" );
-
-#if defined(POLARSSL_SHA2_C)
-        case TLS_RSA_WITH_AES_128_CBC_SHA256:
-            return( "TLS-RSA-WITH-AES-128-CBC-SHA256" );
-
-        case TLS_RSA_WITH_AES_256_CBC_SHA256:
-            return( "TLS-RSA-WITH-AES-256-CBC-SHA256" );
-
-        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
-            return( "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256" );
-
-        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
-            return( "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256" );
-#endif
-
-#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C)
-        case TLS_RSA_WITH_AES_128_GCM_SHA256:
-            return( "TLS-RSA-WITH-AES-128-GCM-SHA256" );
-
-        case TLS_RSA_WITH_AES_256_GCM_SHA384:
-            return( "TLS-RSA-WITH-AES-256-GCM-SHA384" );
-#endif
-
-#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA4_C)
-        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
-            return( "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256" );
-
-        case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
-            return( "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384" );
-#endif
-#endif /* POLARSSL_AES_C */
-
-#if defined(POLARSSL_CAMELLIA_C)
-        case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
-            return( "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA" );
-
-        case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
-            return( "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA" );
-
-        case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
-            return( "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA" );
-
-        case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
-            return( "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA" );
-
-#if defined(POLARSSL_SHA2_C)
-        case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
-            return( "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256" );
-
-        case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
-            return( "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256" );
-
-        case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
-            return( "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256" );
-
-        case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
-            return( "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256" );
-#endif
-#endif
-
-#if defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES)
-#if defined(POLARSSL_CIPHER_NULL_CIPHER)
-        case TLS_RSA_WITH_NULL_MD5:
-            return( "TLS-RSA-WITH-NULL-MD5" );
-        case TLS_RSA_WITH_NULL_SHA:
-            return( "TLS-RSA-WITH-NULL-SHA" );
-        case TLS_RSA_WITH_NULL_SHA256:
-            return( "TLS-RSA-WITH-NULL-SHA256" );
-#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */
-
-#if defined(POLARSSL_DES_C)
-        case TLS_RSA_WITH_DES_CBC_SHA:
-            return( "TLS-RSA-WITH-DES-CBC-SHA" );
-        case TLS_DHE_RSA_WITH_DES_CBC_SHA:
-            return( "TLS-DHE-RSA-WITH-DES-CBC-SHA" );
-#endif
-#endif /* defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES) */
-
-    default:
-        break;
-    }
-
-    return( "unknown" );
-}
-
-int ssl_get_ciphersuite_id( const char *ciphersuite_name )
-{
-#if defined(POLARSSL_ARC4_C)
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-RC4-128-MD5"))
-        return( TLS_RSA_WITH_RC4_128_MD5 );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-RC4-128-SHA"))
-        return( TLS_RSA_WITH_RC4_128_SHA );
-#endif
-
-#if defined(POLARSSL_DES_C)
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-3DES-EDE-CBC-SHA"))
-        return( TLS_RSA_WITH_3DES_EDE_CBC_SHA );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA"))
-        return( TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA );
-#endif
-
-#if defined(POLARSSL_AES_C)
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-AES-128-CBC-SHA"))
-        return( TLS_RSA_WITH_AES_128_CBC_SHA );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-AES-128-CBC-SHA"))
-        return( TLS_DHE_RSA_WITH_AES_128_CBC_SHA );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-AES-256-CBC-SHA"))
-        return( TLS_RSA_WITH_AES_256_CBC_SHA );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-AES-256-CBC-SHA"))
-        return( TLS_DHE_RSA_WITH_AES_256_CBC_SHA );
-
-#if defined(POLARSSL_SHA2_C)
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-AES-128-CBC-SHA256"))
-        return( TLS_RSA_WITH_AES_128_CBC_SHA256 );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-AES-256-CBC-SHA256"))
-        return( TLS_RSA_WITH_AES_256_CBC_SHA256 );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256"))
-        return( TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256"))
-        return( TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 );
-#endif
-
-#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C)
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-AES-128-GCM-SHA256"))
-        return( TLS_RSA_WITH_AES_128_GCM_SHA256 );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-AES-256-GCM-SHA384"))
-        return( TLS_RSA_WITH_AES_256_GCM_SHA384 );
-#endif
-
-#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C)
-    if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256"))
-        return( TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384"))
-        return( TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 );
-#endif
-#endif
-
-#if defined(POLARSSL_CAMELLIA_C)
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA"))
-        return( TLS_RSA_WITH_CAMELLIA_128_CBC_SHA );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA"))
-        return( TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA"))
-        return( TLS_RSA_WITH_CAMELLIA_256_CBC_SHA );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA"))
-        return( TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA );
-
-#if defined(POLARSSL_SHA2_C)
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256"))
-        return( TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256"))
-        return( TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256"))
-        return( TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256"))
-        return( TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 );
-#endif
-#endif
-
-#if defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES)
-#if defined(POLARSSL_CIPHER_NULL_CIPHER)
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-NULL-MD5"))
-        return( TLS_RSA_WITH_NULL_MD5 );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-NULL-SHA"))
-        return( TLS_RSA_WITH_NULL_SHA );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-NULL-SHA256"))
-        return( TLS_RSA_WITH_NULL_SHA256 );
-#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */
-
-#if defined(POLARSSL_DES_C)
-    if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-DES-CBC-SHA"))
-        return( TLS_RSA_WITH_DES_CBC_SHA );
-    if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-DES-CBC-SHA"))
-        return( TLS_DHE_RSA_WITH_DES_CBC_SHA );
-#endif
-#endif /* defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES) */
-
-    return( 0 );
-}
-
 const char *ssl_get_ciphersuite( const ssl_context *ssl )
 {
+    if( ssl == NULL || ssl->session == NULL )
+        return NULL;
+
     return ssl_get_ciphersuite_name( ssl->session->ciphersuite );
 }
 
@@ -3438,98 +3038,42 @@
     return ssl->session->peer_cert;
 }
 
-const int ssl_default_ciphersuites[] =
+/*
+ * Perform a single step of the SSL handshake
+ */
+int ssl_handshake_step( ssl_context *ssl )
 {
-#if defined(POLARSSL_DHM_C)
-#if defined(POLARSSL_AES_C)
-#if defined(POLARSSL_SHA2_C)
-    TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
-#endif /* POLARSSL_SHA2_C */
-#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA4_C)
-    TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
-#endif
-    TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
-#if defined(POLARSSL_SHA2_C)
-    TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
-#endif
-#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C)
-    TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
-#endif
-    TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
-#endif
-#if defined(POLARSSL_CAMELLIA_C)
-#if defined(POLARSSL_SHA2_C)
-    TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
-#endif /* POLARSSL_SHA2_C */
-    TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
-#if defined(POLARSSL_SHA2_C)
-    TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
-#endif /* POLARSSL_SHA2_C */
-    TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
-#endif
-#if defined(POLARSSL_DES_C)
-    TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
-#endif
+    int ret = POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE;
+
+#if defined(POLARSSL_SSL_CLI_C)
+    if( ssl->endpoint == SSL_IS_CLIENT )
+        ret = ssl_handshake_client_step( ssl );
 #endif
 
-#if defined(POLARSSL_AES_C)
-#if defined(POLARSSL_SHA2_C)
-    TLS_RSA_WITH_AES_256_CBC_SHA256,
-#endif /* POLARSSL_SHA2_C */
-#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA4_C)
-    TLS_RSA_WITH_AES_256_GCM_SHA384,
-#endif /* POLARSSL_SHA2_C */
-    TLS_RSA_WITH_AES_256_CBC_SHA,
+#if defined(POLARSSL_SSL_SRV_C)
+    if( ssl->endpoint == SSL_IS_SERVER )
+        ret = ssl_handshake_server_step( ssl );
 #endif
-#if defined(POLARSSL_CAMELLIA_C)
-#if defined(POLARSSL_SHA2_C)
-    TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
-#endif /* POLARSSL_SHA2_C */
-    TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
-#endif
-#if defined(POLARSSL_AES_C)
-#if defined(POLARSSL_SHA2_C)
-    TLS_RSA_WITH_AES_128_CBC_SHA256,
-#endif /* POLARSSL_SHA2_C */
-#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C)
-    TLS_RSA_WITH_AES_128_GCM_SHA256,
-#endif /* POLARSSL_SHA2_C */
-    TLS_RSA_WITH_AES_128_CBC_SHA,
-#endif
-#if defined(POLARSSL_CAMELLIA_C)
-#if defined(POLARSSL_SHA2_C)
-    TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
-#endif /* POLARSSL_SHA2_C */
-    TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
-#endif
-#if defined(POLARSSL_DES_C)
-    TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-#endif
-#if defined(POLARSSL_ARC4_C)
-    TLS_RSA_WITH_RC4_128_SHA,
-    TLS_RSA_WITH_RC4_128_MD5,
-#endif
-    0
-};
+
+    return( ret );
+}
 
 /*
  * Perform the SSL handshake
  */
 int ssl_handshake( ssl_context *ssl )
 {
-    int ret = POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE;
+    int ret = 0;
 
     SSL_DEBUG_MSG( 2, ( "=> handshake" ) );
 
-#if defined(POLARSSL_SSL_CLI_C)
-    if( ssl->endpoint == SSL_IS_CLIENT )
-        ret = ssl_handshake_client( ssl );
-#endif
+    while( ssl->state != SSL_HANDSHAKE_OVER )
+    {
+        ret = ssl_handshake_step( ssl );
 
-#if defined(POLARSSL_SSL_SRV_C)
-    if( ssl->endpoint == SSL_IS_SERVER )
-        ret = ssl_handshake_server( ssl );
-#endif
+        if( ret != 0 )
+            break;
+    }
 
     SSL_DEBUG_MSG( 2, ( "<= handshake" ) );
 
@@ -3833,6 +3377,12 @@
         free( ssl->session_negotiate );
     }
 
+    if( ssl->session )
+    {
+        ssl_session_free( ssl->session );
+        free( ssl->session );
+    }
+
     if ( ssl->hostname != NULL)
     {
         memset( ssl->hostname, 0, ssl->hostname_len );
@@ -3850,7 +3400,7 @@
 
     SSL_DEBUG_MSG( 2, ( "<= free" ) );
 
-    /* Actually free after last debug message */
+    /* Actually clear after last debug message */
     memset( ssl, 0, sizeof( ssl_context ) );
 }
 
diff --git a/library/x509parse.c b/library/x509parse.c
index 493cf3a..bac0e93 100644
--- a/library/x509parse.c
+++ b/library/x509parse.c
@@ -42,12 +42,24 @@
 #include "polarssl/asn1.h"
 #include "polarssl/pem.h"
 #include "polarssl/des.h"
+#if defined(POLARSSL_MD2_C)
 #include "polarssl/md2.h"
+#endif
+#if defined(POLARSSL_MD4_C)
 #include "polarssl/md4.h"
+#endif
+#if defined(POLARSSL_MD5_C)
 #include "polarssl/md5.h"
+#endif
+#if defined(POLARSSL_SHA1_C)
 #include "polarssl/sha1.h"
+#endif
+#if defined(POLARSSL_SHA2_C)
 #include "polarssl/sha2.h"
+#endif
+#if defined(POLARSSL_SHA4_C)
 #include "polarssl/sha4.h"
+#endif
 #include "polarssl/dhm.h"
 
 #include <string.h>
diff --git a/library/x509write.c b/library/x509write.c
index 9f5a910..026afe6 100644
--- a/library/x509write.c
+++ b/library/x509write.c
@@ -30,11 +30,24 @@
 #include "polarssl/asn1write.h"
 #include "polarssl/x509write.h"
 #include "polarssl/x509.h"
-#include "polarssl/sha1.h"
-#include "polarssl/sha2.h"
-#include "polarssl/sha4.h"
+#if defined(POLARSSL_MD2_C)
+#include "polarssl/md2.h"
+#endif
+#if defined(POLARSSL_MD4_C)
 #include "polarssl/md4.h"
+#endif
+#if defined(POLARSSL_MD5_C)
 #include "polarssl/md5.h"
+#endif
+#if defined(POLARSSL_SHA1_C)
+#include "polarssl/sha1.h"
+#endif
+#if defined(POLARSSL_SHA2_C)
+#include "polarssl/sha2.h"
+#endif
+#if defined(POLARSSL_SHA4_C)
+#include "polarssl/sha4.h"
+#endif
 
 int x509_write_pubkey_der( unsigned char *buf, size_t size, rsa_context *rsa )
 {
diff --git a/programs/test/ssl_test.c b/programs/test/ssl_test.c
index 802fda0..e067652 100644
--- a/programs/test/ssl_test.c
+++ b/programs/test/ssl_test.c
@@ -1,7 +1,7 @@
 /*
  *  SSL/TLS stress testing program
  *
- *  Copyright (C) 2006-2011, Brainspark B.V.
+ *  Copyright (C) 2006-2013, Brainspark B.V.
  *
  *  This file is part of PolarSSL (http://www.polarssl.org)
  *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
@@ -272,9 +272,8 @@
     ssl_set_bio( &ssl, net_recv, &client_fd,
                        net_send, &client_fd );
 
-    if( opt->force_ciphersuite[0] == DFL_FORCE_CIPHER )
-          ssl_set_ciphersuites( &ssl, ssl_default_ciphersuites );
-    else  ssl_set_ciphersuites( &ssl, opt->force_ciphersuite );
+    if( opt->force_ciphersuite[0] != DFL_FORCE_CIPHER )
+        ssl_set_ciphersuites( &ssl, opt->force_ciphersuite );
 
     if( opt->iomode == IOMODE_NONBLOCK )
         net_set_nonblock( client_fd );
diff --git a/programs/util/strerror.c b/programs/util/strerror.c
index bb31b3d..e248201 100644
--- a/programs/util/strerror.c
+++ b/programs/util/strerror.c
@@ -38,13 +38,13 @@
 #define USAGE \
     "\n usage: strerror <errorcode>\n"
 
-#if !defined(POLARSSL_ERROR_C) 
+#if !defined(POLARSSL_ERROR_C) && !defined(POLARSSL_ERROR_STRERROR_DUMMY)
 int main( int argc, char *argv[] )
 {
     ((void) argc);
     ((void) argv);
 
-    printf("POLARSSL_ERROR_C not defined.\n");
+    printf("POLARSSL_ERROR_C and/or POLARSSL_ERROR_STRERRO_DUMMY not defined.\n");
     return( 0 );
 }
 #else
diff --git a/programs/x509/cert_app.c b/programs/x509/cert_app.c
index 2fb0c85..c9f74dd 100644
--- a/programs/x509/cert_app.c
+++ b/programs/x509/cert_app.c
@@ -1,7 +1,7 @@
 /*
  *  Certificate reading application
  *
- *  Copyright (C) 2006-2011, Brainspark B.V.
+ *  Copyright (C) 2006-2013, Brainspark B.V.
  *
  *  This file is part of PolarSSL (http://www.polarssl.org)
  *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
@@ -284,8 +284,6 @@
         ssl_set_bio( &ssl, net_recv, &server_fd,
                 net_send, &server_fd );
 
-        ssl_set_ciphersuites( &ssl, ssl_default_ciphersuites );
-
         ssl_set_own_cert( &ssl, &clicert, &rsa );
 
         ssl_set_hostname( &ssl, opt.server_name );
diff --git a/tests/suites/test_suite_version.data b/tests/suites/test_suite_version.data
index f89bd9b..267527a 100644
--- a/tests/suites/test_suite_version.data
+++ b/tests/suites/test_suite_version.data
@@ -1,5 +1,5 @@
 Check compiletime library version
-check_compiletime_version:"1.2.3"
+check_compiletime_version:"1.2.6"
 
 Check runtime library version
-check_runtime_version:"1.2.3"
+check_runtime_version:"1.2.6"