1use std::net::IpAddr;
2
3use rcgen::{
4 BasicConstraints, Certificate, CertificateParams, DistinguishedName, DnType, DnValue, IsCa,
5 Issuer, KeyIdMethod, KeyPair, KeyUsagePurpose, SanType,
6};
7use time::OffsetDateTime;
8
9#[derive(Debug, thiserror::Error)]
10pub enum Error {
11 #[error(transparent)]
12 Rcgen(#[from] rcgen::Error),
13 #[error(transparent)]
14 Io(#[from] std::io::Error),
15}
16
17pub fn generate_ca() -> Result<(Certificate, KeyPair), Error> {
18 let key_pair = KeyPair::generate()?;
19 let mut params = CertificateParams::default();
20
21 params.key_identifier_method = KeyIdMethod::Sha384;
22
23 let mut dn = DistinguishedName::new();
24 dn.push(
25 DnType::CommonName,
26 DnValue::PrintableString("Corrosion Root CA".try_into()?),
27 );
28 params.distinguished_name = dn;
29 params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
30
31 params.not_before = OffsetDateTime::now_utc();
32 params.not_after = OffsetDateTime::now_utc() + time::Duration::days(365 * 5);
33
34 params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign];
35 let cert = params.self_signed(&key_pair)?;
36
37 Ok((cert, key_pair))
38}
39
40pub fn generate_server_cert(
41 ca_cert_pem: &str,
42 ca_key_pem: &str,
43 ip: IpAddr,
44) -> Result<(Certificate, String, KeyPair), Error> {
45 let ca_cert = ca_cert(ca_cert_pem, ca_key_pem)?;
46 let key_pair = KeyPair::generate()?;
47
48 let mut params = CertificateParams::default();
49
50 params.key_identifier_method = KeyIdMethod::Sha384;
51
52 let mut dn = DistinguishedName::new();
53 dn.push(
54 DnType::CommonName,
55 DnValue::PrintableString("r.u.local".try_into()?),
56 );
57 params.distinguished_name = dn;
58
59 params.subject_alt_names = vec![SanType::IpAddress(ip)];
60
61 params.not_before = OffsetDateTime::now_utc();
62 params.not_after = OffsetDateTime::now_utc() + time::Duration::days(365);
63
64 let cert = params.signed_by(&key_pair, &ca_cert)?;
65 let cert_signed = cert.pem();
66
67 Ok((cert, cert_signed, key_pair))
68}
69
70fn ca_cert<'a>(
71 ca_cert_pem: &'a str,
72 ca_key_pem: &'a str,
73) -> Result<Issuer<'a, KeyPair>, rcgen::Error> {
74 let key_pair = KeyPair::from_pem(ca_key_pem)?;
75 Issuer::from_ca_cert_pem(ca_cert_pem, key_pair)
76}
77
78pub fn generate_client_cert(
79 ca_cert_pem: &str,
80 ca_key_pem: &str,
81) -> Result<(Certificate, String, KeyPair), Error> {
82 let ca_cert = ca_cert(ca_cert_pem, ca_key_pem)?;
83 let key_pair = KeyPair::generate()?;
84
85 let mut params = CertificateParams::default();
86
87 params.key_identifier_method = KeyIdMethod::Sha384;
88
89 let dn = DistinguishedName::new();
90 params.distinguished_name = dn;
91
92 params.not_before = OffsetDateTime::now_utc();
93 params.not_after = OffsetDateTime::now_utc() + time::Duration::days(365);
94
95 let cert = params.signed_by(&key_pair, &ca_cert)?;
96 let cert_signed = cert.pem();
97
98 Ok((cert, cert_signed, key_pair))
99}