1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
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 <openssl/evp.h>
8#include <openssl/x509.h>
9
10#include <vector>
11
12#include "base/logging.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/stl_util.h"
15#include "crypto/openssl_util.h"
16
17namespace crypto {
18
19namespace {
20
21const EVP_MD* ToOpenSSLDigest(SignatureVerifier::HashAlgorithm hash_alg) {
22  switch (hash_alg) {
23    case SignatureVerifier::SHA1:
24      return EVP_sha1();
25    case SignatureVerifier::SHA256:
26      return EVP_sha256();
27  }
28  return EVP_md_null();
29}
30
31}  // namespace
32
33struct SignatureVerifier::VerifyContext {
34  ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> ctx;
35};
36
37SignatureVerifier::SignatureVerifier()
38    : verify_context_(NULL) {
39}
40
41SignatureVerifier::~SignatureVerifier() {
42  Reset();
43}
44
45bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm,
46                                   int signature_algorithm_len,
47                                   const uint8* signature,
48                                   int signature_len,
49                                   const uint8* public_key_info,
50                                   int public_key_info_len) {
51  OpenSSLErrStackTracer err_tracer(FROM_HERE);
52  ScopedOpenSSL<X509_ALGOR, X509_ALGOR_free> algorithm(
53      d2i_X509_ALGOR(NULL, &signature_algorithm, signature_algorithm_len));
54  if (!algorithm.get())
55    return false;
56  int nid = OBJ_obj2nid(algorithm.get()->algorithm);
57  const EVP_MD* digest;
58  if (nid == NID_ecdsa_with_SHA1) {
59    digest = EVP_sha1();
60  } else if (nid == NID_ecdsa_with_SHA256) {
61    digest = EVP_sha256();
62  } else {
63    // This works for PKCS #1 v1.5 RSA signatures, but not for ECDSA
64    // signatures.
65    digest = EVP_get_digestbyobj(algorithm.get()->algorithm);
66  }
67  if (!digest)
68    return false;
69
70  return CommonInit(digest, signature, signature_len, public_key_info,
71                    public_key_info_len, NULL);
72}
73
74bool SignatureVerifier::VerifyInitRSAPSS(HashAlgorithm hash_alg,
75                                         HashAlgorithm mask_hash_alg,
76                                         int salt_len,
77                                         const uint8* signature,
78                                         int signature_len,
79                                         const uint8* public_key_info,
80                                         int public_key_info_len) {
81  OpenSSLErrStackTracer err_tracer(FROM_HERE);
82  const EVP_MD* digest = ToOpenSSLDigest(hash_alg);
83  DCHECK(digest);
84
85  EVP_PKEY_CTX* pkey_ctx;
86  if (!CommonInit(digest, signature, signature_len, public_key_info,
87                  public_key_info_len, &pkey_ctx)) {
88    return false;
89  }
90
91  int rv = EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING);
92  if (rv != 1)
93    return false;
94  rv = EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx,
95                                    ToOpenSSLDigest(mask_hash_alg));
96  if (rv != 1)
97    return false;
98  rv = EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len);
99  return rv == 1;
100}
101
102void SignatureVerifier::VerifyUpdate(const uint8* data_part,
103                                     int data_part_len) {
104  DCHECK(verify_context_);
105  OpenSSLErrStackTracer err_tracer(FROM_HERE);
106  int rv = EVP_DigestVerifyUpdate(verify_context_->ctx.get(),
107                                  data_part, data_part_len);
108  DCHECK_EQ(rv, 1);
109}
110
111bool SignatureVerifier::VerifyFinal() {
112  DCHECK(verify_context_);
113  OpenSSLErrStackTracer err_tracer(FROM_HERE);
114  int rv = EVP_DigestVerifyFinal(verify_context_->ctx.get(),
115                                 vector_as_array(&signature_),
116                                 signature_.size());
117  // rv is -1 if a DER-encoded ECDSA signature cannot be decoded correctly.
118  DCHECK_GE(rv, -1);
119  Reset();
120  return rv == 1;
121}
122
123bool SignatureVerifier::CommonInit(const EVP_MD* digest,
124                                   const uint8* signature,
125                                   int signature_len,
126                                   const uint8* public_key_info,
127                                   int public_key_info_len,
128                                   EVP_PKEY_CTX** pkey_ctx) {
129  if (verify_context_)
130    return false;
131
132  verify_context_ = new VerifyContext;
133
134  signature_.assign(signature, signature + signature_len);
135
136  // BIO_new_mem_buf is not const aware, but it does not modify the buffer.
137  char* data = reinterpret_cast<char*>(const_cast<uint8*>(public_key_info));
138  ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new_mem_buf(data,
139                                                       public_key_info_len));
140  if (!bio.get())
141    return false;
142
143  ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> public_key(
144      d2i_PUBKEY_bio(bio.get(), NULL));
145  if (!public_key.get())
146    return false;
147
148  verify_context_->ctx.reset(EVP_MD_CTX_create());
149  int rv = EVP_DigestVerifyInit(verify_context_->ctx.get(), pkey_ctx,
150                                digest, NULL, public_key.get());
151  return rv == 1;
152}
153
154void SignatureVerifier::Reset() {
155  delete verify_context_;
156  verify_context_ = NULL;
157  signature_.clear();
158}
159
160}  // namespace crypto
161