OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 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 <string> |
| 6 #include <vector> |
| 7 |
| 8 #include "net/tools/transport_security_state_generator/input_file_parsers.h" |
| 9 #include "net/tools/transport_security_state_generator/pinsets.h" |
| 10 #include "net/tools/transport_security_state_generator/transport_security_state_
entry.h" |
| 11 #include "testing/gtest/include/gtest/gtest.h" |
| 12 |
| 13 namespace net { |
| 14 |
| 15 namespace transport_security_state { |
| 16 |
| 17 // Test that all values are correctly parsed from a valid JSON input. |
| 18 TEST(InputFileParsersTest, ParseJSON) { |
| 19 std::string valid = |
| 20 "{" |
| 21 " \"pinsets\": [{" |
| 22 " \"name\": \"test\"," |
| 23 " \"static_spki_hashes\": [\"TestSPKI\"]," |
| 24 " \"bad_static_spki_hashes\": [\"BadTestSPKI\"]," |
| 25 " \"report_uri\": \"https://hpkp-log.example.com\"" |
| 26 " }]," |
| 27 " \"entries\": [" |
| 28 " {" |
| 29 " \"name\": \"hsts.example.com\"," |
| 30 " \"mode\": \"force-https\", " |
| 31 " \"include_subdomains\": true" |
| 32 " }, {" |
| 33 " \"name\": \"hpkp.example.com\"," |
| 34 " \"pins\": \"thepinset\"," |
| 35 " \"include_subdomains_for_pinning\": true" |
| 36 " }, {" |
| 37 " \"name\": \"expect-ct.example.com\"," |
| 38 " \"expect_ct\": true," |
| 39 " \"expect_ct_report_uri\": \"https://expect-ct-log.example.com\"" |
| 40 " }, {" |
| 41 " \"name\": \"expect-staple.example.com\"," |
| 42 " \"expect_staple\": true," |
| 43 " \"expect_staple_report_uri\": " |
| 44 "\"https://expect-staple-log.example.com\"," |
| 45 " \"include_subdomains_for_expect_staple\": true" |
| 46 " }" |
| 47 " ]," |
| 48 " \"domain_ids\": [" |
| 49 " \"NOT_PINNED\"," |
| 50 " \"EXAMPLE_COM\"" |
| 51 " ]" |
| 52 "}"; |
| 53 |
| 54 TransportSecurityStateEntries entries; |
| 55 Pinsets pinsets; |
| 56 DomainIDList domain_ids; |
| 57 std::vector<std::string> errors; |
| 58 |
| 59 EXPECT_TRUE(ParseJSON(valid, &entries, &pinsets, &domain_ids, &errors)); |
| 60 EXPECT_EQ(0U, errors.size()); |
| 61 |
| 62 ASSERT_EQ(1U, pinsets.size()); |
| 63 PinsetMap::const_iterator pinset = pinsets.pinsets().find("test"); |
| 64 ASSERT_NE(pinset, pinsets.pinsets().cend()); |
| 65 EXPECT_EQ("test", pinset->second->name()); |
| 66 EXPECT_EQ("https://hpkp-log.example.com", pinset->second->report_uri()); |
| 67 |
| 68 ASSERT_EQ(1U, pinset->second->static_spki_hashes().size()); |
| 69 EXPECT_EQ("TestSPKI", pinset->second->static_spki_hashes()[0]); |
| 70 |
| 71 ASSERT_EQ(1U, pinset->second->bad_static_spki_hashes().size()); |
| 72 EXPECT_EQ("BadTestSPKI", pinset->second->bad_static_spki_hashes()[0]); |
| 73 |
| 74 ASSERT_EQ(4U, entries.size()); |
| 75 TransportSecurityStateEntry* entry = entries[0].get(); |
| 76 EXPECT_EQ("hsts.example.com", entry->hostname); |
| 77 EXPECT_TRUE(entry->force_https); |
| 78 EXPECT_FALSE(entry->hpkp_include_subdomains); |
| 79 EXPECT_EQ("", entry->pinset); |
| 80 EXPECT_FALSE(entry->expect_ct); |
| 81 EXPECT_EQ("", entry->expect_ct_report_uri); |
| 82 EXPECT_FALSE(entry->expect_staple); |
| 83 EXPECT_FALSE(entry->expect_staple_include_subdomains); |
| 84 EXPECT_EQ("", entry->expect_staple_report_uri); |
| 85 |
| 86 entry = entries[1].get(); |
| 87 EXPECT_EQ("hpkp.example.com", entry->hostname); |
| 88 EXPECT_FALSE(entry->force_https); |
| 89 EXPECT_TRUE(entry->hpkp_include_subdomains); |
| 90 EXPECT_EQ("thepinset", entry->pinset); |
| 91 EXPECT_FALSE(entry->expect_ct); |
| 92 EXPECT_EQ("", entry->expect_ct_report_uri); |
| 93 EXPECT_FALSE(entry->expect_staple); |
| 94 EXPECT_FALSE(entry->expect_staple_include_subdomains); |
| 95 EXPECT_EQ("", entry->expect_staple_report_uri); |
| 96 |
| 97 entry = entries[2].get(); |
| 98 EXPECT_EQ("expect-ct.example.com", entry->hostname); |
| 99 EXPECT_FALSE(entry->force_https); |
| 100 EXPECT_FALSE(entry->hpkp_include_subdomains); |
| 101 EXPECT_EQ("", entry->pinset); |
| 102 EXPECT_TRUE(entry->expect_ct); |
| 103 EXPECT_EQ("https://expect-ct-log.example.com", entry->expect_ct_report_uri); |
| 104 EXPECT_FALSE(entry->expect_staple); |
| 105 EXPECT_FALSE(entry->expect_staple_include_subdomains); |
| 106 EXPECT_EQ("", entry->expect_staple_report_uri); |
| 107 |
| 108 entry = entries[3].get(); |
| 109 EXPECT_EQ("expect-staple.example.com", entry->hostname); |
| 110 EXPECT_FALSE(entry->force_https); |
| 111 EXPECT_FALSE(entry->hpkp_include_subdomains); |
| 112 EXPECT_EQ("", entry->pinset); |
| 113 EXPECT_FALSE(entry->expect_ct); |
| 114 EXPECT_EQ("", entry->expect_ct_report_uri); |
| 115 EXPECT_TRUE(entry->expect_staple); |
| 116 EXPECT_TRUE(entry->expect_staple_include_subdomains); |
| 117 EXPECT_EQ("https://expect-staple-log.example.com", |
| 118 entry->expect_staple_report_uri); |
| 119 |
| 120 ASSERT_EQ(2U, domain_ids.size()); |
| 121 EXPECT_EQ("NOT_PINNED", domain_ids[0]); |
| 122 EXPECT_EQ("EXAMPLE_COM", domain_ids[1]); |
| 123 } |
| 124 |
| 125 // Test that parsing valid JSON with missing keys fails. |
| 126 TEST(InputFileParsersTest, ParseJSONInvalid) { |
| 127 TransportSecurityStateEntries entries; |
| 128 Pinsets pinsets; |
| 129 DomainIDList domain_ids; |
| 130 std::vector<std::string> errors; |
| 131 |
| 132 std::string no_pinsets = |
| 133 "{" |
| 134 " \"entries\": []," |
| 135 " \"domain_ids\": []" |
| 136 "}"; |
| 137 |
| 138 EXPECT_FALSE(ParseJSON(no_pinsets, &entries, &pinsets, &domain_ids, &errors)); |
| 139 |
| 140 std::string no_entries = |
| 141 "{" |
| 142 " \"pinsets\": []," |
| 143 " \"domain_ids\": []" |
| 144 "}"; |
| 145 |
| 146 EXPECT_FALSE(ParseJSON(no_entries, &entries, &pinsets, &domain_ids, &errors)); |
| 147 |
| 148 std::string no_domain_ids = |
| 149 "{" |
| 150 " \"pinsets\": []," |
| 151 " \"entries\": []" |
| 152 "}\n"; |
| 153 |
| 154 EXPECT_FALSE( |
| 155 ParseJSON(no_domain_ids, &entries, &pinsets, &domain_ids, &errors)); |
| 156 } |
| 157 |
| 158 // Test that parsing valid JSON with invalid (HSTS) entries fails. |
| 159 TEST(InputFileParsersTest, ParseJSONInvalidHSTS) { |
| 160 TransportSecurityStateEntries entries; |
| 161 Pinsets pinsets; |
| 162 DomainIDList domain_ids; |
| 163 std::vector<std::string> errors; |
| 164 |
| 165 std::string missing_hostname = |
| 166 "{" |
| 167 " \"pinsets\": []," |
| 168 " \"entries\": [" |
| 169 " {" |
| 170 " \"mode\": \"force-https\"" |
| 171 " }" |
| 172 " ]," |
| 173 " \"domain_ids\": []" |
| 174 "}"; |
| 175 |
| 176 EXPECT_FALSE( |
| 177 ParseJSON(missing_hostname, &entries, &pinsets, &domain_ids, &errors)); |
| 178 } |
| 179 |
| 180 // Test that parsing valid JSON invalid (HPKP) entries fails. |
| 181 TEST(InputFileParsersTest, ParseJSONInvalidHPKP) { |
| 182 TransportSecurityStateEntries entries; |
| 183 Pinsets pinsets; |
| 184 DomainIDList domain_ids; |
| 185 std::vector<std::string> errors; |
| 186 |
| 187 std::string missing_hostname = |
| 188 "{" |
| 189 " \"pinsets\": [{" |
| 190 " \"static_spki_hashes\": [\"TestSPKI\"]," |
| 191 " \"bad_static_spki_hashes\": [\"BadTestSPKI\"]," |
| 192 " \"report_uri\": \"https://hpkp-log.example.com\"" |
| 193 " }]," |
| 194 " \"entries\": []," |
| 195 " \"domain_ids\": []" |
| 196 "}"; |
| 197 |
| 198 EXPECT_FALSE( |
| 199 ParseJSON(missing_hostname, &entries, &pinsets, &domain_ids, &errors)); |
| 200 } |
| 201 |
| 202 // Test that non-standard JSON comments don't affect parsing. |
| 203 TEST(InputFileParsersTest, ParseJSONComments) { |
| 204 std::string valid = |
| 205 "// This line should be ignored.\n" |
| 206 "{\n" |
| 207 "// This line should be ignored.\n" |
| 208 " \"pinsets\": [],\n" |
| 209 " \"entries\": [\n" |
| 210 " {\n" |
| 211 "// This line should be ignored.\n" |
| 212 " \"name\": \"hsts.example.com\",\n" |
| 213 " \"mode\": \"force-https\"\n" |
| 214 "// This line should be ignored.\n" |
| 215 " }\n" |
| 216 " ],\n" |
| 217 "// This line should be ignored.\n" |
| 218 " \"domain_ids\": [\n" |
| 219 " \"NOT_PINNED\"\n" |
| 220 " ]\n" |
| 221 "// This line should be ignored.\n" |
| 222 "}\n"; |
| 223 |
| 224 TransportSecurityStateEntries entries; |
| 225 Pinsets pinsets; |
| 226 DomainIDList domain_ids; |
| 227 std::vector<std::string> errors; |
| 228 |
| 229 EXPECT_TRUE(ParseJSON(valid, &entries, &pinsets, &domain_ids, &errors)); |
| 230 EXPECT_EQ(0U, errors.size()); |
| 231 |
| 232 EXPECT_EQ(0U, pinsets.size()); |
| 233 |
| 234 ASSERT_EQ(1U, entries.size()); |
| 235 EXPECT_EQ("hsts.example.com", entries[0]->hostname); |
| 236 EXPECT_TRUE(entries[0]->force_https); |
| 237 |
| 238 ASSERT_EQ(1U, domain_ids.size()); |
| 239 EXPECT_EQ("NOT_PINNED", domain_ids[0]); |
| 240 } |
| 241 |
| 242 // Test parsing of all 3 SPKI formats. |
| 243 TEST(InputFileParsersTest, ParseCertificatesFile) { |
| 244 std::string valid = |
| 245 "# This line should ignored. The rest should result in 3 pins.\n" |
| 246 "TestPublicKey1\n" |
| 247 "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\n" |
| 248 "\n" |
| 249 "TestPublicKey2\n" |
| 250 "-----BEGIN PUBLIC KEY-----\n" |
| 251 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAujzwcb5bJuC/A/Y9izGl\n" |
| 252 "LlA3fnKGbeyn53BdVznJN4fQwU82WKVYdqt8d/1ZDRdYyhGrTgXJeCURe9VSJyX1\n" |
| 253 "X2a5EApSFsopP8Yjy0Rl6dNOLO84KCW9dPmfHC3uP0ac4hnHT5dUr05YvhJmHCkf\n" |
| 254 "as6v/aEgpPLDhRF6UruSUh+gIpUg/F3+vlD99HLfbloukoDtQyxW+86s9sO7RQ00\n" |
| 255 "pd79VOoa/v09FvoS7MFgnBBOtvBQLOXjEH7/qBsnrXFtHBeOtxSLar/FL3OhVXuh\n" |
| 256 "dUTRyc1Mg0ECtz8zHZugW+LleIm5Bf5Yr0bN1O/HfDPCkDaCldcm6xohEHn9pBaW\n" |
| 257 "+wIDAQAB\n" |
| 258 "-----END PUBLIC KEY-----\n" |
| 259 "\n" |
| 260 "# The 'Chromium' prefix is required here.\n" |
| 261 "ChromiumTestCertificate3\n" |
| 262 "-----BEGIN CERTIFICATE-----\n" |
| 263 "MIIDeTCCAmGgAwIBAgIJAMRHXuiAgufAMA0GCSqGSIb3DQEBCwUAMFMxETAPBgNV\n" |
| 264 "BAMMCENocm9taXVtMR4wHAYDVQQKDBVUaGUgQ2hyb21pdW0gUHJvamVjdHMxETAP\n" |
| 265 "BgNVBAsMCFNlY3VyaXR5MQswCQYDVQQGEwJVUzAeFw0xNzAyMDExOTAyMzFaFw0x\n" |
| 266 "ODAyMDExOTAyMzFaMFMxETAPBgNVBAMMCENocm9taXVtMR4wHAYDVQQKDBVUaGUg\n" |
| 267 "Q2hyb21pdW0gUHJvamVjdHMxETAPBgNVBAsMCFNlY3VyaXR5MQswCQYDVQQGEwJV\n" |
| 268 "UzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALtggpf5vNVsmQrJKTQe\n" |
| 269 "ynTeOzVOyROGDugGtR+Cri8WlNg1UAlIyYIS8txZ4oCknsT8gs3TFfu0wxmWNxx5\n" |
| 270 "4oLGy2BQOHH00dgBAsKgqX//mY4mH5AZ85UFYni1hj9aszIJMIBWtgbNGVkppW65\n" |
| 271 "8maF1KVdHmxXMvtKxn/9UsusH/A0ng5UJDYBPISQMv0XqIlv0wdVTIVWIcQhOjWz\n" |
| 272 "MGwFDSjxS1WgEnPgd4Qi7MYaDbUTsXGtWba83vZJ8CQzjLumSJJCnz2aquGmraX0\n" |
| 273 "J0joUjB4fuYL8xrbDqnFmADvozMMVkZ4843w8ikvJkM8nWoIXexVvirfXDoqtdUo\n" |
| 274 "YOcCAwEAAaNQME4wHQYDVR0OBBYEFGJ6O/oLtzpb4OWvrEFxieYb1JbsMB8GA1Ud\n" |
| 275 "IwQYMBaAFGJ6O/oLtzpb4OWvrEFxieYb1JbsMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n" |
| 276 "hvcNAQELBQADggEBAFpt9jlBT6OsfKFAJZnmExbW8JlsqXOJAaR+nD1XOnp6o+DM\n" |
| 277 "NIguj9+wJOW34OM+2Om0n+KMYbDER0p4g3gxoaDblu7otgnC0OTOnx3DPUYab0jr\n" |
| 278 "uT6O4C3/nfWW5sl3Ni3Y99dmdcqKcmYkHsr7uADLPWsjb+sfUrQQfHHnPwzyUz/A\n" |
| 279 "w4rSJ0wxnLOmjk5F5YHMLkNpPrzFA1mFyGIau7THsRIr3B632MLNcOlNR21nOc7i\n" |
| 280 "eB4u+OzpcZXuiQg3bqrNp6Xb70OIW1rfNEiCpps4UZyRnZ/nrzByxeHH5zPWWZk9\n" |
| 281 "nZtxI+65PFOekOjBpbnRC8v1CfOmUSVKIqWaPys=\n" |
| 282 "-----END CERTIFICATE-----"; |
| 283 |
| 284 Pinsets pinsets; |
| 285 std::vector<std::string> errors; |
| 286 EXPECT_TRUE(ParseCertificatesFile(valid, &pinsets, &errors)); |
| 287 ASSERT_EQ(3U, pinsets.spki_size()); |
| 288 EXPECT_EQ(0U, errors.size()); |
| 289 |
| 290 const SPKIHashMap& hashes = pinsets.spki_hashes(); |
| 291 ASSERT_NE(hashes.cend(), hashes.find("TestPublicKey1")); |
| 292 ASSERT_NE(hashes.cend(), hashes.find("TestPublicKey2")); |
| 293 ASSERT_NE(hashes.cend(), hashes.find("ChromiumTestCertificate3")); |
| 294 } |
| 295 |
| 296 TEST(InputFileParsersTest, ParseCertificatesFileInvalid) { |
| 297 Pinsets pinsets; |
| 298 std::vector<std::string> errors; |
| 299 |
| 300 std::string invalid = |
| 301 "TestName\n" |
| 302 "unexpected"; |
| 303 EXPECT_FALSE(ParseCertificatesFile(invalid, &pinsets, &errors)); |
| 304 } |
| 305 |
| 306 TEST(InputFileParsersTest, ParseCertificatesFileInvalidName) { |
| 307 Pinsets pinsets; |
| 308 std::vector<std::string> errors; |
| 309 |
| 310 std::string invalid_name1 = |
| 311 "startsWithSmallLetter\n" |
| 312 "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\n"; |
| 313 EXPECT_FALSE(ParseCertificatesFile(invalid_name1, &pinsets, &errors)); |
| 314 |
| 315 std::string invalid_name2 = |
| 316 "Invalid-Characters-In-Name\n" |
| 317 "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\n"; |
| 318 EXPECT_FALSE(ParseCertificatesFile(invalid_name2, &pinsets, &errors)); |
| 319 |
| 320 std::string invalid_name3 = |
| 321 "1InvalidName\n" |
| 322 "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\n"; |
| 323 EXPECT_FALSE(ParseCertificatesFile(invalid_name3, &pinsets, &errors)); |
| 324 |
| 325 std::string invalid_name4 = |
| 326 "Invalid Name\n" |
| 327 "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\n"; |
| 328 EXPECT_FALSE(ParseCertificatesFile(invalid_name4, &pinsets, &errors)); |
| 329 } |
| 330 |
| 331 TEST(InputFileParsersTest, ParseCertificatesFileInvalidCertificateName) { |
| 332 Pinsets pinsets; |
| 333 std::vector<std::string> errors; |
| 334 std::string certificate = |
| 335 "-----BEGIN CERTIFICATE-----\n" |
| 336 "MIIDIzCCAgugAwIBAgIJALs84KlxWh4GMA0GCSqGSIb3DQEBCwUAMCgxGTAXBgNV\n" |
| 337 "BAoMEENocm9taXVtIENsYXNzIDMxCzAJBgNVBAsMAkcxMB4XDTE3MDIwMTE5NTUw\n" |
| 338 "NVoXDTE4MDIwMTE5NTUwNVowKDEZMBcGA1UECgwQQ2hyb21pdW0gQ2xhc3MgMzEL\n" |
| 339 "MAkGA1UECwwCRzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkolrR\n" |
| 340 "7gCPm22Cc9psS2Jh1mksVneee5ntEezZ2gEU20y9Z9URBReo8SFvaZcgKkAkca1v\n" |
| 341 "552YIG+FBO/u8njxzlHXvuVJ5x2geciqqR4TRhA4jO1ndrNW6nlJfOoYueWbdym3\n" |
| 342 "8zwugoULoCtyLyzdiMI5g8iVBQHDh8+K3TZIHar3HS49TjX5u5nv4igO4RfDcFUa\n" |
| 343 "h8g+6x5nWoFF8oa3FG0YTN+q6iI1i2JHmj/q03fVPv3WLPGJ3JADau9gO1Lw1/qf\n" |
| 344 "R/N3l4MVtjDFFGYzclfqW2UmL6zRirEV0GF2gwSBAGVX3WWhpOcM8rFIWYkZCsI5\n" |
| 345 "iUdtwFNBfcKS9sNpAgMBAAGjUDBOMB0GA1UdDgQWBBTm4VJfibducqwb9h4XELn3\n" |
| 346 "p6zLVzAfBgNVHSMEGDAWgBTm4VJfibducqwb9h4XELn3p6zLVzAMBgNVHRMEBTAD\n" |
| 347 "AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQApTm40RfsZG20IIgWJ62pZ2end/lvaneTh\n" |
| 348 "MZSgFnoTRjKkd/5dh22YyKPw9PnpIuiyi85L36COreqZUvbxqRQnpL1oSCRlLBJQ\n" |
| 349 "2LcGlF0j0Opa+SY2VWup4XjnYF8CvwMl4obNpSuywTFmkXCRxzN23tn8whNHvWHM\n" |
| 350 "BQ7abw8X1KY02uPbHucrpou6KXkKkhyhfML8OD8IRkSM56K6YyedqV97cmEdW0Ie\n" |
| 351 "LlpFJQVX13bmojtSNI1zaiCiEenn5xLa/dAlyFT18Mq6y8plioBinVWFYd0qcRoA\n" |
| 352 "E2j3m+jTVIv3CZ+ivGxggZQ8ZYN8FJ/iTW3pXGojogHh0NRJJ8dM\n" |
| 353 "-----END CERTIFICATE-----"; |
| 354 |
| 355 std::string missing_prefix = "Class3_G1_Test\n" + certificate; |
| 356 EXPECT_FALSE(ParseCertificatesFile(missing_prefix, &pinsets, &errors)); |
| 357 EXPECT_EQ(2U, errors.size()); |
| 358 errors.clear(); |
| 359 |
| 360 std::string missing_class = "Chromium_G1_Test\n" + certificate; |
| 361 EXPECT_FALSE(ParseCertificatesFile(missing_class, &pinsets, &errors)); |
| 362 EXPECT_EQ(2U, errors.size()); |
| 363 errors.clear(); |
| 364 |
| 365 std::string missing_number = "Chromium_Class3_Test\n" + certificate; |
| 366 EXPECT_FALSE(ParseCertificatesFile(missing_number, &pinsets, &errors)); |
| 367 EXPECT_EQ(2U, errors.size()); |
| 368 errors.clear(); |
| 369 |
| 370 std::string valid = "Chromium_Class3_G1_Test\n" + certificate; |
| 371 EXPECT_TRUE(ParseCertificatesFile(valid, &pinsets, &errors)); |
| 372 EXPECT_EQ(0U, errors.size()); |
| 373 } |
| 374 |
| 375 } // namespace transport_security_state |
| 376 |
| 377 } // namespace net |
OLD | NEW |