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