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 #include <string> 6 7 #include "base/time/time.h" 8 #include "chrome/browser/safe_browsing/protocol_parser.h" 9 #include "chrome/browser/safe_browsing/safe_browsing_util.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 // Test parsing one add chunk. 13 TEST(SafeBrowsingProtocolParsingTest, TestAddChunk) { 14 const char kRawAddChunk[] = { 15 '\0', '\0', '\0', '\x1C', // 32-bit payload length in network byte order. 16 '\x08', // field 1, wire format varint 17 '\x01', // chunk_number varint 1 18 '\x22', // field 4, wire format length-delimited 19 '\x18', // varint length 24 20 '1', '1', '1', '1', // 4-byte prefixes 21 '2', '2', '2', '2', 22 '3', '3', '3', '3', 23 '4', '4', '4', '4', 24 '8', '8', '8', '8', 25 '9', '9', '9', '9', 26 }; 27 28 ScopedVector<SBChunkData> chunks; 29 EXPECT_TRUE(safe_browsing::ParseChunk(kRawAddChunk, sizeof(kRawAddChunk), 30 &chunks)); 31 ASSERT_EQ(1U, chunks.size()); 32 EXPECT_EQ(1, chunks[0]->ChunkNumber()); 33 EXPECT_TRUE(chunks[0]->IsAdd()); 34 EXPECT_FALSE(chunks[0]->IsSub()); 35 EXPECT_TRUE(chunks[0]->IsPrefix()); 36 EXPECT_FALSE(chunks[0]->IsFullHash()); 37 ASSERT_EQ(6U, chunks[0]->PrefixCount()); 38 EXPECT_EQ(0x31313131U, chunks[0]->PrefixAt(0)); // 1111 39 EXPECT_EQ(0x32323232U, chunks[0]->PrefixAt(1)); // 2222 40 EXPECT_EQ(0x33333333U, chunks[0]->PrefixAt(2)); // 3333 41 EXPECT_EQ(0x34343434U, chunks[0]->PrefixAt(3)); // 4444 42 EXPECT_EQ(0x38383838U, chunks[0]->PrefixAt(4)); // 8888 43 EXPECT_EQ(0x39393939U, chunks[0]->PrefixAt(5)); // 9999 44 } 45 46 // Test parsing one add chunk with full hashes. 47 TEST(SafeBrowsingProtocolParsingTest, TestAddFullChunk) { 48 const char kRawAddChunk[] = { 49 '\0', '\0', '\0', '\x46', // 32-bit payload length in network byte order. 50 '\x08', // field 1, wire format varint 51 '\x01', // chunk_number varint 1 52 '\x18', // field 3, wire format varint 53 '\x01', // enum PrefixType == FULL_32B 54 '\x22', // field 4, wire format length-delimited 55 '\x40', // varint length 64 (2 full hashes) 56 57 '0', '1', '0', '1', '0', '1', '0', '1', 58 '0', '1', '0', '1', '0', '1', '0', '1', 59 '0', '1', '0', '1', '0', '1', '0', '1', 60 '0', '1', '0', '1', '0', '1', '0', '1', 61 62 '2', '3', '2', '3', '2', '3', '2', '3', 63 '2', '3', '2', '3', '2', '3', '2', '3', 64 '2', '3', '2', '3', '2', '3', '2', '3', 65 '2', '3', '2', '3', '2', '3', '2', '3', 66 }; 67 68 SBFullHash full_hash1, full_hash2; 69 for (int i = 0; i < 32; ++i) { 70 full_hash1.full_hash[i] = i % 2 ? '1' : '0'; 71 full_hash2.full_hash[i] = i % 2 ? '3' : '2'; 72 } 73 74 ScopedVector<SBChunkData> chunks; 75 EXPECT_TRUE(safe_browsing::ParseChunk(kRawAddChunk, sizeof(kRawAddChunk), 76 &chunks)); 77 ASSERT_EQ(1U, chunks.size()); 78 EXPECT_EQ(1, chunks[0]->ChunkNumber()); 79 EXPECT_TRUE(chunks[0]->IsAdd()); 80 EXPECT_FALSE(chunks[0]->IsSub()); 81 EXPECT_FALSE(chunks[0]->IsPrefix()); 82 EXPECT_TRUE(chunks[0]->IsFullHash()); 83 84 ASSERT_EQ(2U, chunks[0]->FullHashCount()); 85 EXPECT_TRUE(SBFullHashEqual(chunks[0]->FullHashAt(0), full_hash1)); 86 EXPECT_TRUE(SBFullHashEqual(chunks[0]->FullHashAt(1), full_hash2)); 87 } 88 89 // Test parsing multiple add chunks. We'll use the same chunk as above, and add 90 // one more after it. 91 TEST(SafeBrowsingProtocolParsingTest, TestAddChunks) { 92 const char kRawAddChunk[] = { 93 '\0', '\0', '\0', '\x1C', // 32-bit payload length in network byte order. 94 '\x08', // field 1, wire format varint 95 '\x01', // chunk_number varint 1 96 '\x22', // field 4, wire format length-delimited 97 '\x18', // varint length 24 98 99 '1', '1', '1', '1', // 4-byte prefixes 100 '2', '2', '2', '2', 101 '3', '3', '3', '3', 102 '4', '4', '4', '4', 103 '8', '8', '8', '8', 104 '9', '9', '9', '9', 105 106 '\0', '\0', '\0', '\x0C', // 32-bit payload length in network byte order. 107 '\x08', // field 1, wire format varint 108 '\x02', // chunk_number varint 1 109 '\x22', // field 4, wire format length-delimited 110 '\x08', // varint length 8 111 'p', 'p', 'p', 'p', // 4-byte prefixes 112 'g', 'g', 'g', 'g', 113 }; 114 115 ScopedVector<SBChunkData> chunks; 116 EXPECT_TRUE(safe_browsing::ParseChunk(kRawAddChunk, sizeof(kRawAddChunk), 117 &chunks)); 118 ASSERT_EQ(2U, chunks.size()); 119 120 EXPECT_EQ(1, chunks[0]->ChunkNumber()); 121 EXPECT_TRUE(chunks[0]->IsAdd()); 122 EXPECT_FALSE(chunks[0]->IsSub()); 123 EXPECT_TRUE(chunks[0]->IsPrefix()); 124 EXPECT_FALSE(chunks[0]->IsFullHash()); 125 ASSERT_EQ(6U, chunks[0]->PrefixCount()); 126 EXPECT_EQ(0x31313131U, chunks[0]->PrefixAt(0)); // 1111 127 EXPECT_EQ(0x32323232U, chunks[0]->PrefixAt(1)); // 2222 128 EXPECT_EQ(0x33333333U, chunks[0]->PrefixAt(2)); // 3333 129 EXPECT_EQ(0x34343434U, chunks[0]->PrefixAt(3)); // 4444 130 EXPECT_EQ(0x38383838U, chunks[0]->PrefixAt(4)); // 8888 131 EXPECT_EQ(0x39393939U, chunks[0]->PrefixAt(5)); // 9999 132 133 EXPECT_EQ(2, chunks[1]->ChunkNumber()); 134 EXPECT_TRUE(chunks[1]->IsAdd()); 135 EXPECT_FALSE(chunks[1]->IsSub()); 136 EXPECT_TRUE(chunks[1]->IsPrefix()); 137 EXPECT_FALSE(chunks[1]->IsFullHash()); 138 ASSERT_EQ(2U, chunks[1]->PrefixCount()); 139 EXPECT_EQ(0x70707070U, chunks[1]->PrefixAt(0)); // pppp 140 EXPECT_EQ(0x67676767U, chunks[1]->PrefixAt(1)); // gggg 141 } 142 143 TEST(SafeBrowsingProtocolParsingTest, TestTruncatedPrefixChunk) { 144 // This chunk delares there are 6 prefixes but actually only contains 3. 145 const char kRawAddChunk[] = { 146 '\0', '\0', '\0', '\x1C', // 32-bit payload length in network byte order. 147 '\x08', // field 1, wire format varint 148 '\x01', // chunk_number varint 1 149 '\x22', // field 4, wire format length-delimited 150 '\x18', // varint length 24 151 '1', '1', '1', '1', // 4-byte prefixes 152 '2', '2', '2', '2', 153 '3', '3', '3', '3', 154 }; 155 156 ScopedVector<SBChunkData> chunks; 157 EXPECT_FALSE(safe_browsing::ParseChunk(kRawAddChunk, sizeof(kRawAddChunk), 158 &chunks)); 159 } 160 161 TEST(SafeBrowsingProtocolParsingTest, TestTruncatedFullHashChunk) { 162 // This chunk delares there are two full hashes but there is only one. 163 const char kRawAddChunk[] = { 164 '\0', '\0', '\0', '\x46', // 32-bit payload length in network byte order. 165 '\x08', // field 1, wire format varint 166 '\x01', // chunk_number varint 1 167 '\x18', // field 3, wire format varint 168 '\x01', // enum PrefixType == FULL_32B 169 '\x22', // field 4, wire format length-delimited 170 '\x40', // varint length 64 (2 full hashes) 171 172 '0', '1', '0', '1', '0', '1', '0', '1', 173 '0', '1', '0', '1', '0', '1', '0', '1', 174 '0', '1', '0', '1', '0', '1', '0', '1', 175 '0', '1', '0', '1', '0', '1', '0', '1', 176 }; 177 178 ScopedVector<SBChunkData> chunks; 179 EXPECT_FALSE(safe_browsing::ParseChunk(kRawAddChunk, sizeof(kRawAddChunk), 180 &chunks)); 181 } 182 183 TEST(SafeBrowsingProtocolParsingTest, TestHugeChunk) { 184 // This chunk delares there are 6 prefixes but actually only contains 3. 185 const char kRawAddChunk[] = { 186 '\x1', '\0', '\0', '\0', // 32-bit payload length in network byte order. 187 '\x08', // field 1, wire format varint 188 '\x01', // chunk_number varint 1 189 '\x22', // field 4, wire format length-delimited 190 '\x18', // varint length 24 191 '1', '1', '1', '1', // 4-byte prefixes 192 '2', '2', '2', '2', 193 '3', '3', '3', '3', 194 }; 195 196 ScopedVector<SBChunkData> chunks; 197 EXPECT_FALSE(safe_browsing::ParseChunk(kRawAddChunk, sizeof(kRawAddChunk), 198 &chunks)); 199 } 200 201 // Test parsing one sub chunk. 202 TEST(SafeBrowsingProtocolParsingTest, TestSubChunk) { 203 const char kRawSubChunk[] = { 204 '\0', '\0', '\0', '\x12', // 32-bit payload length in network byte order 205 '\x08', // field 1, wire format varint 206 '\x03', // chunk_number varint 3 207 '\x10', // field 2, wire format varint 208 '\x01', // enum ChunkType == SUB 209 '\x22', // field 4, wire format length-delimited 210 '\x08', // varint length 8 (2 prefixes) 211 '1', '1', '1', '1', // 4-byte prefixes 212 '2', '2', '2', '2', 213 '\x2a', // field 5, wire format length-delimited 214 '\x02', // varint length 2 (2 add-chunk numbers) 215 '\x07', '\x09', // varint 7, varint 9 216 }; 217 218 ScopedVector<SBChunkData> chunks; 219 EXPECT_TRUE(safe_browsing::ParseChunk(kRawSubChunk, sizeof(kRawSubChunk), 220 &chunks)); 221 ASSERT_EQ(1U, chunks.size()); 222 EXPECT_EQ(3, chunks[0]->ChunkNumber()); 223 EXPECT_FALSE(chunks[0]->IsAdd()); 224 EXPECT_TRUE(chunks[0]->IsSub()); 225 EXPECT_TRUE(chunks[0]->IsPrefix()); 226 EXPECT_FALSE(chunks[0]->IsFullHash()); 227 ASSERT_EQ(2U, chunks[0]->PrefixCount()); 228 EXPECT_EQ(0x31313131U, chunks[0]->PrefixAt(0)); // 1111 229 EXPECT_EQ(7, chunks[0]->AddChunkNumberAt(0)); 230 EXPECT_EQ(0x32323232U, chunks[0]->PrefixAt(1)); // 2222 231 EXPECT_EQ(9, chunks[0]->AddChunkNumberAt(1)); 232 } 233 234 // Test parsing one sub chunk with full hashes. 235 TEST(SafeBrowsingProtocolParsingTest, TestSubFullChunk) { 236 const char kRawSubChunk[] = { 237 '\0', '\0', '\0', '\x4C', // 32-bit payload length in network byte order. 238 '\x08', // field 1, wire format varint 239 '\x02', // chunk_number varint 2 240 '\x10', // field 2, wire format varint 241 '\x01', // enum ChunkType == SUB 242 '\x18', // field 3, wire format varint 243 '\x01', // enum PrefixType == FULL_32B 244 '\x22', // field 4, wire format length-delimited 245 '\x40', // varint length 64 (2 full hashes) 246 247 '0', '1', '0', '1', '0', '1', '0', '1', 248 '0', '1', '0', '1', '0', '1', '0', '1', 249 '0', '1', '0', '1', '0', '1', '0', '1', 250 '0', '1', '0', '1', '0', '1', '0', '1', 251 252 '2', '3', '2', '3', '2', '3', '2', '3', 253 '2', '3', '2', '3', '2', '3', '2', '3', 254 '2', '3', '2', '3', '2', '3', '2', '3', 255 '2', '3', '2', '3', '2', '3', '2', '3', 256 257 '\x2a', // field 5, wire format length-delimited 258 '\x02', // varint length 2 (2 add-chunk numbers) 259 '\x07', '\x09', // varint 7, varint 9 260 }; 261 262 SBFullHash full_hash1, full_hash2; 263 for (int i = 0; i < 32; ++i) { 264 full_hash1.full_hash[i] = i % 2 ? '1' : '0'; 265 full_hash2.full_hash[i] = i % 2 ? '3' : '2'; 266 } 267 268 ScopedVector<SBChunkData> chunks; 269 EXPECT_TRUE(safe_browsing::ParseChunk(kRawSubChunk, sizeof(kRawSubChunk), 270 &chunks)); 271 ASSERT_EQ(1U, chunks.size()); 272 EXPECT_EQ(2, chunks[0]->ChunkNumber()); 273 EXPECT_FALSE(chunks[0]->IsAdd()); 274 EXPECT_TRUE(chunks[0]->IsSub()); 275 EXPECT_FALSE(chunks[0]->IsPrefix()); 276 EXPECT_TRUE(chunks[0]->IsFullHash()); 277 278 ASSERT_EQ(2U, chunks[0]->FullHashCount()); 279 EXPECT_TRUE(SBFullHashEqual(chunks[0]->FullHashAt(0), full_hash1)); 280 EXPECT_EQ(7, chunks[0]->AddChunkNumberAt(0)); 281 EXPECT_TRUE(SBFullHashEqual(chunks[0]->FullHashAt(1), full_hash2)); 282 EXPECT_EQ(9, chunks[0]->AddChunkNumberAt(1)); 283 } 284 285 // Test parsing the SafeBrowsing update response. 286 TEST(SafeBrowsingProtocolParsingTest, TestChunkDelete) { 287 std::string add_del("n:1700\ni:phishy\nad:1-7,43-597,44444,99999\n" 288 "i:malware\nsd:21-27,42,171717\n"); 289 290 size_t next_query_sec = 0; 291 bool reset = false; 292 std::vector<SBChunkDelete> deletes; 293 std::vector<ChunkUrl> urls; 294 EXPECT_TRUE(safe_browsing::ParseUpdate(add_del.data(), add_del.length(), 295 &next_query_sec, &reset, 296 &deletes, &urls)); 297 298 EXPECT_TRUE(urls.empty()); 299 EXPECT_FALSE(reset); 300 EXPECT_EQ(1700U, next_query_sec); 301 ASSERT_EQ(2U, deletes.size()); 302 303 ASSERT_EQ(4U, deletes[0].chunk_del.size()); 304 EXPECT_TRUE(deletes[0].chunk_del[0] == ChunkRange(1, 7)); 305 EXPECT_TRUE(deletes[0].chunk_del[1] == ChunkRange(43, 597)); 306 EXPECT_TRUE(deletes[0].chunk_del[2] == ChunkRange(44444)); 307 EXPECT_TRUE(deletes[0].chunk_del[3] == ChunkRange(99999)); 308 309 ASSERT_EQ(3U, deletes[1].chunk_del.size()); 310 EXPECT_TRUE(deletes[1].chunk_del[0] == ChunkRange(21, 27)); 311 EXPECT_TRUE(deletes[1].chunk_del[1] == ChunkRange(42)); 312 EXPECT_TRUE(deletes[1].chunk_del[2] == ChunkRange(171717)); 313 314 // An update response with missing list name. 315 next_query_sec = 0; 316 deletes.clear(); 317 urls.clear(); 318 add_del = "n:1700\nad:1-7,43-597,44444,99999\ni:malware\nsd:4,21-27171717\n"; 319 EXPECT_FALSE(safe_browsing::ParseUpdate(add_del.data(), add_del.length(), 320 &next_query_sec, &reset, 321 &deletes, &urls)); 322 } 323 324 // Test parsing the SafeBrowsing update response. 325 TEST(SafeBrowsingProtocolParsingTest, TestRedirects) { 326 std::string redirects("i:goog-malware-shavar\n" 327 "u:cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_1\n" 328 "u:cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_2\n" 329 "u:cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_3\n" 330 "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8641-8800:8641-8689," 331 "8691-8731,8733-8786\n"); 332 333 size_t next_query_sec = 0; 334 bool reset = false; 335 std::vector<SBChunkDelete> deletes; 336 std::vector<ChunkUrl> urls; 337 EXPECT_TRUE(safe_browsing::ParseUpdate(redirects.data(), redirects.length(), 338 &next_query_sec, &reset, 339 &deletes, &urls)); 340 EXPECT_FALSE(reset); 341 EXPECT_EQ(0U, next_query_sec); 342 EXPECT_TRUE(deletes.empty()); 343 344 ASSERT_EQ(4U, urls.size()); 345 EXPECT_EQ("cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_1", 346 urls[0].url); 347 EXPECT_EQ("cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_2", 348 urls[1].url); 349 EXPECT_EQ("cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_3", 350 urls[2].url); 351 EXPECT_EQ("s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8641-8800:" 352 "8641-8689,8691-8731,8733-8786", 353 urls[3].url); 354 } 355 356 // Test parsing various SafeBrowsing protocol headers. 357 TEST(SafeBrowsingProtocolParsingTest, TestNextQueryTime) { 358 std::string headers("n:1800\ni:goog-white-shavar\n"); 359 size_t next_query_sec = 0; 360 bool reset = false; 361 std::vector<SBChunkDelete> deletes; 362 std::vector<ChunkUrl> urls; 363 EXPECT_TRUE(safe_browsing::ParseUpdate(headers.data(), headers.length(), 364 &next_query_sec, &reset, 365 &deletes, &urls)); 366 367 EXPECT_EQ(1800U, next_query_sec); 368 EXPECT_FALSE(reset); 369 EXPECT_TRUE(deletes.empty()); 370 EXPECT_TRUE(urls.empty()); 371 } 372 373 // Test parsing data from a GetHashRequest 374 TEST(SafeBrowsingProtocolParsingTest, TestGetHash) { 375 std::string get_hash("45\n" 376 "goog-phish-shavar:32:3\n" 377 "00112233445566778899aabbccddeeff" 378 "00001111222233334444555566667777" 379 "ffffeeeeddddccccbbbbaaaa99998888"); 380 std::vector<SBFullHashResult> full_hashes; 381 base::TimeDelta cache_lifetime; 382 EXPECT_TRUE(safe_browsing::ParseGetHash(get_hash.data(), get_hash.length(), 383 &cache_lifetime, &full_hashes)); 384 385 ASSERT_EQ(3U, full_hashes.size()); 386 EXPECT_EQ(memcmp(&full_hashes[0].hash, 387 "00112233445566778899aabbccddeeff", 388 sizeof(SBFullHash)), 0); 389 EXPECT_EQ(safe_browsing_util::PHISH, full_hashes[0].list_id); 390 EXPECT_EQ(memcmp(&full_hashes[1].hash, 391 "00001111222233334444555566667777", 392 sizeof(SBFullHash)), 0); 393 EXPECT_EQ(safe_browsing_util::PHISH, full_hashes[1].list_id); 394 EXPECT_EQ(memcmp(&full_hashes[2].hash, 395 "ffffeeeeddddccccbbbbaaaa99998888", 396 sizeof(SBFullHash)), 0); 397 EXPECT_EQ(safe_browsing_util::PHISH, full_hashes[2].list_id); 398 399 // Test multiple lists in the GetHash results. 400 std::string get_hash2("45\n" 401 "goog-phish-shavar:32:1\n" 402 "00112233445566778899aabbccddeeff" 403 "goog-malware-shavar:32:2\n" 404 "cafebeefcafebeefdeaddeaddeaddead" 405 "zzzzyyyyxxxxwwwwvvvvuuuuttttssss"); 406 EXPECT_TRUE(safe_browsing::ParseGetHash(get_hash2.data(), get_hash2.length(), 407 &cache_lifetime, &full_hashes)); 408 409 ASSERT_EQ(3U, full_hashes.size()); 410 EXPECT_EQ(memcmp(&full_hashes[0].hash, 411 "00112233445566778899aabbccddeeff", 412 sizeof(SBFullHash)), 0); 413 EXPECT_EQ(safe_browsing_util::PHISH, full_hashes[0].list_id); 414 EXPECT_EQ(memcmp(&full_hashes[1].hash, 415 "cafebeefcafebeefdeaddeaddeaddead", 416 sizeof(SBFullHash)), 0); 417 EXPECT_EQ(safe_browsing_util::MALWARE, full_hashes[1].list_id); 418 EXPECT_EQ(memcmp(&full_hashes[2].hash, 419 "zzzzyyyyxxxxwwwwvvvvuuuuttttssss", 420 sizeof(SBFullHash)), 0); 421 EXPECT_EQ(safe_browsing_util::MALWARE, full_hashes[2].list_id); 422 423 // Test metadata parsing. 424 // TODO(shess): Currently the code doesn't actually put the metadata anywhere, 425 // this is just testing that metadata doesn't break parsing. 426 std::string get_hash3("45\n" 427 "goog-malware-shavar:32:2:m\n" 428 "zzzzyyyyxxxxwwwwvvvvuuuuttttssss" 429 "00112233445566778899aabbccddeeff" 430 "2\nab2\nxy" 431 "goog-phish-shavar:32:1\n" 432 "cafebeefcafebeefdeaddeaddeaddead"); 433 EXPECT_TRUE(safe_browsing::ParseGetHash(get_hash3.data(), get_hash3.length(), 434 &cache_lifetime, &full_hashes)); 435 436 ASSERT_EQ(3U, full_hashes.size()); 437 EXPECT_EQ(memcmp(&full_hashes[0].hash, 438 "zzzzyyyyxxxxwwwwvvvvuuuuttttssss", 439 sizeof(SBFullHash)), 0); 440 EXPECT_EQ(safe_browsing_util::MALWARE, full_hashes[0].list_id); 441 EXPECT_EQ(memcmp(&full_hashes[1].hash, 442 "00112233445566778899aabbccddeeff", 443 sizeof(SBFullHash)), 0); 444 EXPECT_EQ(safe_browsing_util::MALWARE, full_hashes[1].list_id); 445 EXPECT_EQ(memcmp(&full_hashes[2].hash, 446 "cafebeefcafebeefdeaddeaddeaddead", 447 sizeof(SBFullHash)), 0); 448 EXPECT_EQ(safe_browsing_util::PHISH, full_hashes[2].list_id); 449 } 450 451 TEST(SafeBrowsingProtocolParsingTest, TestGetHashWithUnknownList) { 452 std::string hash_response = "45\n" 453 "goog-phish-shavar:32:1\n" 454 "12345678901234567890123456789012" 455 "googpub-phish-shavar:32:1\n" 456 "09876543210987654321098765432109"; 457 std::vector<SBFullHashResult> full_hashes; 458 base::TimeDelta cache_lifetime; 459 EXPECT_TRUE(safe_browsing::ParseGetHash(hash_response.data(), 460 hash_response.size(), 461 &cache_lifetime, 462 &full_hashes)); 463 464 ASSERT_EQ(1U, full_hashes.size()); 465 EXPECT_EQ(memcmp("12345678901234567890123456789012", 466 &full_hashes[0].hash, sizeof(SBFullHash)), 0); 467 EXPECT_EQ(safe_browsing_util::PHISH, full_hashes[0].list_id); 468 469 hash_response += "goog-malware-shavar:32:1\n" 470 "abcdefghijklmnopqrstuvwxyz123457"; 471 full_hashes.clear(); 472 EXPECT_TRUE(safe_browsing::ParseGetHash(hash_response.data(), 473 hash_response.size(), 474 &cache_lifetime, 475 &full_hashes)); 476 477 EXPECT_EQ(2U, full_hashes.size()); 478 EXPECT_EQ(memcmp("12345678901234567890123456789012", 479 &full_hashes[0].hash, sizeof(SBFullHash)), 0); 480 EXPECT_EQ(safe_browsing_util::PHISH, full_hashes[0].list_id); 481 EXPECT_EQ(memcmp("abcdefghijklmnopqrstuvwxyz123457", 482 &full_hashes[1].hash, sizeof(SBFullHash)), 0); 483 EXPECT_EQ(safe_browsing_util::MALWARE, full_hashes[1].list_id); 484 } 485 486 TEST(SafeBrowsingProtocolParsingTest, TestFormatHash) { 487 std::vector<SBPrefix> prefixes; 488 prefixes.push_back(0x34333231); 489 prefixes.push_back(0x64636261); 490 prefixes.push_back(0x73727170); 491 492 EXPECT_EQ("4:12\n1234abcdpqrs", safe_browsing::FormatGetHash(prefixes)); 493 } 494 495 TEST(SafeBrowsingProtocolParsingTest, TestReset) { 496 std::string update("n:1800\ni:phishy\nr:pleasereset\n"); 497 498 bool reset = false; 499 size_t next_update = 0; 500 std::vector<SBChunkDelete> deletes; 501 std::vector<ChunkUrl> urls; 502 EXPECT_TRUE(safe_browsing::ParseUpdate(update.data(), update.size(), 503 &next_update, &reset, 504 &deletes, &urls)); 505 EXPECT_TRUE(reset); 506 } 507 508 // The SafeBrowsing service will occasionally send zero length chunks so that 509 // client requests will have longer contiguous chunk number ranges, and thus 510 // reduce the request size. 511 TEST(SafeBrowsingProtocolParsingTest, TestZeroSizeAddChunk) { 512 const char kEmptyAddChunk[] = { 513 '\0', '\0', '\0', '\x02', // 32-bit payload length in network byte order. 514 '\x08', // field 1, wire format varint 515 '\x02', // chunk_number varint 2 516 }; 517 518 ScopedVector<SBChunkData> chunks; 519 EXPECT_TRUE(safe_browsing::ParseChunk(kEmptyAddChunk, sizeof(kEmptyAddChunk), 520 &chunks)); 521 ASSERT_EQ(1U, chunks.size()); 522 EXPECT_EQ(2, chunks[0]->ChunkNumber()); 523 EXPECT_TRUE(chunks[0]->IsAdd()); 524 EXPECT_FALSE(chunks[0]->IsSub()); 525 EXPECT_TRUE(chunks[0]->IsPrefix()); 526 EXPECT_FALSE(chunks[0]->IsFullHash()); 527 EXPECT_EQ(0U, chunks[0]->PrefixCount()); 528 529 // Now test a zero size chunk in between normal chunks. 530 chunks.clear(); 531 const char kAddChunks[] = { 532 '\0', '\0', '\0', '\x0C', // 32-bit payload length in network byte order. 533 '\x08', // field 1, wire format varint 534 '\x01', // chunk_number varint 1 535 '\x22', // field 4, wire format length-delimited 536 '\x08', // varint length 8 537 538 '1', '1', '1', '1', // 4-byte prefixes 539 '2', '2', '2', '2', 540 541 '\0', '\0', '\0', '\x02', // 32-bit payload length in network byte order. 542 '\x08', // field 1, wire format varint 543 '\x02', // chunk_number varint 2 544 545 '\0', '\0', '\0', '\x08', // 32-bit payload length in network byte order. 546 '\x08', // field 1, wire format varint 547 '\x03', // chunk_number varint 3 548 '\x22', // field 4, wire format length-delimited 549 '\x04', // varint length 8 550 'p', 'p', 'p', 'p', // 4-byte prefixes 551 }; 552 EXPECT_TRUE(safe_browsing::ParseChunk(kAddChunks, sizeof(kAddChunks), 553 &chunks)); 554 ASSERT_EQ(3U, chunks.size()); 555 556 EXPECT_EQ(1, chunks[0]->ChunkNumber()); 557 EXPECT_TRUE(chunks[0]->IsAdd()); 558 EXPECT_FALSE(chunks[0]->IsSub()); 559 EXPECT_TRUE(chunks[0]->IsPrefix()); 560 EXPECT_FALSE(chunks[0]->IsFullHash()); 561 ASSERT_EQ(2U, chunks[0]->PrefixCount()); 562 EXPECT_EQ(0x31313131U, chunks[0]->PrefixAt(0)); // 1111 563 EXPECT_EQ(0x32323232U, chunks[0]->PrefixAt(1)); // 2222 564 565 EXPECT_EQ(2, chunks[1]->ChunkNumber()); 566 EXPECT_TRUE(chunks[1]->IsAdd()); 567 EXPECT_FALSE(chunks[1]->IsSub()); 568 EXPECT_TRUE(chunks[1]->IsPrefix()); 569 EXPECT_FALSE(chunks[1]->IsFullHash()); 570 EXPECT_EQ(0U, chunks[1]->PrefixCount()); 571 572 EXPECT_EQ(3, chunks[2]->ChunkNumber()); 573 EXPECT_TRUE(chunks[2]->IsAdd()); 574 EXPECT_FALSE(chunks[2]->IsSub()); 575 EXPECT_TRUE(chunks[2]->IsPrefix()); 576 EXPECT_FALSE(chunks[2]->IsFullHash()); 577 ASSERT_EQ(1U, chunks[2]->PrefixCount()); 578 EXPECT_EQ(0x70707070U, chunks[2]->PrefixAt(0)); // pppp 579 } 580 581 // Test parsing a zero sized sub chunk. 582 TEST(SafeBrowsingProtocolParsingTest, TestZeroSizeSubChunk) { 583 const char kEmptySubChunk[] = { 584 '\0', '\0', '\0', '\x04', // 32-bit payload length in network byte order. 585 '\x08', // field 1, wire format varint 586 '\x02', // chunk_number varint 2 587 '\x10', // field 2, wire format varint 588 '\x01', // enum ChunkType == SUB 589 }; 590 591 ScopedVector<SBChunkData> chunks; 592 EXPECT_TRUE(safe_browsing::ParseChunk(kEmptySubChunk, sizeof(kEmptySubChunk), 593 &chunks)); 594 ASSERT_EQ(1U, chunks.size()); 595 EXPECT_EQ(2, chunks[0]->ChunkNumber()); 596 EXPECT_FALSE(chunks[0]->IsAdd()); 597 EXPECT_TRUE(chunks[0]->IsSub()); 598 EXPECT_TRUE(chunks[0]->IsPrefix()); 599 EXPECT_FALSE(chunks[0]->IsFullHash()); 600 EXPECT_EQ(0U, chunks[0]->PrefixCount()); 601 602 // Test parsing a zero sized sub chunk mixed in with content carrying chunks. 603 chunks.clear(); 604 const char kSubChunks[] = { 605 '\0', '\0', '\0', '\x12', // 32-bit payload length in network byte order. 606 '\x08', // field 1, wire format varint 607 '\x01', // chunk_number varint 1 608 '\x10', // field 2, wire format varint 609 '\x01', // enum ChunkType == SUB 610 '\x22', // field 4, wire format length-delimited 611 '\x08', // varint length 8 612 '1', '1', '1', '1', // 4-byte prefixes 613 '2', '2', '2', '2', 614 '\x2a', // field 5, wire format length-delimited 615 '\x02', // varint length 2 (2 add-chunk numbers) 616 '\x07', '\x09', // varint 7, varint 9 617 618 '\0', '\0', '\0', '\x04', // 32-bit payload length in network byte order. 619 '\x08', // field 1, wire format varint 620 '\x02', // chunk_number varint 2 621 '\x10', // field 2, wire format varint 622 '\x01', // enum ChunkType == SUB 623 624 '\0', '\0', '\0', '\x0D', // 32-bit payload length in network byte order. 625 '\x08', // field 1, wire format varint 626 '\x03', // chunk_number varint 3 627 '\x10', // field 2, wire format varint 628 '\x01', // enum ChunkType == SUB 629 '\x22', // field 4, wire format length-delimited 630 '\x04', // varint length 8 631 'p', 'p', 'p', 'p', // 4-byte prefix 632 '\x2a', // field 5, wire format length-delimited 633 '\x01', // varint length 1 (1 add-chunk numbers) 634 '\x0B', // varint 11 635 }; 636 637 EXPECT_TRUE(safe_browsing::ParseChunk(kSubChunks, sizeof(kSubChunks), 638 &chunks)); 639 ASSERT_EQ(3U, chunks.size()); 640 641 EXPECT_EQ(1, chunks[0]->ChunkNumber()); 642 EXPECT_FALSE(chunks[0]->IsAdd()); 643 EXPECT_TRUE(chunks[0]->IsSub()); 644 EXPECT_TRUE(chunks[0]->IsPrefix()); 645 EXPECT_FALSE(chunks[0]->IsFullHash()); 646 ASSERT_EQ(2U, chunks[0]->PrefixCount()); 647 EXPECT_EQ(0x31313131U, chunks[0]->PrefixAt(0)); // 1111 648 EXPECT_EQ(7, chunks[0]->AddChunkNumberAt(0)); 649 EXPECT_EQ(0x32323232U, chunks[0]->PrefixAt(1)); // 2222 650 EXPECT_EQ(9, chunks[0]->AddChunkNumberAt(1)); 651 652 EXPECT_EQ(2, chunks[1]->ChunkNumber()); 653 EXPECT_FALSE(chunks[0]->IsAdd()); 654 EXPECT_TRUE(chunks[0]->IsSub()); 655 EXPECT_TRUE(chunks[1]->IsPrefix()); 656 EXPECT_FALSE(chunks[1]->IsFullHash()); 657 EXPECT_EQ(0U, chunks[1]->PrefixCount()); 658 659 EXPECT_EQ(3, chunks[2]->ChunkNumber()); 660 EXPECT_FALSE(chunks[0]->IsAdd()); 661 EXPECT_TRUE(chunks[0]->IsSub()); 662 EXPECT_TRUE(chunks[2]->IsPrefix()); 663 EXPECT_FALSE(chunks[2]->IsFullHash()); 664 ASSERT_EQ(1U, chunks[2]->PrefixCount()); 665 EXPECT_EQ(0x70707070U, chunks[2]->PrefixAt(0)); // pppp 666 EXPECT_EQ(11, chunks[2]->AddChunkNumberAt(0)); 667 } 668