Added pre-shared key handling for the client side of SSL / TLS

Client side handling of the pure PSK ciphersuites is now in the base
code.
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index c5ca733..86d720b 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -727,7 +727,8 @@
     return( 0 );
 }
 
-#if !defined(POLARSSL_DHM_C) && !defined(POLARSSL_ECDH_C)
+#if !defined(POLARSSL_DHM_C) && !defined(POLARSSL_ECDH_C) &&                \
+    !defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED)
 static int ssl_parse_server_key_exchange( ssl_context *ssl )
 {
     SSL_DEBUG_MSG( 2, ( "=> parse server key exchange" ) );
@@ -809,6 +810,36 @@
     return( ret );
 }
 
+static int ssl_parse_server_psk_hint( ssl_context *ssl,
+                                      unsigned char **p,
+                                      unsigned char *end )
+{
+    int ret = POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE;
+
+#if defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED)
+    size_t  len;
+
+    /*
+     * PSK parameters:
+     *
+     * opaque psk_identity_hint<0..2^16-1>;
+     */
+    len = (*p)[1] << 8 | (*p)[0];
+
+    if( (*p) + len > end )
+    {
+        SSL_DEBUG_MSG( 1, ( "bad server key exchange message (psk_identity_hint length)" ) );
+        return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
+    }
+
+    // TODO: Retrieve PSK identity hint and callback to app
+    //
+    *p += len;
+#endif /* POLARSSL_KEY_EXCHANGE_PSK_ENABLED */
+
+    return( ret );
+}
+
 static int ssl_parse_signature_algorithm( ssl_context *ssl,
                                           unsigned char **p,
                                           unsigned char *end,
@@ -822,7 +853,6 @@
     if( (*p)[1] != SSL_SIG_RSA )
     {
         SSL_DEBUG_MSG( 2, ( "server used unsupported SignatureAlgorithm %d", (*p)[1] ) );
-        SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
         return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
     }
 
@@ -880,7 +910,8 @@
     SSL_DEBUG_MSG( 2, ( "=> parse server key exchange" ) );
 
     if( ciphersuite_info->key_exchange != POLARSSL_KEY_EXCHANGE_DHE_RSA &&
-        ciphersuite_info->key_exchange != POLARSSL_KEY_EXCHANGE_ECDHE_RSA )
+        ciphersuite_info->key_exchange != POLARSSL_KEY_EXCHANGE_ECDHE_RSA &&
+        ciphersuite_info->key_exchange != POLARSSL_KEY_EXCHANGE_PSK )
     {
         SSL_DEBUG_MSG( 2, ( "<= skip parse server key exchange" ) );
         ssl->state++;
@@ -901,8 +932,8 @@
 
     if( ssl->in_msg[0] != SSL_HS_SERVER_KEY_EXCHANGE )
     {
-        SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
-        return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
+        ssl->record_read = 1;
+        goto exit;
     }
 
     SSL_DEBUG_BUF( 3,   "server key exchange", ssl->in_msg + 4, ssl->in_hslen - 4 );
@@ -914,14 +945,21 @@
     {
         if( ssl_parse_server_dh_params( ssl, &p, end ) != 0 )
         {
+            SSL_DEBUG_MSG( 1, ( "failed to parsebad server key exchange message" ) );
+            return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
+        }
+    }
+    else if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_ECDHE_RSA )
+    {
+        if( ssl_parse_server_ecdh_params( ssl, &p, end ) != 0 )
+        {
             SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
             return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
         }
     }
-
-    if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_ECDHE_RSA )
+    else if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_PSK )
     {
-        if( ssl_parse_server_ecdh_params( ssl, &p, end ) != 0 )
+        if( ssl_parse_server_psk_hint( ssl, &p, end ) != 0 )
         {
             SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
             return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
@@ -1028,6 +1066,7 @@
         }
     }
 
+exit:
     ssl->state++;
 
     SSL_DEBUG_MSG( 2, ( "<= parse server key exchange" ) );
@@ -1057,16 +1096,21 @@
      *    n+4 .. ...  Distinguished Name #1
      *    ... .. ...  length of DN 2, etc.
      */
-    if( ( ret = ssl_read_record( ssl ) ) != 0 )
+    if( ssl->record_read == 0 )
     {
-        SSL_DEBUG_RET( 1, "ssl_read_record", ret );
-        return( ret );
-    }
+        if( ( ret = ssl_read_record( ssl ) ) != 0 )
+        {
+            SSL_DEBUG_RET( 1, "ssl_read_record", ret );
+            return( ret );
+        }
 
-    if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
-    {
-        SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
-        return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE );
+        if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
+            return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE );
+        }
+
+        ssl->record_read = 1;
     }
 
     ssl->client_auth = 0;
@@ -1081,6 +1125,8 @@
     if( ssl->client_auth == 0 )
         goto exit;
 
+    ssl->record_read = 0;
+
     // TODO: handshake_failure alert for an anonymous server to request
     // client authentication
 
@@ -1154,7 +1200,7 @@
 
     SSL_DEBUG_MSG( 2, ( "=> parse server hello done" ) );
 
-    if( ssl->client_auth != 0 )
+    if( ssl->record_read == 0 )
     {
         if( ( ret = ssl_read_record( ssl ) ) != 0 )
         {
@@ -1168,6 +1214,7 @@
             return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE );
         }
     }
+    ssl->record_read = 0;
 
     if( ssl->in_hslen  != 4 ||
         ssl->in_msg[0] != SSL_HS_SERVER_HELLO_DONE )
@@ -1265,6 +1312,43 @@
     }
     else
 #endif /* POLARSSL_ECDH_C */
+#if defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED)
+    if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_PSK )
+    {
+        unsigned char *p = ssl->handshake->premaster;
+
+        /*
+         * PSK key exchange
+         *
+         * opaque psk_identity<0..2^16-1>;
+         */
+        if( ssl->hostname == NULL )
+            return( POLARSSL_ERR_SSL_PRIVATE_KEY_REQUIRED );
+
+        if( sizeof(ssl->handshake->premaster) < 4 + 2 * ssl->psk_len )
+            return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+
+        n = ssl->psk_identity_len;
+
+        ssl->out_msg[4] = (unsigned char)( n >> 8 );
+        ssl->out_msg[5] = (unsigned char)( n      );
+        i = 6;
+
+        memcpy( ssl->out_msg + i, ssl->psk_identity, ssl->psk_identity_len );
+
+        *(p++) = (unsigned char)( ssl->psk_len >> 8 );
+        *(p++) = (unsigned char)( ssl->psk_len      );
+        p += ssl->psk_len;
+
+        *(p++) = (unsigned char)( ssl->psk_len >> 8 );
+        *(p++) = (unsigned char)( ssl->psk_len      );
+        memcpy( p, ssl->psk, ssl->psk_len );
+        p += ssl->psk_len;
+
+        ssl->handshake->pmslen = 4 + 2 * ssl->psk_len;
+    }
+    else
+#endif /* POLARSSL_KEY_EXCHANGE_PSK_ENABLED */
     {
         /*
          * RSA key exchange -- send rsa_public(pkcs1 v1.5(premaster))
@@ -1331,10 +1415,12 @@
     unsigned char hash[48];
     md_type_t md_alg = POLARSSL_MD_NONE;
     unsigned int hashlen = 0;
+    const ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info;
 
     SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) );
 
-    if( ssl->client_auth == 0 || ssl->own_cert == NULL )
+    if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_PSK ||
+        ssl->client_auth == 0 || ssl->own_cert == NULL )
     {
         SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) );
         ssl->state++;