diff --git a/Cargo.lock b/Cargo.lock index 60a4df44..fe172d43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -118,16 +118,18 @@ dependencies = [ [[package]] name = "jni" -version = "0.19.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ "cesu8", + "cfg-if", "combine", "jni-sys", "log", "thiserror", "walkdir", + "windows-sys 0.45.0", ] [[package]] @@ -350,7 +352,7 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -547,13 +549,37 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] @@ -562,51 +588,93 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" diff --git a/rustls-platform-verifier/Cargo.toml b/rustls-platform-verifier/Cargo.toml index 3249a146..e0bd4871 100644 --- a/rustls-platform-verifier/Cargo.toml +++ b/rustls-platform-verifier/Cargo.toml @@ -32,7 +32,7 @@ docsrs = ["jni", "once_cell"] rustls = { version = "0.21", features = ["dangerous_configuration", "tls12", "logging"] } log = { version = "0.4" } base64 = { version = "0.21", optional = true } # Only used when the `cert-logging` feature is enabled. -jni = { version = "0.19", default-features = false, optional = true } # Only used during doc generation +jni = { version = "0.21", default-features = false, optional = true } # Only used during doc generation once_cell = { version = "1.9", optional = true } # Only used during doc generation. [target.'cfg(all(unix, not(target_os = "android"), not(target_os = "macos"), not(target_os = "ios")))'.dependencies] @@ -42,7 +42,7 @@ webpki = { package = "rustls-webpki", version = "0.101", features = ["alloc", "s [target.'cfg(target_os = "android")'.dependencies] rustls-platform-verifier-android = { path = "../android-release-support", version = "0.1.0" } -jni = { version = "0.19", default-features = false } +jni = { version = "0.21", default-features = false } webpki = { package = "rustls-webpki", version = "0.101", features = ["alloc", "std"] } once_cell = "1.9" android_logger = { version = "0.13", optional = true } # Only used during testing. diff --git a/rustls-platform-verifier/src/android.rs b/rustls-platform-verifier/src/android.rs index 334ff4c3..a68dcdbc 100644 --- a/rustls-platform-verifier/src/android.rs +++ b/rustls-platform-verifier/src/android.rs @@ -56,8 +56,8 @@ impl Global { Ok(Context { env, - context: JObject::from(context), - loader: JObject::from(loader), + context, + loader, }) } } @@ -74,7 +74,7 @@ fn global() -> &'static Global { /// nothing else in your application needs access the Android runtime. /// /// Initialization must be done before any verification is attempted. -pub fn init_hosted(env: &JNIEnv, context: JObject) -> Result<(), JNIError> { +pub fn init_hosted(env: &mut JNIEnv, context: &JObject) -> Result<(), JNIError> { GLOBAL.get_or_try_init(|| -> Result<_, JNIError> { let loader = env.call_method(context, "getClassLoader", "()Ljava/lang/ClassLoader;", &[])?; @@ -126,34 +126,35 @@ impl From for Error { pub(super) struct Context<'a> { env: JNIEnv<'a>, - context: JObject<'a>, - loader: JObject<'a>, + context: &'a GlobalRef, + loader: &'a GlobalRef, } impl<'a> Context<'a> { /// Borrow a reference to the JNI Environment executing the Android application - pub(super) fn env(&self) -> &JNIEnv<'a> { - &self.env + pub(super) fn env(&mut self) -> &mut JNIEnv<'a> { + &mut self.env } /// Borrow the `applicationContext` from the Android application /// - pub(super) fn application_context(&self) -> &JObject<'a> { - &self.context + pub(super) fn application_context(&self) -> GlobalRef { + self.context.clone() } /// Load a class from the application class loader /// /// This should be used instead of `JNIEnv::find_class` to ensure all classes /// in the application can be found. - pub(super) fn load_class(&self, name: &str) -> Result, Error> { + pub(super) fn load_class(&mut self, name: &str) -> Result, Error> { + let loader = self.loader.clone(); let env = self.env(); let name = env.new_string(name)?; let class = env.call_method( - self.loader, + &loader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;", - &[JValue::from(name)], + &[JValue::from(&name)], )?; Ok(JObject::try_from(class)?.into()) @@ -165,17 +166,16 @@ impl<'a> Context<'a> { /// are cleared. pub(super) fn with_context(f: F) -> Result where - F: FnOnce(&Context) -> Result, + F: FnOnce(&mut Context) -> Result, { - let context = global().context()?; - let env = context.env(); + let mut context = global().context()?; // 16 is the default capacity in the JVM, we can make this configurable if necessary - env.push_local_frame(16)?; + context.env.push_local_frame(16)?; - let res = f(&context); + let res = f(&mut context); - env.pop_local_frame(JObject::null())?; + unsafe { context.env.pop_local_frame(&JObject::null()) }?; res } @@ -196,13 +196,13 @@ impl CachedClass { } /// Gets the cached class reference, loaded on first use - pub(super) fn get<'a: 'b, 'b>(&'a self, cx: &Context<'b>) -> Result, Error> { + pub(super) fn get<'a: 'b, 'b>(&'a self, cx: &mut Context<'b>) -> Result<&JClass<'b>, Error> { let class = self.class.get_or_try_init(|| -> Result<_, Error> { let class = cx.load_class(self.name)?; Ok(cx.env().new_global_ref(class)?) })?; - Ok(JClass::from(class.as_obj())) + Ok(class.as_obj().into()) } } diff --git a/rustls-platform-verifier/src/verification/android.rs b/rustls-platform-verifier/src/verification/android.rs index 90239095..b20148e6 100644 --- a/rustls-platform-verifier/src/verification/android.rs +++ b/rustls-platform-verifier/src/verification/android.rs @@ -46,8 +46,9 @@ pub struct Verifier { impl Drop for Verifier { fn drop(&mut self) { with_context::<_, ()>(|cx| { + let cert_verifier_class = CERT_VERIFIER_CLASS.get(cx)?; let env = cx.env(); - env.call_static_method(CERT_VERIFIER_CLASS.get(cx)?, "clearMockRoots", "()V", &[])? + env.call_static_method(cert_verifier_class, "clearMockRoots", "()V", &[])? .v()?; Ok(()) }) @@ -96,20 +97,24 @@ impl Verifier { .unwrap(); let verification_result = with_context(|cx| { + let byte_array_class = BYTE_ARRAY_CLASS.get(cx)?; + let string_class = STRING_CLASS.get(cx)?; + let cert_verifier_class = CERT_VERIFIER_CLASS.get(cx)?; + let app_ctx = cx.application_context(); let env = cx.env(); // We don't provide an initial element so that the array filling can be cleaner. // It's valid to provide a `null` value. Ref: https://docs.oracle.com/en/java/javase/13/docs/specs/jni/functions.html -> NewObjectArray let cert_list = { let array = env.new_object_array( (intermediates.len() + 1).try_into().unwrap(), - BYTE_ARRAY_CLASS.get(cx)?, + byte_array_class, JObject::null(), )?; for (idx, cert) in certificate_chain { let idx = idx.try_into().unwrap(); let cert_buffer = env.byte_array_from_slice(cert)?; - env.set_object_array_element(array, idx, cert_buffer)? + env.set_object_array_element(&array, idx, cert_buffer)? } array @@ -118,31 +123,31 @@ impl Verifier { let allowed_ekus = { let array = env.new_object_array( ALLOWED_EKUS.len().try_into().unwrap(), - STRING_CLASS.get(cx)?, + string_class, JObject::null(), )?; for (idx, eku) in ALLOWED_EKUS.iter().enumerate() { let idx = idx.try_into().unwrap(); let eku = env.new_string(eku)?; - env.set_object_array_element(array, idx, eku)?; + env.set_object_array_element(&array, idx, eku)?; } array }; - let ocsp_response = ocsp_response - .map(|b| env.byte_array_from_slice(b)) - .transpose()? - .map(JObject::from) - .unwrap_or_else(JObject::null); + let ocsp_response = if let Some(b) = ocsp_response { + JObject::from(env.byte_array_from_slice(b)?) + } else { + JObject::null() + }; #[cfg(any(test, feature = "ffi-testing"))] { if let Some(mock_root) = &self.test_only_root_ca_override { let mock_root = env.byte_array_from_slice(mock_root)?; env.call_static_method( - CERT_VERIFIER_CLASS.get(cx)?, + cert_verifier_class, "addMockRoot", "([B)V", &[JValue::from(mock_root)], @@ -167,22 +172,22 @@ impl Verifier { let result = env .call_static_method( - CERT_VERIFIER_CLASS.get(cx)?, + cert_verifier_class, "verifyCertificateChain", VERIFIER_CALL, &[ - JValue::from(*cx.application_context()), - JValue::from(env.new_string(server_name_str)?), - JValue::from(env.new_string(AUTH_TYPE)?), - JValue::from(JObject::from(allowed_ekus)), - JValue::from(ocsp_response), + JValue::from(app_ctx.as_obj()), + JValue::from(&env.new_string(server_name_str)?), + JValue::from(&env.new_string(AUTH_TYPE)?), + JValue::from(&JObject::from(allowed_ekus)), + JValue::from(&ocsp_response), JValue::Long(now), - JValue::from(JObject::from(cert_list)), + JValue::from(&JObject::from(cert_list)), ], )? .l()?; - Ok(extract_result_info(env, result)) + Ok(extract_result_info(env, &result)) }); match verification_result { @@ -227,7 +232,7 @@ impl Verifier { } } -fn extract_result_info(env: &JNIEnv<'_>, result: JObject<'_>) -> (VerifierStatus, Option) { +fn extract_result_info(env: &mut JNIEnv<'_>, result: &JObject<'_>) -> (VerifierStatus, Option) { let status_code = env .get_field(result, "code", "I") .and_then(|code| code.i()) @@ -248,11 +253,14 @@ fn extract_result_info(env: &JNIEnv<'_>, result: JObject<'_>) -> (VerifierStatus let msg = env .get_field(result, "message", "Ljava/lang/String;") .and_then(|m| m.l()) - .map(|o| (!o.is_null()).then_some(o)) - .and_then(|s| s.map(|s| JavaStr::from_env(env, s.into())).transpose()) + .map(|s| if s.is_null() { + None + } else { + JavaStr::from_env(env, &s.into()).ok().map(String::from) + }) .unwrap(); - (status, msg.map(String::from)) + (status, msg) } impl ServerCertVerifier for Verifier {