- Added client side support for signature_algorithm extension and affiliated handling

diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h
index 69e7a06..61a73d2 100644
--- a/include/polarssl/ssl.h
+++ b/include/polarssl/ssl.h
@@ -180,6 +180,7 @@
 #define SSL_ALERT_MSG_INTERNAL_ERROR        80  /* 0x50 */
 #define SSL_ALERT_MSG_USER_CANCELED         90  /* 0x5A */
 #define SSL_ALERT_MSG_NO_RENEGOTIATION     100  /* 0x64 */
+#define SSL_ALERT_MSG_UNSUPPORTED_EXT      110  /* 0x6E */
 
 #define SSL_HS_HELLO_REQUEST            0
 #define SSL_HS_CLIENT_HELLO             1
@@ -198,6 +199,8 @@
 #define TLS_EXT_SERVERNAME              0
 #define TLS_EXT_SERVERNAME_HOSTNAME     0
 
+#define TLS_EXT_SIG_ALG                13
+
 /*
  * SSL state machine
  */
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index 18850c2..19b8607 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -38,13 +38,19 @@
 #include <stdio.h>
 #include <time.h>
 
+#if defined(POLARSSL_SHA4_C)
+#include "polarssl/sha4.h"
+#endif
+
 static int ssl_write_client_hello( ssl_context *ssl )
 {
     int ret;
-    size_t i, n;
+    size_t i, n, ext_len = 0;
     unsigned char *buf;
     unsigned char *p;
     time_t t;
+    unsigned char sig_alg_list[20];
+    size_t sig_alg_len = 0;
 
     SSL_DEBUG_MSG( 2, ( "=> write client hello" ) );
 
@@ -95,8 +101,10 @@
      *    39  . 39+n  session id
      *   40+n . 41+n  ciphersuitelist length
      *   42+n . ..    ciphersuitelist
-     *   ..   . ..    compression alg. (0)
-     *   ..   . ..    extensions (unused)
+     *   ..   . ..    compression methods length
+     *   ..   . ..    compression methods
+     *   ..   . ..    extensions length
+     *   ..   . ..    extensions
      */
     n = ssl->session->length;
 
@@ -135,11 +143,68 @@
 
     if ( ssl->hostname != NULL )
     {
-        SSL_DEBUG_MSG( 3, ( "client hello, server name extension: %s",
+        SSL_DEBUG_MSG( 3, ( "client hello, prepping for server name extension: %s",
                        ssl->hostname ) );
 
-        *p++ = (unsigned char)( ( (ssl->hostname_len + 9) >> 8 ) & 0xFF );
-        *p++ = (unsigned char)( ( (ssl->hostname_len + 9)      ) & 0xFF );
+        ext_len += ssl->hostname_len + 9;
+    }
+
+    /*
+     * Prepare signature_algorithms extension (TLS 1.2)
+     */
+    if( ssl->max_minor_ver == SSL_MINOR_VERSION_3 )
+    {
+#if defined(POLARSSL_SHA4_C)
+        sig_alg_list[sig_alg_len++] = SSL_HASH_SHA512;
+        sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
+        sig_alg_list[sig_alg_len++] = SSL_HASH_SHA384;
+        sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
+#endif
+#if defined(POLARSSL_SHA2_C)
+        sig_alg_list[sig_alg_len++] = SSL_HASH_SHA256;
+        sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
+        sig_alg_list[sig_alg_len++] = SSL_HASH_SHA224;
+        sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
+#endif
+#if defined(POLARSSL_SHA1_C)
+        sig_alg_list[sig_alg_len++] = SSL_HASH_SHA1;
+        sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
+#endif
+#if defined(POLARSSL_MD5_C)
+        sig_alg_list[sig_alg_len++] = SSL_HASH_MD5;
+        sig_alg_list[sig_alg_len++] = SSL_SIG_RSA;
+#endif
+        ext_len = 6 + sig_alg_len;
+    }
+
+    SSL_DEBUG_MSG( 3, ( "client hello, total extension length: %d",
+                   ext_len ) );
+
+    *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF );
+    *p++ = (unsigned char)( ( ext_len      ) & 0xFF );
+
+    if ( ssl->hostname != NULL )
+    {
+        /*
+         * struct {
+         *     NameType name_type;
+         *     select (name_type) {
+         *         case host_name: HostName;
+         *     } name;
+         * } ServerName;
+         *
+         * enum {
+         *     host_name(0), (255)
+         * } NameType;
+         *
+         * opaque HostName<1..2^16-1>;
+         *
+         * struct {
+         *     ServerName server_name_list<1..2^16-1>
+         * } ServerNameList;
+         */
+        SSL_DEBUG_MSG( 3, ( "client hello, adding server name extension: %s",
+                       ssl->hostname ) );
 
         *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME >> 8 ) & 0xFF );
         *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME      ) & 0xFF );
@@ -159,6 +224,41 @@
         p += ssl->hostname_len;
     }
 
+    if( ssl->max_minor_ver == SSL_MINOR_VERSION_3 )
+    {
+        /*
+         * enum {
+         *     none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
+         *     sha512(6), (255)
+         * } HashAlgorithm;
+         *
+         * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) }
+         *   SignatureAlgorithm;
+         *
+         * struct {
+         *     HashAlgorithm hash;
+         *     SignatureAlgorithm signature;
+         * } SignatureAndHashAlgorithm;
+         *
+         * SignatureAndHashAlgorithm
+         *   supported_signature_algorithms<2..2^16-2>;
+         */
+        SSL_DEBUG_MSG( 3, ( "client hello, adding signature_algorithms extension" ) );
+
+        *p++ = (unsigned char)( ( TLS_EXT_SIG_ALG >> 8 ) & 0xFF );
+        *p++ = (unsigned char)( ( TLS_EXT_SIG_ALG      ) & 0xFF );
+
+        *p++ = (unsigned char)( ( ( sig_alg_len + 2 ) >> 8 ) & 0xFF );
+        *p++ = (unsigned char)( ( ( sig_alg_len + 2 )      ) & 0xFF );
+
+        *p++ = (unsigned char)( ( sig_alg_len >> 8 ) & 0xFF );
+        *p++ = (unsigned char)( ( sig_alg_len      ) & 0xFF );
+
+        memcpy( p, sig_alg_list, sig_alg_len );
+
+        p += sig_alg_len;
+    }
+
     ssl->out_msglen  = p - buf;
     ssl->out_msgtype = SSL_MSG_HANDSHAKE;
     ssl->out_msg[0]  = SSL_HS_CLIENT_HELLO;
@@ -339,7 +439,7 @@
     md5_context md5;
     sha1_context sha1;
     int hash_id = SIG_RSA_RAW;
-    unsigned int hashlen;
+    unsigned int hashlen = 0;
 #endif
 
     SSL_DEBUG_MSG( 2, ( "=> parse server key exchange" ) );
@@ -401,7 +501,6 @@
 
     if( ssl->minor_ver == SSL_MINOR_VERSION_3 )
     {
-        // TODO TLS 1.2 Check if valid hash and sig
         if( p[1] != SSL_SIG_RSA )
         {
             SSL_DEBUG_MSG( 2, ( "Server used unsupported SignatureAlgorithm %d", p[1] ) );
@@ -438,11 +537,13 @@
                 break;
 #endif
             default:
-                SSL_DEBUG_MSG( 2, ( "Server used unsupported HashAlgorithm %d", p[1] ) );
+                SSL_DEBUG_MSG( 2, ( "Server used unsupported HashAlgorithm %d", p[0] ) );
                 SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
                 return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); 
         }      
 
+        SSL_DEBUG_MSG( 2, ( "Server used SignatureAlgorithm %d", p[1] ) );
+        SSL_DEBUG_MSG( 2, ( "Server used HashAlgorithm %d", p[0] ) );
         p += 2;
     }
 
@@ -503,6 +604,9 @@
     }
     else
     {
+        sha2_context sha2;
+        sha4_context sha4;
+
         n = ssl->in_hslen - ( end - p ) - 8;
 
         /*
@@ -514,12 +618,59 @@
          */
         /* TODO TLS1.2 Get Hash algorithm from hash and signature extension! */
 
-        sha1_starts( &sha1 );
-        sha1_update( &sha1, ssl->randbytes, 64 );
-        sha1_update( &sha1, ssl->in_msg + 4, n );
-        sha1_finish( &sha1, hash );
-
-        hashlen = 20;
+        switch( hash_id )
+        {
+#if defined(POLARSSL_MD5_C)
+            case SIG_RSA_MD5:
+                md5_starts( &md5 );
+                md5_update( &md5, ssl->randbytes, 64 );
+                md5_update( &md5, ssl->in_msg + 4, n );
+                md5_finish( &md5, hash );
+                hashlen = 16;
+                break;
+#endif
+#if defined(POLARSSL_SHA1_C)
+            case SIG_RSA_SHA1:
+                sha1_starts( &sha1 );
+                sha1_update( &sha1, ssl->randbytes, 64 );
+                sha1_update( &sha1, ssl->in_msg + 4, n );
+                sha1_finish( &sha1, hash );
+                hashlen = 20;
+                break;
+#endif
+#if defined(POLARSSL_SHA2_C)
+            case SIG_RSA_SHA224:
+                sha2_starts( &sha2, 1 );
+                sha2_update( &sha2, ssl->randbytes, 64 );
+                sha2_update( &sha2, ssl->in_msg + 4, n );
+                sha2_finish( &sha2, hash );
+                hashlen = 28;
+                break;
+            case SIG_RSA_SHA256:
+                sha2_starts( &sha2, 0 );
+                sha2_update( &sha2, ssl->randbytes, 64 );
+                sha2_update( &sha2, ssl->in_msg + 4, n );
+                sha2_finish( &sha2, hash );
+                hashlen = 32;
+                break;
+#endif
+#if defined(POLARSSL_SHA4_C)
+            case SIG_RSA_SHA384:
+                sha4_starts( &sha4, 1 );
+                sha4_update( &sha4, ssl->randbytes, 64 );
+                sha4_update( &sha4, ssl->in_msg + 4, n );
+                sha4_finish( &sha4, hash );
+                hashlen = 48;
+                break;
+            case SIG_RSA_SHA512:
+                sha4_starts( &sha4, 0 );
+                sha4_update( &sha4, ssl->randbytes, 64 );
+                sha4_update( &sha4, ssl->in_msg + 4, n );
+                sha4_finish( &sha4, hash );
+                hashlen = 64;
+                break;
+#endif
+        }
     }
     
     SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen );
@@ -778,7 +929,7 @@
     if( ssl->minor_ver == SSL_MINOR_VERSION_3 )
     {
         // TODO TLS1.2 Base on signature algorithm extension received
-        ssl->out_msg[4] = SSL_HASH_SHA1;
+        ssl->out_msg[4] = SSL_HASH_SHA256;
         ssl->out_msg[5] = SSL_SIG_RSA;
 
         offset = 2;