13345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Parse the data returned from the SafeBrowsing v2.1 protocol response.
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include <stdlib.h>
872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/safe_browsing/protocol_parser.h"
1072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/safe_browsing/safe_browsing_util.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "build/build_config.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <Winsock2.h>
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_POSIX)
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <arpa/inet.h>
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/format_macros.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_split.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Helper function for quick scans of a line oriented protocol. Note that we use
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   std::string::assign(const charT* s, size_type n)
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// to copy data into 'line'. This form of 'assign' does not call strlen on
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 'input', which is binary data and is not NULL terminated. 'input' may also
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// contain valid NULL bytes in the payload, which a strlen based copy would
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// truncate.
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetLine(const char* input, int input_len, std::string* line) {
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char* pos = input;
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (pos && (pos - input < input_len)) {
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (*pos == '\n') {
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      line->assign(input, pos - input);
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ++pos;
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//------------------------------------------------------------------------------
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// SafeBrowsingParser implementation
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSafeBrowsingProtocolParser::SafeBrowsingProtocolParser() {
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SafeBrowsingProtocolParser::ParseGetHash(
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char* chunk_data,
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int chunk_len,
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& key,
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool* re_key,
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<SBFullHashResult>* full_hashes) {
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  full_hashes->clear();
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int length = chunk_len;
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char* data = chunk_data;
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int offset;
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string line;
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!key.empty()) {
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!GetLine(data, length, &line))
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;  // Error! Bad GetHash result.
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (line == "e:pleaserekey") {
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      *re_key = true;
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    offset = static_cast<int>(line.size()) + 1;
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    data += offset;
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    length -= offset;
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!safe_browsing_util::VerifyMAC(key, line, data, length))
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (length > 0) {
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!GetLine(data, length, &line))
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    offset = static_cast<int>(line.size()) + 1;
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    data += offset;
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    length -= offset;
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<std::string> cmd_parts;
89731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    base::SplitString(line, ':', &cmd_parts);
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (cmd_parts.size() != 3)
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SBFullHashResult full_hash;
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    full_hash.list_name = cmd_parts[0];
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    full_hash.add_chunk_id = atoi(cmd_parts[1].c_str());
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int full_hash_len = atoi(cmd_parts[2].c_str());
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Ignore hash results from lists we don't recognize.
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (safe_browsing_util::GetListId(full_hash.list_name) < 0) {
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      data += full_hash_len;
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      length -= full_hash_len;
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    while (full_hash_len > 0) {
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DCHECK(static_cast<size_t>(full_hash_len) >= sizeof(SBFullHash));
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      memcpy(&full_hash.hash, data, sizeof(SBFullHash));
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      full_hashes->push_back(full_hash);
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      data += sizeof(SBFullHash);
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      length -= sizeof(SBFullHash);
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      full_hash_len -= sizeof(SBFullHash);
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return length == 0;
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingProtocolParser::FormatGetHash(
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   const std::vector<SBPrefix>& prefixes, std::string* request) {
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(request);
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Format the request for GetHash.
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request->append(StringPrintf("%" PRIuS ":%" PRIuS "\n",
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               sizeof(SBPrefix),
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               sizeof(SBPrefix) * prefixes.size()));
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < prefixes.size(); ++i) {
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    request->append(reinterpret_cast<const char*>(&prefixes[i]),
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    sizeof(SBPrefix));
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SafeBrowsingProtocolParser::ParseUpdate(
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char* chunk_data,
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int chunk_len,
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& key,
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int* next_update_sec,
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool* re_key,
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool* reset,
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<SBChunkDelete>* deletes,
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<ChunkUrl>* chunk_urls) {
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(next_update_sec);
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(deletes);
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(chunk_urls);
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int length = chunk_len;
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char* data = chunk_data;
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Populated below.
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string list_name;
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (length > 0) {
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string cmd_line;
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!GetLine(data, length, &cmd_line))
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;  // Error: bad list format!
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<std::string> cmd_parts;
157731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    base::SplitString(cmd_line, ':', &cmd_parts);
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (cmd_parts.empty())
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& command = cmd_parts[0];
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (cmd_parts.size() != 2 && command[0] != 'u')
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const int consumed = static_cast<int>(cmd_line.size()) + 1;
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    data += consumed;
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    length -= consumed;
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (length < 0)
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;  // Parsing error.
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Differentiate on the first character of the command (which is usually
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // only one character, with the exception of the 'ad' and 'sd' commands).
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    switch (command[0]) {
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case 'a':
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case 's': {
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Must be either an 'ad' (add-del) or 'sd' (sub-del) chunk. We must
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // have also parsed the list name before getting here, or the add-del
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // or sub-del will have no context.
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (command.size() != 2 || command[1] != 'd' || list_name.empty())
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return false;
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SBChunkDelete chunk_delete;
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        chunk_delete.is_sub_del = command[0] == 's';
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        StringToRanges(cmd_parts[1], &chunk_delete.chunk_del);
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        chunk_delete.list_name = list_name;
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        deletes->push_back(chunk_delete);
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case 'e':
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (cmd_parts[1] != "pleaserekey")
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return false;
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        *re_key = true;
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case 'i':
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // The line providing the name of the list (i.e. 'goog-phish-shavar').
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        list_name = cmd_parts[1];
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case 'm':
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Verify that the MAC of the remainer of this chunk is what we expect.
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!key.empty() &&
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            !safe_browsing_util::VerifyMAC(key, cmd_parts[1], data, length))
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return false;
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case 'n':
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // The line providing the next earliest time (in seconds) to re-query.
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        *next_update_sec = atoi(cmd_parts[1].c_str());
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case 'u': {
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // The redirect command is of the form: u:<url>,<mac> where <url> can
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // contain multiple colons, commas or any valid URL characters. We scan
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // backwards in the string looking for the first ',' we encounter and
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // assume that everything before that is the URL and everything after
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // is the MAC (if the MAC was requested).
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::string mac;
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::string redirect_url(cmd_line, 2);  // Skip the initial "u:".
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!key.empty()) {
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          std::string::size_type mac_pos = redirect_url.rfind(',');
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          if (mac_pos == std::string::npos)
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            return false;
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          mac = redirect_url.substr(mac_pos + 1);
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          redirect_url = redirect_url.substr(0, mac_pos);
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ChunkUrl chunk_url;
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        chunk_url.url = redirect_url;
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        chunk_url.list_name = list_name;
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!key.empty())
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          chunk_url.mac = mac;
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        chunk_urls->push_back(chunk_url);
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case 'r':
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (cmd_parts[1] != "pleasereset")
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return false;
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        *reset = true;
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default:
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // According to the spec, we ignore commands we don't understand.
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
25172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool SafeBrowsingProtocolParser::ParseChunk(const std::string& list_name,
25272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                            const char* data,
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            int length,
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            const std::string& key,
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            const std::string& mac,
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            bool* re_key,
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            SBChunkList* chunks) {
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int remaining = length;
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char* chunk_data = data;
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!key.empty() &&
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !safe_browsing_util::VerifyMAC(key, mac, data, length)) {
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (remaining > 0) {
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string cmd_line;
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!GetLine(chunk_data, length, &cmd_line))
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;  // Error: bad chunk format!
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const int line_len = static_cast<int>(cmd_line.length()) + 1;
27272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    chunk_data += line_len;
27372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    remaining -= line_len;
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<std::string> cmd_parts;
275731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    base::SplitString(cmd_line, ':', &cmd_parts);
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Handle a possible re-key command.
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (cmd_parts.size() != 4) {
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (cmd_parts.size() == 2 &&
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          cmd_parts[0] == "e" &&
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          cmd_parts[1] == "pleaserekey") {
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        *re_key = true;
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Process the chunk data.
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const int chunk_number = atoi(cmd_parts[1].c_str());
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const int hash_len = atoi(cmd_parts[2].c_str());
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (hash_len != sizeof(SBPrefix) && hash_len != sizeof(SBFullHash)) {
292513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      VLOG(1) << "ParseChunk got unknown hashlen " << hash_len;
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const int chunk_len = atoi(cmd_parts[3].c_str());
29772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
29872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (remaining < chunk_len)
29972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return false;  // parse error.
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    chunks->push_back(SBChunk());
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    chunks->back().chunk_number = chunk_number;
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (cmd_parts[0] == "a") {
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chunks->back().is_add = true;
30672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (!ParseAddChunk(list_name, chunk_data, chunk_len, hash_len,
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         &chunks->back().hosts))
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;  // Parse error.
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (cmd_parts[0] == "s") {
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chunks->back().is_add = false;
31172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (!ParseSubChunk(list_name, chunk_data, chunk_len, hash_len,
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         &chunks->back().hosts))
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;  // Parse error.
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    chunk_data += chunk_len;
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    remaining -= chunk_len;
32172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    DCHECK_LE(0, remaining);
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(remaining == 0);
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
32972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool SafeBrowsingProtocolParser::ParseAddChunk(const std::string& list_name,
33072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                               const char* data,
33172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                               int data_len,
33272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                               int hash_len,
33372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                               std::deque<SBChunkHost>* hosts) {
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char* chunk_data = data;
33572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int remaining = data_len;
33672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int prefix_count;
33772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  SBEntry::Type type = hash_len == sizeof(SBPrefix) ?
33872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      SBEntry::ADD_PREFIX : SBEntry::ADD_FULL_HASH;
33972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
34072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (list_name == safe_browsing_util::kBinHashList) {
34172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // kBinHashList only contains prefixes, no HOSTKEY and COUNT.
34272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    DCHECK_EQ(0, remaining % hash_len);
34372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    prefix_count = remaining / hash_len;
34472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    SBChunkHost chunk_host;
34572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    chunk_host.host = 0;
34672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    chunk_host.entry = SBEntry::Create(type, prefix_count);
34772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    hosts->push_back(chunk_host);
34872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!ReadPrefixes(&chunk_data, &remaining, chunk_host.entry, prefix_count))
34972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return false;
35072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else {
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SBPrefix host;
35272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const int min_size = sizeof(SBPrefix) + 1;
35372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    while (remaining >= min_size) {
35472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      ReadHostAndPrefixCount(&chunk_data, &remaining, &host, &prefix_count);
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SBChunkHost chunk_host;
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chunk_host.host = host;
35772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      chunk_host.entry = SBEntry::Create(type, prefix_count);
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      hosts->push_back(chunk_host);
35972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (!ReadPrefixes(&chunk_data, &remaining, chunk_host.entry,
36072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                        prefix_count))
36172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        return false;
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return remaining == 0;
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
36772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool SafeBrowsingProtocolParser::ParseSubChunk(const std::string& list_name,
36872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                               const char* data,
36972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                               int data_len,
37072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                               int hash_len,
37172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                               std::deque<SBChunkHost>* hosts) {
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int remaining = data_len;
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char* chunk_data = data;
37472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int prefix_count;
37572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  SBEntry::Type type = hash_len == sizeof(SBPrefix) ?
37672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      SBEntry::SUB_PREFIX : SBEntry::SUB_FULL_HASH;
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (list_name == safe_browsing_util::kBinHashList) {
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SBChunkHost chunk_host;
38072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // Set host to 0 and it won't be used for kBinHashList.
38172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    chunk_host.host = 0;
38272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // kBinHashList only contains (add_chunk_number, prefix) pairs, no HOSTKEY
38372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // and COUNT. |add_chunk_number| is int32.
38472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    prefix_count = remaining / (sizeof(int32) + hash_len);
38572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    chunk_host.entry = SBEntry::Create(type, prefix_count);
38672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!ReadPrefixes(&chunk_data, &remaining, chunk_host.entry, prefix_count))
38772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return false;
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    hosts->push_back(chunk_host);
38972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else {
39072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    SBPrefix host;
39172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const int min_size = 2 * sizeof(SBPrefix) + 1;
39272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    while (remaining >= min_size) {
39372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      ReadHostAndPrefixCount(&chunk_data, &remaining, &host, &prefix_count);
39472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      SBChunkHost chunk_host;
39572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      chunk_host.host = host;
39672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      chunk_host.entry = SBEntry::Create(type, prefix_count);
39772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      hosts->push_back(chunk_host);
39872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (prefix_count == 0) {
39972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        // There is only an add chunk number (no prefixes).
40072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        chunk_host.entry->set_chunk_id(ReadChunkId(&chunk_data, &remaining));
40172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        continue;
40272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      }
40372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (!ReadPrefixes(&chunk_data, &remaining, chunk_host.entry,
40472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                        prefix_count))
40572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        return false;
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return remaining == 0;
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingProtocolParser::ReadHostAndPrefixCount(
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char** data, int* remaining, SBPrefix* host, int* count) {
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Next 4 bytes are the host prefix.
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(host, *data, sizeof(SBPrefix));
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *data += sizeof(SBPrefix);
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *remaining -= sizeof(SBPrefix);
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Next 1 byte is the prefix count (could be zero, but never negative).
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *count = static_cast<unsigned char>(**data);
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *data += 1;
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *remaining -= 1;
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SafeBrowsingProtocolParser::ReadChunkId(
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char** data, int* remaining) {
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int chunk_number;
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(&chunk_number, *data, sizeof(chunk_number));
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *data += sizeof(chunk_number);
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *remaining -= sizeof(chunk_number);
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return htonl(chunk_number);
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SafeBrowsingProtocolParser::ReadPrefixes(
43472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const char** data, int* remaining, SBEntry* entry, int count) {
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int hash_len = entry->HashLen();
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < count; ++i) {
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (entry->IsSub()) {
43872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      entry->SetChunkIdAtPrefix(i, ReadChunkId(data, remaining));
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (*remaining <= 0)
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (entry->IsPrefix()) {
44472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      entry->SetPrefixAt(i, *reinterpret_cast<const SBPrefix*>(*data));
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
44672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      entry->SetFullHashAt(i, *reinterpret_cast<const SBFullHash*>(*data));
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *data += hash_len;
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *remaining -= hash_len;
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (*remaining < 0)
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SafeBrowsingProtocolParser::ParseNewKey(const char* chunk_data,
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             int chunk_length,
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             std::string* client_key,
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             std::string* wrapped_key) {
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(client_key && wrapped_key);
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  client_key->clear();
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  wrapped_key->clear();
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char* data = chunk_data;
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int remaining = chunk_length;
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (remaining > 0) {
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string line;
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!GetLine(data, remaining, &line))
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<std::string> cmd_parts;
474731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    base::SplitString(line, ':', &cmd_parts);
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (cmd_parts.size() != 3)
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (static_cast<int>(cmd_parts[2].size()) != atoi(cmd_parts[1].c_str()))
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (cmd_parts[0] == "clientkey") {
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      client_key->assign(cmd_parts[2]);
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (cmd_parts[0] == "wrappedkey") {
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      wrapped_key->assign(cmd_parts[2]);
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    data += line.size() + 1;
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    remaining -= static_cast<int>(line.size()) + 1;
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (client_key->empty() || wrapped_key->empty())
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
498