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 <stdlib.h>
     10 
     11 #include "base/logging.h"
     12 #include "crypto/nss_util.h"
     13 
     14 namespace crypto {
     15 
     16 SignatureVerifier::SignatureVerifier() : vfy_context_(NULL) {
     17   EnsureNSSInit();
     18 }
     19 
     20 SignatureVerifier::~SignatureVerifier() {
     21   Reset();
     22 }
     23 
     24 bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm,
     25                                    int signature_algorithm_len,
     26                                    const uint8* signature,
     27                                    int signature_len,
     28                                    const uint8* public_key_info,
     29                                    int public_key_info_len) {
     30   signature_.assign(signature, signature + signature_len);
     31 
     32   CERTSubjectPublicKeyInfo* spki = NULL;
     33   SECItem spki_der;
     34   spki_der.type = siBuffer;
     35   spki_der.data = const_cast<uint8*>(public_key_info);
     36   spki_der.len = public_key_info_len;
     37   spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_der);
     38   if (!spki)
     39     return false;
     40   SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki);
     41   SECKEY_DestroySubjectPublicKeyInfo(spki);  // Done with spki.
     42   if (!public_key)
     43     return false;
     44 
     45   PLArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     46   if (!arena) {
     47     SECKEY_DestroyPublicKey(public_key);
     48     return false;
     49   }
     50 
     51   SECItem sig_alg_der;
     52   sig_alg_der.type = siBuffer;
     53   sig_alg_der.data = const_cast<uint8*>(signature_algorithm);
     54   sig_alg_der.len = signature_algorithm_len;
     55   SECAlgorithmID sig_alg_id;
     56   SECStatus rv;
     57   rv = SEC_QuickDERDecodeItem(arena, &sig_alg_id, SECOID_AlgorithmIDTemplate,
     58                               &sig_alg_der);
     59   if (rv != SECSuccess) {
     60     SECKEY_DestroyPublicKey(public_key);
     61     PORT_FreeArena(arena, PR_TRUE);
     62     return false;
     63   }
     64 
     65   SECItem sig;
     66   sig.type = siBuffer;
     67   sig.data = const_cast<uint8*>(signature);
     68   sig.len = signature_len;
     69   SECOidTag hash_alg_tag;
     70   vfy_context_ = VFY_CreateContextWithAlgorithmID(public_key, &sig,
     71                                                   &sig_alg_id, &hash_alg_tag,
     72                                                   NULL);
     73   SECKEY_DestroyPublicKey(public_key);  // Done with public_key.
     74   PORT_FreeArena(arena, PR_TRUE);  // Done with sig_alg_id.
     75   if (!vfy_context_) {
     76     // A corrupted RSA signature could be detected without the data, so
     77     // VFY_CreateContextWithAlgorithmID may fail with SEC_ERROR_BAD_SIGNATURE
     78     // (-8182).
     79     return false;
     80   }
     81 
     82   rv = VFY_Begin(vfy_context_);
     83   if (rv != SECSuccess) {
     84     NOTREACHED();
     85     return false;
     86   }
     87   return true;
     88 }
     89 
     90 void SignatureVerifier::VerifyUpdate(const uint8* data_part,
     91                                      int data_part_len) {
     92   SECStatus rv = VFY_Update(vfy_context_, data_part, data_part_len);
     93   DCHECK(rv == SECSuccess);
     94 }
     95 
     96 bool SignatureVerifier::VerifyFinal() {
     97   SECStatus rv = VFY_End(vfy_context_);
     98   Reset();
     99 
    100   // If signature verification fails, the error code is
    101   // SEC_ERROR_BAD_SIGNATURE (-8182).
    102   return (rv == SECSuccess);
    103 }
    104 
    105 void SignatureVerifier::Reset() {
    106   if (vfy_context_) {
    107     VFY_DestroyContext(vfy_context_, PR_TRUE);
    108     vfy_context_ = NULL;
    109   }
    110   signature_.clear();
    111 }
    112 
    113 }  // namespace crypto
    114