|  | // Copyright 2015 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "parse_certificate.h" | 
|  |  | 
|  | #include <gtest/gtest.h> | 
|  | #include <openssl/pool.h> | 
|  | #include "cert_errors.h" | 
|  | #include "general_names.h" | 
|  | #include "input.h" | 
|  | #include "parsed_certificate.h" | 
|  | #include "test_helpers.h" | 
|  |  | 
|  | BSSL_NAMESPACE_BEGIN | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Pretty-prints a GeneralizedTime as a human-readable string for use in test | 
|  | // expectations (it is more readable to specify the expected results as a | 
|  | // string). | 
|  | std::string ToString(const der::GeneralizedTime &time) { | 
|  | std::ostringstream pretty_time; | 
|  | pretty_time << "year=" << int{time.year} << ", month=" << int{time.month} | 
|  | << ", day=" << int{time.day} << ", hours=" << int{time.hours} | 
|  | << ", minutes=" << int{time.minutes} | 
|  | << ", seconds=" << int{time.seconds}; | 
|  | return pretty_time.str(); | 
|  | } | 
|  |  | 
|  | std::string GetFilePath(const std::string &file_name) { | 
|  | return std::string("testdata/parse_certificate_unittest/") + file_name; | 
|  | } | 
|  |  | 
|  | // Loads certificate data and expectations from the PEM file |file_name|. | 
|  | // Verifies that parsing the Certificate matches expectations: | 
|  | //   * If expected to fail, emits the expected errors | 
|  | //   * If expected to succeeds, the parsed fields match expectations | 
|  | void RunCertificateTest(const std::string &file_name) { | 
|  | std::string data; | 
|  | std::string expected_errors; | 
|  | std::string expected_tbs_certificate; | 
|  | std::string expected_signature_algorithm; | 
|  | std::string expected_signature; | 
|  |  | 
|  | // Read the certificate data and test expectations from a single PEM file. | 
|  | const PemBlockMapping mappings[] = { | 
|  | {"CERTIFICATE", &data}, | 
|  | {"ERRORS", &expected_errors, true /*optional*/}, | 
|  | {"SIGNATURE", &expected_signature, true /*optional*/}, | 
|  | {"SIGNATURE ALGORITHM", &expected_signature_algorithm, true /*optional*/}, | 
|  | {"TBS CERTIFICATE", &expected_tbs_certificate, true /*optional*/}, | 
|  | }; | 
|  | std::string test_file_path = GetFilePath(file_name); | 
|  | ASSERT_TRUE(ReadTestDataFromPemFile(test_file_path, mappings)); | 
|  |  | 
|  | // Note that empty expected_errors doesn't necessarily mean success. | 
|  | bool expected_result = !expected_tbs_certificate.empty(); | 
|  |  | 
|  | // Parsing the certificate. | 
|  | der::Input tbs_certificate_tlv; | 
|  | der::Input signature_algorithm_tlv; | 
|  | der::BitString signature_value; | 
|  | CertErrors errors; | 
|  | bool actual_result = | 
|  | ParseCertificate(der::Input(data), &tbs_certificate_tlv, | 
|  | &signature_algorithm_tlv, &signature_value, &errors); | 
|  |  | 
|  | EXPECT_EQ(expected_result, actual_result); | 
|  | VerifyCertErrors(expected_errors, errors, test_file_path); | 
|  |  | 
|  | // Ensure that the parsed certificate matches expectations. | 
|  | if (expected_result && actual_result) { | 
|  | EXPECT_EQ(0, signature_value.unused_bits()); | 
|  | EXPECT_EQ(der::Input(expected_signature), signature_value.bytes()); | 
|  | EXPECT_EQ(der::Input(expected_signature_algorithm), | 
|  | signature_algorithm_tlv); | 
|  | EXPECT_EQ(der::Input(expected_tbs_certificate), tbs_certificate_tlv); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Tests parsing a Certificate. | 
|  | TEST(ParseCertificateTest, Version3) { | 
|  | RunCertificateTest("cert_version3.pem"); | 
|  | } | 
|  |  | 
|  | // Tests parsing a simplified Certificate-like structure (the sub-fields for | 
|  | // algorithm and tbsCertificate are not actually valid, but ParseCertificate() | 
|  | // doesn't check them) | 
|  | TEST(ParseCertificateTest, Skeleton) { | 
|  | RunCertificateTest("cert_skeleton.pem"); | 
|  | } | 
|  |  | 
|  | // Tests parsing a Certificate that is not a sequence fails. | 
|  | TEST(ParseCertificateTest, NotSequence) { | 
|  | RunCertificateTest("cert_not_sequence.pem"); | 
|  | } | 
|  |  | 
|  | // Tests that uncomsumed data is not allowed after the main SEQUENCE. | 
|  | TEST(ParseCertificateTest, DataAfterSignature) { | 
|  | RunCertificateTest("cert_data_after_signature.pem"); | 
|  | } | 
|  |  | 
|  | // Tests that parsing fails if the signature BIT STRING is missing. | 
|  | TEST(ParseCertificateTest, MissingSignature) { | 
|  | RunCertificateTest("cert_missing_signature.pem"); | 
|  | } | 
|  |  | 
|  | // Tests that parsing fails if the signature is present but not a BIT STRING. | 
|  | TEST(ParseCertificateTest, SignatureNotBitString) { | 
|  | RunCertificateTest("cert_signature_not_bit_string.pem"); | 
|  | } | 
|  |  | 
|  | // Tests that parsing fails if the main SEQUENCE is empty (missing all the | 
|  | // fields). | 
|  | TEST(ParseCertificateTest, EmptySequence) { | 
|  | RunCertificateTest("cert_empty_sequence.pem"); | 
|  | } | 
|  |  | 
|  | // Tests what happens when the signature algorithm is present, but has the wrong | 
|  | // tag. | 
|  | TEST(ParseCertificateTest, AlgorithmNotSequence) { | 
|  | RunCertificateTest("cert_algorithm_not_sequence.pem"); | 
|  | } | 
|  |  | 
|  | // Loads tbsCertificate data and expectations from the PEM file |file_name|. | 
|  | // Verifies that parsing the TBSCertificate succeeds, and each parsed field | 
|  | // matches the expectations. | 
|  | // | 
|  | // TODO(eroman): Get rid of the |expected_version| parameter -- this should be | 
|  | // encoded in the test expectations file. | 
|  | void RunTbsCertificateTestGivenVersion(const std::string &file_name, | 
|  | CertificateVersion expected_version) { | 
|  | std::string data; | 
|  | std::string expected_serial_number; | 
|  | std::string expected_signature_algorithm; | 
|  | std::string expected_issuer; | 
|  | std::string expected_validity_not_before; | 
|  | std::string expected_validity_not_after; | 
|  | std::string expected_subject; | 
|  | std::string expected_spki; | 
|  | std::string expected_issuer_unique_id; | 
|  | std::string expected_subject_unique_id; | 
|  | std::string expected_extensions; | 
|  | std::string expected_errors; | 
|  |  | 
|  | // Read the certificate data and test expectations from a single PEM file. | 
|  | const PemBlockMapping mappings[] = { | 
|  | {"TBS CERTIFICATE", &data}, | 
|  | {"SIGNATURE ALGORITHM", &expected_signature_algorithm, true}, | 
|  | {"SERIAL NUMBER", &expected_serial_number, true}, | 
|  | {"ISSUER", &expected_issuer, true}, | 
|  | {"VALIDITY NOTBEFORE", &expected_validity_not_before, true}, | 
|  | {"VALIDITY NOTAFTER", &expected_validity_not_after, true}, | 
|  | {"SUBJECT", &expected_subject, true}, | 
|  | {"SPKI", &expected_spki, true}, | 
|  | {"ISSUER UNIQUE ID", &expected_issuer_unique_id, true}, | 
|  | {"SUBJECT UNIQUE ID", &expected_subject_unique_id, true}, | 
|  | {"EXTENSIONS", &expected_extensions, true}, | 
|  | {"ERRORS", &expected_errors, true}, | 
|  | }; | 
|  | std::string test_file_path = GetFilePath(file_name); | 
|  | ASSERT_TRUE(ReadTestDataFromPemFile(test_file_path, mappings)); | 
|  |  | 
|  | bool expected_result = !expected_spki.empty(); | 
|  |  | 
|  | ParsedTbsCertificate parsed; | 
|  | CertErrors errors; | 
|  | bool actual_result = | 
|  | ParseTbsCertificate(der::Input(data), {}, &parsed, &errors); | 
|  |  | 
|  | EXPECT_EQ(expected_result, actual_result); | 
|  | VerifyCertErrors(expected_errors, errors, test_file_path); | 
|  |  | 
|  | if (!expected_result || !actual_result) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Ensure that the ParsedTbsCertificate matches expectations. | 
|  | EXPECT_EQ(expected_version, parsed.version); | 
|  |  | 
|  | EXPECT_EQ(der::Input(expected_serial_number), parsed.serial_number); | 
|  | EXPECT_EQ(der::Input(expected_signature_algorithm), | 
|  | parsed.signature_algorithm_tlv); | 
|  |  | 
|  | EXPECT_EQ(der::Input(expected_issuer), parsed.issuer_tlv); | 
|  |  | 
|  | // In the test expectations PEM file, validity is described as a | 
|  | // textual string of the parsed value (rather than as DER). | 
|  | EXPECT_EQ(expected_validity_not_before, ToString(parsed.validity_not_before)); | 
|  | EXPECT_EQ(expected_validity_not_after, ToString(parsed.validity_not_after)); | 
|  |  | 
|  | EXPECT_EQ(der::Input(expected_subject), parsed.subject_tlv); | 
|  | EXPECT_EQ(der::Input(expected_spki), parsed.spki_tlv); | 
|  |  | 
|  | EXPECT_EQ(!expected_issuer_unique_id.empty(), | 
|  | parsed.issuer_unique_id.has_value()); | 
|  | if (parsed.issuer_unique_id.has_value()) { | 
|  | EXPECT_EQ(der::Input(expected_issuer_unique_id), | 
|  | parsed.issuer_unique_id->bytes()); | 
|  | } | 
|  | EXPECT_EQ(!expected_subject_unique_id.empty(), | 
|  | parsed.subject_unique_id.has_value()); | 
|  | if (parsed.subject_unique_id.has_value()) { | 
|  | EXPECT_EQ(der::Input(expected_subject_unique_id), | 
|  | parsed.subject_unique_id->bytes()); | 
|  | } | 
|  |  | 
|  | EXPECT_EQ(!expected_extensions.empty(), parsed.extensions_tlv.has_value()); | 
|  | if (parsed.extensions_tlv) { | 
|  | EXPECT_EQ(der::Input(expected_extensions), parsed.extensions_tlv.value()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void RunTbsCertificateTest(const std::string &file_name) { | 
|  | RunTbsCertificateTestGivenVersion(file_name, CertificateVersion::V3); | 
|  | } | 
|  |  | 
|  | // Tests parsing a TBSCertificate for v3 that contains no optional fields. | 
|  | TEST(ParseTbsCertificateTest, Version3NoOptionals) { | 
|  | RunTbsCertificateTest("tbs_v3_no_optionals.pem"); | 
|  | } | 
|  |  | 
|  | // Tests parsing a TBSCertificate for v3 that contains extensions. | 
|  | TEST(ParseTbsCertificateTest, Version3WithExtensions) { | 
|  | RunTbsCertificateTest("tbs_v3_extensions.pem"); | 
|  | } | 
|  |  | 
|  | // Tests parsing a TBSCertificate which lacks a version number (causing it to | 
|  | // default to v1). | 
|  | TEST(ParseTbsCertificateTest, Version1) { | 
|  | RunTbsCertificateTestGivenVersion("tbs_v1.pem", CertificateVersion::V1); | 
|  | } | 
|  |  | 
|  | // The version was set to v1 explicitly rather than omitting the version field. | 
|  | TEST(ParseTbsCertificateTest, ExplicitVersion1) { | 
|  | RunTbsCertificateTest("tbs_explicit_v1.pem"); | 
|  | } | 
|  |  | 
|  | // Extensions are not defined in version 1. | 
|  | TEST(ParseTbsCertificateTest, Version1WithExtensions) { | 
|  | RunTbsCertificateTest("tbs_v1_extensions.pem"); | 
|  | } | 
|  |  | 
|  | // Extensions are not defined in version 2. | 
|  | TEST(ParseTbsCertificateTest, Version2WithExtensions) { | 
|  | RunTbsCertificateTest("tbs_v2_extensions.pem"); | 
|  | } | 
|  |  | 
|  | // A boring version 2 certificate with none of the optional fields. | 
|  | TEST(ParseTbsCertificateTest, Version2NoOptionals) { | 
|  | RunTbsCertificateTestGivenVersion("tbs_v2_no_optionals.pem", | 
|  | CertificateVersion::V2); | 
|  | } | 
|  |  | 
|  | // A version 2 certificate with an issuer unique ID field. | 
|  | TEST(ParseTbsCertificateTest, Version2IssuerUniqueId) { | 
|  | RunTbsCertificateTestGivenVersion("tbs_v2_issuer_unique_id.pem", | 
|  | CertificateVersion::V2); | 
|  | } | 
|  |  | 
|  | // A version 2 certificate with both a issuer and subject unique ID field. | 
|  | TEST(ParseTbsCertificateTest, Version2IssuerAndSubjectUniqueId) { | 
|  | RunTbsCertificateTestGivenVersion("tbs_v2_issuer_and_subject_unique_id.pem", | 
|  | CertificateVersion::V2); | 
|  | } | 
|  |  | 
|  | // A version 3 certificate with all of the optional fields (issuer unique id, | 
|  | // subject unique id, and extensions). | 
|  | TEST(ParseTbsCertificateTest, Version3AllOptionals) { | 
|  | RunTbsCertificateTest("tbs_v3_all_optionals.pem"); | 
|  | } | 
|  |  | 
|  | // The version was set to v4, which is unrecognized. | 
|  | TEST(ParseTbsCertificateTest, Version4) { RunTbsCertificateTest("tbs_v4.pem"); } | 
|  |  | 
|  | // Tests that extraneous data after extensions in a v3 is rejected. | 
|  | TEST(ParseTbsCertificateTest, Version3DataAfterExtensions) { | 
|  | RunTbsCertificateTest("tbs_v3_data_after_extensions.pem"); | 
|  | } | 
|  |  | 
|  | // Tests using a real-world certificate (whereas the other tests are fabricated | 
|  | // (and in fact invalid) data. | 
|  | TEST(ParseTbsCertificateTest, Version3Real) { | 
|  | RunTbsCertificateTest("tbs_v3_real.pem"); | 
|  | } | 
|  |  | 
|  | // Parses a TBSCertificate whose "validity" field expresses both notBefore | 
|  | // and notAfter using UTCTime. | 
|  | TEST(ParseTbsCertificateTest, ValidityBothUtcTime) { | 
|  | RunTbsCertificateTest("tbs_validity_both_utc_time.pem"); | 
|  | } | 
|  |  | 
|  | // Parses a TBSCertificate whose "validity" field expresses both notBefore | 
|  | // and notAfter using GeneralizedTime. | 
|  | TEST(ParseTbsCertificateTest, ValidityBothGeneralizedTime) { | 
|  | RunTbsCertificateTest("tbs_validity_both_generalized_time.pem"); | 
|  | } | 
|  |  | 
|  | // Parses a TBSCertificate whose "validity" field expresses notBefore using | 
|  | // UTCTime and notAfter using GeneralizedTime. | 
|  | TEST(ParseTbsCertificateTest, ValidityUTCTimeAndGeneralizedTime) { | 
|  | RunTbsCertificateTest("tbs_validity_utc_time_and_generalized_time.pem"); | 
|  | } | 
|  |  | 
|  | // Parses a TBSCertificate whose validity" field expresses notBefore using | 
|  | // GeneralizedTime and notAfter using UTCTime. Also of interest, notBefore > | 
|  | // notAfter. Parsing will succeed, however no time can satisfy this constraint. | 
|  | TEST(ParseTbsCertificateTest, ValidityGeneralizedTimeAndUTCTime) { | 
|  | RunTbsCertificateTest("tbs_validity_generalized_time_and_utc_time.pem"); | 
|  | } | 
|  |  | 
|  | // Parses a TBSCertificate whose "validity" field does not strictly follow | 
|  | // the DER rules (and fails to be parsed). | 
|  | TEST(ParseTbsCertificateTest, ValidityRelaxed) { | 
|  | RunTbsCertificateTest("tbs_validity_relaxed.pem"); | 
|  | } | 
|  |  | 
|  | // Parses a KeyUsage with a single 0 bit. | 
|  | TEST(ParseKeyUsageTest, OneBitAllZeros) { | 
|  | const uint8_t der[] = { | 
|  | 0x03, 0x02,  // BIT STRING | 
|  | 0x07,        // Number of unused bits | 
|  | 0x00,        // bits | 
|  | }; | 
|  |  | 
|  | der::BitString key_usage; | 
|  | ASSERT_FALSE(ParseKeyUsage(der::Input(der), &key_usage)); | 
|  | } | 
|  |  | 
|  | // Parses a KeyUsage with 32 bits that are all 0. | 
|  | TEST(ParseKeyUsageTest, 32BitsAllZeros) { | 
|  | const uint8_t der[] = { | 
|  | 0x03, 0x05,  // BIT STRING | 
|  | 0x00,        // Number of unused bits | 
|  | 0x00, 0x00, 0x00, 0x00, | 
|  | }; | 
|  |  | 
|  | der::BitString key_usage; | 
|  | ASSERT_FALSE(ParseKeyUsage(der::Input(der), &key_usage)); | 
|  | } | 
|  |  | 
|  | // Parses a KeyUsage with 32 bits, one of which is 1 (but not in recognized | 
|  | // set). | 
|  | TEST(ParseKeyUsageTest, 32BitsOneSet) { | 
|  | const uint8_t der[] = { | 
|  | 0x03, 0x05,  // BIT STRING | 
|  | 0x00,        // Number of unused bits | 
|  | 0x00, 0x00, 0x00, 0x02, | 
|  | }; | 
|  |  | 
|  | der::BitString key_usage; | 
|  | ASSERT_TRUE(ParseKeyUsage(der::Input(der), &key_usage)); | 
|  |  | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_DIGITAL_SIGNATURE)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_NON_REPUDIATION)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_ENCIPHERMENT)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_DATA_ENCIPHERMENT)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_AGREEMENT)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_CRL_SIGN)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_ENCIPHER_ONLY)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_DECIPHER_ONLY)); | 
|  | } | 
|  |  | 
|  | // Parses a KeyUsage containing bit string 101. | 
|  | TEST(ParseKeyUsageTest, ThreeBits) { | 
|  | const uint8_t der[] = { | 
|  | 0x03, 0x02,  // BIT STRING | 
|  | 0x05,        // Number of unused bits | 
|  | 0xA0,        // bits | 
|  | }; | 
|  |  | 
|  | der::BitString key_usage; | 
|  | ASSERT_TRUE(ParseKeyUsage(der::Input(der), &key_usage)); | 
|  |  | 
|  | EXPECT_TRUE(key_usage.AssertsBit(KEY_USAGE_BIT_DIGITAL_SIGNATURE)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_NON_REPUDIATION)); | 
|  | EXPECT_TRUE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_ENCIPHERMENT)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_DATA_ENCIPHERMENT)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_AGREEMENT)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_CRL_SIGN)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_ENCIPHER_ONLY)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_DECIPHER_ONLY)); | 
|  | } | 
|  |  | 
|  | // Parses a KeyUsage containing DECIPHER_ONLY, which is the | 
|  | // only bit that doesn't fit in the first byte. | 
|  | TEST(ParseKeyUsageTest, DecipherOnly) { | 
|  | const uint8_t der[] = { | 
|  | 0x03, 0x03,  // BIT STRING | 
|  | 0x07,        // Number of unused bits | 
|  | 0x00, 0x80,  // bits | 
|  | }; | 
|  |  | 
|  | der::BitString key_usage; | 
|  | ASSERT_TRUE(ParseKeyUsage(der::Input(der), &key_usage)); | 
|  |  | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_DIGITAL_SIGNATURE)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_NON_REPUDIATION)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_ENCIPHERMENT)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_DATA_ENCIPHERMENT)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_AGREEMENT)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_CRL_SIGN)); | 
|  | EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_ENCIPHER_ONLY)); | 
|  | EXPECT_TRUE(key_usage.AssertsBit(KEY_USAGE_BIT_DECIPHER_ONLY)); | 
|  | } | 
|  |  | 
|  | // Parses an empty KeyUsage. | 
|  | TEST(ParseKeyUsageTest, Empty) { | 
|  | const uint8_t der[] = { | 
|  | 0x03, 0x01,  // BIT STRING | 
|  | 0x00,        // Number of unused bits | 
|  | }; | 
|  |  | 
|  | der::BitString key_usage; | 
|  | ASSERT_FALSE(ParseKeyUsage(der::Input(der), &key_usage)); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityInfoAccess, BasicTests) { | 
|  | // SEQUENCE { | 
|  | //   SEQUENCE { | 
|  | //     # ocsp with directoryName | 
|  | //     OBJECT_IDENTIFIER { 1.3.6.1.5.5.7.48.1 } | 
|  | //     [4] { | 
|  | //       SEQUENCE { | 
|  | //         SET { | 
|  | //           SEQUENCE { | 
|  | //             # commonName | 
|  | //             OBJECT_IDENTIFIER { 2.5.4.3 } | 
|  | //             PrintableString { "ocsp" } | 
|  | //           } | 
|  | //         } | 
|  | //       } | 
|  | //     } | 
|  | //   } | 
|  | //   SEQUENCE { | 
|  | //     # caIssuers with directoryName | 
|  | //     OBJECT_IDENTIFIER { 1.3.6.1.5.5.7.48.2 } | 
|  | //     [4] { | 
|  | //       SEQUENCE { | 
|  | //         SET { | 
|  | //           SEQUENCE { | 
|  | //             # commonName | 
|  | //             OBJECT_IDENTIFIER { 2.5.4.3 } | 
|  | //             PrintableString { "ca issuer" } | 
|  | //           } | 
|  | //         } | 
|  | //       } | 
|  | //     } | 
|  | //   } | 
|  | //   SEQUENCE { | 
|  | //     # non-standard method with URI | 
|  | //     OBJECT_IDENTIFIER { 1.3.6.1.5.5.7.48.3 } | 
|  | //     [6 PRIMITIVE] { "http://nonstandard.example.com" } | 
|  | //   } | 
|  | //   SEQUENCE { | 
|  | //     # ocsp with URI | 
|  | //     OBJECT_IDENTIFIER { 1.3.6.1.5.5.7.48.1 } | 
|  | //     [6 PRIMITIVE] { "http://ocsp.example.com" } | 
|  | //   } | 
|  | //   SEQUENCE { | 
|  | //     # caIssuers with URI | 
|  | //     OBJECT_IDENTIFIER { 1.3.6.1.5.5.7.48.2 } | 
|  | //     [6 PRIMITIVE] { "http://www.example.com/issuer.crt" } | 
|  | //   } | 
|  | // } | 
|  | const uint8_t der[] = { | 
|  | 0x30, 0x81, 0xc3, 0x30, 0x1d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, | 
|  | 0x07, 0x30, 0x01, 0xa4, 0x11, 0x30, 0x0f, 0x31, 0x0d, 0x30, 0x0b, 0x06, | 
|  | 0x03, 0x55, 0x04, 0x03, 0x13, 0x04, 0x6f, 0x63, 0x73, 0x70, 0x30, 0x22, | 
|  | 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0xa4, 0x16, | 
|  | 0x30, 0x14, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, | 
|  | 0x09, 0x63, 0x61, 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x30, 0x2a, | 
|  | 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x03, 0x86, 0x1e, | 
|  | 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x6f, 0x6e, 0x73, 0x74, | 
|  | 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, | 
|  | 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x23, 0x06, 0x08, 0x2b, 0x06, | 
|  | 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, 0x74, 0x70, | 
|  | 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x65, 0x78, 0x61, 0x6d, | 
|  | 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x2d, 0x06, 0x08, 0x2b, | 
|  | 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x21, 0x68, 0x74, 0x74, | 
|  | 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, | 
|  | 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x73, 0x73, 0x75, | 
|  | 0x65, 0x72, 0x2e, 0x63, 0x72, 0x74}; | 
|  |  | 
|  | std::vector<AuthorityInfoAccessDescription> access_descriptions; | 
|  | ASSERT_TRUE(ParseAuthorityInfoAccess(der::Input(der), &access_descriptions)); | 
|  | ASSERT_EQ(5u, access_descriptions.size()); | 
|  | { | 
|  | const auto &desc = access_descriptions[0]; | 
|  | EXPECT_EQ(der::Input(kAdOcspOid), desc.access_method_oid); | 
|  | const uint8_t location_der[] = {0xa4, 0x11, 0x30, 0x0f, 0x31, 0x0d, 0x30, | 
|  | 0x0b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, | 
|  | 0x04, 0x6f, 0x63, 0x73, 0x70}; | 
|  | EXPECT_EQ(der::Input(location_der), desc.access_location); | 
|  | } | 
|  | { | 
|  | const auto &desc = access_descriptions[1]; | 
|  | EXPECT_EQ(der::Input(kAdCaIssuersOid), desc.access_method_oid); | 
|  | const uint8_t location_der[] = { | 
|  | 0xa4, 0x16, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, | 
|  | 0x03, 0x13, 0x09, 0x63, 0x61, 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72}; | 
|  | EXPECT_EQ(der::Input(location_der), desc.access_location); | 
|  | } | 
|  | { | 
|  | const auto &desc = access_descriptions[2]; | 
|  | const uint8_t method_oid[] = {0x2b, 0x06, 0x01, 0x05, | 
|  | 0x05, 0x07, 0x30, 0x03}; | 
|  | EXPECT_EQ(der::Input(method_oid), desc.access_method_oid); | 
|  | const uint8_t location_der[] = { | 
|  | 0x86, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x6f, | 
|  | 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x2e, 0x65, | 
|  | 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d}; | 
|  | EXPECT_EQ(der::Input(location_der), desc.access_location); | 
|  | } | 
|  | { | 
|  | const auto &desc = access_descriptions[3]; | 
|  | EXPECT_EQ(der::Input(kAdOcspOid), desc.access_method_oid); | 
|  | const uint8_t location_der[] = {0x86, 0x17, 0x68, 0x74, 0x74, 0x70, 0x3a, | 
|  | 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, | 
|  | 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, | 
|  | 0x2e, 0x63, 0x6f, 0x6d}; | 
|  | EXPECT_EQ(der::Input(location_der), desc.access_location); | 
|  | } | 
|  | { | 
|  | const auto &desc = access_descriptions[4]; | 
|  | EXPECT_EQ(der::Input(kAdCaIssuersOid), desc.access_method_oid); | 
|  | const uint8_t location_der[] = { | 
|  | 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, | 
|  | 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, | 
|  | 0x2f, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x2e, 0x63, 0x72, 0x74}; | 
|  | EXPECT_EQ(der::Input(location_der), desc.access_location); | 
|  | } | 
|  |  | 
|  | std::vector<std::string_view> ca_issuers_uris, ocsp_uris; | 
|  | ASSERT_TRUE(ParseAuthorityInfoAccessURIs(der::Input(der), &ca_issuers_uris, | 
|  | &ocsp_uris)); | 
|  | ASSERT_EQ(1u, ca_issuers_uris.size()); | 
|  | EXPECT_EQ("http://www.example.com/issuer.crt", ca_issuers_uris.front()); | 
|  | ASSERT_EQ(1u, ocsp_uris.size()); | 
|  | EXPECT_EQ("http://ocsp.example.com", ocsp_uris.front()); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityInfoAccess, NoOcspOrCaIssuersURIs) { | 
|  | // SEQUENCE { | 
|  | //   SEQUENCE { | 
|  | //     # non-standard method with directoryName | 
|  | //     OBJECT_IDENTIFIER { 1.2.3 } | 
|  | //     [4] { | 
|  | //       SEQUENCE { | 
|  | //         SET { | 
|  | //           SEQUENCE { | 
|  | //             # commonName | 
|  | //             OBJECT_IDENTIFIER { 2.5.4.3 } | 
|  | //             PrintableString { "foo" } | 
|  | //           } | 
|  | //         } | 
|  | //       } | 
|  | //     } | 
|  | //   } | 
|  | // } | 
|  | const uint8_t der[] = {0x30, 0x18, 0x30, 0x16, 0x06, 0x02, 0x2a, 0x03, 0xa4, | 
|  | 0x10, 0x30, 0x0e, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, | 
|  | 0x55, 0x04, 0x03, 0x13, 0x03, 0x66, 0x6f, 0x6f}; | 
|  |  | 
|  | std::vector<AuthorityInfoAccessDescription> access_descriptions; | 
|  | ASSERT_TRUE(ParseAuthorityInfoAccess(der::Input(der), &access_descriptions)); | 
|  | ASSERT_EQ(1u, access_descriptions.size()); | 
|  | const auto &desc = access_descriptions[0]; | 
|  | const uint8_t method_oid[] = {0x2a, 0x03}; | 
|  | EXPECT_EQ(der::Input(method_oid), desc.access_method_oid); | 
|  | const uint8_t location_der[] = {0xa4, 0x10, 0x30, 0x0e, 0x31, 0x0c, | 
|  | 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, | 
|  | 0x03, 0x13, 0x03, 0x66, 0x6f, 0x6f}; | 
|  | EXPECT_EQ(der::Input(location_der), desc.access_location); | 
|  |  | 
|  | std::vector<std::string_view> ca_issuers_uris, ocsp_uris; | 
|  | // ParseAuthorityInfoAccessURIs should still return success since it was a | 
|  | // valid AuthorityInfoAccess extension, even though it did not contain any | 
|  | // elements we care about, and both output vectors should be empty. | 
|  | ASSERT_TRUE(ParseAuthorityInfoAccessURIs(der::Input(der), &ca_issuers_uris, | 
|  | &ocsp_uris)); | 
|  | EXPECT_EQ(0u, ca_issuers_uris.size()); | 
|  | EXPECT_EQ(0u, ocsp_uris.size()); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityInfoAccess, IncompleteAccessDescription) { | 
|  | // SEQUENCE { | 
|  | //   # first entry is ok | 
|  | //   SEQUENCE { | 
|  | //     OBJECT_IDENTIFIER { 1.3.6.1.5.5.7.48.1 } | 
|  | //     [6 PRIMITIVE] { "http://ocsp.example.com" } | 
|  | //   } | 
|  | //   # second is missing accessLocation field | 
|  | //   SEQUENCE { | 
|  | //     OBJECT_IDENTIFIER { 1.3.6.1.5.5.7.48.2 } | 
|  | //   } | 
|  | // } | 
|  | const uint8_t der[] = {0x30, 0x31, 0x30, 0x23, 0x06, 0x08, 0x2b, 0x06, 0x01, | 
|  | 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, | 
|  | 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, | 
|  | 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, | 
|  | 0x63, 0x6f, 0x6d, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, | 
|  | 0x01, 0x05, 0x05, 0x07, 0x30, 0x02}; | 
|  |  | 
|  | std::vector<AuthorityInfoAccessDescription> access_descriptions; | 
|  | EXPECT_FALSE(ParseAuthorityInfoAccess(der::Input(der), &access_descriptions)); | 
|  |  | 
|  | std::vector<std::string_view> ca_issuers_uris, ocsp_uris; | 
|  | EXPECT_FALSE(ParseAuthorityInfoAccessURIs(der::Input(der), &ca_issuers_uris, | 
|  | &ocsp_uris)); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityInfoAccess, ExtraDataInAccessDescription) { | 
|  | // SEQUENCE { | 
|  | //   SEQUENCE { | 
|  | //     OBJECT_IDENTIFIER { 1.3.6.1.5.5.7.48.1 } | 
|  | //     [6 PRIMITIVE] { "http://ocsp.example.com" } | 
|  | //     # invalid, AccessDescription only has 2 fields | 
|  | //     PrintableString { "henlo" } | 
|  | //   } | 
|  | // } | 
|  | const uint8_t der[] = { | 
|  | 0x30, 0x2c, 0x30, 0x2a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, | 
|  | 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, | 
|  | 0x63, 0x73, 0x70, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, | 
|  | 0x63, 0x6f, 0x6d, 0x13, 0x05, 0x68, 0x65, 0x6e, 0x6c, 0x6f}; | 
|  |  | 
|  | std::vector<AuthorityInfoAccessDescription> access_descriptions; | 
|  | EXPECT_FALSE(ParseAuthorityInfoAccess(der::Input(der), &access_descriptions)); | 
|  |  | 
|  | std::vector<std::string_view> ca_issuers_uris, ocsp_uris; | 
|  | EXPECT_FALSE(ParseAuthorityInfoAccessURIs(der::Input(der), &ca_issuers_uris, | 
|  | &ocsp_uris)); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityInfoAccess, EmptySequence) { | 
|  | // SEQUENCE { } | 
|  | const uint8_t der[] = {0x30, 0x00}; | 
|  |  | 
|  | std::vector<AuthorityInfoAccessDescription> access_descriptions; | 
|  | EXPECT_FALSE(ParseAuthorityInfoAccess(der::Input(der), &access_descriptions)); | 
|  |  | 
|  | std::vector<std::string_view> ca_issuers_uris, ocsp_uris; | 
|  | EXPECT_FALSE(ParseAuthorityInfoAccessURIs(der::Input(der), &ca_issuers_uris, | 
|  | &ocsp_uris)); | 
|  | } | 
|  |  | 
|  | // Test fixture for testing ParseCrlDistributionPoints. | 
|  | // | 
|  | // Test data is encoded in certificate files. This fixture is responsible for | 
|  | // reading and parsing the certificates to get at the extension under test. | 
|  | class ParseCrlDistributionPointsTest : public ::testing::Test { | 
|  | public: | 
|  | protected: | 
|  | bool GetCrlDps(const char *file_name, | 
|  | std::vector<ParsedDistributionPoint> *dps) { | 
|  | std::string cert_bytes; | 
|  | // Read the test certificate file. | 
|  | const PemBlockMapping mappings[] = { | 
|  | {"CERTIFICATE", &cert_bytes}, | 
|  | }; | 
|  | std::string test_file_path = GetFilePath(file_name); | 
|  | EXPECT_TRUE(ReadTestDataFromPemFile(test_file_path, mappings)); | 
|  |  | 
|  | // Extract the CRLDP from the test Certificate. | 
|  | CertErrors errors; | 
|  | std::shared_ptr<const ParsedCertificate> cert = ParsedCertificate::Create( | 
|  | bssl::UniquePtr<CRYPTO_BUFFER>(CRYPTO_BUFFER_new( | 
|  | reinterpret_cast<const uint8_t *>(cert_bytes.data()), | 
|  | cert_bytes.size(), nullptr)), | 
|  | {}, &errors); | 
|  |  | 
|  | if (!cert) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | auto it = cert->extensions().find(der::Input(kCrlDistributionPointsOid)); | 
|  | if (it == cert->extensions().end()) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | der::Input crl_dp_tlv = it->second.value; | 
|  |  | 
|  | // Keep the certificate data alive, since this function will return | 
|  | // der::Inputs that reference it. Run the function under test (for parsing | 
|  | // | 
|  | // TODO(eroman): The use of ParsedCertificate in this test should be removed | 
|  | // in lieu of lazy parsing. | 
|  | keep_alive_certs_.push_back(cert); | 
|  |  | 
|  | return ParseCrlDistributionPoints(crl_dp_tlv, dps); | 
|  | } | 
|  |  | 
|  | private: | 
|  | ParsedCertificateList keep_alive_certs_; | 
|  | }; | 
|  |  | 
|  | TEST_F(ParseCrlDistributionPointsTest, OneUriNoIssuer) { | 
|  | std::vector<ParsedDistributionPoint> dps; | 
|  | ASSERT_TRUE(GetCrlDps("crldp_1uri_noissuer.pem", &dps)); | 
|  |  | 
|  | ASSERT_EQ(1u, dps.size()); | 
|  | const ParsedDistributionPoint &dp1 = dps.front(); | 
|  |  | 
|  | ASSERT_TRUE(dp1.distribution_point_fullname); | 
|  | const GeneralNames &fullname = *dp1.distribution_point_fullname; | 
|  | EXPECT_EQ(GENERAL_NAME_UNIFORM_RESOURCE_IDENTIFIER, | 
|  | fullname.present_name_types); | 
|  | ASSERT_EQ(1u, fullname.uniform_resource_identifiers.size()); | 
|  | EXPECT_EQ(fullname.uniform_resource_identifiers.front(), | 
|  | std::string("http://www.example.com/foo.crl")); | 
|  |  | 
|  | EXPECT_FALSE(dp1.distribution_point_name_relative_to_crl_issuer); | 
|  | EXPECT_FALSE(dp1.reasons); | 
|  | EXPECT_FALSE(dp1.crl_issuer); | 
|  | } | 
|  |  | 
|  | TEST_F(ParseCrlDistributionPointsTest, ThreeUrisNoIssuer) { | 
|  | std::vector<ParsedDistributionPoint> dps; | 
|  | ASSERT_TRUE(GetCrlDps("crldp_3uri_noissuer.pem", &dps)); | 
|  |  | 
|  | ASSERT_EQ(1u, dps.size()); | 
|  | const ParsedDistributionPoint &dp1 = dps.front(); | 
|  |  | 
|  | ASSERT_TRUE(dp1.distribution_point_fullname); | 
|  | const GeneralNames &fullname = *dp1.distribution_point_fullname; | 
|  | EXPECT_EQ(GENERAL_NAME_UNIFORM_RESOURCE_IDENTIFIER, | 
|  | fullname.present_name_types); | 
|  | ASSERT_EQ(3u, fullname.uniform_resource_identifiers.size()); | 
|  | EXPECT_EQ(fullname.uniform_resource_identifiers[0], | 
|  | std::string("http://www.example.com/foo1.crl")); | 
|  | EXPECT_EQ(fullname.uniform_resource_identifiers[1], | 
|  | std::string("http://www.example.com/blah.crl")); | 
|  | EXPECT_EQ(fullname.uniform_resource_identifiers[2], | 
|  | std::string("not-even-a-url")); | 
|  |  | 
|  | EXPECT_FALSE(dp1.distribution_point_name_relative_to_crl_issuer); | 
|  | EXPECT_FALSE(dp1.reasons); | 
|  | EXPECT_FALSE(dp1.crl_issuer); | 
|  | } | 
|  |  | 
|  | TEST_F(ParseCrlDistributionPointsTest, CrlIssuerAsDirname) { | 
|  | std::vector<ParsedDistributionPoint> dps; | 
|  | ASSERT_TRUE(GetCrlDps("crldp_issuer_as_dirname.pem", &dps)); | 
|  |  | 
|  | ASSERT_EQ(1u, dps.size()); | 
|  | const ParsedDistributionPoint &dp1 = dps.front(); | 
|  | ASSERT_TRUE(dp1.distribution_point_fullname); | 
|  | const GeneralNames &fullname = *dp1.distribution_point_fullname; | 
|  | EXPECT_EQ(GENERAL_NAME_DIRECTORY_NAME, fullname.present_name_types); | 
|  | // Generated by `ascii2der | xxd -i` from the Name value in | 
|  | // crldp_issuer_as_dirname.pem. | 
|  | const uint8_t kExpectedName[] = { | 
|  | 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, | 
|  | 0x53, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x16, | 
|  | 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, | 
|  | 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x32, 0x30, 0x31, 0x31, 0x31, 0x22, | 
|  | 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x19, 0x69, 0x6e, 0x64, | 
|  | 0x69, 0x72, 0x65, 0x63, 0x74, 0x43, 0x52, 0x4c, 0x20, 0x43, 0x41, 0x33, | 
|  | 0x20, 0x63, 0x52, 0x4c, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x31, 0x29, | 
|  | 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x20, 0x69, 0x6e, 0x64, | 
|  | 0x69, 0x72, 0x65, 0x63, 0x74, 0x20, 0x43, 0x52, 0x4c, 0x20, 0x66, 0x6f, | 
|  | 0x72, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x43, 0x52, | 
|  | 0x4c, 0x20, 0x43, 0x41, 0x33}; | 
|  | ASSERT_EQ(1u, fullname.directory_names.size()); | 
|  | EXPECT_EQ(der::Input(kExpectedName), fullname.directory_names[0]); | 
|  |  | 
|  | EXPECT_FALSE(dp1.distribution_point_name_relative_to_crl_issuer); | 
|  | EXPECT_FALSE(dp1.reasons); | 
|  |  | 
|  | ASSERT_TRUE(dp1.crl_issuer); | 
|  | // Generated by `ascii2der | xxd -i` from the cRLIssuer value in | 
|  | // crldp_issuer_as_dirname.pem. | 
|  | const uint8_t kExpectedCrlIssuer[] = { | 
|  | 0xa4, 0x54, 0x30, 0x52, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, | 
|  | 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1f, 0x30, 0x1d, 0x06, | 
|  | 0x03, 0x55, 0x04, 0x0a, 0x13, 0x16, 0x54, 0x65, 0x73, 0x74, 0x20, | 
|  | 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, | 
|  | 0x73, 0x20, 0x32, 0x30, 0x31, 0x31, 0x31, 0x22, 0x30, 0x20, 0x06, | 
|  | 0x03, 0x55, 0x04, 0x0b, 0x13, 0x19, 0x69, 0x6e, 0x64, 0x69, 0x72, | 
|  | 0x65, 0x63, 0x74, 0x43, 0x52, 0x4c, 0x20, 0x43, 0x41, 0x33, 0x20, | 
|  | 0x63, 0x52, 0x4c, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72}; | 
|  | EXPECT_EQ(der::Input(kExpectedCrlIssuer), dp1.crl_issuer); | 
|  | } | 
|  |  | 
|  | TEST_F(ParseCrlDistributionPointsTest, FullnameAsDirname) { | 
|  | std::vector<ParsedDistributionPoint> dps; | 
|  | ASSERT_TRUE(GetCrlDps("crldp_full_name_as_dirname.pem", &dps)); | 
|  |  | 
|  | ASSERT_EQ(1u, dps.size()); | 
|  | const ParsedDistributionPoint &dp1 = dps.front(); | 
|  |  | 
|  | ASSERT_TRUE(dp1.distribution_point_fullname); | 
|  | const GeneralNames &fullname = *dp1.distribution_point_fullname; | 
|  | EXPECT_EQ(GENERAL_NAME_DIRECTORY_NAME, fullname.present_name_types); | 
|  | // Generated by `ascii2der | xxd -i` from the Name value in | 
|  | // crldp_full_name_as_dirname.pem. | 
|  | const uint8_t kExpectedName[] = { | 
|  | 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, | 
|  | 0x53, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x16, | 
|  | 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, | 
|  | 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x32, 0x30, 0x31, 0x31, 0x31, 0x45, | 
|  | 0x30, 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x3c, 0x53, 0x65, 0x6c, | 
|  | 0x66, 0x2d, 0x49, 0x73, 0x73, 0x75, 0x65, 0x64, 0x20, 0x43, 0x65, 0x72, | 
|  | 0x74, 0x20, 0x44, 0x50, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x42, 0x61, 0x73, | 
|  | 0x69, 0x63, 0x20, 0x53, 0x65, 0x6c, 0x66, 0x2d, 0x49, 0x73, 0x73, 0x75, | 
|  | 0x65, 0x64, 0x20, 0x43, 0x52, 0x4c, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, | 
|  | 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x43, 0x41}; | 
|  | ASSERT_EQ(1u, fullname.directory_names.size()); | 
|  | EXPECT_EQ(der::Input(kExpectedName), fullname.directory_names[0]); | 
|  |  | 
|  | EXPECT_FALSE(dp1.distribution_point_name_relative_to_crl_issuer); | 
|  | EXPECT_FALSE(dp1.reasons); | 
|  | EXPECT_FALSE(dp1.crl_issuer); | 
|  | } | 
|  |  | 
|  | TEST_F(ParseCrlDistributionPointsTest, RelativeNameAndReasonsAndMultipleDPs) { | 
|  | // SEQUENCE { | 
|  | //   SEQUENCE { | 
|  | //     # distributionPoint | 
|  | //     [0] { | 
|  | //       # nameRelativeToCRLIssuer | 
|  | //       [1] { | 
|  | //         SET { | 
|  | //           SEQUENCE { | 
|  | //             # commonName | 
|  | //             OBJECT_IDENTIFIER { 2.5.4.3 } | 
|  | //             PrintableString { "CRL1" } | 
|  | //           } | 
|  | //         } | 
|  | //       } | 
|  | //     } | 
|  | //     # reasons | 
|  | //     [1 PRIMITIVE] { b`011` } | 
|  | //   } | 
|  | //   SEQUENCE { | 
|  | //     # distributionPoint | 
|  | //     [0] { | 
|  | //       # fullName | 
|  | //       [0] { | 
|  | //         [4] { | 
|  | //           SEQUENCE { | 
|  | //             SET { | 
|  | //               SEQUENCE { | 
|  | //                 # commonName | 
|  | //                 OBJECT_IDENTIFIER { 2.5.4.3 } | 
|  | //                 PrintableString { "CRL2" } | 
|  | //               } | 
|  | //             } | 
|  | //           } | 
|  | //         } | 
|  | //       } | 
|  | //     } | 
|  | //     # reasons | 
|  | //     [1 PRIMITIVE] { b`100111111` } | 
|  | //   } | 
|  | // } | 
|  | const uint8_t kInputDer[] = { | 
|  | 0x30, 0x37, 0x30, 0x17, 0xa0, 0x11, 0xa1, 0x0f, 0x31, 0x0d, 0x30, 0x0b, | 
|  | 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x04, 0x43, 0x52, 0x4c, 0x31, 0x81, | 
|  | 0x02, 0x05, 0x60, 0x30, 0x1c, 0xa0, 0x15, 0xa0, 0x13, 0xa4, 0x11, 0x30, | 
|  | 0x0f, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x04, | 
|  | 0x43, 0x52, 0x4c, 0x32, 0x81, 0x03, 0x07, 0x9f, 0x80}; | 
|  |  | 
|  | std::vector<ParsedDistributionPoint> dps; | 
|  | ASSERT_TRUE(ParseCrlDistributionPoints(der::Input(kInputDer), &dps)); | 
|  | ASSERT_EQ(2u, dps.size()); | 
|  | { | 
|  | const ParsedDistributionPoint &dp = dps[0]; | 
|  | EXPECT_FALSE(dp.distribution_point_fullname); | 
|  |  | 
|  | ASSERT_TRUE(dp.distribution_point_name_relative_to_crl_issuer); | 
|  | // SET { | 
|  | //   SEQUENCE { | 
|  | //     # commonName | 
|  | //     OBJECT_IDENTIFIER { 2.5.4.3 } | 
|  | //     PrintableString { "CRL1" } | 
|  | //   } | 
|  | // } | 
|  | const uint8_t kExpectedRDN[] = {0x31, 0x0d, 0x30, 0x0b, 0x06, | 
|  | 0x03, 0x55, 0x04, 0x03, 0x13, | 
|  | 0x04, 0x43, 0x52, 0x4c, 0x31}; | 
|  | EXPECT_EQ(der::Input(kExpectedRDN), | 
|  | *dp.distribution_point_name_relative_to_crl_issuer); | 
|  |  | 
|  | ASSERT_TRUE(dp.reasons); | 
|  | const uint8_t kExpectedReasons[] = {0x05, 0x60}; | 
|  | EXPECT_EQ(der::Input(kExpectedReasons), *dp.reasons); | 
|  |  | 
|  | EXPECT_FALSE(dp.crl_issuer); | 
|  | } | 
|  | { | 
|  | const ParsedDistributionPoint &dp = dps[1]; | 
|  | ASSERT_TRUE(dp.distribution_point_fullname); | 
|  | const GeneralNames &fullname = *dp.distribution_point_fullname; | 
|  | EXPECT_EQ(GENERAL_NAME_DIRECTORY_NAME, fullname.present_name_types); | 
|  | // SET { | 
|  | //   SEQUENCE { | 
|  | //     # commonName | 
|  | //     OBJECT_IDENTIFIER { 2.5.4.3 } | 
|  | //     PrintableString { "CRL2" } | 
|  | //   } | 
|  | // } | 
|  | const uint8_t kExpectedName[] = {0x31, 0x0d, 0x30, 0x0b, 0x06, | 
|  | 0x03, 0x55, 0x04, 0x03, 0x13, | 
|  | 0x04, 0x43, 0x52, 0x4c, 0x32}; | 
|  | ASSERT_EQ(1u, fullname.directory_names.size()); | 
|  | EXPECT_EQ(der::Input(kExpectedName), fullname.directory_names[0]); | 
|  |  | 
|  | EXPECT_FALSE(dp.distribution_point_name_relative_to_crl_issuer); | 
|  |  | 
|  | ASSERT_TRUE(dp.reasons); | 
|  | const uint8_t kExpectedReasons[] = {0x07, 0x9f, 0x80}; | 
|  | EXPECT_EQ(der::Input(kExpectedReasons), *dp.reasons); | 
|  |  | 
|  | EXPECT_FALSE(dp.crl_issuer); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(ParseCrlDistributionPointsTest, NoDistributionPointName) { | 
|  | // SEQUENCE { | 
|  | //   SEQUENCE { | 
|  | //     # cRLIssuer | 
|  | //     [2] { | 
|  | //       [4] { | 
|  | //         SEQUENCE { | 
|  | //           SET { | 
|  | //             SEQUENCE { | 
|  | //               # organizationUnitName | 
|  | //               OBJECT_IDENTIFIER { 2.5.4.11 } | 
|  | //               PrintableString { "crl issuer" } | 
|  | //             } | 
|  | //           } | 
|  | //         } | 
|  | //       } | 
|  | //     } | 
|  | //   } | 
|  | // } | 
|  | const uint8_t kInputDer[] = {0x30, 0x1d, 0x30, 0x1b, 0xa2, 0x19, 0xa4, 0x17, | 
|  | 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, | 
|  | 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x63, 0x72, 0x6c, | 
|  | 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72}; | 
|  |  | 
|  | std::vector<ParsedDistributionPoint> dps; | 
|  | ASSERT_TRUE(ParseCrlDistributionPoints(der::Input(kInputDer), &dps)); | 
|  | ASSERT_EQ(1u, dps.size()); | 
|  | const ParsedDistributionPoint &dp = dps[0]; | 
|  | EXPECT_FALSE(dp.distribution_point_fullname); | 
|  |  | 
|  | EXPECT_FALSE(dp.distribution_point_name_relative_to_crl_issuer); | 
|  |  | 
|  | EXPECT_FALSE(dp.reasons); | 
|  |  | 
|  | ASSERT_TRUE(dp.crl_issuer); | 
|  | const uint8_t kExpectedDer[] = {0xa4, 0x17, 0x30, 0x15, 0x31, 0x13, 0x30, | 
|  | 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, | 
|  | 0x0a, 0x63, 0x72, 0x6c, 0x20, 0x69, 0x73, | 
|  | 0x73, 0x75, 0x65, 0x72}; | 
|  | EXPECT_EQ(der::Input(kExpectedDer), *dp.crl_issuer); | 
|  | } | 
|  |  | 
|  | TEST_F(ParseCrlDistributionPointsTest, OnlyReasons) { | 
|  | // SEQUENCE { | 
|  | //   SEQUENCE { | 
|  | //     # reasons | 
|  | //     [1 PRIMITIVE] { b`011` } | 
|  | //   } | 
|  | // } | 
|  | const uint8_t kInputDer[] = {0x30, 0x06, 0x30, 0x04, 0x81, 0x02, 0x05, 0x60}; | 
|  |  | 
|  | std::vector<ParsedDistributionPoint> dps; | 
|  | EXPECT_FALSE(ParseCrlDistributionPoints(der::Input(kInputDer), &dps)); | 
|  | } | 
|  |  | 
|  | TEST_F(ParseCrlDistributionPointsTest, EmptyDistributionPoint) { | 
|  | // SEQUENCE { | 
|  | //   SEQUENCE { | 
|  | //   } | 
|  | // } | 
|  | const uint8_t kInputDer[] = {0x30, 0x02, 0x30, 0x00}; | 
|  |  | 
|  | std::vector<ParsedDistributionPoint> dps; | 
|  | EXPECT_FALSE(ParseCrlDistributionPoints(der::Input(kInputDer), &dps)); | 
|  | } | 
|  |  | 
|  | TEST_F(ParseCrlDistributionPointsTest, EmptyDistributionPoints) { | 
|  | // SEQUENCE { } | 
|  | const uint8_t kInputDer[] = {0x30, 0x00}; | 
|  |  | 
|  | std::vector<ParsedDistributionPoint> dps; | 
|  | EXPECT_FALSE(ParseCrlDistributionPoints(der::Input(kInputDer), &dps)); | 
|  | } | 
|  |  | 
|  | bool ParseAuthorityKeyIdentifierTestData( | 
|  | const char *file_name, std::string *backing_bytes, | 
|  | ParsedAuthorityKeyIdentifier *authority_key_identifier) { | 
|  | // Read the test file. | 
|  | const PemBlockMapping mappings[] = { | 
|  | {"AUTHORITY_KEY_IDENTIFIER", backing_bytes}, | 
|  | }; | 
|  | std::string test_file_path = | 
|  | std::string( | 
|  | "testdata/parse_certificate_unittest/authority_key_identifier/") + | 
|  | file_name; | 
|  | EXPECT_TRUE(ReadTestDataFromPemFile(test_file_path, mappings)); | 
|  |  | 
|  | return ParseAuthorityKeyIdentifier(der::Input(*backing_bytes), | 
|  | authority_key_identifier); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityKeyIdentifierTest, EmptyInput) { | 
|  | ParsedAuthorityKeyIdentifier authority_key_identifier; | 
|  | EXPECT_FALSE( | 
|  | ParseAuthorityKeyIdentifier(der::Input(), &authority_key_identifier)); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityKeyIdentifierTest, EmptySequence) { | 
|  | std::string backing_bytes; | 
|  | ParsedAuthorityKeyIdentifier authority_key_identifier; | 
|  | // TODO(mattm): should this be an error? RFC 5280 doesn't explicitly say it. | 
|  | ASSERT_TRUE(ParseAuthorityKeyIdentifierTestData( | 
|  | "empty_sequence.pem", &backing_bytes, &authority_key_identifier)); | 
|  |  | 
|  | EXPECT_FALSE(authority_key_identifier.key_identifier); | 
|  | EXPECT_FALSE(authority_key_identifier.authority_cert_issuer); | 
|  | EXPECT_FALSE(authority_key_identifier.authority_cert_serial_number); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityKeyIdentifierTest, KeyIdentifier) { | 
|  | std::string backing_bytes; | 
|  | ParsedAuthorityKeyIdentifier authority_key_identifier; | 
|  | ASSERT_TRUE(ParseAuthorityKeyIdentifierTestData( | 
|  | "key_identifier.pem", &backing_bytes, &authority_key_identifier)); | 
|  |  | 
|  | ASSERT_TRUE(authority_key_identifier.key_identifier); | 
|  | const uint8_t kExpectedValue[] = {0xDE, 0xAD, 0xB0, 0x0F}; | 
|  | EXPECT_EQ(der::Input(kExpectedValue), | 
|  | authority_key_identifier.key_identifier); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityKeyIdentifierTest, IssuerAndSerial) { | 
|  | std::string backing_bytes; | 
|  | ParsedAuthorityKeyIdentifier authority_key_identifier; | 
|  | ASSERT_TRUE(ParseAuthorityKeyIdentifierTestData( | 
|  | "issuer_and_serial.pem", &backing_bytes, &authority_key_identifier)); | 
|  |  | 
|  | EXPECT_FALSE(authority_key_identifier.key_identifier); | 
|  |  | 
|  | ASSERT_TRUE(authority_key_identifier.authority_cert_issuer); | 
|  | const uint8_t kExpectedIssuer[] = {0xa4, 0x11, 0x30, 0x0f, 0x31, 0x0d, 0x30, | 
|  | 0x0b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, | 
|  | 0x04, 0x52, 0x6f, 0x6f, 0x74}; | 
|  | EXPECT_EQ(der::Input(kExpectedIssuer), | 
|  | authority_key_identifier.authority_cert_issuer); | 
|  |  | 
|  | ASSERT_TRUE(authority_key_identifier.authority_cert_serial_number); | 
|  | const uint8_t kExpectedSerial[] = {0x27, 0x4F}; | 
|  | EXPECT_EQ(der::Input(kExpectedSerial), | 
|  | authority_key_identifier.authority_cert_serial_number); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityKeyIdentifierTest, KeyIdentifierAndIssuerAndSerial) { | 
|  | std::string backing_bytes; | 
|  | ParsedAuthorityKeyIdentifier authority_key_identifier; | 
|  | ASSERT_TRUE(ParseAuthorityKeyIdentifierTestData( | 
|  | "key_identifier_and_issuer_and_serial.pem", &backing_bytes, | 
|  | &authority_key_identifier)); | 
|  |  | 
|  | ASSERT_TRUE(authority_key_identifier.key_identifier); | 
|  | const uint8_t kExpectedValue[] = {0xDE, 0xAD, 0xB0, 0x0F}; | 
|  | EXPECT_EQ(der::Input(kExpectedValue), | 
|  | authority_key_identifier.key_identifier); | 
|  |  | 
|  | ASSERT_TRUE(authority_key_identifier.authority_cert_issuer); | 
|  | const uint8_t kExpectedIssuer[] = {0xa4, 0x11, 0x30, 0x0f, 0x31, 0x0d, 0x30, | 
|  | 0x0b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, | 
|  | 0x04, 0x52, 0x6f, 0x6f, 0x74}; | 
|  | EXPECT_EQ(der::Input(kExpectedIssuer), | 
|  | authority_key_identifier.authority_cert_issuer); | 
|  |  | 
|  | ASSERT_TRUE(authority_key_identifier.authority_cert_serial_number); | 
|  | const uint8_t kExpectedSerial[] = {0x27, 0x4F}; | 
|  | EXPECT_EQ(der::Input(kExpectedSerial), | 
|  | authority_key_identifier.authority_cert_serial_number); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityKeyIdentifierTest, IssuerOnly) { | 
|  | std::string backing_bytes; | 
|  | ParsedAuthorityKeyIdentifier authority_key_identifier; | 
|  | EXPECT_FALSE(ParseAuthorityKeyIdentifierTestData( | 
|  | "issuer_only.pem", &backing_bytes, &authority_key_identifier)); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityKeyIdentifierTest, SerialOnly) { | 
|  | std::string backing_bytes; | 
|  | ParsedAuthorityKeyIdentifier authority_key_identifier; | 
|  | EXPECT_FALSE(ParseAuthorityKeyIdentifierTestData( | 
|  | "serial_only.pem", &backing_bytes, &authority_key_identifier)); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityKeyIdentifierTest, InvalidContents) { | 
|  | std::string backing_bytes; | 
|  | ParsedAuthorityKeyIdentifier authority_key_identifier; | 
|  | EXPECT_FALSE(ParseAuthorityKeyIdentifierTestData( | 
|  | "invalid_contents.pem", &backing_bytes, &authority_key_identifier)); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityKeyIdentifierTest, InvalidKeyIdentifier) { | 
|  | std::string backing_bytes; | 
|  | ParsedAuthorityKeyIdentifier authority_key_identifier; | 
|  | EXPECT_FALSE(ParseAuthorityKeyIdentifierTestData( | 
|  | "invalid_key_identifier.pem", &backing_bytes, &authority_key_identifier)); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityKeyIdentifierTest, InvalidIssuer) { | 
|  | std::string backing_bytes; | 
|  | ParsedAuthorityKeyIdentifier authority_key_identifier; | 
|  | EXPECT_FALSE(ParseAuthorityKeyIdentifierTestData( | 
|  | "invalid_issuer.pem", &backing_bytes, &authority_key_identifier)); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityKeyIdentifierTest, InvalidSerial) { | 
|  | std::string backing_bytes; | 
|  | ParsedAuthorityKeyIdentifier authority_key_identifier; | 
|  | EXPECT_FALSE(ParseAuthorityKeyIdentifierTestData( | 
|  | "invalid_serial.pem", &backing_bytes, &authority_key_identifier)); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityKeyIdentifierTest, ExtraContentsAfterIssuerAndSerial) { | 
|  | std::string backing_bytes; | 
|  | ParsedAuthorityKeyIdentifier authority_key_identifier; | 
|  | EXPECT_FALSE(ParseAuthorityKeyIdentifierTestData( | 
|  | "extra_contents_after_issuer_and_serial.pem", &backing_bytes, | 
|  | &authority_key_identifier)); | 
|  | } | 
|  |  | 
|  | TEST(ParseAuthorityKeyIdentifierTest, ExtraContentsAfterExtensionSequence) { | 
|  | std::string backing_bytes; | 
|  | ParsedAuthorityKeyIdentifier authority_key_identifier; | 
|  | EXPECT_FALSE(ParseAuthorityKeyIdentifierTestData( | 
|  | "extra_contents_after_extension_sequence.pem", &backing_bytes, | 
|  | &authority_key_identifier)); | 
|  | } | 
|  |  | 
|  | TEST(ParseSubjectKeyIdentifierTest, EmptyInput) { | 
|  | der::Input subject_key_identifier; | 
|  | EXPECT_FALSE( | 
|  | ParseSubjectKeyIdentifier(der::Input(), &subject_key_identifier)); | 
|  | } | 
|  |  | 
|  | TEST(ParseSubjectKeyIdentifierTest, Valid) { | 
|  | // OCTET_STRING {`abcd`} | 
|  | const uint8_t kInput[] = {0x04, 0x02, 0xab, 0xcd}; | 
|  | const uint8_t kExpected[] = {0xab, 0xcd}; | 
|  | der::Input subject_key_identifier; | 
|  | EXPECT_TRUE( | 
|  | ParseSubjectKeyIdentifier(der::Input(kInput), &subject_key_identifier)); | 
|  | EXPECT_EQ(der::Input(kExpected), subject_key_identifier); | 
|  | } | 
|  |  | 
|  | TEST(ParseSubjectKeyIdentifierTest, ExtraData) { | 
|  | // OCTET_STRING {`abcd`} | 
|  | // NULL | 
|  | const uint8_t kInput[] = {0x04, 0x02, 0xab, 0xcd, 0x05}; | 
|  | der::Input subject_key_identifier; | 
|  | EXPECT_FALSE( | 
|  | ParseSubjectKeyIdentifier(der::Input(kInput), &subject_key_identifier)); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | BSSL_NAMESPACE_END |