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 <cryptohi.h>
      8 #include <keyhi.h>
      9 #include <pk11pub.h>
     10 #include <secerr.h>
     11 #include <sechash.h>
     12 #include <stdlib.h>
     13 
     14 #include "base/logging.h"
     15 #include "crypto/nss_util.h"
     16 #include "crypto/third_party/nss/chromium-nss.h"
     17 
     18 namespace crypto {
     19 
     20 namespace {
     21 
     22 HASH_HashType ToNSSHashType(SignatureVerifier::HashAlgorithm hash_alg) {
     23   switch (hash_alg) {
     24     case SignatureVerifier::SHA1:
     25       return HASH_AlgSHA1;
     26     case SignatureVerifier::SHA256:
     27       return HASH_AlgSHA256;
     28   }
     29   return HASH_AlgNULL;
     30 }
     31 
     32 SECStatus VerifyRSAPSS_End(SECKEYPublicKey* public_key,
     33                            HASHContext* hash_context,
     34                            HASH_HashType mask_hash_alg,
     35                            unsigned int salt_len,
     36                            const unsigned char* signature,
     37                            unsigned int signature_len) {
     38   unsigned int hash_len = HASH_ResultLenContext(hash_context);
     39   std::vector<unsigned char> hash(hash_len);
     40   HASH_End(hash_context, &hash[0], &hash_len, hash.size());
     41 
     42   unsigned int modulus_len = SECKEY_PublicKeyStrength(public_key);
     43   if (signature_len != modulus_len) {
     44     PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
     45     return SECFailure;
     46   }
     47   std::vector<unsigned char> enc(signature_len);
     48   SECStatus rv = PK11_PubEncryptRaw(public_key, &enc[0],
     49                                     const_cast<unsigned char*>(signature),
     50                                     signature_len, NULL);
     51   if (rv != SECSuccess) {
     52     LOG(WARNING) << "PK11_PubEncryptRaw failed";
     53     return rv;
     54   }
     55   return emsa_pss_verify(&hash[0], &enc[0], enc.size(),
     56                          HASH_GetType(hash_context), mask_hash_alg,
     57                          salt_len);
     58 }
     59 
     60 }  // namespace
     61 
     62 SignatureVerifier::SignatureVerifier()
     63     : vfy_context_(NULL),
     64       hash_alg_(SHA1),
     65       mask_hash_alg_(SHA1),
     66       salt_len_(0),
     67       public_key_(NULL),
     68       hash_context_(NULL) {
     69   EnsureNSSInit();
     70 }
     71 
     72 SignatureVerifier::~SignatureVerifier() {
     73   Reset();
     74 }
     75 
     76 bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm,
     77                                    int signature_algorithm_len,
     78                                    const uint8* signature,
     79                                    int signature_len,
     80                                    const uint8* public_key_info,
     81                                    int public_key_info_len) {
     82   if (vfy_context_ || hash_context_)
     83     return false;
     84 
     85   signature_.assign(signature, signature + signature_len);
     86 
     87   SECKEYPublicKey* public_key = DecodePublicKeyInfo(public_key_info,
     88                                                     public_key_info_len);
     89   if (!public_key)
     90     return false;
     91 
     92   PLArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     93   if (!arena) {
     94     SECKEY_DestroyPublicKey(public_key);
     95     return false;
     96   }
     97 
     98   SECItem sig_alg_der;
     99   sig_alg_der.type = siBuffer;
    100   sig_alg_der.data = const_cast<uint8*>(signature_algorithm);
    101   sig_alg_der.len = signature_algorithm_len;
    102   SECAlgorithmID sig_alg_id;
    103   SECStatus rv;
    104   rv = SEC_QuickDERDecodeItem(arena, &sig_alg_id,
    105                               SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
    106                               &sig_alg_der);
    107   if (rv != SECSuccess) {
    108     SECKEY_DestroyPublicKey(public_key);
    109     PORT_FreeArena(arena, PR_TRUE);
    110     return false;
    111   }
    112 
    113   SECItem sig;
    114   sig.type = siBuffer;
    115   sig.data = const_cast<uint8*>(signature);
    116   sig.len = signature_len;
    117   SECOidTag hash_alg_tag;
    118   vfy_context_ = VFY_CreateContextWithAlgorithmID(public_key, &sig,
    119                                                   &sig_alg_id, &hash_alg_tag,
    120                                                   NULL);
    121   SECKEY_DestroyPublicKey(public_key);  // Done with public_key.
    122   PORT_FreeArena(arena, PR_TRUE);  // Done with sig_alg_id.
    123   if (!vfy_context_) {
    124     // A corrupted RSA signature could be detected without the data, so
    125     // VFY_CreateContextWithAlgorithmID may fail with SEC_ERROR_BAD_SIGNATURE
    126     // (-8182).
    127     return false;
    128   }
    129 
    130   rv = VFY_Begin(vfy_context_);
    131   if (rv != SECSuccess) {
    132     NOTREACHED();
    133     return false;
    134   }
    135   return true;
    136 }
    137 
    138 bool SignatureVerifier::VerifyInitRSAPSS(HashAlgorithm hash_alg,
    139                                          HashAlgorithm mask_hash_alg,
    140                                          int salt_len,
    141                                          const uint8* signature,
    142                                          int signature_len,
    143                                          const uint8* public_key_info,
    144                                          int public_key_info_len) {
    145   if (vfy_context_ || hash_context_)
    146     return false;
    147 
    148   signature_.assign(signature, signature + signature_len);
    149 
    150   SECKEYPublicKey* public_key = DecodePublicKeyInfo(public_key_info,
    151                                                     public_key_info_len);
    152   if (!public_key)
    153     return false;
    154 
    155   public_key_ = public_key;
    156   hash_alg_ = hash_alg;
    157   mask_hash_alg_ = mask_hash_alg;
    158   salt_len_ = salt_len;
    159   hash_context_ = HASH_Create(ToNSSHashType(hash_alg_));
    160   if (!hash_context_)
    161     return false;
    162   HASH_Begin(hash_context_);
    163   return true;
    164 }
    165 
    166 void SignatureVerifier::VerifyUpdate(const uint8* data_part,
    167                                      int data_part_len) {
    168   if (vfy_context_) {
    169     SECStatus rv = VFY_Update(vfy_context_, data_part, data_part_len);
    170     DCHECK_EQ(SECSuccess, rv);
    171   } else {
    172     HASH_Update(hash_context_, data_part, data_part_len);
    173   }
    174 }
    175 
    176 bool SignatureVerifier::VerifyFinal() {
    177   SECStatus rv;
    178   if (vfy_context_) {
    179     rv = VFY_End(vfy_context_);
    180   } else {
    181     rv = VerifyRSAPSS_End(public_key_, hash_context_,
    182                           ToNSSHashType(mask_hash_alg_), salt_len_,
    183                           signature_.data(),
    184                           signature_.size());
    185   }
    186   Reset();
    187 
    188   // If signature verification fails, the error code is
    189   // SEC_ERROR_BAD_SIGNATURE (-8182).
    190   return (rv == SECSuccess);
    191 }
    192 
    193 // static
    194 SECKEYPublicKey* SignatureVerifier::DecodePublicKeyInfo(
    195     const uint8* public_key_info,
    196     int public_key_info_len) {
    197   CERTSubjectPublicKeyInfo* spki = NULL;
    198   SECItem spki_der;
    199   spki_der.type = siBuffer;
    200   spki_der.data = const_cast<uint8*>(public_key_info);
    201   spki_der.len = public_key_info_len;
    202   spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_der);
    203   if (!spki)
    204     return NULL;
    205   SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki);
    206   SECKEY_DestroySubjectPublicKeyInfo(spki);  // Done with spki.
    207   return public_key;
    208 }
    209 
    210 void SignatureVerifier::Reset() {
    211   if (vfy_context_) {
    212     VFY_DestroyContext(vfy_context_, PR_TRUE);
    213     vfy_context_ = NULL;
    214   }
    215   if (hash_context_) {
    216     HASH_Destroy(hash_context_);
    217     hash_context_ = NULL;
    218   }
    219   if (public_key_) {
    220     SECKEY_DestroyPublicKey(public_key_);
    221     public_key_ = NULL;
    222   }
    223   signature_.clear();
    224 }
    225 
    226 }  // namespace crypto
    227