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),
50 // Next sets |*out| to the next bit from the input. It returns false if no
51 // more bits are available or true otherwise.
52 bool Next(bool* out) {
53 if (num_bits_used_ == 8) {
54 if (current_byte_index_ >= num_bytes_) {
57 current_byte_ = bytes_[current_byte_index_++];
61 *out = 1 & (current_byte_ >> (7 - num_bits_used_));
66 // Read sets the |num_bits| least-significant bits of |*out| to the value of
67 // the next |num_bits| bits from the input. It returns false if there are
68 // insufficient bits in the input or true otherwise.
69 bool Read(unsigned num_bits, uint32* out) {
70 DCHECK_LE(num_bits, 32u);
73 for (unsigned i = 0; i < num_bits; ++i) {
78 ret |= static_cast<uint32>(bit) << (num_bits - 1 - i);
85 // Unary sets |*out| to the result of decoding a unary value from the input.
86 // It returns false if there were insufficient bits in the input and true
88 bool Unary(size_t* out) {
106 // Seek sets the current offest in the input to bit number |offset|. It
107 // returns true if |offset| is within the range of the input and false
109 bool Seek(size_t offset) {
110 if (offset >= num_bits_) {
113 current_byte_index_ = offset / 8;
114 current_byte_ = bytes_[current_byte_index_++];
115 num_bits_used_ = offset % 8;
120 const uint8* const bytes_;
121 const size_t num_bits_;
122 const size_t num_bytes_;
123 // current_byte_index_ contains the current byte offset in |bytes_|.
124 size_t current_byte_index_;
125 // current_byte_ contains the current byte of the input.
127 // num_bits_used_ contains the number of bits of |current_byte_| that have
129 unsigned num_bits_used_;
132 // HuffmanDecoder is a very simple Huffman reader. The input Huffman tree is
133 // simply encoded as a series of two-byte structures. The first byte determines
134 // the "0" pointer for that node and the second the "1" pointer. Each byte
135 // either has the MSB set, in which case the bottom 7 bits are the value for
136 // that position, or else the bottom seven bits contain the index of a node.
138 // The tree is decoded by walking rather than a table-driven approach.
139 class HuffmanDecoder {
141 HuffmanDecoder(const uint8* tree, size_t tree_bytes)
143 tree_bytes_(tree_bytes) {}
145 bool Decode(BitReader* reader, char* out) {
146 const uint8* current = &tree_[tree_bytes_-2];
150 if (!reader->Next(&bit)) {
154 uint8 b = current[bit];
156 *out = static_cast<char>(b & 0x7f);
160 unsigned offset = static_cast<unsigned>(b) * 2;
161 DCHECK_LT(offset, tree_bytes_);
162 if (offset >= tree_bytes_) {
166 current = &tree_[offset];
171 const uint8* const tree_;
172 const size_t tree_bytes_;
175 } // namespace anonymous
179 // DecodeHSTSPreloadRaw resolves |hostname| in the preloaded data. It returns
180 // false on internal error and true otherwise. After a successful return,
181 // |*out_found| is true iff a relevant entry has been found. If so, |*out|
182 // contains the details.
184 // Don't call this function, call DecodeHSTSPreload, below.
186 // Although this code should be robust, it never processes attacker-controlled
187 // data -- it only operates on the preloaded data built into the binary.
189 // The preloaded data is represented as a trie and matches the hostname
190 // backwards. Each node in the trie starts with a number of characters, which
191 // must match exactly. After that is a dispatch table which maps the next
192 // character in the hostname to another node in the trie.
194 // In the dispatch table, the zero character represents the "end of string"
195 // (which is the *beginning* of a hostname since we process it backwards). The
196 // value in that case is special -- rather than an offset to another trie node,
197 // it contains the HSTS information: whether subdomains are included, pinsets
198 // etc. If an "end of string" matches a period in the hostname then the
199 // information is remembered because, if no more specific node is found, then
200 // that information applies to the hostname.
202 // Dispatch tables are always given in order, but the "end of string" (zero)
203 // value always comes before an entry for '.'.
204 bool DecodeHSTSPreloadRaw(const std::string& hostname,
206 PreloadResult* out) {
207 HuffmanDecoder huffman(kHSTSHuffmanTree, sizeof(kHSTSHuffmanTree));
208 BitReader reader(kPreloadedHSTSData, kPreloadedHSTSBits);
209 size_t bit_offset = kHSTSRootPosition;
210 static const char kEndOfString = 0;
211 static const char kEndOfTable = 127;
215 if (hostname.empty()) {
218 // hostname_offset contains one more than the index of the current character
219 // in the hostname that is being considered. It's one greater so that we can
220 // represent the position just before the beginning (with zero).
221 size_t hostname_offset = hostname.size();
224 // Seek to the desired location.
225 if (!reader.Seek(bit_offset)) {
229 // Decode the unary length of the common prefix.
230 size_t prefix_length;
231 if (!reader.Unary(&prefix_length)) {
235 // Match each character in the prefix.
236 for (size_t i = 0; i < prefix_length; ++i) {
237 if (hostname_offset == 0) {
238 // We can't match the terminator with a prefix string.
243 if (!huffman.Decode(&reader, &c)) {
246 if (hostname[hostname_offset - 1] != c) {
252 bool is_first_offset = true;
253 size_t current_offset = 0;
255 // Next is the dispatch table.
258 if (!huffman.Decode(&reader, &c)) {
261 if (c == kEndOfTable) {
266 if (c == kEndOfString) {
268 if (!reader.Next(&tmp.sts_include_subdomains) ||
269 !reader.Next(&tmp.force_https) ||
270 !reader.Next(&tmp.has_pins)) {
274 tmp.pkp_include_subdomains = tmp.sts_include_subdomains;
277 if (!reader.Read(4, &tmp.pinset_id) ||
278 !reader.Read(9, &tmp.domain_id) ||
279 (!tmp.sts_include_subdomains &&
280 !reader.Next(&tmp.pkp_include_subdomains))) {
285 tmp.hostname_offset = hostname_offset;
287 if (hostname_offset == 0 || hostname[hostname_offset - 1] == '.') {
289 tmp.sts_include_subdomains || tmp.pkp_include_subdomains;
292 if (hostname_offset > 0) {
293 out->force_https &= tmp.sts_include_subdomains;
303 // The entries in a dispatch table are in order thus we can tell if there
304 // will be no match if the current character past the one that we want.
305 if (hostname_offset == 0 || hostname[hostname_offset-1] < c) {
309 if (is_first_offset) {
310 // The first offset is backwards from the current position.
311 uint32 jump_delta_bits;
313 if (!reader.Read(5, &jump_delta_bits) ||
314 !reader.Read(jump_delta_bits, &jump_delta)) {
318 if (bit_offset < jump_delta) {
322 current_offset = bit_offset - jump_delta;
323 is_first_offset = false;
325 // Subsequent offsets are forward from the target of the first offset.
327 if (!reader.Read(1, &is_long_jump)) {
333 if (!reader.Read(7, &jump_delta)) {
337 uint32 jump_delta_bits;
338 if (!reader.Read(4, &jump_delta_bits) ||
339 !reader.Read(jump_delta_bits + 8, &jump_delta)) {
344 current_offset += jump_delta;
345 if (current_offset >= bit_offset) {
350 DCHECK_LT(0u, hostname_offset);
351 if (hostname[hostname_offset - 1] == c) {
352 bit_offset = current_offset;
360 bool DecodeHSTSPreload(const std::string& hostname, PreloadResult* out)
363 if (!DecodeHSTSPreloadRaw(hostname, &found, out)) {
364 DCHECK(false, "Internal error in DecodeHSTSPreloadRaw for hostname %s", hostname.c_str());