|  | // Copyright 2015 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "verify_signed_data.h" | 
|  |  | 
|  | #include <openssl/bytestring.h> | 
|  | #include <openssl/digest.h> | 
|  | #include <openssl/err.h> | 
|  | #include <openssl/evp.h> | 
|  | #include <openssl/pki/signature_verify_cache.h> | 
|  | #include <openssl/rsa.h> | 
|  | #include <openssl/sha.h> | 
|  |  | 
|  | #include "cert_errors.h" | 
|  | #include "input.h" | 
|  | #include "parse_values.h" | 
|  | #include "parser.h" | 
|  | #include "signature_algorithm.h" | 
|  |  | 
|  | BSSL_NAMESPACE_BEGIN | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | bool SHA256UpdateWithLengthPrefixedData(SHA256_CTX *s_ctx, const uint8_t *data, | 
|  | uint64_t length) { | 
|  | return (SHA256_Update(s_ctx, reinterpret_cast<uint8_t *>(&length), | 
|  | sizeof(length)) && | 
|  | SHA256_Update(s_ctx, data, length)); | 
|  | } | 
|  |  | 
|  | // Increase to make incompatible changes in the computation of the | 
|  | // cache key. | 
|  | constexpr uint32_t VerifyCacheKeyVersion = 1; | 
|  |  | 
|  | std::string SignatureVerifyCacheKey(std::string_view algorithm_name, | 
|  | der::Input signed_data, | 
|  | der::Input signature_value_bytes, | 
|  | EVP_PKEY *public_key) { | 
|  | SHA256_CTX s_ctx; | 
|  | bssl::ScopedCBB public_key_cbb; | 
|  | uint8_t digest[SHA256_DIGEST_LENGTH]; | 
|  | uint32_t version = VerifyCacheKeyVersion; | 
|  | if (CBB_init(public_key_cbb.get(), 128) && | 
|  | EVP_marshal_public_key(public_key_cbb.get(), public_key) && | 
|  | SHA256_Init(&s_ctx) && | 
|  | SHA256_Update(&s_ctx, reinterpret_cast<uint8_t *>(&version), | 
|  | sizeof(version)) && | 
|  | SHA256UpdateWithLengthPrefixedData( | 
|  | &s_ctx, reinterpret_cast<const uint8_t *>(algorithm_name.data()), | 
|  | algorithm_name.length()) && | 
|  | SHA256UpdateWithLengthPrefixedData(&s_ctx, CBB_data(public_key_cbb.get()), | 
|  | CBB_len(public_key_cbb.get())) && | 
|  | SHA256UpdateWithLengthPrefixedData(&s_ctx, signature_value_bytes.data(), | 
|  | signature_value_bytes.size()) && | 
|  | SHA256UpdateWithLengthPrefixedData(&s_ctx, signed_data.data(), | 
|  | signed_data.size()) && | 
|  | SHA256_Final(digest, &s_ctx)) { | 
|  | return std::string(reinterpret_cast<char *>(digest), sizeof(digest)); | 
|  | } | 
|  | return std::string(); | 
|  | } | 
|  |  | 
|  | // Place an instance of this class on the call stack to automatically clear | 
|  | // the OpenSSL error stack on function exit. | 
|  | // TODO(crbug.com/boringssl/38): Remove this when the library is more robust to | 
|  | // leaving things in the error queue. | 
|  | class OpenSSLErrStackTracer { | 
|  | public: | 
|  | ~OpenSSLErrStackTracer() { ERR_clear_error(); } | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | // Parses an RSA public key or EC public key from SPKI to an EVP_PKEY. Returns | 
|  | // true on success. | 
|  | // | 
|  | // This function only recognizes the "pk-rsa" (rsaEncryption) flavor of RSA | 
|  | // public key from RFC 5912. | 
|  | // | 
|  | //     pk-rsa PUBLIC-KEY ::= { | 
|  | //      IDENTIFIER rsaEncryption | 
|  | //      KEY RSAPublicKey | 
|  | //      PARAMS TYPE NULL ARE absent | 
|  | //      -- Private key format not in this module -- | 
|  | //      CERT-KEY-USAGE {digitalSignature, nonRepudiation, | 
|  | //      keyEncipherment, dataEncipherment, keyCertSign, cRLSign} | 
|  | //     } | 
|  | // | 
|  | // COMPATIBILITY NOTE: RFC 5912 and RFC 3279 are in disagreement on the value | 
|  | // of parameters for rsaEncryption. Whereas RFC 5912 says they must be absent, | 
|  | // RFC 3279 says they must be NULL: | 
|  | // | 
|  | //     The rsaEncryption OID is intended to be used in the algorithm field | 
|  | //     of a value of type AlgorithmIdentifier.  The parameters field MUST | 
|  | //     have ASN.1 type NULL for this algorithm identifier. | 
|  | // | 
|  | // Following RFC 3279 in this case. | 
|  | // | 
|  | // In the case of parsing EC keys, RFC 5912 describes all the ECDSA | 
|  | // signature algorithms as requiring a public key of type "pk-ec": | 
|  | // | 
|  | //     pk-ec PUBLIC-KEY ::= { | 
|  | //      IDENTIFIER id-ecPublicKey | 
|  | //      KEY ECPoint | 
|  | //      PARAMS TYPE ECParameters ARE required | 
|  | //      -- Private key format not in this module -- | 
|  | //      CERT-KEY-USAGE { digitalSignature, nonRepudiation, keyAgreement, | 
|  | //                           keyCertSign, cRLSign } | 
|  | //     } | 
|  | // | 
|  | // Moreover RFC 5912 stipulates what curves are allowed. The ECParameters | 
|  | // MUST NOT use an implicitCurve or specificCurve for PKIX: | 
|  | // | 
|  | //     ECParameters ::= CHOICE { | 
|  | //      namedCurve      CURVE.&id({NamedCurve}) | 
|  | //      -- implicitCurve   NULL | 
|  | //        -- implicitCurve MUST NOT be used in PKIX | 
|  | //      -- specifiedCurve  SpecifiedCurve | 
|  | //        -- specifiedCurve MUST NOT be used in PKIX | 
|  | //        -- Details for specifiedCurve can be found in [X9.62] | 
|  | //        -- Any future additions to this CHOICE should be coordinated | 
|  | //        -- with ANSI X.9. | 
|  | //     } | 
|  | //     -- If you need to be able to decode ANSI X.9 parameter structures, | 
|  | //     -- uncomment the implicitCurve and specifiedCurve above, and also | 
|  | //     -- uncomment the following: | 
|  | //     --(WITH COMPONENTS {namedCurve PRESENT}) | 
|  | // | 
|  | // The namedCurves are extensible. The ones described by RFC 5912 are: | 
|  | // | 
|  | //     NamedCurve CURVE ::= { | 
|  | //     { ID secp192r1 } | { ID sect163k1 } | { ID sect163r2 } | | 
|  | //     { ID secp224r1 } | { ID sect233k1 } | { ID sect233r1 } | | 
|  | //     { ID secp256r1 } | { ID sect283k1 } | { ID sect283r1 } | | 
|  | //     { ID secp384r1 } | { ID sect409k1 } | { ID sect409r1 } | | 
|  | //     { ID secp521r1 } | { ID sect571k1 } | { ID sect571r1 }, | 
|  | //     ... -- Extensible | 
|  | //     } | 
|  | bool ParsePublicKey(der::Input public_key_spki, | 
|  | bssl::UniquePtr<EVP_PKEY> *public_key) { | 
|  | // Parse the SPKI to an EVP_PKEY. | 
|  | OpenSSLErrStackTracer err_tracer; | 
|  |  | 
|  | CBS cbs; | 
|  | CBS_init(&cbs, public_key_spki.data(), public_key_spki.size()); | 
|  | public_key->reset(EVP_parse_public_key(&cbs)); | 
|  | if (!*public_key || CBS_len(&cbs) != 0) { | 
|  | public_key->reset(); | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VerifySignedData(SignatureAlgorithm algorithm, der::Input signed_data, | 
|  | const der::BitString &signature_value, | 
|  | EVP_PKEY *public_key, SignatureVerifyCache *cache) { | 
|  | int expected_pkey_id = 1; | 
|  | const EVP_MD *digest = nullptr; | 
|  | bool is_rsa_pss = false; | 
|  | std::string_view cache_algorithm_name; | 
|  | switch (algorithm) { | 
|  | case SignatureAlgorithm::kRsaPkcs1Sha1: | 
|  | expected_pkey_id = EVP_PKEY_RSA; | 
|  | digest = EVP_sha1(); | 
|  | cache_algorithm_name = "RsaPkcs1Sha1"; | 
|  | break; | 
|  | case SignatureAlgorithm::kRsaPkcs1Sha256: | 
|  | expected_pkey_id = EVP_PKEY_RSA; | 
|  | digest = EVP_sha256(); | 
|  | cache_algorithm_name = "RsaPkcs1Sha256"; | 
|  | break; | 
|  | case SignatureAlgorithm::kRsaPkcs1Sha384: | 
|  | expected_pkey_id = EVP_PKEY_RSA; | 
|  | digest = EVP_sha384(); | 
|  | cache_algorithm_name = "RsaPkcs1Sha384"; | 
|  | break; | 
|  | case SignatureAlgorithm::kRsaPkcs1Sha512: | 
|  | expected_pkey_id = EVP_PKEY_RSA; | 
|  | digest = EVP_sha512(); | 
|  | cache_algorithm_name = "RsaPkcs1Sha512"; | 
|  | break; | 
|  |  | 
|  | case SignatureAlgorithm::kEcdsaSha1: | 
|  | expected_pkey_id = EVP_PKEY_EC; | 
|  | digest = EVP_sha1(); | 
|  | cache_algorithm_name = "EcdsaSha1"; | 
|  | break; | 
|  | case SignatureAlgorithm::kEcdsaSha256: | 
|  | expected_pkey_id = EVP_PKEY_EC; | 
|  | digest = EVP_sha256(); | 
|  | cache_algorithm_name = "EcdsaSha256"; | 
|  | break; | 
|  | case SignatureAlgorithm::kEcdsaSha384: | 
|  | expected_pkey_id = EVP_PKEY_EC; | 
|  | digest = EVP_sha384(); | 
|  | cache_algorithm_name = "EcdsaSha384"; | 
|  | break; | 
|  | case SignatureAlgorithm::kEcdsaSha512: | 
|  | expected_pkey_id = EVP_PKEY_EC; | 
|  | digest = EVP_sha512(); | 
|  | cache_algorithm_name = "EcdsaSha512"; | 
|  | break; | 
|  |  | 
|  | case SignatureAlgorithm::kRsaPssSha256: | 
|  | expected_pkey_id = EVP_PKEY_RSA; | 
|  | digest = EVP_sha256(); | 
|  | cache_algorithm_name = "RsaPssSha256"; | 
|  | is_rsa_pss = true; | 
|  | break; | 
|  | case SignatureAlgorithm::kRsaPssSha384: | 
|  | expected_pkey_id = EVP_PKEY_RSA; | 
|  | digest = EVP_sha384(); | 
|  | cache_algorithm_name = "RsaPssSha384"; | 
|  | is_rsa_pss = true; | 
|  | break; | 
|  | case SignatureAlgorithm::kRsaPssSha512: | 
|  | expected_pkey_id = EVP_PKEY_RSA; | 
|  | digest = EVP_sha512(); | 
|  | cache_algorithm_name = "RsaPssSha512"; | 
|  | is_rsa_pss = true; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (expected_pkey_id != EVP_PKEY_id(public_key)) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // For the supported algorithms the signature value must be a whole | 
|  | // number of bytes. | 
|  | if (signature_value.unused_bits() != 0) { | 
|  | return false; | 
|  | } | 
|  | der::Input signature_value_bytes = signature_value.bytes(); | 
|  |  | 
|  | std::string cache_key; | 
|  | if (cache) { | 
|  | cache_key = SignatureVerifyCacheKey(cache_algorithm_name, signed_data, | 
|  | signature_value_bytes, public_key); | 
|  | if (!cache_key.empty()) { | 
|  | switch (cache->Check(cache_key)) { | 
|  | case SignatureVerifyCache::Value::kValid: | 
|  | return true; | 
|  | case SignatureVerifyCache::Value::kInvalid: | 
|  | return false; | 
|  | case SignatureVerifyCache::Value::kUnknown: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | OpenSSLErrStackTracer err_tracer; | 
|  |  | 
|  | bssl::ScopedEVP_MD_CTX ctx; | 
|  | EVP_PKEY_CTX *pctx = nullptr;  // Owned by |ctx|. | 
|  |  | 
|  | if (!EVP_DigestVerifyInit(ctx.get(), &pctx, digest, nullptr, public_key)) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (is_rsa_pss) { | 
|  | // All supported RSASSA-PSS algorithms match signing and MGF-1 digest. They | 
|  | // also use the digest length as the salt length, which is specified with -1 | 
|  | // in OpenSSL's API. | 
|  | if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) || | 
|  | !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1)) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool ret = 1 == EVP_DigestVerify(ctx.get(), signature_value_bytes.data(), | 
|  | signature_value_bytes.size(), | 
|  | signed_data.data(), signed_data.size()); | 
|  | if (!cache_key.empty()) { | 
|  | cache->Store(cache_key, ret ? SignatureVerifyCache::Value::kValid | 
|  | : SignatureVerifyCache::Value::kInvalid); | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | bool VerifySignedData(SignatureAlgorithm algorithm, der::Input signed_data, | 
|  | const der::BitString &signature_value, | 
|  | der::Input public_key_spki, SignatureVerifyCache *cache) { | 
|  | bssl::UniquePtr<EVP_PKEY> public_key; | 
|  | if (!ParsePublicKey(public_key_spki, &public_key)) { | 
|  | return false; | 
|  | } | 
|  | return VerifySignedData(algorithm, signed_data, signature_value, | 
|  | public_key.get(), cache); | 
|  | } | 
|  |  | 
|  | BSSL_NAMESPACE_END |