// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "crypto/signature_verifier.h" #include "base/logging.h" #include "crypto/openssl_util.h" #include "third_party/boringssl/src/include/openssl/bytestring.h" #include "third_party/boringssl/src/include/openssl/digest.h" #include "third_party/boringssl/src/include/openssl/evp.h" #include "third_party/boringssl/src/include/openssl/rsa.h" namespace crypto { struct SignatureVerifier::VerifyContext { bssl::ScopedEVP_MD_CTX ctx; }; SignatureVerifier::SignatureVerifier() = default; SignatureVerifier::~SignatureVerifier() = default; bool SignatureVerifier::VerifyInit(SignatureAlgorithm signature_algorithm, base::span signature, base::span public_key_info) { OpenSSLErrStackTracer err_tracer(FROM_HERE); int pkey_type = EVP_PKEY_NONE; const EVP_MD* digest = nullptr; switch (signature_algorithm) { case RSA_PKCS1_SHA1: pkey_type = EVP_PKEY_RSA; digest = EVP_sha1(); break; case RSA_PKCS1_SHA256: case RSA_PSS_SHA256: pkey_type = EVP_PKEY_RSA; digest = EVP_sha256(); break; case ECDSA_SHA256: pkey_type = EVP_PKEY_EC; digest = EVP_sha256(); break; } DCHECK_NE(EVP_PKEY_NONE, pkey_type); DCHECK(digest); if (verify_context_) return false; verify_context_.reset(new VerifyContext); signature_.assign(signature.data(), signature.data() + signature.size()); CBS cbs; CBS_init(&cbs, public_key_info.data(), public_key_info.size()); bssl::UniquePtr public_key(EVP_parse_public_key(&cbs)); if (!public_key || CBS_len(&cbs) != 0 || EVP_PKEY_id(public_key.get()) != pkey_type) { return false; } EVP_PKEY_CTX* pkey_ctx; if (!EVP_DigestVerifyInit(verify_context_->ctx.get(), &pkey_ctx, digest, nullptr, public_key.get())) { return false; } if (signature_algorithm == RSA_PSS_SHA256) { if (!EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) || !EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, digest) || !EVP_PKEY_CTX_set_rsa_pss_saltlen( pkey_ctx, -1 /* match digest and salt length */)) { return false; } } return true; } void SignatureVerifier::VerifyUpdate(base::span data_part) { DCHECK(verify_context_); OpenSSLErrStackTracer err_tracer(FROM_HERE); int rv = EVP_DigestVerifyUpdate(verify_context_->ctx.get(), data_part.data(), data_part.size()); DCHECK_EQ(rv, 1); } bool SignatureVerifier::VerifyFinal() { DCHECK(verify_context_); OpenSSLErrStackTracer err_tracer(FROM_HERE); int rv = EVP_DigestVerifyFinal(verify_context_->ctx.get(), signature_.data(), signature_.size()); DCHECK_EQ(static_cast(!!rv), rv); Reset(); return rv == 1; } void SignatureVerifier::Reset() { verify_context_.reset(); signature_.clear(); } } // namespace crypto