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