1use std::{
2 fs::{self, File},
3 io::{self, BufReader, Error, ErrorKind, Read, Write},
4 path::Path,
5};
6
7use rcgen::{
8 date_time_ymd, BasicConstraints, Certificate, CertificateParams, CertificateSigningRequest,
9 DistinguishedName, DnType, IsCa, KeyPair,
10};
11use rsa::{pkcs1::LineEnding, pkcs8::EncodePrivateKey, RsaPrivateKey};
12use rustls_pemfile::{read_one, Item};
13
14pub struct Ca {
19 pub cert: Certificate,
20}
21
22impl Ca {
23 pub fn new(common_name: &str) -> io::Result<Self> {
24 let cert_params = default_params(None, Some(common_name.to_string()), true)?;
25 let cert = generate(Some(cert_params))?;
26 Ok(Self { cert })
27 }
28
29 pub fn new_with_parameters(cert_params: Option<CertificateParams>) -> io::Result<Self> {
30 let cert = generate(cert_params)?;
31 Ok(Self { cert })
32 }
33
34 pub fn save(
36 &self,
37 overwrite: bool,
38 key_path: Option<&str>,
39 cert_path: Option<&str>,
40 ) -> io::Result<(String, String)> {
41 let key_path = if let Some(p) = key_path {
42 if !overwrite && Path::new(p).exists() {
43 return Err(Error::new(
44 ErrorKind::Other,
45 format!("key path '{p}' already exists"),
46 ));
47 }
48 p.to_string()
49 } else {
50 random_manager::tmp_path(10, Some(".key"))?
51 };
52
53 let cert_path = if let Some(p) = cert_path {
54 if !overwrite && Path::new(p).exists() {
55 return Err(Error::new(
56 ErrorKind::Other,
57 format!("cert path '{p}' already exists"),
58 ));
59 }
60 p.to_string()
61 } else {
62 random_manager::tmp_path(10, Some(".cert"))?
63 };
64
65 let key_contents = self.cert.serialize_private_key_pem();
68 let mut key_file = File::create(&key_path)?;
69 key_file.write_all(key_contents.as_bytes())?;
70 log::info!("saved key '{key_path}' ({}-byte)", key_contents.len());
71
72 let cert_contents = self
73 .cert
74 .serialize_pem()
75 .map_err(|e| Error::new(ErrorKind::Other, format!("failed to serialize_pem {}", e)))?;
76 let mut cert_file = File::create(&cert_path)?;
77 cert_file.write_all(cert_contents.as_bytes())?;
78 log::info!("saved cert '{cert_path}' ({}-byte)", cert_contents.len());
79
80 Ok((key_path, cert_path))
81 }
82
83 pub fn issue_cert(&self, csr_pem: &str) -> io::Result<String> {
86 log::info!("issuing a cert for CSR");
87 let csr = CertificateSigningRequest::from_pem(csr_pem).map_err(|e| {
88 Error::new(
89 ErrorKind::Other,
90 format!("failed CertificateSigningRequest::from_pem {}", e),
91 )
92 })?;
93 csr.serialize_pem_with_signer(&self.cert).map_err(|e| {
94 Error::new(
95 ErrorKind::Other,
96 format!("failed serialize_pem_with_signer {}", e),
97 )
98 })
99 }
100
101 pub fn issue_and_save_cert(
104 &self,
105 csr_pem: &str,
106 overwrite: bool,
107 cert_path: Option<&str>,
108 ) -> io::Result<(String, String)> {
109 let cert_path = if let Some(p) = cert_path {
110 if !overwrite && Path::new(p).exists() {
111 return Err(Error::new(
112 ErrorKind::Other,
113 format!("CSR path '{p}' already exists"),
114 ));
115 }
116 p.to_string()
117 } else {
118 random_manager::tmp_path(10, Some(".csr.pem"))?
119 };
120
121 log::info!("saving the issued certificate in '{cert_path}'");
122 let issued_cert = self.issue_cert(csr_pem)?;
123 let mut issued_cert_file = File::create(&cert_path)?;
124 issued_cert_file.write_all(issued_cert.as_bytes())?;
125 log::info!("saved cert '{cert_path}' ({}-byte)", issued_cert.len());
126
127 Ok((issued_cert, cert_path))
128 }
129}
130
131pub struct CsrEntity {
135 pub cert: Certificate,
136 pub csr_pem: String,
137}
138
139impl CsrEntity {
140 pub fn new(common_name: &str) -> io::Result<Self> {
141 let cert_params = default_params(None, Some(common_name.to_string()), false)?;
142 let (cert, csr_pem) = generate_csr(cert_params)?;
143 Ok(Self { cert, csr_pem })
144 }
145
146 pub fn new_with_parameters(cert_params: CertificateParams) -> io::Result<Self> {
147 let (cert, csr_pem) = generate_csr(cert_params)?;
148 Ok(Self { cert, csr_pem })
149 }
150
151 pub fn save_csr(&self, overwrite: bool, csr_path: Option<&str>) -> io::Result<String> {
153 let csr_path = if let Some(p) = csr_path {
154 if !overwrite && Path::new(p).exists() {
155 return Err(Error::new(
156 ErrorKind::Other,
157 format!("CSR path '{p}' already exists"),
158 ));
159 }
160 p.to_string()
161 } else {
162 random_manager::tmp_path(10, Some(".csr.pem"))?
163 };
164
165 let mut csr_file = File::create(&csr_path)?;
166 csr_file.write_all(self.csr_pem.as_bytes())?;
167 log::info!("saved CSR '{csr_path}' ({}-byte)", self.csr_pem.len());
168
169 Ok(csr_path)
170 }
171
172 pub fn save(
175 &self,
176 overwrite: bool,
177 csr_key_path: Option<&str>,
178 csr_cert_path: Option<&str>,
179 csr_path: Option<&str>,
180 ) -> io::Result<(String, String, String)> {
181 let csr_key_path = if let Some(p) = csr_key_path {
182 if !overwrite && Path::new(p).exists() {
183 return Err(Error::new(
184 ErrorKind::Other,
185 format!("CSR key path '{p}' already exists"),
186 ));
187 }
188 p.to_string()
189 } else {
190 random_manager::tmp_path(10, Some(".key"))?
191 };
192
193 let csr_cert_path = if let Some(p) = csr_cert_path {
194 if !overwrite && Path::new(p).exists() {
195 return Err(Error::new(
196 ErrorKind::Other,
197 format!("CSR cert path '{p}' already exists"),
198 ));
199 }
200 p.to_string()
201 } else {
202 random_manager::tmp_path(10, Some(".cert"))?
203 };
204
205 let csr_path = if let Some(p) = csr_path {
206 if !overwrite && Path::new(p).exists() {
207 return Err(Error::new(
208 ErrorKind::Other,
209 format!("CSR path '{p}' already exists"),
210 ));
211 }
212 p.to_string()
213 } else {
214 random_manager::tmp_path(10, Some(".csr.pem"))?
215 };
216
217 let csr_key_contents = self.cert.serialize_private_key_pem();
220 let mut csr_key_file = File::create(&csr_key_path)?;
221 csr_key_file.write_all(csr_key_contents.as_bytes())?;
222 log::info!(
223 "saved key '{csr_key_path}' ({}-byte)",
224 csr_key_contents.len()
225 );
226
227 let csr_cert_contents = self
228 .cert
229 .serialize_pem()
230 .map_err(|e| Error::new(ErrorKind::Other, format!("failed to serialize_pem {}", e)))?;
231 let mut cert_file = File::create(&csr_cert_path)?;
232 cert_file.write_all(csr_cert_contents.as_bytes())?;
233 log::info!(
234 "saved cert '{csr_cert_path}' ({}-byte)",
235 csr_cert_contents.len()
236 );
237
238 let mut csr_file = File::create(&csr_path)?;
241 csr_file.write_all(self.csr_pem.as_bytes())?;
242 log::info!("saved CSR '{csr_path}' ({}-byte)", self.csr_pem.len());
243
244 Ok((csr_key_path, csr_cert_path, csr_path))
245 }
246}
247
248#[test]
250fn test_csr() {
251 use std::process::{Command, Stdio};
252
253 let _ = env_logger::builder()
254 .filter_level(log::LevelFilter::Info)
255 .is_test(true)
256 .try_init();
257
258 let ca = Ca::new("ca.hello.com").unwrap();
259 let (ca_key_path, ca_cert_path) = ca.save(true, None, None).unwrap();
260 let openssl_args = vec![
261 "x509".to_string(),
262 "-text".to_string(),
263 "-noout".to_string(),
264 "-in".to_string(),
265 ca_cert_path.to_string(),
266 ];
267 let openssl_cmd = Command::new("openssl")
268 .stderr(Stdio::piped())
269 .stdout(Stdio::piped())
270 .args(openssl_args)
271 .spawn()
272 .unwrap();
273 log::info!("ran openssl x509 with PID {}", openssl_cmd.id());
274 let res = openssl_cmd.wait_with_output();
275 match res {
276 Ok(output) => {
277 println!(
278 "openssl output {} bytes:\n{}\n",
279 output.stdout.len(),
280 String::from_utf8(output.stdout).unwrap()
281 )
282 }
283 Err(e) => {
284 log::warn!("failed to run openssl {}", e)
285 }
286 }
287
288 let csr_entity = CsrEntity::new("entity.hello.com").unwrap();
289 log::info!("csr_entity.csr:\n\n{}", csr_entity.csr_pem);
290 let (csr_key_path, csr_cert_path, csr_path) = csr_entity.save(true, None, None, None).unwrap();
291 log::info!("csr_key_path: {csr_key_path}");
292 log::info!("csr_cert_path: {csr_cert_path}");
293 log::info!("csr_path: {csr_path}");
294 let openssl_args = vec![
295 "x509".to_string(),
296 "-text".to_string(),
297 "-noout".to_string(),
298 "-in".to_string(),
299 csr_cert_path.to_string(),
300 ];
301 let openssl_cmd = Command::new("openssl")
302 .stderr(Stdio::piped())
303 .stdout(Stdio::piped())
304 .args(openssl_args)
305 .spawn()
306 .unwrap();
307 log::info!("ran openssl x509 with PID {}", openssl_cmd.id());
308 let res = openssl_cmd.wait_with_output();
309 match res {
310 Ok(output) => {
311 println!(
312 "openssl output {} bytes:\n{}\n",
313 output.stdout.len(),
314 String::from_utf8(output.stdout).unwrap()
315 )
316 }
317 Err(e) => {
318 log::warn!("failed to run openssl {}", e)
319 }
320 }
321
322 let issued_cert = ca.issue_cert(&csr_entity.csr_pem).unwrap();
323 log::info!("issued_cert:\n\n{issued_cert}");
324
325 let (issued_cert, issued_cert_path) = ca
326 .issue_and_save_cert(&csr_entity.csr_pem, true, None)
327 .unwrap();
328 log::info!("issued_cert:\n\n{issued_cert}");
329 log::info!("issued_cert issued_cert_path: {issued_cert_path}");
330 let openssl_args = vec![
331 "x509".to_string(),
332 "-text".to_string(),
333 "-noout".to_string(),
334 "-in".to_string(),
335 issued_cert_path.to_string(),
336 ];
337 let openssl_cmd = Command::new("openssl")
338 .stderr(Stdio::piped())
339 .stdout(Stdio::piped())
340 .args(openssl_args)
341 .spawn()
342 .unwrap();
343 log::info!("ran openssl x509 with PID {}", openssl_cmd.id());
344 let res = openssl_cmd.wait_with_output();
345 match res {
346 Ok(output) => {
347 println!(
348 "openssl output {} bytes:\n{}\n",
349 output.stdout.len(),
350 String::from_utf8(output.stdout).unwrap()
351 )
352 }
353 Err(e) => {
354 log::warn!("failed to run openssl {}", e)
355 }
356 }
357
358 fs::remove_file(&ca_key_path).unwrap();
359 fs::remove_file(&ca_cert_path).unwrap();
360
361 fs::remove_file(&csr_key_path).unwrap();
362 fs::remove_file(&csr_cert_path).unwrap();
363 fs::remove_file(&csr_path).unwrap();
364
365 fs::remove_file(&issued_cert_path).unwrap();
366}
367
368pub fn generate(params: Option<CertificateParams>) -> io::Result<Certificate> {
374 let cert_params = if let Some(p) = params {
375 p
376 } else {
377 default_params(None, None, false)?
378 };
379 Certificate::from_params(cert_params).map_err(|e| {
380 Error::new(
381 ErrorKind::Other,
382 format!("failed to generate certificate {}", e),
383 )
384 })
385}
386
387pub fn generate_csr(params: CertificateParams) -> io::Result<(Certificate, String)> {
390 let cert = generate(Some(params))?;
391 let csr = cert.serialize_request_pem().map_err(|e| {
392 Error::new(
393 ErrorKind::Other,
394 format!("failed to serialize_request_pem {}", e),
395 )
396 })?;
397 Ok((cert, csr))
398}
399
400pub fn generate_and_write_pem(
406 params: Option<CertificateParams>,
407 key_path: &str,
408 cert_path: &str,
409) -> io::Result<()> {
410 log::info!("generating key '{key_path}', cert '{cert_path}' (PEM format)");
411 if Path::new(key_path).exists() {
412 return Err(Error::new(
413 ErrorKind::Other,
414 format!("key path '{key_path}' already exists"),
415 ));
416 }
417 if Path::new(cert_path).exists() {
418 return Err(Error::new(
419 ErrorKind::Other,
420 format!("cert path '{cert_path}' already exists"),
421 ));
422 }
423
424 let cert = generate(params)?;
425
426 let key_contents = cert.serialize_private_key_pem();
429 let mut key_file = File::create(key_path)?;
430 key_file.write_all(key_contents.as_bytes())?;
431 log::info!("saved key '{key_path}' ({}-byte)", key_contents.len());
432
433 let cert_contents = cert
434 .serialize_pem()
435 .map_err(|e| Error::new(ErrorKind::Other, format!("failed to serialize_pem {}", e)))?;
436
437 let mut cert_file = File::create(cert_path)?;
438 cert_file.write_all(cert_contents.as_bytes())?;
439 log::info!("saved cert '{cert_path}' ({}-byte)", cert_contents.len());
440
441 Ok(())
442}
443
444pub fn load_pem_to_vec(key_path: &str, cert_path: &str) -> io::Result<(Vec<u8>, Vec<u8>)> {
446 log::info!("loading PEM from key path '{key_path}' and cert '{cert_path}' (as PEM)");
447
448 if !Path::new(key_path).exists() {
449 return Err(Error::new(
450 ErrorKind::Other,
451 format!("key path '{key_path}' does not exist"),
452 ));
453 }
454 if !Path::new(cert_path).exists() {
455 return Err(Error::new(
456 ErrorKind::Other,
457 format!("cert path '{cert_path}' does not exist"),
458 ));
459 }
460
461 Ok((read_vec(key_path)?, read_vec(cert_path)?))
462}
463
464#[cfg(all(target_arch = "aarch64", target_os = "macos"))]
467fn default_sig_algo() -> String {
468 "PKCS_RSA_SHA256".to_string()
469}
470
471#[cfg(not(all(target_arch = "aarch64", target_os = "macos")))]
472fn default_sig_algo() -> String {
473 "PKCS_ECDSA_P256_SHA256".to_string()
474}
475
476pub fn default_params(
477 sig_algo: Option<String>,
478 common_name: Option<String>,
479 is_ca: bool,
480) -> io::Result<CertificateParams> {
481 let mut cert_params = CertificateParams::default();
482
483 let sa = if let Some(sg) = &sig_algo {
484 sg.to_string()
485 } else {
486 default_sig_algo()
487 };
488 log::info!("generating parameter with signature algorithm '{sa}'");
489
490 let key_pair = match sa.as_str() {
491 "PKCS_RSA_SHA256" => {
492 cert_params.alg = &rcgen::PKCS_RSA_SHA256;
493 let mut rng = rand::thread_rng();
494 let private_key = RsaPrivateKey::new(&mut rng, 2048).map_err(|e| {
495 Error::new(ErrorKind::Other, format!("failed to generate key {}", e))
496 })?;
497 let key = private_key.to_pkcs8_pem(LineEnding::CRLF).map_err(|e| {
498 Error::new(ErrorKind::Other, format!("failed to convert key {}", e))
499 })?;
500 KeyPair::from_pem(&key).map_err(|e| {
501 Error::new(
502 ErrorKind::Other,
503 format!("failed to generate PKCS_RSA_SHA256 key pair {}", e),
504 )
505 })?
506 }
507
508 "PKCS_ECDSA_P256_SHA256" => {
510 cert_params.alg = &rcgen::PKCS_ECDSA_P256_SHA256;
511 KeyPair::generate(&rcgen::PKCS_ECDSA_P256_SHA256).map_err(|e| {
512 Error::new(
513 ErrorKind::Other,
514 format!("failed to generate PKCS_ECDSA_P256_SHA256 key pair {}", e),
515 )
516 })?
517 }
518
519 "PKCS_ECDSA_P384_SHA384" => {
527 cert_params.alg = &rcgen::PKCS_ECDSA_P384_SHA384;
528 KeyPair::generate(&rcgen::PKCS_ECDSA_P384_SHA384).map_err(|e| {
529 Error::new(
530 ErrorKind::Other,
531 format!("failed to generate PKCS_ECDSA_P384_SHA384 key pair {}", e),
532 )
533 })?
534 }
535
536 _ => {
537 return Err(Error::new(
538 ErrorKind::InvalidInput,
539 format!("unknown signature algorithm {sa}"),
540 ))
541 }
542 };
543 cert_params.key_pair = Some(key_pair);
544
545 cert_params.not_before = date_time_ymd(2023, 5, 1);
546 cert_params.not_after = date_time_ymd(5000, 1, 1);
547
548 cert_params.distinguished_name = DistinguishedName::new();
549 cert_params
550 .distinguished_name
551 .push(DnType::CountryName, "US");
552 cert_params
553 .distinguished_name
554 .push(DnType::StateOrProvinceName, "NY");
555 cert_params
556 .distinguished_name
557 .push(DnType::OrganizationName, "Test Org");
558 if let Some(cm) = &common_name {
559 cert_params
560 .distinguished_name
561 .push(DnType::CommonName, cm.to_string());
562 } else {
563 cert_params
564 .distinguished_name
565 .push(DnType::CommonName, "test common name");
566 }
567
568 if is_ca {
569 cert_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
570 }
571
572 Ok(cert_params)
573}
574
575#[test]
577fn test_pem() {
578 use std::process::{Command, Stdio};
579
580 let _ = env_logger::builder()
581 .filter_level(log::LevelFilter::Info)
582 .is_test(true)
583 .try_init();
584
585 let tmp_dir = tempfile::tempdir().unwrap();
586
587 let key_path = tmp_dir.path().join(random_manager::secure_string(20));
588 let key_path = key_path.as_os_str().to_str().unwrap();
589 let mut key_path = String::from(key_path);
590 key_path.push_str(".key");
591
592 let cert_path = tmp_dir.path().join(random_manager::secure_string(20));
593 let cert_path = cert_path.as_os_str().to_str().unwrap();
594 let mut cert_path = String::from(cert_path);
595 cert_path.push_str(".cert");
596 let cert_path = random_manager::tmp_path(10, Some(".pem")).unwrap();
597
598 generate_and_write_pem(None, &key_path, &cert_path).unwrap();
599 load_pem_to_vec(&key_path, &cert_path).unwrap();
600
601 let key_contents = fs::read(&key_path).unwrap();
602 let key_contents = String::from_utf8(key_contents.to_vec()).unwrap();
603 log::info!("key {}", key_contents);
604 log::info!("key: {} bytes", key_contents.len());
605
606 let cert_contents = fs::read(&cert_path).unwrap();
608 let cert_contents = String::from_utf8(cert_contents.to_vec()).unwrap();
609 log::info!("cert {}", cert_contents);
610 log::info!("cert: {} bytes", cert_contents.len());
611
612 let openssl_args = vec![
613 "x509".to_string(),
614 "-in".to_string(),
615 cert_path.to_string(),
616 "-text".to_string(),
617 "-noout".to_string(),
618 ];
619 let openssl_cmd = Command::new("openssl")
620 .stderr(Stdio::piped())
621 .stdout(Stdio::piped())
622 .args(openssl_args)
623 .spawn()
624 .unwrap();
625 log::info!("ran openssl with PID {}", openssl_cmd.id());
626 let res = openssl_cmd.wait_with_output();
627 match res {
628 Ok(output) => {
629 log::info!(
630 "openssl output:\n{}\n",
631 String::from_utf8(output.stdout).unwrap()
632 )
633 }
634 Err(e) => {
635 log::warn!("failed to run openssl {}", e)
636 }
637 }
638
639 let (key, cert) = load_pem_key_cert_to_der(&key_path, &cert_path).unwrap();
640 log::info!("loaded key: {:?}", key);
641 log::info!("loaded cert: {:?}", cert);
642
643 let serial = load_pem_cert_serial(&cert_path).unwrap();
644 log::info!("serial: {:?}", serial);
645
646 fs::remove_file(&key_path).unwrap();
647 fs::remove_file(&cert_path).unwrap();
648}
649
650pub fn load_pem_key_cert_to_der(
652 key_path: &str,
653 cert_path: &str,
654) -> io::Result<(rustls::PrivateKey, rustls::Certificate)> {
655 log::info!("loading PEM from key path '{key_path}' and cert '{cert_path}' (to DER)");
656 if !Path::new(key_path).exists() {
657 return Err(Error::new(
658 ErrorKind::NotFound,
659 format!("cert path {} does not exists", key_path),
660 ));
661 }
662 if !Path::new(cert_path).exists() {
663 return Err(Error::new(
664 ErrorKind::NotFound,
665 format!("cert path {} does not exists", cert_path),
666 ));
667 }
668
669 let key_file = File::open(key_path)?;
685 let mut reader = BufReader::new(key_file);
686 let pem_read = read_one(&mut reader)?;
687 let key = {
688 match pem_read.unwrap() {
689 Item::X509Certificate(_) => {
690 log::warn!("key path {} has unexpected certificate", key_path);
691 None
692 }
693 Item::RSAKey(key) => {
694 log::info!("loaded RSA key");
695 Some(key)
696 }
697 Item::PKCS8Key(key) => {
698 log::info!("loaded PKCS8 key");
699 Some(key)
700 }
701 Item::ECKey(key) => {
702 log::info!("loaded EC key");
703 Some(key)
704 }
705 _ => None,
706 }
707 };
708 if key.is_none() {
709 return Err(Error::new(
710 ErrorKind::NotFound,
711 format!("key path '{key_path}' found no key"),
712 ));
713 }
714 let key_der = key.unwrap();
715
716 let cert_file = File::open(cert_path)?;
717 let mut reader = BufReader::new(cert_file);
718 let pem_read = read_one(&mut reader)?;
719 let cert = {
720 match pem_read.unwrap() {
721 Item::X509Certificate(cert) => Some(cert),
722 Item::RSAKey(_) | Item::PKCS8Key(_) | Item::ECKey(_) => {
723 log::warn!("cert path '{cert_path}' has unexpected private key");
724 None
725 }
726 _ => None,
727 }
728 };
729 if cert.is_none() {
730 return Err(Error::new(
731 ErrorKind::NotFound,
732 format!("cert path '{cert_path}' found no cert"),
733 ));
734 }
735 let cert_der = cert.unwrap();
736
737 Ok((rustls::PrivateKey(key_der), rustls::Certificate(cert_der)))
738}
739
740pub fn load_pem_cert_serial(cert_path: &str) -> io::Result<Vec<u8>> {
742 log::info!("loading PEM cert '{cert_path}'");
743 if !Path::new(cert_path).exists() {
744 return Err(Error::new(
745 ErrorKind::NotFound,
746 format!("cert path '{cert_path}' does not exists"),
747 ));
748 }
749
750 let cert_raw = read_vec(cert_path)?;
751
752 let (_, parsed) = x509_parser::pem::parse_x509_pem(&cert_raw)
753 .map_err(|e| Error::new(ErrorKind::Other, format!("failed parse_x509_pem {}", e)))?;
754 let cert = parsed.parse_x509().map_err(|e| {
755 Error::new(
756 ErrorKind::Other,
757 format!("failed parse_x509_certificate {}", e),
758 )
759 })?;
760 let serial = cert.serial.clone();
761
762 Ok(serial.to_bytes_be())
763}
764
765pub fn load_pem_cert_to_der(cert_path: &str) -> io::Result<rustls::Certificate> {
767 log::info!("loading PEM cert '{cert_path}' (to DER)");
768 if !Path::new(cert_path).exists() {
769 return Err(Error::new(
770 ErrorKind::NotFound,
771 format!("cert path '{cert_path}' does not exists"),
772 ));
773 }
774
775 let cert_file = File::open(cert_path)?;
776 let mut reader = BufReader::new(cert_file);
777 let pem_read = read_one(&mut reader)?;
778 let cert = {
779 match pem_read.unwrap() {
780 Item::X509Certificate(cert) => Some(cert),
781 Item::RSAKey(_) | Item::PKCS8Key(_) | Item::ECKey(_) => {
782 log::warn!("cert path '{cert_path}' has unexpected private key");
783 None
784 }
785 _ => None,
786 }
787 };
788 if cert.is_none() {
789 return Err(Error::new(
790 ErrorKind::NotFound,
791 format!("cert path '{cert_path}' found no cert"),
792 ));
793 }
794 let cert_der = cert.unwrap();
795
796 Ok(rustls::Certificate(cert_der))
797}
798
799pub fn generate_der(
802 params: Option<CertificateParams>,
803) -> io::Result<(rustls::PrivateKey, rustls::Certificate)> {
804 log::info!("generating key and cert (DER format)");
805
806 let cert_params = if let Some(p) = params {
807 p
808 } else {
809 default_params(None, None, false)?
810 };
811 let cert = Certificate::from_params(cert_params).map_err(|e| {
812 Error::new(
813 ErrorKind::Other,
814 format!("failed to generate certificate {}", e),
815 )
816 })?;
817 let cert_der = cert
818 .serialize_der()
819 .map_err(|e| Error::new(ErrorKind::Other, format!("failed to serialize_pem {}", e)))?;
820 let key_der = cert.serialize_private_key_der();
823
824 Ok((rustls::PrivateKey(key_der), rustls::Certificate(cert_der)))
825}
826
827pub fn load_der_key_cert(
829 key_path: &str,
830 cert_path: &str,
831) -> io::Result<(rustls::PrivateKey, rustls::Certificate)> {
832 log::info!("loading DER from key path '{key_path}' and cert '{cert_path}'");
833 let (key, cert) = fs::read(key_path).and_then(|x| Ok((x, fs::read(cert_path)?)))?;
834 Ok((rustls::PrivateKey(key), rustls::Certificate(cert)))
835}
836
837#[test]
839fn test_generate_der() {
840 let _ = env_logger::builder()
841 .filter_level(log::LevelFilter::Info)
842 .is_test(true)
843 .try_init();
844
845 let (key, cert) = generate_der(None).unwrap();
846 log::info!("key: {} bytes", key.0.len());
847 log::info!("cert: {} bytes", cert.0.len());
848}
849
850fn read_vec(p: &str) -> io::Result<Vec<u8>> {
852 let mut f = File::open(p)?;
853 let metadata = fs::metadata(p)?;
854 let mut buffer = vec![0; metadata.len() as usize];
855 let _read_bytes = f.read(&mut buffer)?;
856 Ok(buffer)
857}