1 | //! TLS configuration and types |
2 | //! |
3 | //! A `Client` will use transport layer security (TLS) by default to connect to |
4 | //! HTTPS destinations. |
5 | //! |
6 | //! # Backends |
7 | //! |
8 | //! reqwest supports several TLS backends, enabled with Cargo features. |
9 | //! |
10 | //! ## default-tls |
11 | //! |
12 | //! reqwest will pick a TLS backend by default. This is true when the |
13 | //! `default-tls` feature is enabled. |
14 | //! |
15 | //! While it currently uses `native-tls`, the feature set is designed to only |
16 | //! enable configuration that is shared among available backends. This allows |
17 | //! reqwest to change the default to `rustls` (or another) at some point in the |
18 | //! future. |
19 | //! |
20 | //! <div class="warning">This feature is enabled by default, and takes |
21 | //! precedence if any other crate enables it. This is true even if you declare |
22 | //! `features = []`. You must set `default-features = false` instead.</div> |
23 | //! |
24 | //! Since Cargo features are additive, other crates in your dependency tree can |
25 | //! cause the default backend to be enabled. If you wish to ensure your |
26 | //! `Client` uses a specific backend, call the appropriate builder methods |
27 | //! (such as [`use_rustls_tls()`][]). |
28 | //! |
29 | //! [`use_rustls_tls()`]: crate::ClientBuilder::use_rustls_tls() |
30 | //! |
31 | //! ## native-tls |
32 | //! |
33 | //! This backend uses the [native-tls][] crate. That will try to use the system |
34 | //! TLS on Windows and Mac, and OpenSSL on Linux targets. |
35 | //! |
36 | //! Enabling the feature explicitly allows for `native-tls`-specific |
37 | //! configuration options. |
38 | //! |
39 | //! [native-tls]: https://crates.io/crates/native-tls |
40 | //! |
41 | //! ## rustls-tls |
42 | //! |
43 | //! This backend uses the [rustls][] crate, a TLS library written in Rust. |
44 | //! |
45 | //! [rustls]: https://crates.io/crates/rustls |
46 | |
47 | #[cfg (feature = "__rustls" )] |
48 | use rustls::{ |
49 | client::HandshakeSignatureValid, client::ServerCertVerified, client::ServerCertVerifier, |
50 | DigitallySignedStruct, Error as TLSError, ServerName, |
51 | }; |
52 | use std::{ |
53 | fmt, |
54 | io::{BufRead, BufReader}, |
55 | }; |
56 | |
57 | /// Represents a server X509 certificate. |
58 | #[derive (Clone)] |
59 | pub struct Certificate { |
60 | #[cfg (feature = "native-tls-crate" )] |
61 | native: native_tls_crate::Certificate, |
62 | #[cfg (feature = "__rustls" )] |
63 | original: Cert, |
64 | } |
65 | |
66 | #[cfg (feature = "__rustls" )] |
67 | #[derive (Clone)] |
68 | enum Cert { |
69 | Der(Vec<u8>), |
70 | Pem(Vec<u8>), |
71 | } |
72 | |
73 | /// Represents a private key and X509 cert as a client certificate. |
74 | #[derive (Clone)] |
75 | pub struct Identity { |
76 | #[cfg_attr (not(any(feature = "native-tls" , feature = "__rustls" )), allow(unused))] |
77 | inner: ClientCert, |
78 | } |
79 | |
80 | #[derive (Clone)] |
81 | enum ClientCert { |
82 | #[cfg (feature = "native-tls" )] |
83 | Pkcs12(native_tls_crate::Identity), |
84 | #[cfg (feature = "native-tls" )] |
85 | Pkcs8(native_tls_crate::Identity), |
86 | #[cfg (feature = "__rustls" )] |
87 | Pem { |
88 | key: rustls::PrivateKey, |
89 | certs: Vec<rustls::Certificate>, |
90 | }, |
91 | } |
92 | |
93 | impl Certificate { |
94 | /// Create a `Certificate` from a binary DER encoded certificate |
95 | /// |
96 | /// # Examples |
97 | /// |
98 | /// ``` |
99 | /// # use std::fs::File; |
100 | /// # use std::io::Read; |
101 | /// # fn cert() -> Result<(), Box<dyn std::error::Error>> { |
102 | /// let mut buf = Vec::new(); |
103 | /// File::open("my_cert.der" )? |
104 | /// .read_to_end(&mut buf)?; |
105 | /// let cert = reqwest::Certificate::from_der(&buf)?; |
106 | /// # drop(cert); |
107 | /// # Ok(()) |
108 | /// # } |
109 | /// ``` |
110 | pub fn from_der(der: &[u8]) -> crate::Result<Certificate> { |
111 | Ok(Certificate { |
112 | #[cfg (feature = "native-tls-crate" )] |
113 | native: native_tls_crate::Certificate::from_der(der).map_err(crate::error::builder)?, |
114 | #[cfg (feature = "__rustls" )] |
115 | original: Cert::Der(der.to_owned()), |
116 | }) |
117 | } |
118 | |
119 | /// Create a `Certificate` from a PEM encoded certificate |
120 | /// |
121 | /// # Examples |
122 | /// |
123 | /// ``` |
124 | /// # use std::fs::File; |
125 | /// # use std::io::Read; |
126 | /// # fn cert() -> Result<(), Box<dyn std::error::Error>> { |
127 | /// let mut buf = Vec::new(); |
128 | /// File::open("my_cert.pem" )? |
129 | /// .read_to_end(&mut buf)?; |
130 | /// let cert = reqwest::Certificate::from_pem(&buf)?; |
131 | /// # drop(cert); |
132 | /// # Ok(()) |
133 | /// # } |
134 | /// ``` |
135 | pub fn from_pem(pem: &[u8]) -> crate::Result<Certificate> { |
136 | Ok(Certificate { |
137 | #[cfg (feature = "native-tls-crate" )] |
138 | native: native_tls_crate::Certificate::from_pem(pem).map_err(crate::error::builder)?, |
139 | #[cfg (feature = "__rustls" )] |
140 | original: Cert::Pem(pem.to_owned()), |
141 | }) |
142 | } |
143 | |
144 | /// Create a collection of `Certificate`s from a PEM encoded certificate bundle. |
145 | /// Example byte sources may be `.crt`, `.cer` or `.pem` files. |
146 | /// |
147 | /// # Examples |
148 | /// |
149 | /// ``` |
150 | /// # use std::fs::File; |
151 | /// # use std::io::Read; |
152 | /// # fn cert() -> Result<(), Box<dyn std::error::Error>> { |
153 | /// let mut buf = Vec::new(); |
154 | /// File::open("ca-bundle.crt" )? |
155 | /// .read_to_end(&mut buf)?; |
156 | /// let certs = reqwest::Certificate::from_pem_bundle(&buf)?; |
157 | /// # drop(certs); |
158 | /// # Ok(()) |
159 | /// # } |
160 | /// ``` |
161 | pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<Certificate>> { |
162 | let mut reader = BufReader::new(pem_bundle); |
163 | |
164 | Self::read_pem_certs(&mut reader)? |
165 | .iter() |
166 | .map(|cert_vec| Certificate::from_der(&cert_vec)) |
167 | .collect::<crate::Result<Vec<Certificate>>>() |
168 | } |
169 | |
170 | #[cfg (feature = "native-tls-crate" )] |
171 | pub(crate) fn add_to_native_tls(self, tls: &mut native_tls_crate::TlsConnectorBuilder) { |
172 | tls.add_root_certificate(self.native); |
173 | } |
174 | |
175 | #[cfg (feature = "__rustls" )] |
176 | pub(crate) fn add_to_rustls( |
177 | self, |
178 | root_cert_store: &mut rustls::RootCertStore, |
179 | ) -> crate::Result<()> { |
180 | use std::io::Cursor; |
181 | |
182 | match self.original { |
183 | Cert::Der(buf) => root_cert_store |
184 | .add(&rustls::Certificate(buf)) |
185 | .map_err(crate::error::builder)?, |
186 | Cert::Pem(buf) => { |
187 | let mut reader = Cursor::new(buf); |
188 | let certs = Self::read_pem_certs(&mut reader)?; |
189 | for c in certs { |
190 | root_cert_store |
191 | .add(&rustls::Certificate(c)) |
192 | .map_err(crate::error::builder)?; |
193 | } |
194 | } |
195 | } |
196 | Ok(()) |
197 | } |
198 | |
199 | fn read_pem_certs(reader: &mut impl BufRead) -> crate::Result<Vec<Vec<u8>>> { |
200 | rustls_pemfile::certs(reader) |
201 | .map_err(|_| crate::error::builder("invalid certificate encoding" )) |
202 | } |
203 | } |
204 | |
205 | impl Identity { |
206 | /// Parses a DER-formatted PKCS #12 archive, using the specified password to decrypt the key. |
207 | /// |
208 | /// The archive should contain a leaf certificate and its private key, as well any intermediate |
209 | /// certificates that allow clients to build a chain to a trusted root. |
210 | /// The chain certificates should be in order from the leaf certificate towards the root. |
211 | /// |
212 | /// PKCS #12 archives typically have the file extension `.p12` or `.pfx`, and can be created |
213 | /// with the OpenSSL `pkcs12` tool: |
214 | /// |
215 | /// ```bash |
216 | /// openssl pkcs12 -export -out identity.pfx -inkey key.pem -in cert.pem -certfile chain_certs.pem |
217 | /// ``` |
218 | /// |
219 | /// # Examples |
220 | /// |
221 | /// ``` |
222 | /// # use std::fs::File; |
223 | /// # use std::io::Read; |
224 | /// # fn pkcs12() -> Result<(), Box<dyn std::error::Error>> { |
225 | /// let mut buf = Vec::new(); |
226 | /// File::open("my-ident.pfx")? |
227 | /// .read_to_end(&mut buf)?; |
228 | /// let pkcs12 = reqwest::Identity::from_pkcs12_der(&buf, "my-privkey-password")?; |
229 | /// # drop(pkcs12); |
230 | /// # Ok(()) |
231 | /// # } |
232 | /// ``` |
233 | /// |
234 | /// # Optional |
235 | /// |
236 | /// This requires the `native-tls` Cargo feature enabled. |
237 | #[cfg (feature = "native-tls" )] |
238 | pub fn from_pkcs12_der(der: &[u8], password: &str) -> crate::Result<Identity> { |
239 | Ok(Identity { |
240 | inner: ClientCert::Pkcs12( |
241 | native_tls_crate::Identity::from_pkcs12(der, password) |
242 | .map_err(crate::error::builder)?, |
243 | ), |
244 | }) |
245 | } |
246 | |
247 | /// Parses a chain of PEM encoded X509 certificates, with the leaf certificate first. |
248 | /// `key` is a PEM encoded PKCS #8 formatted private key for the leaf certificate. |
249 | /// |
250 | /// The certificate chain should contain any intermediate cerficates that should be sent to |
251 | /// clients to allow them to build a chain to a trusted root. |
252 | /// |
253 | /// A certificate chain here means a series of PEM encoded certificates concatenated together. |
254 | /// |
255 | /// # Examples |
256 | /// |
257 | /// ``` |
258 | /// # use std::fs; |
259 | /// # fn pkcs8() -> Result<(), Box<dyn std::error::Error>> { |
260 | /// let cert = fs::read("client.pem")?; |
261 | /// let key = fs::read("key.pem")?; |
262 | /// let pkcs8 = reqwest::Identity::from_pkcs8_pem(&cert, &key)?; |
263 | /// # drop(pkcs8); |
264 | /// # Ok(()) |
265 | /// # } |
266 | /// ``` |
267 | /// |
268 | /// # Optional |
269 | /// |
270 | /// This requires the `native-tls` Cargo feature enabled. |
271 | #[cfg (feature = "native-tls" )] |
272 | pub fn from_pkcs8_pem(pem: &[u8], key: &[u8]) -> crate::Result<Identity> { |
273 | Ok(Identity { |
274 | inner: ClientCert::Pkcs8( |
275 | native_tls_crate::Identity::from_pkcs8(pem, key).map_err(crate::error::builder)?, |
276 | ), |
277 | }) |
278 | } |
279 | |
280 | /// Parses PEM encoded private key and certificate. |
281 | /// |
282 | /// The input should contain a PEM encoded private key |
283 | /// and at least one PEM encoded certificate. |
284 | /// |
285 | /// Note: The private key must be in RSA, SEC1 Elliptic Curve or PKCS#8 format. |
286 | /// |
287 | /// # Examples |
288 | /// |
289 | /// ``` |
290 | /// # use std::fs::File; |
291 | /// # use std::io::Read; |
292 | /// # fn pem() -> Result<(), Box<dyn std::error::Error>> { |
293 | /// let mut buf = Vec::new(); |
294 | /// File::open("my-ident.pem")? |
295 | /// .read_to_end(&mut buf)?; |
296 | /// let id = reqwest::Identity::from_pem(&buf)?; |
297 | /// # drop(id); |
298 | /// # Ok(()) |
299 | /// # } |
300 | /// ``` |
301 | /// |
302 | /// # Optional |
303 | /// |
304 | /// This requires the `rustls-tls(-...)` Cargo feature enabled. |
305 | #[cfg (feature = "__rustls" )] |
306 | pub fn from_pem(buf: &[u8]) -> crate::Result<Identity> { |
307 | use std::io::Cursor; |
308 | |
309 | let (key, certs) = { |
310 | let mut pem = Cursor::new(buf); |
311 | let mut sk = Vec::<rustls::PrivateKey>::new(); |
312 | let mut certs = Vec::<rustls::Certificate>::new(); |
313 | |
314 | for item in std::iter::from_fn(|| rustls_pemfile::read_one(&mut pem).transpose()) { |
315 | match item.map_err(|_| { |
316 | crate::error::builder(TLSError::General(String::from( |
317 | "Invalid identity PEM file" , |
318 | ))) |
319 | })? { |
320 | rustls_pemfile::Item::X509Certificate(cert) => { |
321 | certs.push(rustls::Certificate(cert)) |
322 | } |
323 | rustls_pemfile::Item::PKCS8Key(key) => sk.push(rustls::PrivateKey(key)), |
324 | rustls_pemfile::Item::RSAKey(key) => sk.push(rustls::PrivateKey(key)), |
325 | rustls_pemfile::Item::ECKey(key) => sk.push(rustls::PrivateKey(key)), |
326 | _ => { |
327 | return Err(crate::error::builder(TLSError::General(String::from( |
328 | "No valid certificate was found" , |
329 | )))) |
330 | } |
331 | } |
332 | } |
333 | |
334 | if let (Some(sk), false) = (sk.pop(), certs.is_empty()) { |
335 | (sk, certs) |
336 | } else { |
337 | return Err(crate::error::builder(TLSError::General(String::from( |
338 | "private key or certificate not found" , |
339 | )))); |
340 | } |
341 | }; |
342 | |
343 | Ok(Identity { |
344 | inner: ClientCert::Pem { key, certs }, |
345 | }) |
346 | } |
347 | |
348 | #[cfg (feature = "native-tls" )] |
349 | pub(crate) fn add_to_native_tls( |
350 | self, |
351 | tls: &mut native_tls_crate::TlsConnectorBuilder, |
352 | ) -> crate::Result<()> { |
353 | match self.inner { |
354 | ClientCert::Pkcs12(id) | ClientCert::Pkcs8(id) => { |
355 | tls.identity(id); |
356 | Ok(()) |
357 | } |
358 | #[cfg (feature = "__rustls" )] |
359 | ClientCert::Pem { .. } => Err(crate::error::builder("incompatible TLS identity type" )), |
360 | } |
361 | } |
362 | |
363 | #[cfg (feature = "__rustls" )] |
364 | pub(crate) fn add_to_rustls( |
365 | self, |
366 | config_builder: rustls::ConfigBuilder< |
367 | rustls::ClientConfig, |
368 | rustls::client::WantsTransparencyPolicyOrClientCert, |
369 | >, |
370 | ) -> crate::Result<rustls::ClientConfig> { |
371 | match self.inner { |
372 | ClientCert::Pem { key, certs } => config_builder |
373 | .with_client_auth_cert(certs, key) |
374 | .map_err(crate::error::builder), |
375 | #[cfg (feature = "native-tls" )] |
376 | ClientCert::Pkcs12(..) | ClientCert::Pkcs8(..) => { |
377 | Err(crate::error::builder("incompatible TLS identity type" )) |
378 | } |
379 | } |
380 | } |
381 | } |
382 | |
383 | impl fmt::Debug for Certificate { |
384 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
385 | f.debug_struct(name:"Certificate" ).finish() |
386 | } |
387 | } |
388 | |
389 | impl fmt::Debug for Identity { |
390 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
391 | f.debug_struct(name:"Identity" ).finish() |
392 | } |
393 | } |
394 | |
395 | /// A TLS protocol version. |
396 | #[derive (Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] |
397 | pub struct Version(InnerVersion); |
398 | |
399 | #[derive (Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] |
400 | #[non_exhaustive ] |
401 | enum InnerVersion { |
402 | Tls1_0, |
403 | Tls1_1, |
404 | Tls1_2, |
405 | Tls1_3, |
406 | } |
407 | |
408 | // These could perhaps be From/TryFrom implementations, but those would be |
409 | // part of the public API so let's be careful |
410 | impl Version { |
411 | /// Version 1.0 of the TLS protocol. |
412 | pub const TLS_1_0: Version = Version(InnerVersion::Tls1_0); |
413 | /// Version 1.1 of the TLS protocol. |
414 | pub const TLS_1_1: Version = Version(InnerVersion::Tls1_1); |
415 | /// Version 1.2 of the TLS protocol. |
416 | pub const TLS_1_2: Version = Version(InnerVersion::Tls1_2); |
417 | /// Version 1.3 of the TLS protocol. |
418 | pub const TLS_1_3: Version = Version(InnerVersion::Tls1_3); |
419 | |
420 | #[cfg (feature = "default-tls" )] |
421 | pub(crate) fn to_native_tls(self) -> Option<native_tls_crate::Protocol> { |
422 | match self.0 { |
423 | InnerVersion::Tls1_0 => Some(native_tls_crate::Protocol::Tlsv10), |
424 | InnerVersion::Tls1_1 => Some(native_tls_crate::Protocol::Tlsv11), |
425 | InnerVersion::Tls1_2 => Some(native_tls_crate::Protocol::Tlsv12), |
426 | InnerVersion::Tls1_3 => None, |
427 | } |
428 | } |
429 | |
430 | #[cfg (feature = "__rustls" )] |
431 | pub(crate) fn from_rustls(version: rustls::ProtocolVersion) -> Option<Self> { |
432 | match version { |
433 | rustls::ProtocolVersion::SSLv2 => None, |
434 | rustls::ProtocolVersion::SSLv3 => None, |
435 | rustls::ProtocolVersion::TLSv1_0 => Some(Self(InnerVersion::Tls1_0)), |
436 | rustls::ProtocolVersion::TLSv1_1 => Some(Self(InnerVersion::Tls1_1)), |
437 | rustls::ProtocolVersion::TLSv1_2 => Some(Self(InnerVersion::Tls1_2)), |
438 | rustls::ProtocolVersion::TLSv1_3 => Some(Self(InnerVersion::Tls1_3)), |
439 | _ => None, |
440 | } |
441 | } |
442 | } |
443 | |
444 | pub(crate) enum TlsBackend { |
445 | // This is the default and HTTP/3 feature does not use it so suppress it. |
446 | #[allow (dead_code)] |
447 | #[cfg (feature = "default-tls" )] |
448 | Default, |
449 | #[cfg (feature = "native-tls" )] |
450 | BuiltNativeTls(native_tls_crate::TlsConnector), |
451 | #[cfg (feature = "__rustls" )] |
452 | Rustls, |
453 | #[cfg (feature = "__rustls" )] |
454 | BuiltRustls(rustls::ClientConfig), |
455 | #[cfg (any(feature = "native-tls" , feature = "__rustls" ,))] |
456 | UnknownPreconfigured, |
457 | } |
458 | |
459 | impl fmt::Debug for TlsBackend { |
460 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
461 | match self { |
462 | #[cfg (feature = "default-tls" )] |
463 | TlsBackend::Default => write!(f, "Default" ), |
464 | #[cfg (feature = "native-tls" )] |
465 | TlsBackend::BuiltNativeTls(_) => write!(f, "BuiltNativeTls" ), |
466 | #[cfg (feature = "__rustls" )] |
467 | TlsBackend::Rustls => write!(f, "Rustls" ), |
468 | #[cfg (feature = "__rustls" )] |
469 | TlsBackend::BuiltRustls(_) => write!(f, "BuiltRustls" ), |
470 | #[cfg (any(feature = "native-tls" , feature = "__rustls" ,))] |
471 | TlsBackend::UnknownPreconfigured => write!(f, "UnknownPreconfigured" ), |
472 | } |
473 | } |
474 | } |
475 | |
476 | impl Default for TlsBackend { |
477 | fn default() -> TlsBackend { |
478 | #[cfg (all(feature = "default-tls" , not(feature = "http3" )))] |
479 | { |
480 | TlsBackend::Default |
481 | } |
482 | |
483 | #[cfg (any( |
484 | all(feature = "__rustls" , not(feature = "default-tls" )), |
485 | feature = "http3" |
486 | ))] |
487 | { |
488 | TlsBackend::Rustls |
489 | } |
490 | } |
491 | } |
492 | |
493 | #[cfg (feature = "__rustls" )] |
494 | pub(crate) struct NoVerifier; |
495 | |
496 | #[cfg (feature = "__rustls" )] |
497 | impl ServerCertVerifier for NoVerifier { |
498 | fn verify_server_cert( |
499 | &self, |
500 | _end_entity: &rustls::Certificate, |
501 | _intermediates: &[rustls::Certificate], |
502 | _server_name: &ServerName, |
503 | _scts: &mut dyn Iterator<Item = &[u8]>, |
504 | _ocsp_response: &[u8], |
505 | _now: std::time::SystemTime, |
506 | ) -> Result<ServerCertVerified, TLSError> { |
507 | Ok(ServerCertVerified::assertion()) |
508 | } |
509 | |
510 | fn verify_tls12_signature( |
511 | &self, |
512 | _message: &[u8], |
513 | _cert: &rustls::Certificate, |
514 | _dss: &DigitallySignedStruct, |
515 | ) -> Result<HandshakeSignatureValid, TLSError> { |
516 | Ok(HandshakeSignatureValid::assertion()) |
517 | } |
518 | |
519 | fn verify_tls13_signature( |
520 | &self, |
521 | _message: &[u8], |
522 | _cert: &rustls::Certificate, |
523 | _dss: &DigitallySignedStruct, |
524 | ) -> Result<HandshakeSignatureValid, TLSError> { |
525 | Ok(HandshakeSignatureValid::assertion()) |
526 | } |
527 | } |
528 | |
529 | /// Hyper extension carrying extra TLS layer information. |
530 | /// Made available to clients on responses when `tls_info` is set. |
531 | #[derive (Clone)] |
532 | pub struct TlsInfo { |
533 | pub(crate) peer_certificate: Option<Vec<u8>>, |
534 | } |
535 | |
536 | impl TlsInfo { |
537 | /// Get the DER encoded leaf certificate of the peer. |
538 | pub fn peer_certificate(&self) -> Option<&[u8]> { |
539 | self.peer_certificate.as_ref().map(|der: &Vec| &der[..]) |
540 | } |
541 | } |
542 | |
543 | impl std::fmt::Debug for TlsInfo { |
544 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
545 | f.debug_struct(name:"TlsInfo" ).finish() |
546 | } |
547 | } |
548 | |
549 | #[cfg (test)] |
550 | mod tests { |
551 | use super::*; |
552 | |
553 | #[cfg (feature = "default-tls" )] |
554 | #[test ] |
555 | fn certificate_from_der_invalid() { |
556 | Certificate::from_der(b"not der" ).unwrap_err(); |
557 | } |
558 | |
559 | #[cfg (feature = "default-tls" )] |
560 | #[test ] |
561 | fn certificate_from_pem_invalid() { |
562 | Certificate::from_pem(b"not pem" ).unwrap_err(); |
563 | } |
564 | |
565 | #[cfg (feature = "native-tls" )] |
566 | #[test ] |
567 | fn identity_from_pkcs12_der_invalid() { |
568 | Identity::from_pkcs12_der(b"not der" , "nope" ).unwrap_err(); |
569 | } |
570 | |
571 | #[cfg (feature = "native-tls" )] |
572 | #[test ] |
573 | fn identity_from_pkcs8_pem_invalid() { |
574 | Identity::from_pkcs8_pem(b"not pem" , b"not key" ).unwrap_err(); |
575 | } |
576 | |
577 | #[cfg (feature = "__rustls" )] |
578 | #[test ] |
579 | fn identity_from_pem_invalid() { |
580 | Identity::from_pem(b"not pem" ).unwrap_err(); |
581 | } |
582 | |
583 | #[cfg (feature = "__rustls" )] |
584 | #[test ] |
585 | fn identity_from_pem_pkcs1_key() { |
586 | let pem = b"-----BEGIN CERTIFICATE----- \n\ |
587 | -----END CERTIFICATE----- \n\ |
588 | -----BEGIN RSA PRIVATE KEY----- \n\ |
589 | -----END RSA PRIVATE KEY----- \n" ; |
590 | |
591 | Identity::from_pem(pem).unwrap(); |
592 | } |
593 | |
594 | #[test ] |
595 | fn certificates_from_pem_bundle() { |
596 | const PEM_BUNDLE: &[u8] = b" |
597 | -----BEGIN CERTIFICATE----- |
598 | MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 |
599 | MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g |
600 | Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG |
601 | A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg |
602 | Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl |
603 | ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j |
604 | QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr |
605 | ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr |
606 | BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM |
607 | YyRIHN8wfdVoOw== |
608 | -----END CERTIFICATE----- |
609 | |
610 | -----BEGIN CERTIFICATE----- |
611 | MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 |
612 | MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g |
613 | Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG |
614 | A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg |
615 | Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi |
616 | 9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk |
617 | M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB |
618 | /zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB |
619 | MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw |
620 | CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW |
621 | 1KyLa2tJElMzrdfkviT8tQp21KW8EA== |
622 | -----END CERTIFICATE----- |
623 | " ; |
624 | |
625 | assert!(Certificate::from_pem_bundle(PEM_BUNDLE).is_ok()) |
626 | } |
627 | } |
628 | |