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/include/polarssl/config.h b/include/polarssl/config.h
index 850053c..29d4f0d 100644
--- a/include/polarssl/config.h
+++ b/include/polarssl/config.h
@@ -162,6 +162,21 @@
  */
 
 /**
+ * \def POLARSSL_KEY_EXCHANGE_PSK_ENABLED
+ *
+ * Enable the PSK based ciphersuite modes in SSL / TLS
+ * In combination with POLARSSL_RSA_C it also enables RSA_PSK ciphersuites
+ * and in combination with POLARSSL_DHM_C it enables the DHE_PSK ciphersuites
+ *
+ * This enables the following ciphersuites:
+ *      TLS_PSK_WITH_RC4_128_SHA
+ *      TLS_PSK_WITH_3DES_EDE_CBC_SHA
+ *      TLS_PSK_WITH_AES_128_CBC_SHA
+ *      TLS_PSK_WITH_AES_256_CBC_SHA
+ */
+#define POLARSSL_KEY_EXCHANGE_PSK_ENABLED
+
+/**
  * \def POLARSSL_ERROR_STRERROR_DUMMY
  *
  * Enable a dummy error function to make use of error_strerror() in
@@ -348,6 +363,8 @@
  *      TLS_RSA_WITH_AES_256_GCM_SHA384
  *      TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
  *      TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+ *      TLS_PSK_WITH_AES_128_CBC_SHA
+ *      TLS_PSK_WITH_AES_256_CBC_SHA
  *
  * PEM uses AES for decrypting encrypted keys.
  */
@@ -366,6 +383,7 @@
  *      TLS_RSA_WITH_RC4_128_MD5
  *      TLS_RSA_WITH_RC4_128_SHA
  *      TLS_ECDHE_RSA_WITH_RC4_128_SHA
+ *      TLS_PSK_WITH_RC4_128_SHA
  */
 #define POLARSSL_ARC4_C
 
@@ -511,6 +529,7 @@
  *      TLS_RSA_WITH_3DES_EDE_CBC_SHA
  *      TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
  *      TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+ *      TLS_PSK_WITH_3DES_EDE_CBC_SHA
  *
  * PEM uses DES/3DES for decrypting encrypted keys.
  */
diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h
index 43e8069..5c86bb3 100644
--- a/include/polarssl/ssl.h
+++ b/include/polarssl/ssl.h
@@ -201,6 +201,7 @@
 #define SSL_ALERT_MSG_NO_RENEGOTIATION     100  /* 0x64 */
 #define SSL_ALERT_MSG_UNSUPPORTED_EXT      110  /* 0x6E */
 #define SSL_ALERT_MSG_UNRECOGNIZED_NAME    112  /* 0x70 */
+#define SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY 115  /* 0x73 */
 
 #define SSL_HS_HELLO_REQUEST            0
 #define SSL_HS_CLIENT_HELLO             1
@@ -226,7 +227,6 @@
 
 #define TLS_EXT_RENEGOTIATION_INFO      0xFF01
 
-
 /*
  * Generic function pointers for allowing external RSA private key
  * implementations.
@@ -441,6 +441,7 @@
 
     size_t in_hslen;            /*!< current handshake message length */
     int nb_zero;                /*!< # of 0-length encrypted messages */
+    int record_read;            /*!< record is already present        */
 
     /*
      * Record layer (outgoing data)
@@ -483,6 +484,16 @@
     mpi dhm_G;                          /*!<  generator for DHM       */
 #endif
 
+#if defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED)
+    /*
+     * PSK values
+     */
+    const unsigned char *psk;
+    size_t         psk_len;
+    const unsigned char *psk_identity;
+    size_t         psk_identity_len;
+#endif
+
     /*
      * TLS extensions
      */
@@ -780,6 +791,21 @@
                            rsa_sign_func rsa_sign,
                            rsa_key_len_func rsa_key_len );
 
+#if defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED)
+/**
+ * \brief          Set the Pre Shared Key (PSK) and the identity name connected
+ *                 to it. The PSK is used in all PSK-based ciphersuites.
+ *
+ * \param ssl      SSL context
+ * \param psk      pointer to the pre-shared key
+ * \param psk_len  pre-shared key length
+ * \param psk_identity      pointer to the pre-shared key identity
+ * \param psk_identity_len  identity key length
+ */
+void ssl_set_psk( ssl_context *ssl, const unsigned char *psk, size_t psk_len,
+                  const unsigned char *psk_identity, size_t psk_identity_len );
+#endif /* POLARSSL_KEY_EXCHANGE_PSK_ENABLED */
+
 #if defined(POLARSSL_DHM_C)
 /**
  * \brief          Set the Diffie-Hellman public P and G values,
diff --git a/include/polarssl/ssl_ciphersuites.h b/include/polarssl/ssl_ciphersuites.h
index 7ec31ae..665c219 100644
--- a/include/polarssl/ssl_ciphersuites.h
+++ b/include/polarssl/ssl_ciphersuites.h
@@ -53,6 +53,7 @@
 #define TLS_DHE_RSA_WITH_AES_128_CBC_SHA         0x33
 #define TLS_RSA_WITH_AES_256_CBC_SHA             0x35
 #define TLS_DHE_RSA_WITH_AES_256_CBC_SHA         0x39
+
 #define TLS_RSA_WITH_AES_128_CBC_SHA256          0x3C   /**< TLS 1.2 */
 #define TLS_RSA_WITH_AES_256_CBC_SHA256          0x3D   /**< TLS 1.2 */
 #define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256      0x67   /**< TLS 1.2 */
@@ -62,6 +63,22 @@
 #define TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA    0x45
 #define TLS_RSA_WITH_CAMELLIA_256_CBC_SHA        0x84
 #define TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA    0x88
+
+#define TLS_PSK_WITH_RC4_128_SHA                 0x8A
+#define TLS_PSK_WITH_3DES_EDE_CBC_SHA            0x8B
+#define TLS_PSK_WITH_AES_128_CBC_SHA             0x8C
+#define TLS_PSK_WITH_AES_256_CBC_SHA             0x8D
+
+#define TLS_DHE_PSK_WITH_RC4_128_SHA             0x8E
+#define TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA        0x8F
+#define TLS_DHE_PSK_WITH_AES_128_CBC_SHA         0x90
+#define TLS_DHE_PSK_WITH_AES_256_CBC_SHA         0x91
+
+#define TLS_RSA_PSK_WITH_RC4_128_SHA             0x92
+#define TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA        0x93
+#define TLS_RSA_PSK_WITH_AES_128_CBC_SHA         0x94
+#define TLS_RSA_PSK_WITH_AES_256_CBC_SHA         0x95
+
 #define TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256     0xBA   /**< TLS 1.2 */
 #define TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xBE   /**< TLS 1.2 */
 #define TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256     0xC0   /**< TLS 1.2 */
@@ -91,6 +108,9 @@
     POLARSSL_KEY_EXCHANGE_RSA,
     POLARSSL_KEY_EXCHANGE_DHE_RSA,
     POLARSSL_KEY_EXCHANGE_ECDHE_RSA,
+    POLARSSL_KEY_EXCHANGE_PSK,
+    POLARSSL_KEY_EXCHANGE_DHE_PSK,
+    POLARSSL_KEY_EXCHANGE_RSA_PSK,
 } key_exchange_type_t;
 
 typedef struct _ssl_ciphersuite_t ssl_ciphersuite_t;
diff --git a/library/ssl_ciphersuites.c b/library/ssl_ciphersuites.c
index 6e1a4f8..9962965 100644
--- a/library/ssl_ciphersuites.c
+++ b/library/ssl_ciphersuites.c
@@ -70,6 +70,12 @@
     TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
     TLS_ECDHE_RSA_WITH_RC4_128_SHA,
 
+    /* The PSK ephemeral suites */
+    TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
+    TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
+    TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+    TLS_DHE_PSK_WITH_RC4_128_SHA,
+
     /* All AES-256 suites */
     TLS_RSA_WITH_AES_256_CBC_SHA256,
     TLS_RSA_WITH_AES_256_GCM_SHA384,
@@ -93,6 +99,18 @@
     TLS_RSA_WITH_RC4_128_SHA,
     TLS_RSA_WITH_RC4_128_MD5,
 
+    /* The RSA PSK suites */
+    TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+    TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+    TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+    TLS_RSA_PSK_WITH_RC4_128_SHA,
+
+    /* The PSK suites */
+    TLS_PSK_WITH_AES_256_CBC_SHA,
+    TLS_PSK_WITH_AES_128_CBC_SHA,
+    TLS_PSK_WITH_3DES_EDE_CBC_SHA,
+    TLS_PSK_WITH_RC4_128_SHA,
+
     /* Weak or NULL suites */
     TLS_DHE_RSA_WITH_DES_CBC_SHA,
     TLS_RSA_WITH_DES_CBC_SHA,
@@ -370,6 +388,100 @@
       0 },
 #endif /* POLARSSL_DES_C */
 
+#if defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED)
+#if defined(POLARSSL_AES_C)
+    { TLS_PSK_WITH_AES_128_CBC_SHA, "TLS-PSK-WITH-AES-128-CBC-SHA",
+      POLARSSL_CIPHER_AES_128_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_PSK,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+
+    { TLS_PSK_WITH_AES_256_CBC_SHA, "TLS-PSK-WITH-AES-256-CBC-SHA",
+      POLARSSL_CIPHER_AES_256_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_PSK,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_AES_C */
+
+#if defined(POLARSSL_DES_C)
+    { TLS_PSK_WITH_3DES_EDE_CBC_SHA, "TLS-PSK-WITH-3DES-EDE-CBC-SHA",
+      POLARSSL_CIPHER_DES_EDE3_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_PSK,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_DES_C */
+
+#if defined(POLARSSL_ARC4_C)
+    { TLS_PSK_WITH_RC4_128_SHA, "TLS-PSK-WITH-RC4-128-SHA",
+      POLARSSL_CIPHER_ARC4_128, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_PSK,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_ARC4_C */
+
+#if defined(POLARSSL_DHM_C)
+#if defined(POLARSSL_AES_C)
+    { TLS_DHE_PSK_WITH_AES_128_CBC_SHA, "TLS-DHE-PSK-WITH-AES-128-CBC-SHA",
+      POLARSSL_CIPHER_AES_128_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_DHE_PSK,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+
+    { TLS_DHE_PSK_WITH_AES_256_CBC_SHA, "TLS-DHE-PSK-WITH-AES-256-CBC-SHA",
+      POLARSSL_CIPHER_AES_256_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_DHE_PSK,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_AES_C */
+
+#if defined(POLARSSL_DES_C)
+    { TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, "TLS-DHE-PSK-WITH-3DES-EDE-CBC-SHA",
+      POLARSSL_CIPHER_DES_EDE3_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_DHE_PSK,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_DES_C */
+
+#if defined(POLARSSL_ARC4_C)
+    { TLS_DHE_PSK_WITH_RC4_128_SHA, "TLS-DHE-PSK-WITH-RC4-128-SHA",
+      POLARSSL_CIPHER_ARC4_128, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_DHE_PSK,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_ARC4_C */
+#endif /* POLARSSL_DHM_C */
+
+#if defined(POLARSSL_AES_C)
+    { TLS_RSA_PSK_WITH_AES_128_CBC_SHA, "TLS-RSA-PSK-WITH-AES-128-CBC-SHA",
+      POLARSSL_CIPHER_AES_128_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_RSA_PSK,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+
+    { TLS_RSA_PSK_WITH_AES_256_CBC_SHA, "TLS-RSA-PSK-WITH-AES-256-CBC-SHA",
+      POLARSSL_CIPHER_AES_256_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_RSA_PSK,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_AES_C */
+
+#if defined(POLARSSL_DES_C)
+    { TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, "TLS-RSA-PSK-WITH-3DES-EDE-CBC-SHA",
+      POLARSSL_CIPHER_DES_EDE3_CBC, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_RSA_PSK,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_DES_C */
+
+#if defined(POLARSSL_ARC4_C)
+    { TLS_RSA_PSK_WITH_RC4_128_SHA, "TLS-RSA-PSK-WITH-RC4-128-SHA",
+      POLARSSL_CIPHER_ARC4_128, POLARSSL_MD_SHA1, POLARSSL_KEY_EXCHANGE_RSA_PSK,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0,
+      SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3,
+      0 },
+#endif /* POLARSSL_ARC4_C */
+#endif /* POLARSSL_KEY_EXCHANGE_PSK_ENABLED */
+
 #if defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES)
 #if defined(POLARSSL_CIPHER_NULL_CIPHER)
     { TLS_RSA_WITH_NULL_MD5, "TLS-RSA-WITH-NULL-MD5",
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++;
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 85fc7fe..6b47838 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -1848,9 +1848,17 @@
     int ret;
     size_t i, n;
     const x509_cert *crt;
+    const ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info;
 
     SSL_DEBUG_MSG( 2, ( "=> write certificate" ) );
 
+    if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_PSK )
+    {
+        SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) );
+        ssl->state++;
+        return( 0 );
+    }
+
     if( ssl->endpoint == SSL_IS_CLIENT )
     {
         if( ssl->client_auth == 0 )
@@ -1944,9 +1952,17 @@
 {
     int ret;
     size_t i, n;
+    const ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info;
 
     SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) );
 
+    if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_PSK )
+    {
+        SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
+        ssl->state++;
+        return( 0 );
+    }
+
     if( ssl->endpoint == SSL_IS_SERVER &&
         ssl->authmode == SSL_VERIFY_NONE )
     {
@@ -2753,6 +2769,7 @@
 
     ssl->in_hslen = 0;
     ssl->nb_zero = 0;
+    ssl->record_read = 0;
 
     ssl->out_msg = ssl->out_ctr + 13;
     ssl->out_msgtype = 0;
@@ -2908,6 +2925,16 @@
     ssl->rsa_key_len = rsa_key_len;
 }
 
+#if defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED)
+void ssl_set_psk( ssl_context *ssl, const unsigned char *psk, size_t psk_len,
+                  const unsigned char *psk_identity, size_t psk_identity_len )
+{
+    ssl->psk     = psk;
+    ssl->psk_len = psk_len;
+    ssl->psk_identity     = psk_identity;
+    ssl->psk_identity_len = psk_identity_len;
+}
+#endif /* POLARSSL_KEY_EXCHANGE_PSK_ENABLED */
 
 #if defined(POLARSSL_DHM_C)
 int ssl_set_dh_param( ssl_context *ssl, const char *dhm_P, const char *dhm_G )
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 89820a3..62daab1 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -49,6 +49,8 @@
 #define DFL_CA_PATH             ""
 #define DFL_CRT_FILE            ""
 #define DFL_KEY_FILE            ""
+#define DFL_PSK                 ""
+#define DFL_PSK_IDENTITY        "Client_identity"
 #define DFL_FORCE_CIPHER        0
 #define DFL_RENEGOTIATION       SSL_RENEGOTIATION_ENABLED
 #define DFL_ALLOW_LEGACY        SSL_LEGACY_NO_RENEGOTIATION
@@ -71,6 +73,8 @@
     char *ca_path;              /* the path with the CA certificate(s) reside */
     char *crt_file;             /* the file with the client certificate     */
     char *key_file;             /* the file with the client key             */
+    char *psk;                  /* the pre-shared key                       */
+    char *psk_identity;         /* the pre-shared key identity              */
     int force_ciphersuite[2];   /* protocol/ciphersuite to use, or all      */
     int renegotiation;          /* enable / disable renegotiation           */
     int allow_legacy;           /* allow legacy renegotiation               */
@@ -158,6 +162,8 @@
     "                        options: ssl3, tls1, tls1_1, tls1_2\n" \
     "    auth_mode=%%s        default: \"optional\"\n"          \
     "                        options: none, optional, required\n" \
+    "    psk=%%s              default: \"\" (in hex, without 0x)\n" \
+    "    psk_identity=%%s     default: \"Client_identity\"\n" \
     "\n"                                                    \
     "    force_ciphersuite=<name>    default: all enabled\n"\
     " acceptable ciphersuite names:\n"
@@ -180,8 +186,10 @@
 #else
 int main( int argc, char *argv[] )
 {
-    int ret = 0, len, server_fd;
+    int ret = 0, len, server_fd, i;
     unsigned char buf[1024];
+    unsigned char psk[256];
+    size_t psk_len = 0;
     char *pers = "ssl_client2";
 
     entropy_context entropy;
@@ -190,7 +198,6 @@
     x509_cert cacert;
     x509_cert clicert;
     rsa_context rsa;
-    int i;
     char *p, *q;
     const int *list;
 
@@ -229,6 +236,8 @@
     opt.ca_path             = DFL_CA_PATH;
     opt.crt_file            = DFL_CRT_FILE;
     opt.key_file            = DFL_KEY_FILE;
+    opt.psk                 = DFL_PSK;
+    opt.psk_identity        = DFL_PSK_IDENTITY;
     opt.force_ciphersuite[0]= DFL_FORCE_CIPHER;
     opt.renegotiation       = DFL_RENEGOTIATION;
     opt.allow_legacy        = DFL_ALLOW_LEGACY;
@@ -267,6 +276,10 @@
             opt.crt_file = q;
         else if( strcmp( p, "key_file" ) == 0 )
             opt.key_file = q;
+        else if( strcmp( p, "psk" ) == 0 )
+            opt.psk = q;
+        else if( strcmp( p, "psk_identity" ) == 0 )
+            opt.psk_identity = q;
         else if( strcmp( p, "force_ciphersuite" ) == 0 )
         {
             opt.force_ciphersuite[0] = -1;
@@ -358,6 +371,54 @@
     }
 
     /*
+     * Unhexify the pre-shared key if any is given
+     */
+    if( strlen( opt.psk ) )
+    {
+        unsigned char c;
+        size_t j;
+
+        if( strlen( opt.psk ) % 2 != 0 )
+        {
+            printf("pre-shared key not valid hex\n");
+            goto exit;
+        }
+
+        psk_len = strlen( opt.psk ) / 2;
+
+        for( j = 0; j < strlen( opt.psk ); j += 2 )
+        {
+            c = opt.psk[j];
+            if( c >= '0' && c <= '9' )
+                c -= '0';
+            else if( c >= 'a' && c <= 'f' )
+                c -= 'a' - 10;
+            else if( c >= 'A' && c <= 'F' )
+                c -= 'A' - 10;
+            else
+            {
+                printf("pre-shared key not valid hex\n");
+                goto exit;
+            }
+            psk[ j / 2 ] = c << 4;
+
+            c = opt.psk[j + 1];
+            if( c >= '0' && c <= '9' )
+                c -= '0';
+            else if( c >= 'a' && c <= 'f' )
+                c -= 'a' - 10;
+            else if( c >= 'A' && c <= 'F' )
+                c -= 'A' - 10;
+            else
+            {
+                printf("pre-shared key not valid hex\n");
+                goto exit;
+            }
+            psk[ j / 2 ] |= c;
+        }
+    }
+
+    /*
      * 0. Initialize the RNG and the session data
      */
     printf( "\n  . Seeding the random number generator..." );
@@ -502,7 +563,8 @@
 
     ssl_set_ca_chain( &ssl, &cacert, NULL, opt.server_name );
     ssl_set_own_cert( &ssl, &clicert, &rsa );
-
+    ssl_set_psk( &ssl, psk, psk_len, (unsigned char *) opt.psk_identity,
+                 strlen( opt.psk_identity ) );
     ssl_set_hostname( &ssl, opt.server_name );
 
     if( opt.min_version != -1 )
@@ -554,10 +616,13 @@
     else
         printf( " ok\n" );
 
-    printf( "  . Peer certificate information    ...\n" );
-    x509parse_cert_info( (char *) buf, sizeof( buf ) - 1, "      ",
-                         ssl_get_peer_cert( &ssl ) );
-    printf( "%s\n", buf );
+    if( ssl_get_peer_cert( &ssl ) != NULL )
+    {
+        printf( "  . Peer certificate information    ...\n" );
+        x509parse_cert_info( (char *) buf, sizeof( buf ) - 1, "      ",
+                             ssl_get_peer_cert( &ssl ) );
+        printf( "%s\n", buf );
+    }
 
     /*
      * 6. Write the GET request