Skip to main content

embedded_tls/handshake/
certificate.rs

1use crate::TlsError;
2use crate::buffer::CryptoBuffer;
3use crate::extensions::messages::CertificateExtension;
4use crate::parse_buffer::ParseBuffer;
5use heapless::Vec;
6
7#[derive(Debug)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9pub struct CertificateRef<'a> {
10    raw_entries: &'a [u8],
11    request_context: &'a [u8],
12
13    pub entries: Vec<CertificateEntryRef<'a>, 16>,
14}
15
16impl<'a> CertificateRef<'a> {
17    pub fn with_context(request_context: &'a [u8]) -> Self {
18        Self {
19            raw_entries: &[],
20            request_context,
21            entries: Vec::new(),
22        }
23    }
24
25    pub fn add(&mut self, entry: CertificateEntryRef<'a>) -> Result<(), TlsError> {
26        self.entries.push(entry).map_err(|_| {
27            error!("CertificateRef: InsufficientSpace");
28            TlsError::InsufficientSpace
29        })
30    }
31
32    pub fn parse(buf: &mut ParseBuffer<'a>) -> Result<Self, TlsError> {
33        let request_context_len = buf.read_u8().map_err(|_| TlsError::InvalidCertificate)?;
34        let request_context = buf
35            .slice(request_context_len as usize)
36            .map_err(|_| TlsError::InvalidCertificate)?;
37        let entries_len = buf.read_u24().map_err(|_| TlsError::InvalidCertificate)?;
38        let mut raw_entries = buf
39            .slice(entries_len as usize)
40            .map_err(|_| TlsError::InvalidCertificate)?;
41
42        let entries = CertificateEntryRef::parse_vector(&mut raw_entries)?;
43
44        Ok(Self {
45            raw_entries: raw_entries.as_slice(),
46            request_context: request_context.as_slice(),
47            entries,
48        })
49    }
50
51    pub(crate) fn encode(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), TlsError> {
52        buf.with_u8_length(|buf| buf.extend_from_slice(self.request_context))?;
53        buf.with_u24_length(|buf| {
54            for entry in &self.entries {
55                entry.encode(buf)?;
56            }
57            Ok(())
58        })?;
59
60        Ok(())
61    }
62}
63
64#[derive(Debug)]
65#[cfg_attr(feature = "defmt", derive(defmt::Format))]
66pub enum CertificateEntryRef<'a> {
67    X509(&'a [u8]),
68    RawPublicKey(&'a [u8]),
69}
70
71impl<'a> CertificateEntryRef<'a> {
72    pub fn parse(buf: &mut ParseBuffer<'a>) -> Result<Self, TlsError> {
73        let entry_len = buf
74            .read_u24()
75            .map_err(|_| TlsError::InvalidCertificateEntry)?;
76        let cert = buf
77            .slice(entry_len as usize)
78            .map_err(|_| TlsError::InvalidCertificateEntry)?;
79
80        let entry = CertificateEntryRef::X509(cert.as_slice());
81
82        // Validate extensions
83        CertificateExtension::parse_vector::<2>(buf)?;
84
85        Ok(entry)
86    }
87
88    pub fn parse_vector<const N: usize>(
89        buf: &mut ParseBuffer<'a>,
90    ) -> Result<Vec<Self, N>, TlsError> {
91        let mut result = Vec::new();
92
93        while !buf.is_empty() {
94            result
95                .push(Self::parse(buf)?)
96                .map_err(|_| TlsError::DecodeError)?;
97        }
98
99        Ok(result)
100    }
101
102    pub(crate) fn encode(&self, buf: &mut CryptoBuffer<'_>) -> Result<(), TlsError> {
103        match *self {
104            CertificateEntryRef::RawPublicKey(_key) => {
105                todo!("ASN1_subjectPublicKeyInfo encoding?");
106                // buf.with_u24_length(|buf| buf.extend_from_slice(key))?;
107            }
108            CertificateEntryRef::X509(cert) => {
109                buf.with_u24_length(|buf| buf.extend_from_slice(cert))?;
110            }
111        }
112
113        // Zero extensions for now
114        buf.push_u16(0)?;
115        Ok(())
116    }
117}
118
119impl<'a, D: AsRef<[u8]>> From<&'a crate::config::Certificate<D>> for CertificateEntryRef<'a> {
120    fn from(cert: &'a crate::config::Certificate<D>) -> Self {
121        match cert {
122            crate::config::Certificate::X509(data) => CertificateEntryRef::X509(data.as_ref()),
123            crate::config::Certificate::RawPublicKey(data) => {
124                CertificateEntryRef::RawPublicKey(data.as_ref())
125            }
126        }
127    }
128}
129
130#[derive(Debug)]
131#[cfg_attr(feature = "defmt", derive(defmt::Format))]
132pub struct Certificate<const N: usize> {
133    request_context: Vec<u8, 256>,
134    entries_data: Vec<u8, N>,
135}
136
137impl<const N: usize> Certificate<N> {
138    pub fn request_context(&self) -> &[u8] {
139        &self.request_context[..]
140    }
141}
142
143impl<'a, const N: usize> TryFrom<CertificateRef<'a>> for Certificate<N> {
144    type Error = TlsError;
145    fn try_from(cert: CertificateRef<'a>) -> Result<Self, Self::Error> {
146        let mut request_context = Vec::new();
147        request_context
148            .extend_from_slice(cert.request_context)
149            .map_err(|_| TlsError::OutOfMemory)?;
150        let mut entries_data = Vec::new();
151        entries_data
152            .extend_from_slice(cert.raw_entries)
153            .map_err(|_| TlsError::OutOfMemory)?;
154
155        Ok(Self {
156            request_context,
157            entries_data,
158        })
159    }
160}
161
162impl<'a, const N: usize> TryFrom<&'a Certificate<N>> for CertificateRef<'a> {
163    type Error = TlsError;
164    fn try_from(cert: &'a Certificate<N>) -> Result<Self, Self::Error> {
165        let request_context = cert.request_context();
166        let entries =
167            CertificateEntryRef::parse_vector(&mut ParseBuffer::from(&cert.entries_data[..]))?;
168        Ok(Self {
169            raw_entries: &cert.entries_data[..],
170            request_context,
171            entries,
172        })
173    }
174}