Hello,

I recently started working on this patch, rebasing it on latest master, 
cleaning it up (f.i. unifying some code paths where possible, to avoid 
duplicating code), completing the support for the other RSA-PSK 
ciphersuites defined by RFC 4279 and so on.

I'm attaching the version I'm working on, I will be glad if anyone could 
give some feedback (any sorts -- obvious mistakes, code policy 
violations, code style issues, etc.).

Thanks!
-- 
Giuseppe D'Angelo | [email protected] | Software Engineer
KDAB (UK) Ltd., a KDAB Group company
Tel. UK +44-1738-450410, Sweden (HQ) +46-563-540090
KDAB - Qt Experts - Platform-independent software solutions

>From f8e352542c54e412103de5410604958b99bd197e Mon Sep 17 00:00:00 2001
From: Giuseppe D'Angelo <[email protected]>
Date: Sat, 8 Nov 2014 20:44:23 +0100
Subject: [PATCH] Introduce TLS-RSA-PSK support

Build on the existing PSK support and introduce RSA-PSK
(cf. RFC 4279). Based on the original patch by Christian J. Dietrich

This work has been sponsored by Governikus GmbH & Co. KG.

PR: 2464
---
 CHANGES              |    3 +
 doc/apps/ciphers.pod |    4 +
 ssl/s3_clnt.c        |  109 ++++++++++++++++++++-----
 ssl/s3_lib.c         |   69 +++++++++++++++-
 ssl/s3_srvr.c        |  216 +++++++++++++++++++++++++++++++++++++++++++++++---
 ssl/ssl.h            |    4 +-
 ssl/ssl_ciph.c       |   16 ++--
 ssl/ssl_lib.c        |    6 ++
 ssl/ssl_locl.h       |    1 +
 ssl/tls1.h           |   12 +++
 10 files changed, 403 insertions(+), 37 deletions(-)

diff --git a/CHANGES b/CHANGES
index d90febc..8b48914 100644
--- a/CHANGES
+++ b/CHANGES
@@ -303,6 +303,9 @@
      whose return value is often ignored. 
      [Steve Henson]
 
+  *) Support for TLS-RSA-PSK ciphersuites has been added.
+     [Giuseppe D'Angelo, Christian J. Dietrich]
+
  Changes between 1.0.1j and 1.0.2 [xx XXX xxxx]
 
    *) Tighten client-side session ticket handling during renegotiation:
diff --git a/doc/apps/ciphers.pod b/doc/apps/ciphers.pod
index c41a297..f43abff 100644
--- a/doc/apps/ciphers.pod
+++ b/doc/apps/ciphers.pod
@@ -600,6 +600,10 @@ Note: these ciphers can also be used in SSL v3.
 
 =head2 Pre shared keying (PSK) cipheruites
 
+ TLS_RSA_PSK_WITH_RC4_128_SHA              RSA-PSK-RC4-SHA
+ TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA         RSA-PSK-3DES-EDE-CBC-SHA
+ TLS_RSA_PSK_WITH_AES_128_CBC_SHA          RSA-PSK-AES128-CBC-SHA
+ TLS_RSA_PSK_WITH_AES_256_CBC_SHA          RSA-PSK-AES256-CBC-SHA
  TLS_PSK_WITH_RC4_128_SHA                  PSK-RC4-SHA
  TLS_PSK_WITH_3DES_EDE_CBC_SHA             PSK-3DES-EDE-CBC-SHA
  TLS_PSK_WITH_AES_128_CBC_SHA              PSK-AES128-CBC-SHA
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 68c00c5..5fc5f1a 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -343,7 +343,7 @@ int ssl3_connect(SSL *s)
 				}
 #endif
 			/* Check if it is anon DH/ECDH, SRP auth */
-			/* or PSK */
+			/* or plain PSK */
 			if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL|SSL_aSRP)) &&
 			    !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
 				{
@@ -1417,9 +1417,9 @@ int ssl3_get_key_exchange(SSL *s)
 	if (s->s3->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE)
 		{
 #ifndef OPENSSL_NO_PSK
-		/* In plain PSK ciphersuite, ServerKeyExchange can be
+		/* In PSK ciphersuites, ServerKeyExchange can be
 		   omitted if no identity hint is sent. Set
-		   session->sess_cert anyway to avoid problems
+		   session->sess_cert for plain PSK anyway to avoid problems
 		   later.*/
 		if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)
 			{
@@ -1473,7 +1473,8 @@ int ssl3_get_key_exchange(SSL *s)
 	al=SSL_AD_DECODE_ERROR;
 
 #ifndef OPENSSL_NO_PSK
-	if (alg_k & SSL_kPSK)
+	/* handle PSK identity hint */
+	if (alg_k & (SSL_kPSK|SSL_kRSAPSK))
 		{
 		char tmp_id_hint[PSK_MAX_IDENTITY_LEN+1];
 
@@ -1650,7 +1651,7 @@ int ssl3_get_key_exchange(SSL *s)
 	else
 #endif /* !OPENSSL_NO_SRP */
 #ifndef OPENSSL_NO_RSA
-	if (alg_k & SSL_kRSA)
+	if (alg_k & (SSL_kRSA|SSL_kRSAPSK))
 		{
 		if ((rsa=RSA_new()) == NULL)
 			{
@@ -2061,8 +2062,8 @@ fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
 		}
 	else
 		{
-		/* aNULL, aSRP or kPSK do not need public keys */
-		if (!(alg_a & (SSL_aNULL|SSL_aSRP)) && !(alg_k & SSL_kPSK))
+		/* aNULL, aSRP, kPSK or kRSAPSK do not need public keys */
+		if (!(alg_a & (SSL_aNULL|SSL_aSRP)) && !(alg_k & (SSL_kPSK|SSL_kRSAPSK)))
 			{
 			/* Might be wrong key type, check it */
 			if (ssl3_check_cert_and_algorithm(s))
@@ -2540,7 +2541,7 @@ int ssl3_send_client_key_exchange(SSL *s)
 				rsa=pkey->pkey.rsa;
 				EVP_PKEY_free(pkey);
 				}
-				
+
 			tmp_buf[0]=s->client_version>>8;
 			tmp_buf[1]=s->client_version&0xff;
 			if (RAND_bytes(&(tmp_buf[2]),sizeof tmp_buf-2) <= 0)
@@ -3132,15 +3133,19 @@ int ssl3_send_client_key_exchange(SSL *s)
 			}
 #endif
 #ifndef OPENSSL_NO_PSK
-		else if (alg_k & SSL_kPSK)
+		else if (alg_k & SSL_kPSK
+#ifndef OPENSSL_NO_RSA
+			|| alg_k & SSL_kRSAPSK
+#endif
+			 )
 			{
 			/* The callback needs PSK_MAX_IDENTITY_LEN + 1 bytes
 			 * to return a \0-terminated identity. The last byte
 			 * is for us for simulating strnlen. */
 			char identity[PSK_MAX_IDENTITY_LEN + 2];
 			size_t identity_len;
-			unsigned char *t = NULL;
 			unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN*2+4];
+			unsigned char *t = psk_or_pre_ms;
 			unsigned int pre_ms_len = 0, psk_len = 0;
 			int psk_err = 1;
 
@@ -3176,14 +3181,36 @@ int ssl3_send_client_key_exchange(SSL *s)
 					ERR_R_INTERNAL_ERROR);
 				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 (alg_k & SSL_kPSK)
+				{
+				/* create PSK pre_master_secret */
+				pre_ms_len = 2+psk_len+2+psk_len;
+				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);
+				}
+#ifndef OPENSSL_NO_RSA
+			else if (alg_k & SSL_kRSAPSK)
+				{
+				const unsigned int pre_ms_prefix = 48;
+
+				pre_ms_len = 2 + 2 + 46 + 2 + psk_len;
+				memmove(psk_or_pre_ms + 52, psk_or_pre_ms, psk_len);
+				s2n(pre_ms_prefix, t);
+
+				psk_or_pre_ms[2] = s->client_version >> 8;
+				psk_or_pre_ms[3] = s->client_version & 0xff;
+				t += 2;
+
+				if (RAND_bytes(psk_or_pre_ms + 4, 46) <= 0)
+					goto psk_err;
+				t += 46;
+				s2n(psk_len, t);
+				}
+#endif
 
 			if (s->session->psk_identity_hint != NULL)
 				OPENSSL_free(s->session->psk_identity_hint);
@@ -3210,10 +3237,52 @@ int ssl3_send_client_key_exchange(SSL *s)
 				s->method->ssl3_enc->generate_master_secret(s,
 					s->session->master_key,
 					psk_or_pre_ms, pre_ms_len);
+
 			s2n(identity_len, p);
 			memcpy(p, identity, identity_len);
+			p += identity_len;
+
 			n = 2 + identity_len;
+
+#ifndef OPENSSL_NO_RSA
+			if (alg_k & SSL_kRSAPSK)
+				{
+				RSA *rsa;
+				int enc_n;
+
+				if (s->session->sess_cert->peer_rsa_tmp != NULL)
+					{
+					rsa = s->session->sess_cert->peer_rsa_tmp;
+					}
+				else
+					{
+					pkey = X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
+					if ((pkey == NULL) ||
+							(pkey->type != EVP_PKEY_RSA) ||
+							(pkey->pkey.rsa == NULL))
+						{
+							SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+							goto psk_err;
+						}
+					rsa = pkey->pkey.rsa;
+					EVP_PKEY_free(pkey);
+					}
+
+				enc_n = RSA_public_encrypt(48, psk_or_pre_ms + 2, p + 2, rsa, RSA_PKCS1_PADDING);
+				fprintf(stderr, "***\nENCRYPTED %d BYTES USING RSA_public_encrypt\n***\n", enc_n);
+				if (enc_n <= 0)
+					{
+						SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, SSL_R_BAD_RSA_ENCRYPT);
+						goto psk_err;
+					}
+				n += enc_n;
+
+				s2n(enc_n, p);
+				n += 2;
+				}
+#endif
 			psk_err = 0;
+
 		psk_err:
 			OPENSSL_cleanse(identity, sizeof(identity));
 			OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
@@ -3625,7 +3694,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
 		}
 #endif
 #ifndef OPENSSL_NO_RSA
-	if ((alg_k & SSL_kRSA) &&
+	if ((alg_k & (SSL_kRSA|SSL_kRSAPSK)) && // CJD: CHECKME: not 100% sure
 		!(has_bits(i,EVP_PK_RSA|EVP_PKT_ENC) || (rsa != NULL)))
 		{
 		SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_RSA_ENCRYPTING_CERT);
@@ -3658,7 +3727,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
 	if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && !has_bits(i,EVP_PKT_EXP))
 		{
 #ifndef OPENSSL_NO_RSA
-		if (alg_k & SSL_kRSA)
+		if (alg_k & (SSL_kRSA|SSL_kRSAPSK)) // CJD
 			{
 			if (rsa == NULL
 			    || RSA_size(rsa)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher))
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index d670ff0..7361b37 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -1715,6 +1715,73 @@ OPENSSL_GLOBAL const SSL_CIPHER ssl3_ciphers[]={
 	256,
 	256,
 	},
+
+#ifndef OPENSSL_NO_RSA
+	/* RSA-PSK ciphersuites */
+	/* Cipher 92 */
+	{
+	1,
+	TLS1_TXT_RSA_PSK_WITH_RC4_128_SHA,
+	TLS1_CK_RSA_PSK_WITH_RC4_128_SHA,
+	SSL_kRSAPSK,
+	SSL_aRSA,
+	SSL_RC4,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 93 */
+	{
+	1,
+	TLS1_TXT_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+	TLS1_CK_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+	SSL_kRSAPSK,
+	SSL_aRSA,
+	SSL_3DES,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	112,
+	168,
+	},
+
+	/* Cipher 94 */
+	{
+	1,
+	TLS1_TXT_RSA_PSK_WITH_AES_128_CBC_SHA,
+	TLS1_CK_RSA_PSK_WITH_AES_128_CBC_SHA,
+	SSL_kRSAPSK,
+	SSL_aRSA,
+	SSL_AES128,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	128,
+	128,
+	},
+
+	/* Cipher 95 */
+	{
+	1,
+	TLS1_TXT_RSA_PSK_WITH_AES_256_CBC_SHA,
+	TLS1_CK_RSA_PSK_WITH_AES_256_CBC_SHA,
+	SSL_kRSAPSK,
+	SSL_aRSA,
+	SSL_AES256,
+	SSL_SHA1,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
+	256,
+	256,
+	},
+#endif  /* OPENSSL_NO_RSA */
 #endif  /* OPENSSL_NO_PSK */
 
 #ifndef OPENSSL_NO_SEED
@@ -4522,7 +4589,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_k & (SSL_kPSK|SSL_kRSAPSK)) && s->psk_server_callback == NULL)
 			continue;
 #endif /* OPENSSL_NO_PSK */
 
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index bef055a..677db55 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -467,7 +467,8 @@ int ssl3_accept(SSL *s)
 			/* only send if a DH key exchange, fortezza or
 			 * RSA but we have a sign only certificate
 			 *
-			 * PSK: may send PSK identity hints
+			 * PSK|RSAPSK: may send PSK identity hints.
+			 * Send ServerKeyExchange if PSK identity hint is provided.
 			 *
 			 * For ECC ciphersuites, we send a serverKeyExchange
 			 * message only if the cipher suite is either
@@ -476,10 +477,8 @@ 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 */
 #ifndef OPENSSL_NO_PSK
-			    || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint)
+			    || ((alg_k & (SSL_kPSK|SSL_kRSAPSK)) && s->ctx->psk_identity_hint)
 #endif
 #ifndef OPENSSL_NO_SRP
 			    /* SRP: send ServerKeyExchange */
@@ -525,9 +524,9 @@ int ssl3_accept(SSL *s)
 				(s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5) ||
 				/* don't request certificate for SRP auth */
 				(s->s3->tmp.new_cipher->algorithm_auth & SSL_aSRP)
-				/* With normal PSK Certificates and
+				/* With normal PSK, Certificates and
 				 * Certificate Requests are omitted */
-				|| (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
+				|| (s->s3->tmp.new_cipher->algorithm_mkey & (SSL_kPSK|SSL_kRSAPSK)))
 				{
 				/* no cert request */
 				skip=1;
@@ -1894,7 +1893,17 @@ int ssl3_send_server_key_exchange(SSL *s)
 			r[3]=s->srp_ctx.B;
 			}
 		else 
-#endif
+#endif /*! OPENSSL_NO_SRP */
+#ifndef OPENSSL_NO_RSA
+#ifndef OPENSSL_NO_PSK
+			if (type & SSL_kRSAPSK)
+				{
+				/* reserve size for record length and PSK identity hint */
+				n+=2+strlen(s->ctx->psk_identity_hint);
+				}
+			else
+#endif /* !OPENSSL_NO_PSK */
+#endif /* !OPENSSL_NO_RSA */
 			{
 			al=SSL_AD_HANDSHAKE_FAILURE;
 			SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
@@ -1977,7 +1986,7 @@ int ssl3_send_server_key_exchange(SSL *s)
 #endif
 
 #ifndef OPENSSL_NO_PSK
-		if (type & SSL_kPSK)
+		if (type & (SSL_kPSK|SSL_kRSAPSK))
 			{
 			/* copy PSK identity hint */
 			s2n(strlen(s->ctx->psk_identity_hint), p); 
@@ -1992,7 +2001,7 @@ int ssl3_send_server_key_exchange(SSL *s)
 			/* n is the length of the params, they start at &(d[4])
 			 * and p points to the space at the end. */
 #ifndef OPENSSL_NO_RSA
-			if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s))
+			if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s) && !(type & SSL_kRSAPSK))
 				{
 				q=md_buf;
 				j=0;
@@ -2878,8 +2887,195 @@ int ssl3_get_client_key_exchange(SSL *s)
 			if (psk_err != 0)
 				goto f_err;
 			}
-		else
+	else
 #endif
+#ifndef OPENSSL_NO_RSA
+#ifndef OPENSSL_NO_PSK
+		if (alg_k & SSL_kRSAPSK)
+			{
+			unsigned char rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH];
+			int decrypt_len;
+			unsigned char decrypt_good, version_good;
+			unsigned char *orig_p = p;
+
+			unsigned int psk_len;
+
+			const unsigned int pre_master_secret_prefix = 48;
+			unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN * 2 + 4];
+			unsigned int pre_ms_len;
+			unsigned char *t = psk_or_pre_ms;
+
+			char identity[PSK_MAX_IDENTITY_LEN + 1];
+			int identity_len;
+
+			int epms_len;
+
+			int psk_err = 1;
+
+			/* No server callback? Bail out */
+			if (s->psk_server_callback == NULL)
+				{
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_PSK_NO_SERVER_CB);
+				goto f_err;
+				}
+
+			/* FIX THIS UP EAY EAY EAY EAY */
+			if (s->s3->tmp.use_rsa_tmp)
+				{
+				if ((s->cert != NULL) && (s->cert->rsa_tmp != NULL))
+					rsa=s->cert->rsa_tmp;
+				/* Don't do a callback because rsa_tmp should
+				 * be sent already */
+				if (rsa == NULL)
+					{
+					al=SSL_AD_HANDSHAKE_FAILURE;
+					SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_MISSING_TMP_RSA_PKEY);
+					goto f_err;
+					}
+				}
+			else
+				{
+				pkey=s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey;
+				if ((pkey == NULL) ||
+				    (pkey->type != EVP_PKEY_RSA) ||
+				    (pkey->pkey.rsa == NULL))
+					{
+					al=SSL_AD_HANDSHAKE_FAILURE;
+					SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_MISSING_RSA_CERTIFICATE);
+					goto f_err;
+					}
+				rsa=pkey->pkey.rsa;
+				}
+
+
+			/* Extract the PSK identity */
+			if (n < (2 + 2)) /* 2 bytes for the identity len, 2 bytes for the epms len */
+				{
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+				goto f_err;
+				}
+
+			n2s(p, identity_len);
+			if (identity_len > PSK_MAX_IDENTITY_LEN)
+				{
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_DATA_LENGTH_TOO_LONG);
+				goto f_err;
+				}
+
+			if (n < (2 + identity_len + 2)) /* as above, plus the identity len */
+				{
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+				goto f_err;
+				}
+
+			memset(identity, 0, sizeof(identity));
+			memcpy(identity, p, identity_len);
+			p += identity_len;
+
+			/* fill the pre master secret with random bytes */
+			if (RAND_pseudo_bytes(psk_or_pre_ms, sizeof(psk_or_pre_ms)) <= 0)
+				goto err;
+
+			/* read the psk (into the beginning of the psk_or_pre_ms buffer */
+			psk_len = s->psk_server_callback(s, identity, psk_or_pre_ms, sizeof(psk_or_pre_ms));
+
+			if (psk_len > PSK_MAX_PSK_LEN)
+				{
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				       ERR_R_INTERNAL_ERROR);
+				goto rsapsk_err;
+				}
+			else if (psk_len == 0)
+				{
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				       SSL_R_PSK_IDENTITY_NOT_FOUND);
+				al=SSL_AD_UNKNOWN_PSK_IDENTITY;
+				goto rsapsk_err;
+				}
+
+			/* move on onto decoding the 48 encrypted bytes */
+
+			/* how many bytes to decode? */
+			n2s(p, epms_len);
+
+			if (n != (2 + identity_len + 2 + epms_len)) /* as above */
+				{
+				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+				       SSL_R_LENGTH_MISMATCH);
+				goto rsapsk_err;
+				}
+
+			/* decode in place into p */
+			decrypt_len = RSA_private_decrypt(epms_len, p, p, rsa, RSA_PKCS1_PADDING);
+			decrypt_good = constant_time_eq_int_8(decrypt_len, 48);
+
+			/* check the version sent by the client */
+			version_good = constant_time_eq_8(p[0], (unsigned)(s->client_version>>8));
+			version_good &= constant_time_eq_8(p[1], (unsigned)(s->client_version&0xff));
+
+			decrypt_good &= version_good;
+
+			for (i = 0; i < (int) sizeof(rand_premaster_secret); i++)
+				p[i] = constant_time_select_8(decrypt_good, p[i], rand_premaster_secret[i]);
+
+			/* build the pre master secret. it should look like this:
+			 * 48 (2b) + version (2b) + random (46b) + psk_len (2b) + psk */
+			pre_ms_len = 2 + 2 + 46 + 2 + psk_len;
+
+			/* the PSK is at the beginning of psk_or_pre_ms, move at the end */
+			memmove(psk_or_pre_ms + 52, psk_or_pre_ms, psk_len);
+
+			/* fill the "48" in */
+			s2n(pre_master_secret_prefix, t);
+
+			/* fill the 2 bytes version + the 46 random bytes (decrypted earlier with RSA) */
+			memcpy(t, p, 48);
+			t += 48;
+
+			/* fill the psk_len */
+			s2n(psk_len, t);
+
+			/* psk_or_pre_ms now contains the pre master secret */
+
+			/* set the identity in the session */
+			if (s->session->psk_identity != NULL)
+				OPENSSL_free(s->session->psk_identity);
+
+			s->session->psk_identity = BUF_strdup(identity);
+			OPENSSL_cleanse(identity, sizeof(identity));
+
+			if (s->session->psk_identity == NULL)
+				{
+					SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+					goto rsapsk_err;
+				}
+
+			/* set the identity hint in the session */
+			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 rsapsk_err;
+				}
+
+			/* set the premaster key */
+			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;
+	rsapsk_err:
+			OPENSSL_cleanse(orig_p, n); /* clear the whole payload area */
+			if (psk_err != 0)
+				goto f_err;
+			}
+
+	else
+#endif /* !OPENSSL_NO_PSK */
+#endif /* !OPENSSL_NO_RSA */
 #ifndef OPENSSL_NO_SRP
 		if (alg_k & SSL_kSRP)
 			{
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 343247c..0f47f71 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -252,7 +252,8 @@ extern "C" {
 #define SSL_TXT_kECDH		"kECDH"
 #define SSL_TXT_kEECDH		"kEECDH" /* alias for kECDHE */
 #define SSL_TXT_kECDHE		"kECDHE"
-#define SSL_TXT_kPSK            "kPSK"
+#define SSL_TXT_kPSK		"kPSK"
+#define SSL_TXT_kRSAPSK		"kRSAPSK"
 #define SSL_TXT_kGOST		"kGOST"
 #define SSL_TXT_kSRP		"kSRP"
 
@@ -281,6 +282,7 @@ extern "C" {
 #define SSL_TXT_ECDSA		"ECDSA"
 #define SSL_TXT_KRB5      	"KRB5"
 #define SSL_TXT_PSK             "PSK"
+#define SSL_TXT_RSAPSK		"RSAPSK"
 #define SSL_TXT_SRP		"SRP"
 
 #define SSL_TXT_DES		"DES"
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index 3c005f7..72f67f1 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -254,7 +254,8 @@ static const SSL_CIPHER cipher_aliases[]={
 	{0,SSL_TXT_kECDHE,0,  SSL_kECDHE,0,0,0,0,0,0,0,0},
 	{0,SSL_TXT_ECDH,0,    SSL_kECDHr|SSL_kECDHe|SSL_kECDHE,0,0,0,0,0,0,0,0},
 
-        {0,SSL_TXT_kPSK,0,    SSL_kPSK,  0,0,0,0,0,0,0,0},
+	{0,SSL_TXT_kPSK,0,    SSL_kPSK,  0,0,0,0,0,0,0,0},
+	{0,SSL_TXT_kRSAPSK,0, SSL_kRSAPSK,  0,0,0,0,0,0,0,0},
 	{0,SSL_TXT_kSRP,0,    SSL_kSRP,  0,0,0,0,0,0,0,0},
 	{0,SSL_TXT_kGOST,0, SSL_kGOST,0,0,0,0,0,0,0,0},
 
@@ -268,7 +269,7 @@ static const SSL_CIPHER cipher_aliases[]={
 	{0,SSL_TXT_aECDH,0,   0,SSL_aECDH, 0,0,0,0,0,0,0},
 	{0,SSL_TXT_aECDSA,0,  0,SSL_aECDSA,0,0,0,0,0,0,0},
 	{0,SSL_TXT_ECDSA,0,   0,SSL_aECDSA, 0,0,0,0,0,0,0},
-        {0,SSL_TXT_aPSK,0,    0,SSL_aPSK,  0,0,0,0,0,0,0},
+	{0,SSL_TXT_aPSK,0,    0,SSL_aPSK,  0,0,0,0,0,0,0},
 	{0,SSL_TXT_aGOST94,0,0,SSL_aGOST94,0,0,0,0,0,0,0},
 	{0,SSL_TXT_aGOST01,0,0,SSL_aGOST01,0,0,0,0,0,0,0},
 	{0,SSL_TXT_aGOST,0,0,SSL_aGOST94|SSL_aGOST01,0,0,0,0,0,0,0},
@@ -284,7 +285,8 @@ static const SSL_CIPHER cipher_aliases[]={
 	{0,SSL_TXT_RSA,0,     SSL_kRSA,SSL_aRSA,0,0,0,0,0,0,0},
 	{0,SSL_TXT_ADH,0,     SSL_kDHE,SSL_aNULL,0,0,0,0,0,0,0},
 	{0,SSL_TXT_AECDH,0,   SSL_kECDHE,SSL_aNULL,0,0,0,0,0,0,0},
-        {0,SSL_TXT_PSK,0,     SSL_kPSK,SSL_aPSK,0,0,0,0,0,0,0},
+	{0,SSL_TXT_PSK,0,     SSL_kPSK,SSL_aPSK,0,0,0,0,0,0,0},
+	{0,SSL_TXT_RSAPSK,0,  SSL_kRSAPSK,SSL_aRSA,0,0,0,0,0,0,0},
 	{0,SSL_TXT_SRP,0,     SSL_kSRP,0,0,0,0,0,0,0,0},
 
 
@@ -755,7 +757,7 @@ static void ssl_cipher_get_disabled(unsigned long *mkey, unsigned long *auth, un
 	*auth |= SSL_aECDH;
 #endif
 #ifdef OPENSSL_NO_PSK
-	*mkey |= SSL_kPSK;
+	*mkey |= SSL_kPSK|SSL_kRSAPSK;
 	*auth |= SSL_aPSK;
 #endif
 #ifdef OPENSSL_NO_SRP
@@ -1535,7 +1537,8 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
 	ssl_cipher_apply_rule(0, 0, SSL_aECDH, 0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
 	/* ssl_cipher_apply_rule(0, 0, SSL_aDH, 0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail); */
 	ssl_cipher_apply_rule(0, SSL_kRSA, 0, 0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
-	ssl_cipher_apply_rule(0, SSL_kPSK, 0,0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
+	ssl_cipher_apply_rule(0, SSL_kRSAPSK, 0, 0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
+	ssl_cipher_apply_rule(0, SSL_kPSK, 0, 0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
 	ssl_cipher_apply_rule(0, SSL_kKRB5, 0,0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
 
 	/* RC4 is sort-of broken -- move the the end */
@@ -1717,6 +1720,9 @@ char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len)
 	case SSL_kGOST:
 		kx="GOST";
 		break;
+	case SSL_kRSAPSK:
+		kx="RSAPSK";
+		break;
 	default:
 		kx="unknown";
 		}
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 43204de..6969672 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2460,8 +2460,14 @@ void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher)
 
 #ifndef OPENSSL_NO_PSK
 	mask_k |= SSL_kPSK;
+#ifndef OPENSSL_NO_RSA
+	mask_k |= SSL_kRSAPSK;
+#endif
 	mask_a |= SSL_aPSK;
 	emask_k |= SSL_kPSK;
+#ifndef OPENSSL_NO_RSA
+	emask_k |= SSL_kRSAPSK;
+#endif
 	emask_a |= SSL_aPSK;
 #endif
 
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 1fd6bb1..2a5179b 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -301,6 +301,7 @@
 #define SSL_kPSK		0x00000100L /* PSK */
 #define SSL_kGOST       0x00000200L /* GOST key exchange */
 #define SSL_kSRP        0x00000400L /* SRP */
+#define SSL_kRSAPSK     0x00000800L /* RSA-PSK */
 
 /* Bits for algorithm_auth (server authentication) */
 #define SSL_aRSA		0x00000001L /* RSA auth */
diff --git a/ssl/tls1.h b/ssl/tls1.h
index e8188ec..c7b4606 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -416,6 +416,12 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb)
 #define TLS1_CK_PSK_WITH_AES_128_CBC_SHA                0x0300008C
 #define TLS1_CK_PSK_WITH_AES_256_CBC_SHA                0x0300008D
 
+/* RSA-PSK ciphersuites from 4279 */
+#define TLS1_CK_RSA_PSK_WITH_RC4_128_SHA                0x03000092
+#define TLS1_CK_RSA_PSK_WITH_3DES_EDE_CBC_SHA           0x03000093
+#define TLS1_CK_RSA_PSK_WITH_AES_128_CBC_SHA            0x03000094
+#define TLS1_CK_RSA_PSK_WITH_AES_256_CBC_SHA            0x03000095
+
 /* Additional TLS ciphersuites from expired Internet Draft
  * draft-ietf-tls-56-bit-ciphersuites-01.txt
  * (available if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES is defined, see
@@ -655,6 +661,12 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb)
 #define TLS1_TXT_PSK_WITH_AES_128_CBC_SHA		"PSK-AES128-CBC-SHA"
 #define TLS1_TXT_PSK_WITH_AES_256_CBC_SHA		"PSK-AES256-CBC-SHA"
 
+/* RSA-PSK ciphersuites from 4279 */
+#define TLS1_TXT_RSA_PSK_WITH_RC4_128_SHA           "RSA-PSK-RC4-SHA"
+#define TLS1_TXT_RSA_PSK_WITH_3DES_EDE_CBC_SHA      "RSA-PSK-3DES-EDE-CBC-SHA"
+#define TLS1_TXT_RSA_PSK_WITH_AES_128_CBC_SHA       "RSA-PSK-AES128-CBC-SHA"
+#define TLS1_TXT_RSA_PSK_WITH_AES_256_CBC_SHA       "RSA-PSK-AES256-CBC-SHA"
+
 /* SRP ciphersuite from RFC 5054 */
 #define TLS1_TXT_SRP_SHA_WITH_3DES_EDE_CBC_SHA		"SRP-3DES-EDE-CBC-SHA"
 #define TLS1_TXT_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA	"SRP-RSA-3DES-EDE-CBC-SHA"
-- 
1.7.9.5

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to