Implement ECDHE-PSK-WITH-AES-128-GCM-SHA256.
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index af664de..48d4a55 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -344,9 +344,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;
@@ -1404,7 +1405,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_mkey & SSL_aPSK)
 			{
 			s->session->sess_cert=ssl_sess_cert_new();
 			if (s->ctx->psk_identity_hint)
@@ -1452,50 +1453,55 @@
 	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)
-			{
-			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_DATA_LENGTH_TOO_LONG);
-			goto f_err;
-			}
-		if (param_len > n)
-			{
-			al=SSL_AD_DECODE_ERROR;
-			OPENSSL_PUT_ERROR(SSL, 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)
+		if (s->ctx->psk_identity_hint)
 			OPENSSL_free(s->ctx->psk_identity_hint);
-		s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint);
-		if (s->ctx->psk_identity_hint == NULL)
+		s->ctx->psk_identity_hint = NULL;
+		if (i != 0)
 			{
-			OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, ERR_R_MALLOC_FAILURE);
-			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)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_get_key_exchange, SSL_R_DATA_LENGTH_TOO_LONG);
+				goto f_err;
+				}
+			if (param_len > n)
+				{
+				al=SSL_AD_DECODE_ERROR;
+				OPENSSL_PUT_ERROR(SSL, 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);
+			s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint);
+			if (s->ctx->psk_identity_hint == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, 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_RSA
-	if (alg_k & SSL_kRSA)
+	else if (alg_k & SSL_kRSA)
 		{
 		if ((rsa=RSA_new()) == NULL)
 			{
@@ -1544,9 +1550,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)
@@ -1735,14 +1738,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;
 		OPENSSL_PUT_ERROR(SSL, 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 */
 
@@ -1832,8 +1835,9 @@
 		}
 	else
 		{
-		/* aNULL or kPSK do not need public keys */
-		if (!(alg_a & SSL_aNULL) && !(alg_k & SSL_kPSK))
+		if (!(alg_a & SSL_aNULL) &&
+			/* Among PSK ciphers only RSA_PSK needs a public key */
+			!((alg_a & SSL_aPSK) && !(alg_k & SSL_kRSA)))
 			{
 			/* Might be wrong key type, check it */
 			if (ssl3_check_cert_and_algorithm(s))
@@ -2254,8 +2258,9 @@
 int ssl3_send_client_key_exchange(SSL *s)
 	{
 	unsigned char *p;
-	int n;
+	int n = 0;
 	unsigned long alg_k;
+	unsigned long alg_a;
 #ifndef OPENSSL_NO_RSA
 	unsigned char *q;
 	EVP_PKEY *pkey=NULL;
@@ -2267,13 +2272,102 @@
 	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)
 		{
 		p = ssl_handshake_start(s);
 
 		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)
+				{
+				OPENSSL_PUT_ERROR(SSL, 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)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
+				goto psk_err;
+				}
+			else if (psk_len == 0)
+				{
+				OPENSSL_PUT_ERROR(SSL, 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)
+					{
+					OPENSSL_PUT_ERROR(SSL, 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)
+				{
+				OPENSSL_PUT_ERROR(SSL, 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) {}
@@ -2438,13 +2532,19 @@
 			}
 #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
@@ -2561,15 +2661,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)
+					{
+					OPENSSL_PUT_ERROR(SSL, 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;
@@ -2597,111 +2723,47 @@
 					}
 
 				/* 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);
 
-				*p = n; /* length of encoded point */
+				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 = 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)
 			{
 			OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_GOST_NOT_SUPPORTED);
 			goto err;
 			}
-#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)
-				{
-				OPENSSL_PUT_ERROR(SSL, 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)
-				{
-				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
-				goto psk_err;
-				}
-			else if (psk_len == 0)
-				{
-				OPENSSL_PUT_ERROR(SSL, 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)
-				{
-				OPENSSL_PUT_ERROR(SSL, 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)
-				{
-				OPENSSL_PUT_ERROR(SSL, 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) || ((alg_k & SSL_kPSK) && !(alg_a & SSL_aPSK)))
 			{
 			ssl3_send_alert(s, SSL3_AL_FATAL,
 			    SSL_AD_HANDSHAKE_FAILURE);
@@ -3028,7 +3090,7 @@
 	alg_a=s->s3->tmp.new_cipher->algorithm_auth;
 
 	/* we don't have a certificate */
-	if ((alg_a & (SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
+	if ((alg_a & (SSL_aNULL|SSL_aKRB5)) || ((alg_a & SSL_aPSK) && !(alg_k & SSL_kRSA)))
 		return(1);
 
 	sc=s->session->sess_cert;
diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c
index fcb57c8..c275a9a 100644
--- a/ssl/s3_enc.c
+++ b/ssl/s3_enc.c
@@ -695,7 +695,7 @@
 		}
 
 	t=EVP_MD_CTX_size(hash);
-	if (t < 0)
+	if (t < 0 || t > 20)
 		return -1;
 	md_size=t;
 	npad=(48/md_size)*md_size;
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 328bff9..dce8021 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -2476,6 +2476,26 @@
 	256,
 	},
 
+#ifndef OPENSSL_NO_PSK
+    /* ECDH PSK ciphersuites */
+	/* Cipher CAFE */
+	{
+	1,
+	TLS1_TXT_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
+	TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
+	SSL_kEECDH,
+	SSL_aPSK,
+	SSL_AES128GCM,
+	SSL_AEAD,
+	SSL_TLSV1_2,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|
+		SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
+	128,
+	128,
+	},
+#endif /* OPENSSL_NO_PSK */
+
 #endif /* OPENSSL_NO_ECDH */
 
 
@@ -3792,7 +3812,7 @@
 
 #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 91c0e77..72538a0 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -188,6 +188,7 @@
 	{
 	BUF_MEM *buf;
 	unsigned long alg_k;
+	unsigned long alg_a;
 	void (*cb)(const SSL *ssl,int type,int val)=NULL;
 	int ret= -1;
 	int new_state,state,skip=0;
@@ -383,9 +384,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);
@@ -414,6 +417,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 */
@@ -440,10 +444,11 @@
 			 * 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
 			    || (alg_k & SSL_kEDH)
 			    || (alg_k & SSL_kEECDH)
@@ -1539,7 +1544,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];
@@ -1550,15 +1556,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))
@@ -1585,10 +1601,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))
@@ -1640,10 +1655,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;
 
@@ -1765,7 +1779,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
@@ -1775,16 +1789,8 @@
 			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 */
+		else if (!(alg_k & SSL_kPSK))
 			{
 			al=SSL_AD_HANDSHAKE_FAILURE;
 			OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
@@ -1796,8 +1802,9 @@
 			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)
@@ -1827,8 +1834,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:
@@ -1851,17 +1882,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)
@@ -1895,7 +1916,7 @@
 				n+=u+2;
 				}
 			else
-#endif
+#endif /* OPENSSL_NO_RSA */
 			if (md)
 				{
 				/* send signature algorithm */
@@ -2054,6 +2075,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;
@@ -2068,7 +2090,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,
@@ -2082,9 +2108,102 @@
 	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))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_LENGTH_MISMATCH);
+			goto psk_err;
+			}
+		if (i > PSK_MAX_IDENTITY_LEN)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DATA_LENGTH_TOO_LONG);
+			goto psk_err;
+			}
+		if (s->psk_server_callback == NULL)
+			{
+			OPENSSL_PUT_ERROR(SSL, 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)
+			{
+			OPENSSL_PUT_ERROR(SSL, 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 */
+			OPENSSL_PUT_ERROR(SSL, 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)
+			{
+			OPENSSL_PUT_ERROR(SSL, 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)
+			{
+			OPENSSL_PUT_ERROR(SSL, 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)
+	else if (alg_k & SSL_kRSA)
 		{
 		unsigned char rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH];
 		int decrypt_len, decrypt_good_mask;
@@ -2245,10 +2364,9 @@
 				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))
 		{
 		int idx = -1;
 		EVP_PKEY *skey = NULL;
@@ -2344,17 +2462,21 @@
 		if (dh_clnt)
 			return 2;
 		}
-	else
 #endif
 
 #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) 
@@ -2444,7 +2566,7 @@
 				}
 
 			/* Get encoded point length */
-			i = *p; 
+			i = *p;
 			p += 1;
 			if (n != 1 + i)
 				{
@@ -2482,106 +2604,47 @@
 		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)
-				{
-				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_LENGTH_MISMATCH);
-				goto psk_err;
-				}
-			if (i > PSK_MAX_IDENTITY_LEN)
-				{
-				OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DATA_LENGTH_TOO_LONG);
-				goto psk_err;
-				}
-			if (s->psk_server_callback == NULL)
-				{
-				OPENSSL_PUT_ERROR(SSL, 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)
-				{
-				OPENSSL_PUT_ERROR(SSL, 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 */
-				OPENSSL_PUT_ERROR(SSL, 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)
 				{
 				OPENSSL_PUT_ERROR(SSL, 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)
-				{
-				OPENSSL_PUT_ERROR(SSL, 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);
+		return ret;
+		}
 #endif
-		if (alg_k & SSL_kGOST) 
+	else if (alg_k & SSL_kGOST) 
 			{
 			int ret = 0;
 			EVP_PKEY_CTX *pkey_ctx;
@@ -2653,7 +2716,7 @@
 			else
 				goto err;
 			}
-		else
+	else if (!(alg_k & SSL_kPSK))
 		{
 		al=SSL_AD_HANDSHAKE_FAILURE;
 		OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_UNKNOWN_CIPHER_TYPE);
diff --git a/ssl/tls1.h b/ssl/tls1.h
index d09a6e3..79fc9c3 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -571,6 +571,9 @@
 #define TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305		0x0300CC14
 #define TLS1_CK_DHE_RSA_CHACHA20_POLY1305		0x0300CC15
 
+/* Non-standard ECDHE PSK ciphersuites */
+#define TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256    0x0300CAFE
+
 /* XXX
  * Inconsistency alert:
  * The OpenSSL names of ciphers with ephemeral DH here include the string
@@ -726,6 +729,9 @@
 #define TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305	"ECDHE-ECDSA-CHACHA20-POLY1305"
 #define TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305		"DHE-RSA-CHACHA20-POLY1305"
 
+/* Non-standard ECDHE PSK ciphersuites */
+#define TLS1_TXT_ECDHE_PSK_WITH_AES_128_GCM_SHA256  "ECDHE-PSK-WITH-AES-128-GCM-SHA256"
+
 #define TLS_CT_RSA_SIGN			1
 #define TLS_CT_DSS_SIGN			2
 #define TLS_CT_RSA_FIXED_DH		3