Home | History | Annotate | Download | only in crypto
      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 
     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 
     37 SignatureVerifier::SignatureVerifier()
     38     : verify_context_(NULL) {
     39 }
     40 
     41 SignatureVerifier::~SignatureVerifier() {
     42   Reset();
     43 }
     44 
     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 
     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 
    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 
    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 
    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 
    154 void SignatureVerifier::Reset() {
    155   delete verify_context_;
    156   verify_context_ = NULL;
    157   signature_.clear();
    158 }
    159 
    160 }  // namespace crypto
    161