tor-browser

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

pkixcert_signature_algorithm_tests.cpp (10424B)


      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 /* Any copyright is dedicated to the Public Domain.
      4 * http://creativecommons.org/publicdomain/zero/1.0/ */
      5 
      6 #include "pkixgtest.h"
      7 
      8 #include "mozpkix/pkixder.h"
      9 
     10 #include "secoid.h"
     11 
     12 using namespace mozilla::pkix;
     13 using namespace mozilla::pkix::test;
     14 
     15 /* These tests generate invalid certificates on the fly, We want to test
     16 * validation of those certificates, not the generation, so we
     17 * need to temporarily allow disallowed signature policies before
     18 * we do the actual certificate or ocsp signing
     19 */
     20 class HashAlgorithmPolicies
     21 {
     22   static const int numberOfHashes = 4; /* sigh */
     23   static const SECOidTag hashOids[numberOfHashes];
     24 
     25   PRUint32 savedPolicy[numberOfHashes];
     26 
     27 public:
     28   void EnableHashSignaturePolicy(void);
     29   void RestoreHashSignaturePolicy(void);
     30 };
     31 
     32 const SECOidTag HashAlgorithmPolicies::hashOids[numberOfHashes] = {
     33   SEC_OID_MD2,
     34   SEC_OID_MD4,
     35   SEC_OID_MD5,
     36   SEC_OID_SHA1 };
     37 
     38 void
     39 HashAlgorithmPolicies::EnableHashSignaturePolicy(void)
     40 {
     41    for (int i=0;i < numberOfHashes; i++) {
     42        ASSERT_EQ(SECSuccess,
     43                  NSS_GetAlgorithmPolicy(hashOids[i], &savedPolicy[i]));
     44        ASSERT_EQ(SECSuccess,
     45                  NSS_SetAlgorithmPolicy(hashOids[i], NSS_USE_ALG_IN_SIGNATURE, 0));
     46    }
     47 }
     48 
     49 void
     50 HashAlgorithmPolicies::RestoreHashSignaturePolicy(void)
     51 {
     52    for (int i=0;i < numberOfHashes; i++) {
     53        ASSERT_EQ(SECSuccess,
     54                  NSS_SetAlgorithmPolicy(hashOids[i], savedPolicy[i],
     55                                        NSS_USE_ALG_IN_SIGNATURE));
     56    }
     57 }
     58 
     59 static ByteString
     60 CreateCert(const char* issuerCN,
     61           const char* subjectCN,
     62           EndEntityOrCA endEntityOrCA,
     63           const TestSignatureAlgorithm& signatureAlgorithm,
     64           /*out*/ ByteString& subjectDER)
     65 {
     66  static long serialNumberValue = 0;
     67  ++serialNumberValue;
     68  ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue));
     69  EXPECT_FALSE(ENCODING_FAILED(serialNumber));
     70 
     71  ByteString issuerDER(CNToDERName(issuerCN));
     72  EXPECT_FALSE(ENCODING_FAILED(issuerDER));
     73  subjectDER = CNToDERName(subjectCN);
     74  EXPECT_FALSE(ENCODING_FAILED(subjectDER));
     75 
     76  ByteString extensions[2];
     77  if (endEntityOrCA == EndEntityOrCA::MustBeCA) {
     78    extensions[0] =
     79      CreateEncodedBasicConstraints(true, nullptr, Critical::Yes);
     80    EXPECT_FALSE(ENCODING_FAILED(extensions[0]));
     81  }
     82 
     83  ScopedTestKeyPair reusedKey(CloneReusedKeyPair());
     84  HashAlgorithmPolicies policies;
     85  policies.EnableHashSignaturePolicy();
     86  ByteString certDER(CreateEncodedCertificate(v3, signatureAlgorithm,
     87                                              serialNumber, issuerDER,
     88                                              oneDayBeforeNow, oneDayAfterNow,
     89                                              subjectDER, *reusedKey,
     90                                              extensions, *reusedKey,
     91                                              signatureAlgorithm));
     92  policies.RestoreHashSignaturePolicy();
     93  EXPECT_FALSE(ENCODING_FAILED(certDER));
     94  return certDER;
     95 }
     96 
     97 
     98 class AlgorithmTestsTrustDomain final : public DefaultCryptoTrustDomain
     99 {
    100 public:
    101  AlgorithmTestsTrustDomain(const ByteString& aRootDER,
    102                            const ByteString& aRootSubjectDER,
    103               /*optional*/ const ByteString& aIntDER,
    104               /*optional*/ const ByteString& aIntSubjectDER)
    105    : rootDER(aRootDER)
    106    , rootSubjectDER(aRootSubjectDER)
    107    , intDER(aIntDER)
    108    , intSubjectDER(aIntSubjectDER)
    109  {
    110  }
    111 
    112 private:
    113  Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input candidateCert,
    114                      /*out*/ TrustLevel& trustLevel) override
    115  {
    116    if (InputEqualsByteString(candidateCert, rootDER)) {
    117      trustLevel = TrustLevel::TrustAnchor;
    118    } else {
    119      trustLevel = TrustLevel::InheritsTrust;
    120    }
    121    return Success;
    122  }
    123 
    124  Result FindIssuer(Input encodedIssuerName, IssuerChecker& checker, Time)
    125                    override
    126  {
    127    ByteString* issuerDER = nullptr;
    128    if (InputEqualsByteString(encodedIssuerName, rootSubjectDER)) {
    129      issuerDER = &rootDER;
    130    } else if (InputEqualsByteString(encodedIssuerName, intSubjectDER)) {
    131      issuerDER = &intDER;
    132    } else {
    133      // FindIssuer just returns success if it can't find a potential issuer.
    134      return Success;
    135    }
    136    Input issuerCert;
    137    Result rv = issuerCert.Init(issuerDER->data(), issuerDER->length());
    138    if (rv != Success) {
    139      return rv;
    140    }
    141    bool keepGoing;
    142    return checker.Check(issuerCert, nullptr, keepGoing);
    143  }
    144 
    145  Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
    146                         const Input*, const Input*) override
    147  {
    148    return Success;
    149  }
    150 
    151  Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
    152  {
    153    return Success;
    154  }
    155 
    156  ByteString rootDER;
    157  ByteString rootSubjectDER;
    158  ByteString intDER;
    159  ByteString intSubjectDER;
    160 };
    161 
    162 static const TestSignatureAlgorithm NO_INTERMEDIATE
    163 {
    164  TestPublicKeyAlgorithm(ByteString()),
    165  TestDigestAlgorithmID::MD2,
    166  ByteString(),
    167  false
    168 };
    169 
    170 struct ChainValidity final
    171 {
    172  ChainValidity(const TestSignatureAlgorithm& aEndEntitySignatureAlgorithm,
    173                const TestSignatureAlgorithm& aOptionalIntSignatureAlgorithm,
    174                const TestSignatureAlgorithm& aRootSignatureAlgorithm,
    175                bool aIsValid)
    176    : endEntitySignatureAlgorithm(aEndEntitySignatureAlgorithm)
    177    , optionalIntermediateSignatureAlgorithm(aOptionalIntSignatureAlgorithm)
    178    , rootSignatureAlgorithm(aRootSignatureAlgorithm)
    179    , isValid(aIsValid)
    180  { }
    181 
    182  // In general, a certificate is generated for each of these.  However, if
    183  // optionalIntermediateSignatureAlgorithm is NO_INTERMEDIATE, then only 2
    184  // certificates are generated.
    185  // The certificate generated for the given rootSignatureAlgorithm is the
    186  // trust anchor.
    187  TestSignatureAlgorithm endEntitySignatureAlgorithm;
    188  TestSignatureAlgorithm optionalIntermediateSignatureAlgorithm;
    189  TestSignatureAlgorithm rootSignatureAlgorithm;
    190  bool isValid;
    191 };
    192 
    193 static const ChainValidity CHAIN_VALIDITY[] =
    194 {
    195  // The trust anchor may have a signature with an unsupported signature
    196  // algorithm.
    197  ChainValidity(sha256WithRSAEncryption(),
    198                NO_INTERMEDIATE,
    199                md5WithRSAEncryption(),
    200                true),
    201  ChainValidity(sha256WithRSAEncryption(),
    202                NO_INTERMEDIATE,
    203                md2WithRSAEncryption(),
    204                true),
    205 
    206  // Certificates that are not trust anchors must not have a signature with an
    207  // unsupported signature algorithm.
    208  ChainValidity(md5WithRSAEncryption(),
    209                NO_INTERMEDIATE,
    210                sha256WithRSAEncryption(),
    211                false),
    212  ChainValidity(md2WithRSAEncryption(),
    213                NO_INTERMEDIATE,
    214                sha256WithRSAEncryption(),
    215                false),
    216  ChainValidity(md2WithRSAEncryption(),
    217                NO_INTERMEDIATE,
    218                md5WithRSAEncryption(),
    219                false),
    220  ChainValidity(sha256WithRSAEncryption(),
    221                md5WithRSAEncryption(),
    222                sha256WithRSAEncryption(),
    223                false),
    224  ChainValidity(sha256WithRSAEncryption(),
    225                md2WithRSAEncryption(),
    226                sha256WithRSAEncryption(),
    227                false),
    228  ChainValidity(sha256WithRSAEncryption(),
    229                md2WithRSAEncryption(),
    230                md5WithRSAEncryption(),
    231                false),
    232 };
    233 
    234 class pkixcert_IsValidChainForAlgorithm
    235  : public ::testing::Test
    236  , public ::testing::WithParamInterface<ChainValidity>
    237 {
    238 };
    239 
    240 ::std::ostream& operator<<(::std::ostream& os,
    241                           const pkixcert_IsValidChainForAlgorithm&)
    242 {
    243  return os << "TODO (bug 1318770)";
    244 }
    245 
    246 ::std::ostream& operator<<(::std::ostream& os, const ChainValidity&)
    247 {
    248  return os << "TODO (bug 1318770)";
    249 }
    250 
    251 TEST_P(pkixcert_IsValidChainForAlgorithm, IsValidChainForAlgorithm)
    252 {
    253  const ChainValidity& chainValidity(GetParam());
    254  const char* rootCN = "CN=Root";
    255  ByteString rootSubjectDER;
    256  ByteString rootEncoded(
    257    CreateCert(rootCN, rootCN, EndEntityOrCA::MustBeCA,
    258               chainValidity.rootSignatureAlgorithm, rootSubjectDER));
    259  EXPECT_FALSE(ENCODING_FAILED(rootEncoded));
    260  EXPECT_FALSE(ENCODING_FAILED(rootSubjectDER));
    261 
    262  const char* issuerCN = rootCN;
    263 
    264  const char* intermediateCN = "CN=Intermediate";
    265  ByteString intermediateSubjectDER;
    266  ByteString intermediateEncoded;
    267 
    268  // If the the algorithmIdentifier is empty, then it's NO_INTERMEDIATE.
    269  if (!chainValidity.optionalIntermediateSignatureAlgorithm
    270                    .algorithmIdentifier.empty()) {
    271    intermediateEncoded =
    272      CreateCert(rootCN, intermediateCN, EndEntityOrCA::MustBeCA,
    273                 chainValidity.optionalIntermediateSignatureAlgorithm,
    274                 intermediateSubjectDER);
    275    EXPECT_FALSE(ENCODING_FAILED(intermediateEncoded));
    276    EXPECT_FALSE(ENCODING_FAILED(intermediateSubjectDER));
    277    issuerCN = intermediateCN;
    278  }
    279 
    280  AlgorithmTestsTrustDomain trustDomain(rootEncoded, rootSubjectDER,
    281                                        intermediateEncoded,
    282                                        intermediateSubjectDER);
    283 
    284  const char* endEntityCN = "CN=End Entity";
    285  ByteString endEntitySubjectDER;
    286  ByteString endEntityEncoded(
    287    CreateCert(issuerCN, endEntityCN, EndEntityOrCA::MustBeEndEntity,
    288               chainValidity.endEntitySignatureAlgorithm,
    289               endEntitySubjectDER));
    290  EXPECT_FALSE(ENCODING_FAILED(endEntityEncoded));
    291  EXPECT_FALSE(ENCODING_FAILED(endEntitySubjectDER));
    292 
    293  Input endEntity;
    294  ASSERT_EQ(Success, endEntity.Init(endEntityEncoded.data(),
    295                                    endEntityEncoded.length()));
    296  Result expectedResult = chainValidity.isValid
    297                        ? Success
    298                        : Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
    299  ASSERT_EQ(expectedResult,
    300            BuildCertChain(trustDomain, endEntity, Now(),
    301                           EndEntityOrCA::MustBeEndEntity,
    302                           KeyUsage::noParticularKeyUsageRequired,
    303                           KeyPurposeId::id_kp_serverAuth,
    304                           CertPolicyId::anyPolicy, nullptr));
    305 }
    306 
    307 INSTANTIATE_TEST_SUITE_P(pkixcert_IsValidChainForAlgorithm,
    308                        pkixcert_IsValidChainForAlgorithm,
    309                        testing::ValuesIn(CHAIN_VALIDITY));