use std::sync::{Arc, OnceLock};
use jni::{objects::JObject, vm::JavaVM};
use rustls::{
DigitallySignedStruct, SignatureScheme,
client::{
WebPkiServerVerifier,
danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
},
pki_types::{CertificateDer, ServerName, UnixTime},
};
use rustls_platform_verifier::Verifier;
use crate::Error;
pub(crate) fn ensure_initialized() -> Result<(), Error> {
static HANDED_OVER: OnceLock<()> = OnceLock::new();
if HANDED_OVER.get().is_some() {
return Ok(());
}
let context = ndk_context::android_context();
if context.vm().is_null() || context.context().is_null() {
return Err(Error::tls(
"ndk-context holds a null JVM or Android context pointer; the host must register \
real ones before TLS connections are opened",
));
}
let vm = unsafe { JavaVM::from_raw(context.vm().cast()) };
let raw_context: jni::sys::jobject = context.context().cast();
vm.attach_current_thread(|env| {
let borrowed = unsafe { env.as_cast_raw::<JObject<'_>>(&raw_context)? };
let local = env.new_local_ref(&*borrowed)?;
rustls_platform_verifier::android::init_with_env(env, local)
})
.map_err(Error::tls)?;
let _ = HANDED_OVER.set(());
tracing::debug!("rustls-platform-verifier initialised through ndk-context");
Ok(())
}
#[derive(Debug)]
pub(super) struct PlatformOrExtraRoots {
pub(super) platform: Verifier,
pub(super) extra: Arc<WebPkiServerVerifier>,
}
impl ServerCertVerifier for PlatformOrExtraRoots {
fn verify_server_cert(
&self,
end_entity: &CertificateDer<'_>,
intermediates: &[CertificateDer<'_>],
server_name: &ServerName<'_>,
ocsp_response: &[u8],
now: UnixTime,
) -> Result<ServerCertVerified, rustls::Error> {
match self.platform.verify_server_cert(
end_entity,
intermediates,
server_name,
ocsp_response,
now,
) {
Ok(verified) => Ok(verified),
Err(platform_error) => self
.extra
.verify_server_cert(end_entity, intermediates, server_name, ocsp_response, now)
.map_err(|_| platform_error),
}
}
fn verify_tls12_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
self.platform.verify_tls12_signature(message, cert, dss)
}
fn verify_tls13_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
self.platform.verify_tls13_signature(message, cert, dss)
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
self.platform.supported_verify_schemes()
}
}