Home | History | Annotate | Download | only in net
      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   } else {
    109     // an uncaught exception has happened in java code, clear it and return
    110     // a proper error
    111     env->ExceptionClear();
    112     result = VERIFY_INVOCATION_ERROR;
    113   }
    114   // TODO(joth): This balances the GetJNIEnv call; we need to detach as
    115   // currently this method is called in chrome from a worker pool thread that
    116   // may shutdown at anytime. However this assumption should not be baked in
    117   // here: another user of the function may not want to have their thread
    118   // detached at this point.
    119   jni::DetachFromVM();
    120   return result;
    121 }
    122 
    123 // static
    124 void AndroidNetworkLibraryImpl::InitWithApplicationContext(JNIEnv* env,
    125                                                            jobject context) {
    126   // Currently ignoring |context| as it is not needed (but remains in signature
    127   // for API consistency with the equivalent method on class AndroidOS).
    128   if (!net::AndroidNetworkLibrary::GetSharedInstance())
    129     net::AndroidNetworkLibrary::RegisterSharedInstance(
    130         new AndroidNetworkLibraryImpl(env));
    131 }
    132 
    133 AndroidNetworkLibraryImpl::AndroidNetworkLibraryImpl(JNIEnv* env)
    134     : cert_verifier_class_(NULL) {
    135   jclass cls = env->FindClass(kClassPathName);
    136   if (jni::CheckException(env) || !cls) {
    137       NOTREACHED() << "Unable to load class " << kClassPathName;
    138   } else {
    139     cert_verifier_class_ = static_cast<jclass>(env->NewGlobalRef(cls));
    140     env->DeleteLocalRef(cls);
    141   }
    142 }
    143 
    144 AndroidNetworkLibraryImpl::~AndroidNetworkLibraryImpl() {
    145   if (cert_verifier_class_)
    146     jni::GetJNIEnv()->DeleteGlobalRef(cert_verifier_class_);
    147 }
    148 
    149