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