Refactor server-side CertificateVerify handling.

This moves CertificateVerify digest processing to the new
SSL_GET_MESSAGE_DONT_HASH_MESSAGE flag. It also refactors it similarly to
ssl3_send_cert_verify and moves that logic to a common ssl3_cert_verify_hash
function to compute the handshake hash.

This removes a large chunk of duplicate (and divergent!) logic between TLS and
DTLS. It also removes TLS1_FLAGS_KEEP_HANDSHAKE.

Change-Id: Ia63c94f7d76d901bc9c4c33454fbfede411adf63
Reviewed-on: https://boringssl-review.googlesource.com/1633
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index e58e330..725bb09 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2481,6 +2481,7 @@
 #define SSL_F_tls1_check_duplicate_extensions 281
 #define SSL_F_ssl3_expect_change_cipher_spec 282
 #define SSL_F_ssl23_get_v2_client_hello 283
+#define SSL_F_ssl3_cert_verify_hash 284
 #define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 100
 #define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 101
 #define SSL_R_INVALID_NULL_CMD_NAME 102
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index a470b89..4cc9f6c 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -341,7 +341,6 @@
 #define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS	0x0001
 #define SSL3_FLAGS_POP_BUFFER			0x0004
 #define TLS1_FLAGS_TLS_PADDING_BUG		0x0008
-#define TLS1_FLAGS_KEEP_HANDSHAKE		0x0020
 /* TODO(davidben): This flag can probably be merged into s3->change_cipher_spec
  * to something tri-state. (Normal / Expect CCS / Between CCS and Finished). */
 #define SSL3_FLAGS_EXPECT_CCS			0x0080
@@ -422,9 +421,6 @@
 	 * established connection state in case of renegotiations.
 	 */
 	struct	{
-		/* actually only needs to be 16+20 */
-		unsigned char cert_verify_md[EVP_MAX_MD_SIZE*2];
-
 		/* actually only need to be 16+20 for SSLv3 and 12 for TLS */
 		unsigned char finish_md[EVP_MAX_MD_SIZE*2];
 		int finish_md_len;
diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c
index 2b45874..102d442 100644
--- a/ssl/d1_srvr.c
+++ b/ssl/d1_srvr.c
@@ -485,37 +485,6 @@
 				goto end;
 			s->state=SSL3_ST_SR_CERT_VRFY_A;
 			s->init_num=0;
-
-			/* TODO(davidben): These two blocks are different
-			 * between SSL and DTLS. Resolve the difference and code
-			 * duplication. */
-			if (SSL_USE_SIGALGS(s))
-				{
-				if (!s->session->peer)
-					break;
-				/* For sigalgs freeze the handshake buffer
-				 * at this point and digest cached records.
-				 */
-				if (!s->s3->handshake_buffer)
-					{
-					OPENSSL_PUT_ERROR(SSL, dtls1_accept, ERR_R_INTERNAL_ERROR);
-					return -1;
-					}
-				s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
-				if (!ssl3_digest_cached_records(s))
-					return -1;
-				}
-			else
-				{
-				/* We need to get hashes here so if there is
-				 * a client cert, it can be verified */ 
-				s->method->ssl3_enc->cert_verify_mac(s,
-					NID_md5,
-					&(s->s3->tmp.cert_verify_md[0]));
-				s->method->ssl3_enc->cert_verify_mac(s,
-					NID_sha1,
-					&(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
-				}
 			break;
 
 		case SSL3_ST_SR_CERT_VRFY_A:
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 46b0960..7944891 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -118,8 +118,10 @@
 #include <openssl/buf.h>
 #include <openssl/evp.h>
 #include <openssl/mem.h>
+#include <openssl/md5.h>
 #include <openssl/obj.h>
 #include <openssl/rand.h>
+#include <openssl/sha.h>
 #include <openssl/x509.h>
 
 #include "ssl_locl.h"
@@ -483,6 +485,66 @@
 	ssl3_finish_mac(s, (uint8_t *)s->init_buf->data, s->init_num + header_len);
 	}
 
+/* ssl3_cert_verify_hash is documented as needing EVP_MAX_MD_SIZE because that
+ * is sufficient pre-TLS1.2 as well. */
+OPENSSL_COMPILE_ASSERT(EVP_MAX_MD_SIZE > MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH,
+	combined_tls_hash_fits_in_max);
+
+int ssl3_cert_verify_hash(SSL *s, uint8_t *out, size_t *out_len, const EVP_MD **out_md, EVP_PKEY *pkey)
+	{
+	/* For TLS v1.2 send signature algorithm and signature using
+	 * agreed digest and cached handshake records. Otherwise, use
+	 * SHA1 or MD5 + SHA1 depending on key type.  */
+	if (SSL_USE_SIGALGS(s))
+		{
+		const uint8_t *hdata;
+		size_t hdatalen;
+		EVP_MD_CTX mctx;
+		unsigned len;
+
+		if (!BIO_mem_contents(s->s3->handshake_buffer, &hdata, &hdatalen))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_cert_verify_hash, ERR_R_INTERNAL_ERROR);
+			return 0;
+			}
+		EVP_MD_CTX_init(&mctx);
+		if (!EVP_DigestInit_ex(&mctx, *out_md, NULL)
+			|| !EVP_DigestUpdate(&mctx, hdata, hdatalen)
+			|| !EVP_DigestFinal(&mctx, out, &len))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_cert_verify_hash, ERR_R_EVP_LIB);
+			EVP_MD_CTX_cleanup(&mctx);
+			return 0;
+			}
+		*out_len = len;
+		}
+	else if (pkey->type == EVP_PKEY_RSA)
+		{
+		if (s->method->ssl3_enc->cert_verify_mac(s, NID_md5, out) == 0 ||
+			s->method->ssl3_enc->cert_verify_mac(s,
+				NID_sha1, out + MD5_DIGEST_LENGTH) == 0)
+			return 0;
+		*out_len = MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH;
+		/* Using a NULL signature MD makes EVP_PKEY_sign perform
+		 * a raw RSA signature, rather than wrapping in a
+		 * DigestInfo. */
+		*out_md = NULL;
+		}
+	else if (pkey->type == EVP_PKEY_EC)
+		{
+		if (s->method->ssl3_enc->cert_verify_mac(s, NID_sha1, out) == 0)
+			return 0;
+		*out_len = SHA_DIGEST_LENGTH;
+		*out_md = EVP_sha1();
+		}
+	else
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_cert_verify_hash, ERR_R_INTERNAL_ERROR);
+		return 0;
+		}
+	return 1;
+	}
+
 int ssl_cert_type(X509 *x, EVP_PKEY *pkey)
 	{
 	EVP_PKEY *pk;
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index ec992c2..5dce641 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -2315,69 +2315,41 @@
 int ssl3_send_cert_verify(SSL *s)
 	{
 	unsigned char *buf, *p;
-	const EVP_MD *md;
+	const EVP_MD *md = NULL;
 	uint8_t digest[EVP_MAX_MD_SIZE];
-	unsigned digest_length;
+	size_t digest_length;
 	EVP_PKEY *pkey;
 	EVP_PKEY_CTX *pctx = NULL;
-	EVP_MD_CTX mctx;
 	size_t signature_length = 0;
 	unsigned long n = 0;
 
-	EVP_MD_CTX_init(&mctx);
 	buf=(unsigned char *)s->init_buf->data;
 
 	if (s->state == SSL3_ST_CW_CERT_VRFY_A)
 		{
 		p= ssl_handshake_start(s);
 		pkey = s->cert->key->privatekey;
-		/* For TLS v1.2 send signature algorithm and signature using
-		 * agreed digest and cached handshake records. Otherwise, use
-		 * SHA1 or MD5 + SHA1 depending on key type.
-		 */
+
+		/* Write out the digest type if needbe. */
 		if (SSL_USE_SIGALGS(s))
 			{
-			const uint8_t *hdata;
-			size_t hdatalen;
 			md = s->cert->key->digest;
-			if (!BIO_mem_contents(s->s3->handshake_buffer, &hdata, &hdatalen) ||
-			    !tls12_get_sigandhash(p, pkey, md))
+			if (!tls12_get_sigandhash(p, pkey, md))
 				{
 				OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_INTERNAL_ERROR);
 				goto err;
 				}
 			p += 2;
 			n += 2;
-			if (!EVP_DigestInit_ex(&mctx, md, NULL)
-				|| !EVP_DigestUpdate(&mctx, hdata, hdatalen)
-				|| !EVP_DigestFinal(&mctx, digest, &digest_length))
-				{
-				OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_EVP_LIB);
-				goto err;
-				}
 			}
-		else if (pkey->type == EVP_PKEY_RSA)
-			{
-			s->method->ssl3_enc->cert_verify_mac(s, NID_md5, digest);
-			s->method->ssl3_enc->cert_verify_mac(s,
-				NID_sha1, &digest[MD5_DIGEST_LENGTH]);
-			digest_length = MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH;
-			/* Using a NULL signature MD makes EVP_PKEY_sign perform
-			 * a raw RSA signature, rather than wrapping in a
-			 * DigestInfo. */
-			md = NULL;
-			}
-		else if (pkey->type == EVP_PKEY_EC)
-			{
-			s->method->ssl3_enc->cert_verify_mac(s, NID_sha1, digest);
-			digest_length = SHA_DIGEST_LENGTH;
-			md = EVP_sha1();
-			}
-		else
-			{
-			OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_INTERNAL_ERROR);
+
+		/* Compute the digest. */
+		if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey))
 			goto err;
-			}
+
+		/* The handshake buffer is no longer necessary. */
+		if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+			goto err;
 
 		/* Sign the digest. */
 		pctx = EVP_PKEY_CTX_new(pkey, NULL);
@@ -2385,10 +2357,10 @@
 			goto err;
 
 		/* Initialize the EVP_PKEY_CTX and determine the size of the signature. */
-		if (EVP_PKEY_sign_init(pctx) != 1 ||
-			EVP_PKEY_CTX_set_signature_md(pctx, md) != 1 ||
-			EVP_PKEY_sign(pctx, NULL, &signature_length,
-				digest, digest_length) != 1)
+		if (!EVP_PKEY_sign_init(pctx) ||
+			!EVP_PKEY_CTX_set_signature_md(pctx, md) ||
+			!EVP_PKEY_sign(pctx, NULL, &signature_length,
+				digest, digest_length))
 			{
 			OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_EVP_LIB);
 			goto err;
@@ -2400,8 +2372,8 @@
 			goto err;
 			}
 
-		if (EVP_PKEY_sign(pctx, &p[2], &signature_length,
-				digest, digest_length) != 1)
+		if (!EVP_PKEY_sign(pctx, &p[2], &signature_length,
+				digest, digest_length))
 			{
 			OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_EVP_LIB);
 			goto err;
@@ -2410,22 +2382,12 @@
 		s2n(signature_length, p);
 		n += signature_length + 2;
 
-		/* Now that client auth is completed, we no longer need cached
-		 * handshake records and can digest them. */
-		if (SSL_USE_SIGALGS(s))
-			{
-			if (!ssl3_digest_cached_records(s))
-				goto err;
-			}
-
 		ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n);
 		s->state=SSL3_ST_CW_CERT_VRFY_B;
 		}
-	EVP_MD_CTX_cleanup(&mctx);
 	EVP_PKEY_CTX_free(pctx);
 	return ssl_do_write(s);
 err:
-	EVP_MD_CTX_cleanup(&mctx);
 	EVP_PKEY_CTX_free(pctx);
 	return(-1);
 	}
diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c
index b9e4026..e25d90c 100644
--- a/ssl/s3_enc.c
+++ b/ssl/s3_enc.c
@@ -499,7 +499,7 @@
 
 void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len)
 	{
-	if (s->s3->handshake_buffer && !(s->s3->flags & TLS1_FLAGS_KEEP_HANDSHAKE)) 
+	if (s->s3->handshake_buffer)
 		{
 		BIO_write (s->s3->handshake_buffer,(void *)buf,len);
 		} 
@@ -546,12 +546,9 @@
 			s->s3->handshake_dgst[i]=NULL;
 			}
 		}
-	if (!(s->s3->flags & TLS1_FLAGS_KEEP_HANDSHAKE))
-		{
-		/* Free handshake_buffer BIO */
-		BIO_free(s->s3->handshake_buffer);
-		s->s3->handshake_buffer = NULL;
-		}
+	/* Free handshake_buffer BIO */
+	BIO_free(s->s3->handshake_buffer);
+	s->s3->handshake_buffer = NULL;
 
 	return 1;
 	}
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 0654906..e9353d1 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -486,54 +486,6 @@
 				goto end;
 			s->state=SSL3_ST_SR_CERT_VRFY_A;
 			s->init_num=0;
-
-			/* TODO(davidben): These two blocks are different
-			 * between SSL and DTLS. Resolve the difference and code
-			 * duplication. */
-			if (SSL_USE_SIGALGS(s))
-				{
-				if (!s->session->peer)
-					break;
-				/* For sigalgs freeze the handshake buffer
-				 * at this point and digest cached records.
-				 */
-				if (!s->s3->handshake_buffer)
-					{
-					OPENSSL_PUT_ERROR(SSL, ssl3_accept, ERR_R_INTERNAL_ERROR);
-					return -1;
-					}
-				s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
-				if (!ssl3_digest_cached_records(s))
-					return -1;
-				}
-			else
-				{
-				int offset=0;
-				int dgst_num;
-
-				/* We need to get hashes here so if there is
-				 * a client cert, it can be verified
-				 * FIXME - digest processing for CertificateVerify
-				 * should be generalized. But it is next step
-				 */
-				if (s->s3->handshake_buffer)
-					if (!ssl3_digest_cached_records(s))
-						return -1;
-				for (dgst_num=0; dgst_num<SSL_MAX_DIGEST;dgst_num++)	
-					if (s->s3->handshake_dgst[dgst_num]) 
-						{
-						int dgst_size;
-
-						s->method->ssl3_enc->cert_verify_mac(s,EVP_MD_CTX_type(s->s3->handshake_dgst[dgst_num]),&(s->s3->tmp.cert_verify_md[offset]));
-						dgst_size=EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]);
-						if (dgst_size < 0)
-							{
-							ret = -1;
-							goto end;
-							}
-						offset+=dgst_size;
-						}		
-				}
 			break;
 
 		case SSL3_ST_SR_CERT_VRFY_A:
@@ -2298,24 +2250,24 @@
 
 int ssl3_get_cert_verify(SSL *s)
 	{
-	EVP_PKEY *pkey=NULL;
 	int al,ok,ret=0;
 	long n;
 	CBS certificate_verify, signature;
-	int type = 0;
 	X509 *peer = s->session->peer;
+	EVP_PKEY *pkey = NULL;
 	const EVP_MD *md = NULL;
-	EVP_MD_CTX mctx;
-
-	EVP_MD_CTX_init(&mctx);
+	uint8_t digest[EVP_MAX_MD_SIZE];
+	size_t digest_length;
+	EVP_PKEY_CTX *pctx = NULL;
 
 	/* Only RSA and ECDSA client certificates are supported, so a
 	 * CertificateVerify is required if and only if there's a
 	 * client certificate. */
 	if (peer == NULL)
 		{
-		ret = 1;
-		goto done_with_buffer;
+		if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+			return -1;
+		return 1;
 		}
 
 	n=s->method->ssl_get_message(s,
@@ -2323,20 +2275,17 @@
 		SSL3_ST_SR_CERT_VRFY_B,
 		SSL3_MT_CERTIFICATE_VERIFY,
 		SSL3_RT_MAX_PLAIN_LENGTH,
-		SSL_GET_MESSAGE_HASH_MESSAGE,
+		SSL_GET_MESSAGE_DONT_HASH_MESSAGE,
 		&ok);
 
 	if (!ok)
-		{
-		ret = (int)n;
-		goto done;
-		}
+		return (int)n;
 
+	/* Filter out unsupported certificate types. */
 	pkey = X509_get_pubkey(peer);
-	type = X509_certificate_type(peer,pkey);
-	if (!(type & EVP_PKT_SIGN))
+	if (!(X509_certificate_type(peer, pkey) & EVP_PKT_SIGN) ||
+		(pkey->type != EVP_PKEY_RSA && pkey->type != EVP_PKEY_EC))
 		{
-		/* If it's not a signing certificate, it's unsupported. */
 		al = SSL_AD_UNSUPPORTED_CERTIFICATE;
 		OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
 		goto f_err;
@@ -2344,16 +2293,24 @@
 
 	CBS_init(&certificate_verify, s->init_msg, n);
 
-	/* We now have a signature that we need to verify. */
-	/* TODO(davidben): This should share code with
-	 * ssl3_get_server_key_exchange. */
-
+	/* Determine the digest type if needbe. */
 	if (SSL_USE_SIGALGS(s))
 		{
 		if (!tls12_check_peer_sigalg(&md, &al, s, &certificate_verify, pkey))
 			goto f_err;
 		}
 
+	/* Compute the digest. */
+	if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey))
+		goto err;
+
+	/* The handshake buffer is no longer necessary, and we may hash the
+	 * current message.*/
+	if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+		goto err;
+	ssl3_hash_current_message(s);
+
+	/* Parse and verify the signature. */
 	if (!CBS_get_u16_length_prefixed(&certificate_verify, &signature) ||
 		CBS_len(&certificate_verify) != 0)
 		{
@@ -2362,87 +2319,27 @@
 		goto f_err;
 		}
 
-	if (SSL_USE_SIGALGS(s))
+	pctx = EVP_PKEY_CTX_new(pkey, NULL);
+	if (pctx == NULL)
+		goto err;
+	if (!EVP_PKEY_verify_init(pctx) ||
+		!EVP_PKEY_CTX_set_signature_md(pctx, md) ||
+		!EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature),
+			digest, digest_length))
 		{
-		size_t hdatalen;
-		const uint8_t *hdata;
-		if (!BIO_mem_contents(s->s3->handshake_buffer, &hdata, &hdatalen))
-			{
-			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_INTERNAL_ERROR);
-			al=SSL_AD_INTERNAL_ERROR;
-			goto f_err;
-			}
-		if (!EVP_VerifyInit_ex(&mctx, md, NULL)
-			|| !EVP_VerifyUpdate(&mctx, hdata, hdatalen))
-			{
-			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_EVP_LIB);
-			al=SSL_AD_INTERNAL_ERROR;
-			goto f_err;
-			}
-
-		if (EVP_VerifyFinal(&mctx,
-				CBS_data(&signature), CBS_len(&signature),
-				pkey) <= 0)
-			{
-			al=SSL_AD_DECRYPT_ERROR;
-			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_SIGNATURE);
-			goto f_err;
-			}
-		}
-	else
-	if (pkey->type == EVP_PKEY_RSA)
-		{
-		if (!RSA_verify(NID_md5_sha1, s->s3->tmp.cert_verify_md,
-				MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH,
-				CBS_data(&signature), CBS_len(&signature),
-				pkey->pkey.rsa))
-			{
-			al = SSL_AD_DECRYPT_ERROR;
-			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_RSA_SIGNATURE);
-			goto f_err;
-			}
-		}
-	else
-#ifndef OPENSSL_NO_ECDSA
-		if (pkey->type == EVP_PKEY_EC)
-		{
-		if (!ECDSA_verify(pkey->save_type,
-				&(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
-				SHA_DIGEST_LENGTH,
-				CBS_data(&signature), CBS_len(&signature),
-				pkey->pkey.ec))
-			{
-			/* bad signature */
-			al = SSL_AD_DECRYPT_ERROR;
-			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_ECDSA_SIGNATURE);
-			goto f_err;
-			}
-		}
-	else
-#endif
-		{
-		OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_INTERNAL_ERROR);
-		al=SSL_AD_UNSUPPORTED_CERTIFICATE;
+		al = SSL_AD_DECRYPT_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_SIGNATURE);
 		goto f_err;
 		}
 
-
-	ret=1;
+	ret = 1;
 	if (0)
 		{
 f_err:
 		ssl3_send_alert(s,SSL3_AL_FATAL,al);
 		}
-done_with_buffer:
-	/* There is no more need for the handshake buffer. */
-	if (s->s3->handshake_buffer)
-		{
-		BIO_free(s->s3->handshake_buffer);
-		s->s3->handshake_buffer = NULL;
-		s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE;
-		}
-done:
-	EVP_MD_CTX_cleanup(&mctx);
+err:
+	EVP_PKEY_CTX_free(pctx);
 	EVP_PKEY_free(pkey);
 	return(ret);
 	}
diff --git a/ssl/ssl_error.c b/ssl/ssl_error.c
index 16c8aa2..20737a5 100644
--- a/ssl/ssl_error.c
+++ b/ssl/ssl_error.c
@@ -100,10 +100,10 @@
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_write, 0), "ssl23_write"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_accept, 0), "ssl3_accept"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_callback_ctrl, 0), "ssl3_callback_ctrl"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_cert_verify_hash, 0), "ssl3_cert_verify_hash"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_change_cipher_state, 0), "ssl3_change_cipher_state"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_check_cert_and_algorithm, 0), "ssl3_check_cert_and_algorithm"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_check_client_hello, 0), "ssl3_check_client_hello"},
-  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_hello, 0), "ssl3_send_client_hello"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_connect, 0), "ssl3_connect"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_ctrl, 0), "ssl3_ctrl"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_ctx_ctrl, 0), "ssl3_ctx_ctrl"},
@@ -130,11 +130,12 @@
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_handshake_mac, 0), "ssl3_handshake_mac"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_read_bytes, 0), "ssl3_read_bytes"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_read_n, 0), "ssl3_read_n"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_cert_verify, 0), "ssl3_send_cert_verify"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_certificate_request, 0), "ssl3_send_certificate_request"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_channel_id, 0), "ssl3_send_channel_id"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_certificate, 0), "ssl3_send_client_certificate"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_hello, 0), "ssl3_send_client_hello"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_key_exchange, 0), "ssl3_send_client_key_exchange"},
-  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_cert_verify, 0), "ssl3_send_cert_verify"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_certificate, 0), "ssl3_send_server_certificate"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_hello, 0), "ssl3_send_server_hello"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_key_exchange, 0), "ssl3_send_server_key_exchange"},
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index ec044e0..09ba191 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -884,6 +884,15 @@
 /* ssl3_hash_current_message incorporates the current handshake message into
  * the handshake hash. */
 void ssl3_hash_current_message(SSL *s);
+
+/* ssl3_cert_verify_hash writes the CertificateVerify hash into the bytes
+ * pointed to by |out| and writes the number of bytes to |*out_len|. |out| must
+ * have room for EVP_MAX_MD_SIZE bytes. For TLS 1.2 and up, |*out_md| is used
+ * for the hash function, otherwise the hash function depends on the type of
+ * |pkey| and is written to |*out_md|. It returns one on success and zero on
+ * failure. */
+int ssl3_cert_verify_hash(SSL *s, uint8_t *out, size_t *out_len, const EVP_MD **out_md, EVP_PKEY *pkey);
+
 int ssl3_send_finished(SSL *s, int a, int b, const char *sender,int slen);
 int ssl3_num_ciphers(void);
 const SSL_CIPHER *ssl3_get_cipher(unsigned int u);