176a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved. 276a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 376a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch// found in the LICENSE file. 476a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 576a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch#include "android/net/android_network_library_impl.h" 676a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 776a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch#include "base/logging.h" 876a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch#include "android/jni/jni_utils.h" 976a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 1076a88e2c298122bfdfc498a5df61aab702184639Ben Murdochusing namespace android; 1176a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 1276a88e2c298122bfdfc498a5df61aab702184639Ben Murdochnamespace { 1376a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 1476a88e2c298122bfdfc498a5df61aab702184639Ben Murdochconst char* const kClassPathName = "android/net/http/CertificateChainValidator"; 1576a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 1676a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch// Convert X509 chain to DER format bytes. 1776a88e2c298122bfdfc498a5df61aab702184639Ben MurdochjobjectArray GetCertificateByteArray( 1876a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch JNIEnv* env, 1976a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch const std::vector<std::string> cert_chain) { 2076a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch size_t count = cert_chain.size(); 2176a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch DCHECK_GT(count, 0U); 2276a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch // TODO(joth): See if we can centrally cache common classes like this, e.g. 2376a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch // as JniConstants does. 2476a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch jclass byte_array_class = env->FindClass("[B"); 2576a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch jobjectArray joa = env->NewObjectArray(count, byte_array_class, NULL); 2676a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch if (joa == NULL) 2776a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch return NULL; 2876a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 2976a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch for (size_t i = 0; i < count; ++i) { 3076a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch size_t len = cert_chain[i].length(); 3176a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 3276a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch jbyteArray byte_array = env->NewByteArray(len); 3376a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch if (!byte_array) { 3476a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch env->DeleteLocalRef(joa); 3576a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch return NULL; 3676a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch } 3776a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 3876a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch jbyte* bytes = env->GetByteArrayElements(byte_array, NULL); 3976a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch DCHECK(bytes); 4076a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch size_t copied = cert_chain[i].copy(reinterpret_cast<char*>(bytes), len); 4176a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch DCHECK_EQ(copied, len); 4276a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch env->ReleaseByteArrayElements(byte_array, bytes, 0); 4376a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch env->SetObjectArrayElement(joa, i, byte_array); 4476a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch env->DeleteLocalRef(byte_array); 4576a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch } 4676a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch return joa; 4776a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch} 4876a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 4976a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch} // namespace 5076a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 5176a88e2c298122bfdfc498a5df61aab702184639Ben MurdochAndroidNetworkLibraryImpl::VerifyResult 5276a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch AndroidNetworkLibraryImpl::VerifyX509CertChain( 5376a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch const std::vector<std::string>& cert_chain, 5476a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch const std::string& hostname, 5576a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch const std::string& auth_type) { 5676a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch if (!cert_verifier_class_) 5776a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch return VERIFY_INVOCATION_ERROR; 5876a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 59cecae02673edd6b4cee88a9b87a61055a91f70bbKristian Monsen JNIEnv* env = jni::GetJNIEnv(); 6076a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch DCHECK(env); 6176a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 6276a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch static jmethodID verify_fn = env->GetStaticMethodID( 6376a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch cert_verifier_class_, "verifyServerCertificates", 6476a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch "([[BLjava/lang/String;Ljava/lang/String;)Landroid/net/http/SslError;"); 65cecae02673edd6b4cee88a9b87a61055a91f70bbKristian Monsen if (jni::CheckException(env)) { 6676a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch LOG(ERROR) << "verifyServerCertificates method not found; skipping"; 6776a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch return VERIFY_INVOCATION_ERROR; 6876a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch } 6976a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch DCHECK(verify_fn); 7076a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 7176a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch jobjectArray chain_byte_array = GetCertificateByteArray(env, cert_chain); 7276a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch if (!chain_byte_array) 7376a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch return VERIFY_INVOCATION_ERROR; 7476a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 75cecae02673edd6b4cee88a9b87a61055a91f70bbKristian Monsen jstring host_string = jni::ConvertUTF8ToJavaString(env, hostname); 7676a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch DCHECK(host_string); 77cecae02673edd6b4cee88a9b87a61055a91f70bbKristian Monsen jstring auth_string = jni::ConvertUTF8ToJavaString(env, auth_type); 7876a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch DCHECK(auth_string); 7976a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 8076a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch jobject error = env->CallStaticObjectMethod(cert_verifier_class_, verify_fn, 8176a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch chain_byte_array, host_string, 8276a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch auth_string); 8376a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch env->DeleteLocalRef(chain_byte_array); 8476a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch env->DeleteLocalRef(host_string); 8576a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch env->DeleteLocalRef(auth_string); 8676a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 8776a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch VerifyResult result = VERIFY_INVOCATION_ERROR; 88cecae02673edd6b4cee88a9b87a61055a91f70bbKristian Monsen if (!jni::CheckException(env)) { 8976a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch if (!error) { 9076a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch result = VERIFY_OK; 9176a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch } else { 9276a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch jclass error_class = env->GetObjectClass(error); 9376a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch DCHECK(error_class); 9476a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch static jmethodID error_fn = env->GetMethodID(error_class, 9576a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch "getPrimaryError", "()I"); 9676a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch if (error_fn) { 9776a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch int code = env->CallIntMethod(error, error_fn); 98cecae02673edd6b4cee88a9b87a61055a91f70bbKristian Monsen if (!jni::CheckException(env)) { 9976a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch if (code == 2) { // SSL_IDMISMATCH == 2 10076a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch result = VERIFY_BAD_HOSTNAME; 10176a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch } else if (code == 3) { // SSL_UNTRUSTED == 3 10276a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch result = VERIFY_NO_TRUSTED_ROOT; 10376a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch } 10476a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch } 10576a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch } 10676a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch env->DeleteLocalRef(error); 10776a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch } 1084f8351323b84a7b8c3275e6df8a99a4738fabf45Selim Gurun } else { 1094f8351323b84a7b8c3275e6df8a99a4738fabf45Selim Gurun // an uncaught exception has happened in java code, clear it and return 1104f8351323b84a7b8c3275e6df8a99a4738fabf45Selim Gurun // a proper error 1114f8351323b84a7b8c3275e6df8a99a4738fabf45Selim Gurun env->ExceptionClear(); 1124f8351323b84a7b8c3275e6df8a99a4738fabf45Selim Gurun result = VERIFY_INVOCATION_ERROR; 11376a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch } 11476a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch // TODO(joth): This balances the GetJNIEnv call; we need to detach as 11576a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch // currently this method is called in chrome from a worker pool thread that 11676a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch // may shutdown at anytime. However this assumption should not be baked in 11776a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch // here: another user of the function may not want to have their thread 11876a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch // detached at this point. 119cecae02673edd6b4cee88a9b87a61055a91f70bbKristian Monsen jni::DetachFromVM(); 12076a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch return result; 12176a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch} 12276a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 12376a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch// static 12476a88e2c298122bfdfc498a5df61aab702184639Ben Murdochvoid AndroidNetworkLibraryImpl::InitWithApplicationContext(JNIEnv* env, 12576a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch jobject context) { 12676a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch // Currently ignoring |context| as it is not needed (but remains in signature 12776a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch // for API consistency with the equivalent method on class AndroidOS). 128e6720cd0c92969c2a3360cffef01724dbe1fc923Kristian Monsen if (!net::AndroidNetworkLibrary::GetSharedInstance()) 129e6720cd0c92969c2a3360cffef01724dbe1fc923Kristian Monsen net::AndroidNetworkLibrary::RegisterSharedInstance( 130e6720cd0c92969c2a3360cffef01724dbe1fc923Kristian Monsen new AndroidNetworkLibraryImpl(env)); 13176a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch} 13276a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 13376a88e2c298122bfdfc498a5df61aab702184639Ben MurdochAndroidNetworkLibraryImpl::AndroidNetworkLibraryImpl(JNIEnv* env) 13476a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch : cert_verifier_class_(NULL) { 13576a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch jclass cls = env->FindClass(kClassPathName); 136cecae02673edd6b4cee88a9b87a61055a91f70bbKristian Monsen if (jni::CheckException(env) || !cls) { 13776a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch NOTREACHED() << "Unable to load class " << kClassPathName; 13876a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch } else { 13976a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch cert_verifier_class_ = static_cast<jclass>(env->NewGlobalRef(cls)); 14076a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch env->DeleteLocalRef(cls); 14176a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch } 14276a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch} 14376a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 14476a88e2c298122bfdfc498a5df61aab702184639Ben MurdochAndroidNetworkLibraryImpl::~AndroidNetworkLibraryImpl() { 14576a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch if (cert_verifier_class_) 146cecae02673edd6b4cee88a9b87a61055a91f70bbKristian Monsen jni::GetJNIEnv()->DeleteGlobalRef(cert_verifier_class_); 14776a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch} 14876a88e2c298122bfdfc498a5df61aab702184639Ben Murdoch 149