embedded_tls/
config.rs

1use crate::cipher_suites::CipherSuite;
2use crate::extensions::extension_data::signature_algorithms::SignatureScheme;
3use crate::extensions::extension_data::supported_groups::NamedGroup;
4use crate::handshake::certificate::CertificateRef;
5use crate::handshake::certificate_verify::CertificateVerify;
6use crate::TlsError;
7use aes_gcm::{AeadInPlace, Aes128Gcm, Aes256Gcm, KeyInit};
8use core::marker::PhantomData;
9use digest::core_api::BlockSizeUser;
10use digest::{Digest, FixedOutput, OutputSizeUser, Reset};
11use generic_array::ArrayLength;
12use heapless::Vec;
13use rand_core::{CryptoRng, RngCore};
14pub use sha2::Sha256;
15pub use sha2::Sha384;
16use typenum::{Sum, U10, U12, U16, U32};
17
18pub use crate::extensions::extension_data::max_fragment_length::MaxFragmentLength;
19
20pub(crate) const TLS_RECORD_MAX: usize = 16384;
21pub const TLS_RECORD_OVERHEAD: usize = 128;
22
23// longest label is 12b -> buf <= 2 + 1 + 6 + longest + 1 + hash_out = hash_out + 22
24type LongestLabel = U12;
25type LabelOverhead = U10;
26type LabelBuffer<CipherSuite> = Sum<
27    <<CipherSuite as TlsCipherSuite>::Hash as OutputSizeUser>::OutputSize,
28    Sum<LongestLabel, LabelOverhead>,
29>;
30
31/// Represents a TLS 1.3 cipher suite
32pub trait TlsCipherSuite {
33    const CODE_POINT: u16;
34    type Cipher: KeyInit<KeySize = Self::KeyLen> + AeadInPlace<NonceSize = Self::IvLen>;
35    type KeyLen: ArrayLength<u8>;
36    type IvLen: ArrayLength<u8>;
37
38    type Hash: Digest + Reset + Clone + OutputSizeUser + BlockSizeUser + FixedOutput;
39    type LabelBufferSize: ArrayLength<u8>;
40}
41
42pub struct Aes128GcmSha256;
43impl TlsCipherSuite for Aes128GcmSha256 {
44    const CODE_POINT: u16 = CipherSuite::TlsAes128GcmSha256 as u16;
45    type Cipher = Aes128Gcm;
46    type KeyLen = U16;
47    type IvLen = U12;
48
49    type Hash = Sha256;
50    type LabelBufferSize = LabelBuffer<Self>;
51}
52
53pub struct Aes256GcmSha384;
54impl TlsCipherSuite for Aes256GcmSha384 {
55    const CODE_POINT: u16 = CipherSuite::TlsAes256GcmSha384 as u16;
56    type Cipher = Aes256Gcm;
57    type KeyLen = U32;
58    type IvLen = U12;
59
60    type Hash = Sha384;
61    type LabelBufferSize = LabelBuffer<Self>;
62}
63
64/// A TLS 1.3 verifier.
65///
66/// The verifier is responsible for verifying certificates and signatures. Since certificate verification is
67/// an expensive process, this trait allows clients to choose how much verification should take place,
68/// and also to skip the verification if the server is verified through other means (I.e. a pre-shared key).
69pub trait TlsVerifier<'a, CipherSuite>
70where
71    CipherSuite: TlsCipherSuite,
72{
73    /// Create a new verification instance.
74    ///
75    /// This method is called for every TLS handshake.
76    ///
77    /// Host verification is enabled by passing a server hostname.
78    fn new(host: Option<&'a str>) -> Self;
79
80    /// Verify a certificate.
81    ///
82    /// The handshake transcript up to this point and the server certificate is provided
83    /// for the implementation
84    /// to use.
85    fn verify_certificate(
86        &mut self,
87        transcript: &CipherSuite::Hash,
88        ca: &Option<Certificate>,
89        cert: CertificateRef,
90    ) -> Result<(), TlsError>;
91
92    /// Verify the certificate signature.
93    ///
94    /// The signature verification uses the transcript and certificate provided earlier to decode the provided signature.
95    fn verify_signature(&mut self, verify: CertificateVerify) -> Result<(), crate::TlsError>;
96}
97
98pub struct NoVerify;
99
100impl<'a, CipherSuite> TlsVerifier<'a, CipherSuite> for NoVerify
101where
102    CipherSuite: TlsCipherSuite,
103{
104    fn new(_host: Option<&str>) -> Self {
105        Self
106    }
107
108    fn verify_certificate(
109        &mut self,
110        _transcript: &CipherSuite::Hash,
111        _ca: &Option<Certificate>,
112        _cert: CertificateRef,
113    ) -> Result<(), TlsError> {
114        Ok(())
115    }
116
117    fn verify_signature(&mut self, _verify: CertificateVerify) -> Result<(), crate::TlsError> {
118        Ok(())
119    }
120}
121
122#[derive(Debug)]
123#[cfg_attr(feature = "defmt", derive(defmt::Format))]
124pub struct TlsConfig<'a, CipherSuite>
125where
126    CipherSuite: TlsCipherSuite,
127{
128    //pub(crate) cipher_suites: Vec<CipherSuite, U16>,
129    pub(crate) server_name: Option<&'a str>,
130    pub(crate) psk: Option<(&'a [u8], Vec<&'a [u8], 4>)>,
131    pub(crate) cipher_suite: PhantomData<CipherSuite>,
132    pub(crate) signature_schemes: Vec<SignatureScheme, 16>,
133    pub(crate) named_groups: Vec<NamedGroup, 16>,
134    pub(crate) max_fragment_length: Option<MaxFragmentLength>,
135    pub(crate) ca: Option<Certificate<'a>>,
136    pub(crate) cert: Option<Certificate<'a>>,
137}
138
139pub trait TlsClock {
140    fn now() -> Option<u64>;
141}
142
143pub struct NoClock;
144
145impl TlsClock for NoClock {
146    fn now() -> Option<u64> {
147        None
148    }
149}
150
151#[derive(Debug)]
152#[cfg_attr(feature = "defmt", derive(defmt::Format))]
153pub struct TlsContext<'a, CipherSuite, RNG>
154where
155    CipherSuite: TlsCipherSuite,
156    RNG: CryptoRng + RngCore + 'a,
157{
158    pub(crate) config: &'a TlsConfig<'a, CipherSuite>,
159    pub(crate) rng: &'a mut RNG,
160}
161
162impl<'a, CipherSuite, RNG> TlsContext<'a, CipherSuite, RNG>
163where
164    CipherSuite: TlsCipherSuite,
165    RNG: CryptoRng + RngCore + 'a,
166{
167    /// Create a new context with a given config and random number generator reference.
168    pub fn new(config: &'a TlsConfig<'a, CipherSuite>, rng: &'a mut RNG) -> Self {
169        Self { config, rng }
170    }
171}
172
173impl<'a, CipherSuite> TlsConfig<'a, CipherSuite>
174where
175    CipherSuite: TlsCipherSuite,
176{
177    pub fn new() -> Self {
178        let mut config = Self {
179            cipher_suite: PhantomData,
180            signature_schemes: Vec::new(),
181            named_groups: Vec::new(),
182            max_fragment_length: None,
183            psk: None,
184            server_name: None,
185            ca: None,
186            cert: None,
187        };
188
189        //config.cipher_suites.push(CipherSuite::TlsAes128GcmSha256);
190        //
191        if cfg!(feature = "alloc") {
192            config = config.enable_rsa_signatures();
193        }
194
195        unwrap!(config
196            .signature_schemes
197            .push(SignatureScheme::EcdsaSecp256r1Sha256)
198            .ok());
199        unwrap!(config
200            .signature_schemes
201            .push(SignatureScheme::EcdsaSecp384r1Sha384)
202            .ok());
203        unwrap!(config.signature_schemes.push(SignatureScheme::Ed25519).ok());
204
205        unwrap!(config.named_groups.push(NamedGroup::Secp256r1));
206
207        config
208    }
209
210    /// Enable RSA ciphers even if they might not be supported.
211    pub fn enable_rsa_signatures(mut self) -> Self {
212        unwrap!(self
213            .signature_schemes
214            .push(SignatureScheme::RsaPkcs1Sha256)
215            .ok());
216        unwrap!(self
217            .signature_schemes
218            .push(SignatureScheme::RsaPkcs1Sha384)
219            .ok());
220        unwrap!(self
221            .signature_schemes
222            .push(SignatureScheme::RsaPkcs1Sha512)
223            .ok());
224        unwrap!(self
225            .signature_schemes
226            .push(SignatureScheme::RsaPssRsaeSha256)
227            .ok());
228        unwrap!(self
229            .signature_schemes
230            .push(SignatureScheme::RsaPssRsaeSha384)
231            .ok());
232        unwrap!(self
233            .signature_schemes
234            .push(SignatureScheme::RsaPssRsaeSha512)
235            .ok());
236        self
237    }
238
239    pub fn with_server_name(mut self, server_name: &'a str) -> Self {
240        self.server_name = Some(server_name);
241        self
242    }
243
244    /// Configures the maximum plaintext fragment size.
245    ///
246    /// This option may help reduce memory size, as smaller fragment lengths require smaller
247    /// read/write buffers. Note that embedded-tls does not currently use this option to fragment
248    /// writes. Note that the buffers need to include some overhead over the configured fragment
249    /// length.
250    ///
251    /// From [RFC 6066, Section 4.  Maximum Fragment Length Negotiation](https://www.rfc-editor.org/rfc/rfc6066#page-8):
252    ///
253    /// > Without this extension, TLS specifies a fixed maximum plaintext
254    /// > fragment length of 2^14 bytes.  It may be desirable for constrained
255    /// > clients to negotiate a smaller maximum fragment length due to memory
256    /// > limitations or bandwidth limitations.
257    ///
258    /// > For example, if the negotiated length is 2^9=512, then, when using currently defined
259    /// > cipher suites ([...]) and null compression, the record-layer output can be at most
260    /// > 805 bytes: 5 bytes of headers, 512 bytes of application data, 256 bytes of padding,
261    /// > and 32 bytes of MAC.
262    pub fn with_max_fragment_length(mut self, max_fragment_length: MaxFragmentLength) -> Self {
263        self.max_fragment_length = Some(max_fragment_length);
264        self
265    }
266
267    /// Resets the max fragment length to 14 bits (16384).
268    pub fn reset_max_fragment_length(mut self) -> Self {
269        self.max_fragment_length = None;
270        self
271    }
272
273    pub fn with_ca(mut self, ca: Certificate<'a>) -> Self {
274        self.ca = Some(ca);
275        self
276    }
277
278    pub fn with_cert(mut self, cert: Certificate<'a>) -> Self {
279        self.cert = Some(cert);
280        self
281    }
282
283    pub fn with_psk(mut self, psk: &'a [u8], identities: &[&'a [u8]]) -> Self {
284        // TODO: Remove potential panic
285        self.psk = Some((psk, unwrap!(Vec::from_slice(identities).ok())));
286        self
287    }
288}
289
290impl<'a, CipherSuite> Default for TlsConfig<'a, CipherSuite>
291where
292    CipherSuite: TlsCipherSuite,
293{
294    fn default() -> Self {
295        TlsConfig::new()
296    }
297}
298
299#[derive(Debug, Clone)]
300#[cfg_attr(feature = "defmt", derive(defmt::Format))]
301pub enum Certificate<'a> {
302    X509(&'a [u8]),
303    RawPublicKey(&'a [u8]),
304}