tor-browser

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

pkixcert_extension_tests.cpp (11474B)


      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 "pkixgtest.h"
     26 
     27 #include "mozpkix/pkixder.h"
     28 #include "mozpkix/pkixutil.h"
     29 #include "mozpkix/test/pkixtestutil.h"
     30 
     31 using namespace mozilla::pkix;
     32 using namespace mozilla::pkix::test;
     33 
     34 // Creates a self-signed certificate with the given extension.
     35 static ByteString
     36 CreateCertWithExtensions(const char* subjectCN,
     37                         const ByteString* extensions)
     38 {
     39  static long serialNumberValue = 0;
     40  ++serialNumberValue;
     41  ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue));
     42  EXPECT_FALSE(ENCODING_FAILED(serialNumber));
     43  ByteString issuerDER(CNToDERName(subjectCN));
     44  EXPECT_FALSE(ENCODING_FAILED(issuerDER));
     45  ByteString subjectDER(CNToDERName(subjectCN));
     46  EXPECT_FALSE(ENCODING_FAILED(subjectDER));
     47  ScopedTestKeyPair subjectKey(CloneReusedKeyPair());
     48  return CreateEncodedCertificate(v3, sha256WithRSAEncryption(),
     49                                  serialNumber, issuerDER,
     50                                  oneDayBeforeNow, oneDayAfterNow,
     51                                  subjectDER, *subjectKey, extensions,
     52                                  *subjectKey,
     53                                  sha256WithRSAEncryption());
     54 }
     55 
     56 // Creates a self-signed certificate with the given extension.
     57 static ByteString
     58 CreateCertWithOneExtension(const char* subjectStr, const ByteString& extension)
     59 {
     60  const ByteString extensions[] = { extension, ByteString() };
     61  return CreateCertWithExtensions(subjectStr, extensions);
     62 }
     63 
     64 class TrustEverythingTrustDomain final : public DefaultCryptoTrustDomain
     65 {
     66 private:
     67  Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input,
     68                      /*out*/ TrustLevel& trustLevel) override
     69  {
     70    trustLevel = TrustLevel::TrustAnchor;
     71    return Success;
     72  }
     73 
     74  Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
     75                         /*optional*/ const Input*, /*optional*/ const Input*)
     76                         override
     77  {
     78    return Success;
     79  }
     80 
     81  Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
     82  {
     83    return Success;
     84  }
     85 };
     86 
     87 // python DottedOIDToCode.py --tlv unknownExtensionOID 1.3.6.1.4.1.13769.666.666.666.1.500.9.3
     88 static const uint8_t tlv_unknownExtensionOID[] = {
     89  0x06, 0x12, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85, 0x1a, 0x85, 0x1a,
     90  0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x03
     91 };
     92 
     93 // python DottedOIDToCode.py --tlv id-pe-authorityInformationAccess 1.3.6.1.5.5.7.1.1
     94 static const uint8_t tlv_id_pe_authorityInformationAccess[] = {
     95  0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
     96 };
     97 
     98 // python DottedOIDToCode.py --tlv wrongExtensionOID 1.3.6.6.1.5.5.7.1.1
     99 // (there is an extra "6" that shouldn't be in this OID)
    100 static const uint8_t tlv_wrongExtensionOID[] = {
    101  0x06, 0x09, 0x2b, 0x06, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
    102 };
    103 
    104 // python DottedOIDToCode.py --tlv id-ce-unknown 2.5.29.55
    105 // (this is a made-up OID for testing "id-ce"-prefixed OIDs that mozilla::pkix
    106 // doesn't handle)
    107 static const uint8_t tlv_id_ce_unknown[] = {
    108  0x06, 0x03, 0x55, 0x1d, 0x37
    109 };
    110 
    111 // python DottedOIDToCode.py --tlv id-ce-inhibitAnyPolicy 2.5.29.54
    112 static const uint8_t tlv_id_ce_inhibitAnyPolicy[] = {
    113  0x06, 0x03, 0x55, 0x1d, 0x36
    114 };
    115 
    116 // python DottedOIDToCode.py --tlv id-pkix-ocsp-nocheck 1.3.6.1.5.5.7.48.1.5
    117 static const uint8_t tlv_id_pkix_ocsp_nocheck[] = {
    118  0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x05
    119 };
    120 
    121 struct ExtensionTestcase
    122 {
    123  ByteString extension;
    124  Result expectedResult;
    125 };
    126 
    127 ::std::ostream& operator<<(::std::ostream& os, const ExtensionTestcase&)
    128 {
    129  return os << "TODO (bug 1318770)";
    130 }
    131 
    132 static const ExtensionTestcase EXTENSION_TESTCASES[] =
    133 {
    134  // Tests that a non-critical extension not in the id-ce or id-pe arcs (which
    135  // is thus unknown to us) verifies successfully even if empty (extensions we
    136  // know about aren't normally allowed to be empty).
    137  { TLV(der::SEQUENCE,
    138        BytesToByteString(tlv_unknownExtensionOID) +
    139        TLV(der::OCTET_STRING, ByteString())),
    140    Success
    141  },
    142 
    143  // Tests that a critical extension not in the id-ce or id-pe arcs (which is
    144  // thus unknown to us) is detected and that verification fails with the
    145  // appropriate error.
    146  { TLV(der::SEQUENCE,
    147        BytesToByteString(tlv_unknownExtensionOID) +
    148        Boolean(true) +
    149        TLV(der::OCTET_STRING, ByteString())),
    150    Result::ERROR_UNKNOWN_CRITICAL_EXTENSION
    151  },
    152 
    153  // Tests that a id-pe-authorityInformationAccess critical extension
    154  // is detected and that verification succeeds.
    155  // XXX: According to RFC 5280 an AIA that consists of an empty sequence is
    156  // not legal, but we accept it and that is not what we're testing here.
    157  { TLV(der::SEQUENCE,
    158        BytesToByteString(tlv_id_pe_authorityInformationAccess) +
    159        Boolean(true) +
    160        TLV(der::OCTET_STRING, TLV(der::SEQUENCE, ByteString()))),
    161    Success
    162  },
    163 
    164  // Tests that an incorrect OID for id-pe-authorityInformationAccess
    165  // (when marked critical) is detected and that verification fails.
    166  // (Until bug 1020993 was fixed, this wrong value was used for
    167  // id-pe-authorityInformationAccess.)
    168  { TLV(der::SEQUENCE,
    169        BytesToByteString(tlv_wrongExtensionOID) +
    170        Boolean(true) +
    171        TLV(der::OCTET_STRING, ByteString())),
    172    Result::ERROR_UNKNOWN_CRITICAL_EXTENSION
    173  },
    174 
    175  // We know about some id-ce extensions (OID arc 2.5.29), but not all of them.
    176  // Tests that an unknown id-ce extension is detected and that verification
    177  // fails.
    178  { TLV(der::SEQUENCE,
    179        BytesToByteString(tlv_id_ce_unknown) +
    180        Boolean(true) +
    181        TLV(der::OCTET_STRING, ByteString())),
    182    Result::ERROR_UNKNOWN_CRITICAL_EXTENSION
    183  },
    184 
    185  // Tests that a certificate with a known critical id-ce extension (in this
    186  // case, OID 2.5.29.54, which is id-ce-inhibitAnyPolicy), verifies
    187  // successfully.
    188  { TLV(der::SEQUENCE,
    189        BytesToByteString(tlv_id_ce_inhibitAnyPolicy) +
    190        Boolean(true) +
    191        TLV(der::OCTET_STRING, Integer(0))),
    192    Success
    193  },
    194 
    195  // Tests that a certificate with the id-pkix-ocsp-nocheck extension (marked
    196  // critical) verifies successfully.
    197  // RFC 6960:
    198  //   ext-ocsp-nocheck EXTENSION ::= { SYNTAX NULL IDENTIFIED
    199  //                                    BY id-pkix-ocsp-nocheck }
    200  { TLV(der::SEQUENCE,
    201        BytesToByteString(tlv_id_pkix_ocsp_nocheck) +
    202        Boolean(true) +
    203        TLV(der::OCTET_STRING, TLV(der::NULLTag, ByteString()))),
    204    Success
    205  },
    206 
    207  // Tests that a certificate with another representation of the
    208  // id-pkix-ocsp-nocheck extension (marked critical) verifies successfully.
    209  // According to http://comments.gmane.org/gmane.ietf.x509/30947,
    210  // some code creates certificates where value of the extension is
    211  // an empty OCTET STRING.
    212  { TLV(der::SEQUENCE,
    213        BytesToByteString(tlv_id_pkix_ocsp_nocheck) +
    214        Boolean(true) +
    215        TLV(der::OCTET_STRING, ByteString())),
    216    Success
    217  },
    218 };
    219 
    220 class pkixcert_extension
    221  : public ::testing::Test
    222  , public ::testing::WithParamInterface<ExtensionTestcase>
    223 {
    224 protected:
    225  static TrustEverythingTrustDomain trustDomain;
    226 };
    227 
    228 /*static*/ TrustEverythingTrustDomain pkixcert_extension::trustDomain;
    229 
    230 TEST_P(pkixcert_extension, ExtensionHandledProperly)
    231 {
    232  const ExtensionTestcase& testcase(GetParam());
    233  const char* cn = "Cert Extension Test";
    234  ByteString cert(CreateCertWithOneExtension(cn, testcase.extension));
    235  ASSERT_FALSE(ENCODING_FAILED(cert));
    236  Input certInput;
    237  ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
    238  ASSERT_EQ(testcase.expectedResult,
    239            BuildCertChain(trustDomain, certInput, Now(),
    240                           EndEntityOrCA::MustBeEndEntity,
    241                           KeyUsage::noParticularKeyUsageRequired,
    242                           KeyPurposeId::anyExtendedKeyUsage,
    243                           CertPolicyId::anyPolicy,
    244                           nullptr/*stapledOCSPResponse*/));
    245 }
    246 
    247 INSTANTIATE_TEST_SUITE_P(pkixcert_extension,
    248                        pkixcert_extension,
    249                        testing::ValuesIn(EXTENSION_TESTCASES));
    250 
    251 // Two subjectAltNames must result in an error.
    252 TEST_F(pkixcert_extension, DuplicateSubjectAltName)
    253 {
    254  // python DottedOIDToCode.py --tlv id-ce-subjectAltName 2.5.29.17
    255  static const uint8_t tlv_id_ce_subjectAltName[] = {
    256    0x06, 0x03, 0x55, 0x1d, 0x11
    257  };
    258 
    259  ByteString subjectAltName(
    260    TLV(der::SEQUENCE,
    261        BytesToByteString(tlv_id_ce_subjectAltName) +
    262        TLV(der::OCTET_STRING, TLV(der::SEQUENCE, DNSName("example.com")))));
    263  static const ByteString extensions[] = { subjectAltName, subjectAltName,
    264                                           ByteString() };
    265  static const char* certCN = "Cert With Duplicate subjectAltName";
    266  ByteString cert(CreateCertWithExtensions(certCN, extensions));
    267  ASSERT_FALSE(ENCODING_FAILED(cert));
    268  Input certInput;
    269  ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
    270  ASSERT_EQ(Result::ERROR_EXTENSION_VALUE_INVALID,
    271            BuildCertChain(trustDomain, certInput, Now(),
    272                           EndEntityOrCA::MustBeEndEntity,
    273                           KeyUsage::noParticularKeyUsageRequired,
    274                           KeyPurposeId::anyExtendedKeyUsage,
    275                           CertPolicyId::anyPolicy,
    276                           nullptr/*stapledOCSPResponse*/));
    277 }
    278 
    279 TEST_F(pkixcert_extension, QCStatements)
    280 {
    281  // python DottedOIDToCode.py --tlv id-pe-qcStatements 1.3.6.1.5.5.7.1.3
    282  const uint8_t tlv_id_pe_qcStatements[] = {
    283    0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x03
    284  };
    285 
    286  ByteString qcStatementsBytes(
    287    TLV(der::SEQUENCE,
    288        BytesToByteString(tlv_id_pe_qcStatements) +
    289        TLV(der::OCTET_STRING, ByteString(reinterpret_cast<const uint8_t*>("qcStatements contents")))));
    290  const ByteString extensions[] = { qcStatementsBytes, ByteString() };
    291  const char* certCN = "Cert With qcStatements";
    292  ByteString cert(CreateCertWithExtensions(certCN, extensions));
    293  ASSERT_FALSE(ENCODING_FAILED(cert));
    294  Input certInput;
    295  ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
    296  BackCert backCert(certInput, EndEntityOrCA::MustBeEndEntity, nullptr);
    297  ASSERT_EQ(Success, backCert.Init());
    298  const Input *qcStatements(backCert.GetQCStatements());
    299  ASSERT_TRUE(qcStatements);
    300  ByteString qcStatementsContents(qcStatements->UnsafeGetData(), qcStatements->GetLength());
    301  ASSERT_EQ(ByteString(reinterpret_cast<const uint8_t*>("qcStatements contents")), qcStatementsContents);
    302 }