2 * Copyright 2014 The Chromium Authors. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 // This file is subset of chromium-efl/net/http/transport_security_state.cc
33 #include "net/http/transport_security_state.h"
34 #include "net/http/transport_security_state_static.h"
35 #include "base/logging.h"
39 // BitReader is a class that allows a bytestring to be read bit-by-bit.
42 BitReader(const uint8* bytes, size_t num_bits)
45 num_bytes_((num_bits + 7) / 8),
46 current_byte_index_(0),
49 // Next sets |*out| to the next bit from the input. It returns false if no
50 // more bits are available or true otherwise.
51 bool Next(bool* out) {
52 if (num_bits_used_ == 8) {
53 if (current_byte_index_ >= num_bytes_) {
56 current_byte_ = bytes_[current_byte_index_++];
60 *out = 1 & (current_byte_ >> (7 - num_bits_used_));
65 // Read sets the |num_bits| least-significant bits of |*out| to the value of
66 // the next |num_bits| bits from the input. It returns false if there are
67 // insufficient bits in the input or true otherwise.
68 bool Read(unsigned num_bits, uint32* out) {
69 DCHECK_LE(num_bits, 32u);
72 for (unsigned i = 0; i < num_bits; ++i) {
77 ret |= static_cast<uint32>(bit) << (num_bits - 1 - i);
84 // Unary sets |*out| to the result of decoding a unary value from the input.
85 // It returns false if there were insufficient bits in the input and true
87 bool Unary(size_t* out) {
105 // Seek sets the current offest in the input to bit number |offset|. It
106 // returns true if |offset| is within the range of the input and false
108 bool Seek(size_t offset) {
109 if (offset >= num_bits_) {
112 current_byte_index_ = offset / 8;
113 current_byte_ = bytes_[current_byte_index_++];
114 num_bits_used_ = offset % 8;
119 const uint8* const bytes_;
120 const size_t num_bits_;
121 const size_t num_bytes_;
122 // current_byte_index_ contains the current byte offset in |bytes_|.
123 size_t current_byte_index_;
124 // current_byte_ contains the current byte of the input.
126 // num_bits_used_ contains the number of bits of |current_byte_| that have
128 unsigned num_bits_used_;
131 // HuffmanDecoder is a very simple Huffman reader. The input Huffman tree is
132 // simply encoded as a series of two-byte structures. The first byte determines
133 // the "0" pointer for that node and the second the "1" pointer. Each byte
134 // either has the MSB set, in which case the bottom 7 bits are the value for
135 // that position, or else the bottom seven bits contain the index of a node.
137 // The tree is decoded by walking rather than a table-driven approach.
138 class HuffmanDecoder {
140 HuffmanDecoder(const uint8* tree, size_t tree_bytes)
142 tree_bytes_(tree_bytes) {}
144 bool Decode(BitReader* reader, char* out) {
145 const uint8* current = &tree_[tree_bytes_-2];
149 if (!reader->Next(&bit)) {
153 uint8 b = current[bit];
155 *out = static_cast<char>(b & 0x7f);
159 unsigned offset = static_cast<unsigned>(b) * 2;
160 DCHECK_LT(offset, tree_bytes_);
161 if (offset >= tree_bytes_) {
165 current = &tree_[offset];
170 const uint8* const tree_;
171 const size_t tree_bytes_;
174 } // namespace anonymous
178 // DecodeHSTSPreloadRaw resolves |hostname| in the preloaded data. It returns
179 // false on internal error and true otherwise. After a successful return,
180 // |*out_found| is true iff a relevant entry has been found. If so, |*out|
181 // contains the details.
183 // Don't call this function, call DecodeHSTSPreload, below.
185 // Although this code should be robust, it never processes attacker-controlled
186 // data -- it only operates on the preloaded data built into the binary.
188 // The preloaded data is represented as a trie and matches the hostname
189 // backwards. Each node in the trie starts with a number of characters, which
190 // must match exactly. After that is a dispatch table which maps the next
191 // character in the hostname to another node in the trie.
193 // In the dispatch table, the zero character represents the "end of string"
194 // (which is the *beginning* of a hostname since we process it backwards). The
195 // value in that case is special -- rather than an offset to another trie node,
196 // it contains the HSTS information: whether subdomains are included, pinsets
197 // etc. If an "end of string" matches a period in the hostname then the
198 // information is remembered because, if no more specific node is found, then
199 // that information applies to the hostname.
201 // Dispatch tables are always given in order, but the "end of string" (zero)
202 // value always comes before an entry for '.'.
203 bool DecodeHSTSPreloadRaw(const std::string& hostname,
205 PreloadResult* out) {
206 HuffmanDecoder huffman(kHSTSHuffmanTree, sizeof(kHSTSHuffmanTree));
207 BitReader reader(kPreloadedHSTSData, kPreloadedHSTSBits);
208 size_t bit_offset = kHSTSRootPosition;
209 static const char kEndOfString = 0;
210 static const char kEndOfTable = 127;
214 if (hostname.empty()) {
217 // hostname_offset contains one more than the index of the current character
218 // in the hostname that is being considered. It's one greater so that we can
219 // represent the position just before the beginning (with zero).
220 size_t hostname_offset = hostname.size();
223 // Seek to the desired location.
224 if (!reader.Seek(bit_offset)) {
228 // Decode the unary length of the common prefix.
229 size_t prefix_length;
230 if (!reader.Unary(&prefix_length)) {
234 // Match each character in the prefix.
235 for (size_t i = 0; i < prefix_length; ++i) {
236 if (hostname_offset == 0) {
237 // We can't match the terminator with a prefix string.
242 if (!huffman.Decode(&reader, &c)) {
245 if (hostname[hostname_offset - 1] != c) {
251 bool is_first_offset = true;
252 size_t current_offset = 0;
254 // Next is the dispatch table.
257 if (!huffman.Decode(&reader, &c)) {
260 if (c == kEndOfTable) {
265 if (c == kEndOfString) {
267 if (!reader.Next(&tmp.sts_include_subdomains) ||
268 !reader.Next(&tmp.force_https) ||
269 !reader.Next(&tmp.has_pins)) {
273 tmp.pkp_include_subdomains = tmp.sts_include_subdomains;
276 if (!reader.Read(4, &tmp.pinset_id) ||
277 !reader.Read(9, &tmp.domain_id) ||
278 (!tmp.sts_include_subdomains &&
279 !reader.Next(&tmp.pkp_include_subdomains))) {
284 tmp.hostname_offset = hostname_offset;
286 if (hostname_offset == 0 || hostname[hostname_offset - 1] == '.') {
288 tmp.sts_include_subdomains || tmp.pkp_include_subdomains;
291 if (hostname_offset > 0) {
292 out->force_https &= tmp.sts_include_subdomains;
302 // The entries in a dispatch table are in order thus we can tell if there
303 // will be no match if the current character past the one that we want.
304 if (hostname_offset == 0 || hostname[hostname_offset-1] < c) {
308 if (is_first_offset) {
309 // The first offset is backwards from the current position.
310 uint32 jump_delta_bits;
312 if (!reader.Read(5, &jump_delta_bits) ||
313 !reader.Read(jump_delta_bits, &jump_delta)) {
317 if (bit_offset < jump_delta) {
321 current_offset = bit_offset - jump_delta;
322 is_first_offset = false;
324 // Subsequent offsets are forward from the target of the first offset.
326 if (!reader.Read(1, &is_long_jump)) {
332 if (!reader.Read(7, &jump_delta)) {
336 uint32 jump_delta_bits;
337 if (!reader.Read(4, &jump_delta_bits) ||
338 !reader.Read(jump_delta_bits + 8, &jump_delta)) {
343 current_offset += jump_delta;
344 if (current_offset >= bit_offset) {
349 DCHECK_LT(0u, hostname_offset);
350 if (hostname[hostname_offset - 1] == c) {
351 bit_offset = current_offset;
359 bool DecodeHSTSPreload(const std::string& hostname, PreloadResult* out)
362 if (!DecodeHSTSPreloadRaw(hostname, &found, out)) {
363 DCHECK(false, "Internal error in DecodeHSTSPreloadRaw for hostname %s", hostname.c_str());