1// Copyright (c) 2006-2008 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 "base/string_util.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.
13TEST(SafeBrowsingProtocolParsingTest, TestAddChunk) {
14  std::string add_chunk("a:1:4:35\naaaax1111\0032222333344447777\00288889999");
15  add_chunk[13] = '\0';
16
17  // Run the parse.
18  SafeBrowsingProtocolParser parser;
19  bool re_key = false;
20  SBChunkList chunks;
21  bool result = parser.ParseChunk(
22      safe_browsing_util::kMalwareList,
23      add_chunk.data(),
24      static_cast<int>(add_chunk.length()),
25      "", "",  &re_key, &chunks);
26  EXPECT_TRUE(result);
27  EXPECT_FALSE(re_key);
28  EXPECT_EQ(chunks.size(), 1U);
29  EXPECT_EQ(chunks[0].chunk_number, 1);
30  EXPECT_EQ(chunks[0].hosts.size(), 3U);
31
32  EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161);
33  SBEntry* entry = chunks[0].hosts[0].entry;
34  EXPECT_TRUE(entry->IsAdd());
35  EXPECT_TRUE(entry->IsPrefix());
36  EXPECT_EQ(entry->prefix_count(), 0);
37
38  EXPECT_EQ(chunks[0].hosts[1].host, 0x31313131);
39  entry = chunks[0].hosts[1].entry;
40  EXPECT_TRUE(entry->IsAdd());
41  EXPECT_TRUE(entry->IsPrefix());
42  EXPECT_EQ(entry->prefix_count(), 3);
43  EXPECT_EQ(entry->PrefixAt(0), 0x32323232);
44  EXPECT_EQ(entry->PrefixAt(1), 0x33333333);
45  EXPECT_EQ(entry->PrefixAt(2), 0x34343434);
46
47  EXPECT_EQ(chunks[0].hosts[2].host, 0x37373737);
48  entry = chunks[0].hosts[2].entry;
49  EXPECT_TRUE(entry->IsAdd());
50  EXPECT_TRUE(entry->IsPrefix());
51  EXPECT_EQ(entry->prefix_count(), 2);
52  EXPECT_EQ(entry->PrefixAt(0), 0x38383838);
53  EXPECT_EQ(entry->PrefixAt(1), 0x39393939);
54}
55
56// Test parsing one add chunk with full hashes.
57TEST(SafeBrowsingProtocolParsingTest, TestAddFullChunk) {
58  std::string add_chunk("a:1:32:69\naaaa");
59  add_chunk.push_back(2);
60
61  SBFullHash full_hash1, full_hash2;
62  for (int i = 0; i < 32; ++i) {
63    full_hash1.full_hash[i] = i % 2 ? 1 : 2;
64    full_hash2.full_hash[i] = i % 2 ? 3 : 4;
65  }
66
67  add_chunk.append(full_hash1.full_hash, 32);
68  add_chunk.append(full_hash2.full_hash, 32);
69
70  // Run the parse.
71  SafeBrowsingProtocolParser parser;
72  bool re_key = false;
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      "", "", &re_key, &chunks);
79  EXPECT_TRUE(result);
80  EXPECT_FALSE(re_key);
81  EXPECT_EQ(chunks.size(), 1U);
82  EXPECT_EQ(chunks[0].chunk_number, 1);
83  EXPECT_EQ(chunks[0].hosts.size(), 1U);
84
85  EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161);
86  SBEntry* entry = chunks[0].hosts[0].entry;
87  EXPECT_TRUE(entry->IsAdd());
88  EXPECT_FALSE(entry->IsPrefix());
89  EXPECT_EQ(entry->prefix_count(), 2);
90  EXPECT_TRUE(entry->FullHashAt(0) == full_hash1);
91  EXPECT_TRUE(entry->FullHashAt(1) == full_hash2);
92}
93
94// Test parsing multiple add chunks. We'll use the same chunk as above, and add
95// one more after it.
96TEST(SafeBrowsingProtocolParsingTest, TestAddChunks) {
97  std::string add_chunk("a:1:4:35\naaaax1111\0032222333344447777\00288889999"
98                        "a:2:4:13\n5555\002ppppgggg");
99  add_chunk[13] = '\0';
100
101  // Run the parse.
102  SafeBrowsingProtocolParser parser;
103  bool re_key = false;
104  SBChunkList chunks;
105  bool result = parser.ParseChunk(
106      safe_browsing_util::kMalwareList,
107      add_chunk.data(),
108      static_cast<int>(add_chunk.length()),
109      "", "", &re_key, &chunks);
110  EXPECT_TRUE(result);
111  EXPECT_FALSE(re_key);
112  EXPECT_EQ(chunks.size(), 2U);
113  EXPECT_EQ(chunks[0].chunk_number, 1);
114  EXPECT_EQ(chunks[0].hosts.size(), 3U);
115
116  EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161);
117  SBEntry* entry = chunks[0].hosts[0].entry;
118  EXPECT_TRUE(entry->IsAdd());
119  EXPECT_TRUE(entry->IsPrefix());
120  EXPECT_EQ(entry->prefix_count(), 0);
121
122  EXPECT_EQ(chunks[0].hosts[1].host, 0x31313131);
123  entry = chunks[0].hosts[1].entry;
124  EXPECT_TRUE(entry->IsAdd());
125  EXPECT_TRUE(entry->IsPrefix());
126  EXPECT_EQ(entry->prefix_count(), 3);
127  EXPECT_EQ(entry->PrefixAt(0), 0x32323232);
128  EXPECT_EQ(entry->PrefixAt(1), 0x33333333);
129  EXPECT_EQ(entry->PrefixAt(2), 0x34343434);
130
131  EXPECT_EQ(chunks[0].hosts[2].host, 0x37373737);
132  entry = chunks[0].hosts[2].entry;
133  EXPECT_TRUE(entry->IsAdd());
134  EXPECT_TRUE(entry->IsPrefix());
135  EXPECT_EQ(entry->prefix_count(), 2);
136  EXPECT_EQ(entry->PrefixAt(0), 0x38383838);
137  EXPECT_EQ(entry->PrefixAt(1), 0x39393939);
138
139
140  EXPECT_EQ(chunks[1].chunk_number, 2);
141  EXPECT_EQ(chunks[1].hosts.size(), 1U);
142
143  EXPECT_EQ(chunks[1].hosts[0].host, 0x35353535);
144  entry = chunks[1].hosts[0].entry;
145  EXPECT_TRUE(entry->IsAdd());
146  EXPECT_TRUE(entry->IsPrefix());
147  EXPECT_EQ(entry->prefix_count(), 2);
148  EXPECT_EQ(entry->PrefixAt(0), 0x70707070);
149  EXPECT_EQ(entry->PrefixAt(1), 0x67676767);
150}
151
152// Test parsing one add chunk where a hostkey spans several entries.
153TEST(SafeBrowsingProtocolParsingTest, TestAddBigChunk) {
154  std::string add_chunk("a:1:4:1050\naaaaX");
155  add_chunk[add_chunk.size() - 1] |= 0xFF;
156  for (int i = 0; i < 255; ++i)
157    add_chunk.append(StringPrintf("%04d", i));
158
159  add_chunk.append("aaaa");
160  add_chunk.push_back(5);
161  for (int i = 0; i < 5; ++i)
162    add_chunk.append(StringPrintf("001%d", i));
163
164  SafeBrowsingProtocolParser parser;
165  bool re_key = false;
166  SBChunkList chunks;
167  bool result = parser.ParseChunk(
168      safe_browsing_util::kMalwareList,
169      add_chunk.data(),
170      static_cast<int>(add_chunk.length()),
171      "", "", &re_key, &chunks);
172  EXPECT_TRUE(result);
173  EXPECT_FALSE(re_key);
174  EXPECT_EQ(chunks.size(), 1U);
175  EXPECT_EQ(chunks[0].chunk_number, 1);
176
177  EXPECT_EQ(chunks[0].hosts.size(), 2U);
178
179  const SBChunkHost& host0 = chunks[0].hosts[0];
180  EXPECT_EQ(host0.host, 0x61616161);
181  EXPECT_EQ(host0.entry->prefix_count(), 255);
182
183  const SBChunkHost& host1 = chunks[0].hosts[1];
184  EXPECT_EQ(host1.host, 0x61616161);
185  EXPECT_EQ(host1.entry->prefix_count(), 5);
186}
187
188// Test to make sure we could deal with truncated bin hash chunk.
189TEST(SafeBrowsingProtocolParsingTest, TestTruncatedBinHashChunk) {
190  // This chunk delares there are 4 prefixes but actually only contains 2.
191  const char add_chunk[] = "a:1:4:16\n11112222";
192  SafeBrowsingProtocolParser parser;
193  bool re_key = false;
194  SBChunkList chunks;
195  bool result = parser.ParseChunk(add_chunk,
196                                  safe_browsing_util::kBinHashList,
197                                  static_cast<int>(sizeof(add_chunk)),
198                                  "", "", &re_key, &chunks);
199  EXPECT_FALSE(result);
200  EXPECT_FALSE(re_key);
201  EXPECT_EQ(chunks.size(), 0U);
202}
203
204// Test to make sure we could deal with truncated malwarelist chunk.
205TEST(SafeBrowsingProtocolParsingTest, TestTruncatedUrlHashChunk) {
206  // This chunk delares there are 4 prefixes but actually only contains 2.
207  const char add_chunk[] = "a:1:4:21\naaaa\00411112222";
208  SafeBrowsingProtocolParser parser;
209  bool re_key = false;
210  SBChunkList chunks;
211
212  // For safe_browsing_util::kMalwareList.
213  bool result = parser.ParseChunk(add_chunk,
214                                  safe_browsing_util::kMalwareList,
215                                  static_cast<int>(sizeof(add_chunk)),
216                                  "", "", &re_key, &chunks);
217  EXPECT_FALSE(result);
218  EXPECT_FALSE(re_key);
219  EXPECT_EQ(chunks.size(), 0U);
220
221  // For safe_browsing_util::kPhishingList.
222  result = parser.ParseChunk(add_chunk,
223                             safe_browsing_util::kPhishingList,
224                             static_cast<int>(sizeof(add_chunk)),
225                             "", "", &re_key, &chunks);
226  EXPECT_FALSE(result);
227  EXPECT_FALSE(re_key);
228  EXPECT_EQ(chunks.size(), 0U);
229
230  // For safe_browsing_util::kBinUrlList.
231  result = parser.ParseChunk(add_chunk,
232                             safe_browsing_util::kBinUrlList,
233                             static_cast<int>(sizeof(add_chunk)),
234                             "", "", &re_key, &chunks);
235  EXPECT_FALSE(result);
236  EXPECT_FALSE(re_key);
237  EXPECT_EQ(chunks.size(), 0U);
238}
239
240// Test parsing one sub chunk.
241TEST(SafeBrowsingProtocolParsingTest, TestSubChunk) {
242  std::string sub_chunk("s:9:4:59\naaaaxkkkk1111\003"
243                        "zzzz2222zzzz3333zzzz4444"
244                        "7777\002yyyy8888yyyy9999");
245  sub_chunk[13] = '\0';
246
247  // Run the parse.
248  SafeBrowsingProtocolParser parser;
249  bool re_key = false;
250  SBChunkList chunks;
251  bool result = parser.ParseChunk(
252      safe_browsing_util::kMalwareList,
253      sub_chunk.data(),
254      static_cast<int>(sub_chunk.length()),
255      "", "", &re_key, &chunks);
256  EXPECT_TRUE(result);
257  EXPECT_FALSE(re_key);
258  EXPECT_EQ(chunks.size(), 1U);
259  EXPECT_EQ(chunks[0].chunk_number, 9);
260  EXPECT_EQ(chunks[0].hosts.size(), 3U);
261
262  EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161);
263  SBEntry* entry = chunks[0].hosts[0].entry;
264  EXPECT_TRUE(entry->IsSub());
265  EXPECT_TRUE(entry->IsPrefix());
266  EXPECT_EQ(entry->chunk_id(), 0x6b6b6b6b);
267  EXPECT_EQ(entry->prefix_count(), 0);
268
269  EXPECT_EQ(chunks[0].hosts[1].host, 0x31313131);
270  entry = chunks[0].hosts[1].entry;
271  EXPECT_TRUE(entry->IsSub());
272  EXPECT_TRUE(entry->IsPrefix());
273  EXPECT_EQ(entry->prefix_count(), 3);
274  EXPECT_EQ(entry->ChunkIdAtPrefix(0), 0x7a7a7a7a);
275  EXPECT_EQ(entry->PrefixAt(0), 0x32323232);
276  EXPECT_EQ(entry->ChunkIdAtPrefix(1), 0x7a7a7a7a);
277  EXPECT_EQ(entry->PrefixAt(1), 0x33333333);
278  EXPECT_EQ(entry->ChunkIdAtPrefix(2), 0x7a7a7a7a);
279  EXPECT_EQ(entry->PrefixAt(2), 0x34343434);
280
281  EXPECT_EQ(chunks[0].hosts[2].host, 0x37373737);
282  entry = chunks[0].hosts[2].entry;
283  EXPECT_TRUE(entry->IsSub());
284  EXPECT_TRUE(entry->IsPrefix());
285  EXPECT_EQ(entry->prefix_count(), 2);
286  EXPECT_EQ(entry->ChunkIdAtPrefix(0), 0x79797979);
287  EXPECT_EQ(entry->PrefixAt(0), 0x38383838);
288  EXPECT_EQ(entry->ChunkIdAtPrefix(1), 0x79797979);
289  EXPECT_EQ(entry->PrefixAt(1), 0x39393939);
290}
291
292// Test parsing one sub chunk with full hashes.
293TEST(SafeBrowsingProtocolParsingTest, TestSubFullChunk) {
294  std::string sub_chunk("s:1:32:77\naaaa");
295  sub_chunk.push_back(2);
296
297  SBFullHash full_hash1, full_hash2;
298  for (int i = 0; i < 32; ++i) {
299    full_hash1.full_hash[i] = i % 2 ? 1 : 2;
300    full_hash2.full_hash[i] = i % 2 ? 3 : 4;
301  }
302
303  sub_chunk.append("yyyy");
304  sub_chunk.append(full_hash1.full_hash, 32);
305  sub_chunk.append("zzzz");
306  sub_chunk.append(full_hash2.full_hash, 32);
307
308  // Run the parse.
309  SafeBrowsingProtocolParser parser;
310  bool re_key = false;
311  SBChunkList chunks;
312  bool result = parser.ParseChunk(
313      safe_browsing_util::kMalwareList,
314      sub_chunk.data(),
315      static_cast<int>(sub_chunk.length()),
316      "", "", &re_key, &chunks);
317  EXPECT_TRUE(result);
318  EXPECT_FALSE(re_key);
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.
335TEST(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 re_key = false;
342  bool reset = false;
343  std::vector<SBChunkDelete> deletes;
344  std::vector<ChunkUrl> urls;
345  EXPECT_TRUE(parser.ParseUpdate(add_del.data(),
346                                 static_cast<int>(add_del.length()), "",
347                                 &next_query_sec, &re_key,
348                                 &reset, &deletes, &urls));
349
350  EXPECT_TRUE(urls.empty());
351  EXPECT_FALSE(re_key);
352  EXPECT_FALSE(reset);
353  EXPECT_EQ(next_query_sec, 1700);
354  EXPECT_EQ(deletes.size(), 2U);
355
356  EXPECT_EQ(deletes[0].chunk_del.size(), 4U);
357  EXPECT_TRUE(deletes[0].chunk_del[0] == ChunkRange(1, 7));
358  EXPECT_TRUE(deletes[0].chunk_del[1] == ChunkRange(43, 597));
359  EXPECT_TRUE(deletes[0].chunk_del[2] == ChunkRange(44444));
360  EXPECT_TRUE(deletes[0].chunk_del[3] == ChunkRange(99999));
361
362  EXPECT_EQ(deletes[1].chunk_del.size(), 3U);
363  EXPECT_TRUE(deletes[1].chunk_del[0] == ChunkRange(21, 27));
364  EXPECT_TRUE(deletes[1].chunk_del[1] == ChunkRange(42));
365  EXPECT_TRUE(deletes[1].chunk_del[2] == ChunkRange(171717));
366
367  // An update response with missing list name.
368
369  next_query_sec = 0;
370  deletes.clear();
371  urls.clear();
372  add_del = "n:1700\nad:1-7,43-597,44444,99999\ni:malware\nsd:4,21-27171717\n";
373  EXPECT_FALSE(parser.ParseUpdate(add_del.data(),
374                                  static_cast<int>(add_del.length()), "",
375                                  &next_query_sec, &re_key,
376                                  &reset, &deletes, &urls));
377}
378
379// Test parsing the SafeBrowsing update response.
380TEST(SafeBrowsingProtocolParsingTest, TestRedirects) {
381  std::string redirects("i:goog-malware-shavar\n"
382    "u:cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_1\n"
383    "u:cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_2\n"
384    "u:cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_3\n"
385    "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8641-8800:8641-8689,"
386    "8691-8731,8733-8786\n");
387
388  SafeBrowsingProtocolParser parser;
389  int next_query_sec = 0;
390  bool re_key = false;
391  bool reset = false;
392  std::vector<SBChunkDelete> deletes;
393  std::vector<ChunkUrl> urls;
394  EXPECT_TRUE(parser.ParseUpdate(redirects.data(),
395                                 static_cast<int>(redirects.length()), "",
396                                 &next_query_sec, &re_key,
397                                 &reset, &deletes, &urls));
398
399  EXPECT_FALSE(re_key);
400  EXPECT_FALSE(reset);
401  EXPECT_EQ(urls.size(), 4U);
402  EXPECT_EQ(urls[0].url,
403      "cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_1");
404  EXPECT_EQ(urls[1].url,
405      "cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_2");
406  EXPECT_EQ(urls[2].url,
407      "cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_3");
408  EXPECT_EQ(urls[3].url,
409      "s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8641-8800:8641-8689,"
410      "8691-8731,8733-8786");
411  EXPECT_EQ(next_query_sec, 0);
412  EXPECT_TRUE(deletes.empty());
413}
414
415TEST(SafeBrowsingProtocolParsingTest, TestRedirectsWithMac) {
416  std::string redirects("i:goog-phish-shavar\n"
417    "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_s_6501-6505:6501-6505,"
418    "pcY6iVeT9-CBQ3fdAF0rpnKjR1Y=\n"
419    "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8001-8160:8001-8024,"
420    "8026-8045,8048-8049,8051-8134,8136-8152,8155-8160,"
421    "j6XXAEWnjYk9tVVLBSdQvIEq2Wg=\n");
422
423  SafeBrowsingProtocolParser parser;
424  int next_query_sec = 0;
425  bool re_key = false;
426  bool reset = false;
427  const std::string key("58Lqn5WIP961x3zuLGo5Uw==");
428  std::vector<SBChunkDelete> deletes;
429  std::vector<ChunkUrl> urls;
430  EXPECT_TRUE(parser.ParseUpdate(redirects.data(),
431                                 static_cast<int>(redirects.length()), key,
432                                 &next_query_sec, &re_key,
433                                 &reset, &deletes, &urls));
434
435  EXPECT_FALSE(re_key);
436  EXPECT_FALSE(reset);
437  EXPECT_EQ(urls.size(), 2U);
438  EXPECT_EQ(urls[0].url,
439      "s.ytimg.com/safebrowsing/rd/goog-phish-shavar_s_6501-6505:6501-6505");
440  EXPECT_EQ(urls[0].mac, "pcY6iVeT9-CBQ3fdAF0rpnKjR1Y=");
441  EXPECT_EQ(urls[1].url,
442      "s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8001-8160:8001-8024,"
443      "8026-8045,8048-8049,8051-8134,8136-8152,8155-8160");
444  EXPECT_EQ(urls[1].mac, "j6XXAEWnjYk9tVVLBSdQvIEq2Wg=");
445}
446
447// Test parsing various SafeBrowsing protocol headers.
448TEST(SafeBrowsingProtocolParsingTest, TestNextQueryTime) {
449  std::string headers("n:1800\ni:goog-white-shavar\n");
450  SafeBrowsingProtocolParser parser;
451  int next_query_sec = 0;
452  bool re_key = false;
453  bool reset = false;
454  std::vector<SBChunkDelete> deletes;
455  std::vector<ChunkUrl> urls;
456  EXPECT_TRUE(parser.ParseUpdate(headers.data(),
457                                 static_cast<int>(headers.length()), "",
458                                 &next_query_sec, &re_key,
459                                 &reset, &deletes, &urls));
460
461  EXPECT_EQ(next_query_sec, 1800);
462  EXPECT_FALSE(re_key);
463  EXPECT_FALSE(reset);
464  EXPECT_TRUE(deletes.empty());
465  EXPECT_TRUE(urls.empty());
466}
467
468// Test parsing data from a GetHashRequest
469TEST(SafeBrowsingProtocolParsingTest, TestGetHash) {
470  std::string get_hash("goog-phish-shavar:19:96\n"
471                       "00112233445566778899aabbccddeeff"
472                       "00001111222233334444555566667777"
473                       "ffffeeeeddddccccbbbbaaaa99998888");
474  std::vector<SBFullHashResult> full_hashes;
475  bool re_key = false;
476  SafeBrowsingProtocolParser parser;
477  EXPECT_TRUE(parser.ParseGetHash(get_hash.data(),
478                                  static_cast<int>(get_hash.length()), "",
479                                  &re_key,
480                                  &full_hashes));
481
482  EXPECT_FALSE(re_key);
483  EXPECT_EQ(full_hashes.size(), 3U);
484  EXPECT_EQ(memcmp(&full_hashes[0].hash,
485                   "00112233445566778899aabbccddeeff",
486                   sizeof(SBFullHash)), 0);
487  EXPECT_EQ(full_hashes[0].list_name, "goog-phish-shavar");
488  EXPECT_EQ(memcmp(&full_hashes[1].hash,
489                   "00001111222233334444555566667777",
490                   sizeof(SBFullHash)), 0);
491  EXPECT_EQ(full_hashes[1].list_name, "goog-phish-shavar");
492  EXPECT_EQ(memcmp(&full_hashes[2].hash,
493                   "ffffeeeeddddccccbbbbaaaa99998888",
494                   sizeof(SBFullHash)), 0);
495  EXPECT_EQ(full_hashes[2].list_name, "goog-phish-shavar");
496
497  // Test multiple lists in the GetHash results.
498  std::string get_hash2("goog-phish-shavar:19:32\n"
499                        "00112233445566778899aabbccddeeff"
500                        "goog-malware-shavar:19:64\n"
501                        "cafebeefcafebeefdeaddeaddeaddead"
502                        "zzzzyyyyxxxxwwwwvvvvuuuuttttssss");
503  EXPECT_TRUE(parser.ParseGetHash(get_hash2.data(),
504                                  static_cast<int>(get_hash2.length()), "",
505                                  &re_key,
506                                  &full_hashes));
507
508  EXPECT_FALSE(re_key);
509  EXPECT_EQ(full_hashes.size(), 3U);
510  EXPECT_EQ(memcmp(&full_hashes[0].hash,
511                   "00112233445566778899aabbccddeeff",
512                   sizeof(SBFullHash)), 0);
513  EXPECT_EQ(full_hashes[0].list_name, "goog-phish-shavar");
514  EXPECT_EQ(memcmp(&full_hashes[1].hash,
515                   "cafebeefcafebeefdeaddeaddeaddead",
516                   sizeof(SBFullHash)), 0);
517  EXPECT_EQ(full_hashes[1].list_name, "goog-malware-shavar");
518  EXPECT_EQ(memcmp(&full_hashes[2].hash,
519                   "zzzzyyyyxxxxwwwwvvvvuuuuttttssss",
520                   sizeof(SBFullHash)), 0);
521  EXPECT_EQ(full_hashes[2].list_name, "goog-malware-shavar");
522}
523
524TEST(SafeBrowsingProtocolParsingTest, TestGetHashWithMac) {
525  const unsigned char get_hash[] = {
526    0x32, 0x56, 0x74, 0x6f, 0x6b, 0x36, 0x64, 0x41,
527    0x51, 0x72, 0x65, 0x51, 0x62, 0x38, 0x51, 0x68,
528    0x59, 0x45, 0x57, 0x51, 0x57, 0x4d, 0x52, 0x65,
529    0x42, 0x63, 0x41, 0x3d, 0x0a, 0x67, 0x6f, 0x6f,
530    0x67, 0x2d, 0x70, 0x68, 0x69, 0x73, 0x68, 0x2d,
531    0x73, 0x68, 0x61, 0x76, 0x61, 0x72, 0x3a, 0x36,
532    0x31, 0x36, 0x39, 0x3a, 0x33, 0x32, 0x0a, 0x17,
533    0x7f, 0x03, 0x42, 0x28, 0x1c, 0x31, 0xb9, 0x0b,
534    0x1c, 0x7b, 0x9d, 0xaf, 0x7b, 0x43, 0x99, 0x10,
535    0xc1, 0xab, 0xe3, 0x1b, 0x35, 0x80, 0x38, 0x96,
536    0xf9, 0x44, 0x4f, 0x28, 0xb4, 0xeb, 0x45
537  };
538
539  const unsigned char hash_result[] = {
540    0x17, 0x7f, 0x03, 0x42, 0x28, 0x1c, 0x31, 0xb9,
541    0x0b, 0x1c, 0x7b, 0x9d, 0xaf, 0x7b, 0x43, 0x99,
542    0x10, 0xc1, 0xab, 0xe3, 0x1b, 0x35, 0x80, 0x38,
543    0x96, 0xf9, 0x44, 0x4f, 0x28, 0xb4, 0xeb, 0x45
544  };
545
546  const std::string key = "58Lqn5WIP961x3zuLGo5Uw==";
547  std::vector<SBFullHashResult> full_hashes;
548  bool re_key = false;
549  SafeBrowsingProtocolParser parser;
550  EXPECT_TRUE(parser.ParseGetHash(reinterpret_cast<const char*>(get_hash),
551                                  sizeof(get_hash),
552                                  key,
553                                  &re_key,
554                                  &full_hashes));
555  EXPECT_FALSE(re_key);
556  EXPECT_EQ(full_hashes.size(), 1U);
557  EXPECT_EQ(memcmp(hash_result, &full_hashes[0].hash, sizeof(SBFullHash)), 0);
558}
559
560TEST(SafeBrowsingProtocolParsingTest, TestGetHashWithUnknownList) {
561  std::string hash_response = "goog-phish-shavar:1:32\n"
562                              "12345678901234567890123456789012"
563                              "googpub-phish-shavar:19:32\n"
564                              "09876543210987654321098765432109";
565  bool re_key = false;
566  std::string key = "";
567  std::vector<SBFullHashResult> full_hashes;
568  SafeBrowsingProtocolParser parser;
569  EXPECT_TRUE(parser.ParseGetHash(hash_response.data(),
570                                  hash_response.size(),
571                                  key,
572                                  &re_key,
573                                  &full_hashes));
574
575  EXPECT_EQ(full_hashes.size(), 1U);
576  EXPECT_EQ(memcmp("12345678901234567890123456789012",
577                   &full_hashes[0].hash, sizeof(SBFullHash)), 0);
578  EXPECT_EQ(full_hashes[0].list_name, "goog-phish-shavar");
579  EXPECT_EQ(full_hashes[0].add_chunk_id, 1);
580
581  hash_response += "goog-malware-shavar:7:32\n"
582                   "abcdefghijklmnopqrstuvwxyz123457";
583  full_hashes.clear();
584  EXPECT_TRUE(parser.ParseGetHash(hash_response.data(),
585                                  hash_response.size(),
586                                  key,
587                                  &re_key,
588                                  &full_hashes));
589
590  EXPECT_EQ(full_hashes.size(), 2U);
591  EXPECT_EQ(memcmp("12345678901234567890123456789012",
592                   &full_hashes[0].hash, sizeof(SBFullHash)), 0);
593  EXPECT_EQ(full_hashes[0].list_name, "goog-phish-shavar");
594  EXPECT_EQ(full_hashes[0].add_chunk_id, 1);
595  EXPECT_EQ(memcmp("abcdefghijklmnopqrstuvwxyz123457",
596                   &full_hashes[1].hash, sizeof(SBFullHash)), 0);
597  EXPECT_EQ(full_hashes[1].list_name, "goog-malware-shavar");
598  EXPECT_EQ(full_hashes[1].add_chunk_id, 7);
599}
600
601TEST(SafeBrowsingProtocolParsingTest, TestFormatHash) {
602  SafeBrowsingProtocolParser parser;
603  std::vector<SBPrefix> prefixes;
604  std::string get_hash;
605
606  prefixes.push_back(0x34333231);
607  prefixes.push_back(0x64636261);
608  prefixes.push_back(0x73727170);
609
610  parser.FormatGetHash(prefixes, &get_hash);
611  EXPECT_EQ(get_hash, "4:12\n1234abcdpqrs");
612}
613
614TEST(SafeBrowsingProtocolParsingTest, TestGetKey) {
615  SafeBrowsingProtocolParser parser;
616  std::string key_response("clientkey:10:0123456789\n"
617                           "wrappedkey:20:abcdefghijklmnopqrst\n");
618
619  std::string client_key, wrapped_key;
620  EXPECT_TRUE(parser.ParseNewKey(key_response.data(),
621                                 static_cast<int>(key_response.length()),
622                                 &client_key,
623                                 &wrapped_key));
624
625  EXPECT_EQ(client_key, "0123456789");
626  EXPECT_EQ(wrapped_key, "abcdefghijklmnopqrst");
627}
628
629TEST(SafeBrowsingProtocolParsingTest, TestReKey) {
630  SafeBrowsingProtocolParser parser;
631  std::string update("n:1800\ni:phishy\ne:pleaserekey\n");
632
633  bool re_key = false;
634  bool reset = false;
635  int next_update = -1;
636  std::vector<SBChunkDelete> deletes;
637  std::vector<ChunkUrl> urls;
638  EXPECT_TRUE(parser.ParseUpdate(update.data(),
639                                 static_cast<int>(update.size()), "",
640                                 &next_update, &re_key,
641                                 &reset, &deletes, &urls));
642  EXPECT_TRUE(re_key);
643}
644
645TEST(SafeBrowsingProtocolParsingTest, TestReset) {
646  SafeBrowsingProtocolParser parser;
647  std::string update("n:1800\ni:phishy\nr:pleasereset\n");
648
649  bool re_key = false;
650  bool reset = false;
651  int next_update = -1;
652  std::vector<SBChunkDelete> deletes;
653  std::vector<ChunkUrl> urls;
654  EXPECT_TRUE(parser.ParseUpdate(update.data(),
655                                 static_cast<int>(update.size()), "",
656                                 &next_update, &re_key,
657                                 &reset, &deletes, &urls));
658  EXPECT_TRUE(reset);
659}
660
661// The SafeBrowsing service will occasionally send zero length chunks so that
662// client requests will have longer contiguous chunk number ranges, and thus
663// reduce the request size.
664TEST(SafeBrowsingProtocolParsingTest, TestZeroSizeAddChunk) {
665  std::string add_chunk("a:1:4:0\n");
666  SafeBrowsingProtocolParser parser;
667  bool re_key = false;
668  SBChunkList chunks;
669
670  bool result = parser.ParseChunk(
671      safe_browsing_util::kMalwareList,
672      add_chunk.data(),
673      static_cast<int>(add_chunk.length()),
674      "", "", &re_key, &chunks);
675  EXPECT_TRUE(result);
676  EXPECT_EQ(chunks.size(), 1U);
677  EXPECT_EQ(chunks[0].chunk_number, 1);
678  EXPECT_EQ(chunks[0].hosts.size(), 0U);
679
680  // Now test a zero size chunk in between normal chunks.
681  chunks.clear();
682  std::string add_chunks("a:1:4:18\n1234\001abcd5678\001wxyz"
683                         "a:2:4:0\n"
684                         "a:3:4:9\ncafe\001beef");
685  result = parser.ParseChunk(
686      safe_browsing_util::kMalwareList,
687      add_chunks.data(),
688      static_cast<int>(add_chunks.length()),
689      "", "", &re_key, &chunks);
690  EXPECT_TRUE(result);
691  EXPECT_EQ(chunks.size(), 3U);
692
693  // See that each chunk has the right content.
694  EXPECT_EQ(chunks[0].chunk_number, 1);
695  EXPECT_EQ(chunks[0].hosts.size(), 2U);
696  EXPECT_EQ(chunks[0].hosts[0].host, 0x34333231);
697  EXPECT_EQ(chunks[0].hosts[0].entry->PrefixAt(0), 0x64636261);
698  EXPECT_EQ(chunks[0].hosts[1].host, 0x38373635);
699  EXPECT_EQ(chunks[0].hosts[1].entry->PrefixAt(0), 0x7a797877);
700
701  EXPECT_EQ(chunks[1].chunk_number, 2);
702  EXPECT_EQ(chunks[1].hosts.size(), 0U);
703
704  EXPECT_EQ(chunks[2].chunk_number, 3);
705  EXPECT_EQ(chunks[2].hosts.size(), 1U);
706  EXPECT_EQ(chunks[2].hosts[0].host, 0x65666163);
707  EXPECT_EQ(chunks[2].hosts[0].entry->PrefixAt(0), 0x66656562);
708}
709
710// Test parsing a zero sized sub chunk.
711TEST(SafeBrowsingProtocolParsingTest, TestZeroSizeSubChunk) {
712  std::string sub_chunk("s:9:4:0\n");
713  SafeBrowsingProtocolParser parser;
714  bool re_key = false;
715  SBChunkList chunks;
716
717  bool result = parser.ParseChunk(
718      safe_browsing_util::kMalwareList,
719      sub_chunk.data(),
720      static_cast<int>(sub_chunk.length()),
721      "", "", &re_key, &chunks);
722  EXPECT_TRUE(result);
723  EXPECT_EQ(chunks.size(), 1U);
724  EXPECT_EQ(chunks[0].chunk_number, 9);
725  EXPECT_EQ(chunks[0].hosts.size(), 0U);
726  chunks.clear();
727
728  // Test parsing a zero sized sub chunk mixed in with content carrying chunks.
729  std::string sub_chunks("s:1:4:9\nabcdxwxyz"
730                         "s:2:4:0\n"
731                         "s:3:4:26\nefgh\0011234pqrscafe\0015678lmno");
732  sub_chunks[12] = '\0';
733
734  result = parser.ParseChunk(
735      safe_browsing_util::kMalwareList,
736      sub_chunks.data(),
737      static_cast<int>(sub_chunks.length()),
738      "", "", &re_key, &chunks);
739  EXPECT_TRUE(result);
740
741  EXPECT_EQ(chunks[0].chunk_number, 1);
742  EXPECT_EQ(chunks[0].hosts.size(), 1U);
743  EXPECT_EQ(chunks[0].hosts[0].host, 0x64636261);
744  EXPECT_EQ(chunks[0].hosts[0].entry->prefix_count(), 0);
745
746  EXPECT_EQ(chunks[1].chunk_number, 2);
747  EXPECT_EQ(chunks[1].hosts.size(), 0U);
748
749  EXPECT_EQ(chunks[2].chunk_number, 3);
750  EXPECT_EQ(chunks[2].hosts.size(), 2U);
751  EXPECT_EQ(chunks[2].hosts[0].host, 0x68676665);
752  EXPECT_EQ(chunks[2].hosts[0].entry->prefix_count(), 1);
753  EXPECT_EQ(chunks[2].hosts[0].entry->PrefixAt(0), 0x73727170);
754  EXPECT_EQ(chunks[2].hosts[0].entry->ChunkIdAtPrefix(0), 0x31323334);
755  EXPECT_EQ(chunks[2].hosts[1].host, 0x65666163);
756  EXPECT_EQ(chunks[2].hosts[1].entry->prefix_count(), 1);
757  EXPECT_EQ(chunks[2].hosts[1].entry->PrefixAt(0), 0x6f6e6d6c);
758  EXPECT_EQ(chunks[2].hosts[1].entry->ChunkIdAtPrefix(0), 0x35363738);
759}
760
761TEST(SafeBrowsingProtocolParsingTest, TestVerifyUpdateMac) {
762  SafeBrowsingProtocolParser parser;
763
764  const std::string update =
765      "m:XIU0LiQhAPJq6dynXwHbygjS5tw=\n"
766      "n:1895\n"
767      "i:goog-phish-shavar\n"
768      "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_s_6501-6505:6501-6505,"
769        "pcY6iVeT9-CBQ3fdAF0rpnKjR1Y=\n"
770      "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_s_6506-6510:6506-6510,"
771        "SDBrYC3rX3KEPe72LOypnP6QYac=\n"
772      "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_s_6511-6520:6511-6520,"
773        "9UQo-e7OkcsXT2wFWTAhOuWOsUs=\n"
774      "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_s_6521-6560:6521-6560,"
775        "qVNw6JIpR1q6PIXST7J4LJ9n3Zg=\n"
776      "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_s_6561-6720:6561-6720,"
777        "7OiJvCbiwvpzPITW-hQohY5NHuc=\n"
778      "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_s_6721-6880:6721-6880,"
779        "oBS3svhoi9deIa0sWZ_gnD0ujj8=\n"
780      "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_s_6881-7040:6881-7040,"
781        "a0r8Xit4VvH39xgyQHZTPczKBIE=\n"
782      "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_s_7041-7200:7041-7163,"
783        "q538LChutGknBw55s6kcE2wTcvU=\n"
784      "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8001-8160:8001-8024,"
785        "8026-8045,8048-8049,8051-8134,8136-8152,8155-8160,"
786        "j6XXAEWnjYk9tVVLBSdQvIEq2Wg=\n"
787      "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8161-8320:8161-8215,"
788        "8217-8222,8224-8320,YaNfiqdQOt-uLCLWVLj46AZpAjQ=\n"
789      "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8321-8480:8321-8391,"
790        "8393-8399,8402,8404-8419,8421-8425,8427,8431-8433,8435-8439,8441-8443,"
791        "8445-8446,8448-8480,ALj31GQMwGiIeU3bM2ZYKITfU-U=\n"
792      "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8481-8640:8481-8500,"
793        "8502-8508,8510-8511,8513-8517,8519-8525,8527-8531,8533,8536-8539,"
794        "8541-8576,8578-8638,8640,TlQYRmS_kZ5PBAUIUyNQDq0Jprs=\n"
795      "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8641-8800:8641-8689,"
796        "8691-8731,8733-8786,x1Qf7hdNrO8b6yym03ZzNydDS1o=\n";
797
798  bool re_key = false;
799  bool reset = false;
800  int next_update = -1;
801  std::vector<SBChunkDelete> deletes;
802  std::vector<ChunkUrl> urls;
803  const std::string key("58Lqn5WIP961x3zuLGo5Uw==");
804  EXPECT_TRUE(parser.ParseUpdate(update.data(),
805                                 static_cast<int>(update.size()), key,
806                                 &next_update, &re_key,
807                                 &reset, &deletes, &urls));
808  EXPECT_FALSE(re_key);
809  EXPECT_EQ(next_update, 1895);
810}
811
812TEST(SafeBrowsingProtocolParsingTest, TestVerifyChunkMac) {
813  SafeBrowsingProtocolParser parser;
814
815  const unsigned char chunk[] = {
816    0x73, 0x3a, 0x32, 0x30, 0x30, 0x32, 0x3a, 0x34,
817    0x3a, 0x32, 0x32, 0x0a, 0x2f, 0x4f, 0x89, 0x7a,
818    0x01, 0x00, 0x00, 0x0a, 0x59, 0xc8, 0x71, 0xdf,
819    0x9d, 0x29, 0x0c, 0xba, 0xd7, 0x00, 0x00, 0x00,
820    0x0a, 0x59
821  };
822
823  bool re_key = false;
824  SBChunkList chunks;
825  const std::string key("v_aDSz6jI92WeHCOoZ07QA==");
826  const std::string mac("W9Xp2fUcQ9V66If6Cvsrstpa4Kk=");
827
828  EXPECT_TRUE(parser.ParseChunk(
829      safe_browsing_util::kMalwareList,
830      reinterpret_cast<const char*>(chunk),
831      sizeof(chunk), key, mac,
832      &re_key, &chunks));
833  EXPECT_FALSE(re_key);
834}
835
836TEST(SafeBrowsingProtocolParsingTest, TestAddBinHashChunks) {
837  std::string add_chunk("a:1:4:16\naaaabbbbccccdddd"
838                        "a:2:4:8\n11112222");
839  // Run the parse.
840  SafeBrowsingProtocolParser parser;
841  bool re_key = false;
842  SBChunkList chunks;
843  bool result = parser.ParseChunk(
844      safe_browsing_util::kBinHashList,
845      add_chunk.data(),
846      static_cast<int>(add_chunk.length()),
847      "", "", &re_key, &chunks);
848  EXPECT_TRUE(result);
849  EXPECT_FALSE(re_key);
850  EXPECT_EQ(chunks.size(), 2U);
851  EXPECT_EQ(chunks[0].chunk_number, 1);
852  EXPECT_EQ(chunks[0].hosts.size(), 1U);
853
854  EXPECT_EQ(chunks[0].hosts[0].host, 0);
855  SBEntry* entry = chunks[0].hosts[0].entry;
856  EXPECT_TRUE(entry->IsAdd());
857  EXPECT_TRUE(entry->IsPrefix());
858  EXPECT_EQ(entry->prefix_count(), 4);
859
860  EXPECT_EQ(chunks[1].chunk_number, 2);
861  EXPECT_EQ(chunks[1].hosts.size(), 1U);
862
863  EXPECT_EQ(chunks[1].hosts[0].host, 0);
864  entry = chunks[1].hosts[0].entry;
865  EXPECT_TRUE(entry->IsAdd());
866  EXPECT_TRUE(entry->IsPrefix());
867  EXPECT_EQ(entry->prefix_count(), 2);
868  EXPECT_EQ(entry->PrefixAt(0), 0x31313131);
869  EXPECT_EQ(entry->PrefixAt(1), 0x32323232);
870}
871
872// Test parsing one add chunk where a hostkey spans several entries.
873TEST(SafeBrowsingProtocolParsingTest, TestAddBigBinHashChunk) {
874  std::string add_chunk("a:1:4:1028\n");
875  for (int i = 0; i < 257; ++i)
876    add_chunk.append(StringPrintf("%04d", i));
877
878  SafeBrowsingProtocolParser parser;
879  bool re_key = false;
880  SBChunkList chunks;
881  bool result = parser.ParseChunk(
882      safe_browsing_util::kBinHashList,
883      add_chunk.data(),
884      static_cast<int>(add_chunk.length()),
885      "", "", &re_key, &chunks);
886  EXPECT_TRUE(result);
887  EXPECT_FALSE(re_key);
888  EXPECT_EQ(chunks.size(), 1U);
889  EXPECT_EQ(chunks[0].chunk_number, 1);
890
891  EXPECT_EQ(chunks[0].hosts.size(), 1U);
892
893  const SBChunkHost& host0 = chunks[0].hosts[0];
894  EXPECT_EQ(host0.host, 0);
895  EXPECT_EQ(host0.entry->prefix_count(), 257);
896}
897
898// Test parsing one sub chunk.
899TEST(SafeBrowsingProtocolParsingTest, TestSubBinHashChunk) {
900  std::string sub_chunk("s:9:4:16\n1111mmmm2222nnnn");
901
902  // Run the parser.
903  SafeBrowsingProtocolParser parser;
904  bool re_key = false;
905  SBChunkList chunks;
906  bool result = parser.ParseChunk(
907      safe_browsing_util::kBinHashList,
908      sub_chunk.data(),
909      static_cast<int>(sub_chunk.length()),
910      "", "", &re_key, &chunks);
911  EXPECT_TRUE(result);
912  EXPECT_FALSE(re_key);
913  EXPECT_EQ(chunks.size(), 1U);
914  EXPECT_EQ(chunks[0].chunk_number, 9);
915  EXPECT_EQ(chunks[0].hosts.size(), 1U);
916
917  EXPECT_EQ(chunks[0].hosts[0].host, 0);
918  SBEntry* entry = chunks[0].hosts[0].entry;
919  EXPECT_TRUE(entry->IsSub());
920  EXPECT_TRUE(entry->IsPrefix());
921  EXPECT_EQ(entry->prefix_count(), 2);
922  EXPECT_EQ(entry->ChunkIdAtPrefix(0), 0x31313131);
923  EXPECT_EQ(entry->PrefixAt(0), 0x6d6d6d6d);
924  EXPECT_EQ(entry->ChunkIdAtPrefix(1), 0x32323232);
925  EXPECT_EQ(entry->PrefixAt(1), 0x6e6e6e6e);
926}
927