1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
use std::{
fs::{self, File},
io::BufReader,
path::Path,
};
use bevy::prelude::{trace, warn};
use crate::shared::{CertificateFingerprint, QuinnetError};
/// Represents the origin of a certificate.
#[derive(Debug, Clone)]
pub enum CertOrigin {
/// Indicates that the certificate was generated. The `server_hostname` field contains the hostname used when generating the certificate.
Generated { server_hostname: String },
/// Indicates that the certificate was loaded from a file.
Loaded,
}
/// How the server should retrieve its certificate.
#[derive(Debug, Clone)]
pub enum CertificateRetrievalMode {
/// The server will always generate a new self-signed certificate when starting up, using `server_hostname` as the subject of the certificate.
GenerateSelfSigned { server_hostname: String },
/// Try to load cert & key from files `cert_file``and `key_file`.
LoadFromFile { cert_file: String, key_file: String },
/// Try to load cert & key from files `cert_file``and `key_file`.
/// If the files do not exist, generate a self-signed certificate using `server_hostname` as the subject of the certificate. Optionally save it to disk if `save_on_disk` is enabled.
LoadFromFileOrGenerateSelfSigned {
cert_file: String,
key_file: String,
save_on_disk: bool,
server_hostname: String,
},
}
/// Represents a server certificate.
pub struct ServerCertificate {
/// A vector of [rustls::Certificate] that contains the server's certificate chain.
pub cert_chain: Vec<rustls::Certificate>,
/// The server's private key, represented by a [rustls::PrivateKey] struct.
pub priv_key: rustls::PrivateKey,
/// The fingerprint of the server's main certificate, represented by a [CertificateFingerprint] struct.
pub fingerprint: CertificateFingerprint,
}
fn read_certs_from_files(
cert_file: &String,
key_file: &String,
) -> Result<ServerCertificate, QuinnetError> {
let mut cert_chain_reader = BufReader::new(File::open(cert_file)?);
let cert_chain: Vec<rustls::Certificate> = rustls_pemfile::certs(&mut cert_chain_reader)?
.into_iter()
.map(rustls::Certificate)
.collect();
let mut key_reader = BufReader::new(File::open(key_file)?);
let mut keys = rustls_pemfile::pkcs8_private_keys(&mut key_reader)?;
assert_eq!(keys.len(), 1);
let priv_key = rustls::PrivateKey(keys.remove(0));
assert!(cert_chain.len() >= 1);
let fingerprint = CertificateFingerprint::from(&cert_chain[0]);
Ok(ServerCertificate {
cert_chain,
priv_key,
fingerprint,
})
}
fn write_certs_to_files(
cert: &rcgen::Certificate,
cert_file: &String,
key_file: &String,
) -> Result<(), QuinnetError> {
let pem_cert = cert.serialize_pem()?;
let pem_key = cert.serialize_private_key_pem();
for file in vec![cert_file, key_file] {
let path = std::path::Path::new(file);
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
}
fs::write(cert_file, pem_cert)?;
fs::write(key_file, pem_key)?;
Ok(())
}
fn generate_self_signed_certificate(
server_host: &String,
) -> Result<(ServerCertificate, rcgen::Certificate), QuinnetError> {
let cert = rcgen::generate_simple_self_signed(vec![server_host.into()])?;
let cert_der = cert.serialize_der()?;
let priv_key = rustls::PrivateKey(cert.serialize_private_key_der());
let rustls_cert = rustls::Certificate(cert_der.clone());
let fingerprint = CertificateFingerprint::from(&rustls_cert);
let cert_chain = vec![rustls_cert];
Ok((
ServerCertificate {
cert_chain,
priv_key,
fingerprint,
},
cert,
))
}
pub(crate) fn retrieve_certificate(
cert_mode: CertificateRetrievalMode,
) -> Result<ServerCertificate, QuinnetError> {
match cert_mode {
CertificateRetrievalMode::GenerateSelfSigned { server_hostname } => {
let (server_cert, _rcgen_cert) = generate_self_signed_certificate(&server_hostname)?;
trace!("Generatied a new self-signed certificate");
Ok(server_cert)
}
CertificateRetrievalMode::LoadFromFile {
cert_file,
key_file,
} => {
let server_cert = read_certs_from_files(&cert_file, &key_file)?;
trace!("Successfuly loaded cert and key from files");
Ok(server_cert)
}
CertificateRetrievalMode::LoadFromFileOrGenerateSelfSigned {
save_on_disk,
cert_file,
key_file,
server_hostname,
} => {
if Path::new(&cert_file).exists() && Path::new(&key_file).exists() {
let server_cert = read_certs_from_files(&cert_file, &key_file)?;
trace!("Successfuly loaded cert and key from files");
Ok(server_cert)
} else {
warn!("{} and/or {} do not exist, could not load existing certificate. Generating a new self-signed certificate.", cert_file, key_file);
let (server_cert, rcgen_cert) = generate_self_signed_certificate(&server_hostname)?;
if save_on_disk {
write_certs_to_files(&rcgen_cert, &cert_file, &key_file)?;
trace!("Successfuly saved cert and key to files");
}
Ok(server_cert)
}
}
}
}
|