third_wheel/
certificates.rs1use log::debug;
2use std::io;
3use std::{fs::File, path::Path};
4
5use openssl::asn1::Asn1Time;
6use openssl::bn::{BigNum, MsbOption};
7use openssl::hash::MessageDigest;
8use openssl::pkcs12::Pkcs12;
9use openssl::pkey::{PKey, Private};
10use openssl::rsa::Rsa;
11use openssl::stack::Stack;
12use openssl::x509::extension::SubjectAlternativeName;
13use openssl::x509::{GeneralNameRef, X509Name, X509NameBuilder, X509NameRef, X509};
14
15use crate::error::Error;
16
17pub struct CertificateAuthority {
21 pub cert: X509,
23 pub key: PKey<Private>,
25}
26
27impl CertificateAuthority {
28 pub fn load_from_pem_files<P: AsRef<Path>, Q: AsRef<Path>>(
33 cert_file: P,
34 key_file: Q,
35 ) -> Result<Self, Error> {
36 let cert = X509::from_pem(&get_bytes_from_file(cert_file)?)?;
37
38 let key = get_bytes_from_file(key_file)?;
39 let key = PKey::from_rsa(Rsa::private_key_from_pem(&key)?)?;
40
41 Ok(Self { cert, key })
42 }
43
44 pub fn load_from_pem_files_with_passphrase_on_key<P: AsRef<Path>, Q: AsRef<Path>>(
47 cert_file: P,
48 key_file: Q,
49 passphrase: &str,
50 ) -> Result<Self, Error> {
51 let cert = X509::from_pem(&get_bytes_from_file(cert_file)?)?;
52
53 let key = get_bytes_from_file(key_file)?;
54 let key = PKey::from_rsa(Rsa::private_key_from_pem_passphrase(
55 &key,
56 passphrase.as_bytes(),
57 )?)?;
58
59 Ok(Self { cert, key })
60 }
61}
62
63fn get_bytes_from_file<P: AsRef<Path>>(path: P) -> Result<Vec<u8>, Error> {
64 let mut file = File::open(path)?;
65 let mut bytes: Vec<u8> = vec![];
66 io::copy(&mut file, &mut bytes)?;
67 Ok(bytes)
68}
69
70pub(crate) fn native_identity(
71 certificate: &X509,
72 key: &PKey<Private>,
73) -> Result<native_tls::Identity, Error> {
74 let pkcs = Pkcs12::builder()
75 .build(&"third-wheel", &"", key, certificate)?
76 .to_der()?;
77 let identity = native_tls::Identity::from_pkcs12(&pkcs, &"third-wheel")?;
78 Ok(identity)
79}
80
81pub fn create_signed_certificate_for_domain(
87 domain: &str,
88 ca: &CertificateAuthority,
89) -> Result<X509, Error> {
90 let mut cert_builder = X509::builder()?;
91
92 let mut host_name = X509Name::builder()?;
93 host_name.append_entry_by_text("CN", domain)?;
94 let host_name = host_name.build();
95
96 cert_builder.set_subject_name(&host_name)?;
97 cert_builder.set_version(2)?;
98 cert_builder.set_not_before((Asn1Time::days_from_now(0)?).as_ref())?;
99 cert_builder.set_not_after((Asn1Time::days_from_now(365)?).as_ref())?;
100
101 let serial_number = {
102 let mut serial_number = BigNum::new()?;
103 serial_number.rand(159, MsbOption::MAYBE_ZERO, false)?;
104 serial_number.to_asn1_integer()?
105 };
106 cert_builder.set_serial_number(&serial_number)?;
107
108 let subject_alternative_name = SubjectAlternativeName::new()
109 .dns(domain)
110 .build(&cert_builder.x509v3_context(Some(&ca.cert), None))?;
111 cert_builder.append_extension(subject_alternative_name)?;
112
113 cert_builder.set_issuer_name(&ca.cert.issuer_name())?;
114 cert_builder.set_pubkey(&ca.key)?;
115 cert_builder.sign(&ca.key, MessageDigest::sha256())?;
116
117 Ok(cert_builder.build())
118}
119
120fn copy_name(in_name: &X509NameRef) -> Result<X509Name, Error> {
121 let mut copy: X509NameBuilder = X509Name::builder()?;
122 for entry in in_name.entries() {
123 copy.append_entry_by_nid(
124 entry.object().nid(),
125 entry
126 .data()
127 .as_utf8()
128 .expect("Expected string as entry in name")
129 .as_ref(),
130 )
131 .expect("Failed to add entry by nid");
132 }
133
134 Ok(copy.build())
135}
136
137fn copy_alt_names(in_cert: &X509) -> Option<SubjectAlternativeName> {
138 match in_cert.subject_alt_names() {
139 Some(in_alt_names) => {
140 let mut subject_alternative_name = SubjectAlternativeName::new();
141 for gn in in_alt_names {
142 if let Some(email) = gn.email() {
143 subject_alternative_name.email(email);
144 } else if let Some(dns) = gn.dnsname() {
145 subject_alternative_name.dns(dns);
146 } else if let Some(uri) = gn.uri() {
147 subject_alternative_name.uri(uri);
148 } else if let Some(ipaddress) = gn.ipaddress() {
149 subject_alternative_name.ip(&String::from_utf8(ipaddress.to_vec())
153 .expect("ip address on certificate is not formatted as ascii"));
154 }
155 }
156 Some(subject_alternative_name)
157 }
158 None => None,
159 }
160}
161
162pub(crate) fn spoof_certificate(
163 certificate: &X509,
164 ca: &CertificateAuthority,
165) -> Result<X509, Error> {
166 let mut cert_builder = X509::builder()?;
167
168 let name: &X509NameRef = certificate.subject_name();
169 let host_name = copy_name(name)?;
170 cert_builder.set_subject_name(&host_name)?;
171 cert_builder.set_not_before(certificate.not_before())?;
172 cert_builder.set_not_after(certificate.not_after())?;
173
174 cert_builder.set_serial_number(certificate.serial_number())?;
175
176 cert_builder.set_version(2)?;
177
178 if let Some(subject_alternative_name) = copy_alt_names(certificate) {
179 let subject_alternative_name =
180 subject_alternative_name.build(&cert_builder.x509v3_context(Some(&ca.cert), None))?;
181 cert_builder.append_extension(subject_alternative_name)?;
182 }
183
184 cert_builder.set_issuer_name(&ca.cert.issuer_name())?;
185 cert_builder.set_pubkey(&ca.key)?;
186 cert_builder.sign(&ca.key, MessageDigest::sha256())?;
187
188 Ok(cert_builder.build())
189}
190
191#[allow(dead_code)]
192fn print_certificate(certificate: &X509) {
193 debug!("New certificate");
194
195 debug!("subject_name:");
196 for entry in certificate.subject_name().entries() {
197 debug!("{}: {}", entry.object(), entry.data().as_utf8().unwrap());
198 }
199 debug!("issuer_name:");
200 for entry in certificate.issuer_name().entries() {
201 debug!("{}: {}", entry.object(), entry.data().as_utf8().unwrap());
202 }
203
204 debug!("subject_alt_names");
205 for general_name in certificate
206 .subject_alt_names()
207 .unwrap_or_else(|| Stack::new().unwrap())
208 .iter()
209 {
210 print_general_name(general_name);
211 }
212
213 debug!("issuer_alt_names");
214 for general_name in certificate
215 .issuer_alt_names()
216 .unwrap_or_else(|| Stack::new().unwrap())
217 .iter()
218 {
219 print_general_name(general_name);
220 }
221
222 debug!("public_key: {:?}", certificate.public_key());
223
224 debug!("not_after: {}", certificate.not_after());
225 debug!("not_before: {}", certificate.not_before());
226
227 debug!("Signature: ");
228 debug!("{:x?}", certificate.signature().as_slice());
229
230 debug!(
231 "Signature algorithm: {}",
232 certificate.signature_algorithm().object()
233 );
234
235 debug!("ocsp_responders:");
236 let responders = certificate.ocsp_responders();
237 match responders {
238 Ok(stack) => {
239 for responder in stack.iter() {
240 debug!("{:?}", responder);
241 }
242 }
243 Err(err) => debug!("Responders threw error: {}", err),
244 }
245
246 let serial_number = certificate.serial_number().to_bn();
247 match serial_number {
248 Ok(sn) => debug!("{}", sn),
249 Err(err) => debug!("Responders threw error: {}", err),
250 }
251}
252
253fn print_general_name(general_name: &GeneralNameRef) {
254 if let Some(email) = general_name.email() {
255 debug!("email: {}", email);
256 }
257 if let Some(dnsname) = general_name.dnsname() {
258 debug!("dnsname: {}", dnsname);
259 }
260 if let Some(uri) = general_name.uri() {
261 debug!("uri: {}", uri);
262 }
263 if let Some(ipaddress) = general_name.ipaddress() {
264 debug!("ipaddress: {:?}", ipaddress);
265 }
266}