• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 namespace crypto {
18 
19 namespace {
20 
ToOpenSSLDigest(SignatureVerifier::HashAlgorithm hash_alg)21 const 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 
33 struct SignatureVerifier::VerifyContext {
34   ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> ctx;
35 };
36 
SignatureVerifier()37 SignatureVerifier::SignatureVerifier()
38     : verify_context_(NULL) {
39 }
40 
~SignatureVerifier()41 SignatureVerifier::~SignatureVerifier() {
42   Reset();
43 }
44 
VerifyInit(const uint8 * signature_algorithm,int signature_algorithm_len,const uint8 * signature,int signature_len,const uint8 * public_key_info,int public_key_info_len)45 bool 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 
VerifyInitRSAPSS(HashAlgorithm hash_alg,HashAlgorithm mask_hash_alg,int salt_len,const uint8 * signature,int signature_len,const uint8 * public_key_info,int public_key_info_len)74 bool 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 
VerifyUpdate(const uint8 * data_part,int data_part_len)102 void 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 
VerifyFinal()111 bool 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 
CommonInit(const EVP_MD * digest,const uint8 * signature,int signature_len,const uint8 * public_key_info,int public_key_info_len,EVP_PKEY_CTX ** pkey_ctx)123 bool 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 
Reset()154 void SignatureVerifier::Reset() {
155   delete verify_context_;
156   verify_context_ = NULL;
157   signature_.clear();
158 }
159 
160 }  // namespace crypto
161