Skip to main content

typhoon/certificate/
client.rs

1//! Client certificate: public keys + server addresses distributed to clients.
2
3use std::fs::File;
4use std::io::{Read, Write};
5use std::net::SocketAddr;
6use std::path::Path;
7use std::sync::Arc;
8
9use cfg_if::cfg_if;
10use classic_mceliece_rust::PublicKey as McEliecePublicKey;
11use ed25519_dalek::VerifyingKey;
12
13cfg_if! {
14    if #[cfg(any(feature = "full_software", feature = "full_hardware"))] {
15        use x25519_dalek::PublicKey as X25519PublicKey;
16        use super::utils::X25519_BYTES;
17    }
18}
19use super::utils::{CertificateError, ED25519_BYTES, EPK_BYTES, ObfuscationBufferContainer, TYPE_CLIENT, read_addresses, read_header, write_addresses, write_header};
20use crate::bytes::FixedByteBuffer;
21
22// ── ClientCertificate ─────────────────────────────────────────────────────────
23
24/// Client-side connection descriptor: crypto public keys + server addresses (fast mode).
25///
26/// Derived from a [`ServerKeyPair`](super::ServerKeyPair) and distributed to clients out-of-band.
27/// Pass directly to [`ClientSocketBuilder::new`](crate::socket::ClientSocketBuilder::new).
28#[cfg(any(feature = "fast_software", feature = "fast_hardware"))]
29#[derive(Clone, Debug)]
30pub struct ClientCertificate {
31    pub(crate) epk: Arc<McEliecePublicKey<'static>>,
32    pub(crate) vpk: VerifyingKey,
33    pub(crate) obfs: FixedByteBuffer<ED25519_BYTES>,
34    pub(crate) addresses: Vec<SocketAddr>,
35}
36
37/// Client-side connection descriptor: crypto public keys + server addresses (full mode).
38///
39/// Derived from a [`ServerKeyPair`](super::ServerKeyPair) and distributed to clients out-of-band.
40/// Pass directly to [`ClientSocketBuilder::new`](crate::socket::ClientSocketBuilder::new).
41#[cfg(any(feature = "full_software", feature = "full_hardware"))]
42#[derive(Clone, Debug)]
43pub struct ClientCertificate {
44    pub(crate) epk: Arc<McEliecePublicKey<'static>>,
45    pub(crate) vpk: VerifyingKey,
46    pub(crate) opk: X25519PublicKey,
47    pub(crate) addresses: Vec<SocketAddr>,
48}
49
50impl ClientCertificate {
51    /// Return the server addresses embedded in this certificate.
52    pub fn addresses(&self) -> &[SocketAddr] {
53        &self.addresses
54    }
55
56    /// Save the client certificate to a binary file (fast mode).
57    ///
58    /// # File layout (fast mode, `F`)
59    ///
60    /// | Offset | Size                 | Field      | Description |
61    /// |--------|----------------------|------------|-------------|
62    /// | 0      | 10                   | Header     | Magic `TYPHOON`, type `C`, mode `F`, version `1` |
63    /// | 10     | 261120 (`EPK_BYTES`) | EPK        | Classic McEliece 348864 public key |
64    /// | 261130 | 32 (`ED25519_BYTES`) | VPK        | Ed25519 verifying key |
65    /// | 261162 | 32 (`ED25519_BYTES`) | OBFS       | Symmetric tailer obfuscation key |
66    /// | 261194 | 2                    | ADDR_COUNT | Number of addresses (big-endian u16) |
67    /// | 261196 | varies               | ADDRS      | Address list; each entry: 1-byte family (`4`/`6`), 4 or 16 IP bytes, 2-byte port (big-endian) |
68    #[cfg(any(feature = "fast_software", feature = "fast_hardware"))]
69    pub fn save(&self, path: impl AsRef<Path>) -> Result<(), CertificateError> {
70        let mut f = File::create(path)?;
71        write_header(&mut f, TYPE_CLIENT)?;
72        f.write_all(self.epk.as_array())?;
73        f.write_all(&self.vpk.to_bytes())?;
74        f.write_all(self.obfs.as_ref())?;
75        write_addresses(&mut f, &self.addresses)?;
76        Ok(())
77    }
78
79    /// Save the client certificate to a binary file (full mode).
80    ///
81    /// # File layout (full mode, `U`)
82    ///
83    /// | Offset | Size                 | Field      | Description |
84    /// |--------|----------------------|------------|-------------|
85    /// | 0      | 10                   | Header     | Magic `TYPHOON`, type `C`, mode `U`, version `1` |
86    /// | 10     | 261120 (`EPK_BYTES`) | EPK        | Classic McEliece 348864 public key |
87    /// | 261130 | 32 (`ED25519_BYTES`) | VPK        | Ed25519 verifying key |
88    /// | 261162 | 32 (`X25519_BYTES`)  | OPK        | X25519 long-term public key |
89    /// | 261194 | 2                    | ADDR_COUNT | Number of addresses (big-endian u16) |
90    /// | 261196 | varies               | ADDRS      | Address list; each entry: 1-byte family (`4`/`6`), 4 or 16 IP bytes, 2-byte port (big-endian) |
91    #[cfg(any(feature = "full_software", feature = "full_hardware"))]
92    pub fn save(&self, path: impl AsRef<Path>) -> Result<(), CertificateError> {
93        let mut f = File::create(path)?;
94        write_header(&mut f, TYPE_CLIENT)?;
95        f.write_all(self.epk.as_array())?;
96        f.write_all(&self.vpk.to_bytes())?;
97        f.write_all(self.opk.as_bytes())?;
98        write_addresses(&mut f, &self.addresses)?;
99        Ok(())
100    }
101
102    /// Load a client certificate from a binary file produced by [`save`](Self::save) (fast mode).
103    #[cfg(any(feature = "fast_software", feature = "fast_hardware"))]
104    pub fn load(path: impl AsRef<Path>) -> Result<Self, CertificateError> {
105        let mut f = File::open(path)?;
106        read_header(&mut f, TYPE_CLIENT)?;
107        let mut epk_buf = Box::new([0u8; EPK_BYTES]);
108        f.read_exact(epk_buf.as_mut())?;
109        let mut vpk_arr = [0u8; ED25519_BYTES];
110        f.read_exact(&mut vpk_arr)?;
111        let vpk = VerifyingKey::from_bytes(&vpk_arr).map_err(|_| CertificateError::InvalidKeyData)?;
112        let mut obfs_arr = [0u8; ED25519_BYTES];
113        f.read_exact(&mut obfs_arr)?;
114        let addresses = read_addresses(&mut f)?;
115        Ok(Self {
116            epk: Arc::new(McEliecePublicKey::from(epk_buf)),
117            vpk,
118            obfs: FixedByteBuffer::from(obfs_arr),
119            addresses,
120        })
121    }
122
123    /// Load a client certificate from a binary file produced by [`save`](Self::save) (full mode).
124    #[cfg(any(feature = "full_software", feature = "full_hardware"))]
125    pub fn load(path: impl AsRef<Path>) -> Result<Self, CertificateError> {
126        let mut f = File::open(path)?;
127        read_header(&mut f, TYPE_CLIENT)?;
128        let mut epk_buf = Box::new([0u8; EPK_BYTES]);
129        f.read_exact(epk_buf.as_mut())?;
130        let mut vpk_arr = [0u8; ED25519_BYTES];
131        f.read_exact(&mut vpk_arr)?;
132        let vpk = VerifyingKey::from_bytes(&vpk_arr).map_err(|_| CertificateError::InvalidKeyData)?;
133        let mut opk_arr = [0u8; X25519_BYTES];
134        f.read_exact(&mut opk_arr)?;
135        let addresses = read_addresses(&mut f)?;
136        Ok(Self {
137            epk: Arc::new(McEliecePublicKey::from(epk_buf)),
138            vpk,
139            opk: X25519PublicKey::from(opk_arr),
140            addresses,
141        })
142    }
143}
144
145// ── ObfuscationBufferContainer impl ──────────────────────────────────────────
146
147impl ObfuscationBufferContainer for ClientCertificate {
148    #[cfg(any(feature = "full_software", feature = "full_hardware"))]
149    #[inline]
150    fn obfuscation_buffer(&self) -> FixedByteBuffer<ED25519_BYTES> {
151        FixedByteBuffer::from(self.opk.as_bytes())
152    }
153
154    #[cfg(any(feature = "fast_software", feature = "fast_hardware"))]
155    #[inline]
156    fn obfuscation_buffer(&self) -> FixedByteBuffer<ED25519_BYTES> {
157        self.obfs
158    }
159}