1 // Copyright (c) 2012 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 // Program to test the SafeBrowsing protocol parsing v2.1. 6 7 #include <map> 8 #include <string> 9 10 #include "base/strings/stringprintf.h" 11 #include "chrome/browser/safe_browsing/protocol_parser.h" 12 #include "chrome/browser/safe_browsing/safe_browsing_util.h" 13 #include "testing/gtest/include/gtest/gtest.h" 14 15 // Test parsing one add chunk. 16 TEST(SafeBrowsingProtocolParsingTest, TestAddChunk) { 17 std::string add_chunk("a:1:4:35\naaaax1111\0032222333344447777\00288889999"); 18 add_chunk[13] = '\0'; 19 20 // Run the parse. 21 SafeBrowsingProtocolParser parser; 22 SBChunkList chunks; 23 bool result = parser.ParseChunk( 24 safe_browsing_util::kMalwareList, 25 add_chunk.data(), 26 static_cast<int>(add_chunk.length()), 27 &chunks); 28 EXPECT_TRUE(result); 29 EXPECT_EQ(chunks.size(), 1U); 30 EXPECT_EQ(chunks[0].chunk_number, 1); 31 EXPECT_EQ(chunks[0].hosts.size(), 3U); 32 33 EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161); 34 SBEntry* entry = chunks[0].hosts[0].entry; 35 EXPECT_TRUE(entry->IsAdd()); 36 EXPECT_TRUE(entry->IsPrefix()); 37 EXPECT_EQ(entry->prefix_count(), 0); 38 39 EXPECT_EQ(chunks[0].hosts[1].host, 0x31313131); 40 entry = chunks[0].hosts[1].entry; 41 EXPECT_TRUE(entry->IsAdd()); 42 EXPECT_TRUE(entry->IsPrefix()); 43 EXPECT_EQ(entry->prefix_count(), 3); 44 EXPECT_EQ(entry->PrefixAt(0), 0x32323232); 45 EXPECT_EQ(entry->PrefixAt(1), 0x33333333); 46 EXPECT_EQ(entry->PrefixAt(2), 0x34343434); 47 48 EXPECT_EQ(chunks[0].hosts[2].host, 0x37373737); 49 entry = chunks[0].hosts[2].entry; 50 EXPECT_TRUE(entry->IsAdd()); 51 EXPECT_TRUE(entry->IsPrefix()); 52 EXPECT_EQ(entry->prefix_count(), 2); 53 EXPECT_EQ(entry->PrefixAt(0), 0x38383838); 54 EXPECT_EQ(entry->PrefixAt(1), 0x39393939); 55 } 56 57 // Test parsing one add chunk with full hashes. 58 TEST(SafeBrowsingProtocolParsingTest, TestAddFullChunk) { 59 std::string add_chunk("a:1:32:69\naaaa"); 60 add_chunk.push_back(2); 61 62 SBFullHash full_hash1, full_hash2; 63 for (int i = 0; i < 32; ++i) { 64 full_hash1.full_hash[i] = i % 2 ? 1 : 2; 65 full_hash2.full_hash[i] = i % 2 ? 3 : 4; 66 } 67 68 add_chunk.append(full_hash1.full_hash, 32); 69 add_chunk.append(full_hash2.full_hash, 32); 70 71 // Run the parse. 72 SafeBrowsingProtocolParser parser; 73 SBChunkList chunks; 74 bool result = parser.ParseChunk( 75 safe_browsing_util::kMalwareList, 76 add_chunk.data(), 77 static_cast<int>(add_chunk.length()), 78 &chunks); 79 EXPECT_TRUE(result); 80 EXPECT_EQ(chunks.size(), 1U); 81 EXPECT_EQ(chunks[0].chunk_number, 1); 82 EXPECT_EQ(chunks[0].hosts.size(), 1U); 83 84 EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161); 85 SBEntry* entry = chunks[0].hosts[0].entry; 86 EXPECT_TRUE(entry->IsAdd()); 87 EXPECT_FALSE(entry->IsPrefix()); 88 EXPECT_EQ(entry->prefix_count(), 2); 89 EXPECT_TRUE(entry->FullHashAt(0) == full_hash1); 90 EXPECT_TRUE(entry->FullHashAt(1) == full_hash2); 91 } 92 93 // Test parsing multiple add chunks. We'll use the same chunk as above, and add 94 // one more after it. 95 TEST(SafeBrowsingProtocolParsingTest, TestAddChunks) { 96 std::string add_chunk("a:1:4:35\naaaax1111\0032222333344447777\00288889999" 97 "a:2:4:13\n5555\002ppppgggg"); 98 add_chunk[13] = '\0'; 99 100 // Run the parse. 101 SafeBrowsingProtocolParser parser; 102 SBChunkList chunks; 103 bool result = parser.ParseChunk( 104 safe_browsing_util::kMalwareList, 105 add_chunk.data(), 106 static_cast<int>(add_chunk.length()), 107 &chunks); 108 EXPECT_TRUE(result); 109 EXPECT_EQ(chunks.size(), 2U); 110 EXPECT_EQ(chunks[0].chunk_number, 1); 111 EXPECT_EQ(chunks[0].hosts.size(), 3U); 112 113 EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161); 114 SBEntry* entry = chunks[0].hosts[0].entry; 115 EXPECT_TRUE(entry->IsAdd()); 116 EXPECT_TRUE(entry->IsPrefix()); 117 EXPECT_EQ(entry->prefix_count(), 0); 118 119 EXPECT_EQ(chunks[0].hosts[1].host, 0x31313131); 120 entry = chunks[0].hosts[1].entry; 121 EXPECT_TRUE(entry->IsAdd()); 122 EXPECT_TRUE(entry->IsPrefix()); 123 EXPECT_EQ(entry->prefix_count(), 3); 124 EXPECT_EQ(entry->PrefixAt(0), 0x32323232); 125 EXPECT_EQ(entry->PrefixAt(1), 0x33333333); 126 EXPECT_EQ(entry->PrefixAt(2), 0x34343434); 127 128 EXPECT_EQ(chunks[0].hosts[2].host, 0x37373737); 129 entry = chunks[0].hosts[2].entry; 130 EXPECT_TRUE(entry->IsAdd()); 131 EXPECT_TRUE(entry->IsPrefix()); 132 EXPECT_EQ(entry->prefix_count(), 2); 133 EXPECT_EQ(entry->PrefixAt(0), 0x38383838); 134 EXPECT_EQ(entry->PrefixAt(1), 0x39393939); 135 136 137 EXPECT_EQ(chunks[1].chunk_number, 2); 138 EXPECT_EQ(chunks[1].hosts.size(), 1U); 139 140 EXPECT_EQ(chunks[1].hosts[0].host, 0x35353535); 141 entry = chunks[1].hosts[0].entry; 142 EXPECT_TRUE(entry->IsAdd()); 143 EXPECT_TRUE(entry->IsPrefix()); 144 EXPECT_EQ(entry->prefix_count(), 2); 145 EXPECT_EQ(entry->PrefixAt(0), 0x70707070); 146 EXPECT_EQ(entry->PrefixAt(1), 0x67676767); 147 } 148 149 // Test parsing one add chunk where a hostkey spans several entries. 150 TEST(SafeBrowsingProtocolParsingTest, TestAddBigChunk) { 151 std::string add_chunk("a:1:4:1050\naaaaX"); 152 add_chunk[add_chunk.size() - 1] |= 0xFF; 153 for (int i = 0; i < 255; ++i) 154 add_chunk.append(base::StringPrintf("%04d", i)); 155 156 add_chunk.append("aaaa"); 157 add_chunk.push_back(5); 158 for (int i = 0; i < 5; ++i) 159 add_chunk.append(base::StringPrintf("001%d", i)); 160 161 SafeBrowsingProtocolParser parser; 162 SBChunkList chunks; 163 bool result = parser.ParseChunk( 164 safe_browsing_util::kMalwareList, 165 add_chunk.data(), 166 static_cast<int>(add_chunk.length()), 167 &chunks); 168 EXPECT_TRUE(result); 169 EXPECT_EQ(chunks.size(), 1U); 170 EXPECT_EQ(chunks[0].chunk_number, 1); 171 172 EXPECT_EQ(chunks[0].hosts.size(), 2U); 173 174 const SBChunkHost& host0 = chunks[0].hosts[0]; 175 EXPECT_EQ(host0.host, 0x61616161); 176 EXPECT_EQ(host0.entry->prefix_count(), 255); 177 178 const SBChunkHost& host1 = chunks[0].hosts[1]; 179 EXPECT_EQ(host1.host, 0x61616161); 180 EXPECT_EQ(host1.entry->prefix_count(), 5); 181 } 182 183 // Test to make sure we could deal with truncated bin hash chunk. 184 TEST(SafeBrowsingProtocolParsingTest, TestTruncatedBinHashChunk) { 185 // This chunk delares there are 4 prefixes but actually only contains 2. 186 const char add_chunk[] = "a:1:4:16\n11112222"; 187 SafeBrowsingProtocolParser parser; 188 SBChunkList chunks; 189 bool result = parser.ParseChunk(safe_browsing_util::kBinHashList, 190 add_chunk, 191 static_cast<int>(sizeof(add_chunk)), 192 &chunks); 193 EXPECT_FALSE(result); 194 EXPECT_EQ(chunks.size(), 0U); 195 } 196 197 // Test to make sure we could deal with truncated malwarelist chunk. 198 TEST(SafeBrowsingProtocolParsingTest, TestTruncatedUrlHashChunk) { 199 // This chunk delares there are 4 prefixes but actually only contains 2. 200 const char add_chunk[] = "a:1:4:21\naaaa\00411112222"; 201 SafeBrowsingProtocolParser parser; 202 SBChunkList chunks; 203 204 // For safe_browsing_util::kMalwareList. 205 bool result = parser.ParseChunk(safe_browsing_util::kMalwareList, 206 add_chunk, 207 static_cast<int>(sizeof(add_chunk)), 208 &chunks); 209 EXPECT_FALSE(result); 210 EXPECT_EQ(chunks.size(), 0U); 211 212 // For safe_browsing_util::kPhishingList. 213 result = parser.ParseChunk(safe_browsing_util::kPhishingList, 214 add_chunk, 215 static_cast<int>(sizeof(add_chunk)), 216 &chunks); 217 EXPECT_FALSE(result); 218 EXPECT_EQ(chunks.size(), 0U); 219 220 // For safe_browsing_util::kBinUrlList. 221 result = parser.ParseChunk(safe_browsing_util::kBinUrlList, 222 add_chunk, 223 static_cast<int>(sizeof(add_chunk)), 224 &chunks); 225 EXPECT_FALSE(result); 226 EXPECT_EQ(chunks.size(), 0U); 227 } 228 229 // Test to verify handling of a truncated chunk header. 230 TEST(SafeBrowsingProtocolParsingTest, TestTruncatedHeader) { 231 std::string truncated_chunks("a:1:4:0\na:"); 232 233 // Run the parser. 234 SafeBrowsingProtocolParser parser; 235 SBChunkList chunks; 236 bool result = parser.ParseChunk( 237 safe_browsing_util::kMalwareList, 238 truncated_chunks.data(), 239 static_cast<int>(truncated_chunks.length()), 240 &chunks); 241 EXPECT_FALSE(result); 242 } 243 244 // Test parsing one sub chunk. 245 TEST(SafeBrowsingProtocolParsingTest, TestSubChunk) { 246 std::string sub_chunk("s:9:4:59\naaaaxkkkk1111\003" 247 "zzzz2222zzzz3333zzzz4444" 248 "7777\002yyyy8888yyyy9999"); 249 sub_chunk[13] = '\0'; 250 251 // Run the parse. 252 SafeBrowsingProtocolParser parser; 253 SBChunkList chunks; 254 bool result = parser.ParseChunk( 255 safe_browsing_util::kMalwareList, 256 sub_chunk.data(), 257 static_cast<int>(sub_chunk.length()), 258 &chunks); 259 EXPECT_TRUE(result); 260 EXPECT_EQ(chunks.size(), 1U); 261 EXPECT_EQ(chunks[0].chunk_number, 9); 262 EXPECT_EQ(chunks[0].hosts.size(), 3U); 263 264 EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161); 265 SBEntry* entry = chunks[0].hosts[0].entry; 266 EXPECT_TRUE(entry->IsSub()); 267 EXPECT_TRUE(entry->IsPrefix()); 268 EXPECT_EQ(entry->chunk_id(), 0x6b6b6b6b); 269 EXPECT_EQ(entry->prefix_count(), 0); 270 271 EXPECT_EQ(chunks[0].hosts[1].host, 0x31313131); 272 entry = chunks[0].hosts[1].entry; 273 EXPECT_TRUE(entry->IsSub()); 274 EXPECT_TRUE(entry->IsPrefix()); 275 EXPECT_EQ(entry->prefix_count(), 3); 276 EXPECT_EQ(entry->ChunkIdAtPrefix(0), 0x7a7a7a7a); 277 EXPECT_EQ(entry->PrefixAt(0), 0x32323232); 278 EXPECT_EQ(entry->ChunkIdAtPrefix(1), 0x7a7a7a7a); 279 EXPECT_EQ(entry->PrefixAt(1), 0x33333333); 280 EXPECT_EQ(entry->ChunkIdAtPrefix(2), 0x7a7a7a7a); 281 EXPECT_EQ(entry->PrefixAt(2), 0x34343434); 282 283 EXPECT_EQ(chunks[0].hosts[2].host, 0x37373737); 284 entry = chunks[0].hosts[2].entry; 285 EXPECT_TRUE(entry->IsSub()); 286 EXPECT_TRUE(entry->IsPrefix()); 287 EXPECT_EQ(entry->prefix_count(), 2); 288 EXPECT_EQ(entry->ChunkIdAtPrefix(0), 0x79797979); 289 EXPECT_EQ(entry->PrefixAt(0), 0x38383838); 290 EXPECT_EQ(entry->ChunkIdAtPrefix(1), 0x79797979); 291 EXPECT_EQ(entry->PrefixAt(1), 0x39393939); 292 } 293 294 // Test parsing one sub chunk with full hashes. 295 TEST(SafeBrowsingProtocolParsingTest, TestSubFullChunk) { 296 std::string sub_chunk("s:1:32:77\naaaa"); 297 sub_chunk.push_back(2); 298 299 SBFullHash full_hash1, full_hash2; 300 for (int i = 0; i < 32; ++i) { 301 full_hash1.full_hash[i] = i % 2 ? 1 : 2; 302 full_hash2.full_hash[i] = i % 2 ? 3 : 4; 303 } 304 305 sub_chunk.append("yyyy"); 306 sub_chunk.append(full_hash1.full_hash, 32); 307 sub_chunk.append("zzzz"); 308 sub_chunk.append(full_hash2.full_hash, 32); 309 310 // Run the parse. 311 SafeBrowsingProtocolParser parser; 312 SBChunkList chunks; 313 bool result = parser.ParseChunk( 314 safe_browsing_util::kMalwareList, 315 sub_chunk.data(), 316 static_cast<int>(sub_chunk.length()), 317 &chunks); 318 EXPECT_TRUE(result); 319 EXPECT_EQ(chunks.size(), 1U); 320 EXPECT_EQ(chunks[0].chunk_number, 1); 321 EXPECT_EQ(chunks[0].hosts.size(), 1U); 322 323 EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161); 324 SBEntry* entry = chunks[0].hosts[0].entry; 325 EXPECT_TRUE(entry->IsSub()); 326 EXPECT_FALSE(entry->IsPrefix()); 327 EXPECT_EQ(entry->prefix_count(), 2); 328 EXPECT_EQ(entry->ChunkIdAtPrefix(0), 0x79797979); 329 EXPECT_TRUE(entry->FullHashAt(0) == full_hash1); 330 EXPECT_EQ(entry->ChunkIdAtPrefix(1), 0x7a7a7a7a); 331 EXPECT_TRUE(entry->FullHashAt(1) == full_hash2); 332 } 333 334 // Test parsing the SafeBrowsing update response. 335 TEST(SafeBrowsingProtocolParsingTest, TestChunkDelete) { 336 std::string add_del("n:1700\ni:phishy\nad:1-7,43-597,44444,99999\n" 337 "i:malware\nsd:21-27,42,171717\n"); 338 339 SafeBrowsingProtocolParser parser; 340 int next_query_sec = 0; 341 bool reset = false; 342 std::vector<SBChunkDelete> deletes; 343 std::vector<ChunkUrl> urls; 344 EXPECT_TRUE(parser.ParseUpdate(add_del.data(), 345 static_cast<int>(add_del.length()), 346 &next_query_sec, &reset, &deletes, &urls)); 347 348 EXPECT_TRUE(urls.empty()); 349 EXPECT_FALSE(reset); 350 EXPECT_EQ(next_query_sec, 1700); 351 EXPECT_EQ(deletes.size(), 2U); 352 353 EXPECT_EQ(deletes[0].chunk_del.size(), 4U); 354 EXPECT_TRUE(deletes[0].chunk_del[0] == ChunkRange(1, 7)); 355 EXPECT_TRUE(deletes[0].chunk_del[1] == ChunkRange(43, 597)); 356 EXPECT_TRUE(deletes[0].chunk_del[2] == ChunkRange(44444)); 357 EXPECT_TRUE(deletes[0].chunk_del[3] == ChunkRange(99999)); 358 359 EXPECT_EQ(deletes[1].chunk_del.size(), 3U); 360 EXPECT_TRUE(deletes[1].chunk_del[0] == ChunkRange(21, 27)); 361 EXPECT_TRUE(deletes[1].chunk_del[1] == ChunkRange(42)); 362 EXPECT_TRUE(deletes[1].chunk_del[2] == ChunkRange(171717)); 363 364 // An update response with missing list name. 365 366 next_query_sec = 0; 367 deletes.clear(); 368 urls.clear(); 369 add_del = "n:1700\nad:1-7,43-597,44444,99999\ni:malware\nsd:4,21-27171717\n"; 370 EXPECT_FALSE(parser.ParseUpdate(add_del.data(), 371 static_cast<int>(add_del.length()), 372 &next_query_sec, &reset, &deletes, &urls)); 373 } 374 375 // Test parsing the SafeBrowsing update response. 376 TEST(SafeBrowsingProtocolParsingTest, TestRedirects) { 377 std::string redirects("i:goog-malware-shavar\n" 378 "u:cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_1\n" 379 "u:cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_2\n" 380 "u:cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_3\n" 381 "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8641-8800:8641-8689," 382 "8691-8731,8733-8786\n"); 383 384 SafeBrowsingProtocolParser parser; 385 int next_query_sec = 0; 386 bool reset = false; 387 std::vector<SBChunkDelete> deletes; 388 std::vector<ChunkUrl> urls; 389 EXPECT_TRUE(parser.ParseUpdate(redirects.data(), 390 static_cast<int>(redirects.length()), 391 &next_query_sec, &reset, &deletes, &urls)); 392 393 EXPECT_FALSE(reset); 394 EXPECT_EQ(urls.size(), 4U); 395 EXPECT_EQ(urls[0].url, 396 "cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_1"); 397 EXPECT_EQ(urls[1].url, 398 "cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_2"); 399 EXPECT_EQ(urls[2].url, 400 "cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_3"); 401 EXPECT_EQ(urls[3].url, 402 "s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8641-8800:8641-8689," 403 "8691-8731,8733-8786"); 404 EXPECT_EQ(next_query_sec, 0); 405 EXPECT_TRUE(deletes.empty()); 406 } 407 408 // Test parsing various SafeBrowsing protocol headers. 409 TEST(SafeBrowsingProtocolParsingTest, TestNextQueryTime) { 410 std::string headers("n:1800\ni:goog-white-shavar\n"); 411 SafeBrowsingProtocolParser parser; 412 int next_query_sec = 0; 413 bool reset = false; 414 std::vector<SBChunkDelete> deletes; 415 std::vector<ChunkUrl> urls; 416 EXPECT_TRUE(parser.ParseUpdate(headers.data(), 417 static_cast<int>(headers.length()), 418 &next_query_sec, &reset, &deletes, &urls)); 419 420 EXPECT_EQ(next_query_sec, 1800); 421 EXPECT_FALSE(reset); 422 EXPECT_TRUE(deletes.empty()); 423 EXPECT_TRUE(urls.empty()); 424 } 425 426 // Test parsing data from a GetHashRequest 427 TEST(SafeBrowsingProtocolParsingTest, TestGetHash) { 428 std::string get_hash("goog-phish-shavar:19:96\n" 429 "00112233445566778899aabbccddeeff" 430 "00001111222233334444555566667777" 431 "ffffeeeeddddccccbbbbaaaa99998888"); 432 std::vector<SBFullHashResult> full_hashes; 433 SafeBrowsingProtocolParser parser; 434 EXPECT_TRUE(parser.ParseGetHash(get_hash.data(), 435 static_cast<int>(get_hash.length()), 436 &full_hashes)); 437 438 EXPECT_EQ(full_hashes.size(), 3U); 439 EXPECT_EQ(memcmp(&full_hashes[0].hash, 440 "00112233445566778899aabbccddeeff", 441 sizeof(SBFullHash)), 0); 442 EXPECT_EQ(full_hashes[0].list_name, "goog-phish-shavar"); 443 EXPECT_EQ(memcmp(&full_hashes[1].hash, 444 "00001111222233334444555566667777", 445 sizeof(SBFullHash)), 0); 446 EXPECT_EQ(full_hashes[1].list_name, "goog-phish-shavar"); 447 EXPECT_EQ(memcmp(&full_hashes[2].hash, 448 "ffffeeeeddddccccbbbbaaaa99998888", 449 sizeof(SBFullHash)), 0); 450 EXPECT_EQ(full_hashes[2].list_name, "goog-phish-shavar"); 451 452 // Test multiple lists in the GetHash results. 453 std::string get_hash2("goog-phish-shavar:19:32\n" 454 "00112233445566778899aabbccddeeff" 455 "goog-malware-shavar:19:64\n" 456 "cafebeefcafebeefdeaddeaddeaddead" 457 "zzzzyyyyxxxxwwwwvvvvuuuuttttssss"); 458 EXPECT_TRUE(parser.ParseGetHash(get_hash2.data(), 459 static_cast<int>(get_hash2.length()), 460 &full_hashes)); 461 462 EXPECT_EQ(full_hashes.size(), 3U); 463 EXPECT_EQ(memcmp(&full_hashes[0].hash, 464 "00112233445566778899aabbccddeeff", 465 sizeof(SBFullHash)), 0); 466 EXPECT_EQ(full_hashes[0].list_name, "goog-phish-shavar"); 467 EXPECT_EQ(memcmp(&full_hashes[1].hash, 468 "cafebeefcafebeefdeaddeaddeaddead", 469 sizeof(SBFullHash)), 0); 470 EXPECT_EQ(full_hashes[1].list_name, "goog-malware-shavar"); 471 EXPECT_EQ(memcmp(&full_hashes[2].hash, 472 "zzzzyyyyxxxxwwwwvvvvuuuuttttssss", 473 sizeof(SBFullHash)), 0); 474 EXPECT_EQ(full_hashes[2].list_name, "goog-malware-shavar"); 475 } 476 477 TEST(SafeBrowsingProtocolParsingTest, TestGetHashWithUnknownList) { 478 std::string hash_response = "goog-phish-shavar:1:32\n" 479 "12345678901234567890123456789012" 480 "googpub-phish-shavar:19:32\n" 481 "09876543210987654321098765432109"; 482 std::vector<SBFullHashResult> full_hashes; 483 SafeBrowsingProtocolParser parser; 484 EXPECT_TRUE(parser.ParseGetHash(hash_response.data(), 485 hash_response.size(), 486 &full_hashes)); 487 488 EXPECT_EQ(full_hashes.size(), 1U); 489 EXPECT_EQ(memcmp("12345678901234567890123456789012", 490 &full_hashes[0].hash, sizeof(SBFullHash)), 0); 491 EXPECT_EQ(full_hashes[0].list_name, "goog-phish-shavar"); 492 EXPECT_EQ(full_hashes[0].add_chunk_id, 1); 493 494 hash_response += "goog-malware-shavar:7:32\n" 495 "abcdefghijklmnopqrstuvwxyz123457"; 496 full_hashes.clear(); 497 EXPECT_TRUE(parser.ParseGetHash(hash_response.data(), 498 hash_response.size(), 499 &full_hashes)); 500 501 EXPECT_EQ(full_hashes.size(), 2U); 502 EXPECT_EQ(memcmp("12345678901234567890123456789012", 503 &full_hashes[0].hash, sizeof(SBFullHash)), 0); 504 EXPECT_EQ(full_hashes[0].list_name, "goog-phish-shavar"); 505 EXPECT_EQ(full_hashes[0].add_chunk_id, 1); 506 EXPECT_EQ(memcmp("abcdefghijklmnopqrstuvwxyz123457", 507 &full_hashes[1].hash, sizeof(SBFullHash)), 0); 508 EXPECT_EQ(full_hashes[1].list_name, "goog-malware-shavar"); 509 EXPECT_EQ(full_hashes[1].add_chunk_id, 7); 510 } 511 512 TEST(SafeBrowsingProtocolParsingTest, TestFormatHash) { 513 SafeBrowsingProtocolParser parser; 514 std::vector<SBPrefix> prefixes; 515 std::string get_hash; 516 517 prefixes.push_back(0x34333231); 518 prefixes.push_back(0x64636261); 519 prefixes.push_back(0x73727170); 520 521 parser.FormatGetHash(prefixes, &get_hash); 522 EXPECT_EQ(get_hash, "4:12\n1234abcdpqrs"); 523 } 524 525 TEST(SafeBrowsingProtocolParsingTest, TestReset) { 526 SafeBrowsingProtocolParser parser; 527 std::string update("n:1800\ni:phishy\nr:pleasereset\n"); 528 529 bool reset = false; 530 int next_update = -1; 531 std::vector<SBChunkDelete> deletes; 532 std::vector<ChunkUrl> urls; 533 EXPECT_TRUE(parser.ParseUpdate(update.data(), 534 static_cast<int>(update.size()), 535 &next_update, &reset, &deletes, &urls)); 536 EXPECT_TRUE(reset); 537 } 538 539 // The SafeBrowsing service will occasionally send zero length chunks so that 540 // client requests will have longer contiguous chunk number ranges, and thus 541 // reduce the request size. 542 TEST(SafeBrowsingProtocolParsingTest, TestZeroSizeAddChunk) { 543 std::string add_chunk("a:1:4:0\n"); 544 SafeBrowsingProtocolParser parser; 545 SBChunkList chunks; 546 547 bool result = parser.ParseChunk( 548 safe_browsing_util::kMalwareList, 549 add_chunk.data(), 550 static_cast<int>(add_chunk.length()), 551 &chunks); 552 EXPECT_TRUE(result); 553 EXPECT_EQ(chunks.size(), 1U); 554 EXPECT_EQ(chunks[0].chunk_number, 1); 555 EXPECT_EQ(chunks[0].hosts.size(), 0U); 556 557 // Now test a zero size chunk in between normal chunks. 558 chunks.clear(); 559 std::string add_chunks("a:1:4:18\n1234\001abcd5678\001wxyz" 560 "a:2:4:0\n" 561 "a:3:4:9\ncafe\001beef"); 562 result = parser.ParseChunk( 563 safe_browsing_util::kMalwareList, 564 add_chunks.data(), 565 static_cast<int>(add_chunks.length()), 566 &chunks); 567 EXPECT_TRUE(result); 568 EXPECT_EQ(chunks.size(), 3U); 569 570 // See that each chunk has the right content. 571 EXPECT_EQ(chunks[0].chunk_number, 1); 572 EXPECT_EQ(chunks[0].hosts.size(), 2U); 573 EXPECT_EQ(chunks[0].hosts[0].host, 0x34333231); 574 EXPECT_EQ(chunks[0].hosts[0].entry->PrefixAt(0), 0x64636261); 575 EXPECT_EQ(chunks[0].hosts[1].host, 0x38373635); 576 EXPECT_EQ(chunks[0].hosts[1].entry->PrefixAt(0), 0x7a797877); 577 578 EXPECT_EQ(chunks[1].chunk_number, 2); 579 EXPECT_EQ(chunks[1].hosts.size(), 0U); 580 581 EXPECT_EQ(chunks[2].chunk_number, 3); 582 EXPECT_EQ(chunks[2].hosts.size(), 1U); 583 EXPECT_EQ(chunks[2].hosts[0].host, 0x65666163); 584 EXPECT_EQ(chunks[2].hosts[0].entry->PrefixAt(0), 0x66656562); 585 } 586 587 // Test parsing a zero sized sub chunk. 588 TEST(SafeBrowsingProtocolParsingTest, TestZeroSizeSubChunk) { 589 std::string sub_chunk("s:9:4:0\n"); 590 SafeBrowsingProtocolParser parser; 591 SBChunkList chunks; 592 593 bool result = parser.ParseChunk( 594 safe_browsing_util::kMalwareList, 595 sub_chunk.data(), 596 static_cast<int>(sub_chunk.length()), 597 &chunks); 598 EXPECT_TRUE(result); 599 EXPECT_EQ(chunks.size(), 1U); 600 EXPECT_EQ(chunks[0].chunk_number, 9); 601 EXPECT_EQ(chunks[0].hosts.size(), 0U); 602 chunks.clear(); 603 604 // Test parsing a zero sized sub chunk mixed in with content carrying chunks. 605 std::string sub_chunks("s:1:4:9\nabcdxwxyz" 606 "s:2:4:0\n" 607 "s:3:4:26\nefgh\0011234pqrscafe\0015678lmno"); 608 sub_chunks[12] = '\0'; 609 610 result = parser.ParseChunk( 611 safe_browsing_util::kMalwareList, 612 sub_chunks.data(), 613 static_cast<int>(sub_chunks.length()), 614 &chunks); 615 EXPECT_TRUE(result); 616 617 EXPECT_EQ(chunks[0].chunk_number, 1); 618 EXPECT_EQ(chunks[0].hosts.size(), 1U); 619 EXPECT_EQ(chunks[0].hosts[0].host, 0x64636261); 620 EXPECT_EQ(chunks[0].hosts[0].entry->prefix_count(), 0); 621 622 EXPECT_EQ(chunks[1].chunk_number, 2); 623 EXPECT_EQ(chunks[1].hosts.size(), 0U); 624 625 EXPECT_EQ(chunks[2].chunk_number, 3); 626 EXPECT_EQ(chunks[2].hosts.size(), 2U); 627 EXPECT_EQ(chunks[2].hosts[0].host, 0x68676665); 628 EXPECT_EQ(chunks[2].hosts[0].entry->prefix_count(), 1); 629 EXPECT_EQ(chunks[2].hosts[0].entry->PrefixAt(0), 0x73727170); 630 EXPECT_EQ(chunks[2].hosts[0].entry->ChunkIdAtPrefix(0), 0x31323334); 631 EXPECT_EQ(chunks[2].hosts[1].host, 0x65666163); 632 EXPECT_EQ(chunks[2].hosts[1].entry->prefix_count(), 1); 633 EXPECT_EQ(chunks[2].hosts[1].entry->PrefixAt(0), 0x6f6e6d6c); 634 EXPECT_EQ(chunks[2].hosts[1].entry->ChunkIdAtPrefix(0), 0x35363738); 635 } 636 637 TEST(SafeBrowsingProtocolParsingTest, TestAddBinHashChunks) { 638 std::string add_chunk("a:1:4:16\naaaabbbbccccdddd" 639 "a:2:4:8\n11112222"); 640 // Run the parse. 641 SafeBrowsingProtocolParser parser; 642 SBChunkList chunks; 643 bool result = parser.ParseChunk( 644 safe_browsing_util::kBinHashList, 645 add_chunk.data(), 646 static_cast<int>(add_chunk.length()), 647 &chunks); 648 EXPECT_TRUE(result); 649 EXPECT_EQ(chunks.size(), 2U); 650 EXPECT_EQ(chunks[0].chunk_number, 1); 651 EXPECT_EQ(chunks[0].hosts.size(), 1U); 652 653 EXPECT_EQ(chunks[0].hosts[0].host, 0); 654 SBEntry* entry = chunks[0].hosts[0].entry; 655 EXPECT_TRUE(entry->IsAdd()); 656 EXPECT_TRUE(entry->IsPrefix()); 657 EXPECT_EQ(entry->prefix_count(), 4); 658 659 EXPECT_EQ(chunks[1].chunk_number, 2); 660 EXPECT_EQ(chunks[1].hosts.size(), 1U); 661 662 EXPECT_EQ(chunks[1].hosts[0].host, 0); 663 entry = chunks[1].hosts[0].entry; 664 EXPECT_TRUE(entry->IsAdd()); 665 EXPECT_TRUE(entry->IsPrefix()); 666 EXPECT_EQ(entry->prefix_count(), 2); 667 EXPECT_EQ(entry->PrefixAt(0), 0x31313131); 668 EXPECT_EQ(entry->PrefixAt(1), 0x32323232); 669 } 670 671 // Test parsing one add chunk where a hostkey spans several entries. 672 TEST(SafeBrowsingProtocolParsingTest, TestAddBigBinHashChunk) { 673 std::string add_chunk("a:1:4:1028\n"); 674 for (int i = 0; i < 257; ++i) 675 add_chunk.append(base::StringPrintf("%04d", i)); 676 677 SafeBrowsingProtocolParser parser; 678 SBChunkList chunks; 679 bool result = parser.ParseChunk( 680 safe_browsing_util::kBinHashList, 681 add_chunk.data(), 682 static_cast<int>(add_chunk.length()), 683 &chunks); 684 EXPECT_TRUE(result); 685 EXPECT_EQ(chunks.size(), 1U); 686 EXPECT_EQ(chunks[0].chunk_number, 1); 687 688 EXPECT_EQ(chunks[0].hosts.size(), 1U); 689 690 const SBChunkHost& host0 = chunks[0].hosts[0]; 691 EXPECT_EQ(host0.host, 0); 692 EXPECT_EQ(host0.entry->prefix_count(), 257); 693 } 694 695 // Test parsing one sub chunk. 696 TEST(SafeBrowsingProtocolParsingTest, TestSubBinHashChunk) { 697 std::string sub_chunk("s:9:4:16\n1111mmmm2222nnnn"); 698 699 // Run the parser. 700 SafeBrowsingProtocolParser parser; 701 SBChunkList chunks; 702 bool result = parser.ParseChunk( 703 safe_browsing_util::kBinHashList, 704 sub_chunk.data(), 705 static_cast<int>(sub_chunk.length()), 706 &chunks); 707 EXPECT_TRUE(result); 708 EXPECT_EQ(chunks.size(), 1U); 709 EXPECT_EQ(chunks[0].chunk_number, 9); 710 EXPECT_EQ(chunks[0].hosts.size(), 1U); 711 712 EXPECT_EQ(chunks[0].hosts[0].host, 0); 713 SBEntry* entry = chunks[0].hosts[0].entry; 714 EXPECT_TRUE(entry->IsSub()); 715 EXPECT_TRUE(entry->IsPrefix()); 716 EXPECT_EQ(entry->prefix_count(), 2); 717 EXPECT_EQ(entry->ChunkIdAtPrefix(0), 0x31313131); 718 EXPECT_EQ(entry->PrefixAt(0), 0x6d6d6d6d); 719 EXPECT_EQ(entry->ChunkIdAtPrefix(1), 0x32323232); 720 EXPECT_EQ(entry->PrefixAt(1), 0x6e6e6e6e); 721 } 722 723 TEST(SafeBrowsingProtocolParsingTest, TestAddDownloadWhitelistChunk) { 724 std::string add_chunk("a:1:32:32\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 725 "a:2:32:64\nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" 726 "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"); 727 // Run the parse. 728 SafeBrowsingProtocolParser parser; 729 SBChunkList chunks; 730 bool result = parser.ParseChunk( 731 safe_browsing_util::kDownloadWhiteList, 732 add_chunk.data(), 733 static_cast<int>(add_chunk.length()), 734 &chunks); 735 EXPECT_TRUE(result); 736 EXPECT_EQ(chunks.size(), 2U); 737 EXPECT_EQ(chunks[0].chunk_number, 1); 738 EXPECT_EQ(chunks[0].hosts.size(), 1U); 739 EXPECT_EQ(chunks[0].hosts[0].host, 0); 740 SBEntry* entry = chunks[0].hosts[0].entry; 741 EXPECT_TRUE(entry->IsAdd()); 742 EXPECT_FALSE(entry->IsPrefix()); 743 EXPECT_EQ(entry->prefix_count(), 1); 744 SBFullHash full; 745 memcpy(full.full_hash, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 32); 746 EXPECT_TRUE(entry->FullHashAt(0) == full); 747 748 EXPECT_EQ(chunks[1].chunk_number, 2); 749 EXPECT_EQ(chunks[1].hosts.size(), 1U); 750 EXPECT_EQ(chunks[1].hosts[0].host, 0); 751 entry = chunks[1].hosts[0].entry; 752 EXPECT_TRUE(entry->IsAdd()); 753 EXPECT_FALSE(entry->IsPrefix()); 754 EXPECT_EQ(entry->prefix_count(), 2); 755 memcpy(full.full_hash, "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy", 32); 756 EXPECT_TRUE(entry->FullHashAt(0) == full); 757 memcpy(full.full_hash, "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", 32); 758 EXPECT_TRUE(entry->FullHashAt(1) == full); 759 } 760 761 // Test parsing one sub chunk. 762 TEST(SafeBrowsingProtocolParsingTest, TestSubDownloadWhitelistChunk) { 763 std::string sub_chunk("s:1:32:36\n1111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); 764 765 // Run the parser. 766 SafeBrowsingProtocolParser parser; 767 SBChunkList chunks; 768 bool result = parser.ParseChunk( 769 safe_browsing_util::kDownloadWhiteList, 770 sub_chunk.data(), 771 static_cast<int>(sub_chunk.length()), 772 &chunks); 773 ASSERT_TRUE(result); 774 ASSERT_EQ(chunks.size(), 1U); 775 EXPECT_EQ(chunks[0].chunk_number, 1); 776 EXPECT_EQ(chunks[0].hosts.size(), 1U); 777 778 EXPECT_EQ(chunks[0].hosts[0].host, 0); 779 SBEntry* entry = chunks[0].hosts[0].entry; 780 EXPECT_TRUE(entry->IsSub()); 781 ASSERT_FALSE(entry->IsPrefix()); 782 ASSERT_EQ(entry->prefix_count(), 1); 783 EXPECT_EQ(entry->ChunkIdAtPrefix(0), 0x31313131); 784 SBFullHash full; 785 memcpy(full.full_hash, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 32); 786 EXPECT_TRUE(entry->FullHashAt(0) == full); 787 } 788 789 // There should be one test case for every list added here. Each list 790 // chunk data should contain exactly one add chunk and one sub chunk. 791 TEST(SafeBrowsingProtocolParsingTest, TestAllLists) { 792 std::map<std::string, std::string> add_testdata; 793 // goog-*-shavar lists have a host-key followed by one or more prefixes. 794 add_testdata[safe_browsing_util::kMalwareList] = std::string( 795 "a:129057:4:34\n\xd9\xb8\xb2\x14\x00\xe4""B7P\x00\xaf\x91" 796 "{\xd7\x01\xad\xa6\xb5""X\xbb\xcf""F\xcf\x00\xf7""A\xbd" 797 "p\x00\xab\xd7\x89\xd3\x00", 48); 798 add_testdata[safe_browsing_util::kPhishingList] = std::string( 799 "a:301377:4:9\n\xdb\xe0\xaa\x8e\x01\x85\xba\xb2\x9e", 22); 800 add_testdata[safe_browsing_util::kBinUrlList] = std::string( 801 "a:19420:4:18\n_\x92\x9e\xcd\x01\x03""}I\xa2\\3\xe6""h\x01\xee" 802 "H\xf6\xe4", 31); 803 add_testdata[safe_browsing_util::kSideEffectFreeWhitelist] = std::string( 804 "a:1818:4:9\n\x85\xd0\xfe""i\x01""}\x98\xb1\xe5", 20); 805 // goog-*-digestvar lists have no host-key data. 806 add_testdata[safe_browsing_util::kBinHashList] = std::string( 807 "a:5:4:4\nBBBB", 12); 808 add_testdata[safe_browsing_util::kExtensionBlacklist] = std::string( 809 "a:81:4:8\nhleedfcc", 17); 810 // goog-*-sha256 lists have host-keys but they only contains 811 // full-length entires. 812 add_testdata[safe_browsing_util::kCsdWhiteList] = std::string( 813 "a:35:32:37\n\x06\xf9\xb1\xaf\x01\x06\xf9\xb1\xaf""5\xc""9!\x17\x1e" 814 "*-\xc9"",*>YSl6\xf9""B\xb8\x96""O\x98""r\xf2\xd5\x8d\xe3""T\x99", 48); 815 // goog-*-digest256 has no host-keys and contains only full-length 816 // hashes. 817 add_testdata[safe_browsing_util::kDownloadWhiteList] = std::string( 818 "a:42:32:32\n\xc8\xec\x9f\x9c\x9b\x9a"",\x82""G:F(\xe9\xad\x9c""b$\x8a" 819 "\xba""%\x19\xae""c\x03\x87""~\xd1\xd3""bvC\xfd", 43); 820 add_testdata[safe_browsing_util::kIPBlacklist] = std::string( 821 "a:12:32:32\n8\x99\x17\xda\xec""+i`\x1a\xb3""8pVh\n$\x01\xd1\x12" 822 ":\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 43); 823 824 std::map<std::string, std::string> sub_testdata; 825 // goog-*-shavar lists have a host-key, add number followed by zero or more 826 // prefixes. 827 sub_testdata[safe_browsing_util::kMalwareList] = std::string( 828 "s:122930:4:9\n\x85""!_\x13\x00\x00\x01\xf1\xa2", 22); 829 sub_testdata[safe_browsing_util::kPhishingList] = std::string( 830 "s:150181:4:9\nr\x90""zt\x00\x00\x04\x9f""@", 22); 831 sub_testdata[safe_browsing_util::kBinUrlList] = std::string( 832 "s:3:4:13\nHOST\x01""####BBBB", 22); 833 sub_testdata[safe_browsing_util::kSideEffectFreeWhitelist] = std::string( 834 "s:4:4:9\nHOST\x00""####", 17); 835 // goog-*-digestvar lists have no host-key data. 836 sub_testdata[safe_browsing_util::kBinHashList] = std::string( 837 "s:5:4:8\n####BBBB", 16); 838 sub_testdata[safe_browsing_util::kExtensionBlacklist] = std::string( 839 "s:3:4:8\n\x00\x00\x00""%pgkc", 16); 840 // goog-*-sha256 lists have host-keys but they only contains 841 // full-length entires. 842 sub_testdata[safe_browsing_util::kCsdWhiteList] = std::string( 843 "s:1:32:41\n\x1a""\"[\n\x01\x00\x00\x00\x15\x1""a\"[\n\xe9\x81""P\x11" 844 "LR\xcb""3\x00""B\x90\xb3\x15""K\xf5\xdc\xd0""V\xc2""aI\x1e""-\xc8" 845 "\xce"":\t\x01", 51); 846 // goog-*-digest256 has no host-keys and contains only full-length 847 // hashes. 848 sub_testdata[safe_browsing_util::kDownloadWhiteList] = std::string( 849 "s:15:32:36\n\x00\x00\x00""-\x12""!\xa2\x8d""z\x80""a\xfb\x14\xff" 850 "f\x13\x18\xcc\xdb\xbd\xc0\xb1""~\xd6\x82""[\xf6\xdc\xa1\x81" 851 "TI%\xef""C\xab", 47); 852 sub_testdata[safe_browsing_util::kIPBlacklist] = std::string( 853 "s:13:32:108\n\x00\x00\x00\rL2\x1e\xc6""P3\x94\x1f\xf1""Cv\x18\x9d\xdf" 854 "ih4M.c\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r_" 855 "\xfd\xbe""v\x87\xba""'\x1d\x12\r\xc0\xde""B\xc8""{a\xe7\x07""u\x11\x80" 856 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\tz\xfe\xdb" 857 "h\t\x08\xc5""dd\x9""ag\xee\xf5\x83\x91""@\xd9\xa4""i*\x80\x00\x00\x00" 858 "\x00\x00\x00\x00\x00\x00\x00\x00", 120); 859 860 SafeBrowsingProtocolParser parser; 861 for (size_t i = 0; i < arraysize(safe_browsing_util::kAllLists); ++i) { 862 std::string listname = safe_browsing_util::kAllLists[i]; 863 864 { 865 ASSERT_EQ(add_testdata.count(listname), 1U) 866 << "Missing add chunk test case for Safe Browsing list: " << listname; 867 const std::string& chunk_data = add_testdata[listname]; 868 SBChunkList chunks; 869 EXPECT_TRUE(parser.ParseChunk(listname, 870 chunk_data.data(), 871 static_cast<int>(chunk_data.length()), 872 &chunks)) 873 << "Unable to parse add chunk data for listname: " 874 << listname; 875 ASSERT_EQ(chunks.size(), 1U); 876 EXPECT_TRUE(chunks[0].is_add); 877 } 878 { 879 ASSERT_EQ(sub_testdata.count(listname), 1U) 880 << "Missing sub chunk test case for Safe Browsing list: " << listname; 881 const std::string& chunk_data = sub_testdata[listname]; 882 SBChunkList chunks; 883 EXPECT_TRUE(parser.ParseChunk(listname, 884 chunk_data.data(), 885 static_cast<int>(chunk_data.length()), 886 &chunks)) 887 << "Unable to parse sub chunk data for listname: " 888 << listname; 889 ASSERT_EQ(chunks.size(), 1U); 890 EXPECT_FALSE(chunks[0].is_add); 891 } 892 } 893 } 894