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 #include "crypto/scoped_openssl_types.h"
     17 
     18 namespace crypto {
     19 
     20 namespace {
     21 
     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 
     38 SignatureVerifier::SignatureVerifier()
     39     : verify_context_(NULL) {
     40 }
     41 
     42 SignatureVerifier::~SignatureVerifier() {
     43   Reset();
     44 }
     45 
     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 
     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 
    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 
    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 
    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 
    160 void SignatureVerifier::Reset() {
    161   delete verify_context_;
    162   verify_context_ = NULL;
    163   signature_.clear();
    164 }
    165 
    166 }  // namespace crypto
    167