use std::env;
use std::ffi::{OsStr, OsString};
use std::path::{Path, PathBuf};
pub unsafe fn try_init_openssl_env_vars() -> bool {
let ProbeResult {
cert_file,
cert_dir,
} = probe();
if let Some(path) = &cert_file {
unsafe {
put(ENV_CERT_FILE, path.as_os_str());
}
}
if !cert_dir.is_empty() {
let mut joined = OsString::new();
for (i, path) in cert_dir.iter().enumerate() {
if i != 0 {
joined.push(":");
}
joined.push(path.as_os_str());
}
unsafe {
put(ENV_CERT_DIR, &joined);
}
}
unsafe fn put(var: &str, path: &OsStr) {
if env::var_os(var).as_deref() != Some(path) {
unsafe {
env::set_var(var, path);
}
}
}
cert_file.is_some() || !cert_dir.is_empty()
}
pub fn probe() -> ProbeResult {
let mut result = ProbeResult::from_env();
if result.cert_file.is_none() {
result.cert_file =
CERTIFICATE_FILE_NAMES
.iter()
.find_map(|p| match Path::new(p).exists() {
true => Some(PathBuf::from(p)),
false => None,
});
}
for certs_dir in candidate_cert_dirs() {
let cert_dir = PathBuf::from(certs_dir);
if cert_dir.exists() {
result.cert_dir.push(cert_dir);
}
}
result
}
pub fn candidate_cert_dirs() -> impl Iterator<Item = &'static Path> {
CERTIFICATE_DIRS
.iter()
.map(Path::new)
.filter(|p| p.exists())
}
pub fn has_ssl_cert_env_vars() -> bool {
let probe = ProbeResult::from_env();
probe.cert_file.is_some() || !probe.cert_dir.is_empty()
}
pub struct ProbeResult {
pub cert_file: Option<PathBuf>,
pub cert_dir: Vec<PathBuf>,
}
impl ProbeResult {
fn from_env() -> ProbeResult {
let var = |name| env::var_os(name).map(PathBuf::from).filter(|p| p.exists());
ProbeResult {
cert_file: var(ENV_CERT_FILE),
cert_dir: match var(ENV_CERT_DIR) {
Some(p) => vec![p],
None => vec![],
},
}
}
}
#[cfg(target_os = "linux")]
const CERTIFICATE_DIRS: &[&str] = &[
"/etc/ssl/certs", "/etc/pki/tls/certs", "/etc/security/certificates", ];
#[cfg(target_os = "freebsd")]
const CERTIFICATE_DIRS: &[&str] = &[
"/etc/ssl/certs", "/usr/local/share/certs", ];
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
const CERTIFICATE_DIRS: &[&str] = &["/etc/certs/CA"];
#[cfg(target_os = "netbsd")]
const CERTIFICATE_DIRS: &[&str] = &["/etc/openssl/certs"];
#[cfg(target_os = "aix")]
const CERTIFICATE_DIRS: &[&str] = &["/var/ssl/certs"];
#[cfg(not(any(
target_os = "linux",
target_os = "freebsd",
target_os = "illumos",
target_os = "solaris",
target_os = "netbsd",
target_os = "aix"
)))]
const CERTIFICATE_DIRS: &[&str] = &["/etc/ssl/certs"];
#[cfg(target_os = "linux")]
const CERTIFICATE_FILE_NAMES: &[&str] = &[
"/etc/ssl/certs/ca-certificates.crt", "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", "/etc/pki/tls/certs/ca-bundle.crt", "/etc/ssl/ca-bundle.pem", "/etc/pki/tls/cacert.pem", "/etc/ssl/cert.pem", "/opt/etc/ssl/certs/ca-certificates.crt", "/etc/ssl/certs/cacert.pem", ];
#[cfg(target_os = "freebsd")]
const CERTIFICATE_FILE_NAMES: &[&str] = &["/usr/local/etc/ssl/cert.pem"];
#[cfg(target_os = "dragonfly")]
const CERTIFICATE_FILE_NAMES: &[&str] = &["/usr/local/share/certs/ca-root-nss.crt"];
#[cfg(target_os = "netbsd")]
const CERTIFICATE_FILE_NAMES: &[&str] = &["/etc/openssl/certs/ca-certificates.crt"];
#[cfg(target_os = "openbsd")]
const CERTIFICATE_FILE_NAMES: &[&str] = &["/etc/ssl/cert.pem"];
#[cfg(target_os = "solaris")] const CERTIFICATE_FILE_NAMES: &[&str] = &["/etc/certs/ca-certificates.crt"];
#[cfg(target_os = "illumos")]
const CERTIFICATE_FILE_NAMES: &[&str] = &[
"/etc/ssl/cacert.pem", "/etc/certs/ca-certificates.crt", ];
#[cfg(target_os = "android")] const CERTIFICATE_FILE_NAMES: &[&str] = &["/data/data/com.termux/files/usr/etc/tls/cert.pem"];
#[cfg(target_os = "haiku")] const CERTIFICATE_FILE_NAMES: &[&str] = &["/boot/system/data/ssl/CARootCertificates.pem"];
#[cfg(not(any(
target_os = "linux",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd",
target_os = "solaris",
target_os = "illumos",
target_os = "android",
target_os = "haiku",
)))]
const CERTIFICATE_FILE_NAMES: &[&str] = &["/etc/ssl/certs/ca-certificates.crt"];
pub const ENV_CERT_FILE: &str = "SSL_CERT_FILE";
pub const ENV_CERT_DIR: &str = "SSL_CERT_DIR";