1use crate::asn1;
5use crate::crypto::rng;
6use crate::crypto::sha2::Sha256;
7use crate::keys::{self, EcCurve, PrivateKey};
8use crate::pem;
9use crate::x509;
10use std::net::IpAddr;
11
12#[derive(Clone, Debug)]
14pub struct SelfSigned {
15 pub cert_der: Vec<u8>,
16 pub key_der: Vec<u8>,
18 pub cert_pem: String,
19 pub key_pem: String,
20 pub key: PrivateKey,
21}
22
23pub fn self_signed(name: &str) -> SelfSigned {
26 let mut names = vec![name.to_string()];
27 if name.eq_ignore_ascii_case("localhost") {
28 names.push("127.0.0.1".into());
29 names.push("::1".into());
30 }
31 let refs: Vec<&str> = names.iter().map(|s| s.as_str()).collect();
32 self_signed_with_sans(&refs, 365)
33}
34
35pub fn self_signed_with_sans(names: &[&str], days_valid: i64) -> SelfSigned {
38 assert!(!names.is_empty(), "at least one name required");
39 let curve = EcCurve::P256;
40 let d = curve.generate_private();
41 let public = curve.public_key(&d).expect("valid scalar");
42 let key = PrivateKey::Ec { curve, d: d.clone(), public: public.clone() };
43
44 let now = x509::now_unix();
45 let mut serial = rng::bytes(16);
46 serial[0] &= 0x7f;
47 serial[0] |= 0x01;
48 let sig_alg = asn1::seq(&[asn1::oid("1.2.840.10045.4.3.2")]);
49 let name = asn1::seq(&[asn1::set(&[asn1::seq(&[asn1::oid("2.5.4.3"), asn1::tlv(asn1::TAG_UTF8_STRING, names[0].as_bytes())])])]);
50 let validity = asn1::seq(&[asn1::time(now - 86400), asn1::time(now + days_valid * 86400)]);
51 let spki = asn1::seq(&[asn1::seq(&[asn1::oid(keys::OID_EC_PUBLIC_KEY), asn1::oid(keys::OID_P256)]), asn1::bit_string(&public)]);
52
53 let mut general_names = Vec::new();
54 for n in names {
55 match n.parse::<IpAddr>() {
56 Ok(IpAddr::V4(v4)) => general_names.push(asn1::tlv(0x87, &v4.octets())),
57 Ok(IpAddr::V6(v6)) => general_names.push(asn1::tlv(0x87, &v6.octets())),
58 Err(_) => general_names.push(asn1::tlv(0x82, n.as_bytes())),
59 }
60 }
61 let ext = |oid: &str, critical: bool, value: Vec<u8>| -> Vec<u8> {
62 let mut parts = vec![asn1::oid(oid)];
63 if critical {
64 parts.push(asn1::tlv(asn1::TAG_BOOLEAN, &[0xff]));
65 }
66 parts.push(asn1::octet_string(&value));
67 asn1::seq(&parts)
68 };
69 let ski = Sha256::digest(&public)[..20].to_vec();
70 let extensions = asn1::seq(&[
71 ext("2.5.29.17", false, asn1::seq(&general_names)),
72 ext("2.5.29.19", true, asn1::seq(&[asn1::tlv(asn1::TAG_BOOLEAN, &[0xff])])),
74 ext("2.5.29.15", true, asn1::tlv(asn1::TAG_BIT_STRING, &[0x02, 0x84])),
76 ext("2.5.29.37", false, asn1::seq(&[asn1::oid(x509::OID_EKU_SERVER_AUTH), asn1::oid(x509::OID_EKU_CLIENT_AUTH)])),
77 ext("2.5.29.14", false, asn1::octet_string(&ski)),
78 ]);
79 let tbs = asn1::seq(&[
80 asn1::explicit(0, &asn1::uint(&[2])),
81 asn1::uint(&serial),
82 sig_alg.clone(),
83 name.clone(),
84 validity,
85 name,
86 spki,
87 asn1::explicit(3, &extensions),
88 ]);
89 let (r, s) = curve.sign(&d, &Sha256::digest(&tbs), crate::crypto::sha2::HashAlg::Sha256).expect("sign");
90 let sig = keys::ecdsa_sig_to_der(&r, &s);
91 let cert_der = asn1::seq(&[tbs, sig_alg, asn1::bit_string(&sig)]);
92 let key_der = key.to_pkcs8_der().expect("EC key");
93 SelfSigned {
94 cert_pem: pem::encode_pem("CERTIFICATE", &cert_der),
95 key_pem: pem::encode_pem("PRIVATE KEY", &key_der),
96 cert_der,
97 key_der,
98 key,
99 }
100}
101
102#[derive(Clone, Debug)]
104pub struct CertParams {
105 pub common_name: String,
107 pub sans: Vec<String>,
109 pub is_ca: bool,
110 pub ext_key_usage: Vec<String>,
112 pub days_valid: i64,
113}
114
115impl CertParams {
116 pub fn server(names: &[&str]) -> CertParams {
118 CertParams {
119 common_name: names[0].to_string(),
120 sans: names.iter().map(|s| s.to_string()).collect(),
121 is_ca: false,
122 ext_key_usage: vec![x509::OID_EKU_SERVER_AUTH.to_string()],
123 days_valid: 365,
124 }
125 }
126
127 pub fn client(cn: &str) -> CertParams {
129 CertParams { common_name: cn.to_string(), sans: Vec::new(), is_ca: false, ext_key_usage: vec![x509::OID_EKU_CLIENT_AUTH.to_string()], days_valid: 365 }
130 }
131
132 pub fn ca(cn: &str) -> CertParams {
134 CertParams { common_name: cn.to_string(), sans: Vec::new(), is_ca: true, ext_key_usage: Vec::new(), days_valid: 3650 }
135 }
136}
137
138pub(crate) fn sig_alg_for(key: &PrivateKey) -> Vec<u8> {
139 match key {
140 #[cfg(feature = "p384")]
141 PrivateKey::Ec { curve: EcCurve::P384, .. } => asn1::seq(&[asn1::oid("1.2.840.10045.4.3.3")]),
142 PrivateKey::Ec { .. } => asn1::seq(&[asn1::oid("1.2.840.10045.4.3.2")]),
143 #[cfg(feature = "ed25519")]
144 PrivateKey::Ed25519 { .. } => asn1::seq(&[asn1::oid(keys::OID_ED25519)]),
145 #[cfg(feature = "rsa")]
146 PrivateKey::Rsa(_) => asn1::seq(&[asn1::oid("1.2.840.113549.1.1.11"), asn1::tlv(asn1::TAG_NULL, &[])]),
147 }
148}
149
150pub(crate) fn sign_with(key: &PrivateKey, tbs: &[u8]) -> Vec<u8> {
151 #[cfg(feature = "rsa")]
152 use crate::crypto::sha2::HashAlg;
153 match key {
154 PrivateKey::Ec { curve, d, .. } => {
155 let h = curve.hash();
156 let (r, s) = curve.sign(d, &h.hash(tbs), h).expect("sign");
157 keys::ecdsa_sig_to_der(&r, &s)
158 }
159 #[cfg(feature = "ed25519")]
160 PrivateKey::Ed25519 { seed, public } => crate::crypto::ed25519::sign_with_public(seed, public, tbs).to_vec(),
161 #[cfg(feature = "rsa")]
162 PrivateKey::Rsa(k) => k.sign_pkcs1(HashAlg::Sha256, &HashAlg::Sha256.hash(tbs)).expect("sign"),
163 }
164}
165
166fn name_der(cn: &str) -> Vec<u8> {
167 asn1::seq(&[asn1::set(&[asn1::seq(&[asn1::oid("2.5.4.3"), asn1::tlv(asn1::TAG_UTF8_STRING, cn.as_bytes())])])])
168}
169
170pub fn issue(params: &CertParams, key: PrivateKey, issuer: Option<&SelfSigned>) -> SelfSigned {
172 let now = x509::now_unix();
173 let mut serial = rng::bytes(16);
174 serial[0] &= 0x7f;
175 serial[0] |= 0x01;
176 let (issuer_name, signer) = match issuer {
177 Some(i) => (x509::Certificate::from_der(&i.cert_der).expect("issuer certificate").subject_raw, &i.key),
178 None => (name_der(¶ms.common_name), &key),
179 };
180 let sig_alg = sig_alg_for(signer);
181 let spki = key.public_key().to_spki();
182 let ext = |oid: &str, critical: bool, value: Vec<u8>| -> Vec<u8> {
183 let mut parts = vec![asn1::oid(oid)];
184 if critical {
185 parts.push(asn1::tlv(asn1::TAG_BOOLEAN, &[0xff]));
186 }
187 parts.push(asn1::octet_string(&value));
188 asn1::seq(&parts)
189 };
190 let mut exts = Vec::new();
191 if !params.sans.is_empty() {
192 let mut general_names = Vec::new();
193 for n in ¶ms.sans {
194 match n.parse::<IpAddr>() {
195 Ok(IpAddr::V4(v4)) => general_names.push(asn1::tlv(0x87, &v4.octets())),
196 Ok(IpAddr::V6(v6)) => general_names.push(asn1::tlv(0x87, &v6.octets())),
197 Err(_) => general_names.push(asn1::tlv(0x82, n.as_bytes())),
198 }
199 }
200 exts.push(ext("2.5.29.17", false, asn1::seq(&general_names)));
201 }
202 if params.is_ca {
203 exts.push(ext("2.5.29.19", true, asn1::seq(&[asn1::tlv(asn1::TAG_BOOLEAN, &[0xff])])));
204 exts.push(ext("2.5.29.15", true, asn1::tlv(asn1::TAG_BIT_STRING, &[0x01, 0x86])));
206 } else {
207 exts.push(ext("2.5.29.19", true, asn1::seq(&[])));
208 exts.push(ext("2.5.29.15", true, asn1::tlv(asn1::TAG_BIT_STRING, &[0x07, 0x80])));
209 }
210 if !params.ext_key_usage.is_empty() {
211 exts.push(ext("2.5.29.37", false, asn1::seq(¶ms.ext_key_usage.iter().map(|o| asn1::oid(o)).collect::<Vec<_>>())));
212 }
213 let tbs = asn1::seq(&[
214 asn1::explicit(0, &asn1::uint(&[2])),
215 asn1::uint(&serial),
216 sig_alg.clone(),
217 issuer_name,
218 asn1::seq(&[asn1::time(now - 86400), asn1::time(now + params.days_valid * 86400)]),
219 name_der(¶ms.common_name),
220 spki,
221 asn1::explicit(3, &asn1::seq(&exts)),
222 ]);
223 let sig = sign_with(signer, &tbs);
224 let cert_der = asn1::seq(&[tbs, sig_alg, asn1::bit_string(&sig)]);
225 let key_der = key.to_pkcs8();
226 SelfSigned { cert_pem: pem::encode_pem("CERTIFICATE", &cert_der), key_pem: pem::encode_pem("PRIVATE KEY", &key_der), cert_der, key_der, key }
227}