1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "android/net/android_network_library_impl.h" 6 7 #include "base/logging.h" 8 #include "android/jni/jni_utils.h" 9 10 using namespace android; 11 12 namespace { 13 14 const char* const kClassPathName = "android/net/http/CertificateChainValidator"; 15 16 // Convert X509 chain to DER format bytes. 17 jobjectArray GetCertificateByteArray( 18 JNIEnv* env, 19 const std::vector<std::string> cert_chain) { 20 size_t count = cert_chain.size(); 21 DCHECK_GT(count, 0U); 22 // TODO(joth): See if we can centrally cache common classes like this, e.g. 23 // as JniConstants does. 24 jclass byte_array_class = env->FindClass("[B"); 25 jobjectArray joa = env->NewObjectArray(count, byte_array_class, NULL); 26 if (joa == NULL) 27 return NULL; 28 29 for (size_t i = 0; i < count; ++i) { 30 size_t len = cert_chain[i].length(); 31 32 jbyteArray byte_array = env->NewByteArray(len); 33 if (!byte_array) { 34 env->DeleteLocalRef(joa); 35 return NULL; 36 } 37 38 jbyte* bytes = env->GetByteArrayElements(byte_array, NULL); 39 DCHECK(bytes); 40 size_t copied = cert_chain[i].copy(reinterpret_cast<char*>(bytes), len); 41 DCHECK_EQ(copied, len); 42 env->ReleaseByteArrayElements(byte_array, bytes, 0); 43 env->SetObjectArrayElement(joa, i, byte_array); 44 env->DeleteLocalRef(byte_array); 45 } 46 return joa; 47 } 48 49 } // namespace 50 51 AndroidNetworkLibraryImpl::VerifyResult 52 AndroidNetworkLibraryImpl::VerifyX509CertChain( 53 const std::vector<std::string>& cert_chain, 54 const std::string& hostname, 55 const std::string& auth_type) { 56 if (!cert_verifier_class_) 57 return VERIFY_INVOCATION_ERROR; 58 59 JNIEnv* env = jni::GetJNIEnv(); 60 DCHECK(env); 61 62 static jmethodID verify_fn = env->GetStaticMethodID( 63 cert_verifier_class_, "verifyServerCertificates", 64 "([[BLjava/lang/String;Ljava/lang/String;)Landroid/net/http/SslError;"); 65 if (jni::CheckException(env)) { 66 LOG(ERROR) << "verifyServerCertificates method not found; skipping"; 67 return VERIFY_INVOCATION_ERROR; 68 } 69 DCHECK(verify_fn); 70 71 jobjectArray chain_byte_array = GetCertificateByteArray(env, cert_chain); 72 if (!chain_byte_array) 73 return VERIFY_INVOCATION_ERROR; 74 75 jstring host_string = jni::ConvertUTF8ToJavaString(env, hostname); 76 DCHECK(host_string); 77 jstring auth_string = jni::ConvertUTF8ToJavaString(env, auth_type); 78 DCHECK(auth_string); 79 80 jobject error = env->CallStaticObjectMethod(cert_verifier_class_, verify_fn, 81 chain_byte_array, host_string, 82 auth_string); 83 env->DeleteLocalRef(chain_byte_array); 84 env->DeleteLocalRef(host_string); 85 env->DeleteLocalRef(auth_string); 86 87 VerifyResult result = VERIFY_INVOCATION_ERROR; 88 if (!jni::CheckException(env)) { 89 if (!error) { 90 result = VERIFY_OK; 91 } else { 92 jclass error_class = env->GetObjectClass(error); 93 DCHECK(error_class); 94 static jmethodID error_fn = env->GetMethodID(error_class, 95 "getPrimaryError", "()I"); 96 if (error_fn) { 97 int code = env->CallIntMethod(error, error_fn); 98 if (!jni::CheckException(env)) { 99 if (code == 2) { // SSL_IDMISMATCH == 2 100 result = VERIFY_BAD_HOSTNAME; 101 } else if (code == 3) { // SSL_UNTRUSTED == 3 102 result = VERIFY_NO_TRUSTED_ROOT; 103 } 104 } 105 } 106 env->DeleteLocalRef(error); 107 } 108 } 109 // TODO(joth): This balances the GetJNIEnv call; we need to detach as 110 // currently this method is called in chrome from a worker pool thread that 111 // may shutdown at anytime. However this assumption should not be baked in 112 // here: another user of the function may not want to have their thread 113 // detached at this point. 114 jni::DetachFromVM(); 115 return result; 116 } 117 118 // static 119 void AndroidNetworkLibraryImpl::InitWithApplicationContext(JNIEnv* env, 120 jobject context) { 121 // Currently ignoring |context| as it is not needed (but remains in signature 122 // for API consistency with the equivalent method on class AndroidOS). 123 if (!net::AndroidNetworkLibrary::GetSharedInstance()) 124 net::AndroidNetworkLibrary::RegisterSharedInstance( 125 new AndroidNetworkLibraryImpl(env)); 126 } 127 128 AndroidNetworkLibraryImpl::AndroidNetworkLibraryImpl(JNIEnv* env) 129 : cert_verifier_class_(NULL) { 130 jclass cls = env->FindClass(kClassPathName); 131 if (jni::CheckException(env) || !cls) { 132 NOTREACHED() << "Unable to load class " << kClassPathName; 133 } else { 134 cert_verifier_class_ = static_cast<jclass>(env->NewGlobalRef(cls)); 135 env->DeleteLocalRef(cls); 136 } 137 } 138 139 AndroidNetworkLibraryImpl::~AndroidNetworkLibraryImpl() { 140 if (cert_verifier_class_) 141 jni::GetJNIEnv()->DeleteGlobalRef(cert_verifier_class_); 142 } 143 144