Don't decompose signature algorithms in ssl_rsa.c. This is a lot more verbose and looks the same between RSA and ECDSA for now, but it gives us room to implement the various algorithm-specific checks. ECDSA algorithms must match the curve, PKCS#1 is forbidden in TLS 1.3, etc. Change-Id: I348cfae664d7b08195a2ab1190820b410e74c5e9 Reviewed-on: https://boringssl-review.googlesource.com/8694 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c index 6dcbcc9..3dd8ae0 100644 --- a/ssl/ssl_rsa.c +++ b/ssl/ssl_rsa.c
@@ -399,77 +399,137 @@ return EVP_PKEY_size(ssl->cert->privatekey); } -/* tls12_get_hash returns the EVP_MD corresponding to the TLS signature - * algorithm |sigalg|. It returns NULL if the type is unknown. */ -static const EVP_MD *tls12_get_hash(uint16_t sigalg) { - if (sigalg == SSL_SIGN_RSA_PKCS1_MD5_SHA1) { - return EVP_md5_sha1(); - } - - switch (sigalg >> 8) { - case TLSEXT_hash_sha1: - return EVP_sha1(); - - case TLSEXT_hash_sha256: - return EVP_sha256(); - - case TLSEXT_hash_sha384: - return EVP_sha384(); - - case TLSEXT_hash_sha512: - return EVP_sha512(); - +static int is_rsa_pkcs1(const EVP_MD **out_md, uint16_t sigalg) { + switch (sigalg) { + case SSL_SIGN_RSA_PKCS1_MD5_SHA1: + *out_md = EVP_md5_sha1(); + return 1; + case SSL_SIGN_RSA_PKCS1_SHA1: + *out_md = EVP_sha1(); + return 1; + case SSL_SIGN_RSA_PKCS1_SHA256: + *out_md = EVP_sha256(); + return 1; + case SSL_SIGN_RSA_PKCS1_SHA384: + *out_md = EVP_sha384(); + return 1; + case SSL_SIGN_RSA_PKCS1_SHA512: + *out_md = EVP_sha512(); + return 1; default: - return NULL; + return 0; } } +static int ssl_sign_rsa_pkcs1(SSL *ssl, uint8_t *out, size_t *out_len, + size_t max_out, const EVP_MD *md, + const uint8_t *in, size_t in_len) { + EVP_MD_CTX ctx; + EVP_MD_CTX_init(&ctx); + *out_len = max_out; + int ret = EVP_DigestSignInit(&ctx, NULL, md, NULL, ssl->cert->privatekey) && + EVP_DigestSignUpdate(&ctx, in, in_len) && + EVP_DigestSignFinal(&ctx, out, out_len); + EVP_MD_CTX_cleanup(&ctx); + return ret; +} + +static int ssl_verify_rsa_pkcs1(SSL *ssl, const uint8_t *signature, + size_t signature_len, const EVP_MD *md, + EVP_PKEY *pkey, const uint8_t *in, + size_t in_len) { + EVP_MD_CTX md_ctx; + EVP_MD_CTX_init(&md_ctx); + int ret = EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) && + EVP_DigestVerifyUpdate(&md_ctx, in, in_len) && + EVP_DigestVerifyFinal(&md_ctx, signature, signature_len); + EVP_MD_CTX_cleanup(&md_ctx); + return ret; +} + +static int is_ecdsa(const EVP_MD **out_md, uint16_t sigalg) { + switch (sigalg) { + case SSL_SIGN_ECDSA_SHA1: + *out_md = EVP_sha1(); + return 1; + case SSL_SIGN_ECDSA_SECP256R1_SHA256: + *out_md = EVP_sha256(); + return 1; + case SSL_SIGN_ECDSA_SECP384R1_SHA384: + *out_md = EVP_sha384(); + return 1; + case SSL_SIGN_ECDSA_SECP521R1_SHA512: + *out_md = EVP_sha512(); + return 1; + default: + return 0; + } +} + +static int ssl_sign_ecdsa(SSL *ssl, uint8_t *out, size_t *out_len, + size_t max_out, const EVP_MD *md, const uint8_t *in, + size_t in_len) { + EVP_MD_CTX ctx; + EVP_MD_CTX_init(&ctx); + *out_len = max_out; + int ret = EVP_DigestSignInit(&ctx, NULL, md, NULL, ssl->cert->privatekey) && + EVP_DigestSignUpdate(&ctx, in, in_len) && + EVP_DigestSignFinal(&ctx, out, out_len); + EVP_MD_CTX_cleanup(&ctx); + return ret; +} + +static int ssl_verify_ecdsa(SSL *ssl, const uint8_t *signature, + size_t signature_len, const EVP_MD *md, + EVP_PKEY *pkey, const uint8_t *in, size_t in_len) { + EVP_MD_CTX md_ctx; + EVP_MD_CTX_init(&md_ctx); + int ret = EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) && + EVP_DigestVerifyUpdate(&md_ctx, in, in_len) && + EVP_DigestVerifyFinal(&md_ctx, signature, signature_len); + EVP_MD_CTX_cleanup(&md_ctx); + return ret; +} + enum ssl_private_key_result_t ssl_private_key_sign( SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, uint16_t signature_algorithm, const uint8_t *in, size_t in_len) { - const EVP_MD *md = tls12_get_hash(signature_algorithm); - if (md == NULL) { - return ssl_private_key_failure; - } - - EVP_MD_CTX mctx; - uint8_t hash[EVP_MAX_MD_SIZE]; - unsigned hash_len; - - EVP_MD_CTX_init(&mctx); - if (!EVP_DigestInit_ex(&mctx, md, NULL) || - !EVP_DigestUpdate(&mctx, in, in_len) || - !EVP_DigestFinal(&mctx, hash, &hash_len)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_EVP_LIB); - EVP_MD_CTX_cleanup(&mctx); - return 0; - } - EVP_MD_CTX_cleanup(&mctx); - - if (ssl->cert->key_method != NULL) { + /* For now, custom private keys can only handle pre-TLS-1.3 signature + * algorithms. + * + * TODO(davidben): Switch SSL_PRIVATE_KEY_METHOD to message-based APIs. */ + const EVP_MD *md; + if (!is_rsa_pkcs1(&md, signature_algorithm) && + !is_ecdsa(&md, signature_algorithm)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY); + return ssl_private_key_failure; + } + + uint8_t hash[EVP_MAX_MD_SIZE]; + unsigned hash_len; + if (!EVP_Digest(in, in_len, hash, &hash_len, md, NULL)) { + return ssl_private_key_failure; + } + return ssl->cert->key_method->sign(ssl, out, out_len, max_out, md, hash, hash_len); } - enum ssl_private_key_result_t ret = ssl_private_key_failure; - EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL); - if (ctx == NULL) { - goto end; + const EVP_MD *md; + if (is_rsa_pkcs1(&md, signature_algorithm)) { + return ssl_sign_rsa_pkcs1(ssl, out, out_len, max_out, md, in, in_len) + ? ssl_private_key_success + : ssl_private_key_failure; + } + if (is_ecdsa(&md, signature_algorithm)) { + return ssl_sign_ecdsa(ssl, out, out_len, max_out, md, in, in_len) + ? ssl_private_key_success + : ssl_private_key_failure; } - size_t len = max_out; - if (!EVP_PKEY_sign_init(ctx) || - !EVP_PKEY_CTX_set_signature_md(ctx, md) || - !EVP_PKEY_sign(ctx, out, &len, hash, hash_len)) { - goto end; - } - *out_len = len; - ret = ssl_private_key_success; - -end: - EVP_PKEY_CTX_free(ctx); - return ret; + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + return ssl_private_key_failure; } enum ssl_private_key_result_t ssl_private_key_sign_complete( @@ -481,18 +541,18 @@ int ssl_public_key_verify(SSL *ssl, const uint8_t *signature, size_t signature_len, uint16_t signature_algorithm, EVP_PKEY *pkey, const uint8_t *in, size_t in_len) { - const EVP_MD *md = tls12_get_hash(signature_algorithm); - if (md == NULL) { - return 0; + const EVP_MD *md; + if (is_rsa_pkcs1(&md, signature_algorithm)) { + return ssl_verify_rsa_pkcs1(ssl, signature, signature_len, md, pkey, in, + in_len); + } + if (is_ecdsa(&md, signature_algorithm)) { + return ssl_verify_ecdsa(ssl, signature, signature_len, md, pkey, in, + in_len); } - EVP_MD_CTX md_ctx; - EVP_MD_CTX_init(&md_ctx); - int ret = EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) && - EVP_DigestVerifyUpdate(&md_ctx, in, in_len) && - EVP_DigestVerifyFinal(&md_ctx, signature, signature_len); - EVP_MD_CTX_cleanup(&md_ctx); - return ret; + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + return 0; } enum ssl_private_key_result_t ssl_private_key_decrypt(