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 }