| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. | 
|  | 2 // Use of this source code is governed by a BSD-style license that can be | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 #include "net/tools/domain_security_preload_generator/trie/trie_writer.h" | 
|  | 6 | 
|  | 7 #include <algorithm> | 
|  | 8 | 
|  | 9 #include "base/logging.h" | 
|  | 10 #include "base/strings/string_piece.h" | 
|  | 11 #include "base/strings/string_split.h" | 
|  | 12 #include "base/strings/string_util.h" | 
|  | 13 #include "net/tools/domain_security_preload_generator/trie/trie_bit_buffer.h" | 
|  | 14 | 
|  | 15 namespace net { | 
|  | 16 | 
|  | 17 namespace transport_security_state { | 
|  | 18 | 
|  | 19 namespace { | 
|  | 20 | 
|  | 21 bool CompareReversedEntries(const std::unique_ptr<ReversedEntry>& lhs, | 
|  | 22                             const std::unique_ptr<ReversedEntry>& rhs) { | 
|  | 23   return lhs->reversed_name < rhs->reversed_name; | 
|  | 24 } | 
|  | 25 | 
|  | 26 std::string DomainConstant(base::StringPiece input) { | 
|  | 27   std::vector<base::StringPiece> parts = base::SplitStringPiece( | 
|  | 28       input, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); | 
|  | 29   if (parts.empty()) { | 
|  | 30     return std::string(); | 
|  | 31   } | 
|  | 32 | 
|  | 33   std::string gtld = parts[parts.size() - 1].as_string(); | 
|  | 34   if (parts.size() == 1) { | 
|  | 35     return base::ToUpperASCII(gtld); | 
|  | 36   } | 
|  | 37 | 
|  | 38   std::string domain = base::ToUpperASCII(parts[parts.size() - 2].as_string()); | 
|  | 39   base::ReplaceChars(domain, "-", "_", &domain); | 
|  | 40 | 
|  | 41   return base::ToUpperASCII(domain + "_" + gtld); | 
|  | 42 } | 
|  | 43 | 
|  | 44 }  // namespace | 
|  | 45 | 
|  | 46 ReversedEntry::ReversedEntry(std::vector<uint8_t> reversed_name, | 
|  | 47                              const DomainSecurityEntry* entry) | 
|  | 48     : reversed_name(reversed_name), entry(entry) {} | 
|  | 49 | 
|  | 50 ReversedEntry::~ReversedEntry() {} | 
|  | 51 | 
|  | 52 TrieWriter::TrieWriter(const HuffmanRepresentationTable& huffman_table, | 
|  | 53                        const NameIDMap& domain_ids_map, | 
|  | 54                        const NameIDMap& expect_ct_report_uri_map, | 
|  | 55                        const NameIDMap& expect_staple_report_uri_map, | 
|  | 56                        const NameIDMap& pinsets_map, | 
|  | 57                        HuffmanFrequencyTracker* frequency_tracker) | 
|  | 58     : huffman_table_(huffman_table), | 
|  | 59       domain_ids_map_(domain_ids_map), | 
|  | 60       expect_ct_report_uri_map_(expect_ct_report_uri_map), | 
|  | 61       expect_staple_report_uri_map_(expect_staple_report_uri_map), | 
|  | 62       pinsets_map_(pinsets_map), | 
|  | 63       frequency_tracker_(frequency_tracker) {} | 
|  | 64 | 
|  | 65 TrieWriter::~TrieWriter() {} | 
|  | 66 | 
|  | 67 uint32_t TrieWriter::WriteEntries(const DomainSecurityEntries& entries) { | 
|  | 68   ReversedEntries reversed_entries; | 
|  | 69 | 
|  | 70   for (auto const& entry : entries) { | 
|  | 71     std::unique_ptr<ReversedEntry> reversed_entry( | 
|  | 72         new ReversedEntry(ReverseName(entry->hostname), entry.get())); | 
|  | 73     reversed_entries.push_back(std::move(reversed_entry)); | 
|  | 74   } | 
|  | 75 | 
|  | 76   std::stable_sort(reversed_entries.begin(), reversed_entries.end(), | 
|  | 77                    CompareReversedEntries); | 
|  | 78 | 
|  | 79   return WriteDispatchTables(reversed_entries.begin(), reversed_entries.end()); | 
|  | 80 } | 
|  | 81 | 
|  | 82 uint32_t TrieWriter::WriteDispatchTables(ReversedEntries::iterator start, | 
|  | 83                                          ReversedEntries::iterator end) { | 
|  | 84   DCHECK(start != end) << "No entries passed to WriteDispatchTables"; | 
|  | 85 | 
|  | 86   TrieBitBuffer writer; | 
|  | 87 | 
|  | 88   std::vector<uint8_t> prefix = LongestCommonPrefix(start, end); | 
|  | 89   for (size_t i = 0; i < prefix.size(); ++i) { | 
|  | 90     writer.WriteBit(1); | 
|  | 91   } | 
|  | 92   writer.WriteBit(0); | 
|  | 93 | 
|  | 94   if (prefix.size()) { | 
|  | 95     for (size_t i = 0; i < prefix.size(); ++i) { | 
|  | 96       writer.WriteChar(prefix.at(i), huffman_table_, frequency_tracker_); | 
|  | 97     } | 
|  | 98   } | 
|  | 99 | 
|  | 100   RemovePrefix(prefix.size(), start, end); | 
|  | 101   int32_t last_position = -1; | 
|  | 102 | 
|  | 103   while (start != end) { | 
|  | 104     uint8_t candidate = (*start)->reversed_name.at(0); | 
|  | 105     ReversedEntries::iterator sub_entries_end = start + 1; | 
|  | 106 | 
|  | 107     for (; sub_entries_end != end; sub_entries_end++) { | 
|  | 108       if ((*sub_entries_end)->reversed_name.at(0) != candidate) { | 
|  | 109         break; | 
|  | 110       } | 
|  | 111     } | 
|  | 112 | 
|  | 113     writer.WriteChar(candidate, huffman_table_, frequency_tracker_); | 
|  | 114 | 
|  | 115     if (candidate == kTerminalValue) { | 
|  | 116       DCHECK((sub_entries_end - start) == 1) | 
|  | 117           << "Multiple values with the same name"; | 
|  | 118       WriteSecurityEntry((*start)->entry, &writer); | 
|  | 119     } else { | 
|  | 120       RemovePrefix(1, start, sub_entries_end); | 
|  | 121       uint32_t position = WriteDispatchTables(start, sub_entries_end); | 
|  | 122       writer.WritePosition(position, &last_position); | 
|  | 123     } | 
|  | 124 | 
|  | 125     start = sub_entries_end; | 
|  | 126   } | 
|  | 127 | 
|  | 128   writer.WriteChar(kEndOfTableValue, huffman_table_, frequency_tracker_); | 
|  | 129 | 
|  | 130   uint32_t position = buffer_.position(); | 
|  | 131   writer.Flush(); | 
|  | 132   writer.WriteToBitWriter(&buffer_); | 
|  | 133   return position; | 
|  | 134 } | 
|  | 135 | 
|  | 136 void TrieWriter::WriteSecurityEntry(const DomainSecurityEntry* entry, | 
|  | 137                                     TrieBitBuffer* writer) { | 
|  | 138   uint8_t include_subdomains = 0; | 
|  | 139   if (entry->include_subdomains) { | 
|  | 140     include_subdomains = 1; | 
|  | 141   } | 
|  | 142   writer->WriteBit(include_subdomains); | 
|  | 143 | 
|  | 144   uint8_t force_https = 0; | 
|  | 145   if (entry->force_https) { | 
|  | 146     force_https = 1; | 
|  | 147   } | 
|  | 148   writer->WriteBit(force_https); | 
|  | 149 | 
|  | 150   if (entry->pinset.size()) { | 
|  | 151     writer->WriteBit(1); | 
|  | 152     NameIDMap::const_iterator pin_id_it = pinsets_map_.find(entry->pinset); | 
|  | 153     DCHECK(pin_id_it != pinsets_map_.cend()) << "invalid pinset"; | 
|  | 154     const uint8_t& pin_id = pin_id_it->second; | 
|  | 155     DCHECK(pin_id <= 16) << "too many pinsets"; | 
|  | 156     writer->WriteBits(pin_id, 4); | 
|  | 157 | 
|  | 158     NameIDMap::const_iterator domain_id_it = | 
|  | 159         domain_ids_map_.find(DomainConstant(entry->hostname)); | 
|  | 160     DCHECK(domain_id_it != domain_ids_map_.cend()) << "invalid domain id"; | 
|  | 161     uint32_t domain_id = domain_id_it->second; | 
|  | 162     DCHECK(domain_id < 512) << "too many domain ids"; | 
|  | 163     writer->WriteBits(domain_id, 9); | 
|  | 164 | 
|  | 165     if (!entry->include_subdomains) { | 
|  | 166       uint8_t include_subdomains_for_pinning = 0; | 
|  | 167       if (entry->hpkp_include_subdomains) { | 
|  | 168         include_subdomains_for_pinning = 1; | 
|  | 169       } | 
|  | 170       writer->WriteBit(include_subdomains_for_pinning); | 
|  | 171     } | 
|  | 172   } else { | 
|  | 173     writer->WriteBit(0); | 
|  | 174   } | 
|  | 175 | 
|  | 176   if (entry->expect_ct) { | 
|  | 177     writer->WriteBit(1); | 
|  | 178     NameIDMap::const_iterator expect_ct_report_uri_it = | 
|  | 179         expect_ct_report_uri_map_.find(entry->expect_ct_report_uri); | 
|  | 180     DCHECK(expect_ct_report_uri_it != expect_ct_report_uri_map_.cend()) | 
|  | 181         << "invalid expect-ct report-uri"; | 
|  | 182     const uint8_t& expect_ct_report_id = expect_ct_report_uri_it->second; | 
|  | 183 | 
|  | 184     DCHECK(expect_ct_report_id < 16) << "too many expect-ct ids"; | 
|  | 185 | 
|  | 186     writer->WriteBits(expect_ct_report_id, 4); | 
|  | 187   } else { | 
|  | 188     writer->WriteBit(0); | 
|  | 189   } | 
|  | 190 | 
|  | 191   if (entry->expect_staple) { | 
|  | 192     writer->WriteBit(1); | 
|  | 193 | 
|  | 194     if (entry->expect_staple_include_subdomains) { | 
|  | 195       writer->WriteBit(1); | 
|  | 196     } else { | 
|  | 197       writer->WriteBit(0); | 
|  | 198     } | 
|  | 199 | 
|  | 200     NameIDMap::const_iterator expect_staple_report_uri_it = | 
|  | 201         expect_staple_report_uri_map_.find(entry->expect_staple_report_uri); | 
|  | 202     DCHECK(expect_staple_report_uri_it != expect_staple_report_uri_map_.cend()) | 
|  | 203         << "invalid expect-ct report-uri"; | 
|  | 204     const uint8_t& expect_staple_report_id = | 
|  | 205         expect_staple_report_uri_it->second; | 
|  | 206     DCHECK(expect_staple_report_id < 16) << "too many expect-staple ids"; | 
|  | 207 | 
|  | 208     writer->WriteBits(expect_staple_report_id, 4); | 
|  | 209   } else { | 
|  | 210     writer->WriteBit(0); | 
|  | 211   } | 
|  | 212 } | 
|  | 213 | 
|  | 214 void TrieWriter::RemovePrefix(size_t length, | 
|  | 215                               ReversedEntries::iterator start, | 
|  | 216                               ReversedEntries::iterator end) { | 
|  | 217   for (ReversedEntries::iterator it = start; it != end; ++it) { | 
|  | 218     (*it)->reversed_name.erase((*it)->reversed_name.begin(), | 
|  | 219                                (*it)->reversed_name.begin() + length); | 
|  | 220   } | 
|  | 221 } | 
|  | 222 | 
|  | 223 std::vector<uint8_t> TrieWriter::LongestCommonPrefix( | 
|  | 224     ReversedEntries::iterator start, | 
|  | 225     ReversedEntries::iterator end) const { | 
|  | 226   if (start == end) { | 
|  | 227     return std::vector<uint8_t>(); | 
|  | 228   } | 
|  | 229 | 
|  | 230   std::vector<uint8_t> prefix; | 
|  | 231   for (size_t i = 0;; ++i) { | 
|  | 232     if (i > (*start)->reversed_name.size()) { | 
|  | 233       break; | 
|  | 234     } | 
|  | 235 | 
|  | 236     uint8_t candidate = (*start)->reversed_name.at(i); | 
|  | 237     if (candidate == kTerminalValue) { | 
|  | 238       break; | 
|  | 239     } | 
|  | 240 | 
|  | 241     bool ok = true; | 
|  | 242     for (ReversedEntries::iterator it = start + 1; it != end; ++it) { | 
|  | 243       if (i > (*it)->reversed_name.size() || | 
|  | 244           (*it)->reversed_name.at(i) != candidate) { | 
|  | 245         ok = false; | 
|  | 246         break; | 
|  | 247       } | 
|  | 248     } | 
|  | 249 | 
|  | 250     if (!ok) { | 
|  | 251       break; | 
|  | 252     } | 
|  | 253 | 
|  | 254     prefix.push_back(candidate); | 
|  | 255   } | 
|  | 256 | 
|  | 257   return prefix; | 
|  | 258 } | 
|  | 259 | 
|  | 260 std::vector<uint8_t> TrieWriter::ReverseName( | 
|  | 261     const std::string& hostname) const { | 
|  | 262   size_t hostname_size = hostname.size(); | 
|  | 263   std::vector<uint8_t> reversed_name(hostname_size + 1); | 
|  | 264 | 
|  | 265   for (size_t i = 0; i < hostname_size; ++i) { | 
|  | 266     reversed_name[i] = hostname[hostname_size - i - 1]; | 
|  | 267   } | 
|  | 268 | 
|  | 269   reversed_name[reversed_name.size() - 1] = kTerminalValue; | 
|  | 270   return reversed_name; | 
|  | 271 } | 
|  | 272 | 
|  | 273 uint32_t TrieWriter::position() const { | 
|  | 274   return buffer_.position(); | 
|  | 275 } | 
|  | 276 | 
|  | 277 void TrieWriter::Flush() { | 
|  | 278   buffer_.Flush(); | 
|  | 279 } | 
|  | 280 | 
|  | 281 }  // namespace transport_security_state | 
|  | 282 | 
|  | 283 }  // namespace net | 
| OLD | NEW | 
|---|