• 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 #include "crypto/scoped_openssl_types.h"
17 
18 namespace crypto {
19 
20 namespace {
21 
ToOpenSSLDigest(SignatureVerifier::HashAlgorithm hash_alg)22 const 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 
34 struct SignatureVerifier::VerifyContext {
35   ScopedEVP_MD_CTX ctx;
36 };
37 
SignatureVerifier()38 SignatureVerifier::SignatureVerifier()
39     : verify_context_(NULL) {
40 }
41 
~SignatureVerifier()42 SignatureVerifier::~SignatureVerifier() {
43   Reset();
44 }
45 
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)46 bool 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 
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)75 bool 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 
VerifyUpdate(const uint8 * data_part,int data_part_len)110 void 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 
VerifyFinal()119 bool 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 
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)131 bool 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 
Reset()160 void SignatureVerifier::Reset() {
161   delete verify_context_;
162   verify_context_ = NULL;
163   signature_.clear();
164 }
165 
166 }  // namespace crypto
167