1 // Copyright 2011 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "crypto/signature_verifier.h"
6
7 #include <memory>
8
9 #include "base/check_op.h"
10 #include "crypto/openssl_util.h"
11 #include "third_party/boringssl/src/include/openssl/bytestring.h"
12 #include "third_party/boringssl/src/include/openssl/digest.h"
13 #include "third_party/boringssl/src/include/openssl/evp.h"
14 #include "third_party/boringssl/src/include/openssl/rsa.h"
15
16 namespace crypto {
17
18 struct SignatureVerifier::VerifyContext {
19 bssl::ScopedEVP_MD_CTX ctx;
20 };
21
22 SignatureVerifier::SignatureVerifier() = default;
23
24 SignatureVerifier::~SignatureVerifier() = default;
25
VerifyInit(SignatureAlgorithm signature_algorithm,base::span<const uint8_t> signature,base::span<const uint8_t> public_key_info)26 bool SignatureVerifier::VerifyInit(SignatureAlgorithm signature_algorithm,
27 base::span<const uint8_t> signature,
28 base::span<const uint8_t> public_key_info) {
29 OpenSSLErrStackTracer err_tracer(FROM_HERE);
30
31 int pkey_type = EVP_PKEY_NONE;
32 const EVP_MD* digest = nullptr;
33 switch (signature_algorithm) {
34 case RSA_PKCS1_SHA1:
35 pkey_type = EVP_PKEY_RSA;
36 digest = EVP_sha1();
37 break;
38 case RSA_PKCS1_SHA256:
39 case RSA_PSS_SHA256:
40 pkey_type = EVP_PKEY_RSA;
41 digest = EVP_sha256();
42 break;
43 case ECDSA_SHA256:
44 pkey_type = EVP_PKEY_EC;
45 digest = EVP_sha256();
46 break;
47 }
48 DCHECK_NE(EVP_PKEY_NONE, pkey_type);
49 DCHECK(digest);
50
51 if (verify_context_)
52 return false;
53
54 verify_context_ = std::make_unique<VerifyContext>();
55 signature_.assign(signature.data(), signature.data() + signature.size());
56
57 CBS cbs;
58 CBS_init(&cbs, public_key_info.data(), public_key_info.size());
59 bssl::UniquePtr<EVP_PKEY> public_key(EVP_parse_public_key(&cbs));
60 if (!public_key || CBS_len(&cbs) != 0 ||
61 EVP_PKEY_id(public_key.get()) != pkey_type) {
62 return false;
63 }
64
65 EVP_PKEY_CTX* pkey_ctx;
66 if (!EVP_DigestVerifyInit(verify_context_->ctx.get(), &pkey_ctx, digest,
67 nullptr, public_key.get())) {
68 return false;
69 }
70
71 if (signature_algorithm == RSA_PSS_SHA256) {
72 if (!EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) ||
73 !EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, digest) ||
74 !EVP_PKEY_CTX_set_rsa_pss_saltlen(
75 pkey_ctx, -1 /* match digest and salt length */)) {
76 return false;
77 }
78 }
79
80 return true;
81 }
82
VerifyUpdate(base::span<const uint8_t> data_part)83 void SignatureVerifier::VerifyUpdate(base::span<const uint8_t> data_part) {
84 DCHECK(verify_context_);
85 OpenSSLErrStackTracer err_tracer(FROM_HERE);
86 int rv = EVP_DigestVerifyUpdate(verify_context_->ctx.get(), data_part.data(),
87 data_part.size());
88 DCHECK_EQ(rv, 1);
89 }
90
VerifyFinal()91 bool SignatureVerifier::VerifyFinal() {
92 DCHECK(verify_context_);
93 OpenSSLErrStackTracer err_tracer(FROM_HERE);
94 int rv = EVP_DigestVerifyFinal(verify_context_->ctx.get(), signature_.data(),
95 signature_.size());
96 DCHECK_EQ(static_cast<int>(!!rv), rv);
97 Reset();
98 return rv == 1;
99 }
100
Reset()101 void SignatureVerifier::Reset() {
102 verify_context_.reset();
103 signature_.clear();
104 }
105
106 } // namespace crypto
107