15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parse the data returned from the SafeBrowsing v2.1 protocol response. 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// TODOv3(shess): Review these changes carefully. 8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/format_macros.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/strings/string_number_conversions.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h" 15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sys_byteorder.h" 17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/time/time.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/safe_browsing/protocol_parser.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/safe_browsing/safe_browsing_util.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Helper class for scanning a buffer. 25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class BufferReader { 26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public: 27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) BufferReader(const char* data, size_t length) 28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : data_(data), 29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) length_(length) { 30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Return info about remaining buffer data. 33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t length() const { 34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return length_; 35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const char* data() const { 37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return data_; 38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bool empty() const { 40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return length_ == 0; 41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Remove |l| characters from the buffer. 44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) void Advance(size_t l) { 45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK_LE(l, length()); 46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) data_ += l; 47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) length_ -= l; 48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Get a reference to data in the buffer. 51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // TODO(shess): I'm not sure I like this. Fill out a StringPiece instead? 52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bool RefData(const void** pptr, size_t l) { 53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (length() < l) { 54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Advance(length()); // poison 55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *pptr = data(); 59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Advance(l); 60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return true; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Copy data out of the buffer. 64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bool GetData(void* ptr, size_t l) { 65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const void* buf_ptr; 66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!RefData(&buf_ptr, l)) 67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) memcpy(ptr, buf_ptr, l); 70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return true; 71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Read a 32-bit integer in network byte order into a local uint32. 74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bool GetNet32(uint32* i) { 75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!GetData(i, sizeof(*i))) 76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *i = base::NetToHost32(*i); 79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return true; 80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Returns false if there is no data, otherwise fills |*line| with a reference 83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // to the next line of data in the buffer. 84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bool GetLine(base::StringPiece* line) { 85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!length_) 86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Find the end of the line, or the end of the input. 89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t eol = 0; 90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) while (eol < length_ && data_[eol] != '\n') { 91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ++eol; 92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) line->set(data_, eol); 94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Advance(eol); 95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Skip the newline if present. 97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (length_ && data_[0] == '\n') 98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Advance(1); 99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return true; 101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Read out |c| colon-separated pieces from the next line. The resulting 104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // pieces point into the original data buffer. 105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bool GetPieces(size_t c, std::vector<base::StringPiece>* pieces) { 106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::StringPiece line; 107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!GetLine(&line)) 108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Find the parts separated by ':'. 111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) while (pieces->size() + 1 < c) { 112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t colon_ofs = line.find(':'); 113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (colon_ofs == base::StringPiece::npos) { 114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Advance(length_); 115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pieces->push_back(line.substr(0, colon_ofs)); 119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) line.remove_prefix(colon_ofs + 1); 120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // The last piece runs to the end of the line. 123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pieces->push_back(line); 124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return true; 125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) private: 128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const char* data_; 129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t length_; 130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(BufferReader); 132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool ParseGetHashMetadata(size_t hash_count, 1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci BufferReader* reader, 1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci std::vector<SBFullHashResult>* full_hashes) { 1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (size_t i = 0; i < hash_count; ++i) { 1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::StringPiece line; 1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!reader->GetLine(&line)) 1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci size_t meta_data_len; 1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!base::StringToSizeT(line, &meta_data_len)) 1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const void* meta_data; 1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!reader->RefData(&meta_data, meta_data_len)) 1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (full_hashes) { 1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci (*full_hashes)[full_hashes->size() - hash_count + i].metadata.assign( 1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci reinterpret_cast<const char*>(meta_data), meta_data_len); 1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return true; 1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 158f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} // namespace 159f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace safe_browsing { 161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// BODY = CACHELIFETIME LF HASHENTRY* EOF 163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// CACHELIFETIME = DIGIT+ 164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// HASHENTRY = LISTNAME ":" HASHSIZE ":" NUMRESPONSES [":m"] LF 165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// HASHDATA (METADATALEN LF METADATA)* 166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// HASHSIZE = DIGIT+ # Length of each full hash 167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// NUMRESPONSES = DIGIT+ # Number of full hashes in HASHDATA 168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// HASHDATA = <HASHSIZE*NUMRESPONSES number of unsigned bytes> 169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// METADATALEN = DIGIT+ 170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// METADATA = <METADATALEN number of unsigned bytes> 171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ParseGetHash(const char* chunk_data, 172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t chunk_len, 173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::TimeDelta* cache_lifetime, 174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::vector<SBFullHashResult>* full_hashes) { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) full_hashes->clear(); 176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) BufferReader reader(chunk_data, chunk_len); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Parse out cache lifetime. 179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) { 180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::StringPiece line; 181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!reader.GetLine(&line)) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int64_t cache_lifetime_seconds; 185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!base::StringToInt64(line, &cache_lifetime_seconds)) 186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // TODO(shess): Zero also doesn't make sense, but isn't clearly forbidden, 189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // either. Maybe there should be a threshold involved. 190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (cache_lifetime_seconds < 0) 191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *cache_lifetime = base::TimeDelta::FromSeconds(cache_lifetime_seconds); 194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) while (!reader.empty()) { 197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::vector<base::StringPiece> cmd_parts; 198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!reader.GetPieces(3, &cmd_parts)) 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SBFullHashResult full_hash; 2020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch full_hash.list_id = safe_browsing_util::GetListId(cmd_parts[0]); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t hash_len; 205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!base::StringToSizeT(cmd_parts[1], &hash_len)) 206f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 207f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // TODO(shess): Is this possible? If not, why the length present? 209f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (hash_len != sizeof(SBFullHash)) 210f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 211f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 212f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Metadata is indicated by an optional ":m" at the end of the line. 213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bool has_metadata = false; 214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::StringPiece hash_count_string = cmd_parts[2]; 215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t optional_colon = hash_count_string.find(':', 0); 216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (optional_colon != base::StringPiece::npos) { 217f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (hash_count_string.substr(optional_colon) != ":m") 218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) has_metadata = true; 220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) hash_count_string.remove_suffix(2); 221f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 222f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 223f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t hash_count; 224f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!base::StringToSizeT(hash_count_string, &hash_count)) 225f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (hash_len * hash_count > reader.length()) 2285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return false; 2295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore hash results from lists we don't recognize. 2310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (full_hash.list_id < 0) { 232f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) reader.Advance(hash_len * hash_count); 2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (has_metadata && !ParseGetHashMetadata(hash_count, &reader, NULL)) 2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 238f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (size_t i = 0; i < hash_count; ++i) { 239f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!reader.GetData(&full_hash.hash, hash_len)) 240f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) full_hashes->push_back(full_hash); 242f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (has_metadata && !ParseGetHashMetadata(hash_count, &reader, full_hashes)) 2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return reader.empty(); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 251f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// BODY = HEADER LF PREFIXES EOF 252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// HEADER = PREFIXSIZE ":" LENGTH 253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// PREFIXSIZE = DIGIT+ # Size of each prefix in bytes 254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// LENGTH = DIGIT+ # Size of PREFIXES in bytes 255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)std::string FormatGetHash(const std::vector<SBPrefix>& prefixes) { 256f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::string request; 257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) request.append(base::Uint64ToString(sizeof(SBPrefix))); 258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) request.append(":"); 259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) request.append(base::Uint64ToString(sizeof(SBPrefix) * prefixes.size())); 260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) request.append("\n"); 261f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 262f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // SBPrefix values are read without concern for byte order, so write back the 263f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // same way. 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < prefixes.size(); ++i) { 265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) request.append(reinterpret_cast<const char*>(&prefixes[i]), 266f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) sizeof(SBPrefix)); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 268f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 269f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return request; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ParseUpdate(const char* chunk_data, 273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t chunk_len, 274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t* next_update_sec, 275f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bool* reset, 276f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::vector<SBChunkDelete>* deletes, 277f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::vector<ChunkUrl>* chunk_urls) { 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(next_update_sec); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(deletes); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(chunk_urls); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 282f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) BufferReader reader(chunk_data, chunk_len); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Populated below. 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string list_name; 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) while (!reader.empty()) { 288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::vector<base::StringPiece> pieces; 289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!reader.GetPieces(2, &pieces)) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::StringPiece& command = pieces[0]; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Differentiate on the first character of the command (which is usually 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // only one character, with the exception of the 'ad' and 'sd' commands). 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (command[0]) { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 'a': 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 's': { 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Must be either an 'ad' (add-del) or 'sd' (sub-del) chunk. We must 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have also parsed the list name before getting here, or the add-del 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // or sub-del will have no context. 302f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (list_name.empty() || (command != "ad" && command != "sd")) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SBChunkDelete chunk_delete; 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_delete.is_sub_del = command[0] == 's'; 306f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) StringToRanges(pieces[1].as_string(), &chunk_delete.chunk_del); 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_delete.list_name = list_name; 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deletes->push_back(chunk_delete); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 'i': 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The line providing the name of the list (i.e. 'goog-phish-shavar'). 314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) list_name = pieces[1].as_string(); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 'n': 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The line providing the next earliest time (in seconds) to re-query. 319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!base::StringToSizeT(pieces[1], next_update_sec)) 320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 'u': { 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ChunkUrl chunk_url; 325f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) chunk_url.url = pieces[1].as_string(); // Skip the initial "u:". 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_url.list_name = list_name; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_urls->push_back(chunk_url); 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 'r': 332f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (pieces[1] != "pleasereset") 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *reset = true; 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // According to the spec, we ignore commands we don't understand. 339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // TODO(shess): Does this apply to r:unknown or n:not-integer? 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 347f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// BODY = (UINT32 CHUNKDATA)+ 348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// UINT32 = Unsigned 32-bit integer in network byte order 349f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// CHUNKDATA = Encoded ChunkData protocol message 350f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ParseChunk(const char* data, 351f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t length, 352f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ScopedVector<SBChunkData>* chunks) { 353f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) BufferReader reader(data, length); 354f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 355f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) while (!reader.empty()) { 356f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uint32 l = 0; 357f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!reader.GetNet32(&l) || l == 0 || l > reader.length()) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 360f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const void* p = NULL; 361f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!reader.RefData(&p, l)) 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 364f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<SBChunkData> chunk(new SBChunkData()); 365f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!chunk->ParseFrom(reinterpret_cast<const unsigned char*>(p), l)) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 368f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) chunks->push_back(chunk.release()); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 371f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(reader.empty()); 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// LIST = LISTNAME ";" LISTINFO (":" LISTINFO)* 376f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// LISTINFO = CHUNKTYPE ":" CHUNKLIST 377f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// CHUNKTYPE = "a" | "s" 378f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// CHUNKLIST = (RANGE | NUMBER) ["," CHUNKLIST] 379f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// NUMBER = DIGIT+ 380f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// RANGE = NUMBER "-" NUMBER 381f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)std::string FormatList(const SBListChunkRanges& list) { 382f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::string formatted_results = list.name; 383f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) formatted_results.append(";"); 384f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 385f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!list.adds.empty()) 386f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) formatted_results.append("a:").append(list.adds); 387f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!list.adds.empty() && !list.subs.empty()) 388f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) formatted_results.append(":"); 389f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!list.subs.empty()) 390f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) formatted_results.append("s:").append(list.subs); 391f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) formatted_results.append("\n"); 392f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 393f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return formatted_results; 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 396f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} // namespace safe_browsing 397