| Index: net/cert/internal/verify_signed_data.cc
|
| diff --git a/net/cert/internal/verify_signed_data.cc b/net/cert/internal/verify_signed_data.cc
|
| index fd68328694be015b60e39de5d041bfdd3a875678..c95e6d781cc28e3091164a4e2be519f8d4c58c36 100644
|
| --- a/net/cert/internal/verify_signed_data.cc
|
| +++ b/net/cert/internal/verify_signed_data.cc
|
| @@ -18,7 +18,8 @@ namespace net {
|
| bool VerifySignedData(const SignatureAlgorithm& signature_algorithm,
|
| const der::Input& signed_data,
|
| const der::Input& signature_value_bit_string,
|
| - const der::Input& public_key) {
|
| + const der::Input& public_key,
|
| + const VerificationPolicy* policy) {
|
| NOTIMPLEMENTED();
|
| return false;
|
| }
|
| @@ -38,6 +39,7 @@ bool VerifySignedData(const SignatureAlgorithm& signature_algorithm,
|
| #include "crypto/openssl_util.h"
|
| #include "crypto/scoped_openssl_types.h"
|
| #include "net/cert/internal/signature_algorithm.h"
|
| +#include "net/cert/internal/verification_policy.h"
|
| #include "net/der/input.h"
|
| #include "net/der/parser.h"
|
|
|
| @@ -46,9 +48,14 @@ namespace net {
|
| namespace {
|
|
|
| // Converts a DigestAlgorithm to an equivalent EVP_MD*.
|
| -WARN_UNUSED_RESULT bool GetDigest(DigestAlgorithm digest, const EVP_MD** out) {
|
| +WARN_UNUSED_RESULT bool GetDigest(DigestAlgorithm digest,
|
| + const VerificationPolicy* policy,
|
| + const EVP_MD** out) {
|
| *out = nullptr;
|
|
|
| + if (!policy->IsAcceptableDigestAlgorithm(digest))
|
| + return false;
|
| +
|
| switch (digest) {
|
| case DigestAlgorithm::Sha1:
|
| *out = EVP_sha1();
|
| @@ -69,7 +76,8 @@ WARN_UNUSED_RESULT bool GetDigest(DigestAlgorithm digest, const EVP_MD** out) {
|
|
|
| // Sets the RSASSA-PSS parameters on |pctx|. Returns true on success.
|
| WARN_UNUSED_RESULT bool ApplyRsaPssOptions(const RsaPssParameters* params,
|
| - EVP_PKEY_CTX* pctx) {
|
| + EVP_PKEY_CTX* pctx,
|
| + const VerificationPolicy* policy) {
|
| // BoringSSL takes a signed int for the salt length, and interprets
|
| // negative values in a special manner. Make sure not to silently underflow.
|
| base::CheckedNumeric<int> salt_length_bytes_int(params->salt_length());
|
| @@ -77,7 +85,7 @@ WARN_UNUSED_RESULT bool ApplyRsaPssOptions(const RsaPssParameters* params,
|
| return false;
|
|
|
| const EVP_MD* mgf1_hash;
|
| - if (!GetDigest(params->mgf1_hash(), &mgf1_hash))
|
| + if (!GetDigest(params->mgf1_hash(), policy, &mgf1_hash))
|
| return false;
|
|
|
| return EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) &&
|
| @@ -160,8 +168,18 @@ WARN_UNUSED_RESULT bool ImportPkeyFromSpki(const der::Input& spki,
|
| //
|
| // Following RFC 3279 in this case.
|
| WARN_UNUSED_RESULT bool ParseRsaKeyFromSpki(const der::Input& public_key_spki,
|
| - crypto::ScopedEVP_PKEY* pkey) {
|
| - return ImportPkeyFromSpki(public_key_spki, EVP_PKEY_RSA, pkey);
|
| + crypto::ScopedEVP_PKEY* pkey,
|
| + const VerificationPolicy* policy) {
|
| + if (!ImportPkeyFromSpki(public_key_spki, EVP_PKEY_RSA, pkey))
|
| + return false;
|
| +
|
| + // Extract the modulus length from the key.
|
| + crypto::ScopedRSA rsa(EVP_PKEY_get1_RSA(pkey->get()));
|
| + if (!rsa.get())
|
| + return false;
|
| + unsigned int modulus_length_bits = BN_num_bits(rsa.get()->n);
|
| +
|
| + return policy->IsAcceptableModulusLengthForRsa(modulus_length_bits);
|
| }
|
|
|
| // Does signature verification using either RSA or ECDSA.
|
| @@ -171,7 +189,8 @@ WARN_UNUSED_RESULT bool ParseRsaKeyFromSpki(const der::Input& public_key_spki,
|
| WARN_UNUSED_RESULT bool DoVerify(const SignatureAlgorithm& algorithm,
|
| const der::Input& signed_data,
|
| const der::Input& signature_value,
|
| - EVP_PKEY* public_key) {
|
| + EVP_PKEY* public_key,
|
| + const VerificationPolicy* policy) {
|
| DCHECK(algorithm.algorithm() == SignatureAlgorithmId::RsaPkcs1 ||
|
| algorithm.algorithm() == SignatureAlgorithmId::RsaPss ||
|
| algorithm.algorithm() == SignatureAlgorithmId::Ecdsa);
|
| @@ -182,7 +201,7 @@ WARN_UNUSED_RESULT bool DoVerify(const SignatureAlgorithm& algorithm,
|
| EVP_PKEY_CTX* pctx = nullptr; // Owned by |ctx|.
|
|
|
| const EVP_MD* digest;
|
| - if (!GetDigest(algorithm.digest(), &digest))
|
| + if (!GetDigest(algorithm.digest(), policy, &digest))
|
| return false;
|
|
|
| if (!EVP_DigestVerifyInit(ctx.get(), &pctx, digest, nullptr, public_key))
|
| @@ -190,7 +209,7 @@ WARN_UNUSED_RESULT bool DoVerify(const SignatureAlgorithm& algorithm,
|
|
|
| // Set the RSASSA-PSS specific options.
|
| if (algorithm.algorithm() == SignatureAlgorithmId::RsaPss &&
|
| - !ApplyRsaPssOptions(algorithm.ParamsForRsaPss(), pctx)) {
|
| + !ApplyRsaPssOptions(algorithm.ParamsForRsaPss(), pctx, policy)) {
|
| return false;
|
| }
|
|
|
| @@ -203,21 +222,6 @@ WARN_UNUSED_RESULT bool DoVerify(const SignatureAlgorithm& algorithm,
|
| signature_value.Length());
|
| }
|
|
|
| -// Returns true if the given curve is allowed for ECDSA. The input is a
|
| -// BoringSSL NID.
|
| -//
|
| -// TODO(eroman): Extract policy decisions such as allowed curves, hashes, RSA
|
| -// modulus size, to somewhere more central.
|
| -WARN_UNUSED_RESULT bool IsAllowedCurveName(int curve_nid) {
|
| - switch (curve_nid) {
|
| - case NID_X9_62_prime256v1:
|
| - case NID_secp384r1:
|
| - case NID_secp521r1:
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| // Parses an EC public key from SPKI to an EVP_PKEY.
|
| //
|
| // Returns true on success.
|
| @@ -263,18 +267,18 @@ WARN_UNUSED_RESULT bool IsAllowedCurveName(int curve_nid) {
|
| // ... -- Extensible
|
| // }
|
| WARN_UNUSED_RESULT bool ParseEcKeyFromSpki(const der::Input& public_key_spki,
|
| - crypto::ScopedEVP_PKEY* pkey) {
|
| + crypto::ScopedEVP_PKEY* pkey,
|
| + const VerificationPolicy* policy) {
|
| if (!ImportPkeyFromSpki(public_key_spki, EVP_PKEY_EC, pkey))
|
| return false;
|
|
|
| - // Enforce policy on allowed curves in case ImportPkeyFromSpki() were to
|
| - // recognize and allow use of a weak curve.
|
| + // Extract the curve name.
|
| crypto::ScopedEC_KEY ec(EVP_PKEY_get1_EC_KEY(pkey->get()));
|
| if (!ec.get())
|
| return false; // Unexpected.
|
| -
|
| int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get()));
|
| - return IsAllowedCurveName(curve_nid);
|
| +
|
| + return policy->IsAcceptableCurveForEcdsa(curve_nid);
|
| }
|
|
|
| } // namespace
|
| @@ -282,18 +286,24 @@ WARN_UNUSED_RESULT bool ParseEcKeyFromSpki(const der::Input& public_key_spki,
|
| bool VerifySignedData(const SignatureAlgorithm& signature_algorithm,
|
| const der::Input& signed_data,
|
| const der::Input& signature_value_bit_string,
|
| - const der::Input& public_key_spki) {
|
| + const der::Input& public_key_spki,
|
| + const VerificationPolicy* policy) {
|
| + // Optimization: Check the digest before parsing the SPKI. This isn't
|
| + // strictly necessary as it will also get checked by GetDigest().
|
| + if (!policy->IsAcceptableDigestAlgorithm(signature_algorithm.digest()))
|
| + return false;
|
| +
|
| crypto::ScopedEVP_PKEY public_key;
|
|
|
| // Parse the SPKI to an EVP_PKEY appropriate for the signature algorithm.
|
| switch (signature_algorithm.algorithm()) {
|
| case SignatureAlgorithmId::RsaPkcs1:
|
| case SignatureAlgorithmId::RsaPss:
|
| - if (!ParseRsaKeyFromSpki(public_key_spki, &public_key))
|
| + if (!ParseRsaKeyFromSpki(public_key_spki, &public_key, policy))
|
| return false;
|
| break;
|
| case SignatureAlgorithmId::Ecdsa:
|
| - if (!ParseEcKeyFromSpki(public_key_spki, &public_key))
|
| + if (!ParseEcKeyFromSpki(public_key_spki, &public_key, policy))
|
| return false;
|
| break;
|
| }
|
| @@ -310,7 +320,7 @@ bool VerifySignedData(const SignatureAlgorithm& signature_algorithm,
|
| return false;
|
|
|
| return DoVerify(signature_algorithm, signed_data, signature_value,
|
| - public_key.get());
|
| + public_key.get(), policy);
|
| }
|
|
|
| } // namespace net
|
|
|