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.
TEST(SafeBrowsingProtocolParsingTest,TestAddChunk)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.
TEST(SafeBrowsingProtocolParsingTest,TestAddFullChunk)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.
TEST(SafeBrowsingProtocolParsingTest,TestAddChunks)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
TEST(SafeBrowsingProtocolParsingTest,TestTruncatedPrefixChunk)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
TEST(SafeBrowsingProtocolParsingTest,TestTruncatedFullHashChunk)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
TEST(SafeBrowsingProtocolParsingTest,TestHugeChunk)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.
TEST(SafeBrowsingProtocolParsingTest,TestSubChunk)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.
TEST(SafeBrowsingProtocolParsingTest,TestSubFullChunk)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.
TEST(SafeBrowsingProtocolParsingTest,TestChunkDelete)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.
TEST(SafeBrowsingProtocolParsingTest,TestRedirects)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.
TEST(SafeBrowsingProtocolParsingTest,TestNextQueryTime)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
TEST(SafeBrowsingProtocolParsingTest,TestGetHash)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
TEST(SafeBrowsingProtocolParsingTest,TestGetHashWithUnknownList)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
TEST(SafeBrowsingProtocolParsingTest,TestFormatHash)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
TEST(SafeBrowsingProtocolParsingTest,TestReset)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.
TEST(SafeBrowsingProtocolParsingTest,TestZeroSizeAddChunk)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.
TEST(SafeBrowsingProtocolParsingTest,TestZeroSizeSubChunk)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