OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/cert/internal/parse_certificate.h" | |
6 | |
7 #include "base/base64.h" | |
8 #include "base/base_paths.h" | |
9 #include "base/files/file_util.h" | |
10 #include "base/path_service.h" | |
11 #include "net/base/test_data_directory.h" | |
12 #include "net/cert/pem_tokenizer.h" | |
13 #include "net/der/input.h" | |
14 #include "testing/gtest/include/gtest/gtest.h" | |
15 | |
16 namespace net { | |
17 | |
18 namespace der { | |
19 | |
20 // These functions are used by GTEST to support EXPECT_EQ() for | |
davidben
2015/08/11 20:31:57
Nit: I think GTest is the more common capitalizati
eroman
2015/08/12 00:37:10
Done.
| |
21 // der::Input. | |
22 | |
23 void PrintTo(const Input& data, ::std::ostream* os) { | |
davidben
2015/08/11 20:31:57
#include <ostream>
eroman
2015/08/12 00:37:10
Done.
| |
24 std::string b64; | |
25 base::Base64Encode( | |
26 base::StringPiece(reinterpret_cast<const char*>(data.UnsafeData()), | |
27 data.Length()), | |
28 &b64); | |
29 | |
30 *os << "[" << b64 << "]"; | |
31 } | |
32 | |
33 bool operator==(const Input& a, const Input& b) { | |
34 return a.Equals(b); | |
35 } | |
36 | |
37 } // namespace der | |
38 | |
39 namespace { | |
40 | |
41 // Returns a path to the file |file_name| within the unittest data directory. | |
42 base::FilePath GetTestFilePath(const std::string& file_name) { | |
43 base::FilePath src_root; | |
44 PathService::Get(base::DIR_SOURCE_ROOT, &src_root); | |
45 return src_root.Append( | |
46 FILE_PATH_LITERAL("net/data/parse_certificate_unittest")) | |
47 .AppendASCII(file_name); | |
48 } | |
49 | |
50 // Contains the expected values in a ParsedCertificate. | |
51 struct ParsedCertificateExpectations { | |
52 std::string signature; | |
53 std::string signature_algorithm; | |
54 }; | |
55 | |
56 // Contains the expected values in a ParsedTbsCertificate. | |
57 struct ParsedTbsCertificateExpectations { | |
58 std::string serial_number; | |
59 std::string signature_algorithm; | |
60 std::string issuer; | |
61 std::string validity; | |
62 std::string subject; | |
63 std::string spki; | |
64 std::string extensions; | |
65 }; | |
66 | |
67 // Reads a test file |file_name| which contains both a certificate | |
68 // (CERTIFICATE), and all the expected values for the parsed files (like SPKI). | |
69 // On success fills |cert| with the cert DER data, and fills | |
70 // |cert_expectations| and |tbs_expectations| with the expected values for its | |
71 // consitituent fields. | |
72 ::testing::AssertionResult LoadTestCertificatePemData( | |
73 const std::string& file_name, | |
74 std::string* cert, | |
75 ParsedCertificateExpectations* cert_expectations, | |
76 ParsedTbsCertificateExpectations* tbs_expectations) { | |
77 base::FilePath path = GetTestFilePath(file_name); | |
78 std::string file_data; | |
79 if (!base::ReadFileToString(path, &file_data)) { | |
80 return ::testing::AssertionFailure() << "Couldn't read file: " | |
81 << path.value(); | |
82 } | |
83 | |
84 const char kCertificateBlock[] = "CERTIFICATE"; | |
85 const char kSignatureBlock[] = "SIGNATURE"; | |
86 const char kSignatureAlgorithmBlock[] = "SIGNATURE ALGORITHM"; | |
87 const char kSerialNumber[] = "SERIAL NUMBER"; | |
88 const char kIssuerBlock[] = "ISSUER"; | |
89 const char kValidityBlock[] = "VALIDITY"; | |
90 const char kSubjectBlock[] = "SUBJECT"; | |
91 const char kSpkiBlock[] = "SPKI"; | |
92 const char kExtensionsBlock[] = "EXTENSIONS"; | |
93 | |
94 std::vector<std::string> pem_headers; | |
95 pem_headers.push_back(kCertificateBlock); | |
96 pem_headers.push_back(kSignatureBlock); | |
97 pem_headers.push_back(kSignatureAlgorithmBlock); | |
98 pem_headers.push_back(kSerialNumber); | |
99 pem_headers.push_back(kIssuerBlock); | |
100 pem_headers.push_back(kValidityBlock); | |
101 pem_headers.push_back(kSubjectBlock); | |
102 pem_headers.push_back(kSpkiBlock); | |
103 pem_headers.push_back(kExtensionsBlock); | |
104 | |
105 PEMTokenizer pem_tokenizer(file_data, pem_headers); | |
106 while (pem_tokenizer.GetNext()) { | |
107 const std::string& block_type = pem_tokenizer.block_type(); | |
108 if (block_type == kCertificateBlock) { | |
109 cert->assign(pem_tokenizer.data()); | |
110 } else if (block_type == kSignatureBlock) { | |
111 cert_expectations->signature.assign(pem_tokenizer.data()); | |
112 } else if (block_type == kSignatureAlgorithmBlock) { | |
113 cert_expectations->signature_algorithm.assign(pem_tokenizer.data()); | |
114 tbs_expectations->signature_algorithm.assign(pem_tokenizer.data()); | |
115 } else if (block_type == kSerialNumber) { | |
116 tbs_expectations->serial_number.assign(pem_tokenizer.data()); | |
117 } else if (block_type == kIssuerBlock) { | |
118 tbs_expectations->issuer.assign(pem_tokenizer.data()); | |
119 } else if (block_type == kValidityBlock) { | |
120 tbs_expectations->validity.assign(pem_tokenizer.data()); | |
121 } else if (block_type == kSubjectBlock) { | |
122 tbs_expectations->subject.assign(pem_tokenizer.data()); | |
123 } else if (block_type == kSpkiBlock) { | |
124 tbs_expectations->spki.assign(pem_tokenizer.data()); | |
125 } else if (block_type == kExtensionsBlock) { | |
126 tbs_expectations->extensions.assign(pem_tokenizer.data()); | |
127 } | |
128 } | |
129 | |
130 return ::testing::AssertionSuccess(); | |
131 } | |
132 | |
133 // TODO(eroman): This function was copied from verify_signed_data_unittest.cc | |
134 // | |
135 // Creates a der::Input from an std::string. The lifetimes are a bit subtle | |
136 // when using this function: | |
137 // | |
138 // The returned der::Input() is only valid so long as the input string is alive | |
139 // and is not mutated. | |
140 // | |
141 // Note that the input parameter has been made a pointer to prevent callers | |
142 // from accidentally passing an r-value. | |
143 der::Input InputFromString(const std::string* s) { | |
144 return der::Input(reinterpret_cast<const uint8_t*>(s->data()), s->size()); | |
145 } | |
146 | |
147 // Verifies that the given |cert| matches |expectations|. | |
148 void EnsureParsedCertificate( | |
149 const ParsedCertificate& cert, | |
150 const ParsedCertificateExpectations& expectations) { | |
151 EXPECT_EQ(0, cert.signature_value.unused_bits()); | |
152 EXPECT_EQ(InputFromString(&expectations.signature), | |
153 cert.signature_value.bytes()); | |
154 EXPECT_EQ(InputFromString(&expectations.signature_algorithm), | |
155 cert.signature_algorithm_tlv); | |
156 } | |
157 | |
158 // Verifies that the given |tbs| matches |expectations|. | |
159 void EnsureParsedTbsCertificate( | |
160 const ParsedTbsCertificate& tbs, | |
161 const ParsedTbsCertificateExpectations& expectations, | |
162 CertificateVersion expected_version) { | |
163 EXPECT_EQ(expected_version, tbs.version); | |
164 | |
165 EXPECT_EQ(InputFromString(&expectations.serial_number), tbs.serial_number); | |
166 EXPECT_EQ(InputFromString(&expectations.signature_algorithm), | |
167 tbs.signature_algorithm_tlv); | |
168 | |
169 EXPECT_EQ(InputFromString(&expectations.issuer), tbs.issuer_tlv); | |
170 EXPECT_EQ(InputFromString(&expectations.validity), tbs.validity_tlv); | |
171 EXPECT_EQ(InputFromString(&expectations.subject), tbs.subject_tlv); | |
172 EXPECT_EQ(InputFromString(&expectations.spki), tbs.spki_tlv); | |
173 | |
174 EXPECT_FALSE(tbs.has_issuer_unique_id); | |
175 EXPECT_FALSE(tbs.has_subject_unique_id); | |
176 | |
177 EXPECT_EQ(InputFromString(&expectations.extensions), tbs.extensions_tlv); | |
178 EXPECT_EQ(!expectations.extensions.empty(), tbs.has_extensions); | |
179 } | |
180 | |
181 // Loads certificate data from the PEM file |file_name| and verifies that both | |
182 // parsing the Certificate and TBSCertificate succeed. Upon return |cert| and | |
183 // |tbs| are filled accordingly. | |
184 void EnsureParsingTbsSucceds(const std::string& file_name, | |
185 CertificateVersion expected_version) { | |
186 std::string cert_data; | |
187 ParsedCertificateExpectations cert_expectations; | |
188 ParsedTbsCertificateExpectations tbs_expectations; | |
189 | |
190 // Read the certificate data and test expectations from a single PEM file. | |
191 ASSERT_TRUE(LoadTestCertificatePemData( | |
192 file_name, &cert_data, &cert_expectations, &tbs_expectations)); | |
193 | |
194 // Parsing the certificate should succeed. | |
195 ParsedCertificate cert; | |
196 ASSERT_TRUE(ParseCertificate(InputFromString(&cert_data), &cert)); | |
197 | |
198 // Ensure that the ParsedCertificate matches expectations. | |
199 EnsureParsedCertificate(cert, cert_expectations); | |
200 | |
201 ParsedTbsCertificate tbs; | |
202 ASSERT_TRUE(ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs)); | |
203 | |
204 // Ensure that the ParsedTbdCertificate matches expectations. | |
205 EnsureParsedTbsCertificate(tbs, tbs_expectations, expected_version); | |
206 } | |
207 | |
208 // Loads certificate data from the PEM file |file_name| and verifies that the | |
209 // Certificate parsing succeed, however the TBSCertificate parsing fails. | |
210 void EnsureParsingTbsFails(const std::string& file_name) { | |
211 std::string cert_data; | |
212 ParsedCertificateExpectations cert_expectations; | |
213 ParsedTbsCertificateExpectations tbs_expectations; | |
214 | |
215 ASSERT_TRUE(LoadTestCertificatePemData( | |
216 file_name, &cert_data, &cert_expectations, &tbs_expectations)); | |
217 | |
218 ParsedCertificate cert; | |
219 ASSERT_TRUE(ParseCertificate(InputFromString(&cert_data), &cert)); | |
220 | |
221 EnsureParsedCertificate(cert, cert_expectations); | |
222 | |
223 ParsedTbsCertificate tbs; | |
224 ASSERT_FALSE(ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs)); | |
225 } | |
226 | |
227 // Tests parsing a TBSCertificate with a negative serial number. | |
228 // | |
229 // CAs are not supposed to include negative serial numbers, however RFC 5280 | |
230 // says that consumers should be expected to deal with them (so they are allowed | |
231 // by ParseTbsCertificate()). | |
232 TEST(ParseCertificateTest, NegativeSerialNumber) { | |
233 EnsureParsingTbsSucceds("negative_serial.pem", CertificateVersion::V3); | |
234 } | |
235 | |
236 // Tests parsing a TBSCertificate with a serial number that is 21 octets long | |
237 // (and the first byte is 0). | |
238 TEST(ParseCertificateTest, SerialNumber21OctetsLeading0) { | |
239 EnsureParsingTbsFails("serial_number_21_octets_leading_0.pem"); | |
240 } | |
241 | |
242 // Tests parsing a TBSCertificate with a serial number that is 26 octets long | |
243 // (and does not contain a leading 0). | |
244 TEST(ParseCertificateTest, SerialNumber26Octets) { | |
245 EnsureParsingTbsFails("serial_number_26_octets.pem"); | |
246 } | |
247 | |
248 // Tests parsing a TBSCertificate which lacks a version number (causing it to | |
249 // default to v1). | |
250 TEST(ParseCertificateTest, CertificateVersion1) { | |
251 EnsureParsingTbsSucceds("version1.pem", CertificateVersion::V1); | |
252 } | |
253 | |
254 // Tests parsing a TBSCertificate with version 3. | |
255 TEST(ParseCertificateTest, CertificateVersion3) { | |
256 EnsureParsingTbsSucceds("version3.pem", CertificateVersion::V3); | |
257 } | |
258 | |
259 } // namespace | |
260 | |
261 } // namespace net | |
OLD | NEW |