Merge "Add support for TLS-ECDHE-PSK cipher suites"
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index 6283c6a..ec8948d 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -531,6 +531,10 @@
 #define TLS1_CK_ECDH_RSA_WITH_AES_128_GCM_SHA256        0x0300C031
 #define TLS1_CK_ECDH_RSA_WITH_AES_256_GCM_SHA384        0x0300C032
 
+/* ECDHE PSK ciphersuites from RFC 5489 */
+#define TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA256    0x0300C037
+#define TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA384    0x0300C038
+
 /* XXX
  * Inconsistency alert:
  * The OpenSSL names of ciphers with ephemeral DH here include the string
@@ -682,6 +686,10 @@
 #define TLS1_TXT_ECDH_RSA_WITH_AES_128_GCM_SHA256       "ECDH-RSA-AES128-GCM-SHA256"
 #define TLS1_TXT_ECDH_RSA_WITH_AES_256_GCM_SHA384       "ECDH-RSA-AES256-GCM-SHA384"
 
+/* ECDHE PSK ciphersuites from RFC 5489 */
+#define TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA256  "ECDHE-PSK-WITH-AES-128-CBC-SHA256"
+#define TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA384  "ECDHE-PSK-WITH-AES-256-CBC-SHA384"
+
 #define TLS_CT_RSA_SIGN			1
 #define TLS_CT_DSS_SIGN			2
 #define TLS_CT_RSA_FIXED_DH		3
diff --git a/openssl.config b/openssl.config
index 8248107..75d9cc9 100644
--- a/openssl.config
+++ b/openssl.config
@@ -1083,6 +1083,7 @@
 alpn.patch \
 cbc_record_splitting.patch \
 dsa_nonce.patch \
+ecdhe_psk.patch \
 "
 
 source ./openssl.trusty.config
diff --git a/patches/README b/patches/README
index 4159a85..c9588dd 100644
--- a/patches/README
+++ b/patches/README
@@ -48,3 +48,7 @@
 Adds an option to mix in hash of message and private key into (EC)DSA nonces to
 make (EC)DSA more resilient to weaknesses in RNGs used for nonces. The feature
 is disabled by default.
+
+ecdhe_psk.patch
+
+Adds support for ECDHE Pre-Shared Key (PSK) TLS cipher suites.
diff --git a/patches/ecdhe_psk.patch b/patches/ecdhe_psk.patch
new file mode 100644
index 0000000..6ff2d16
--- /dev/null
+++ b/patches/ecdhe_psk.patch
@@ -0,0 +1,1405 @@
+From 8f48440b360cfe1672acdb67bc1253b30562bffd Mon Sep 17 00:00:00 2001
+From: Adam Langley <agl@chromium.org>
+Date: Thu, 14 Nov 2013 16:12:01 -0500
+Subject: Implement ECDHE-PSK-WITH-AES.
+
+Add support for TLS-ECDHE-PSK cipher suites:
+* TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA256, and
+* TLS-ECDHE-PSK-WITH-AES-256-CBC-SHA384.
+---
+ ssl/s3_clnt.c | 358 +++++++++++++++++++++----------------
+ ssl/s3_lib.c  |  38 +++++-
+ ssl/s3_srvr.c | 554 ++++++++++++++++++++++++++++++++--------------------------
+ ssl/ssl_lib.c |   2 +-
+ ssl/tls1.h    |  11 ++
+ 5 files changed, 583 insertions(+), 400 deletions(-)
+
+diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
+index a3df502..67edeaa 100644
+--- a/ssl/s3_clnt.c
++++ b/ssl/s3_clnt.c
+@@ -333,9 +333,10 @@ int ssl3_connect(SSL *s)
+ 				}
+ #endif
+ 			/* Check if it is anon DH/ECDH */
+-			/* or PSK */
++			/* or non-RSA PSK */
+ 			if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
+-			    !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
++			    !((s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK) &&
++			      !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kRSA)))
+ 				{
+ 				ret=ssl3_get_server_certificate(s);
+ 				if (ret <= 0) goto end;
+@@ -1365,7 +1366,7 @@ int ssl3_get_key_exchange(SSL *s)
+ 		   omitted if no identity hint is sent. Set
+ 		   session->sess_cert anyway to avoid problems
+ 		   later.*/
+-		if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)
++		if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK)
+ 			{
+ 			s->session->sess_cert=ssl_sess_cert_new();
+ 			if (s->ctx->psk_identity_hint)
+@@ -1413,52 +1414,56 @@ int ssl3_get_key_exchange(SSL *s)
+ 	EVP_MD_CTX_init(&md_ctx);
+ 
+ #ifndef OPENSSL_NO_PSK
+-	if (alg_k & SSL_kPSK)
++	if (alg_a & SSL_aPSK)
+ 		{
+ 		char tmp_id_hint[PSK_MAX_IDENTITY_LEN+1];
+ 
+ 		al=SSL_AD_HANDSHAKE_FAILURE;
+ 		n2s(p,i);
+ 		param_len=i+2;
+-		/* Store PSK identity hint for later use, hint is used
+-		 * in ssl3_send_client_key_exchange.  Assume that the
+-		 * maximum length of a PSK identity hint can be as
+-		 * long as the maximum length of a PSK identity. */
+-		if (i > PSK_MAX_IDENTITY_LEN)
+-			{
+-			SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
+-				SSL_R_DATA_LENGTH_TOO_LONG);
+-			goto f_err;
+-			}
+-		if (param_len > n)
++		s->ctx->psk_identity_hint = NULL;
++		if (i != 0)
+ 			{
+-			al=SSL_AD_DECODE_ERROR;
+-			SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
+-				SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH);
+-			goto f_err;
++			/* Store PSK identity hint for later use, hint is used
++			 * in ssl3_send_client_key_exchange.  Assume that the
++			 * maximum length of a PSK identity hint can be as
++			 * long as the maximum length of a PSK identity. */
++			if (i > PSK_MAX_IDENTITY_LEN)
++				{
++				SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
++					SSL_R_DATA_LENGTH_TOO_LONG);
++				goto f_err;
++				}
++			if (param_len > n)
++				{
++				al=SSL_AD_DECODE_ERROR;
++				SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
++					SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH);
++				goto f_err;
++				}
++			/* If received PSK identity hint contains NULL
++			 * characters, the hint is truncated from the first
++			 * NULL. p may not be ending with NULL, so create a
++			 * NULL-terminated string. */
++			memcpy(tmp_id_hint, p, i);
++			memset(tmp_id_hint+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
++			if (s->ctx->psk_identity_hint != NULL)
++				OPENSSL_free(s->ctx->psk_identity_hint);
++			s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint);
++			if (s->ctx->psk_identity_hint == NULL)
++				{
++				SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
++				goto f_err;
++				}
+ 			}
+-		/* If received PSK identity hint contains NULL
+-		 * characters, the hint is truncated from the first
+-		 * NULL. p may not be ending with NULL, so create a
+-		 * NULL-terminated string. */
+-		memcpy(tmp_id_hint, p, i);
+-		memset(tmp_id_hint+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
+-		if (s->ctx->psk_identity_hint != NULL)
+-			OPENSSL_free(s->ctx->psk_identity_hint);
+-		s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint);
+-		if (s->ctx->psk_identity_hint == NULL)
+-			{
+-			SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+-			goto f_err;
+-			}	   
+-
+ 		p+=i;
+ 		n-=param_len;
+ 		}
+-	else
+ #endif /* !OPENSSL_NO_PSK */
++
++	if (0) {}
+ #ifndef OPENSSL_NO_SRP
+-	if (alg_k & SSL_kSRP)
++	else if (alg_k & SSL_kSRP)
+ 		{
+ 		n2s(p,i);
+ 		param_len=i+2;
+@@ -1535,10 +1540,9 @@ int ssl3_get_key_exchange(SSL *s)
+ 			pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN].x509);
+ #endif
+ 		}
+-	else
+ #endif /* !OPENSSL_NO_SRP */
+ #ifndef OPENSSL_NO_RSA
+-	if (alg_k & SSL_kRSA)
++	else if (alg_k & SSL_kRSA)
+ 		{
+ 		if ((rsa=RSA_new()) == NULL)
+ 			{
+@@ -1587,9 +1591,6 @@ int ssl3_get_key_exchange(SSL *s)
+ 		s->session->sess_cert->peer_rsa_tmp=rsa;
+ 		rsa=NULL;
+ 		}
+-#else /* OPENSSL_NO_RSA */
+-	if (0)
+-		;
+ #endif
+ #ifndef OPENSSL_NO_DH
+ 	else if (alg_k & SSL_kEDH)
+@@ -1770,14 +1771,14 @@ int ssl3_get_key_exchange(SSL *s)
+ 		EC_POINT_free(srvr_ecpoint);
+ 		srvr_ecpoint = NULL;
+ 		}
+-	else if (alg_k)
++#endif /* !OPENSSL_NO_ECDH */
++
++	else if (!(alg_k & SSL_kPSK))
+ 		{
+ 		al=SSL_AD_UNEXPECTED_MESSAGE;
+ 		SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
+ 		goto f_err;
+ 		}
+-#endif /* !OPENSSL_NO_ECDH */
+-
+ 
+ 	/* p points to the next byte, there are 'n' bytes left */
+ 
+@@ -1882,8 +1883,9 @@ fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
+ 		}
+ 	else
+ 		{
+-		if (!(alg_a & SSL_aNULL) && !(alg_k & SSL_kPSK))
+-			/* aNULL or kPSK do not need public keys */
++		if (!(alg_a & SSL_aNULL) &&
++			/* Among PSK ciphers only RSA_PSK needs a public key */
++			!((alg_a & SSL_aPSK) && !(alg_k & SSL_kRSA)))
+ 			{
+ 			SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+ 			goto err;
+@@ -2285,6 +2287,7 @@ int ssl3_send_client_key_exchange(SSL *s)
+ 	unsigned char *p,*d;
+ 	int n;
+ 	unsigned long alg_k;
++	unsigned long alg_a;
+ #ifndef OPENSSL_NO_RSA
+ 	unsigned char *q;
+ 	EVP_PKEY *pkey=NULL;
+@@ -2299,7 +2302,11 @@ int ssl3_send_client_key_exchange(SSL *s)
+ 	unsigned char *encodedPoint = NULL;
+ 	int encoded_pt_len = 0;
+ 	BN_CTX * bn_ctx = NULL;
+-#endif
++#ifndef OPENSSL_NO_PSK
++	unsigned int psk_len = 0;
++	unsigned char psk[PSK_MAX_PSK_LEN];
++#endif /* OPENSSL_NO_PSK */
++#endif /* OPENSSL_NO_ECDH */
+ 
+ 	if (s->state == SSL3_ST_CW_KEY_EXCH_A)
+ 		{
+@@ -2307,7 +2314,96 @@ int ssl3_send_client_key_exchange(SSL *s)
+ 		p= &(d[4]);
+ 
+ 		alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
++		alg_a=s->s3->tmp.new_cipher->algorithm_auth;
++
++#ifndef OPENSSL_NO_PSK
++		if (alg_a & SSL_aPSK)
++			{
++			char identity[PSK_MAX_IDENTITY_LEN];
++			unsigned char *t = NULL;
++			unsigned char pre_ms[PSK_MAX_PSK_LEN*2+4];
++			unsigned int pre_ms_len = 0;
++			int psk_err = 1;
++
++			n = 0;
++			if (s->psk_client_callback == NULL)
++				{
++				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
++					SSL_R_PSK_NO_CLIENT_CB);
++				goto err;
++				}
+ 
++			psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint,
++				identity, PSK_MAX_IDENTITY_LEN, psk, sizeof(psk));
++			if (psk_len > PSK_MAX_PSK_LEN)
++				{
++				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
++					ERR_R_INTERNAL_ERROR);
++				goto psk_err;
++				}
++			else if (psk_len == 0)
++				{
++				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
++					SSL_R_PSK_IDENTITY_NOT_FOUND);
++				goto psk_err;
++				}
++
++			if (!(alg_k & SSL_kEECDH))
++				{
++				/* Create the shared secret now if we're not using ECDHE-PSK.*/
++				pre_ms_len = 2+psk_len+2+psk_len;
++				t = pre_ms;
++				s2n(psk_len, t);
++				memset(t, 0, psk_len);
++				t+=psk_len;
++				s2n(psk_len, t);
++				memcpy(t, psk, psk_len);
++
++				s->session->master_key_length =
++					s->method->ssl3_enc->generate_master_secret(s,
++						s->session->master_key,
++						pre_ms, pre_ms_len);
++				n = strlen(identity);
++				s2n(n, p);
++				memcpy(p, identity, n);
++				n += 2;
++				}
++
++			if (s->session->psk_identity_hint != NULL)
++				OPENSSL_free(s->session->psk_identity_hint);
++			s->session->psk_identity_hint = NULL;
++			if (s->ctx->psk_identity_hint)
++				{
++				s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
++				if (s->ctx->psk_identity_hint != NULL &&
++					s->session->psk_identity_hint == NULL)
++					{
++					SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
++						ERR_R_MALLOC_FAILURE);
++					goto psk_err;
++					}
++				}
++
++			if (s->session->psk_identity != NULL)
++				OPENSSL_free(s->session->psk_identity);
++			s->session->psk_identity = BUF_strdup(identity);
++			if (s->session->psk_identity == NULL)
++				{
++				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
++					ERR_R_MALLOC_FAILURE);
++				goto psk_err;
++				}
++			psk_err = 0;
++		psk_err:
++			OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN);
++			OPENSSL_cleanse(pre_ms, sizeof(pre_ms));
++			if (psk_err != 0)
++				{
++				ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
++				goto err;
++				}
++			}
++#endif
+ 		/* Fool emacs indentation */
+ 		if (0) {}
+ #ifndef OPENSSL_NO_RSA
+@@ -2568,14 +2664,19 @@ int ssl3_send_client_key_exchange(SSL *s)
+ 			/* perhaps clean things up a bit EAY EAY EAY EAY*/
+ 			}
+ #endif
+-
+-#ifndef OPENSSL_NO_ECDH 
++#ifndef OPENSSL_NO_ECDH
+ 		else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
+ 			{
+ 			const EC_GROUP *srvr_group = NULL;
+ 			EC_KEY *tkey;
+ 			int ecdh_clnt_cert = 0;
+ 			int field_size = 0;
++#ifndef OPENSSL_NO_PSK
++			unsigned char *pre_ms;
++			unsigned char *t;
++			unsigned int pre_ms_len;
++			unsigned int i;
++#endif
+ 
+ 			/* Did we send out the client's
+ 			 * ECDH share for use in premaster
+@@ -2696,15 +2797,41 @@ int ssl3_send_client_key_exchange(SSL *s)
+ 				goto err;
+ 				}
+ 
+-			/* generate master key from the result */
+-			s->session->master_key_length = s->method->ssl3_enc \
+-			    -> generate_master_secret(s, 
+-				s->session->master_key,
+-				p, n);
+-
++#ifndef OPENSSL_NO_PSK
++			/* ECDHE PSK ciphersuites from RFC 5489 */
++			if ((alg_a & SSL_aPSK) && psk_len != 0)
++				{
++				pre_ms_len = 2+psk_len+2+n;
++				pre_ms = OPENSSL_malloc(pre_ms_len);
++				if (pre_ms == NULL)
++					{
++					SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
++			    		ERR_R_MALLOC_FAILURE);
++					goto err;
++					}
++				memset(pre_ms, 0, pre_ms_len);
++				t = pre_ms;
++				s2n(psk_len, t);
++				memcpy(t, psk, psk_len);
++				t += psk_len;
++				s2n(n, t);
++				memcpy(t, p, n);
++				s->session->master_key_length = s->method->ssl3_enc \
++					-> generate_master_secret(s,
++						s->session->master_key, pre_ms, pre_ms_len);
++				OPENSSL_cleanse(pre_ms, pre_ms_len);
++				OPENSSL_free(pre_ms);
++				}
++#endif /* OPENSSL_NO_PSK */
++			if (!(alg_a & SSL_aPSK))
++				{
++				/* generate master key from the result */
++				s->session->master_key_length = s->method->ssl3_enc \
++					-> generate_master_secret(s,
++						s->session->master_key, p, n);
++				}
+ 			memset(p, 0, n); /* clean up */
+-
+-			if (ecdh_clnt_cert) 
++			if (ecdh_clnt_cert)
+ 				{
+ 				/* Send empty client key exch message */
+ 				n = 0;
+@@ -2732,29 +2859,42 @@ int ssl3_send_client_key_exchange(SSL *s)
+ 					}
+ 
+ 				/* Encode the public key */
+-				n = EC_POINT_point2oct(srvr_group, 
+-				    EC_KEY_get0_public_key(clnt_ecdh), 
+-				    POINT_CONVERSION_UNCOMPRESSED, 
++				encoded_pt_len = EC_POINT_point2oct(srvr_group,
++				    EC_KEY_get0_public_key(clnt_ecdh),
++				    POINT_CONVERSION_UNCOMPRESSED,
+ 				    encodedPoint, encoded_pt_len, bn_ctx);
++				
++				n = 0;
++#ifndef OPENSSL_NO_PSK
++				if ((alg_a & SSL_aPSK) && psk_len != 0)
++					{
++					i = strlen(s->session->psk_identity);
++					s2n(i, p);
++					memcpy(p, s->session->psk_identity, i);
++					p += i;
++					n = i + 2;
++					}
++#endif
+ 
+-				*p = n; /* length of encoded point */
++				*p = encoded_pt_len; /* length of encoded point */
+ 				/* Encoded point will be copied here */
+-				p += 1; 
++				p += 1;
++				n += 1;
+ 				/* copy the point */
+-				memcpy((unsigned char *)p, encodedPoint, n);
++				memcpy((unsigned char *)p, encodedPoint, encoded_pt_len);
+ 				/* increment n to account for length field */
+-				n += 1; 
++				n += encoded_pt_len;
+ 				}
+ 
+ 			/* Free allocated memory */
+ 			BN_CTX_free(bn_ctx);
+ 			if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
+-			if (clnt_ecdh != NULL) 
++			if (clnt_ecdh != NULL)
+ 				 EC_KEY_free(clnt_ecdh);
+ 			EVP_PKEY_free(srvr_pub_pkey);
+ 			}
+ #endif /* !OPENSSL_NO_ECDH */
+-		else if (alg_k & SSL_kGOST) 
++		else if (alg_k & SSL_kGOST)
+ 			{
+ 			/* GOST key exchange message creation */
+ 			EVP_PKEY_CTX *pkey_ctx;
+@@ -2877,89 +3017,7 @@ int ssl3_send_client_key_exchange(SSL *s)
+ 				}
+ 			}
+ #endif
+-#ifndef OPENSSL_NO_PSK
+-		else if (alg_k & SSL_kPSK)
+-			{
+-			char identity[PSK_MAX_IDENTITY_LEN];
+-			unsigned char *t = NULL;
+-			unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4];
+-			unsigned int pre_ms_len = 0, psk_len = 0;
+-			int psk_err = 1;
+-
+-			n = 0;
+-			if (s->psk_client_callback == NULL)
+-				{
+-				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+-					SSL_R_PSK_NO_CLIENT_CB);
+-				goto err;
+-				}
+-
+-			psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint,
+-				identity, PSK_MAX_IDENTITY_LEN,
+-				psk_or_pre_ms, sizeof(psk_or_pre_ms));
+-			if (psk_len > PSK_MAX_PSK_LEN)
+-				{
+-				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+-					ERR_R_INTERNAL_ERROR);
+-				goto psk_err;
+-				}
+-			else if (psk_len == 0)
+-				{
+-				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+-					SSL_R_PSK_IDENTITY_NOT_FOUND);
+-				goto psk_err;
+-				}
+-
+-			/* create PSK pre_master_secret */
+-			pre_ms_len = 2+psk_len+2+psk_len;
+-			t = psk_or_pre_ms;
+-			memmove(psk_or_pre_ms+psk_len+4, psk_or_pre_ms, psk_len);
+-			s2n(psk_len, t);
+-			memset(t, 0, psk_len);
+-			t+=psk_len;
+-			s2n(psk_len, t);
+-
+-			if (s->session->psk_identity_hint != NULL)
+-				OPENSSL_free(s->session->psk_identity_hint);
+-			s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
+-			if (s->ctx->psk_identity_hint != NULL &&
+-				s->session->psk_identity_hint == NULL)
+-				{
+-				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+-					ERR_R_MALLOC_FAILURE);
+-				goto psk_err;
+-				}
+-
+-			if (s->session->psk_identity != NULL)
+-				OPENSSL_free(s->session->psk_identity);
+-			s->session->psk_identity = BUF_strdup(identity);
+-			if (s->session->psk_identity == NULL)
+-				{
+-				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+-					ERR_R_MALLOC_FAILURE);
+-				goto psk_err;
+-				}
+-
+-			s->session->master_key_length =
+-				s->method->ssl3_enc->generate_master_secret(s,
+-					s->session->master_key,
+-					psk_or_pre_ms, pre_ms_len); 
+-			n = strlen(identity);
+-			s2n(n, p);
+-			memcpy(p, identity, n);
+-			n+=2;
+-			psk_err = 0;
+-		psk_err:
+-			OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN);
+-			OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
+-			if (psk_err != 0)
+-				{
+-				ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+-				goto err;
+-				}
+-			}
+-#endif
+-		else
++		else if (!(alg_k & SSL_kPSK))
+ 			{
+ 			ssl3_send_alert(s, SSL3_AL_FATAL,
+ 			    SSL_AD_HANDSHAKE_FAILURE);
+@@ -3264,7 +3322,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
+ 	alg_a=s->s3->tmp.new_cipher->algorithm_auth;
+ 
+ 	/* we don't have a certificate */
+-	if ((alg_a & (SSL_aDH|SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
++	if ((alg_a & (SSL_aDH|SSL_aNULL|SSL_aKRB5)) || ((alg_a & SSL_aPSK) && !(alg_k & SSL_kRSA)))
+ 		return(1);
+ 
+ 	sc=s->session->sess_cert;
+diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
+index 1d87ac5..d060a05 100644
+--- a/ssl/s3_lib.c
++++ b/ssl/s3_lib.c
+@@ -2851,6 +2851,42 @@ OPENSSL_GLOBAL SSL_CIPHER ssl3_ciphers[]={
+ 	256,
+ 	},
+ 
++#ifndef OPENSSL_NO_PSK
++    /* ECDH PSK ciphersuites from RFC 5489 */
++
++	/* Cipher C037 */
++	{
++	1,
++	TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
++	TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
++	SSL_kEECDH,
++	SSL_aPSK,
++	SSL_AES128,
++	SSL_SHA256,
++	SSL_TLSV1,
++	SSL_NOT_EXP|SSL_HIGH,
++	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF_SHA256,
++	128,
++	128,
++	},
++
++	/* Cipher C038 */
++	{
++	1,
++	TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
++	TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
++	SSL_kEECDH,
++	SSL_aPSK,
++	SSL_AES256,
++	SSL_SHA384,
++	SSL_TLSV1,
++	SSL_NOT_EXP|SSL_HIGH,
++	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF_SHA384,
++	256,
++	256,
++	},
++#endif /* OPENSSL_NO_PSK */
++
+ #endif /* OPENSSL_NO_ECDH */
+ 
+ 
+@@ -3979,7 +4032,7 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
+ #endif /* OPENSSL_NO_KRB5 */
+ #ifndef OPENSSL_NO_PSK
+ 		/* with PSK there must be server callback set */
+-		if ((alg_k & SSL_kPSK) && s->psk_server_callback == NULL)
++		if ((alg_a & SSL_aPSK) && s->psk_server_callback == NULL)
+ 			continue;
+ #endif /* OPENSSL_NO_PSK */
+ 
+diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
+index 2586751..2d67a15 100644
+--- a/ssl/s3_srvr.c
++++ b/ssl/s3_srvr.c
+@@ -217,6 +217,7 @@ int ssl3_accept(SSL *s)
+ 	{
+ 	BUF_MEM *buf;
+ 	unsigned long alg_k,Time=(unsigned long)time(NULL);
++	unsigned long alg_a;
+ 	void (*cb)(const SSL *ssl,int type,int val)=NULL;
+ 	int ret= -1;
+ 	int new_state,state,skip=0;
+@@ -418,9 +419,11 @@ int ssl3_accept(SSL *s)
+ 		case SSL3_ST_SW_CERT_A:
+ 		case SSL3_ST_SW_CERT_B:
+ 			/* Check if it is anon DH or anon ECDH, */
+-			/* normal PSK or KRB5 or SRP */
++			/* non-RSA PSK or KRB5 or SRP */
+ 			if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+-				&& !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)
++				/* Among PSK ciphersuites only RSA_PSK uses server certificate */
++				&& !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK &&
++					 !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kRSA))
+ 				&& !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5))
+ 				{
+ 				ret=ssl3_send_server_certificate(s);
+@@ -449,6 +452,7 @@ int ssl3_accept(SSL *s)
+ 		case SSL3_ST_SW_KEY_EXCH_A:
+ 		case SSL3_ST_SW_KEY_EXCH_B:
+ 			alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
++			alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+ 
+ 			/* clear this, it may get reset by
+ 			 * send_server_key_exchange */
+@@ -478,10 +482,12 @@ int ssl3_accept(SSL *s)
+ 			 * public key for key exchange.
+ 			 */
+ 			if (s->s3->tmp.use_rsa_tmp
+-			/* PSK: send ServerKeyExchange if PSK identity
+-			 * hint if provided */
++			/* PSK: send ServerKeyExchange if either:
++			 *   - PSK identity hint is provided, or
++			 *   - the key exchange is kEECDH.
++			 */
+ #ifndef OPENSSL_NO_PSK
+-			    || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint)
++			    || ((alg_a & SSL_aPSK) && ((alg_k & SSL_kEECDH) || s->ctx->psk_identity_hint))
+ #endif
+ #ifndef OPENSSL_NO_SRP
+ 			    /* SRP: send ServerKeyExchange */
+@@ -1656,7 +1662,8 @@ int ssl3_send_server_key_exchange(SSL *s)
+ 	const EVP_MD *md = NULL;
+ 	unsigned char *p,*d;
+ 	int al,i;
+-	unsigned long type;
++	unsigned long alg_k;
++	unsigned long alg_a;
+ 	int n;
+ 	CERT *cert;
+ 	BIGNUM *r[4];
+@@ -1667,15 +1674,25 @@ int ssl3_send_server_key_exchange(SSL *s)
+ 	EVP_MD_CTX_init(&md_ctx);
+ 	if (s->state == SSL3_ST_SW_KEY_EXCH_A)
+ 		{
+-		type=s->s3->tmp.new_cipher->algorithm_mkey;
++		alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
++		alg_a=s->s3->tmp.new_cipher->algorithm_auth;
+ 		cert=s->cert;
+ 
+ 		buf=s->init_buf;
+ 
+ 		r[0]=r[1]=r[2]=r[3]=NULL;
+ 		n=0;
++#ifndef OPENSSL_NO_PSK
++		if (alg_a & SSL_aPSK)
++			{
++			/* size for PSK identity hint */
++			n+=2;
++			if (s->ctx->psk_identity_hint)
++				n+=strlen(s->ctx->psk_identity_hint);
++			}
++#endif /* !OPENSSL_NO_PSK */
+ #ifndef OPENSSL_NO_RSA
+-		if (type & SSL_kRSA)
++		if (alg_k & SSL_kRSA)
+ 			{
+ 			rsa=cert->rsa_tmp;
+ 			if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL))
+@@ -1702,10 +1719,9 @@ int ssl3_send_server_key_exchange(SSL *s)
+ 			r[1]=rsa->e;
+ 			s->s3->tmp.use_rsa_tmp=1;
+ 			}
+-		else
+ #endif
+ #ifndef OPENSSL_NO_DH
+-			if (type & SSL_kEDH)
++		else if (alg_k & SSL_kEDH)
+ 			{
+ 			dhp=cert->dh_tmp;
+ 			if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
+@@ -1758,10 +1774,9 @@ int ssl3_send_server_key_exchange(SSL *s)
+ 			r[1]=dh->g;
+ 			r[2]=dh->pub_key;
+ 			}
+-		else 
+ #endif
+ #ifndef OPENSSL_NO_ECDH
+-			if (type & SSL_kEECDH)
++		else if (alg_k & SSL_kEECDH)
+ 			{
+ 			const EC_GROUP *group;
+ 
+@@ -1874,7 +1889,7 @@ int ssl3_send_server_key_exchange(SSL *s)
+ 			 * to encode the entire ServerECDHParams
+ 			 * structure. 
+ 			 */
+-			n = 4 + encodedlen;
++			n += 4 + encodedlen;
+ 
+ 			/* We'll generate the serverKeyExchange message
+ 			 * explicitly so we can set these to NULLs
+@@ -1884,18 +1899,9 @@ int ssl3_send_server_key_exchange(SSL *s)
+ 			r[2]=NULL;
+ 			r[3]=NULL;
+ 			}
+-		else 
+ #endif /* !OPENSSL_NO_ECDH */
+-#ifndef OPENSSL_NO_PSK
+-			if (type & SSL_kPSK)
+-				{
+-				/* reserve size for record length and PSK identity hint*/
+-				n+=2+strlen(s->ctx->psk_identity_hint);
+-				}
+-			else
+-#endif /* !OPENSSL_NO_PSK */
+ #ifndef OPENSSL_NO_SRP
+-		if (type & SSL_kSRP)
++		else if (alg_k & SSL_kSRP)
+ 			{
+ 			if ((s->srp_ctx.N == NULL) ||
+ 				(s->srp_ctx.g == NULL) ||
+@@ -1910,8 +1916,8 @@ int ssl3_send_server_key_exchange(SSL *s)
+ 			r[2]=s->srp_ctx.s;
+ 			r[3]=s->srp_ctx.B;
+ 			}
+-		else 
+ #endif
++		else if (!(alg_k & SSL_kPSK))
+ 			{
+ 			al=SSL_AD_HANDSHAKE_FAILURE;
+ 			SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
+@@ -1921,15 +1927,16 @@ int ssl3_send_server_key_exchange(SSL *s)
+ 			{
+ 			nr[i]=BN_num_bytes(r[i]);
+ #ifndef OPENSSL_NO_SRP
+-			if ((i == 2) && (type & SSL_kSRP))
++			if ((i == 2) && (alg_k & SSL_kSRP))
+ 				n+=1+nr[i];
+ 			else
+ #endif
+ 			n+=2+nr[i];
+ 			}
+ 
+-		if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+-			&& !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
++		if (!(alg_a & SSL_aNULL)
++			/* Among PSK ciphersuites only RSA uses a certificate */
++			&& !((alg_a & SSL_aPSK) && !(alg_k & SSL_kRSA)))
+ 			{
+ 			if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher,&md))
+ 				== NULL)
+@@ -1956,7 +1963,7 @@ int ssl3_send_server_key_exchange(SSL *s)
+ 		for (i=0; i < 4 && r[i] != NULL; i++)
+ 			{
+ #ifndef OPENSSL_NO_SRP
+-			if ((i == 2) && (type & SSL_kSRP))
++			if ((i == 2) && (alg_k & SSL_kSRP))
+ 				{
+ 				*p = nr[i];
+ 				p++;
+@@ -1968,8 +1975,32 @@ int ssl3_send_server_key_exchange(SSL *s)
+ 			p+=nr[i];
+ 			}
+ 
++/* Note: ECDHE PSK ciphersuites use SSL_kEECDH and SSL_aPSK.
++ * When one of them is used, the server key exchange record needs to have both
++ * the psk_identity_hint and the ServerECDHParams. */
++#ifndef OPENSSL_NO_PSK
++		if (alg_a & SSL_aPSK)
++			{
++			if (s->ctx->psk_identity_hint)
++				{
++				/* copy PSK identity hint */
++				s2n(strlen(s->ctx->psk_identity_hint), p);
++				strncpy((char *)p, s->ctx->psk_identity_hint, strlen(s->ctx->psk_identity_hint));
++				p+=strlen(s->ctx->psk_identity_hint);
++				}
++			else
++				{
++				/* No identity hint is provided. */
++				*p = 0;
++				p += 1;
++				*p = 0;
++				p += 1;
++				}
++			}
++#endif /* OPENSSL_NO_PSK */
++
+ #ifndef OPENSSL_NO_ECDH
+-		if (type & SSL_kEECDH) 
++		if (alg_k & SSL_kEECDH)
+ 			{
+ 			/* XXX: For now, we only support named (not generic) curves.
+ 			 * In this situation, the serverKeyExchange message has:
+@@ -1992,17 +2023,7 @@ int ssl3_send_server_key_exchange(SSL *s)
+ 			encodedPoint = NULL;
+ 			p += encodedlen;
+ 			}
+-#endif
+-
+-#ifndef OPENSSL_NO_PSK
+-		if (type & SSL_kPSK)
+-			{
+-			/* copy PSK identity hint */
+-			s2n(strlen(s->ctx->psk_identity_hint), p); 
+-			strncpy((char *)p, s->ctx->psk_identity_hint, strlen(s->ctx->psk_identity_hint));
+-			p+=strlen(s->ctx->psk_identity_hint);
+-			}
+-#endif
++#endif /* OPENSSL_NO_ECDH */
+ 
+ 		/* not anonymous */
+ 		if (pkey != NULL)
+@@ -2039,7 +2060,7 @@ int ssl3_send_server_key_exchange(SSL *s)
+ 				n+=u+2;
+ 				}
+ 			else
+-#endif
++#endif /* OPENSSL_NO_RSA */
+ 			if (md)
+ 				{
+ 				/* For TLS1.2 and later send signature
+@@ -2208,6 +2229,7 @@ int ssl3_get_client_key_exchange(SSL *s)
+ 	int i,al,ok;
+ 	long n;
+ 	unsigned long alg_k;
++	unsigned long alg_a;
+ 	unsigned char *p;
+ #ifndef OPENSSL_NO_RSA
+ 	RSA *rsa=NULL;
+@@ -2225,7 +2247,11 @@ int ssl3_get_client_key_exchange(SSL *s)
+ 	EC_KEY *srvr_ecdh = NULL;
+ 	EVP_PKEY *clnt_pub_pkey = NULL;
+ 	EC_POINT *clnt_ecpoint = NULL;
+-	BN_CTX *bn_ctx = NULL; 
++	BN_CTX *bn_ctx = NULL;
++#ifndef OPENSSL_NO_PSK
++	unsigned int psk_len = 0;
++	unsigned char psk[PSK_MAX_PSK_LEN];
++#endif /* OPENSSL_NO_PSK */
+ #endif
+ 
+ 	n=s->method->ssl_get_message(s,
+@@ -2239,7 +2265,106 @@ int ssl3_get_client_key_exchange(SSL *s)
+ 	p=(unsigned char *)s->init_msg;
+ 
+ 	alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
++	alg_a=s->s3->tmp.new_cipher->algorithm_auth;
++
++#ifndef OPENSSL_NO_PSK
++	if (alg_a & SSL_aPSK)
++		{
++		unsigned char *t = NULL;
++		unsigned char pre_ms[PSK_MAX_PSK_LEN*2+4];
++		unsigned int pre_ms_len = 0;
++		int psk_err = 1;
++		char tmp_id[PSK_MAX_IDENTITY_LEN+1];
++
++		al=SSL_AD_HANDSHAKE_FAILURE;
++
++		n2s(p, i);
++		if (n != i+2 && !(alg_k & SSL_kEECDH))
++			{
++			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
++				SSL_R_LENGTH_MISMATCH);
++			goto psk_err;
++			}
++		if (i > PSK_MAX_IDENTITY_LEN)
++			{
++			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
++				SSL_R_DATA_LENGTH_TOO_LONG);
++			goto psk_err;
++			}
++		if (s->psk_server_callback == NULL)
++			{
++			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
++			       SSL_R_PSK_NO_SERVER_CB);
++			goto psk_err;
++			}
++
++		/* Create guaranteed NUL-terminated identity
++		 * string for the callback */
++		memcpy(tmp_id, p, i);
++		memset(tmp_id+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
++		psk_len = s->psk_server_callback(s, tmp_id, psk, sizeof(psk));
+ 
++		if (psk_len > PSK_MAX_PSK_LEN)
++			{
++			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
++				ERR_R_INTERNAL_ERROR);
++			goto psk_err;
++			}
++		else if (psk_len == 0)
++			{
++			/* PSK related to the given identity not found */
++			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
++			       SSL_R_PSK_IDENTITY_NOT_FOUND);
++			al=SSL_AD_UNKNOWN_PSK_IDENTITY;
++			goto psk_err;
++			}
++		if (!(alg_k & SSL_kEECDH))
++			{
++			/* Create the shared secret now if we're not using ECDHE-PSK.*/
++			pre_ms_len=2+psk_len+2+psk_len;
++			t = pre_ms;
++			s2n(psk_len, t);
++			memset(t, 0, psk_len);
++			t+=psk_len;
++			s2n(psk_len, t);
++			memcpy(t, psk, psk_len);
++
++			s->session->master_key_length=
++				s->method->ssl3_enc->generate_master_secret(s,
++					s->session->master_key, pre_ms, pre_ms_len);
++			}
++		if (s->session->psk_identity != NULL)
++			OPENSSL_free(s->session->psk_identity);
++		s->session->psk_identity = BUF_strdup(tmp_id);
++		OPENSSL_cleanse(tmp_id, PSK_MAX_IDENTITY_LEN+1);
++		if (s->session->psk_identity == NULL)
++			{
++			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
++				ERR_R_MALLOC_FAILURE);
++			goto psk_err;
++			}
++
++		if (s->session->psk_identity_hint != NULL)
++			OPENSSL_free(s->session->psk_identity_hint);
++		s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
++		if (s->ctx->psk_identity_hint != NULL &&
++			s->session->psk_identity_hint == NULL)
++			{
++			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
++				ERR_R_MALLOC_FAILURE);
++			goto psk_err;
++			}
++
++		p += i;
++		n -= (i + 2);
++		psk_err = 0;
++	psk_err:
++		OPENSSL_cleanse(pre_ms, sizeof(pre_ms));
++		if (psk_err != 0)
++			goto f_err;
++		}
++#endif /* OPENSSL_NO_PSK */
++	if (0) {}
+ #ifndef OPENSSL_NO_RSA
+ 	if (alg_k & SSL_kRSA)
+ 		{
+@@ -2403,10 +2528,9 @@ int ssl3_get_client_key_exchange(SSL *s)
+ 				p,sizeof(rand_premaster_secret));
+ 		OPENSSL_cleanse(p,sizeof(rand_premaster_secret));
+ 		}
+-	else
+ #endif
+ #ifndef OPENSSL_NO_DH
+-		if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
++	else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+ 		{
+ 		n2s(p,i);
+ 		if (n != i+2)
+@@ -2467,10 +2591,9 @@ int ssl3_get_client_key_exchange(SSL *s)
+ 				s->session->master_key,p,i);
+ 		OPENSSL_cleanse(p,i);
+ 		}
+-	else
+ #endif
+ #ifndef OPENSSL_NO_KRB5
+-	if (alg_k & SSL_kKRB5)
++	else if (alg_k & SSL_kKRB5)
+ 		{
+ 		krb5_error_code		krb5rc;
+ 		krb5_data		enc_ticket;
+@@ -2659,17 +2782,20 @@ int ssl3_get_client_key_exchange(SSL *s)
+ 		**  if (s->kssl_ctx)  s->kssl_ctx = NULL;
+ 		*/
+ 		}
+-	else
+ #endif	/* OPENSSL_NO_KRB5 */
+-
+ #ifndef OPENSSL_NO_ECDH
+-		if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
++	else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
+ 		{
+ 		int ret = 1;
+ 		int field_size = 0;
+ 		const EC_KEY   *tkey;
+ 		const EC_GROUP *group;
+ 		const BIGNUM *priv_key;
++#ifndef OPENSSL_NO_PSK
++		unsigned char *pre_ms;
++		unsigned int pre_ms_len;
++		unsigned char *t;
++#endif /* OPENSSL_NO_PSK */
+ 
+ 		/* initialize structures for server's ECDH key pair */
+ 		if ((srvr_ecdh = EC_KEY_new()) == NULL) 
+@@ -2765,7 +2891,7 @@ int ssl3_get_client_key_exchange(SSL *s)
+ 				}
+ 
+ 			/* Get encoded point length */
+-			i = *p; 
++			i = *p;
+ 			p += 1;
+ 			if (n != 1 + i)
+ 				{
+@@ -2807,223 +2933,155 @@ int ssl3_get_client_key_exchange(SSL *s)
+ 		EC_KEY_free(srvr_ecdh);
+ 		BN_CTX_free(bn_ctx);
+ 		EC_KEY_free(s->s3->tmp.ecdh);
+-		s->s3->tmp.ecdh = NULL; 
++		s->s3->tmp.ecdh = NULL;
+ 
+-		/* Compute the master secret */
+-		s->session->master_key_length = s->method->ssl3_enc-> \
+-		    generate_master_secret(s, s->session->master_key, p, i);
+-		
+-		OPENSSL_cleanse(p, i);
+-		return (ret);
+-		}
+-	else
+-#endif
+ #ifndef OPENSSL_NO_PSK
+-		if (alg_k & SSL_kPSK)
++		/* ECDHE PSK ciphersuites from RFC 5489 */
++	    if ((alg_a & SSL_aPSK) && psk_len != 0)
+ 			{
+-			unsigned char *t = NULL;
+-			unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4];
+-			unsigned int pre_ms_len = 0, psk_len = 0;
+-			int psk_err = 1;
+-			char tmp_id[PSK_MAX_IDENTITY_LEN+1];
+-
+-			al=SSL_AD_HANDSHAKE_FAILURE;
+-
+-			n2s(p,i);
+-			if (n != i+2)
+-				{
+-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+-					SSL_R_LENGTH_MISMATCH);
+-				goto psk_err;
+-				}
+-			if (i > PSK_MAX_IDENTITY_LEN)
+-				{
+-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+-					SSL_R_DATA_LENGTH_TOO_LONG);
+-				goto psk_err;
+-				}
+-			if (s->psk_server_callback == NULL)
+-				{
+-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+-				       SSL_R_PSK_NO_SERVER_CB);
+-				goto psk_err;
+-				}
+-
+-			/* Create guaranteed NULL-terminated identity
+-			 * string for the callback */
+-			memcpy(tmp_id, p, i);
+-			memset(tmp_id+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
+-			psk_len = s->psk_server_callback(s, tmp_id,
+-				psk_or_pre_ms, sizeof(psk_or_pre_ms));
+-			OPENSSL_cleanse(tmp_id, PSK_MAX_IDENTITY_LEN+1);
+-
+-			if (psk_len > PSK_MAX_PSK_LEN)
+-				{
+-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+-					ERR_R_INTERNAL_ERROR);
+-				goto psk_err;
+-				}
+-			else if (psk_len == 0)
+-				{
+-				/* PSK related to the given identity not found */
+-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+-				       SSL_R_PSK_IDENTITY_NOT_FOUND);
+-				al=SSL_AD_UNKNOWN_PSK_IDENTITY;
+-				goto psk_err;
+-				}
+-
+-			/* create PSK pre_master_secret */
+-			pre_ms_len=2+psk_len+2+psk_len;
+-			t = psk_or_pre_ms;
+-			memmove(psk_or_pre_ms+psk_len+4, psk_or_pre_ms, psk_len);
+-			s2n(psk_len, t);
+-			memset(t, 0, psk_len);
+-			t+=psk_len;
+-			s2n(psk_len, t);
+-
+-			if (s->session->psk_identity != NULL)
+-				OPENSSL_free(s->session->psk_identity);
+-			s->session->psk_identity = BUF_strdup((char *)p);
+-			if (s->session->psk_identity == NULL)
+-				{
+-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+-					ERR_R_MALLOC_FAILURE);
+-				goto psk_err;
+-				}
+-
+-			if (s->session->psk_identity_hint != NULL)
+-				OPENSSL_free(s->session->psk_identity_hint);
+-			s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
+-			if (s->ctx->psk_identity_hint != NULL &&
+-				s->session->psk_identity_hint == NULL)
++			pre_ms_len = 2+psk_len+2+i;
++			pre_ms = OPENSSL_malloc(pre_ms_len);
++			if (pre_ms == NULL)
+ 				{
+ 				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ 					ERR_R_MALLOC_FAILURE);
+-				goto psk_err;
++				goto err;
+ 				}
+-
+-			s->session->master_key_length=
+-				s->method->ssl3_enc->generate_master_secret(s,
+-					s->session->master_key, psk_or_pre_ms, pre_ms_len);
+-			psk_err = 0;
+-		psk_err:
+-			OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
+-			if (psk_err != 0)
+-				goto f_err;
++			memset(pre_ms, 0, pre_ms_len);
++			t = pre_ms;
++			s2n(psk_len, t);
++			memcpy(t, psk, psk_len);
++			t += psk_len;
++			s2n(i, t);
++			memcpy(t, p, i);
++			s->session->master_key_length = s->method->ssl3_enc \
++				-> generate_master_secret(s,
++					s->session->master_key, pre_ms, pre_ms_len);
++			OPENSSL_cleanse(pre_ms, pre_ms_len);
++			OPENSSL_free(pre_ms);
+ 			}
+-		else
++#endif /* OPENSSL_NO_PSK */
++		if (!(alg_a & SSL_aPSK))
++			{
++			/* Compute the master secret */
++			s->session->master_key_length = s->method->ssl3_enc \
++				-> generate_master_secret(s,
++					s->session->master_key, p, i);
++			}
++
++		OPENSSL_cleanse(p, i);
++		}
+ #endif
+ #ifndef OPENSSL_NO_SRP
+-		if (alg_k & SSL_kSRP)
+-			{
+-			int param_len;
++	else if (alg_k & SSL_kSRP)
++		{
++		int param_len;
+ 
+-			n2s(p,i);
+-			param_len=i+2;
+-			if (param_len > n)
+-				{
+-				al=SSL_AD_DECODE_ERROR;
+-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_SRP_A_LENGTH);
+-				goto f_err;
+-				}
+-			if (!(s->srp_ctx.A=BN_bin2bn(p,i,NULL)))
+-				{
+-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_BN_LIB);
+-				goto err;
+-				}
+-			if (s->session->srp_username != NULL)
+-				OPENSSL_free(s->session->srp_username);
+-			s->session->srp_username = BUF_strdup(s->srp_ctx.login);
+-			if (s->session->srp_username == NULL)
+-				{
+-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+-					ERR_R_MALLOC_FAILURE);
+-				goto err;
+-				}
++		n2s(p,i);
++		param_len=i+2;
++		if (param_len > n)
++			{
++			al=SSL_AD_DECODE_ERROR;
++			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_SRP_A_LENGTH);
++			goto f_err;
++			}
++		if (!(s->srp_ctx.A=BN_bin2bn(p,i,NULL)))
++			{
++			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_BN_LIB);
++			goto err;
++			}
++		if (s->session->srp_username != NULL)
++			OPENSSL_free(s->session->srp_username);
++		s->session->srp_username = BUF_strdup(s->srp_ctx.login);
++		if (s->session->srp_username == NULL)
++			{
++			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
++				ERR_R_MALLOC_FAILURE);
++			goto err;
++			}
+ 
+-			if ((s->session->master_key_length = SRP_generate_server_master_secret(s,s->session->master_key))<0)
+-				{
+-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+-				goto err;
+-				}
++		if ((s->session->master_key_length = SRP_generate_server_master_secret(s,s->session->master_key))<0)
++			{
++			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
++			goto err;
++			}
+ 
+-			p+=i;
++		p+=i;
++		}
++#endif	/* OPENSSL_NO_SRP */
++	else if (alg_k & SSL_kGOST) 
++		{
++		int ret = 0;
++		EVP_PKEY_CTX *pkey_ctx;
++		EVP_PKEY *client_pub_pkey = NULL, *pk = NULL;
++		unsigned char premaster_secret[32], *start;
++		size_t outlen=32, inlen;
++		unsigned long alg_a;
++
++		/* Get our certificate private key*/
++		alg_a = s->s3->tmp.new_cipher->algorithm_auth;
++		if (alg_a & SSL_aGOST94)
++			pk = s->cert->pkeys[SSL_PKEY_GOST94].privatekey;
++		else if (alg_a & SSL_aGOST01)
++			pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
++
++		pkey_ctx = EVP_PKEY_CTX_new(pk,NULL);
++		EVP_PKEY_decrypt_init(pkey_ctx);
++		/* If client certificate is present and is of the same type, maybe
++		 * use it for key exchange.  Don't mind errors from
++		 * EVP_PKEY_derive_set_peer, because it is completely valid to use
++		 * a client certificate for authorization only. */
++		client_pub_pkey = X509_get_pubkey(s->session->peer);
++		if (client_pub_pkey)
++			{
++			if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0)
++				ERR_clear_error();
++			}
++		/* Decrypt session key */
++		if ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED))) 
++			{
++			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
++			goto gerr;
++			}
++		if (p[1] == 0x81)
++			{
++			start = p+3;
++			inlen = p[2];
++			}
++		else if (p[1] < 0x80)
++			{
++			start = p+2;
++			inlen = p[1];
+ 			}
+ 		else
+-#endif	/* OPENSSL_NO_SRP */
+-		if (alg_k & SSL_kGOST) 
+ 			{
+-			int ret = 0;
+-			EVP_PKEY_CTX *pkey_ctx;
+-			EVP_PKEY *client_pub_pkey = NULL, *pk = NULL;
+-			unsigned char premaster_secret[32], *start;
+-			size_t outlen=32, inlen;
+-			unsigned long alg_a;
+-
+-			/* Get our certificate private key*/
+-			alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+-			if (alg_a & SSL_aGOST94)
+-				pk = s->cert->pkeys[SSL_PKEY_GOST94].privatekey;
+-			else if (alg_a & SSL_aGOST01)
+-				pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
+-
+-			pkey_ctx = EVP_PKEY_CTX_new(pk,NULL);
+-			EVP_PKEY_decrypt_init(pkey_ctx);
+-			/* If client certificate is present and is of the same type, maybe
+-			 * use it for key exchange.  Don't mind errors from
+-			 * EVP_PKEY_derive_set_peer, because it is completely valid to use
+-			 * a client certificate for authorization only. */
+-			client_pub_pkey = X509_get_pubkey(s->session->peer);
+-			if (client_pub_pkey)
+-				{
+-				if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0)
+-					ERR_clear_error();
+-				}
+-			/* Decrypt session key */
+-			if ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED))) 
+-				{
+-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
+-				goto gerr;
+-				}
+-			if (p[1] == 0x81)
+-				{
+-				start = p+3;
+-				inlen = p[2];
+-				}
+-			else if (p[1] < 0x80)
+-				{
+-				start = p+2;
+-				inlen = p[1];
+-				}
+-			else
+-				{
+-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
+-				goto gerr;
+-				}
+-			if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,start,inlen) <=0) 
++			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
++			goto gerr;
++			}
++		if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,start,inlen) <=0) 
+ 
+-				{
+-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
+-				goto gerr;
+-				}
+-			/* Generate master secret */
+-			s->session->master_key_length=
+-				s->method->ssl3_enc->generate_master_secret(s,
+-					s->session->master_key,premaster_secret,32);
+-			/* Check if pubkey from client certificate was used */
+-			if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
+-				ret = 2;
+-			else
+-				ret = 1;
+-		gerr:
+-			EVP_PKEY_free(client_pub_pkey);
+-			EVP_PKEY_CTX_free(pkey_ctx);
+-			if (ret)
+-				return ret;
+-			else
+-				goto err;
++			{
++			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
++			goto gerr;
+ 			}
++		/* Generate master secret */
++		s->session->master_key_length=
++			s->method->ssl3_enc->generate_master_secret(s,
++				s->session->master_key,premaster_secret,32);
++		/* Check if pubkey from client certificate was used */
++		if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
++			ret = 2;
++		else
++			ret = 1;
++	gerr:
++		EVP_PKEY_free(client_pub_pkey);
++		EVP_PKEY_CTX_free(pkey_ctx);
++		if (ret)
++			return ret;
+ 		else
++			goto err;
++		}
++	else if (!(alg_k & SSL_kPSK))
+ 		{
+ 		al=SSL_AD_HANDSHAKE_FAILURE;
+ 		SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
+index ec54418..48fb9ef 100644
+--- a/ssl/ssl_lib.c
++++ b/ssl/ssl_lib.c
+@@ -1420,7 +1420,7 @@ int ssl_cipher_list_to_bytes(SSL *s,STACK_OF(SSL_CIPHER) *sk,unsigned char *p,
+ #endif /* OPENSSL_NO_KRB5 */
+ #ifndef OPENSSL_NO_PSK
+ 		/* with PSK there must be client callback set */
+-		if (((c->algorithm_mkey & SSL_kPSK) || (c->algorithm_auth & SSL_aPSK)) &&
++		if ((c->algorithm_auth & SSL_aPSK) &&
+ 		    s->psk_client_callback == NULL)
+ 			continue;
+ #endif /* OPENSSL_NO_PSK */
+diff --git a/ssl/tls1.h b/ssl/tls1.h
+index 9e035fb..3e6b7c7 100644
+--- a/ssl/tls1.h
++++ b/ssl/tls1.h
+@@ -536,6 +536,10 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb)
+ #define TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305		0x0300CC14
+ #define TLS1_CK_DHE_RSA_CHACHA20_POLY1305		0x0300CC15
+ 
++/* ECDHE PSK ciphersuites from RFC 5489 */
++#define TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA256    0x0300C037
++#define TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA384    0x0300C038
++
+ /* XXX
+  * Inconsistency alert:
+  * The OpenSSL names of ciphers with ephemeral DH here include the string
+@@ -691,6 +698,10 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb)
+ #define TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305	"ECDHE-ECDSA-CHACHA20-POLY1305"
+ #define TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305		"DHE-RSA-CHACHA20-POLY1305"
+ 
++/* ECDHE PSK ciphersuites from RFC 5489 */
++#define TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA256  "ECDHE-PSK-WITH-AES-128-CBC-SHA256"
++#define TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA384  "ECDHE-PSK-WITH-AES-256-CBC-SHA384"
++
+ #define TLS_CT_RSA_SIGN			1
+ #define TLS_CT_DSS_SIGN			2
+ #define TLS_CT_RSA_FIXED_DH		3
+-- 
+1.9.1.423.g4596e3a
+
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index f71470a..6d2b002 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -345,9 +345,10 @@
 				}
 #endif
 			/* Check if it is anon DH/ECDH */
-			/* or PSK */
+			/* or non-RSA PSK */
 			if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
-			    !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
+			    !((s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK) &&
+			      !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kRSA)))
 				{
 				ret=ssl3_get_server_certificate(s);
 				if (ret <= 0) goto end;
@@ -1377,7 +1378,7 @@
 		   omitted if no identity hint is sent. Set
 		   session->sess_cert anyway to avoid problems
 		   later.*/
-		if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)
+		if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK)
 			{
 			s->session->sess_cert=ssl_sess_cert_new();
 			if (s->ctx->psk_identity_hint)
@@ -1425,52 +1426,56 @@
 	EVP_MD_CTX_init(&md_ctx);
 
 #ifndef OPENSSL_NO_PSK
-	if (alg_k & SSL_kPSK)
+	if (alg_a & SSL_aPSK)
 		{
 		char tmp_id_hint[PSK_MAX_IDENTITY_LEN+1];
 
 		al=SSL_AD_HANDSHAKE_FAILURE;
 		n2s(p,i);
 		param_len=i+2;
-		/* Store PSK identity hint for later use, hint is used
-		 * in ssl3_send_client_key_exchange.  Assume that the
-		 * maximum length of a PSK identity hint can be as
-		 * long as the maximum length of a PSK identity. */
-		if (i > PSK_MAX_IDENTITY_LEN)
+		s->ctx->psk_identity_hint = NULL;
+		if (i != 0)
 			{
-			SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
-				SSL_R_DATA_LENGTH_TOO_LONG);
-			goto f_err;
+			/* Store PSK identity hint for later use, hint is used
+			 * in ssl3_send_client_key_exchange.  Assume that the
+			 * maximum length of a PSK identity hint can be as
+			 * long as the maximum length of a PSK identity. */
+			if (i > PSK_MAX_IDENTITY_LEN)
+				{
+				SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
+					SSL_R_DATA_LENGTH_TOO_LONG);
+				goto f_err;
+				}
+			if (param_len > n)
+				{
+				al=SSL_AD_DECODE_ERROR;
+				SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
+					SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH);
+				goto f_err;
+				}
+			/* If received PSK identity hint contains NULL
+			 * characters, the hint is truncated from the first
+			 * NULL. p may not be ending with NULL, so create a
+			 * NULL-terminated string. */
+			memcpy(tmp_id_hint, p, i);
+			memset(tmp_id_hint+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
+			if (s->ctx->psk_identity_hint != NULL)
+				OPENSSL_free(s->ctx->psk_identity_hint);
+			s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint);
+			if (s->ctx->psk_identity_hint == NULL)
+				{
+				SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+				goto f_err;
+				}
 			}
-		if (param_len > n)
-			{
-			al=SSL_AD_DECODE_ERROR;
-			SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
-				SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH);
-			goto f_err;
-			}
-		/* If received PSK identity hint contains NULL
-		 * characters, the hint is truncated from the first
-		 * NULL. p may not be ending with NULL, so create a
-		 * NULL-terminated string. */
-		memcpy(tmp_id_hint, p, i);
-		memset(tmp_id_hint+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
-		if (s->ctx->psk_identity_hint != NULL)
-			OPENSSL_free(s->ctx->psk_identity_hint);
-		s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint);
-		if (s->ctx->psk_identity_hint == NULL)
-			{
-			SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-			goto f_err;
-			}	   
-
 		p+=i;
 		n-=param_len;
 		}
-	else
 #endif /* !OPENSSL_NO_PSK */
+
+	if (0) {}
 #ifndef OPENSSL_NO_SRP
-	if (alg_k & SSL_kSRP)
+	else if (alg_k & SSL_kSRP)
 		{
 		n2s(p,i);
 		param_len=i+2;
@@ -1547,10 +1552,9 @@
 			pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN].x509);
 #endif
 		}
-	else
 #endif /* !OPENSSL_NO_SRP */
 #ifndef OPENSSL_NO_RSA
-	if (alg_k & SSL_kRSA)
+	else if (alg_k & SSL_kRSA)
 		{
 		if ((rsa=RSA_new()) == NULL)
 			{
@@ -1599,9 +1603,6 @@
 		s->session->sess_cert->peer_rsa_tmp=rsa;
 		rsa=NULL;
 		}
-#else /* OPENSSL_NO_RSA */
-	if (0)
-		;
 #endif
 #ifndef OPENSSL_NO_DH
 	else if (alg_k & SSL_kEDH)
@@ -1782,14 +1783,14 @@
 		EC_POINT_free(srvr_ecpoint);
 		srvr_ecpoint = NULL;
 		}
-	else if (alg_k)
+#endif /* !OPENSSL_NO_ECDH */
+
+	else if (!(alg_k & SSL_kPSK))
 		{
 		al=SSL_AD_UNEXPECTED_MESSAGE;
 		SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
 		goto f_err;
 		}
-#endif /* !OPENSSL_NO_ECDH */
-
 
 	/* p points to the next byte, there are 'n' bytes left */
 
@@ -1894,8 +1895,9 @@
 		}
 	else
 		{
-		if (!(alg_a & SSL_aNULL) && !(alg_k & SSL_kPSK))
-			/* aNULL or kPSK do not need public keys */
+		if (!(alg_a & SSL_aNULL) &&
+			/* Among PSK ciphers only RSA_PSK needs a public key */
+			!((alg_a & SSL_aPSK) && !(alg_k & SSL_kRSA)))
 			{
 			SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
 			goto err;
@@ -2297,6 +2299,7 @@
 	unsigned char *p,*d;
 	int n;
 	unsigned long alg_k;
+	unsigned long alg_a;
 #ifndef OPENSSL_NO_RSA
 	unsigned char *q;
 	EVP_PKEY *pkey=NULL;
@@ -2311,7 +2314,11 @@
 	unsigned char *encodedPoint = NULL;
 	int encoded_pt_len = 0;
 	BN_CTX * bn_ctx = NULL;
-#endif
+#ifndef OPENSSL_NO_PSK
+	unsigned int psk_len = 0;
+	unsigned char psk[PSK_MAX_PSK_LEN];
+#endif /* OPENSSL_NO_PSK */
+#endif /* OPENSSL_NO_ECDH */
 
 	if (s->state == SSL3_ST_CW_KEY_EXCH_A)
 		{
@@ -2319,7 +2326,96 @@
 		p= &(d[4]);
 
 		alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
+		alg_a=s->s3->tmp.new_cipher->algorithm_auth;
 
+#ifndef OPENSSL_NO_PSK
+		if (alg_a & SSL_aPSK)
+			{
+			char identity[PSK_MAX_IDENTITY_LEN];
+			unsigned char *t = NULL;
+			unsigned char pre_ms[PSK_MAX_PSK_LEN*2+4];
+			unsigned int pre_ms_len = 0;
+			int psk_err = 1;
+
+			n = 0;
+			if (s->psk_client_callback == NULL)
+				{
+				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+					SSL_R_PSK_NO_CLIENT_CB);
+				goto err;
+				}
+
+			psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint,
+				identity, PSK_MAX_IDENTITY_LEN, psk, sizeof(psk));
+			if (psk_len > PSK_MAX_PSK_LEN)
+				{
+				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+					ERR_R_INTERNAL_ERROR);
+				goto psk_err;
+				}
+			else if (psk_len == 0)
+				{
+				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+					SSL_R_PSK_IDENTITY_NOT_FOUND);
+				goto psk_err;
+				}
+
+			if (!(alg_k & SSL_kEECDH))
+				{
+				/* Create the shared secret now if we're not using ECDHE-PSK.*/
+				pre_ms_len = 2+psk_len+2+psk_len;
+				t = pre_ms;
+				s2n(psk_len, t);
+				memset(t, 0, psk_len);
+				t+=psk_len;
+				s2n(psk_len, t);
+				memcpy(t, psk, psk_len);
+
+				s->session->master_key_length =
+					s->method->ssl3_enc->generate_master_secret(s,
+						s->session->master_key,
+						pre_ms, pre_ms_len);
+				n = strlen(identity);
+				s2n(n, p);
+				memcpy(p, identity, n);
+				n += 2;
+				}
+
+			if (s->session->psk_identity_hint != NULL)
+				OPENSSL_free(s->session->psk_identity_hint);
+			s->session->psk_identity_hint = NULL;
+			if (s->ctx->psk_identity_hint)
+				{
+				s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
+				if (s->ctx->psk_identity_hint != NULL &&
+					s->session->psk_identity_hint == NULL)
+					{
+					SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+						ERR_R_MALLOC_FAILURE);
+					goto psk_err;
+					}
+				}
+
+			if (s->session->psk_identity != NULL)
+				OPENSSL_free(s->session->psk_identity);
+			s->session->psk_identity = BUF_strdup(identity);
+			if (s->session->psk_identity == NULL)
+				{
+				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+					ERR_R_MALLOC_FAILURE);
+				goto psk_err;
+				}
+			psk_err = 0;
+		psk_err:
+			OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN);
+			OPENSSL_cleanse(pre_ms, sizeof(pre_ms));
+			if (psk_err != 0)
+				{
+				ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+				goto err;
+				}
+			}
+#endif
 		/* Fool emacs indentation */
 		if (0) {}
 #ifndef OPENSSL_NO_RSA
@@ -2580,14 +2676,19 @@
 			/* perhaps clean things up a bit EAY EAY EAY EAY*/
 			}
 #endif
-
-#ifndef OPENSSL_NO_ECDH 
+#ifndef OPENSSL_NO_ECDH
 		else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
 			{
 			const EC_GROUP *srvr_group = NULL;
 			EC_KEY *tkey;
 			int ecdh_clnt_cert = 0;
 			int field_size = 0;
+#ifndef OPENSSL_NO_PSK
+			unsigned char *pre_ms;
+			unsigned char *t;
+			unsigned int pre_ms_len;
+			unsigned int i;
+#endif
 
 			/* Did we send out the client's
 			 * ECDH share for use in premaster
@@ -2708,15 +2809,41 @@
 				goto err;
 				}
 
-			/* generate master key from the result */
-			s->session->master_key_length = s->method->ssl3_enc \
-			    -> generate_master_secret(s, 
-				s->session->master_key,
-				p, n);
-
+#ifndef OPENSSL_NO_PSK
+			/* ECDHE PSK ciphersuites from RFC 5489 */
+			if ((alg_a & SSL_aPSK) && psk_len != 0)
+				{
+				pre_ms_len = 2+psk_len+2+n;
+				pre_ms = OPENSSL_malloc(pre_ms_len);
+				if (pre_ms == NULL)
+					{
+					SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+			    		ERR_R_MALLOC_FAILURE);
+					goto err;
+					}
+				memset(pre_ms, 0, pre_ms_len);
+				t = pre_ms;
+				s2n(psk_len, t);
+				memcpy(t, psk, psk_len);
+				t += psk_len;
+				s2n(n, t);
+				memcpy(t, p, n);
+				s->session->master_key_length = s->method->ssl3_enc \
+					-> generate_master_secret(s,
+						s->session->master_key, pre_ms, pre_ms_len);
+				OPENSSL_cleanse(pre_ms, pre_ms_len);
+				OPENSSL_free(pre_ms);
+				}
+#endif /* OPENSSL_NO_PSK */
+			if (!(alg_a & SSL_aPSK))
+				{
+				/* generate master key from the result */
+				s->session->master_key_length = s->method->ssl3_enc \
+					-> generate_master_secret(s,
+						s->session->master_key, p, n);
+				}
 			memset(p, 0, n); /* clean up */
-
-			if (ecdh_clnt_cert) 
+			if (ecdh_clnt_cert)
 				{
 				/* Send empty client key exch message */
 				n = 0;
@@ -2744,29 +2871,42 @@
 					}
 
 				/* Encode the public key */
-				n = EC_POINT_point2oct(srvr_group, 
-				    EC_KEY_get0_public_key(clnt_ecdh), 
-				    POINT_CONVERSION_UNCOMPRESSED, 
+				encoded_pt_len = EC_POINT_point2oct(srvr_group,
+				    EC_KEY_get0_public_key(clnt_ecdh),
+				    POINT_CONVERSION_UNCOMPRESSED,
 				    encodedPoint, encoded_pt_len, bn_ctx);
+				
+				n = 0;
+#ifndef OPENSSL_NO_PSK
+				if ((alg_a & SSL_aPSK) && psk_len != 0)
+					{
+					i = strlen(s->session->psk_identity);
+					s2n(i, p);
+					memcpy(p, s->session->psk_identity, i);
+					p += i;
+					n = i + 2;
+					}
+#endif
 
-				*p = n; /* length of encoded point */
+				*p = encoded_pt_len; /* length of encoded point */
 				/* Encoded point will be copied here */
-				p += 1; 
+				p += 1;
+				n += 1;
 				/* copy the point */
-				memcpy((unsigned char *)p, encodedPoint, n);
+				memcpy((unsigned char *)p, encodedPoint, encoded_pt_len);
 				/* increment n to account for length field */
-				n += 1; 
+				n += encoded_pt_len;
 				}
 
 			/* Free allocated memory */
 			BN_CTX_free(bn_ctx);
 			if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
-			if (clnt_ecdh != NULL) 
+			if (clnt_ecdh != NULL)
 				 EC_KEY_free(clnt_ecdh);
 			EVP_PKEY_free(srvr_pub_pkey);
 			}
 #endif /* !OPENSSL_NO_ECDH */
-		else if (alg_k & SSL_kGOST) 
+		else if (alg_k & SSL_kGOST)
 			{
 			/* GOST key exchange message creation */
 			EVP_PKEY_CTX *pkey_ctx;
@@ -2889,89 +3029,7 @@
 				}
 			}
 #endif
-#ifndef OPENSSL_NO_PSK
-		else if (alg_k & SSL_kPSK)
-			{
-			char identity[PSK_MAX_IDENTITY_LEN];
-			unsigned char *t = NULL;
-			unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4];
-			unsigned int pre_ms_len = 0, psk_len = 0;
-			int psk_err = 1;
-
-			n = 0;
-			if (s->psk_client_callback == NULL)
-				{
-				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-					SSL_R_PSK_NO_CLIENT_CB);
-				goto err;
-				}
-
-			psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint,
-				identity, PSK_MAX_IDENTITY_LEN,
-				psk_or_pre_ms, sizeof(psk_or_pre_ms));
-			if (psk_len > PSK_MAX_PSK_LEN)
-				{
-				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-					ERR_R_INTERNAL_ERROR);
-				goto psk_err;
-				}
-			else if (psk_len == 0)
-				{
-				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-					SSL_R_PSK_IDENTITY_NOT_FOUND);
-				goto psk_err;
-				}
-
-			/* create PSK pre_master_secret */
-			pre_ms_len = 2+psk_len+2+psk_len;
-			t = psk_or_pre_ms;
-			memmove(psk_or_pre_ms+psk_len+4, psk_or_pre_ms, psk_len);
-			s2n(psk_len, t);
-			memset(t, 0, psk_len);
-			t+=psk_len;
-			s2n(psk_len, t);
-
-			if (s->session->psk_identity_hint != NULL)
-				OPENSSL_free(s->session->psk_identity_hint);
-			s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
-			if (s->ctx->psk_identity_hint != NULL &&
-				s->session->psk_identity_hint == NULL)
-				{
-				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-					ERR_R_MALLOC_FAILURE);
-				goto psk_err;
-				}
-
-			if (s->session->psk_identity != NULL)
-				OPENSSL_free(s->session->psk_identity);
-			s->session->psk_identity = BUF_strdup(identity);
-			if (s->session->psk_identity == NULL)
-				{
-				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
-					ERR_R_MALLOC_FAILURE);
-				goto psk_err;
-				}
-
-			s->session->master_key_length =
-				s->method->ssl3_enc->generate_master_secret(s,
-					s->session->master_key,
-					psk_or_pre_ms, pre_ms_len); 
-			n = strlen(identity);
-			s2n(n, p);
-			memcpy(p, identity, n);
-			n+=2;
-			psk_err = 0;
-		psk_err:
-			OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN);
-			OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
-			if (psk_err != 0)
-				{
-				ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-				goto err;
-				}
-			}
-#endif
-		else
+		else if (!(alg_k & SSL_kPSK))
 			{
 			ssl3_send_alert(s, SSL3_AL_FATAL,
 			    SSL_AD_HANDSHAKE_FAILURE);
@@ -3276,7 +3334,7 @@
 	alg_a=s->s3->tmp.new_cipher->algorithm_auth;
 
 	/* we don't have a certificate */
-	if ((alg_a & (SSL_aDH|SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
+	if ((alg_a & (SSL_aDH|SSL_aNULL|SSL_aKRB5)) || ((alg_a & SSL_aPSK) && !(alg_k & SSL_kRSA)))
 		return(1);
 
 	sc=s->session->sess_cert;
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index f7a5c6f..f84da7f 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -2826,6 +2826,42 @@
 	256,
 	},
 
+#ifndef OPENSSL_NO_PSK
+    /* ECDH PSK ciphersuites from RFC 5489 */
+
+	/* Cipher C037 */
+	{
+	1,
+	TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+	TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+	SSL_kEECDH,
+	SSL_aPSK,
+	SSL_AES128,
+	SSL_SHA256,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF_SHA256,
+	128,
+	128,
+	},
+
+	/* Cipher C038 */
+	{
+	1,
+	TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
+	TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
+	SSL_kEECDH,
+	SSL_aPSK,
+	SSL_AES256,
+	SSL_SHA384,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF_SHA384,
+	256,
+	256,
+	},
+#endif /* OPENSSL_NO_PSK */
+
 #endif /* OPENSSL_NO_ECDH */
 
 
@@ -3911,7 +3947,7 @@
 #endif /* OPENSSL_NO_KRB5 */
 #ifndef OPENSSL_NO_PSK
 		/* with PSK there must be server callback set */
-		if ((alg_k & SSL_kPSK) && s->psk_server_callback == NULL)
+		if ((alg_a & SSL_aPSK) && s->psk_server_callback == NULL)
 			continue;
 #endif /* OPENSSL_NO_PSK */
 
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 8692f14..68ed534 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -217,6 +217,7 @@
 	{
 	BUF_MEM *buf;
 	unsigned long alg_k,Time=(unsigned long)time(NULL);
+	unsigned long alg_a;
 	void (*cb)(const SSL *ssl,int type,int val)=NULL;
 	int ret= -1;
 	int new_state,state,skip=0;
@@ -412,9 +413,11 @@
 		case SSL3_ST_SW_CERT_A:
 		case SSL3_ST_SW_CERT_B:
 			/* Check if it is anon DH or anon ECDH, */
-			/* normal PSK or KRB5 or SRP */
+			/* non-RSA PSK or KRB5 or SRP */
 			if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
-				&& !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)
+				/* Among PSK ciphersuites only RSA_PSK uses server certificate */
+				&& !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK &&
+					 !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kRSA))
 				&& !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5))
 				{
 				ret=ssl3_send_server_certificate(s);
@@ -443,6 +446,7 @@
 		case SSL3_ST_SW_KEY_EXCH_A:
 		case SSL3_ST_SW_KEY_EXCH_B:
 			alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+			alg_a = s->s3->tmp.new_cipher->algorithm_auth;
 
 			/* clear this, it may get reset by
 			 * send_server_key_exchange */
@@ -472,10 +476,12 @@
 			 * public key for key exchange.
 			 */
 			if (s->s3->tmp.use_rsa_tmp
-			/* PSK: send ServerKeyExchange if PSK identity
-			 * hint if provided */
+			/* PSK: send ServerKeyExchange if either:
+			 *   - PSK identity hint is provided, or
+			 *   - the key exchange is kEECDH.
+			 */
 #ifndef OPENSSL_NO_PSK
-			    || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint)
+			    || ((alg_a & SSL_aPSK) && ((alg_k & SSL_kEECDH) || s->ctx->psk_identity_hint))
 #endif
 #ifndef OPENSSL_NO_SRP
 			    /* SRP: send ServerKeyExchange */
@@ -1593,7 +1599,8 @@
 	const EVP_MD *md = NULL;
 	unsigned char *p,*d;
 	int al,i;
-	unsigned long type;
+	unsigned long alg_k;
+	unsigned long alg_a;
 	int n;
 	CERT *cert;
 	BIGNUM *r[4];
@@ -1604,15 +1611,25 @@
 	EVP_MD_CTX_init(&md_ctx);
 	if (s->state == SSL3_ST_SW_KEY_EXCH_A)
 		{
-		type=s->s3->tmp.new_cipher->algorithm_mkey;
+		alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
+		alg_a=s->s3->tmp.new_cipher->algorithm_auth;
 		cert=s->cert;
 
 		buf=s->init_buf;
 
 		r[0]=r[1]=r[2]=r[3]=NULL;
 		n=0;
+#ifndef OPENSSL_NO_PSK
+		if (alg_a & SSL_aPSK)
+			{
+			/* size for PSK identity hint */
+			n+=2;
+			if (s->ctx->psk_identity_hint)
+				n+=strlen(s->ctx->psk_identity_hint);
+			}
+#endif /* !OPENSSL_NO_PSK */
 #ifndef OPENSSL_NO_RSA
-		if (type & SSL_kRSA)
+		if (alg_k & SSL_kRSA)
 			{
 			rsa=cert->rsa_tmp;
 			if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL))
@@ -1639,10 +1656,9 @@
 			r[1]=rsa->e;
 			s->s3->tmp.use_rsa_tmp=1;
 			}
-		else
 #endif
 #ifndef OPENSSL_NO_DH
-			if (type & SSL_kEDH)
+		else if (alg_k & SSL_kEDH)
 			{
 			dhp=cert->dh_tmp;
 			if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
@@ -1695,10 +1711,9 @@
 			r[1]=dh->g;
 			r[2]=dh->pub_key;
 			}
-		else 
 #endif
 #ifndef OPENSSL_NO_ECDH
-			if (type & SSL_kEECDH)
+		else if (alg_k & SSL_kEECDH)
 			{
 			const EC_GROUP *group;
 
@@ -1811,7 +1826,7 @@
 			 * to encode the entire ServerECDHParams
 			 * structure. 
 			 */
-			n = 4 + encodedlen;
+			n += 4 + encodedlen;
 
 			/* We'll generate the serverKeyExchange message
 			 * explicitly so we can set these to NULLs
@@ -1821,18 +1836,9 @@
 			r[2]=NULL;
 			r[3]=NULL;
 			}
-		else 
 #endif /* !OPENSSL_NO_ECDH */
-#ifndef OPENSSL_NO_PSK
-			if (type & SSL_kPSK)
-				{
-				/* reserve size for record length and PSK identity hint*/
-				n+=2+strlen(s->ctx->psk_identity_hint);
-				}
-			else
-#endif /* !OPENSSL_NO_PSK */
 #ifndef OPENSSL_NO_SRP
-		if (type & SSL_kSRP)
+		else if (alg_k & SSL_kSRP)
 			{
 			if ((s->srp_ctx.N == NULL) ||
 				(s->srp_ctx.g == NULL) ||
@@ -1847,8 +1853,8 @@
 			r[2]=s->srp_ctx.s;
 			r[3]=s->srp_ctx.B;
 			}
-		else 
 #endif
+		else if (!(alg_k & SSL_kPSK))
 			{
 			al=SSL_AD_HANDSHAKE_FAILURE;
 			SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
@@ -1858,15 +1864,16 @@
 			{
 			nr[i]=BN_num_bytes(r[i]);
 #ifndef OPENSSL_NO_SRP
-			if ((i == 2) && (type & SSL_kSRP))
+			if ((i == 2) && (alg_k & SSL_kSRP))
 				n+=1+nr[i];
 			else
 #endif
 			n+=2+nr[i];
 			}
 
-		if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
-			&& !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
+		if (!(alg_a & SSL_aNULL)
+			/* Among PSK ciphersuites only RSA uses a certificate */
+			&& !((alg_a & SSL_aPSK) && !(alg_k & SSL_kRSA)))
 			{
 			if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher,&md))
 				== NULL)
@@ -1893,7 +1900,7 @@
 		for (i=0; i < 4 && r[i] != NULL; i++)
 			{
 #ifndef OPENSSL_NO_SRP
-			if ((i == 2) && (type & SSL_kSRP))
+			if ((i == 2) && (alg_k & SSL_kSRP))
 				{
 				*p = nr[i];
 				p++;
@@ -1905,8 +1912,32 @@
 			p+=nr[i];
 			}
 
+/* Note: ECDHE PSK ciphersuites use SSL_kEECDH and SSL_aPSK.
+ * When one of them is used, the server key exchange record needs to have both
+ * the psk_identity_hint and the ServerECDHParams. */
+#ifndef OPENSSL_NO_PSK
+		if (alg_a & SSL_aPSK)
+			{
+			if (s->ctx->psk_identity_hint)
+				{
+				/* copy PSK identity hint */
+				s2n(strlen(s->ctx->psk_identity_hint), p);
+				strncpy((char *)p, s->ctx->psk_identity_hint, strlen(s->ctx->psk_identity_hint));
+				p+=strlen(s->ctx->psk_identity_hint);
+				}
+			else
+				{
+				/* No identity hint is provided. */
+				*p = 0;
+				p += 1;
+				*p = 0;
+				p += 1;
+				}
+			}
+#endif /* OPENSSL_NO_PSK */
+
 #ifndef OPENSSL_NO_ECDH
-		if (type & SSL_kEECDH) 
+		if (alg_k & SSL_kEECDH)
 			{
 			/* XXX: For now, we only support named (not generic) curves.
 			 * In this situation, the serverKeyExchange message has:
@@ -1929,17 +1960,7 @@
 			encodedPoint = NULL;
 			p += encodedlen;
 			}
-#endif
-
-#ifndef OPENSSL_NO_PSK
-		if (type & SSL_kPSK)
-			{
-			/* copy PSK identity hint */
-			s2n(strlen(s->ctx->psk_identity_hint), p); 
-			strncpy((char *)p, s->ctx->psk_identity_hint, strlen(s->ctx->psk_identity_hint));
-			p+=strlen(s->ctx->psk_identity_hint);
-			}
-#endif
+#endif /* OPENSSL_NO_ECDH */
 
 		/* not anonymous */
 		if (pkey != NULL)
@@ -1976,7 +1997,7 @@
 				n+=u+2;
 				}
 			else
-#endif
+#endif /* OPENSSL_NO_RSA */
 			if (md)
 				{
 				/* For TLS1.2 and later send signature
@@ -2145,6 +2166,7 @@
 	int i,al,ok;
 	long n;
 	unsigned long alg_k;
+	unsigned long alg_a;
 	unsigned char *p;
 #ifndef OPENSSL_NO_RSA
 	RSA *rsa=NULL;
@@ -2162,7 +2184,11 @@
 	EC_KEY *srvr_ecdh = NULL;
 	EVP_PKEY *clnt_pub_pkey = NULL;
 	EC_POINT *clnt_ecpoint = NULL;
-	BN_CTX *bn_ctx = NULL; 
+	BN_CTX *bn_ctx = NULL;
+#ifndef OPENSSL_NO_PSK
+	unsigned int psk_len = 0;
+	unsigned char psk[PSK_MAX_PSK_LEN];
+#endif /* OPENSSL_NO_PSK */
 #endif
 
 	n=s->method->ssl_get_message(s,
@@ -2176,7 +2202,106 @@
 	p=(unsigned char *)s->init_msg;
 
 	alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
+	alg_a=s->s3->tmp.new_cipher->algorithm_auth;
 
+#ifndef OPENSSL_NO_PSK
+	if (alg_a & SSL_aPSK)
+		{
+		unsigned char *t = NULL;
+		unsigned char pre_ms[PSK_MAX_PSK_LEN*2+4];
+		unsigned int pre_ms_len = 0;
+		int psk_err = 1;
+		char tmp_id[PSK_MAX_IDENTITY_LEN+1];
+
+		al=SSL_AD_HANDSHAKE_FAILURE;
+
+		n2s(p, i);
+		if (n != i+2 && !(alg_k & SSL_kEECDH))
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				SSL_R_LENGTH_MISMATCH);
+			goto psk_err;
+			}
+		if (i > PSK_MAX_IDENTITY_LEN)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				SSL_R_DATA_LENGTH_TOO_LONG);
+			goto psk_err;
+			}
+		if (s->psk_server_callback == NULL)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+			       SSL_R_PSK_NO_SERVER_CB);
+			goto psk_err;
+			}
+
+		/* Create guaranteed NUL-terminated identity
+		 * string for the callback */
+		memcpy(tmp_id, p, i);
+		memset(tmp_id+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
+		psk_len = s->psk_server_callback(s, tmp_id, psk, sizeof(psk));
+
+		if (psk_len > PSK_MAX_PSK_LEN)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				ERR_R_INTERNAL_ERROR);
+			goto psk_err;
+			}
+		else if (psk_len == 0)
+			{
+			/* PSK related to the given identity not found */
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+			       SSL_R_PSK_IDENTITY_NOT_FOUND);
+			al=SSL_AD_UNKNOWN_PSK_IDENTITY;
+			goto psk_err;
+			}
+		if (!(alg_k & SSL_kEECDH))
+			{
+			/* Create the shared secret now if we're not using ECDHE-PSK.*/
+			pre_ms_len=2+psk_len+2+psk_len;
+			t = pre_ms;
+			s2n(psk_len, t);
+			memset(t, 0, psk_len);
+			t+=psk_len;
+			s2n(psk_len, t);
+			memcpy(t, psk, psk_len);
+
+			s->session->master_key_length=
+				s->method->ssl3_enc->generate_master_secret(s,
+					s->session->master_key, pre_ms, pre_ms_len);
+			}
+		if (s->session->psk_identity != NULL)
+			OPENSSL_free(s->session->psk_identity);
+		s->session->psk_identity = BUF_strdup(tmp_id);
+		OPENSSL_cleanse(tmp_id, PSK_MAX_IDENTITY_LEN+1);
+		if (s->session->psk_identity == NULL)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				ERR_R_MALLOC_FAILURE);
+			goto psk_err;
+			}
+
+		if (s->session->psk_identity_hint != NULL)
+			OPENSSL_free(s->session->psk_identity_hint);
+		s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
+		if (s->ctx->psk_identity_hint != NULL &&
+			s->session->psk_identity_hint == NULL)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				ERR_R_MALLOC_FAILURE);
+			goto psk_err;
+			}
+
+		p += i;
+		n -= (i + 2);
+		psk_err = 0;
+	psk_err:
+		OPENSSL_cleanse(pre_ms, sizeof(pre_ms));
+		if (psk_err != 0)
+			goto f_err;
+		}
+#endif /* OPENSSL_NO_PSK */
+	if (0) {}
 #ifndef OPENSSL_NO_RSA
 	if (alg_k & SSL_kRSA)
 		{
@@ -2281,10 +2406,9 @@
 				p,i);
 		OPENSSL_cleanse(p,i);
 		}
-	else
 #endif
 #ifndef OPENSSL_NO_DH
-		if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+	else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
 		{
 		n2s(p,i);
 		if (n != i+2)
@@ -2345,10 +2469,9 @@
 				s->session->master_key,p,i);
 		OPENSSL_cleanse(p,i);
 		}
-	else
 #endif
 #ifndef OPENSSL_NO_KRB5
-	if (alg_k & SSL_kKRB5)
+	else if (alg_k & SSL_kKRB5)
 		{
 		krb5_error_code		krb5rc;
 		krb5_data		enc_ticket;
@@ -2537,17 +2660,20 @@
 		**  if (s->kssl_ctx)  s->kssl_ctx = NULL;
 		*/
 		}
-	else
 #endif	/* OPENSSL_NO_KRB5 */
-
 #ifndef OPENSSL_NO_ECDH
-		if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
+	else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
 		{
 		int ret = 1;
 		int field_size = 0;
 		const EC_KEY   *tkey;
 		const EC_GROUP *group;
 		const BIGNUM *priv_key;
+#ifndef OPENSSL_NO_PSK
+		unsigned char *pre_ms;
+		unsigned int pre_ms_len;
+		unsigned char *t;
+#endif /* OPENSSL_NO_PSK */
 
 		/* initialize structures for server's ECDH key pair */
 		if ((srvr_ecdh = EC_KEY_new()) == NULL) 
@@ -2643,7 +2769,7 @@
 				}
 
 			/* Get encoded point length */
-			i = *p; 
+			i = *p;
 			p += 1;
 			if (n != 1 + i)
 				{
@@ -2685,223 +2811,155 @@
 		EC_KEY_free(srvr_ecdh);
 		BN_CTX_free(bn_ctx);
 		EC_KEY_free(s->s3->tmp.ecdh);
-		s->s3->tmp.ecdh = NULL; 
+		s->s3->tmp.ecdh = NULL;
 
-		/* Compute the master secret */
-		s->session->master_key_length = s->method->ssl3_enc-> \
-		    generate_master_secret(s, s->session->master_key, p, i);
-		
-		OPENSSL_cleanse(p, i);
-		return (ret);
-		}
-	else
-#endif
 #ifndef OPENSSL_NO_PSK
-		if (alg_k & SSL_kPSK)
+		/* ECDHE PSK ciphersuites from RFC 5489 */
+	    if ((alg_a & SSL_aPSK) && psk_len != 0)
 			{
-			unsigned char *t = NULL;
-			unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4];
-			unsigned int pre_ms_len = 0, psk_len = 0;
-			int psk_err = 1;
-			char tmp_id[PSK_MAX_IDENTITY_LEN+1];
-
-			al=SSL_AD_HANDSHAKE_FAILURE;
-
-			n2s(p,i);
-			if (n != i+2)
-				{
-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-					SSL_R_LENGTH_MISMATCH);
-				goto psk_err;
-				}
-			if (i > PSK_MAX_IDENTITY_LEN)
-				{
-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-					SSL_R_DATA_LENGTH_TOO_LONG);
-				goto psk_err;
-				}
-			if (s->psk_server_callback == NULL)
-				{
-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-				       SSL_R_PSK_NO_SERVER_CB);
-				goto psk_err;
-				}
-
-			/* Create guaranteed NULL-terminated identity
-			 * string for the callback */
-			memcpy(tmp_id, p, i);
-			memset(tmp_id+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
-			psk_len = s->psk_server_callback(s, tmp_id,
-				psk_or_pre_ms, sizeof(psk_or_pre_ms));
-			OPENSSL_cleanse(tmp_id, PSK_MAX_IDENTITY_LEN+1);
-
-			if (psk_len > PSK_MAX_PSK_LEN)
-				{
-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-					ERR_R_INTERNAL_ERROR);
-				goto psk_err;
-				}
-			else if (psk_len == 0)
-				{
-				/* PSK related to the given identity not found */
-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-				       SSL_R_PSK_IDENTITY_NOT_FOUND);
-				al=SSL_AD_UNKNOWN_PSK_IDENTITY;
-				goto psk_err;
-				}
-
-			/* create PSK pre_master_secret */
-			pre_ms_len=2+psk_len+2+psk_len;
-			t = psk_or_pre_ms;
-			memmove(psk_or_pre_ms+psk_len+4, psk_or_pre_ms, psk_len);
-			s2n(psk_len, t);
-			memset(t, 0, psk_len);
-			t+=psk_len;
-			s2n(psk_len, t);
-
-			if (s->session->psk_identity != NULL)
-				OPENSSL_free(s->session->psk_identity);
-			s->session->psk_identity = BUF_strdup((char *)p);
-			if (s->session->psk_identity == NULL)
+			pre_ms_len = 2+psk_len+2+i;
+			pre_ms = OPENSSL_malloc(pre_ms_len);
+			if (pre_ms == NULL)
 				{
 				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
 					ERR_R_MALLOC_FAILURE);
-				goto psk_err;
+				goto err;
 				}
-
-			if (s->session->psk_identity_hint != NULL)
-				OPENSSL_free(s->session->psk_identity_hint);
-			s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
-			if (s->ctx->psk_identity_hint != NULL &&
-				s->session->psk_identity_hint == NULL)
-				{
-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-					ERR_R_MALLOC_FAILURE);
-				goto psk_err;
-				}
-
-			s->session->master_key_length=
-				s->method->ssl3_enc->generate_master_secret(s,
-					s->session->master_key, psk_or_pre_ms, pre_ms_len);
-			psk_err = 0;
-		psk_err:
-			OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
-			if (psk_err != 0)
-				goto f_err;
+			memset(pre_ms, 0, pre_ms_len);
+			t = pre_ms;
+			s2n(psk_len, t);
+			memcpy(t, psk, psk_len);
+			t += psk_len;
+			s2n(i, t);
+			memcpy(t, p, i);
+			s->session->master_key_length = s->method->ssl3_enc \
+				-> generate_master_secret(s,
+					s->session->master_key, pre_ms, pre_ms_len);
+			OPENSSL_cleanse(pre_ms, pre_ms_len);
+			OPENSSL_free(pre_ms);
 			}
-		else
+#endif /* OPENSSL_NO_PSK */
+		if (!(alg_a & SSL_aPSK))
+			{
+			/* Compute the master secret */
+			s->session->master_key_length = s->method->ssl3_enc \
+				-> generate_master_secret(s,
+					s->session->master_key, p, i);
+			}
+
+		OPENSSL_cleanse(p, i);
+		}
 #endif
 #ifndef OPENSSL_NO_SRP
-		if (alg_k & SSL_kSRP)
+	else if (alg_k & SSL_kSRP)
+		{
+		int param_len;
+
+		n2s(p,i);
+		param_len=i+2;
+		if (param_len > n)
 			{
-			int param_len;
-
-			n2s(p,i);
-			param_len=i+2;
-			if (param_len > n)
-				{
-				al=SSL_AD_DECODE_ERROR;
-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_SRP_A_LENGTH);
-				goto f_err;
-				}
-			if (!(s->srp_ctx.A=BN_bin2bn(p,i,NULL)))
-				{
-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_BN_LIB);
-				goto err;
-				}
-			if (s->session->srp_username != NULL)
-				OPENSSL_free(s->session->srp_username);
-			s->session->srp_username = BUF_strdup(s->srp_ctx.login);
-			if (s->session->srp_username == NULL)
-				{
-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-					ERR_R_MALLOC_FAILURE);
-				goto err;
-				}
-
-			if ((s->session->master_key_length = SRP_generate_server_master_secret(s,s->session->master_key))<0)
-				{
-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
-				goto err;
-				}
-
-			p+=i;
+			al=SSL_AD_DECODE_ERROR;
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_SRP_A_LENGTH);
+			goto f_err;
 			}
-		else
+		if (!(s->srp_ctx.A=BN_bin2bn(p,i,NULL)))
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_BN_LIB);
+			goto err;
+			}
+		if (s->session->srp_username != NULL)
+			OPENSSL_free(s->session->srp_username);
+		s->session->srp_username = BUF_strdup(s->srp_ctx.login);
+		if (s->session->srp_username == NULL)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				ERR_R_MALLOC_FAILURE);
+			goto err;
+			}
+
+		if ((s->session->master_key_length = SRP_generate_server_master_secret(s,s->session->master_key))<0)
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+			goto err;
+			}
+
+		p+=i;
+		}
 #endif	/* OPENSSL_NO_SRP */
-		if (alg_k & SSL_kGOST) 
+	else if (alg_k & SSL_kGOST) 
+		{
+		int ret = 0;
+		EVP_PKEY_CTX *pkey_ctx;
+		EVP_PKEY *client_pub_pkey = NULL, *pk = NULL;
+		unsigned char premaster_secret[32], *start;
+		size_t outlen=32, inlen;
+		unsigned long alg_a;
+
+		/* Get our certificate private key*/
+		alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+		if (alg_a & SSL_aGOST94)
+			pk = s->cert->pkeys[SSL_PKEY_GOST94].privatekey;
+		else if (alg_a & SSL_aGOST01)
+			pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
+
+		pkey_ctx = EVP_PKEY_CTX_new(pk,NULL);
+		EVP_PKEY_decrypt_init(pkey_ctx);
+		/* If client certificate is present and is of the same type, maybe
+		 * use it for key exchange.  Don't mind errors from
+		 * EVP_PKEY_derive_set_peer, because it is completely valid to use
+		 * a client certificate for authorization only. */
+		client_pub_pkey = X509_get_pubkey(s->session->peer);
+		if (client_pub_pkey)
 			{
-			int ret = 0;
-			EVP_PKEY_CTX *pkey_ctx;
-			EVP_PKEY *client_pub_pkey = NULL, *pk = NULL;
-			unsigned char premaster_secret[32], *start;
-			size_t outlen=32, inlen;
-			unsigned long alg_a;
-
-			/* Get our certificate private key*/
-			alg_a = s->s3->tmp.new_cipher->algorithm_auth;
-			if (alg_a & SSL_aGOST94)
-				pk = s->cert->pkeys[SSL_PKEY_GOST94].privatekey;
-			else if (alg_a & SSL_aGOST01)
-				pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
-
-			pkey_ctx = EVP_PKEY_CTX_new(pk,NULL);
-			EVP_PKEY_decrypt_init(pkey_ctx);
-			/* If client certificate is present and is of the same type, maybe
-			 * use it for key exchange.  Don't mind errors from
-			 * EVP_PKEY_derive_set_peer, because it is completely valid to use
-			 * a client certificate for authorization only. */
-			client_pub_pkey = X509_get_pubkey(s->session->peer);
-			if (client_pub_pkey)
-				{
-				if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0)
-					ERR_clear_error();
-				}
-			/* Decrypt session key */
-			if ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED))) 
-				{
-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
-				goto gerr;
-				}
-			if (p[1] == 0x81)
-				{
-				start = p+3;
-				inlen = p[2];
-				}
-			else if (p[1] < 0x80)
-				{
-				start = p+2;
-				inlen = p[1];
-				}
-			else
-				{
-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
-				goto gerr;
-				}
-			if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,start,inlen) <=0) 
-
-				{
-				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
-				goto gerr;
-				}
-			/* Generate master secret */
-			s->session->master_key_length=
-				s->method->ssl3_enc->generate_master_secret(s,
-					s->session->master_key,premaster_secret,32);
-			/* Check if pubkey from client certificate was used */
-			if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
-				ret = 2;
-			else
-				ret = 1;
-		gerr:
-			EVP_PKEY_free(client_pub_pkey);
-			EVP_PKEY_CTX_free(pkey_ctx);
-			if (ret)
-				return ret;
-			else
-				goto err;
+			if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0)
+				ERR_clear_error();
+			}
+		/* Decrypt session key */
+		if ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED))) 
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
+			goto gerr;
+			}
+		if (p[1] == 0x81)
+			{
+			start = p+3;
+			inlen = p[2];
+			}
+		else if (p[1] < 0x80)
+			{
+			start = p+2;
+			inlen = p[1];
 			}
 		else
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
+			goto gerr;
+			}
+		if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,start,inlen) <=0) 
+
+			{
+			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
+			goto gerr;
+			}
+		/* Generate master secret */
+		s->session->master_key_length=
+			s->method->ssl3_enc->generate_master_secret(s,
+				s->session->master_key,premaster_secret,32);
+		/* Check if pubkey from client certificate was used */
+		if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
+			ret = 2;
+		else
+			ret = 1;
+	gerr:
+		EVP_PKEY_free(client_pub_pkey);
+		EVP_PKEY_CTX_free(pkey_ctx);
+		if (ret)
+			return ret;
+		else
+			goto err;
+		}
+	else if (!(alg_k & SSL_kPSK))
 		{
 		al=SSL_AD_HANDSHAKE_FAILURE;
 		SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 7452386..43a2dfd 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1440,7 +1440,7 @@
 #endif /* OPENSSL_NO_KRB5 */
 #ifndef OPENSSL_NO_PSK
 		/* with PSK there must be client callback set */
-		if (((c->algorithm_mkey & SSL_kPSK) || (c->algorithm_auth & SSL_aPSK)) &&
+		if ((c->algorithm_auth & SSL_aPSK) &&
 		    s->psk_client_callback == NULL)
 			continue;
 #endif /* OPENSSL_NO_PSK */
diff --git a/ssl/tls1.h b/ssl/tls1.h
index 6283c6a..ec8948d 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -531,6 +531,10 @@
 #define TLS1_CK_ECDH_RSA_WITH_AES_128_GCM_SHA256        0x0300C031
 #define TLS1_CK_ECDH_RSA_WITH_AES_256_GCM_SHA384        0x0300C032
 
+/* ECDHE PSK ciphersuites from RFC 5489 */
+#define TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA256    0x0300C037
+#define TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA384    0x0300C038
+
 /* XXX
  * Inconsistency alert:
  * The OpenSSL names of ciphers with ephemeral DH here include the string
@@ -682,6 +686,10 @@
 #define TLS1_TXT_ECDH_RSA_WITH_AES_128_GCM_SHA256       "ECDH-RSA-AES128-GCM-SHA256"
 #define TLS1_TXT_ECDH_RSA_WITH_AES_256_GCM_SHA384       "ECDH-RSA-AES256-GCM-SHA384"
 
+/* ECDHE PSK ciphersuites from RFC 5489 */
+#define TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA256  "ECDHE-PSK-WITH-AES-128-CBC-SHA256"
+#define TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA384  "ECDHE-PSK-WITH-AES-256-CBC-SHA384"
+
 #define TLS_CT_RSA_SIGN			1
 #define TLS_CT_DSS_SIGN			2
 #define TLS_CT_RSA_FIXED_DH		3