| Index: net/cert/internal/verify_certificate_chain_unittest.cc | 
| diff --git a/net/cert/internal/verify_certificate_chain_unittest.cc b/net/cert/internal/verify_certificate_chain_unittest.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..12bf274c32096034d3eb15028196907527d57acb | 
| --- /dev/null | 
| +++ b/net/cert/internal/verify_certificate_chain_unittest.cc | 
| @@ -0,0 +1,187 @@ | 
| +// Copyright 2015 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "net/cert/internal/verify_certificate_chain.h" | 
| + | 
| +#include "base/base_paths.h" | 
| +#include "base/files/file_util.h" | 
| +#include "base/path_service.h" | 
| +#include "base/strings/string_split.h" | 
| +#include "base/strings/string_util.h" | 
| +#include "base/strings/stringprintf.h" | 
| +#include "net/cert/internal/parse_certificate.h" | 
| +#include "net/cert/internal/signature_policy.h" | 
| +#include "net/cert/internal/test_helpers.h" | 
| +#include "net/cert/pem_tokenizer.h" | 
| +#include "net/der/input.h" | 
| +#include "testing/gtest/include/gtest/gtest.h" | 
| + | 
| +namespace net { | 
| + | 
| +namespace { | 
| + | 
| +// Reads a data file from the unit-test data. | 
| +std::string ReadTestFileToString(const std::string& file_name) { | 
| +  // Compute the full path, relative to the src/ directory. | 
| +  base::FilePath src_root; | 
| +  PathService::Get(base::DIR_SOURCE_ROOT, &src_root); | 
| +  base::FilePath filepath = src_root.AppendASCII( | 
| +      std::string("net/data/verify_certificate_chain_unittest/") + file_name); | 
| + | 
| +  // Read the full contents of the file. | 
| +  std::string file_data; | 
| +  if (!base::ReadFileToString(filepath, &file_data)) { | 
| +    ADD_FAILURE() << "Couldn't read file: " << filepath.value(); | 
| +    return std::string(); | 
| +  } | 
| + | 
| +  return file_data; | 
| +} | 
| + | 
| +// Adds the certificate |cert_der| as a trusted root in |trust_store|. | 
| +void AddCertificateToTrustStore(const std::string& cert_der, | 
| +                                TrustStore* trust_store) { | 
| +  ParsedCertificate cert; | 
| +  ASSERT_TRUE(ParseCertificate(InputFromString(&cert_der), &cert)); | 
| + | 
| +  ParsedTbsCertificate tbs; | 
| +  ASSERT_TRUE(ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs)); | 
| +  TrustedRoot root = {tbs.spki_tlv.AsString(), tbs.subject_tlv.AsString()}; | 
| +  trust_store->roots.push_back(root); | 
| +} | 
| + | 
| +// Reads a test case from |file_name|. Test cases are comprised of a | 
| +// certificate chain, trust store, and timestamp to validate at. | 
| +void ReadTestFromFile(const std::string& file_name, | 
| +                      std::vector<std::string>* chain, | 
| +                      TrustStore* trust_store, | 
| +                      der::GeneralizedTime* time, | 
| +                      bool* verify_result) { | 
| +  chain->clear(); | 
| +  *trust_store = TrustStore(); | 
| + | 
| +  std::string file_data = ReadTestFileToString(file_name); | 
| + | 
| +  std::vector<std::string> pem_headers; | 
| + | 
| +  const char kCertificateHeader[] = "CERTIFICATE"; | 
| +  const char kTrustedCertificateHeader[] = "TRUSTED_CERTIFICATE"; | 
| +  const char kTimeHeader[] = "TIME"; | 
| +  const char kResultHeader[] = "VERIFY_RESULT"; | 
| + | 
| +  pem_headers.push_back(kCertificateHeader); | 
| +  pem_headers.push_back(kTrustedCertificateHeader); | 
| +  pem_headers.push_back(kTimeHeader); | 
| +  pem_headers.push_back(kResultHeader); | 
| + | 
| +  bool has_time = false; | 
| +  bool has_result = false; | 
| + | 
| +  PEMTokenizer pem_tokenizer(file_data, pem_headers); | 
| +  while (pem_tokenizer.GetNext()) { | 
| +    const std::string& block_type = pem_tokenizer.block_type(); | 
| +    const std::string& block_data = pem_tokenizer.data(); | 
| + | 
| +    if (block_type == kCertificateHeader) { | 
| +      chain->push_back(block_data); | 
| +    } else if (block_type == kTrustedCertificateHeader) { | 
| +      AddCertificateToTrustStore(block_data, trust_store); | 
| +    } else if (block_type == kTimeHeader) { | 
| +      ASSERT_FALSE(has_time) << "Duplicate " << kTimeHeader; | 
| +      has_time = true; | 
| +      ASSERT_TRUE(der::ParseUTCTime(InputFromString(&block_data), time)); | 
| +    } else if (block_type == kResultHeader) { | 
| +      ASSERT_FALSE(has_result) << "Duplicate " << kResultHeader; | 
| +      has_result = true; | 
| +      *verify_result = block_data == "SUCCESS"; | 
| +    } | 
| +  } | 
| + | 
| +  ASSERT_TRUE(has_time); | 
| +  ASSERT_TRUE(has_result); | 
| +} | 
| + | 
| +void RunTest(const char* file_name) { | 
| +  std::vector<std::string> chain; | 
| +  TrustStore trust_store; | 
| +  der::GeneralizedTime time; | 
| +  bool expected_result; | 
| + | 
| +  ReadTestFromFile(file_name, &chain, &trust_store, &time, &expected_result); | 
| + | 
| +  std::vector<der::Input> input_chain; | 
| +  for (const auto& cert_str : chain) | 
| +    input_chain.push_back(InputFromString(&cert_str)); | 
| + | 
| +  SimpleSignaturePolicy signature_policy(2048); | 
| + | 
| +  bool result = | 
| +      VerifyCertificateChain(input_chain, trust_store, &signature_policy, time); | 
| + | 
| +  ASSERT_EQ(expected_result, result); | 
| +} | 
| + | 
| +TEST(VerifyCertificateChainTest, TargetAndIntermediary) { | 
| +  RunTest("target-and-intermediary.pem"); | 
| +} | 
| + | 
| +TEST(VerifyCertificateChainTest, UnknownRoot) { | 
| +  RunTest("unknown-root.pem"); | 
| +} | 
| + | 
| +TEST(VerifyCertificateChainTest, IntermediaryLacksBasicConstraints) { | 
| +  RunTest("intermediary-lacks-basic-constraints.pem"); | 
| +} | 
| + | 
| +TEST(VerifyCertificateChainTest, IntermediaryBasicConstraintsCaFalse) { | 
| +  RunTest("intermediary-basic-constraints-ca-false.pem"); | 
| +} | 
| + | 
| +TEST(VerifyCertificateChainTest, IntermediaryBasicConstraintsNotCritical) { | 
| +  RunTest("intermediary-basic-constraints-not-critical.pem"); | 
| +} | 
| + | 
| +TEST(VerifyCertificateChainTest, IntermediaryLacksSigningKeyUsage) { | 
| +  RunTest("intermediary-lacks-signing-key-usage.pem"); | 
| +} | 
| + | 
| +TEST(VerifyCertificateChainTest, IntermediaryUnknownCriticalExtension) { | 
| +  RunTest("intermediary-unknown-critical-extension.pem"); | 
| +} | 
| + | 
| +TEST(VerifyCertificateChainTest, IntermediaryUnknownNonCriticalExtension) { | 
| +  RunTest("intermediary-unknown-non-critical-extension.pem"); | 
| +} | 
| + | 
| +TEST(VerifyCertificateChainTest, ViolatesBasicConstraintsPathlen0) { | 
| +  RunTest("violates-basic-constraints-pathlen-0.pem"); | 
| +} | 
| + | 
| +TEST(VerifyCertificateChainTest, BasicConstraintsPathlen0SelfIssued) { | 
| +  RunTest("basic-constraints-pathlen-0-self-issued.pem"); | 
| +} | 
| + | 
| +TEST(VerifyCertificateChainTest, TargetSignedWithMd5) { | 
| +  RunTest("target-signed-with-md5.pem"); | 
| +} | 
| + | 
| +TEST(VerifyCertificateChainTest, IntermediarySignedWithMd5) { | 
| +  RunTest("intermediary-signed-with-md5.pem"); | 
| +} | 
| + | 
| +TEST(VerifyCertificateChainTest, TargetWrongSignature) { | 
| +  RunTest("target-wrong-signature.pem"); | 
| +} | 
| + | 
| +TEST(VerifyCertificateChainTest, TargetSignedBy512bitRsa) { | 
| +  RunTest("target-signed-by-512bit-rsa.pem"); | 
| +} | 
| + | 
| +TEST(VerifyCertificateChainTest, TargetSignedUsingEcdsa) { | 
| +  RunTest("target-signed-using-ecdsa.py"); | 
| +} | 
| + | 
| +}  // namespace | 
| + | 
| +}  // namespace net | 
|  |