1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "net/cert/internal/test_helpers.h"
11
12 #include "base/base_paths.h"
13 #include "base/files/file_util.h"
14 #include "base/path_service.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "third_party/boringssl/src/include/openssl/pool.h"
17 #include "third_party/boringssl/src/pki/cert_errors.h"
18 #include "third_party/boringssl/src/pki/pem.h"
19
20 namespace net {
21
ReadTestDataFromPemFile(const std::string & file_path_ascii,const PemBlockMapping * mappings,size_t mappings_length)22 ::testing::AssertionResult ReadTestDataFromPemFile(
23 const std::string& file_path_ascii,
24 const PemBlockMapping* mappings,
25 size_t mappings_length) {
26 std::string file_data = ReadTestFileToString(file_path_ascii);
27
28 // mappings_copy is used to keep track of which mappings have already been
29 // satisfied (by nulling the |value| field). This is used to track when
30 // blocks are multiply defined.
31 std::vector<PemBlockMapping> mappings_copy(mappings,
32 mappings + mappings_length);
33
34 // Build the |pem_headers| vector needed for PEMTokenzier.
35 std::vector<std::string> pem_headers;
36 for (const auto& mapping : mappings_copy) {
37 pem_headers.push_back(mapping.block_name);
38 }
39
40 bssl::PEMTokenizer pem_tokenizer(file_data, pem_headers);
41 while (pem_tokenizer.GetNext()) {
42 for (auto& mapping : mappings_copy) {
43 // Find the mapping for this block type.
44 if (pem_tokenizer.block_type() == mapping.block_name) {
45 if (!mapping.value) {
46 return ::testing::AssertionFailure()
47 << "PEM block defined multiple times: " << mapping.block_name;
48 }
49
50 // Copy the data to the result.
51 mapping.value->assign(pem_tokenizer.data());
52
53 // Mark the mapping as having been satisfied.
54 mapping.value = nullptr;
55 }
56 }
57 }
58
59 // Ensure that all specified blocks were found.
60 for (const auto& mapping : mappings_copy) {
61 if (mapping.value && !mapping.optional) {
62 return ::testing::AssertionFailure()
63 << "PEM block missing: " << mapping.block_name;
64 }
65 }
66
67 return ::testing::AssertionSuccess();
68 }
69
ReadCertChainFromFile(const std::string & file_path_ascii,bssl::ParsedCertificateList * chain)70 bool ReadCertChainFromFile(const std::string& file_path_ascii,
71 bssl::ParsedCertificateList* chain) {
72 // Reset all the out parameters to their defaults.
73 chain->clear();
74
75 std::string file_data = ReadTestFileToString(file_path_ascii);
76 if (file_data.empty()) {
77 return false;
78 }
79
80 std::vector<std::string> pem_headers = {"CERTIFICATE"};
81
82 bssl::PEMTokenizer pem_tokenizer(file_data, pem_headers);
83 while (pem_tokenizer.GetNext()) {
84 const std::string& block_data = pem_tokenizer.data();
85
86 bssl::CertErrors errors;
87 if (!bssl::ParsedCertificate::CreateAndAddToVector(
88 bssl::UniquePtr<CRYPTO_BUFFER>(CRYPTO_BUFFER_new(
89 reinterpret_cast<const uint8_t*>(block_data.data()),
90 block_data.size(), nullptr)),
91 {}, chain, &errors)) {
92 ADD_FAILURE() << errors.ToDebugString();
93 return false;
94 }
95 }
96
97 return true;
98 }
99
ReadCertFromFile(const std::string & file_path_ascii)100 std::shared_ptr<const bssl::ParsedCertificate> ReadCertFromFile(
101 const std::string& file_path_ascii) {
102 bssl::ParsedCertificateList chain;
103 if (!ReadCertChainFromFile(file_path_ascii, &chain)) {
104 return nullptr;
105 }
106 if (chain.size() != 1) {
107 return nullptr;
108 }
109 return chain[0];
110 }
111
ReadTestFileToString(const std::string & file_path_ascii)112 std::string ReadTestFileToString(const std::string& file_path_ascii) {
113 // Compute the full path, relative to the src/ directory.
114 base::FilePath src_root;
115 base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &src_root);
116 base::FilePath filepath = src_root.AppendASCII(file_path_ascii);
117
118 // Read the full contents of the file.
119 std::string file_data;
120 if (!base::ReadFileToString(filepath, &file_data)) {
121 ADD_FAILURE() << "Couldn't read file: " << filepath.value();
122 return std::string();
123 }
124
125 return file_data;
126 }
127
128 } // namespace net
129