Chromium Code Reviews| 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 |