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);