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