tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

mutators.cc (3758B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "mutators.h"
      6 
      7 #include <cassert>
      8 #include <cstring>
      9 #include <random>
     10 #include <tuple>
     11 
     12 static std::tuple<uint8_t *, size_t> ParseItem(uint8_t *data,
     13                                               size_t maxLength) {
     14  // Short form. Bit 8 has value "0" and bits 7-1 give the length.
     15  if ((data[1] & 0x80) == 0) {
     16    size_t length = std::min(static_cast<size_t>(data[1]), maxLength - 2);
     17    return std::make_tuple(&data[2], length);
     18  }
     19 
     20  // Constructed, indefinite length. Read until {0x00, 0x00}.
     21  if (data[1] == 0x80) {
     22    void *offset = memmem(&data[2], maxLength - 2, "\0", 2);
     23    size_t length = offset ? (static_cast<uint8_t *>(offset) - &data[2]) + 2
     24                           : maxLength - 2;
     25    return std::make_tuple(&data[2], length);
     26  }
     27 
     28  // Long form. Two to 127 octets. Bit 8 of first octet has value "1"
     29  // and bits 7-1 give the number of additional length octets.
     30  size_t octets = std::min(static_cast<size_t>(data[1] & 0x7f), maxLength - 2);
     31 
     32  // Handle lengths bigger than 32 bits.
     33  if (octets > 4) {
     34    // Ignore any further children, assign remaining length.
     35    return std::make_tuple(&data[2] + octets, maxLength - 2 - octets);
     36  }
     37 
     38  // Parse the length.
     39  size_t length = 0;
     40  for (size_t j = 0; j < octets; j++) {
     41    length = (length << 8) | data[2 + j];
     42  }
     43 
     44  length = std::min(length, maxLength - 2 - octets);
     45  return std::make_tuple(&data[2] + octets, length);
     46 }
     47 
     48 static std::vector<uint8_t *> ParseItems(uint8_t *data, size_t size) {
     49  std::vector<uint8_t *> items;
     50  std::vector<size_t> lengths;
     51 
     52  // The first item is always the whole corpus.
     53  items.push_back(data);
     54  lengths.push_back(size);
     55 
     56  // Can't use iterators here because the `items` vector is modified inside the
     57  // loop. That's safe as long as we always check `items.size()` before every
     58  // iteration, and only call `.push_back()` to append new items we found.
     59  // Items are accessed through `items.at()`, we hold no references.
     60  for (size_t i = 0; i < items.size(); i++) {
     61    uint8_t *item = items.at(i);
     62    size_t remaining = lengths.at(i);
     63 
     64    // Empty or primitive items have no children.
     65    if (remaining == 0 || (0x20 & item[0]) == 0) {
     66      continue;
     67    }
     68 
     69    while (remaining > 2) {
     70      uint8_t *content;
     71      size_t length;
     72 
     73      std::tie(content, length) = ParseItem(item, remaining);
     74 
     75      if (length > 0) {
     76        // Record the item.
     77        items.push_back(content);
     78 
     79        // Record the length for further parsing.
     80        lengths.push_back(length);
     81      }
     82 
     83      // Reduce number of bytes left in current item.
     84      remaining -= length + (content - item);
     85 
     86      // Skip the item we just parsed.
     87      item = content + length;
     88    }
     89  }
     90 
     91  return items;
     92 }
     93 
     94 namespace ASN1Mutators {
     95 
     96 size_t FlipConstructed(uint8_t *data, size_t size, size_t maxSize,
     97                       unsigned int seed) {
     98  auto items = ParseItems(data, size);
     99 
    100  std::mt19937 rng(seed);
    101  std::uniform_int_distribution<size_t> dist(0, items.size() - 1);
    102  uint8_t *item = items.at(dist(rng));
    103 
    104  // Flip "constructed" type bit.
    105  item[0] ^= 0x20;
    106 
    107  return size;
    108 }
    109 
    110 size_t ChangeType(uint8_t *data, size_t size, size_t maxSize,
    111                  unsigned int seed) {
    112  auto items = ParseItems(data, size);
    113 
    114  std::mt19937 rng(seed);
    115  std::uniform_int_distribution<size_t> dist(0, items.size() - 1);
    116  uint8_t *item = items.at(dist(rng));
    117 
    118  // Change type to a random int [0, 30].
    119  static std::uniform_int_distribution<size_t> tdist(0, 30);
    120  item[0] = tdist(rng);
    121 
    122  return size;
    123 }
    124 
    125 }  // namespace ASN1Mutators