typhoon/certificate/
utils.rs1use std::io::{self, Read, Write};
4use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
5
6use classic_mceliece_rust::{CRYPTO_PUBLICKEYBYTES, CRYPTO_SECRETKEYBYTES};
7
8use crate::bytes::FixedByteBuffer;
9
10pub const EPK_BYTES: usize = 261_120;
14pub const ESK_BYTES: usize = 6_492;
16pub const ED25519_BYTES: usize = 32;
18pub const X25519_BYTES: usize = 32;
20
21const _: () = assert!(EPK_BYTES == CRYPTO_PUBLICKEYBYTES, "EPK_BYTES must match CRYPTO_PUBLICKEYBYTES");
23const _: () = assert!(ESK_BYTES == CRYPTO_SECRETKEYBYTES, "ESK_BYTES must match CRYPTO_SECRETKEYBYTES");
24
25pub(crate) const MAGIC: &[u8; 7] = b"TYPHOON";
28#[cfg(feature = "server")]
29pub(crate) const TYPE_SERVER: u8 = b'S';
30pub(crate) const TYPE_CLIENT: u8 = b'C';
31pub(crate) const FORMAT_VERSION: u8 = 1;
32
33#[cfg(any(feature = "fast_software", feature = "fast_hardware"))]
34pub(crate) const MODE_BYTE: u8 = b'F';
35#[cfg(any(feature = "full_software", feature = "full_hardware"))]
36pub(crate) const MODE_BYTE: u8 = b'U';
37
38#[derive(Debug, thiserror::Error)]
42pub enum CertificateError {
43 #[error("I/O error: {0}")]
44 Io(#[from] io::Error),
45 #[error("invalid file: bad magic bytes")]
46 InvalidMagic,
47 #[error("invalid file type: expected '{expected}', got '{got}'")]
48 InvalidType {
49 expected: char,
50 got: char,
51 },
52 #[error("mode mismatch: file was written for a different crypto mode")]
53 ModeMismatch,
54 #[error("unsupported format version: {0}")]
55 UnsupportedVersion(u8),
56 #[error("invalid key data in file")]
57 InvalidKeyData,
58 #[error("certificate contains no server addresses")]
59 NoAddresses,
60}
61
62pub(crate) fn write_header(w: &mut impl Write, record_type: u8) -> Result<(), io::Error> {
65 w.write_all(MAGIC)?;
66 w.write_all(&[record_type, MODE_BYTE, FORMAT_VERSION])
67}
68
69pub(crate) fn read_header(r: &mut impl Read, expected_type: u8) -> Result<(), CertificateError> {
70 let mut magic = [0u8; 7];
71 r.read_exact(&mut magic)?;
72 if &magic != MAGIC {
73 return Err(CertificateError::InvalidMagic);
74 }
75 let mut header = [0u8; 3];
76 r.read_exact(&mut header)?;
77 let [record_type, mode, version] = header;
78 if record_type != expected_type {
79 return Err(CertificateError::InvalidType {
80 expected: expected_type as char,
81 got: record_type as char,
82 });
83 }
84 if mode != MODE_BYTE {
85 return Err(CertificateError::ModeMismatch);
86 }
87 if version != FORMAT_VERSION {
88 return Err(CertificateError::UnsupportedVersion(version));
89 }
90 Ok(())
91}
92
93pub(crate) fn write_addresses(w: &mut impl Write, addrs: &[SocketAddr]) -> Result<(), io::Error> {
96 w.write_all(&(addrs.len() as u16).to_be_bytes())?;
97 for addr in addrs {
98 match addr.ip() {
99 IpAddr::V4(ip) => {
100 w.write_all(&[4u8])?;
101 w.write_all(&ip.octets())?;
102 }
103 IpAddr::V6(ip) => {
104 w.write_all(&[6u8])?;
105 w.write_all(&ip.octets())?;
106 }
107 }
108 w.write_all(&addr.port().to_be_bytes())?;
109 }
110 Ok(())
111}
112
113pub(crate) fn read_addresses(r: &mut impl Read) -> Result<Vec<SocketAddr>, CertificateError> {
114 let mut count_bytes = [0u8; 2];
115 r.read_exact(&mut count_bytes)?;
116 let count = u16::from_be_bytes(count_bytes) as usize;
117 let mut addrs = Vec::with_capacity(count);
118 for _ in 0..count {
119 let mut family = [0u8; 1];
120 r.read_exact(&mut family)?;
121 let ip = match family[0] {
122 4 => {
123 let mut octets = [0u8; 4];
124 r.read_exact(&mut octets)?;
125 IpAddr::V4(Ipv4Addr::from(octets))
126 }
127 6 => {
128 let mut octets = [0u8; 16];
129 r.read_exact(&mut octets)?;
130 IpAddr::V6(Ipv6Addr::from(octets))
131 }
132 _ => return Err(CertificateError::InvalidKeyData),
133 };
134 let mut port_bytes = [0u8; 2];
135 r.read_exact(&mut port_bytes)?;
136 addrs.push(SocketAddr::new(ip, u16::from_be_bytes(port_bytes)));
137 }
138 Ok(addrs)
139}
140
141pub(crate) trait ObfuscationBufferContainer {
145 fn obfuscation_buffer(&self) -> FixedByteBuffer<ED25519_BYTES>;
147}