tor-browser

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

pkixtestnss.cpp (11724B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This code is made available to you under your choice of the following sets
      4 * of licensing terms:
      5 */
      6 /* This Source Code Form is subject to the terms of the Mozilla Public
      7 * License, v. 2.0. If a copy of the MPL was not distributed with this
      8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9 */
     10 /* Copyright 2013 Mozilla Contributors
     11 *
     12 * Licensed under the Apache License, Version 2.0 (the "License");
     13 * you may not use this file except in compliance with the License.
     14 * You may obtain a copy of the License at
     15 *
     16 *     http://www.apache.org/licenses/LICENSE-2.0
     17 *
     18 * Unless required by applicable law or agreed to in writing, software
     19 * distributed under the License is distributed on an "AS IS" BASIS,
     20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     21 * See the License for the specific language governing permissions and
     22 * limitations under the License.
     23 */
     24 
     25 #include "mozpkix/test/pkixtestutil.h"
     26 #include "mozpkix/test/pkixtestnss.h"
     27 
     28 #include <limits>
     29 
     30 #include "cryptohi.h"
     31 #include "keyhi.h"
     32 #include "nss.h"
     33 #include "pk11pqg.h"
     34 #include "pk11pub.h"
     35 #include "mozpkix/nss_scoped_ptrs.h"
     36 #include "mozpkix/pkixnss.h"
     37 #include "mozpkix/pkixder.h"
     38 #include "mozpkix/pkixutil.h"
     39 #include "prinit.h"
     40 #include "secerr.h"
     41 #include "secitem.h"
     42 
     43 namespace mozilla { namespace pkix { namespace test {
     44 
     45 namespace {
     46 
     47 TestKeyPair* GenerateKeyPairInner();
     48 
     49 void
     50 InitNSSIfNeeded()
     51 {
     52  if (NSS_NoDB_Init(nullptr) != SECSuccess) {
     53    abort();
     54  }
     55 }
     56 
     57 static ScopedTestKeyPair reusedKeyPair;
     58 
     59 PRStatus
     60 InitReusedKeyPair()
     61 {
     62  InitNSSIfNeeded();
     63  reusedKeyPair.reset(GenerateKeyPairInner());
     64  return reusedKeyPair ? PR_SUCCESS : PR_FAILURE;
     65 }
     66 
     67 class NSSTestKeyPair final : public TestKeyPair
     68 {
     69 public:
     70  NSSTestKeyPair(const TestPublicKeyAlgorithm& aPublicKeyAlg,
     71                 const ByteString& spk,
     72                 const ByteString& aEncryptedPrivateKey,
     73                 const ByteString& aEncryptionAlgorithm,
     74                 const ByteString& aEncryptionParams)
     75    : TestKeyPair(aPublicKeyAlg, spk)
     76    , encryptedPrivateKey(aEncryptedPrivateKey)
     77    , encryptionAlgorithm(aEncryptionAlgorithm)
     78    , encryptionParams(aEncryptionParams)
     79  {
     80  }
     81 
     82  Result SignData(const ByteString& tbs,
     83                  const TestSignatureAlgorithm& signatureAlgorithm,
     84                  /*out*/ ByteString& signature) const override
     85  {
     86    SECOidTag oidTag;
     87    if (signatureAlgorithm.publicKeyAlg == RSA_PKCS1()) {
     88      switch (signatureAlgorithm.digestAlg) {
     89        case TestDigestAlgorithmID::MD2:
     90          oidTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
     91          break;
     92        case TestDigestAlgorithmID::MD5:
     93          oidTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
     94          break;
     95        case TestDigestAlgorithmID::SHA1:
     96          oidTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
     97          break;
     98        case TestDigestAlgorithmID::SHA224:
     99          oidTag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION;
    100          break;
    101        case TestDigestAlgorithmID::SHA256:
    102          oidTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
    103          break;
    104        case TestDigestAlgorithmID::SHA384:
    105          oidTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
    106          break;
    107        case TestDigestAlgorithmID::SHA512:
    108          oidTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
    109          break;
    110        MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
    111      }
    112    } else {
    113      abort();
    114    }
    115 
    116    ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
    117    if (!slot) {
    118      return MapPRErrorCodeToResult(PR_GetError());
    119    }
    120    SECItem encryptedPrivateKeyInfoItem = {
    121      siBuffer,
    122      const_cast<uint8_t*>(encryptedPrivateKey.data()),
    123      static_cast<unsigned int>(encryptedPrivateKey.length())
    124    };
    125    SECItem encryptionAlgorithmItem = {
    126      siBuffer,
    127      const_cast<uint8_t*>(encryptionAlgorithm.data()),
    128      static_cast<unsigned int>(encryptionAlgorithm.length())
    129    };
    130    SECItem encryptionParamsItem = {
    131      siBuffer,
    132      const_cast<uint8_t*>(encryptionParams.data()),
    133      static_cast<unsigned int>(encryptionParams.length())
    134    };
    135    SECKEYEncryptedPrivateKeyInfo encryptedPrivateKeyInfo = {
    136      nullptr,
    137      { encryptionAlgorithmItem, encryptionParamsItem },
    138      encryptedPrivateKeyInfoItem
    139    };
    140    SECItem passwordItem = { siBuffer, nullptr, 0 };
    141    SECItem publicValueItem = {
    142      siBuffer,
    143      const_cast<uint8_t*>(subjectPublicKey.data()),
    144      static_cast<unsigned int>(subjectPublicKey.length())
    145    };
    146    SECKEYPrivateKey* privateKey;
    147    // This should always be an RSA key (we'll have aborted above if we're not
    148    // doing an RSA signature).
    149    if (PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(
    150          slot.get(), &encryptedPrivateKeyInfo, &passwordItem, nullptr,
    151          &publicValueItem, false, false, rsaKey, KU_ALL, &privateKey,
    152          nullptr) != SECSuccess) {
    153      return MapPRErrorCodeToResult(PR_GetError());
    154    }
    155    ScopedSECKEYPrivateKey scopedPrivateKey(privateKey);
    156    SECItem signatureItem;
    157    if (SEC_SignData(&signatureItem, tbs.data(),
    158                     static_cast<int>(tbs.length()),
    159                     scopedPrivateKey.get(), oidTag) != SECSuccess) {
    160      return MapPRErrorCodeToResult(PR_GetError());
    161    }
    162    signature.assign(signatureItem.data, signatureItem.len);
    163    SECITEM_FreeItem(&signatureItem, false);
    164    return Success;
    165  }
    166 
    167  TestKeyPair* Clone() const override
    168  {
    169    return new (std::nothrow) NSSTestKeyPair(publicKeyAlg,
    170                                             subjectPublicKey,
    171                                             encryptedPrivateKey,
    172                                             encryptionAlgorithm,
    173                                             encryptionParams);
    174  }
    175 
    176 private:
    177  const ByteString encryptedPrivateKey;
    178  const ByteString encryptionAlgorithm;
    179  const ByteString encryptionParams;
    180 };
    181 
    182 } // namespace
    183 
    184 // This private function is also used by Gecko's PSM test framework
    185 // (OCSPCommon.cpp).
    186 TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg,
    187                               const ScopedSECKEYPublicKey& publicKey,
    188                               const ScopedSECKEYPrivateKey& privateKey)
    189 {
    190  ScopedCERTSubjectPublicKeyInfo
    191    spki(SECKEY_CreateSubjectPublicKeyInfo(publicKey.get()));
    192  if (!spki) {
    193    return nullptr;
    194  }
    195  SECItem spkDER = spki->subjectPublicKey;
    196  DER_ConvertBitString(&spkDER); // bits to bytes
    197  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
    198  if (!slot) {
    199    return nullptr;
    200  }
    201  // Because NSSTestKeyPair isn't tracked by XPCOM and won't otherwise be aware
    202  // of shutdown, we don't have a way to release NSS resources at the
    203  // appropriate time. To work around this, NSSTestKeyPair doesn't hold on to
    204  // NSS resources. Instead, we export the generated private key part as an
    205  // encrypted blob (with an empty password and fairly lame encryption). When we
    206  // need to use it (e.g. to sign something), we decrypt it and create a
    207  // temporary key object.
    208  SECItem passwordItem = { siBuffer, nullptr, 0 };
    209  ScopedSECKEYEncryptedPrivateKeyInfo encryptedPrivateKey(
    210    PK11_ExportEncryptedPrivKeyInfo(
    211      slot.get(), SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC,
    212      &passwordItem, privateKey.get(), 1, nullptr));
    213  if (!encryptedPrivateKey) {
    214    return nullptr;
    215  }
    216 
    217  return new (std::nothrow) NSSTestKeyPair(
    218    publicKeyAlg,
    219    ByteString(spkDER.data, spkDER.len),
    220    ByteString(encryptedPrivateKey->encryptedData.data,
    221               encryptedPrivateKey->encryptedData.len),
    222    ByteString(encryptedPrivateKey->algorithm.algorithm.data,
    223               encryptedPrivateKey->algorithm.algorithm.len),
    224    ByteString(encryptedPrivateKey->algorithm.parameters.data,
    225               encryptedPrivateKey->algorithm.parameters.len));
    226 }
    227 
    228 namespace {
    229 
    230 TestKeyPair*
    231 GenerateKeyPairInner()
    232 {
    233  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
    234  if (!slot) {
    235    abort();
    236  }
    237  PK11RSAGenParams params;
    238  params.keySizeInBits = 2048;
    239  params.pe = 65537;
    240 
    241  // Bug 1012786: PK11_GenerateKeyPair can fail if there is insufficient
    242  // entropy to generate a random key. Attempting to add some entropy and
    243  // retrying appears to solve this issue.
    244  for (uint32_t retries = 0; retries < 10; retries++) {
    245    SECKEYPublicKey* publicKeyTemp = nullptr;
    246    ScopedSECKEYPrivateKey
    247      privateKey(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN,
    248                                      &params, &publicKeyTemp, false, true,
    249                                      nullptr));
    250    ScopedSECKEYPublicKey publicKey(publicKeyTemp);
    251    if (privateKey) {
    252      return CreateTestKeyPair(RSA_PKCS1(), publicKey, privateKey);
    253    }
    254 
    255    assert(!publicKeyTemp);
    256 
    257    if (PR_GetError() != SEC_ERROR_PKCS11_FUNCTION_FAILED) {
    258      break;
    259    }
    260 
    261    // Since these keys are only for testing, we don't need them to be good,
    262    // random keys.
    263    // https://xkcd.com/221/
    264    static const uint8_t RANDOM_NUMBER[] = { 4, 4, 4, 4, 4, 4, 4, 4 };
    265    if (PK11_RandomUpdate(
    266          const_cast<void*>(reinterpret_cast<const void*>(RANDOM_NUMBER)),
    267          sizeof(RANDOM_NUMBER)) != SECSuccess) {
    268      break;
    269    }
    270  }
    271 
    272  abort();
    273 }
    274 
    275 } // namespace
    276 
    277 TestKeyPair*
    278 GenerateKeyPair()
    279 {
    280  InitNSSIfNeeded();
    281  return GenerateKeyPairInner();
    282 }
    283 
    284 TestKeyPair*
    285 CloneReusedKeyPair()
    286 {
    287  static PRCallOnceType initCallOnce;
    288  if (PR_CallOnce(&initCallOnce, InitReusedKeyPair) != PR_SUCCESS) {
    289    abort();
    290  }
    291  assert(reusedKeyPair);
    292  return reusedKeyPair->Clone();
    293 }
    294 
    295 TestKeyPair*
    296 GenerateDSSKeyPair()
    297 {
    298  InitNSSIfNeeded();
    299 
    300  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
    301  if (!slot) {
    302    return nullptr;
    303  }
    304 
    305  ByteString p(DSS_P());
    306  ByteString q(DSS_Q());
    307  ByteString g(DSS_G());
    308 
    309  static const PQGParams PARAMS = {
    310    nullptr,
    311    { siBuffer,
    312      const_cast<uint8_t*>(p.data()),
    313      static_cast<unsigned int>(p.length())
    314    },
    315    { siBuffer,
    316      const_cast<uint8_t*>(q.data()),
    317      static_cast<unsigned int>(q.length())
    318    },
    319    { siBuffer,
    320      const_cast<uint8_t*>(g.data()),
    321      static_cast<unsigned int>(g.length())
    322    }
    323  };
    324 
    325  SECKEYPublicKey* publicKeyTemp = nullptr;
    326  ScopedSECKEYPrivateKey
    327    privateKey(PK11_GenerateKeyPair(slot.get(), CKM_DSA_KEY_PAIR_GEN,
    328                                    const_cast<PQGParams*>(&PARAMS),
    329                                    &publicKeyTemp, false, true, nullptr));
    330  if (!privateKey) {
    331    return nullptr;
    332  }
    333  ScopedSECKEYPublicKey publicKey(publicKeyTemp);
    334  return CreateTestKeyPair(DSS(), publicKey, privateKey);
    335 }
    336 
    337 Result
    338 TestVerifyECDSASignedData(Input data, DigestAlgorithm digestAlgorithm,
    339    Input signature, Input subjectPublicKeyInfo)
    340 {
    341  InitNSSIfNeeded();
    342  return VerifyECDSASignedDataNSS(data, digestAlgorithm, signature,
    343      subjectPublicKeyInfo, nullptr);
    344 }
    345 
    346 Result
    347 TestVerifyRSAPKCS1SignedData(Input data, DigestAlgorithm digestAlgorithm,
    348    Input signature, Input subjectPublicKeyInfo)
    349 {
    350  InitNSSIfNeeded();
    351  return VerifyRSAPKCS1SignedDataNSS(data, digestAlgorithm, signature,
    352      subjectPublicKeyInfo, nullptr);
    353 }
    354 
    355 Result
    356 TestVerifyRSAPSSSignedData(Input data, DigestAlgorithm digestAlgorithm,
    357    Input signature, Input subjectPublicKeyInfo)
    358 {
    359  InitNSSIfNeeded();
    360  return VerifyRSAPSSSignedDataNSS(data, digestAlgorithm, signature,
    361      subjectPublicKeyInfo, nullptr);
    362 }
    363 
    364 Result
    365 TestDigestBuf(Input item,
    366              DigestAlgorithm digestAlg,
    367              /*out*/ uint8_t* digestBuf,
    368              size_t digestBufLen)
    369 {
    370  InitNSSIfNeeded();
    371  return DigestBufNSS(item, digestAlg, digestBuf, digestBufLen);
    372 }
    373 
    374 } } } // namespace mozilla::pkix::test