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 <davidben@google.com>
diff --git a/crypto/digest/digest_test.c b/crypto/digest/digest_test.c
index 7c37cb5..6c73e95 100644
--- a/crypto/digest/digest_test.c
+++ b/crypto/digest/digest_test.c
@@ -112,6 +112,10 @@
"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 e3d3a87..52d446f 100644
--- a/crypto/digest/digests.c
+++ b/crypto/digest/digests.c
@@ -193,6 +193,45 @@
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 @@
{ 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 a453ea3..864917e 100644
--- a/include/openssl/digest.h
+++ b/include/openssl/digest.h
@@ -84,6 +84,10 @@
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 d040317..17d18d4 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -523,10 +523,7 @@
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 17b4f9a..cbde84f 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -1428,8 +1428,14 @@
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 @@
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 d915fc8..998f1b4 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -1201,10 +1201,6 @@
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 @@
{
/* 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);