tor-browser

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

pkixbuild_tests.cpp (32871B)


      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 #if defined(_MSC_VER) && _MSC_VER < 1900
     26 // When building with -D_HAS_EXCEPTIONS=0, MSVC's <xtree> header triggers
     27 // warning C4702: unreachable code.
     28 // https://connect.microsoft.com/VisualStudio/feedback/details/809962
     29 #pragma warning(push)
     30 #pragma warning(disable: 4702)
     31 #endif
     32 
     33 #include <map>
     34 #include <vector>
     35 
     36 #if defined(_MSC_VER) && _MSC_VER < 1900
     37 #pragma warning(pop)
     38 #endif
     39 
     40 #include "pkixgtest.h"
     41 
     42 #include "mozpkix/pkixder.h"
     43 
     44 using namespace mozilla::pkix;
     45 using namespace mozilla::pkix::test;
     46 
     47 static ByteString
     48 CreateCert(const char* issuerCN, // null means "empty name"
     49           const char* subjectCN, // null means "empty name"
     50           EndEntityOrCA endEntityOrCA,
     51           /*optional modified*/ std::map<ByteString, ByteString>*
     52             subjectDERToCertDER = nullptr,
     53           /*optional*/ const ByteString* extension = nullptr,
     54           /*optional*/ const TestKeyPair* issuerKeyPair = nullptr,
     55           /*optional*/ const TestKeyPair* subjectKeyPair = nullptr)
     56 {
     57  static long serialNumberValue = 0;
     58  ++serialNumberValue;
     59  ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue));
     60  EXPECT_FALSE(ENCODING_FAILED(serialNumber));
     61 
     62  ByteString issuerDER(issuerCN ? CNToDERName(issuerCN) : Name(ByteString()));
     63  ByteString subjectDER(subjectCN ? CNToDERName(subjectCN) : Name(ByteString()));
     64 
     65  std::vector<ByteString> extensions;
     66  if (endEntityOrCA == EndEntityOrCA::MustBeCA) {
     67    ByteString basicConstraints =
     68      CreateEncodedBasicConstraints(true, nullptr, Critical::Yes);
     69    EXPECT_FALSE(ENCODING_FAILED(basicConstraints));
     70    extensions.push_back(basicConstraints);
     71  }
     72  if (extension) {
     73    extensions.push_back(*extension);
     74  }
     75  extensions.push_back(ByteString()); // marks the end of the list
     76 
     77  ScopedTestKeyPair reusedKey(CloneReusedKeyPair());
     78  ByteString certDER(CreateEncodedCertificate(
     79                       v3, sha256WithRSAEncryption(), serialNumber, issuerDER,
     80                       oneDayBeforeNow, oneDayAfterNow, subjectDER,
     81                       subjectKeyPair ? *subjectKeyPair : *reusedKey,
     82                       extensions.data(),
     83                       issuerKeyPair ? *issuerKeyPair : *reusedKey,
     84                       sha256WithRSAEncryption()));
     85  EXPECT_FALSE(ENCODING_FAILED(certDER));
     86 
     87  if (subjectDERToCertDER) {
     88    (*subjectDERToCertDER)[subjectDER] = certDER;
     89  }
     90 
     91  return certDER;
     92 }
     93 
     94 class TestTrustDomain final : public DefaultCryptoTrustDomain
     95 {
     96 public:
     97  // The "cert chain tail" is a longish chain of certificates that is used by
     98  // all of the tests here. We share this chain across all the tests in order
     99  // to speed up the tests (generating keypairs for the certs is very slow).
    100  bool SetUpCertChainTail()
    101  {
    102    static char const* const names[] = {
    103        "CA1 (Root)", "CA2", "CA3", "CA4", "CA5", "CA6", "CA7"
    104    };
    105 
    106    for (size_t i = 0; i < MOZILLA_PKIX_ARRAY_LENGTH(names); ++i) {
    107      const char* issuerName = i == 0 ? names[0] : names[i-1];
    108      CreateCACert(issuerName, names[i]);
    109      if (i == 0) {
    110        rootCACertDER = leafCACertDER;
    111      }
    112    }
    113 
    114    return true;
    115  }
    116 
    117  void CreateCACert(const char* issuerName, const char* subjectName)
    118  {
    119    leafCACertDER = CreateCert(issuerName, subjectName,
    120                               EndEntityOrCA::MustBeCA, &subjectDERToCertDER);
    121    assert(!ENCODING_FAILED(leafCACertDER));
    122  }
    123 
    124  ByteString GetLeafCACertDER() const { return leafCACertDER; }
    125 
    126 private:
    127  Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input candidateCert,
    128                      /*out*/ TrustLevel& trustLevel) override
    129  {
    130    trustLevel = InputEqualsByteString(candidateCert, rootCACertDER)
    131               ? TrustLevel::TrustAnchor
    132               : TrustLevel::InheritsTrust;
    133    return Success;
    134  }
    135 
    136  Result FindIssuer(Input encodedIssuerName, IssuerChecker& checker, Time)
    137                    override
    138  {
    139    ByteString subjectDER(InputToByteString(encodedIssuerName));
    140    ByteString certDER(subjectDERToCertDER[subjectDER]);
    141    Input derCert;
    142    Result rv = derCert.Init(certDER.data(), certDER.length());
    143    if (rv != Success) {
    144      return rv;
    145    }
    146    bool keepGoing;
    147    rv = checker.Check(derCert, nullptr/*additionalNameConstraints*/,
    148                       keepGoing);
    149    if (rv != Success) {
    150      return rv;
    151    }
    152    return Success;
    153  }
    154 
    155  Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
    156                         /*optional*/ const Input*, /*optional*/ const Input*)
    157                         override
    158  {
    159    return Success;
    160  }
    161 
    162  Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
    163  {
    164    return Success;
    165  }
    166 
    167  std::map<ByteString, ByteString> subjectDERToCertDER;
    168  ByteString leafCACertDER;
    169  ByteString rootCACertDER;
    170 };
    171 
    172 class pkixbuild : public ::testing::Test
    173 {
    174 public:
    175  static void SetUpTestSuite()
    176  {
    177    if (!trustDomain.SetUpCertChainTail()) {
    178      abort();
    179    }
    180  }
    181 
    182 protected:
    183 
    184  static TestTrustDomain trustDomain;
    185 };
    186 
    187 /*static*/ TestTrustDomain pkixbuild::trustDomain;
    188 
    189 TEST_F(pkixbuild, MaxAcceptableCertChainLength)
    190 {
    191  {
    192    ByteString leafCACert(trustDomain.GetLeafCACertDER());
    193    Input certDER;
    194    ASSERT_EQ(Success, certDER.Init(leafCACert.data(), leafCACert.length()));
    195    ASSERT_EQ(Success,
    196              BuildCertChain(trustDomain, certDER, Now(),
    197                             EndEntityOrCA::MustBeCA,
    198                             KeyUsage::noParticularKeyUsageRequired,
    199                             KeyPurposeId::id_kp_serverAuth,
    200                             CertPolicyId::anyPolicy,
    201                             nullptr/*stapledOCSPResponse*/));
    202  }
    203 
    204  {
    205    ByteString certDER(CreateCert("CA7", "Direct End-Entity",
    206                                  EndEntityOrCA::MustBeEndEntity));
    207    ASSERT_FALSE(ENCODING_FAILED(certDER));
    208    Input certDERInput;
    209    ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
    210    ASSERT_EQ(Success,
    211              BuildCertChain(trustDomain, certDERInput, Now(),
    212                             EndEntityOrCA::MustBeEndEntity,
    213                             KeyUsage::noParticularKeyUsageRequired,
    214                             KeyPurposeId::id_kp_serverAuth,
    215                             CertPolicyId::anyPolicy,
    216                             nullptr/*stapledOCSPResponse*/));
    217  }
    218 }
    219 
    220 TEST_F(pkixbuild, BeyondMaxAcceptableCertChainLength)
    221 {
    222  static char const* const caCertName = "CA Too Far";
    223 
    224  trustDomain.CreateCACert("CA7", caCertName);
    225 
    226  {
    227    ByteString certDER(trustDomain.GetLeafCACertDER());
    228    Input certDERInput;
    229    ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
    230    ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
    231              BuildCertChain(trustDomain, certDERInput, Now(),
    232                             EndEntityOrCA::MustBeCA,
    233                             KeyUsage::noParticularKeyUsageRequired,
    234                             KeyPurposeId::id_kp_serverAuth,
    235                             CertPolicyId::anyPolicy,
    236                             nullptr/*stapledOCSPResponse*/));
    237  }
    238 
    239  {
    240    ByteString certDER(CreateCert(caCertName, "End-Entity Too Far",
    241                                  EndEntityOrCA::MustBeEndEntity));
    242    ASSERT_FALSE(ENCODING_FAILED(certDER));
    243    Input certDERInput;
    244    ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
    245    ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
    246              BuildCertChain(trustDomain, certDERInput, Now(),
    247                             EndEntityOrCA::MustBeEndEntity,
    248                             KeyUsage::noParticularKeyUsageRequired,
    249                             KeyPurposeId::id_kp_serverAuth,
    250                             CertPolicyId::anyPolicy,
    251                             nullptr/*stapledOCSPResponse*/));
    252  }
    253 }
    254 
    255 // A TrustDomain that checks certificates against a given root certificate.
    256 // It is initialized with the DER encoding of a root certificate that
    257 // is treated as a trust anchor and is assumed to have issued all certificates
    258 // (i.e. FindIssuer always attempts to build the next step in the chain with
    259 // it).
    260 class SingleRootTrustDomain : public DefaultCryptoTrustDomain
    261 {
    262 public:
    263  explicit SingleRootTrustDomain(ByteString aRootDER)
    264    : rootDER(aRootDER)
    265  {
    266  }
    267 
    268  // The CertPolicyId argument is unused because we don't care about EV.
    269  Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input candidateCert,
    270                      /*out*/ TrustLevel& trustLevel) override
    271  {
    272    Input rootCert;
    273    Result rv = rootCert.Init(rootDER.data(), rootDER.length());
    274    if (rv != Success) {
    275      return rv;
    276    }
    277    if (InputsAreEqual(candidateCert, rootCert)) {
    278      trustLevel = TrustLevel::TrustAnchor;
    279    } else {
    280      trustLevel = TrustLevel::InheritsTrust;
    281    }
    282    return Success;
    283  }
    284 
    285  Result FindIssuer(Input, IssuerChecker& checker, Time) override
    286  {
    287    // keepGoing is an out parameter from IssuerChecker.Check. It would tell us
    288    // whether or not to continue attempting other potential issuers. We only
    289    // know of one potential issuer, however, so we ignore it.
    290    bool keepGoing;
    291    Input rootCert;
    292    Result rv = rootCert.Init(rootDER.data(), rootDER.length());
    293    if (rv != Success) {
    294      return rv;
    295    }
    296    return checker.Check(rootCert, nullptr, keepGoing);
    297  }
    298 
    299  Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
    300  {
    301    return Success;
    302  }
    303 
    304  Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
    305                         /*optional*/ const Input*, /*optional*/ const Input*)
    306                         override
    307  {
    308    return Success;
    309  }
    310 
    311 private:
    312  ByteString rootDER;
    313 };
    314 
    315 // A TrustDomain that explicitly fails if CheckRevocation is called.
    316 class ExpiredCertTrustDomain final : public SingleRootTrustDomain
    317 {
    318 public:
    319  explicit ExpiredCertTrustDomain(ByteString aRootDER)
    320    : SingleRootTrustDomain(aRootDER)
    321  {
    322  }
    323 
    324  Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
    325                         /*optional*/ const Input*, /*optional*/ const Input*)
    326                         override
    327  {
    328    ADD_FAILURE();
    329    return NotReached("CheckRevocation should not be called",
    330                      Result::FATAL_ERROR_LIBRARY_FAILURE);
    331  }
    332 };
    333 
    334 TEST_F(pkixbuild, NoRevocationCheckingForExpiredCert)
    335 {
    336  const char* rootCN = "Root CA";
    337  ByteString rootDER(CreateCert(rootCN, rootCN, EndEntityOrCA::MustBeCA,
    338                                nullptr));
    339  EXPECT_FALSE(ENCODING_FAILED(rootDER));
    340  ExpiredCertTrustDomain expiredCertTrustDomain(rootDER);
    341 
    342  ByteString serialNumber(CreateEncodedSerialNumber(100));
    343  EXPECT_FALSE(ENCODING_FAILED(serialNumber));
    344  ByteString issuerDER(CNToDERName(rootCN));
    345  ByteString subjectDER(CNToDERName("Expired End-Entity Cert"));
    346  ScopedTestKeyPair reusedKey(CloneReusedKeyPair());
    347  ByteString certDER(CreateEncodedCertificate(
    348                       v3, sha256WithRSAEncryption(),
    349                       serialNumber, issuerDER,
    350                       twoDaysBeforeNow,
    351                       oneDayBeforeNow,
    352                       subjectDER, *reusedKey, nullptr, *reusedKey,
    353                       sha256WithRSAEncryption()));
    354  EXPECT_FALSE(ENCODING_FAILED(certDER));
    355 
    356  Input cert;
    357  ASSERT_EQ(Success, cert.Init(certDER.data(), certDER.length()));
    358  ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE,
    359            BuildCertChain(expiredCertTrustDomain, cert, Now(),
    360                           EndEntityOrCA::MustBeEndEntity,
    361                           KeyUsage::noParticularKeyUsageRequired,
    362                           KeyPurposeId::id_kp_serverAuth,
    363                           CertPolicyId::anyPolicy,
    364                           nullptr));
    365 }
    366 
    367 class DSSTrustDomain final : public EverythingFailsByDefaultTrustDomain
    368 {
    369 public:
    370  Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
    371                      Input, /*out*/ TrustLevel& trustLevel) override
    372  {
    373    trustLevel = TrustLevel::TrustAnchor;
    374    return Success;
    375  }
    376 };
    377 
    378 class pkixbuild_DSS : public ::testing::Test { };
    379 
    380 TEST_F(pkixbuild_DSS, DSSEndEntityKeyNotAccepted)
    381 {
    382  DSSTrustDomain trustDomain;
    383 
    384  ByteString serialNumber(CreateEncodedSerialNumber(1));
    385  ASSERT_FALSE(ENCODING_FAILED(serialNumber));
    386 
    387  ByteString subjectDER(CNToDERName("DSS"));
    388  ASSERT_FALSE(ENCODING_FAILED(subjectDER));
    389  ScopedTestKeyPair subjectKey(GenerateDSSKeyPair());
    390  ASSERT_TRUE(subjectKey.get());
    391 
    392  ByteString issuerDER(CNToDERName("RSA"));
    393  ASSERT_FALSE(ENCODING_FAILED(issuerDER));
    394  ScopedTestKeyPair issuerKey(CloneReusedKeyPair());
    395  ASSERT_TRUE(issuerKey.get());
    396 
    397  ByteString cert(CreateEncodedCertificate(v3, sha256WithRSAEncryption(),
    398                                           serialNumber, issuerDER,
    399                                           oneDayBeforeNow, oneDayAfterNow,
    400                                           subjectDER, *subjectKey, nullptr,
    401                                           *issuerKey, sha256WithRSAEncryption()));
    402  ASSERT_FALSE(ENCODING_FAILED(cert));
    403  Input certDER;
    404  ASSERT_EQ(Success, certDER.Init(cert.data(), cert.length()));
    405 
    406  ASSERT_EQ(Result::ERROR_UNSUPPORTED_KEYALG,
    407            BuildCertChain(trustDomain, certDER, Now(),
    408                           EndEntityOrCA::MustBeEndEntity,
    409                           KeyUsage::noParticularKeyUsageRequired,
    410                           KeyPurposeId::id_kp_serverAuth,
    411                           CertPolicyId::anyPolicy,
    412                           nullptr/*stapledOCSPResponse*/));
    413 }
    414 
    415 class IssuerNameCheckTrustDomain final : public DefaultCryptoTrustDomain
    416 {
    417 public:
    418  IssuerNameCheckTrustDomain(const ByteString& aIssuer, bool aExpectedKeepGoing)
    419    : issuer(aIssuer)
    420    , expectedKeepGoing(aExpectedKeepGoing)
    421  {
    422  }
    423 
    424  Result GetCertTrust(EndEntityOrCA endEntityOrCA, const CertPolicyId&, Input,
    425                      /*out*/ TrustLevel& trustLevel) override
    426  {
    427    trustLevel = endEntityOrCA == EndEntityOrCA::MustBeCA
    428               ? TrustLevel::TrustAnchor
    429               : TrustLevel::InheritsTrust;
    430    return Success;
    431  }
    432 
    433  Result FindIssuer(Input, IssuerChecker& checker, Time) override
    434  {
    435    Input issuerInput;
    436    EXPECT_EQ(Success, issuerInput.Init(issuer.data(), issuer.length()));
    437    bool keepGoing;
    438    EXPECT_EQ(Success,
    439              checker.Check(issuerInput, nullptr /*additionalNameConstraints*/,
    440                            keepGoing));
    441    EXPECT_EQ(expectedKeepGoing, keepGoing);
    442    return Success;
    443  }
    444 
    445  Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
    446                         /*optional*/ const Input*, /*optional*/ const Input*)
    447                         override
    448  {
    449    return Success;
    450  }
    451 
    452  Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
    453  {
    454    return Success;
    455  }
    456 
    457 private:
    458  const ByteString issuer;
    459  const bool expectedKeepGoing;
    460 };
    461 
    462 struct IssuerNameCheckParams
    463 {
    464  const char* subjectIssuerCN; // null means "empty name"
    465  const char* issuerSubjectCN; // null means "empty name"
    466  bool matches;
    467  Result expectedError;
    468 };
    469 
    470 static const IssuerNameCheckParams ISSUER_NAME_CHECK_PARAMS[] =
    471 {
    472  { "foo", "foo", true, Success },
    473  { "foo", "bar", false, Result::ERROR_UNKNOWN_ISSUER },
    474  { "f", "foo", false, Result::ERROR_UNKNOWN_ISSUER }, // prefix
    475  { "foo", "f", false, Result::ERROR_UNKNOWN_ISSUER }, // prefix
    476  { "foo", "Foo", false, Result::ERROR_UNKNOWN_ISSUER }, // case sensitive
    477  { "", "", true, Success },
    478  { nullptr, nullptr, false, Result::ERROR_EMPTY_ISSUER_NAME }, // empty issuer
    479 
    480  // check that certificate-related errors are deferred and superseded by
    481  // ERROR_UNKNOWN_ISSUER when a chain can't be built due to name mismatches
    482  { "foo", nullptr, false, Result::ERROR_UNKNOWN_ISSUER },
    483  { nullptr, "foo", false, Result::ERROR_UNKNOWN_ISSUER }
    484 };
    485 
    486 class pkixbuild_IssuerNameCheck
    487  : public ::testing::Test
    488  , public ::testing::WithParamInterface<IssuerNameCheckParams>
    489 {
    490 };
    491 
    492 TEST_P(pkixbuild_IssuerNameCheck, MatchingName)
    493 {
    494  const IssuerNameCheckParams& params(GetParam());
    495 
    496  ByteString issuerCertDER(CreateCert(params.issuerSubjectCN,
    497                                      params.issuerSubjectCN,
    498                                      EndEntityOrCA::MustBeCA, nullptr));
    499  ASSERT_FALSE(ENCODING_FAILED(issuerCertDER));
    500 
    501  ByteString subjectCertDER(CreateCert(params.subjectIssuerCN, "end-entity",
    502                                       EndEntityOrCA::MustBeEndEntity,
    503                                       nullptr));
    504  ASSERT_FALSE(ENCODING_FAILED(subjectCertDER));
    505 
    506  Input subjectCertDERInput;
    507  ASSERT_EQ(Success, subjectCertDERInput.Init(subjectCertDER.data(),
    508                                              subjectCertDER.length()));
    509 
    510  IssuerNameCheckTrustDomain trustDomain(issuerCertDER, !params.matches);
    511  ASSERT_EQ(params.expectedError,
    512            BuildCertChain(trustDomain, subjectCertDERInput, Now(),
    513                           EndEntityOrCA::MustBeEndEntity,
    514                           KeyUsage::noParticularKeyUsageRequired,
    515                           KeyPurposeId::id_kp_serverAuth,
    516                           CertPolicyId::anyPolicy,
    517                           nullptr/*stapledOCSPResponse*/));
    518 }
    519 
    520 INSTANTIATE_TEST_SUITE_P(pkixbuild_IssuerNameCheck, pkixbuild_IssuerNameCheck,
    521                        testing::ValuesIn(ISSUER_NAME_CHECK_PARAMS));
    522 
    523 
    524 // Records the embedded SCT list extension for later examination.
    525 class EmbeddedSCTListTestTrustDomain final : public SingleRootTrustDomain
    526 {
    527 public:
    528  explicit EmbeddedSCTListTestTrustDomain(ByteString aRootDER)
    529    : SingleRootTrustDomain(aRootDER)
    530  {
    531  }
    532 
    533  virtual void NoteAuxiliaryExtension(AuxiliaryExtension extension,
    534                                      Input extensionData) override
    535  {
    536    if (extension == AuxiliaryExtension::EmbeddedSCTList) {
    537      signedCertificateTimestamps = InputToByteString(extensionData);
    538    } else {
    539      ADD_FAILURE();
    540    }
    541  }
    542 
    543  ByteString signedCertificateTimestamps;
    544 };
    545 
    546 TEST_F(pkixbuild, CertificateTransparencyExtension)
    547 {
    548  // python security/pkix/tools/DottedOIDToCode.py --tlv
    549  //   id-embeddedSctList 1.3.6.1.4.1.11129.2.4.2
    550  static const uint8_t tlv_id_embeddedSctList[] = {
    551    0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x02
    552  };
    553  static const uint8_t dummySctList[] = {
    554    0x01, 0x02, 0x03, 0x04, 0x05
    555  };
    556 
    557  ByteString ctExtension = TLV(der::SEQUENCE,
    558    BytesToByteString(tlv_id_embeddedSctList) +
    559    Boolean(false) +
    560    TLV(der::OCTET_STRING,
    561      // SignedCertificateTimestampList structure is encoded as an OCTET STRING
    562      // within the X.509v3 extension (see RFC 6962 section 3.3).
    563      // pkix decodes it internally and returns the actual structure.
    564      TLV(der::OCTET_STRING, BytesToByteString(dummySctList))));
    565 
    566  const char* rootCN = "Root CA";
    567  ByteString rootDER(CreateCert(rootCN, rootCN, EndEntityOrCA::MustBeCA));
    568  ASSERT_FALSE(ENCODING_FAILED(rootDER));
    569 
    570  ByteString certDER(CreateCert(rootCN, "Cert with SCT list",
    571                                EndEntityOrCA::MustBeEndEntity,
    572                                nullptr, /*subjectDERToCertDER*/
    573                                &ctExtension));
    574  ASSERT_FALSE(ENCODING_FAILED(certDER));
    575 
    576  Input certInput;
    577  ASSERT_EQ(Success, certInput.Init(certDER.data(), certDER.length()));
    578 
    579  EmbeddedSCTListTestTrustDomain extTrustDomain(rootDER);
    580  ASSERT_EQ(Success,
    581            BuildCertChain(extTrustDomain, certInput, Now(),
    582                           EndEntityOrCA::MustBeEndEntity,
    583                           KeyUsage::noParticularKeyUsageRequired,
    584                           KeyPurposeId::anyExtendedKeyUsage,
    585                           CertPolicyId::anyPolicy,
    586                           nullptr /*stapledOCSPResponse*/));
    587  ASSERT_EQ(BytesToByteString(dummySctList),
    588            extTrustDomain.signedCertificateTimestamps);
    589 }
    590 
    591 // This TrustDomain implements a hierarchy like so:
    592 //
    593 // A   B
    594 // |   |
    595 // C   D
    596 //  \ /
    597 //   E
    598 //
    599 // where A is a trust anchor, B is not a trust anchor and has no known issuer, C
    600 // and D are intermediates with the same subject and subject public key, and E
    601 // is an end-entity (in practice, the end-entity will be generated by the test
    602 // functions using this trust domain).
    603 class MultiplePathTrustDomain: public DefaultCryptoTrustDomain
    604 {
    605 public:
    606  void SetUpCerts()
    607  {
    608    ASSERT_FALSE(ENCODING_FAILED(CreateCert("UntrustedRoot", "UntrustedRoot",
    609                                            EndEntityOrCA::MustBeCA,
    610                                            &subjectDERToCertDER)));
    611    // The subject DER -> cert DER mapping would be overwritten for subject
    612    // "Intermediate" when we create the second "Intermediate" certificate, so
    613    // we keep a copy of this "Intermediate".
    614    intermediateSignedByUntrustedRootCertDER =
    615      CreateCert("UntrustedRoot", "Intermediate", EndEntityOrCA::MustBeCA);
    616    ASSERT_FALSE(ENCODING_FAILED(intermediateSignedByUntrustedRootCertDER));
    617    rootCACertDER = CreateCert("TrustedRoot", "TrustedRoot",
    618                               EndEntityOrCA::MustBeCA, &subjectDERToCertDER);
    619    ASSERT_FALSE(ENCODING_FAILED(rootCACertDER));
    620    ASSERT_FALSE(ENCODING_FAILED(CreateCert("TrustedRoot", "Intermediate",
    621                                            EndEntityOrCA::MustBeCA,
    622                                            &subjectDERToCertDER)));
    623  }
    624 
    625 private:
    626  Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input candidateCert,
    627                      /*out*/ TrustLevel& trustLevel) override
    628  {
    629    trustLevel = InputEqualsByteString(candidateCert, rootCACertDER)
    630               ? TrustLevel::TrustAnchor
    631               : TrustLevel::InheritsTrust;
    632    return Success;
    633  }
    634 
    635  Result CheckCert(ByteString& certDER, IssuerChecker& checker, bool& keepGoing)
    636  {
    637    Input derCert;
    638    Result rv = derCert.Init(certDER.data(), certDER.length());
    639    if (rv != Success) {
    640      return rv;
    641    }
    642    return checker.Check(derCert, nullptr/*additionalNameConstraints*/,
    643                         keepGoing);
    644  }
    645 
    646  Result FindIssuer(Input encodedIssuerName, IssuerChecker& checker, Time)
    647                    override
    648  {
    649    ByteString subjectDER(InputToByteString(encodedIssuerName));
    650    ByteString certDER(subjectDERToCertDER[subjectDER]);
    651    assert(!ENCODING_FAILED(certDER));
    652    bool keepGoing;
    653    Result rv = CheckCert(certDER, checker, keepGoing);
    654    if (rv != Success) {
    655      return rv;
    656    }
    657    // Also try the other intermediate.
    658    if (keepGoing) {
    659      rv = CheckCert(intermediateSignedByUntrustedRootCertDER, checker,
    660                     keepGoing);
    661      if (rv != Success) {
    662        return rv;
    663      }
    664    }
    665    return Success;
    666  }
    667 
    668  Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
    669                         /*optional*/ const Input*,
    670                         /*optional*/ const Input*) override
    671  {
    672    return Success;
    673  }
    674 
    675  Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
    676  {
    677    return Success;
    678  }
    679 
    680  std::map<ByteString, ByteString> subjectDERToCertDER;
    681  ByteString rootCACertDER;
    682  ByteString intermediateSignedByUntrustedRootCertDER;
    683 };
    684 
    685 TEST_F(pkixbuild, BadEmbeddedSCTWithMultiplePaths)
    686 {
    687  MultiplePathTrustDomain localTrustDomain;
    688  localTrustDomain.SetUpCerts();
    689 
    690  // python security/pkix/tools/DottedOIDToCode.py --tlv
    691  //   id-embeddedSctList 1.3.6.1.4.1.11129.2.4.2
    692  static const uint8_t tlv_id_embeddedSctList[] = {
    693    0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x02
    694  };
    695  static const uint8_t dummySctList[] = {
    696    0x01, 0x02, 0x03, 0x04, 0x05
    697  };
    698  ByteString ctExtension = TLV(der::SEQUENCE,
    699    BytesToByteString(tlv_id_embeddedSctList) +
    700    Boolean(false) +
    701    // The contents of the OCTET STRING are supposed to consist of an OCTET
    702    // STRING of useful data. We're testing what happens if it isn't, so shove
    703    // some bogus (non-OCTET STRING) data in there.
    704    TLV(der::OCTET_STRING, BytesToByteString(dummySctList)));
    705  ByteString certDER(CreateCert("Intermediate", "Cert with bogus SCT list",
    706                                EndEntityOrCA::MustBeEndEntity,
    707                                nullptr, /*subjectDERToCertDER*/
    708                                &ctExtension));
    709  ASSERT_FALSE(ENCODING_FAILED(certDER));
    710  Input certDERInput;
    711  ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
    712  ASSERT_EQ(Result::ERROR_BAD_DER,
    713            BuildCertChain(localTrustDomain, certDERInput, Now(),
    714                           EndEntityOrCA::MustBeEndEntity,
    715                           KeyUsage::noParticularKeyUsageRequired,
    716                           KeyPurposeId::id_kp_serverAuth,
    717                           CertPolicyId::anyPolicy,
    718                           nullptr/*stapledOCSPResponse*/));
    719 }
    720 
    721 // Same as a MultiplePathTrustDomain, but the end-entity is revoked.
    722 class RevokedEndEntityTrustDomain final : public MultiplePathTrustDomain
    723 {
    724 public:
    725  Result CheckRevocation(EndEntityOrCA endEntityOrCA, const CertID&, Time,
    726                         Duration, /*optional*/ const Input*,
    727                         /*optional*/ const Input*) override
    728  {
    729    if (endEntityOrCA == EndEntityOrCA::MustBeEndEntity) {
    730      return Result::ERROR_REVOKED_CERTIFICATE;
    731    }
    732    return Success;
    733  }
    734 };
    735 
    736 TEST_F(pkixbuild, RevokedEndEntityWithMultiplePaths)
    737 {
    738  RevokedEndEntityTrustDomain localTrustDomain;
    739  localTrustDomain.SetUpCerts();
    740  ByteString certDER(CreateCert("Intermediate", "RevokedEndEntity",
    741                                EndEntityOrCA::MustBeEndEntity));
    742  ASSERT_FALSE(ENCODING_FAILED(certDER));
    743  Input certDERInput;
    744  ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
    745  ASSERT_EQ(Result::ERROR_REVOKED_CERTIFICATE,
    746            BuildCertChain(localTrustDomain, certDERInput, Now(),
    747                           EndEntityOrCA::MustBeEndEntity,
    748                           KeyUsage::noParticularKeyUsageRequired,
    749                           KeyPurposeId::id_kp_serverAuth,
    750                           CertPolicyId::anyPolicy,
    751                           nullptr/*stapledOCSPResponse*/));
    752 }
    753 
    754 // This represents a collection of different certificates that all have the same
    755 // subject and issuer distinguished name.
    756 class SelfIssuedCertificatesTrustDomain final : public DefaultCryptoTrustDomain
    757 {
    758 public:
    759  void SetUpCerts(size_t totalCerts)
    760  {
    761    ASSERT_TRUE(totalCerts > 0);
    762    // First we generate a trust anchor.
    763    ScopedTestKeyPair rootKeyPair(GenerateKeyPair());
    764    rootCACertDER = CreateCert("DN", "DN", EndEntityOrCA::MustBeCA, nullptr,
    765                               nullptr, rootKeyPair.get(), rootKeyPair.get());
    766    ASSERT_FALSE(ENCODING_FAILED(rootCACertDER));
    767    certs.push_back(rootCACertDER);
    768    ScopedTestKeyPair issuerKeyPair(rootKeyPair.release());
    769    size_t subCAsGenerated;
    770    // Then we generate 6 sub-CAs (given that we were requested to generate at
    771    // least that many).
    772    for (subCAsGenerated = 0;
    773         subCAsGenerated < totalCerts - 1 && subCAsGenerated < 6;
    774         subCAsGenerated++) {
    775      // Each certificate has to have a unique SPKI (mozilla::pkix does loop
    776      // detection and stops searching if it encounters two certificates in a
    777      // path with the same subject and SPKI).
    778      ScopedTestKeyPair keyPair(GenerateKeyPair());
    779      ByteString cert(CreateCert("DN", "DN", EndEntityOrCA::MustBeCA, nullptr,
    780                                 nullptr, issuerKeyPair.get(), keyPair.get()));
    781      ASSERT_FALSE(ENCODING_FAILED(cert));
    782      certs.push_back(cert);
    783      issuerKeyPair.reset(keyPair.release());
    784    }
    785    // We set firstIssuerKey here because we can't end up with a path that has
    786    // more than 7 CAs in it (because mozilla::pkix limits the path length).
    787    firstIssuerKey.reset(issuerKeyPair.release());
    788    // For any more sub CAs we generate, it doesn't matter what their keys are
    789    // as long as they're different.
    790    for (; subCAsGenerated < totalCerts - 1; subCAsGenerated++) {
    791      ScopedTestKeyPair keyPair(GenerateKeyPair());
    792      ByteString cert(CreateCert("DN", "DN", EndEntityOrCA::MustBeCA, nullptr,
    793                                 nullptr, keyPair.get(), keyPair.get()));
    794      ASSERT_FALSE(ENCODING_FAILED(cert));
    795      certs.insert(certs.begin(), cert);
    796    }
    797  }
    798 
    799  const TestKeyPair* GetFirstIssuerKey()
    800  {
    801    return firstIssuerKey.get();
    802  }
    803 
    804 private:
    805  Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input candidateCert,
    806                      /*out*/ TrustLevel& trustLevel) override
    807  {
    808    trustLevel = InputEqualsByteString(candidateCert, rootCACertDER)
    809               ? TrustLevel::TrustAnchor
    810               : TrustLevel::InheritsTrust;
    811    return Success;
    812  }
    813 
    814  Result FindIssuer(Input, IssuerChecker& checker, Time) override
    815  {
    816    bool keepGoing;
    817    for (auto& cert: certs) {
    818      Input certInput;
    819      Result rv = certInput.Init(cert.data(), cert.length());
    820      if (rv != Success) {
    821        return rv;
    822      }
    823      rv = checker.Check(certInput, nullptr, keepGoing);
    824      if (rv != Success || !keepGoing) {
    825        return rv;
    826      }
    827    }
    828    return Success;
    829  }
    830 
    831  Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
    832                         /*optional*/ const Input*, /*optional*/ const Input*)
    833                         override
    834  {
    835    return Success;
    836  }
    837 
    838  Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
    839  {
    840    return Success;
    841  }
    842 
    843  std::vector<ByteString> certs;
    844  ByteString rootCACertDER;
    845  ScopedTestKeyPair firstIssuerKey;
    846 };
    847 
    848 TEST_F(pkixbuild, AvoidUnboundedPathSearchingFailure)
    849 {
    850  SelfIssuedCertificatesTrustDomain localTrustDomain;
    851  // This creates a few hundred million potential paths of length 8 (end entity
    852  // + 6 sub-CAs + root). It would be prohibitively expensive to enumerate all
    853  // of these, so we give mozilla::pkix a budget that is spent when searching
    854  // paths. If the budget is exhausted, it simply returns an unknown issuer
    855  // error. In the future it might be nice to return a specific error that would
    856  // give the front-end a hint that maybe it shouldn't have so many certificates
    857  // that all have the same subject and issuer DN but different SPKIs.
    858  localTrustDomain.SetUpCerts(18);
    859  ByteString certDER(CreateCert("DN", "DN", EndEntityOrCA::MustBeEndEntity,
    860                                nullptr, nullptr,
    861                                localTrustDomain.GetFirstIssuerKey()));
    862  ASSERT_FALSE(ENCODING_FAILED(certDER));
    863  Input certDERInput;
    864  ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
    865  ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
    866            BuildCertChain(localTrustDomain, certDERInput, Now(),
    867                           EndEntityOrCA::MustBeEndEntity,
    868                           KeyUsage::noParticularKeyUsageRequired,
    869                           KeyPurposeId::id_kp_serverAuth,
    870                           CertPolicyId::anyPolicy,
    871                           nullptr/*stapledOCSPResponse*/));
    872 }
    873 
    874 TEST_F(pkixbuild, AvoidUnboundedPathSearchingSuccess)
    875 {
    876  SelfIssuedCertificatesTrustDomain localTrustDomain;
    877  // This creates a few hundred thousand possible potential paths of length 8
    878  // (end entity + 6 sub-CAs + root). This will nearly exhaust mozilla::pkix's
    879  // search budget, so this should succeed.
    880  localTrustDomain.SetUpCerts(10);
    881  ByteString certDER(CreateCert("DN", "DN", EndEntityOrCA::MustBeEndEntity,
    882                                nullptr, nullptr,
    883                                localTrustDomain.GetFirstIssuerKey()));
    884  ASSERT_FALSE(ENCODING_FAILED(certDER));
    885  Input certDERInput;
    886  ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
    887  ASSERT_EQ(Success,
    888            BuildCertChain(localTrustDomain, certDERInput, Now(),
    889                           EndEntityOrCA::MustBeEndEntity,
    890                           KeyUsage::noParticularKeyUsageRequired,
    891                           KeyPurposeId::id_kp_serverAuth,
    892                           CertPolicyId::anyPolicy,
    893                           nullptr/*stapledOCSPResponse*/));
    894 }