[go: up one dir, main page]

ureq/tls/
cert.rs

1use std::fmt;
2use std::hash::{Hash, Hasher};
3
4use crate::Error;
5
6/// An X509 certificate for a server or a client.
7///
8/// These are either used as trust roots, or client authentication.
9///
10/// The internal representation is DER form. The provided helpers for PEM
11/// translates to DER.
12#[derive(Clone, Hash)]
13pub struct Certificate<'a> {
14    der: CertDer<'a>,
15}
16
17#[derive(Clone)]
18enum CertDer<'a> {
19    Borrowed(&'a [u8]),
20    Owned(Vec<u8>),
21    Rustls(rustls_pki_types::CertificateDer<'static>),
22}
23
24impl Hash for CertDer<'_> {
25    fn hash<H: Hasher>(&self, state: &mut H) {
26        core::mem::discriminant(self).hash(state);
27        self.as_ref().hash(state)
28    }
29}
30
31impl<'a> AsRef<[u8]> for CertDer<'a> {
32    fn as_ref(&self) -> &[u8] {
33        match self {
34            CertDer::Borrowed(v) => v,
35            CertDer::Owned(v) => v,
36            CertDer::Rustls(v) => v,
37        }
38    }
39}
40
41impl<'a> Certificate<'a> {
42    /// Read an X509 certificate in DER form.
43    ///
44    /// Does not immediately validate whether the data provided is a valid DER formatted
45    /// X509. That validation is the responsibility of the TLS provider.
46    pub fn from_der(der: &'a [u8]) -> Self {
47        let der = CertDer::Borrowed(der);
48        Certificate { der }
49    }
50
51    /// Read an X509 certificate in PEM form.
52    ///
53    /// This is a shorthand for [`parse_pem`] followed by picking the first certificate.
54    /// Fails with an error if there is no certificate found in the PEM given.
55    ///
56    /// Translates to DER format internally.
57    pub fn from_pem(pem: &'a [u8]) -> Result<Certificate<'static>, Error> {
58        let item = parse_pem(pem)
59            .find(|p| matches!(p, Err(_) | Ok(PemItem::Certificate(_))))
60            // None means there were no matches in the PEM chain
61            .ok_or(Error::Tls("No pem encoded cert found"))??;
62
63        let PemItem::Certificate(cert) = item else {
64            unreachable!("matches! above for Certificate");
65        };
66
67        Ok(cert)
68    }
69
70    /// This certificate in DER (the internal) format.
71    pub fn der(&self) -> &[u8] {
72        self.der.as_ref()
73    }
74
75    /// Clones (allocates) to produce a static copy.
76    pub fn to_owned(&self) -> Certificate<'static> {
77        Certificate {
78            der: CertDer::Owned(self.der.as_ref().to_vec()),
79        }
80    }
81}
82
83/// A private key used in client certificate auth.
84///
85/// The internal representation is DER form. The provided helpers for PEM
86/// translates to DER.
87///
88/// Deliberately not `Clone` to avoid accidental copies in memory.
89#[derive(Hash)]
90pub struct PrivateKey<'a> {
91    kind: KeyKind,
92    der: PrivateKeyDer<'a>,
93}
94
95enum PrivateKeyDer<'a> {
96    Borrowed(&'a [u8]),
97    Owned(Vec<u8>),
98    Rustls(rustls_pki_types::PrivateKeyDer<'static>),
99}
100
101impl Hash for PrivateKeyDer<'_> {
102    fn hash<H: Hasher>(&self, state: &mut H) {
103        core::mem::discriminant(self).hash(state);
104        match self {
105            PrivateKeyDer::Borrowed(v) => v.hash(state),
106            PrivateKeyDer::Owned(v) => v.hash(state),
107            PrivateKeyDer::Rustls(v) => v.secret_der().as_ref().hash(state),
108        }
109    }
110}
111
112impl<'a> AsRef<[u8]> for PrivateKey<'a> {
113    fn as_ref(&self) -> &[u8] {
114        match &self.der {
115            PrivateKeyDer::Borrowed(v) => v,
116            PrivateKeyDer::Owned(v) => v,
117            PrivateKeyDer::Rustls(v) => v.secret_der(),
118        }
119    }
120}
121
122/// The kind of private key.
123///
124/// * For **rustls** any kind is valid.
125/// * For **native-tls** the only valid option is [`Pkcs8`](KeyKind::Pkcs8).
126#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
127#[non_exhaustive]
128pub enum KeyKind {
129    /// An RSA private key
130    Pkcs1,
131    /// A PKCS#8 private key.
132    ///
133    /// Not encrypted with a passphrase.
134    Pkcs8,
135    /// A Sec1 private key
136    Sec1,
137}
138
139impl<'a> PrivateKey<'a> {
140    /// Read private key in DER form.
141    ///
142    /// Does not immediately validate whether the data provided is a valid DER.
143    /// That validation is the responsibility of the TLS provider.
144    pub fn from_der(kind: KeyKind, der: &'a [u8]) -> Self {
145        let der = PrivateKeyDer::Borrowed(der);
146        PrivateKey { kind, der }
147    }
148
149    /// Read a private key in PEM form.
150    ///
151    /// This is a shorthand for [`parse_pem`] followed by picking the first found key.
152    /// Fails with an error if there are no keys found in the PEM given.
153    ///
154    /// Translates to DER format internally.
155    pub fn from_pem(pem: &'a [u8]) -> Result<PrivateKey<'static>, Error> {
156        let item = parse_pem(pem)
157            .find(|p| matches!(p, Err(_) | Ok(PemItem::PrivateKey(_))))
158            // None means there were no matches in the PEM chain
159            .ok_or(Error::Tls("No pem encoded private key found"))??;
160
161        let PemItem::PrivateKey(key) = item else {
162            unreachable!("matches! above for PrivateKey");
163        };
164
165        Ok(key)
166    }
167
168    /// The key kind
169    pub fn kind(&self) -> KeyKind {
170        self.kind
171    }
172
173    /// This private key in DER (the internal) format.
174    pub fn der(&self) -> &[u8] {
175        self.as_ref()
176    }
177
178    /// Clones (allocates) to produce a static copy.
179    pub fn to_owned(&self) -> PrivateKey<'static> {
180        PrivateKey {
181            kind: self.kind,
182            der: match &self.der {
183                PrivateKeyDer::Borrowed(v) => PrivateKeyDer::Owned(v.to_vec()),
184                PrivateKeyDer::Owned(v) => PrivateKeyDer::Owned(v.to_vec()),
185                PrivateKeyDer::Rustls(v) => PrivateKeyDer::Rustls(v.clone_key()),
186            },
187        }
188    }
189}
190
191/// Parser of PEM data.
192///
193/// The data may contain one or many PEM items. The iterator produces the recognized PEM
194/// items and skip others.
195pub fn parse_pem(pem: &[u8]) -> impl Iterator<Item = Result<PemItem<'static>, Error>> + '_ {
196    PemIter(pem)
197}
198
199/// Kinds of PEM data found by [`parse_pem`]
200#[non_exhaustive]
201pub enum PemItem<'a> {
202    /// An X509 certificate
203    Certificate(Certificate<'a>),
204
205    /// A private key
206    PrivateKey(PrivateKey<'a>),
207}
208
209struct PemIter<'a>(&'a [u8]);
210
211impl<'a> Iterator for PemIter<'a> {
212    type Item = Result<PemItem<'static>, Error>;
213
214    fn next(&mut self) -> Option<Self::Item> {
215        loop {
216            match rustls_pemfile::read_one_from_slice(self.0) {
217                Ok(Some((cert, rest))) => {
218                    // Move slice along for next iterator next()
219                    self.0 = rest;
220
221                    match cert {
222                        rustls_pemfile::Item::X509Certificate(der) => {
223                            return Some(Ok(Certificate {
224                                der: CertDer::Rustls(der),
225                            }
226                            .into()));
227                        }
228                        rustls_pemfile::Item::Pkcs1Key(der) => {
229                            return Some(Ok(PrivateKey {
230                                kind: KeyKind::Pkcs1,
231                                der: PrivateKeyDer::Rustls(der.into()),
232                            }
233                            .into()));
234                        }
235                        rustls_pemfile::Item::Pkcs8Key(der) => {
236                            return Some(Ok(PrivateKey {
237                                kind: KeyKind::Pkcs8,
238                                der: PrivateKeyDer::Rustls(der.into()),
239                            }
240                            .into()));
241                        }
242                        rustls_pemfile::Item::Sec1Key(der) => {
243                            return Some(Ok(PrivateKey {
244                                kind: KeyKind::Sec1,
245                                der: PrivateKeyDer::Rustls(der.into()),
246                            }
247                            .into()));
248                        }
249
250                        // Skip unhandled item type (CSR etc)
251                        _ => continue,
252                    }
253                }
254
255                // It's over
256                Ok(None) => return None,
257
258                Err(e) => {
259                    return Some(Err(Error::Pem(e)));
260                }
261            }
262        }
263    }
264}
265
266impl<'a> From<Certificate<'a>> for PemItem<'a> {
267    fn from(value: Certificate<'a>) -> Self {
268        PemItem::Certificate(value)
269    }
270}
271
272impl<'a> From<PrivateKey<'a>> for PemItem<'a> {
273    fn from(value: PrivateKey<'a>) -> Self {
274        PemItem::PrivateKey(value)
275    }
276}
277
278impl<'a> fmt::Debug for Certificate<'a> {
279    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
280        f.debug_struct("Certificate").finish()
281    }
282}
283
284impl<'a> fmt::Debug for PrivateKey<'a> {
285    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
286        f.debug_struct("PrivateKey")
287            .field("kind", &self.kind)
288            .finish()
289    }
290}