tor-browser

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

pkixc_tests.cpp (7901B)


      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
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      4 */
      5 
      6 #include "pkixgtest.h"
      7 
      8 #include "mozpkix/pkixc.h"
      9 #include "mozpkix/pkixder.h"
     10 #include "mozpkix/pkixnss.h"
     11 #include "secerr.h"
     12 #include "sslerr.h"
     13 
     14 using namespace mozilla::pkix;
     15 using namespace mozilla::pkix::test;
     16 
     17 static ByteString CreateCert(
     18    const char* issuerCN, const char* subjectCN, EndEntityOrCA endEntityOrCA,
     19    /*optional*/ const ByteString* subjectAlternativeNameExtension = nullptr,
     20    /*optional*/ const ByteString* extendedKeyUsageExtension = nullptr) {
     21  EXPECT_TRUE(issuerCN);
     22  EXPECT_TRUE(subjectCN);
     23  static long serialNumberValue = 0;
     24  ++serialNumberValue;
     25  ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue));
     26  EXPECT_FALSE(ENCODING_FAILED(serialNumber));
     27 
     28  ByteString issuerDER(CNToDERName(issuerCN));
     29  ByteString subjectDER(CNToDERName(subjectCN));
     30 
     31  std::time_t notBefore = 1620000000;
     32  std::time_t notAfter = 1630000000;
     33 
     34  std::vector<ByteString> extensions;
     35  if (endEntityOrCA == EndEntityOrCA::MustBeCA) {
     36    ByteString basicConstraints =
     37        CreateEncodedBasicConstraints(true, nullptr, Critical::Yes);
     38    EXPECT_FALSE(ENCODING_FAILED(basicConstraints));
     39    extensions.push_back(basicConstraints);
     40  }
     41  if (subjectAlternativeNameExtension) {
     42    extensions.push_back(*subjectAlternativeNameExtension);
     43  }
     44  if (extendedKeyUsageExtension) {
     45    extensions.push_back(*extendedKeyUsageExtension);
     46  }
     47  extensions.push_back(ByteString());  // marks the end of the list
     48 
     49  ScopedTestKeyPair reusedKey(CloneReusedKeyPair());
     50  ByteString certDER(CreateEncodedCertificate(
     51      v3, sha256WithRSAEncryption(), serialNumber, issuerDER, notBefore,
     52      notAfter, subjectDER, *reusedKey, extensions.data(), *reusedKey,
     53      sha256WithRSAEncryption()));
     54  EXPECT_FALSE(ENCODING_FAILED(certDER));
     55 
     56  return certDER;
     57 }
     58 
     59 class pkixc_tests : public ::testing::Test {};
     60 
     61 TEST_F(pkixc_tests, Valid_VerifyCodeSigningCertificateChain) {
     62  ByteString root(CreateCert("CA", "CA", EndEntityOrCA::MustBeCA));
     63  ByteString intermediate(
     64      CreateCert("CA", "intermediate", EndEntityOrCA::MustBeCA));
     65  ByteString subjectAltNameExtension =
     66      CreateEncodedSubjectAltName(DNSName("example.com"));
     67  ByteString endEntity(CreateCert("intermediate", "end-entity",
     68                                  EndEntityOrCA::MustBeEndEntity,
     69                                  &subjectAltNameExtension));
     70  const uint8_t* certificates[] = {endEntity.data(), intermediate.data(),
     71                                   root.data()};
     72  const uint16_t certificateLengths[] = {
     73      static_cast<uint16_t>(endEntity.length()),
     74      static_cast<uint16_t>(intermediate.length()),
     75      static_cast<uint16_t>(root.length())};
     76  const size_t numCertificates = 3;
     77  const uint64_t secondsSinceEpoch = 1625000000;
     78  uint8_t rootSHA256Digest[32] = {0};
     79  Input rootInput;
     80  Result rv = rootInput.Init(root.data(), root.length());
     81  ASSERT_EQ(rv, Success);
     82  rv = DigestBufNSS(rootInput, DigestAlgorithm::sha256, rootSHA256Digest,
     83                    sizeof(rootSHA256Digest));
     84  ASSERT_EQ(rv, Success);
     85  const uint8_t hostname[] = {"example.com"};
     86  size_t hostnameLength = strlen("example.com");
     87  PRErrorCode error = 0;
     88  ASSERT_TRUE(VerifyCodeSigningCertificateChain(
     89      &certificates[0], &certificateLengths[0], numCertificates,
     90      secondsSinceEpoch, &rootSHA256Digest[0], &hostname[0], hostnameLength,
     91      &error));
     92 
     93  // If the extended key usage extension is present, it must have the code
     94  // signing usage.
     95  ByteString extendedKeyUsageExtension(
     96      CreateEKUExtension(BytesToByteString(tlv_id_kp_codeSigning)));
     97  ByteString endEntityWithEKU(
     98      CreateCert("intermediate", "end-entity", EndEntityOrCA::MustBeEndEntity,
     99                 &subjectAltNameExtension, &extendedKeyUsageExtension));
    100  const uint8_t* certificatesWithEKU[] = {endEntityWithEKU.data(),
    101                                          intermediate.data(), root.data()};
    102  const uint16_t certificateLengthsWithEKU[] = {
    103      static_cast<uint16_t>(endEntityWithEKU.length()),
    104      static_cast<uint16_t>(intermediate.length()),
    105      static_cast<uint16_t>(root.length())};
    106  ASSERT_TRUE(VerifyCodeSigningCertificateChain(
    107      &certificatesWithEKU[0], &certificateLengthsWithEKU[0], numCertificates,
    108      secondsSinceEpoch, &rootSHA256Digest[0], &hostname[0], hostnameLength,
    109      &error));
    110 }
    111 
    112 TEST_F(pkixc_tests, Invalid_VerifyCodeSigningCertificateChain) {
    113  ByteString root(CreateCert("CA", "CA", EndEntityOrCA::MustBeCA));
    114  ByteString subjectAltNameExtension =
    115      CreateEncodedSubjectAltName(DNSName("example.com"));
    116  ByteString endEntity(CreateCert("CA", "end-entity",
    117                                  EndEntityOrCA::MustBeEndEntity,
    118                                  &subjectAltNameExtension));
    119  const uint8_t* certificates[] = {endEntity.data(), root.data()};
    120  const uint16_t certificateLengths[] = {
    121      static_cast<uint16_t>(endEntity.length()),
    122      static_cast<uint16_t>(root.length())};
    123  const size_t numCertificates = 2;
    124  const uint64_t secondsSinceEpoch = 1625000000;
    125  uint8_t rootSHA256Digest[32] = {0};
    126  Input rootInput;
    127  Result rv = rootInput.Init(root.data(), root.length());
    128  ASSERT_EQ(rv, Success);
    129  rv = DigestBufNSS(rootInput, DigestAlgorithm::sha256, rootSHA256Digest,
    130                    sizeof(rootSHA256Digest));
    131  ASSERT_EQ(rv, Success);
    132  const uint8_t hostname[] = {"example.com"};
    133  size_t hostnameLength = strlen("example.com");
    134  PRErrorCode error = 0;
    135  // Consistency check first to ensure these tests are meaningful.
    136  ASSERT_TRUE(VerifyCodeSigningCertificateChain(
    137      &certificates[0], &certificateLengths[0], numCertificates,
    138      secondsSinceEpoch, &rootSHA256Digest[0], &hostname[0], hostnameLength,
    139      &error));
    140  ASSERT_EQ(error, 0);
    141 
    142  // Test with "now" after the certificates have expired.
    143  ASSERT_FALSE(VerifyCodeSigningCertificateChain(
    144      &certificates[0], &certificateLengths[0], numCertificates,
    145      secondsSinceEpoch + 10000000, &rootSHA256Digest[0], &hostname[0],
    146      hostnameLength, &error));
    147  ASSERT_EQ(error, SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
    148 
    149  // Test with a different root digest.
    150  uint8_t wrongRootSHA256Digest[32] = {1};
    151  ASSERT_FALSE(VerifyCodeSigningCertificateChain(
    152      &certificates[0], &certificateLengths[0], numCertificates,
    153      secondsSinceEpoch, &wrongRootSHA256Digest[0], &hostname[0],
    154      hostnameLength, &error));
    155  ASSERT_EQ(error, SEC_ERROR_UNKNOWN_ISSUER);
    156 
    157  // Test with a different host name.
    158  const uint8_t wrongHostname[] = "example.org";
    159  size_t wrongHostnameLength = strlen("example.org");
    160  ASSERT_FALSE(VerifyCodeSigningCertificateChain(
    161      &certificates[0], &certificateLengths[0], numCertificates,
    162      secondsSinceEpoch, &rootSHA256Digest[0], &wrongHostname[0],
    163      wrongHostnameLength, &error));
    164  ASSERT_EQ(error, SSL_ERROR_BAD_CERT_DOMAIN);
    165 
    166  // Test with a certificate with an extended key usage that doesn't include
    167  // code signing.
    168  ByteString extendedKeyUsageExtension(
    169      CreateEKUExtension(BytesToByteString(tlv_id_kp_clientAuth)));
    170  ByteString endEntityWithEKU(
    171      CreateCert("CA", "end-entity", EndEntityOrCA::MustBeEndEntity,
    172                 &subjectAltNameExtension, &extendedKeyUsageExtension));
    173  const uint8_t* certificatesWithEKU[] = {endEntityWithEKU.data(), root.data()};
    174  const uint16_t certificateLengthsWithEKU[] = {
    175      static_cast<uint16_t>(endEntityWithEKU.length()),
    176      static_cast<uint16_t>(root.length())};
    177  ASSERT_FALSE(VerifyCodeSigningCertificateChain(
    178      &certificatesWithEKU[0], &certificateLengthsWithEKU[0], numCertificates,
    179      secondsSinceEpoch, &rootSHA256Digest[0], &hostname[0], hostnameLength,
    180      &error));
    181  ASSERT_EQ(error, SEC_ERROR_INADEQUATE_CERT_TYPE);
    182 }