tor-browser

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

build.rs (5340B)


      1 /* -*- Mode: rust; rust-indent-offset: 4 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 use base64::prelude::BASE64_STANDARD;
      7 use base64::Engine;
      8 use std::cmp::Ordering;
      9 use std::fs::{read_dir, File};
     10 use std::io::{BufRead, BufReader, BufWriter, Write};
     11 use std::path::{Path, PathBuf};
     12 
     13 #[derive(Eq, PartialEq)]
     14 struct TrustAnchor {
     15    bytes: Vec<u8>,
     16    subject: Vec<u8>,
     17    subject_start: u16,
     18    subject_len: u8,
     19 }
     20 
     21 impl PartialOrd for TrustAnchor {
     22    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
     23        self.subject.partial_cmp(&other.subject)
     24    }
     25 }
     26 
     27 impl TrustAnchor {
     28    fn new(bytes: Vec<u8>) -> TrustAnchor {
     29        let (_, _, subject) =
     30            rsclientcerts_util::read_encoded_certificate_identifiers(bytes.as_slice())
     31                .expect("Couldn't decode certificate.");
     32        let subject_start = bytes
     33            .windows(subject.len())
     34            .position(|s| s == subject)
     35            .expect("subject should appear in bytes");
     36        let subject_start: u16 = subject_start
     37            .try_into()
     38            .expect("subject start hopefully fits in u16");
     39        let subject_len = subject
     40            .len()
     41            .try_into()
     42            .expect("subject length hopefully fits in u8");
     43        TrustAnchor {
     44            bytes,
     45            subject,
     46            subject_start,
     47            subject_len,
     48        }
     49    }
     50 }
     51 
     52 fn read_trust_anchors(
     53    trust_anchor_filename_or_directory: PathBuf,
     54 ) -> std::io::Result<Vec<TrustAnchor>> {
     55    let mut trust_anchors = if trust_anchor_filename_or_directory.is_dir() {
     56        let mut trust_anchors = Vec::new();
     57        for dir_entry in read_dir(trust_anchor_filename_or_directory)? {
     58            trust_anchors.append(&mut read_trust_anchors_from(dir_entry?.path())?);
     59        }
     60        trust_anchors
     61    } else {
     62        read_trust_anchors_from(trust_anchor_filename_or_directory)?
     63    };
     64 
     65    trust_anchors.sort_by_cached_key(|trust_anchor| trust_anchor.subject.clone());
     66    Ok(trust_anchors)
     67 }
     68 
     69 fn read_trust_anchors_from(trust_anchor_file_path: PathBuf) -> std::io::Result<Vec<TrustAnchor>> {
     70    let trust_anchor_file = File::open(trust_anchor_file_path)?;
     71    let reader = BufReader::new(trust_anchor_file);
     72    let mut maybe_current_trust_anchor: Option<Vec<String>> = None;
     73    let mut trust_anchors = Vec::new();
     74    for line in reader.lines() {
     75        let line = line.expect("Couldn't read contents of trust anchors file.");
     76        match line.as_str() {
     77            "-----BEGIN CERTIFICATE-----" => {
     78                maybe_current_trust_anchor.replace(Vec::new());
     79            }
     80            "-----END CERTIFICATE-----" => {
     81                let current_trust_anchor = maybe_current_trust_anchor
     82                    .take()
     83                    .expect("END CERTIFICATE without BEGIN CERTIFICATE?");
     84                let base64 = current_trust_anchor.join("");
     85                let bytes = BASE64_STANDARD
     86                    .decode(base64)
     87                    .expect("Couldn't base64-decode trust anchor.");
     88                let trust_anchor = TrustAnchor::new(bytes);
     89                trust_anchors.push(trust_anchor);
     90            }
     91            _ => {
     92                if let Some(current_trust_anchor) = maybe_current_trust_anchor.as_mut() {
     93                    current_trust_anchor.push(line);
     94                }
     95            }
     96        }
     97    }
     98    Ok(trust_anchors)
     99 }
    100 
    101 fn emit_trust_anchors(
    102    out: &mut dyn Write,
    103    prefix: &str,
    104    trust_anchors_filename_or_directory: &str,
    105 ) -> std::io::Result<()> {
    106    let trust_anchors_path = Path::new(trust_anchors_filename_or_directory);
    107    let trust_anchors = read_trust_anchors(trust_anchors_path.to_path_buf())?;
    108    for (index, trust_anchor) in trust_anchors.iter().enumerate() {
    109        writeln!(
    110            out,
    111            "static {prefix}TRUST_ANCHOR_{index:0>4}_BYTES: &[u8] = &{:?};",
    112            trust_anchor.bytes
    113        )?;
    114    }
    115 
    116    writeln!(
    117        out,
    118        "pub (crate) static {prefix}TRUST_ANCHORS: [TrustAnchor; {num_trust_anchors}] = [",
    119        num_trust_anchors = trust_anchors.len()
    120    )?;
    121    for (index, trust_anchor) in trust_anchors.iter().enumerate() {
    122        writeln!(out, "    TrustAnchor {{")?;
    123        writeln!(
    124            out,
    125            "        bytes: {prefix}TRUST_ANCHOR_{index:0>4}_BYTES,"
    126        )?;
    127        writeln!(
    128            out,
    129            "        subject: ({}, {}),",
    130            trust_anchor.subject_start, trust_anchor.subject_len
    131        )?;
    132        writeln!(out, "    }},")?;
    133    }
    134    writeln!(out, "];")?;
    135    Ok(())
    136 }
    137 
    138 fn main() -> std::io::Result<()> {
    139    let trust_anchors = "trust_anchors.pem";
    140    let test_trust_anchors = "test_trust_anchors";
    141    println!("cargo:rerun-if-changed={}", trust_anchors);
    142    println!("cargo:rerun-if-changed={}", test_trust_anchors);
    143 
    144    let out_path = PathBuf::from(std::env::var("OUT_DIR").expect("OUT_DIR should be set in env."));
    145    let mut out = BufWriter::new(
    146        File::create(out_path.join("trust_anchors.rs")).expect("Could not write trust_anchors.rs."),
    147    );
    148 
    149    emit_trust_anchors(&mut out, "", trust_anchors)?;
    150    emit_trust_anchors(&mut out, "TEST_", test_trust_anchors)?;
    151 
    152    Ok(())
    153 }