embedded_tls/
config.rs

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