Be strict about expecting a server Certificate message.

Introduce a ssl_cipher_has_server_public_key to save the repeated
NULL/PSK/RSA_PSK[*] check. Don't allow skipping to ServerKeyExchange when
expecting Certificate; the messages expected are determined by the cipher
suite. The ssl3_get_server_public_key call is already guarded.

As the previous test demonstrates, this is safe because of the
ssl3_check_cert_and_algorithm call, but avoid the looseness in the parsing
there.

[*] NB: we don't implement RSA_PSK, and OpenSSL has never implemented it.

Change-Id: I0571e6bcbeb8eb883f77878bdc98d1aa3a287cf3
Reviewed-on: https://boringssl-review.googlesource.com/1156
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 35c399f..6c10a32 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -313,11 +313,7 @@
 				s->init_num=0;
 				break;
 				}
-			/* Check if it is anon DH/ECDH */
-			/* or non-RSA PSK */
-			if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
-			    !((s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK) &&
-			      !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kRSA)))
+			if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher))
 				{
 				ret=ssl3_get_server_certificate(s);
 				if (ret <= 0) goto end;
@@ -1118,24 +1114,12 @@
 	n=s->method->ssl_get_message(s,
 		SSL3_ST_CR_CERT_A,
 		SSL3_ST_CR_CERT_B,
-		-1,
+		SSL3_MT_CERTIFICATE,
 		s->max_cert_list,
 		&ok);
 
 	if (!ok) return((int)n);
 
-	if (s->s3->tmp.message_type == SSL3_MT_SERVER_KEY_EXCHANGE)
-		{
-		s->s3->tmp.reuse_message=1;
-		return(1);
-		}
-
-	if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE)
-		{
-		al=SSL_AD_UNEXPECTED_MESSAGE;
-		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_certificate, SSL_R_BAD_MESSAGE_TYPE);
-		goto f_err;
-		}
 	CBS_init(&cbs, (uint8_t *)s->init_msg, n);
 
 	if ((sk=sk_X509_new_null()) == NULL)
@@ -1732,9 +1716,7 @@
 		}
 	else
 		{
-		if (!(alg_a & SSL_aNULL) &&
-			/* Among PSK ciphers only RSA_PSK needs a public key */
-			!((alg_a & SSL_aPSK) && !(alg_k & SSL_kRSA)))
+		if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher))
 			{
 			/* Might be wrong key type, check it */
 			if (ssl3_check_cert_and_algorithm(s))
@@ -2916,13 +2898,13 @@
 	DH *dh;
 #endif
 
+	/* we don't have a certificate */
+	if (!ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher))
+		return 1;
+
 	alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
 	alg_a=s->s3->tmp.new_cipher->algorithm_auth;
 
-	/* we don't have a certificate */
-	if ((alg_a & SSL_aNULL) || ((alg_a & SSL_aPSK) && !(alg_k & SSL_kRSA)))
-		return(1);
-
 	sc=s->session->sess_cert;
 	if (sc == NULL)
 		{