OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2013 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 "chrome/browser/ui/android/ssl_client_certificate_request.h" |
| 6 |
| 7 #include "base/android/jni_array.h" |
| 8 #include "base/android/jni_string.h" |
| 9 #include "base/android/scoped_java_ref.h" |
| 10 #include "base/logging.h" |
| 11 #include "content/public/browser/browser_thread.h" |
| 12 #include "jni/SSLClientCertificateRequest_jni.h" |
| 13 #include "net/base/host_port_pair.h" |
| 14 #include "net/base/ssl_cert_request_info.h" |
| 15 #include "net/base/ssl_client_cert_type.h" |
| 16 |
| 17 namespace browser { |
| 18 namespace android { |
| 19 |
| 20 using content::BrowserThread; |
| 21 |
| 22 bool SSLClientCertificateRequest::Start( |
| 23 const net::SSLCertRequestInfo* cert_request_info) { |
| 24 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 25 JNIEnv* env = base::android::AttachCurrentThread(); |
| 26 |
| 27 // Build the |key_types| JNI parameter, as a String[] |
| 28 std::vector<std::string> key_types; |
| 29 for (size_t n = 0; n < cert_request_info->cert_key_types.size(); ++n) { |
| 30 switch (cert_request_info->cert_key_types[n]) { |
| 31 case net::CLIENT_CERT_RSA_SIGN: |
| 32 key_types.push_back("RSA"); |
| 33 break; |
| 34 case net::CLIENT_CERT_DSS_SIGN: |
| 35 key_types.push_back("DSA"); |
| 36 break; |
| 37 case net::CLIENT_CERT_ECDSA_SIGN: |
| 38 key_types.push_back("ECDSA"); |
| 39 break; |
| 40 default: |
| 41 // Ignore unknown types. |
| 42 break; |
| 43 } |
| 44 } |
| 45 ScopedJavaLocalRef<jobjectArray> key_types_ref = |
| 46 base::android::ToJavaArrayOfStrings(env, key_types); |
| 47 if (key_types_ref.is_null()) { |
| 48 LOG(ERROR) << "Could not create key types array (String[])"; |
| 49 return false; |
| 50 } |
| 51 |
| 52 // Build the |encoded_principals| JNI parameter, as a byte[][] |
| 53 ScopedJavaLocalRef<jobjectArray> principals_ref = |
| 54 base::android::ToJavaArrayOfByteArray( |
| 55 env, cert_request_info->cert_authorities); |
| 56 if (principals_ref.is_null()) { |
| 57 LOG(ERROR) << "Could not create principals array (byte[][])"; |
| 58 return false; |
| 59 } |
| 60 |
| 61 // Build the |host_name| and |port| JNI parameters, as a String and |
| 62 // a jint. |
| 63 net::HostPortPair host_and_port = |
| 64 net::HostPortPair::FromString(cert_request_info->host_and_port); |
| 65 |
| 66 ScopedJavaLocalRef<jstring> host_name_ref = |
| 67 base::android::ConvertUTF8ToJavaString(env, host_and_port.host()); |
| 68 if (host_name_ref.is_null()) { |
| 69 LOG(ERROR) << "Could not extract host name from: '" |
| 70 << cert_request_info->host_and_port << "'"; |
| 71 return false; |
| 72 } |
| 73 |
| 74 jint port = host_and_port.port(); |
| 75 if (port <= 0 || port > 65535) { |
| 76 LOG(ERROR) << "Invalid port number in: " |
| 77 << cert_request_info->host_and_port << "'"; |
| 78 return false; |
| 79 } |
| 80 |
| 81 // Convert the request's address into a pointer that will be passed |
| 82 // to the Java method through JNI. |
| 83 jint request_id = reinterpret_cast<jint>(this); |
| 84 |
| 85 if (!Java_SSLClientCertificateRequest_selectClientCertificate( |
| 86 env, request_id, key_types_ref.obj(), principals_ref.obj(), |
| 87 host_name_ref.obj(), port)) { |
| 88 return false; |
| 89 } |
| 90 |
| 91 // Ensure the request won't be destroyed until OnRequestCompletion is |
| 92 // called later in the future. |
| 93 this->AddRef(); |
| 94 return true; |
| 95 } |
| 96 |
| 97 // Called from JNI on request completion/result. |
| 98 // |env| is the current thread's JNIEnv. |
| 99 // |object| is the SSLClientCertificateRequest Java class reference. |
| 100 // |delegate_id| is the id passed to |
| 101 // Java_SSLClientCertificateRequest_selectClientCertificate() in Start(). |
| 102 // |encoded_chain_ref| is a JNI reference to a Java array of byte arrays, |
| 103 // each item holding a DER-encoded X.509 certificate. |
| 104 // |private_key_ref| is the platform PrivateKey object JNI reference for |
| 105 // the client certificate. |
| 106 // Note: both |encoded_chain_ref| and |private_key_ref| will be NULL if |
| 107 // the user didn't select a certificate. |
| 108 void SSLClientCertificateRequest::OnRequestCompletion( |
| 109 JNIEnv* env, |
| 110 jobject object, |
| 111 jobjectArray encoded_chain_ref, |
| 112 jobject private_key_ref) { |
| 113 |
| 114 // Ensure that the request is released when the |
| 115 // function exits. Note that this also undoes the AddRef |
| 116 // from ::Start(). |
| 117 scoped_refptr<SSLClientCertificateRequest> guard(this); |
| 118 this->Release(); |
| 119 |
| 120 // When the request is cancelled by the user, just send NULL |
| 121 // to the callback immediately. |
| 122 if (private_key_ref == NULL || private_key_ref == NULL) { |
| 123 LOG(ERROR) << "Client certificate request cancelled"; |
| 124 OnCompletion(NULL, NULL); |
| 125 return; |
| 126 } |
| 127 |
| 128 // Convert the encoded chain to a vector of strings. |
| 129 std::vector<std::string> encoded_chain_strings; |
| 130 if (encoded_chain_ref) { |
| 131 base::android::JavaArrayOfByteArrayToStringVector( |
| 132 env, encoded_chain_ref, &encoded_chain_strings); |
| 133 } |
| 134 |
| 135 std::vector<base::StringPiece> encoded_chain; |
| 136 for (size_t n = 0; n < encoded_chain_strings.size(); ++n) |
| 137 encoded_chain.push_back(encoded_chain_strings[n]); |
| 138 |
| 139 // Pass the results to the subclass. |
| 140 OnCompletion(&encoded_chain, private_key_ref); |
| 141 } |
| 142 |
| 143 } // namespace android |
| 144 } // namespace browser |
| 145 |
| 146 bool RegisterSSLClientCertificateRequestAndroid(JNIEnv* env) { |
| 147 return browser::android::RegisterNativesImpl(env); |
| 148 } |
OLD | NEW |