1use std::path::PathBuf;
17use std::pin::Pin;
18use std::sync::{Arc, RwLock};
19
20use openssl::nid::Nid;
21use openssl::ssl::{Ssl, SslAcceptor, SslMethod, SslOptions, SslVerifyMode, SslVersion};
22use openssl::x509::{X509, X509NameRef, X509VerifyResult};
23use tokio::net::TcpStream;
24use tokio_openssl::SslStream;
25
26pub const DEFAULT_CIPHERS: &str = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:\
28ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-GCM-SHA384";
29
30#[derive(Debug, Clone)]
31pub struct TlsSettings {
32 pub identities: Vec<(PathBuf, PathBuf)>,
34 pub client_ca: Option<PathBuf>,
36 pub ciphers: String,
38}
39
40#[derive(Debug, Clone)]
42pub struct TlsInfo {
43 pub version: String,
44 pub cipher: String,
45 pub client_cert: Option<ClientCert>,
46}
47
48#[derive(Debug, Clone)]
49pub struct ClientCert {
50 pub common_name: Option<String>,
51 pub organization: Option<String>,
52 pub verified: bool,
54 pub error: Option<String>,
56 pub serial_hex: String,
57}
58
59pub struct TlsAcceptor {
60 settings: TlsSettings,
61 current: RwLock<Arc<SslAcceptor>>,
62}
63
64fn build(s: &TlsSettings) -> Result<SslAcceptor, String> {
65 if s.identities.is_empty() {
66 return Err("at least one TLS certificate/key pair is required".into());
67 }
68 let mut b =
69 SslAcceptor::mozilla_intermediate_v5(SslMethod::tls_server()).map_err(|e| e.to_string())?;
70 b.set_min_proto_version(Some(SslVersion::TLS1_2))
71 .map_err(|e| e.to_string())?;
72 b.set_cipher_list(&s.ciphers)
73 .map_err(|e| format!("invalid cipher list: {e}"))?;
74 b.set_options(
75 SslOptions::NO_COMPRESSION
76 | SslOptions::NO_RENEGOTIATION
77 | SslOptions::CIPHER_SERVER_PREFERENCE,
78 );
79 for (cert, key) in &s.identities {
81 b.set_certificate_chain_file(cert)
82 .map_err(|e| format!("{}: {e}", cert.display()))?;
83 b.set_private_key_file(key, openssl::ssl::SslFiletype::PEM)
84 .map_err(|e| format!("{}: {e}", key.display()))?;
85 b.check_private_key()
86 .map_err(|e| format!("{} does not match {}: {e}", key.display(), cert.display()))?;
87 }
88 if let Some(ca) = &s.client_ca {
89 b.set_ca_file(ca)
90 .map_err(|e| format!("{}: {e}", ca.display()))?;
91 let pem = std::fs::read(ca).map_err(|e| format!("{}: {e}", ca.display()))?;
92 let mut names = openssl::stack::Stack::new().map_err(|e| e.to_string())?;
93 for cert in X509::stack_from_pem(&pem).map_err(|e| e.to_string())? {
94 names
95 .push(cert.subject_name().to_owned().map_err(|e| e.to_string())?)
96 .map_err(|e| e.to_string())?;
97 }
98 b.set_client_ca_list(names);
99 b.set_verify_callback(SslVerifyMode::PEER, |_, _| true);
101 }
102 b.set_session_id_context(b"ocpp-csms")
103 .map_err(|e| e.to_string())?;
104 Ok(b.build())
105}
106
107fn name_entry(name: &X509NameRef, nid: Nid) -> Option<String> {
108 name.entries_by_nid(nid)
109 .next()
110 .and_then(|e| e.data().to_string().ok())
111}
112
113impl TlsAcceptor {
114 pub fn new(settings: TlsSettings) -> Result<TlsAcceptor, String> {
115 let acceptor = build(&settings)?;
116 Ok(TlsAcceptor {
117 settings,
118 current: RwLock::new(Arc::new(acceptor)),
119 })
120 }
121
122 pub fn reload(&self) -> Result<(), String> {
124 let acceptor = build(&self.settings)?;
125 *self.current.write().unwrap_or_else(|e| e.into_inner()) = Arc::new(acceptor);
126 Ok(())
127 }
128
129 pub fn verifies_clients(&self) -> bool {
130 self.settings.client_ca.is_some()
131 }
132
133 pub async fn accept(&self, tcp: TcpStream) -> Result<(SslStream<TcpStream>, TlsInfo), String> {
134 let acceptor = self
135 .current
136 .read()
137 .unwrap_or_else(|e| e.into_inner())
138 .clone();
139 let ssl = Ssl::new(acceptor.context()).map_err(|e| e.to_string())?;
140 let mut stream = SslStream::new(ssl, tcp).map_err(|e| e.to_string())?;
141 Pin::new(&mut stream)
142 .accept()
143 .await
144 .map_err(|e| e.to_string())?;
145 let ssl = stream.ssl();
146 let client_cert = ssl.peer_certificate().map(|cert| {
147 let result = ssl.verify_result();
148 let verified = self.verifies_clients() && result == X509VerifyResult::OK;
149 ClientCert {
150 common_name: name_entry(cert.subject_name(), Nid::COMMONNAME),
151 organization: name_entry(cert.subject_name(), Nid::ORGANIZATIONNAME),
152 verified,
153 error: (!verified).then(|| {
154 if self.verifies_clients() {
155 result.error_string().to_owned()
156 } else {
157 "client certificates are not configured".into()
158 }
159 }),
160 serial_hex: cert
161 .serial_number()
162 .to_bn()
163 .and_then(|b| b.to_hex_str())
164 .map(|s| s.to_string())
165 .unwrap_or_default(),
166 }
167 });
168 let info = TlsInfo {
169 version: ssl.version_str().to_owned(),
170 cipher: ssl
171 .current_cipher()
172 .map(|c| c.name().to_owned())
173 .unwrap_or_default(),
174 client_cert,
175 };
176 Ok((stream, info))
177 }
178}