tor-browser

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

tls.rs (11182B)


      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 https://mozilla.org/MPL/2.0/. */
      4 
      5 use super::AbridgedError;
      6 use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
      7 use log::trace;
      8 use std::io::Cursor;
      9 use std::io::Write;
     10 use std::u8;
     11 
     12 /// Parses a TLS vector as defined in https://datatracker.ietf.org/doc/html/rfc8446#section-3.4
     13 /// The length prefix is specified as WIDTH within 1..4 inclusive.
     14 /// The result either indicates an error or produces the body of the vec
     15 /// and any remaining data.
     16 fn read_tls_vec<'a, const WIDTH: u8>(
     17    value: &'a [u8],
     18 ) -> Result<(&'a [u8], &'a [u8]), AbridgedError> {
     19    debug_assert!(WIDTH <= 4, "Invalid width specified");
     20 
     21    let Some((len_bytes, remainder)) = value.split_at_checked(usize::from(WIDTH)) else {
     22        return Err(AbridgedError::ParsingInvalidTLSVec);
     23    };
     24 
     25    let io_err_wrapper = |x| AbridgedError::ReadingError(x);
     26    let mut len_rdr = Cursor::new(len_bytes);
     27    let len: u32 = match WIDTH {
     28        1 => len_rdr.read_u8().map_err(io_err_wrapper)?.into(),
     29        2 => len_rdr
     30            .read_u16::<BigEndian>()
     31            .map_err(io_err_wrapper)?
     32            .into(),
     33        3 => len_rdr.read_u24::<BigEndian>().map_err(io_err_wrapper)?,
     34        4 => len_rdr.read_u32::<BigEndian>().map_err(io_err_wrapper)?,
     35        _ => return Err(AbridgedError::InvalidOperation),
     36    };
     37 
     38    let Some((vec_body, remainder)) = remainder.split_at_checked(len as usize) else {
     39        return Err(AbridgedError::ParsingInvalidTLSVec);
     40    };
     41 
     42    trace!(
     43        "In length: {}, Output length: {}, Remainder Length: {}",
     44        value.len(),
     45        vec_body.len(),
     46        remainder.len()
     47    );
     48    Ok((vec_body, remainder))
     49 }
     50 
     51 /// Writes out an integer as defined in https://datatracker.ietf.org/doc/html/rfc8446#section-3.3
     52 /// WIDTH must be between 1 and 4
     53 fn write_tls_int<const WIDTH: u8>(writer: &mut impl Write, int: u32) -> Result<(), AbridgedError> {
     54    debug_assert!(WIDTH <= 4 && WIDTH > 0, "Invalid width specified");
     55    if u64::from(int) > 2_u64.pow(u32::from(WIDTH) * 8) - 1 {
     56        return Err(AbridgedError::InvalidOperation);
     57    }
     58    // Panics if int is out of range.
     59    writer
     60        .write_uint::<BigEndian>(u64::from(int), usize::from(WIDTH))
     61        .map_err(|x| AbridgedError::WritingError(x))?;
     62    Ok(())
     63 }
     64 
     65 /// Writes out a TLS vector as defined in https://datatracker.ietf.org/doc/html/rfc8446#section-3.4
     66 /// WIDTH must be between 1 and 4
     67 fn write_tls_vec<const WIDTH: u8>(
     68    value: &[u8],
     69    writer: &mut impl Write,
     70 ) -> Result<(), AbridgedError> {
     71    debug_assert!(WIDTH <= 4 && WIDTH > 0, "Invalid width specified");
     72 
     73    let len: u32 = value
     74        .len()
     75        .try_into()
     76        .or(Err(AbridgedError::InvalidOperation))?;
     77 
     78    write_tls_int::<WIDTH>(writer, len)?;
     79    writer
     80        .write_all(value)
     81        .or_else(|x| Err(AbridgedError::WritingError(x)))?;
     82    Ok(())
     83 }
     84 
     85 /// These types represent the structure of a TLS 1.3 certificate message
     86 ///
     87 /// RFC 8446: 4.4.2
     88 /// enum {
     89 ///     X509(0),
     90 ///     RawPublicKey(2),
     91 ///     (255)
     92 /// } CertificateType;
     93 ///
     94 /// struct {
     95 ///     select (certificate_type) {
     96 ///         case RawPublicKey:
     97 ///           /* From RFC 7250 ASN.1_subjectPublicKeyInfo */
     98 ///           opaque ASN1_subjectPublicKeyInfo<1..2^24-1>;
     99 ///
    100 ///         case X509:
    101 ///           opaque cert_data<1..2^24-1>;
    102 ///     };
    103 ///     Extension extensions<0..2^16-1>;
    104 /// } CertificateEntry;
    105 ///
    106 /// struct {
    107 ///     opaque certificate_request_context<0..2^8-1>;
    108 ///     CertificateEntry certificate_list<0..2^24-1>;
    109 /// } Certificate;
    110 
    111 #[derive(Debug)]
    112 pub struct CertificateEntry {
    113    pub data: Vec<u8>,
    114    pub extensions: Vec<u8>,
    115 }
    116 
    117 pub type UncompressedCertEntry = CertificateEntry;
    118 pub type CompressedCertEntry = CertificateEntry;
    119 
    120 #[derive(Debug)]
    121 pub struct CertificateMessage {
    122    pub request_context: Vec<u8>,
    123    pub certificate_entries: Vec<CertificateEntry>,
    124 }
    125 
    126 impl CertificateEntry {
    127    pub fn read_from_bytes(value: &[u8]) -> Result<(CertificateEntry, &[u8]), AbridgedError> {
    128        let (data, remainder) = read_tls_vec::<3>(value)?;
    129        let (extensions, remainder) = read_tls_vec::<2>(remainder)?;
    130        Ok((
    131            CertificateEntry {
    132                data: data.to_vec(),
    133                extensions: extensions.to_vec(),
    134            },
    135            remainder,
    136        ))
    137    }
    138 
    139    pub fn write_to_bytes(&self, writer: &mut impl Write) -> Result<(), AbridgedError> {
    140        write_tls_vec::<3>(&self.data, writer)?;
    141        write_tls_vec::<2>(&self.extensions, writer)?;
    142        Ok(())
    143    }
    144 
    145    pub fn get_size(&self) -> usize {
    146        let calculated_size = 3 + self.data.len() + 2 + self.extensions.len();
    147 
    148        if cfg!(debug_assertions) {
    149            let mut output = Vec::with_capacity(calculated_size);
    150            self.write_to_bytes(&mut output).expect("Shouldn't error");
    151            debug_assert_eq!(calculated_size, output.len());
    152        }
    153        calculated_size
    154    }
    155 }
    156 
    157 impl CertificateMessage {
    158    pub fn read_from_bytes(value: &[u8]) -> Result<(CertificateMessage, &[u8]), AbridgedError> {
    159        trace!("Parsing certificate message from {} bytes", value.len());
    160        let (request_context, certificate_entries) = read_tls_vec::<1>(value)?;
    161        trace!(
    162            "Parsing request_context of size {}, {} remaining",
    163            request_context.len(),
    164            value.len()
    165        );
    166        let (certificate_entries, tail) = read_tls_vec::<3>(certificate_entries)?;
    167        trace!(
    168            "Parsing certificate_field of size {}, {} remaining",
    169            certificate_entries.len(),
    170            value.len()
    171        );
    172 
    173        let mut parsed_certificate_entries = Vec::with_capacity(5);
    174 
    175        let mut remaining_data = certificate_entries;
    176        while !remaining_data.is_empty() {
    177            let (entry, temp) = CertificateEntry::read_from_bytes(remaining_data)?;
    178            remaining_data = temp;
    179            parsed_certificate_entries.push(entry);
    180        }
    181        Ok((
    182            CertificateMessage {
    183                request_context: request_context.to_vec(),
    184                certificate_entries: parsed_certificate_entries,
    185            },
    186            tail,
    187        ))
    188    }
    189 
    190    pub fn write_to_bytes(&self, writer: &mut impl Write) -> Result<(), AbridgedError> {
    191        let ce_size: u32 = self
    192            .certificate_entries
    193            .iter()
    194            .map(CertificateEntry::get_size)
    195            .sum::<usize>()
    196            .try_into()
    197            .or(Err(AbridgedError::InvalidOperation))?;
    198        write_tls_vec::<1>(&self.request_context, writer)?;
    199        write_tls_int::<3>(writer, ce_size)?;
    200        for ce in &self.certificate_entries {
    201            ce.write_to_bytes(writer)?;
    202        }
    203        Ok(())
    204    }
    205 
    206    pub fn get_size(&self) -> usize {
    207        let calculated_size = 1
    208            + self.request_context.len()
    209            + 3
    210            + self
    211                .certificate_entries
    212                .iter()
    213                .map(|x| x.get_size())
    214                .sum::<usize>();
    215 
    216        if cfg!(debug_assertions) {
    217            let mut output = Vec::with_capacity(calculated_size);
    218            self.write_to_bytes(&mut output).expect("Shouldn't error");
    219            debug_assert_eq!(calculated_size, output.len());
    220        }
    221        calculated_size
    222    }
    223 }
    224 
    225 /// These tests do not run in CI because ./mach rusttests does not support crates which link
    226 /// against gecko symbols.
    227 #[cfg(test)]
    228 mod tests {
    229    use super::CertificateMessage;
    230 
    231    // Borrowed from https://tls13.xargs.org/#server-certificate
    232    // Added a single byte extension field
    233    const CERTMSG: &str = "
    234        0000032b0003253082032130820209a0030201020208155a92adc2048f90300d06092a86
    235        4886f70d01010b05003022310b300906035504061302555331133011060355040a130a4578616d70
    236        6c65204341301e170d3138313030353031333831375a170d3139313030353031333831375a302b31
    237        0b3009060355040613025553311c301a060355040313136578616d706c652e756c666865696d2e6e
    238        657430820122300d06092a864886f70d01010105000382010f003082010a0282010100c4803606ba
    239        e7476b089404eca7b691043ff792bc19eefb7d74d7a80d001e7b4b3a4ae60fe8c071fc73e7024c0d
    240        bcf4bdd11d396bba70464a13e94af83df3e10959547bc955fb412da3765211e1f3dc776caa53376e
    241        ca3aecbec3aab73b31d56cb6529c8098bcc9e02818e20bf7f8a03afd1704509ece79bd9f39f1ea69
    242        ec47972e830fb5ca95de95a1e60422d5eebe527954a1e7bf8a86f6466d0d9f16951a4cf7a0469259
    243        5c1352f2549e5afb4ebfd77a37950144e4c026874c653e407d7d23074401f484ffd08f7a1fa05210
    244        d1f4f0d5ce79702932e2cabe701fdfad6b4bb71101f44bad666a11130fe2ee829e4d029dc91cdd67
    245        16dbb9061886edc1ba94210203010001a3523050300e0603551d0f0101ff0404030205a0301d0603
    246        551d250416301406082b0601050507030206082b06010505070301301f0603551d23041830168014
    247        894fde5bcc69e252cf3ea300dfb197b81de1c146300d06092a864886f70d01010b05000382010100
    248        591645a69a2e3779e4f6dd271aba1c0bfd6cd75599b5e7c36e533eff3659084324c9e7a504079d39
    249        e0d42987ffe3ebdd09c1cf1d914455870b571dd19bdf1d24f8bb9a11fe80fd592ba0398cde11e265
    250        1e618ce598fa96e5372eef3d248afde17463ebbfabb8e4d1ab502a54ec0064e92f7819660d3f27cf
    251        209e667fce5ae2e4ac99c7c93818f8b2510722dfed97f32e3e9349d4c66c9ea6396d744462a06b42
    252        c6d5ba688eac3a017bddfc8e2cfcad27cb69d3ccdca280414465d3ae348ce0f34ab2fb9c61837131
    253        2b191041641c237f11a5d65c844f0404849938712b959ed685bc5c5dd645ed19909473402926dcb4
    254        0e3469a15941e8e2cca84bb6084636a00001ff";
    255 
    256    #[test]
    257    fn happy_path() {
    258        let mut cert_hex: String = String::from(CERTMSG);
    259        cert_hex.retain(|x| !x.is_whitespace());
    260        let mut cert_bytes: Vec<u8> = hex::decode(cert_hex).unwrap().into();
    261        let _ =
    262            CertificateMessage::read_from_bytes(&mut cert_bytes).expect("Should correctly decode");
    263        assert_eq!(cert_bytes.len(), 0, "nothing left over");
    264    }
    265 
    266    #[test]
    267    fn round_trip() {
    268        let mut cert_hex: String = String::from(CERTMSG);
    269        cert_hex.retain(|x| !x.is_whitespace());
    270        let cert_bytes: Vec<u8> = hex::decode(cert_hex).unwrap().into();
    271 
    272        let (msg, _) = CertificateMessage::read_from_bytes(&mut cert_bytes.clone())
    273            .expect("Should correctly decode");
    274 
    275        let msg_bytes: Vec<u8> = Vec::new();
    276        let mut cursor = std::io::Cursor::new(msg_bytes);
    277        msg.write_to_bytes(&mut cursor).expect("No errors");
    278 
    279        let msg_bytes: Vec<u8> = cursor.into_inner().into();
    280        assert_eq!(msg_bytes.len(), cert_bytes.len(), "nothing left over");
    281        assert_eq!(msg_bytes, cert_bytes);
    282        assert_eq!(true, false);
    283    }
    284 
    285    #[test]
    286    fn large_integers() {
    287        let msg_bytes: Vec<u8> = Vec::new();
    288        let mut cursor = std::io::Cursor::new(msg_bytes);
    289        assert!(super::write_tls_int::<1>(&mut cursor, u8::MAX as u32 + 1,).is_err());
    290        assert!(super::write_tls_int::<2>(&mut cursor, u16::MAX as u32 + 1).is_err());
    291        assert!(super::write_tls_int::<3>(&mut cursor, 2_u32.pow(24) + 1).is_err());
    292        assert!(super::write_tls_int::<4>(&mut cursor, u32::MAX).is_ok());
    293    }
    294 }