Home | History | Annotate | Download | only in cert
      1 // Copyright 2013 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 "net/cert/ct_log_verifier.h"
      6 
      7 #include <openssl/evp.h>
      8 #include <openssl/x509.h>
      9 
     10 #include "base/logging.h"
     11 #include "crypto/openssl_util.h"
     12 #include "crypto/sha2.h"
     13 
     14 namespace net {
     15 
     16 namespace {
     17 
     18 const EVP_MD* GetEvpAlg(ct::DigitallySigned::HashAlgorithm alg) {
     19   switch (alg) {
     20     case ct::DigitallySigned::HASH_ALGO_MD5:
     21       return EVP_md5();
     22     case ct::DigitallySigned::HASH_ALGO_SHA1:
     23       return EVP_sha1();
     24     case ct::DigitallySigned::HASH_ALGO_SHA224:
     25       return EVP_sha224();
     26     case ct::DigitallySigned::HASH_ALGO_SHA256:
     27       return EVP_sha256();
     28     case ct::DigitallySigned::HASH_ALGO_SHA384:
     29       return EVP_sha384();
     30     case ct::DigitallySigned::HASH_ALGO_SHA512:
     31       return EVP_sha512();
     32     case ct::DigitallySigned::HASH_ALGO_NONE:
     33     default:
     34       NOTREACHED();
     35       return NULL;
     36   }
     37 }
     38 
     39 }  // namespace
     40 
     41 CTLogVerifier::~CTLogVerifier() {
     42   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
     43 
     44   if (public_key_)
     45     EVP_PKEY_free(public_key_);
     46 }
     47 
     48 CTLogVerifier::CTLogVerifier()
     49     : hash_algorithm_(ct::DigitallySigned::HASH_ALGO_NONE),
     50       signature_algorithm_(ct::DigitallySigned::SIG_ALGO_ANONYMOUS),
     51       public_key_(NULL) {}
     52 
     53 bool CTLogVerifier::Init(const base::StringPiece& public_key,
     54                          const base::StringPiece& description) {
     55   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
     56 
     57   crypto::ScopedOpenSSL<BIO, BIO_free_all> bio(
     58       BIO_new_mem_buf(const_cast<char*>(public_key.data()), public_key.size()));
     59   if (!bio.get())
     60     return false;
     61 
     62   public_key_ = d2i_PUBKEY_bio(bio.get(), NULL);
     63   if (!public_key_)
     64     return false;
     65 
     66   key_id_ = crypto::SHA256HashString(public_key);
     67   description_ = description.as_string();
     68 
     69   // Right now, only RSASSA-PKCS1v15 with SHA-256 and ECDSA with SHA-256 are
     70   // supported.
     71   switch (EVP_PKEY_type(public_key_->type)) {
     72     case EVP_PKEY_RSA:
     73       hash_algorithm_ = ct::DigitallySigned::HASH_ALGO_SHA256;
     74       signature_algorithm_ = ct::DigitallySigned::SIG_ALGO_RSA;
     75       break;
     76     case EVP_PKEY_EC:
     77       hash_algorithm_ = ct::DigitallySigned::HASH_ALGO_SHA256;
     78       signature_algorithm_ = ct::DigitallySigned::SIG_ALGO_ECDSA;
     79       break;
     80     default:
     81       DVLOG(1) << "Unsupported key type: " << EVP_PKEY_type(public_key_->type);
     82       return false;
     83   }
     84 
     85   // Extra sanity check: Require RSA keys of at least 2048 bits.
     86   // EVP_PKEY_size returns the size in bytes. 256 = 2048-bit RSA key.
     87   if (signature_algorithm_ == ct::DigitallySigned::SIG_ALGO_RSA &&
     88       EVP_PKEY_size(public_key_) < 256) {
     89     DVLOG(1) << "Too small a public key.";
     90     return false;
     91   }
     92 
     93   return true;
     94 }
     95 
     96 bool CTLogVerifier::VerifySignature(const base::StringPiece& data_to_sign,
     97                                     const base::StringPiece& signature) {
     98   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
     99 
    100   const EVP_MD* hash_alg = GetEvpAlg(hash_algorithm_);
    101   if (hash_alg == NULL)
    102     return false;
    103 
    104   EVP_MD_CTX ctx;
    105   EVP_MD_CTX_init(&ctx);
    106 
    107   bool ok = (
    108       1 == EVP_DigestVerifyInit(&ctx, NULL, hash_alg, NULL, public_key_) &&
    109       1 == EVP_DigestVerifyUpdate(
    110           &ctx, data_to_sign.data(), data_to_sign.size()) &&
    111       1 == EVP_DigestVerifyFinal(
    112           &ctx,
    113           reinterpret_cast<unsigned char*>(const_cast<char*>(signature.data())),
    114           signature.size()));
    115 
    116   EVP_MD_CTX_cleanup(&ctx);
    117   return ok;
    118 }
    119 
    120 }  // namespace net
    121