tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pk11_signature_test.cc (6451B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include <memory>
      6 #include "nss.h"
      7 #include "pk11pub.h"
      8 #include "sechash.h"
      9 #include "prerror.h"
     10 
     11 #include "cpputil.h"
     12 #include "nss_scoped_ptrs.h"
     13 #include "databuffer.h"
     14 
     15 #include "gtest/gtest.h"
     16 #include "pk11_signature_test.h"
     17 
     18 namespace nss_test {
     19 
     20 ScopedSECKEYPrivateKey Pk11SignatureTest::ImportPrivateKey(
     21    const DataBuffer& pkcs8) {
     22  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
     23  if (!slot) {
     24    ADD_FAILURE() << "No slot";
     25    return nullptr;
     26  }
     27 
     28  SECItem pkcs8Item = {siBuffer, toUcharPtr(pkcs8.data()),
     29                       static_cast<unsigned int>(pkcs8.len())};
     30 
     31  SECKEYPrivateKey* key = nullptr;
     32  SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
     33      slot.get(), &pkcs8Item, nullptr, nullptr, false, false, KU_ALL, &key,
     34      nullptr);
     35 
     36  if (rv != SECSuccess) {
     37    return nullptr;
     38  }
     39 
     40  return ScopedSECKEYPrivateKey(key);
     41 }
     42 
     43 ScopedSECKEYPublicKey Pk11SignatureTest::ImportPublicKey(
     44    const DataBuffer& spki) {
     45  SECItem spkiItem = {siBuffer, toUcharPtr(spki.data()),
     46                      static_cast<unsigned int>(spki.len())};
     47 
     48  ScopedCERTSubjectPublicKeyInfo certSpki(
     49      SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem));
     50  if (!certSpki) {
     51    return nullptr;
     52  }
     53 
     54  return ScopedSECKEYPublicKey(SECKEY_ExtractPublicKey(certSpki.get()));
     55 }
     56 
     57 bool Pk11SignatureTest::SignRaw(ScopedSECKEYPrivateKey& privKey,
     58                                const DataBuffer& hash, DataBuffer* sig) {
     59  SECItem hashItem = {siBuffer, toUcharPtr(hash.data()),
     60                      static_cast<unsigned int>(hash.len())};
     61  unsigned int sigLen = PK11_SignatureLen(privKey.get());
     62  EXPECT_LT(0, (int)sigLen);
     63  sig->Allocate(static_cast<size_t>(sigLen));
     64  SECItem sigItem = {siBuffer, toUcharPtr(sig->data()),
     65                     static_cast<unsigned int>(sig->len())};
     66  SECStatus rv = PK11_SignWithMechanism(privKey.get(), mechanism_, parameters(),
     67                                        &sigItem, &hashItem);
     68  EXPECT_EQ(sigLen, sigItem.len);
     69  return rv == SECSuccess;
     70 }
     71 
     72 bool Pk11SignatureTest::DigestAndSign(ScopedSECKEYPrivateKey& privKey,
     73                                      const DataBuffer& data, DataBuffer* sig) {
     74  unsigned int sigLen = PK11_SignatureLen(privKey.get());
     75  bool result = true;
     76  EXPECT_LT(0, (int)sigLen);
     77  sig->Allocate(static_cast<size_t>(sigLen));
     78 
     79  // test the hash and verify interface */
     80  PK11Context* context = PK11_CreateContextByPrivKey(
     81      combo_, CKA_SIGN, privKey.get(), parameters());
     82  if (context == NULL) {
     83    ADD_FAILURE() << "Failed to sign data: couldn't create context"
     84                  << "\n"
     85                  << "mech=0x" << std::hex << combo_ << "\n"
     86                  << "Error: " << PORT_ErrorToString(PORT_GetError());
     87    return false;
     88  }
     89  SECStatus rv = PK11_DigestOp(context, data.data(), data.len());
     90  if (rv != SECSuccess) {
     91    ADD_FAILURE() << "Failed to sign data: Update failed\n"
     92                  << "Error: " << PORT_ErrorToString(PORT_GetError());
     93    PK11_DestroyContext(context, PR_TRUE);
     94    return false;
     95  }
     96  unsigned int len = sigLen;
     97  rv = PK11_DigestFinal(context, sig->data(), &len, sigLen);
     98  if (rv != SECSuccess) {
     99    ADD_FAILURE() << "Failed to sign data: final failed\n"
    100                  << "Error: " << PORT_ErrorToString(PORT_GetError());
    101    result = false;
    102  }
    103  if (len != sigLen) {
    104    ADD_FAILURE() << "sign data: unexpected len " << len << "expected"
    105                  << sigLen;
    106    result = false;
    107  }
    108  PK11_DestroyContext(context, PR_TRUE);
    109  return result;
    110 }
    111 
    112 bool Pk11SignatureTest::ImportPrivateKeyAndSignHashedData(
    113    const DataBuffer& pkcs8, const DataBuffer& data, DataBuffer* sig,
    114    DataBuffer* sig2) {
    115  ScopedSECKEYPrivateKey privKey(ImportPrivateKey(pkcs8));
    116  if (!privKey) {
    117    return false;
    118  }
    119 
    120  DataBuffer hash;
    121  if (!ComputeHash(data, &hash)) {
    122    ADD_FAILURE() << "Failed to compute hash";
    123    return false;
    124  }
    125  if (!SignRaw(privKey, hash, sig)) {
    126    ADD_FAILURE() << "Failed to sign hashed data";
    127    return false;
    128  }
    129  if (!DigestAndSign(privKey, data, sig2)) {
    130    /* failure was already added by SignData, with an error message */
    131    return false;
    132  }
    133  return true;
    134 }
    135 
    136 void Pk11SignatureTest::Verify(ScopedSECKEYPublicKey& pubKey,
    137                               const DataBuffer& data, const DataBuffer& sig,
    138                               bool valid) {
    139  SECStatus rv;
    140 
    141  SECItem sigItem = {siBuffer, toUcharPtr(sig.data()),
    142                     static_cast<unsigned int>(sig.len())};
    143 
    144  if (skip_digest_) {
    145    SECItem dataItem = {siBuffer, toUcharPtr(data.data()),
    146                        static_cast<unsigned int>(data.len())};
    147    rv = PK11_VerifyWithMechanism(pubKey.get(), mechanism_, parameters(),
    148                                  &sigItem, &dataItem, nullptr);
    149    EXPECT_EQ(rv, valid ? SECSuccess : SECFailure);
    150    return;
    151  }
    152 
    153  DataBuffer hash;
    154  /* RSA single shot requires encoding the hash before calling
    155   * VerifyWithMechanism. We already check that mechanism
    156   * with the VFY_ interface, so just do the combined hash/Verify
    157   * in that case */
    158  if (!skip_raw_) {
    159    ASSERT_TRUE(ComputeHash(data, &hash));
    160 
    161    // Verify.
    162    SECItem hashItem = {siBuffer, toUcharPtr(hash.data()),
    163                        static_cast<unsigned int>(hash.len())};
    164    rv = PK11_VerifyWithMechanism(pubKey.get(), mechanism_, parameters(),
    165                                  &sigItem, &hashItem, nullptr);
    166    EXPECT_EQ(rv, valid ? SECSuccess : SECFailure);
    167  }
    168 
    169  // test the hash and verify interface */
    170  PK11Context* context = PK11_CreateContextByPubKey(
    171      combo_, CKA_VERIFY, pubKey.get(), parameters(), NULL);
    172  /* we assert here because we'll crash if we try to continue
    173   * without a context. */
    174  ASSERT_NE((void*)context, (void*)NULL)
    175      << "CreateContext failed Error:" << PORT_ErrorToString(PORT_GetError())
    176      << "\n";
    177  rv = PK11_DigestOp(context, data.data(), data.len());
    178  /* expect success unconditionally here */
    179  EXPECT_EQ(rv, SECSuccess);
    180  unsigned int len;
    181  rv = PK11_DigestFinal(context, sigItem.data, &len, sigItem.len);
    182  EXPECT_EQ(rv, valid ? SECSuccess : SECFailure)
    183      << "verify failed Error:" << PORT_ErrorToString(PORT_GetError()) << "\n";
    184  PK11_DestroyContext(context, PR_TRUE);
    185 }
    186 }  // namespace nss_test