From 00505ec2e1e4c3047b4f61a306f2ac1372fa7640 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 26 Nov 2014 16:38:00 -0500 Subject: [PATCH] Add EVP_md5_sha1. Use it in ssl3_cert_verify_hash so signing a pre-TLS-1.2 handshake hash can go through RSA_sign and be intercepted via RSA_METHOD appropriately. This avoids Windows needing to intercept sign_raw. (CAPI keys cannot provide sign_raw, unless the input size happens to be that of NID_md5_sha1.) Also use it in processing ServerKeyExchange to avoid special-casing RSA. BUG=crbug.com/437023 Change-Id: Ia07433f468b75fdf7bfc8fa90c9751639b2478e6 Reviewed-on: https://boringssl-review.googlesource.com/2420 Reviewed-by: David Benjamin --- crypto/digest/digest_test.c | 4 ++ crypto/digest/digests.c | 40 +++++++++++++++++ include/openssl/digest.h | 4 ++ ssl/s3_both.c | 5 +-- ssl/s3_clnt.c | 55 +++++++---------------- ssl/s3_srvr.c | 90 +++++++++++++------------------------ 6 files changed, 95 insertions(+), 103 deletions(-) diff --git a/crypto/digest/digest_test.c b/crypto/digest/digest_test.c index 7c37cb55..6c73e957 100644 --- a/crypto/digest/digest_test.c +++ b/crypto/digest/digest_test.c @@ -112,6 +112,10 @@ static const TEST_VECTOR kTestVectors[] = { "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 1, "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909" }, + + /* MD5-SHA1 tests. */ + { &EVP_md5_sha1, NULL, "abc", 1, + "900150983cd24fb0d6963f7d28e17f72a9993e364706816aba3e25717850c26c9cd0d89d" }, }; static int compare_digest(const TEST_VECTOR *test, diff --git a/crypto/digest/digests.c b/crypto/digest/digests.c index e3d3a871..52d446fd 100644 --- a/crypto/digest/digests.c +++ b/crypto/digest/digests.c @@ -193,6 +193,45 @@ static const EVP_MD sha512_md = { const EVP_MD *EVP_sha512(void) { return &sha512_md; } + +typedef struct { + MD5_CTX md5; + SHA_CTX sha1; +} MD5_SHA1_CTX; + +static int md5_sha1_init(EVP_MD_CTX *md_ctx) { + MD5_SHA1_CTX *ctx = md_ctx->md_data; + return MD5_Init(&ctx->md5) && SHA1_Init(&ctx->sha1); +} + +static int md5_sha1_update(EVP_MD_CTX *md_ctx, const void *data, size_t count) { + MD5_SHA1_CTX *ctx = md_ctx->md_data; + return MD5_Update(&ctx->md5, data, count) && SHA1_Update(&ctx->sha1, data, count); +} + +static int md5_sha1_final(EVP_MD_CTX *md_ctx, unsigned char *out) { + MD5_SHA1_CTX *ctx = md_ctx->md_data; + if (!MD5_Final(out, &ctx->md5) || + !SHA1_Final(out + MD5_DIGEST_LENGTH, &ctx->sha1)) { + return 0; + } + return 1; +} + +static const EVP_MD md5_sha1_md = { + NID_md5_sha1, + MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, + 0 /* flags */, + md5_sha1_init, + md5_sha1_update, + md5_sha1_final, + 64 /* block size */, + sizeof(MD5_SHA1_CTX), +}; + +const EVP_MD *EVP_md5_sha1(void) { return &md5_sha1_md; } + + struct nid_to_digest { int nid; const EVP_MD *(*md_func)(); @@ -205,6 +244,7 @@ static const struct nid_to_digest nid_to_digest_mapping[] = { { NID_sha256, EVP_sha256 }, { NID_sha384, EVP_sha384 }, { NID_sha512, EVP_sha512 }, + { NID_md5_sha1, EVP_md5_sha1 }, { NID_dsaWithSHA, EVP_sha1 }, { NID_dsaWithSHA1, EVP_sha1 }, { NID_ecdsa_with_SHA1, EVP_sha1 }, diff --git a/include/openssl/digest.h b/include/openssl/digest.h index a453ea3b..864917e2 100644 --- a/include/openssl/digest.h +++ b/include/openssl/digest.h @@ -84,6 +84,10 @@ OPENSSL_EXPORT const EVP_MD *EVP_sha256(void); OPENSSL_EXPORT const EVP_MD *EVP_sha384(void); OPENSSL_EXPORT const EVP_MD *EVP_sha512(void); +/* EVP_md5_sha1 is a TLS-specific |EVP_MD| which computes the concatenation of + * MD5 and SHA-1, as used in TLS 1.1 and below. */ +OPENSSL_EXPORT const EVP_MD *EVP_md5_sha1(void); + /* EVP_get_digestbynid returns an |EVP_MD| for the given NID, or NULL if no * such digest is known. */ OPENSSL_EXPORT const EVP_MD *EVP_get_digestbynid(int nid); diff --git a/ssl/s3_both.c b/ssl/s3_both.c index d0403175..17d18d42 100644 --- a/ssl/s3_both.c +++ b/ssl/s3_both.c @@ -523,10 +523,7 @@ int ssl3_cert_verify_hash(SSL *s, uint8_t *out, size_t *out_len, const EVP_MD ** 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; + *out_md = EVP_md5_sha1(); } else if (pkey->type == EVP_PKEY_EC) { diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 17b4f9a2..cbde84f9 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -1428,8 +1428,14 @@ int ssl3_get_server_key_exchange(SSL *s) if (!tls12_check_peer_sigalg(&md, &al, s, &server_key_exchange, pkey)) goto f_err; } + else if (pkey->type == EVP_PKEY_RSA) + { + md = EVP_md5_sha1(); + } else + { md = EVP_sha1(); + } /* The last field in |server_key_exchange| is the * signature. */ @@ -1441,47 +1447,16 @@ int ssl3_get_server_key_exchange(SSL *s) goto f_err; } - if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) + if (!EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) || + !EVP_DigestVerifyUpdate(&md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) || + !EVP_DigestVerifyUpdate(&md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) || + !EVP_DigestVerifyUpdate(&md_ctx, CBS_data(¶meter), CBS_len(¶meter)) || + !EVP_DigestVerifyFinal(&md_ctx, CBS_data(&signature), CBS_len(&signature))) { - int num; - unsigned char *q, md_buf[EVP_MAX_MD_SIZE*2]; - size_t md_len = 0; - - q=md_buf; - for (num=2; num > 0; num--) - { - unsigned int digest_len; - EVP_DigestInit_ex(&md_ctx, - (num == 2) ? EVP_md5() : EVP_sha1(), NULL); - EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); - EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); - EVP_DigestUpdate(&md_ctx, CBS_data(¶meter), CBS_len(¶meter)); - EVP_DigestFinal_ex(&md_ctx, q, &digest_len); - q += digest_len; - md_len += digest_len; - } - if (!RSA_verify(NID_md5_sha1, md_buf, md_len, - CBS_data(&signature), CBS_len(&signature), - pkey->pkey.rsa)) - { - al = SSL_AD_DECRYPT_ERROR; - OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_BAD_SIGNATURE); - goto f_err; - } - } - else - { - if (!EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) || - !EVP_DigestVerifyUpdate(&md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) || - !EVP_DigestVerifyUpdate(&md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) || - !EVP_DigestVerifyUpdate(&md_ctx, CBS_data(¶meter), CBS_len(¶meter)) || - !EVP_DigestVerifyFinal(&md_ctx, CBS_data(&signature), CBS_len(&signature))) - { - /* bad signature */ - al=SSL_AD_DECRYPT_ERROR; - OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_BAD_SIGNATURE); - goto f_err; - } + /* bad signature */ + al=SSL_AD_DECRYPT_ERROR; + OPENSSL_PUT_ERROR(SSL, ssl3_get_server_key_exchange, SSL_R_BAD_SIGNATURE); + goto f_err; } } else diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index d915fc8a..998f1b4f 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -1201,10 +1201,6 @@ int ssl3_send_server_done(SSL *s) int ssl3_send_server_key_exchange(SSL *s) { - unsigned char *q; - int j,num; - unsigned char md_buf[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH]; - unsigned int u; DH *dh=NULL,*dhp; EC_KEY *ecdh=NULL, *ecdhp; unsigned char *encodedPoint = NULL; @@ -1506,68 +1502,44 @@ 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. */ - if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) + const EVP_MD *md; + size_t sig_len = EVP_PKEY_size(pkey); + + /* Determine signature algorithm. */ + if (SSL_USE_SIGALGS(s)) { - q=md_buf; - j=0; - for (num=2; num > 0; num--) + md = tls1_choose_signing_digest(s, pkey); + if (!tls12_get_sigandhash(p, pkey, md)) { - EVP_DigestInit_ex(&md_ctx, - (num == 2) ? EVP_md5() : EVP_sha1(), NULL); - EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); - EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); - EVP_DigestUpdate(&md_ctx,d,n); - EVP_DigestFinal_ex(&md_ctx,q, - (unsigned int *)&i); - q+=i; - j+=i; + /* Should never happen */ + al=SSL_AD_INTERNAL_ERROR; + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_INTERNAL_ERROR); + goto f_err; } - if (RSA_sign(NID_md5_sha1, md_buf, j, - &(p[2]), &u, pkey->pkey.rsa) <= 0) - { - OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_LIB_RSA); - goto err; - } - s2n(u,p); - n+=u+2; + p+=2; + } + else if (pkey->type == EVP_PKEY_RSA) + { + md = EVP_md5_sha1(); } else { - const EVP_MD *md; - size_t sig_len = EVP_PKEY_size(pkey); - - - /* send signature algorithm */ - if (SSL_USE_SIGALGS(s)) - { - md = tls1_choose_signing_digest(s, pkey); - if (!tls12_get_sigandhash(p, pkey, md)) - { - /* Should never happen */ - al=SSL_AD_INTERNAL_ERROR; - OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_R_INTERNAL_ERROR); - goto f_err; - } - p+=2; - } - else - { - md = EVP_sha1(); - } - if (!EVP_DigestSignInit(&md_ctx, NULL, md, NULL, pkey) || - !EVP_DigestSignUpdate(&md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) || - !EVP_DigestSignUpdate(&md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) || - !EVP_DigestSignUpdate(&md_ctx, d, n) || - !EVP_DigestSignFinal(&md_ctx, &p[2], &sig_len)) - { - OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_LIB_EVP); - goto err; - } - s2n(sig_len, p); - n += sig_len + 2; - if (SSL_USE_SIGALGS(s)) - n += 2; + md = EVP_sha1(); } + + if (!EVP_DigestSignInit(&md_ctx, NULL, md, NULL, pkey) || + !EVP_DigestSignUpdate(&md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) || + !EVP_DigestSignUpdate(&md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) || + !EVP_DigestSignUpdate(&md_ctx, d, n) || + !EVP_DigestSignFinal(&md_ctx, &p[2], &sig_len)) + { + OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_LIB_EVP); + goto err; + } + s2n(sig_len, p); + n += sig_len + 2; + if (SSL_USE_SIGALGS(s)) + n += 2; } ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, n);