diff --git a/vm/src/stdlib/ssl.rs b/vm/src/stdlib/ssl.rs index 1d85b6faa0..360a996178 100644 --- a/vm/src/stdlib/ssl.rs +++ b/vm/src/stdlib/ssl.rs @@ -283,6 +283,9 @@ impl SlotConstructor for PySslContext { let mut builder = SslContextBuilder::new(method).map_err(|e| convert_openssl_error(vm, e))?; + #[cfg(target_os = "android")] + android::load_client_ca_list(vm, &mut builder)?; + let check_hostname = proto == SslVersion::TlsClient; builder.set_verify(if check_hostname { SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT @@ -1252,3 +1255,66 @@ impl Write for SocketStream { socket.flush() } } + +#[cfg(target_os = "android")] +mod android { + use crate::{ + exceptions::PyBaseExceptionRef, stdlib::ssl::convert_openssl_error, VirtualMachine, + }; + use openssl::{ + ssl::SslContextBuilder, + x509::{store::X509StoreBuilder, X509}, + }; + use std::{ + fs::{read_dir, File}, + io::Read, + path::Path, + }; + + static CERT_DIR: &'static str = "/system/etc/security/cacerts"; + + pub(super) fn load_client_ca_list( + vm: &VirtualMachine, + b: &mut SslContextBuilder, + ) -> Result<(), PyBaseExceptionRef> { + let root = Path::new(CERT_DIR); + if !root.is_dir() { + return Err(vm.new_exception_msg( + vm.ctx.exceptions.file_not_found_error.clone(), + CERT_DIR.to_string(), + )); + } + + let mut combined_pem = String::new(); + let entries = + read_dir(root).map_err(|err| vm.new_os_error(format!("read cert root: {}", err)))?; + for entry in entries { + let entry = entry.map_err(|err| vm.new_os_error(format!("iter cert root: {}", err)))?; + + let path = entry.path(); + if !path.is_file() { + continue; + } + + File::open(&path) + .and_then(|mut file| file.read_to_string(&mut combined_pem)) + .map_err(|err| { + vm.new_os_error(format!("open cert file {}: {}", path.display(), err)) + })?; + + combined_pem.push('\n'); + } + + let mut store_b = X509StoreBuilder::new().map_err(|err| convert_openssl_error(vm, err))?; + let x509_vec = X509::stack_from_pem(combined_pem.as_bytes()) + .map_err(|err| convert_openssl_error(vm, err))?; + for x509 in x509_vec { + store_b + .add_cert(x509) + .map_err(|err| convert_openssl_error(vm, err))?; + } + b.set_cert_store(store_b.build()); + + Ok(()) + } +}