Index: net/android/keystore.cc |
diff --git a/net/android/keystore.cc b/net/android/keystore.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e7fc3ee0854742489367a50a67769f0699117532 |
--- /dev/null |
+++ b/net/android/keystore.cc |
@@ -0,0 +1,180 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "net/android/keystore.h" |
+ |
+#include <vector> |
+ |
+#include "base/android/jni_android.h" |
+#include "base/android/jni_array.h" |
+#include "base/android/jni_string.h" |
+#include "base/logging.h" |
+ |
+#include "jni/AndroidKeyStore_jni.h" |
+ |
+using base::android::AttachCurrentThread; |
+using base::android::ConvertUTF8ToJavaString; |
+using base::android::ConvertJavaStringToUTF8; |
+using base::android::GetApplicationContext; |
+using base::android::HasException; |
+using base::android::JavaByteArrayToByteVector; |
+using base::android::ScopedJavaLocalRef; |
+using base::android::ToJavaByteArray; |
+using base::android::ToJavaArrayOfByteArray; |
+using base::android::ToJavaArrayOfStrings; |
+using base::android::JavaArrayOfByteArrayToStringVector; |
+ |
+namespace net { |
+namespace android { |
+ |
+namespace { |
+ |
+typedef std::vector<ClientCertRequest*> ClientCertRequestList; |
+ |
+// Global list of active client certificate requests. |
+// |
+// Note: There is no locking because all functions related to |
+// ClientCertRequestList should run on the UI thread. |
+ClientCertRequestList g_client_cert_requests; |
+ |
+// Return a new unique request id. Can't be 0. |
+int GetNewRequestId() { |
+ static int s_last_id; |
+ |
+ int id = ++s_last_id; |
+ if (id == INT_MAX) |
+ s_last_id = 0; |
+ DCHECK(id != 0); |
+ return id; |
+} |
+ |
+} // namespace |
+ |
+void OnRequestCompletion( |
+ JNIEnv* env, |
+ jclass /* clazz */, |
+ jint request_id, |
+ jstring private_key_alias_ref, |
+ jobjectArray encoded_chain_ref, |
+ jobject private_key_ref) { |
+ // Find the certificate request in the active list. |
+ // If none found, it was cancelled so return immediately. |
+ ClientCertRequest* request = NULL; |
+ for (ClientCertRequestList::iterator it = g_client_cert_requests.begin(); |
+ it != g_client_cert_requests.end(); ++it) { |
+ if ((*it)->request_id() == request_id) { |
+ // Found it, remove it from the active list. |
+ request = (*it); |
+ g_client_cert_requests.erase(it); |
+ break; |
+ } |
+ } |
+ |
+ if (!request) |
+ return; |
+ |
+ // Convert Java object to their C++ counterparts |
+ std::string private_key_alias; |
+ |
+ if (private_key_alias_ref) { |
+ private_key_alias = ConvertJavaStringToUTF8( |
+ env, private_key_alias_ref); |
+ } |
+ |
+ // Convert the encoded chain to a vector of strings. |
+ std::vector<std::string> encoded_chain; |
+ JavaArrayOfByteArrayToStringVector( |
+ env, encoded_chain_ref, &encoded_chain); |
+ |
+ // Call the delegate. |
+ request->OnCertificateSelection(private_key_alias, |
+ encoded_chain, |
+ private_key_ref); |
+} |
+ |
+ClientCertRequest::~ClientCertRequest() { |
+ if (request_id_ != 0) |
+ Cancel(); |
+} |
+ |
+bool ClientCertRequest::Start( |
+ const std::vector<std::string>& key_types, |
+ const std::vector<std::string>& principals, |
+ const std::string& host_name, |
+ int port) { |
+ |
+ // Convert parameters to equivalent Java objects. |
+ JNIEnv* env = AttachCurrentThread(); |
+ |
+ ScopedJavaLocalRef<jobjectArray> key_types_ref = |
+ ToJavaArrayOfStrings(env, key_types); |
+ if (key_types_ref.is_null()) |
+ return false; |
+ |
+ ScopedJavaLocalRef<jobjectArray> principals_ref = |
+ ToJavaArrayOfByteArray(env, principals); |
+ if (principals_ref.is_null()) |
+ return false; |
+ |
+ ScopedJavaLocalRef<jstring> host_name_ref = |
+ ConvertUTF8ToJavaString(env, host_name); |
+ if (host_name_ref.is_null()) |
+ return false; |
+ |
+ // Add to global list of active requests. |
+ request_id_ = GetNewRequestId(); |
+ g_client_cert_requests.push_back(this); |
+ |
+ // Invoke platform API. |
+ return Java_AndroidKeyStore_selectClientCertificate( |
+ env, request_id_, key_types_ref.obj(), principals_ref.obj(), |
+ host_name_ref.obj(), port, NULL); |
+} |
+ |
+void ClientCertRequest::Cancel() { |
+ if (request_id_ == 0) |
+ return; |
+ |
+ ClientCertRequestList::iterator it = std::find( |
+ g_client_cert_requests.begin(), |
+ g_client_cert_requests.end(), |
+ this); |
+ |
+ if (it != g_client_cert_requests.end()) { |
+ (*it)->request_id_ = 0; |
+ g_client_cert_requests.erase(it); |
+ } |
+} |
+ |
+bool SignWithPrivateKey( |
+ jobject private_key_ref, |
+ const base::StringPiece& message, |
+ std::vector<uint8>* signature) { |
+ JNIEnv* env = AttachCurrentThread(); |
+ |
+ // Convert message to byte[] array. |
+ ScopedJavaLocalRef<jbyteArray> message_ref = |
+ ToJavaByteArray(env, |
+ reinterpret_cast<const uint8*>(message.data()), |
+ message.length()); |
+ DCHECK(!message_ref.is_null()); |
+ |
+ // Invoke platform API |
+ ScopedJavaLocalRef<jbyteArray> signature_ref = |
+ Java_AndroidKeyStore_signWithPrivateKey( |
+ env, private_key_ref, message_ref.obj()); |
+ if (HasException(env) || signature_ref.is_null()) |
+ return false; |
+ |
+ // Write signature to string. |
+ JavaByteArrayToByteVector(env, signature_ref.obj(), signature); |
+ return true; |
+} |
+ |
+bool RegisterKeyStore(JNIEnv* env) { |
+ return RegisterNativesImpl(env); |
+} |
+ |
+} // namespace android |
+} // namespace net |