Refactoring AndroidKeyStore to support a KeyStore running in another process

This CL does a number of things:
1) Extracts an AndroidKeyStore interface which specifies the API needed by the
native OpenSSL engine from an AndroidKeyStore. Also changes from using
PrivateKey to AndroidPrivateKey to provide a layer of indirection needed for a
remote PrivateKey
2) Renames the previous AndroidKeyStore to AndroidKeyStoreLocalImpl as it's
used for interacting with an in-process Android KeyStore
3) Provides a new class AndroidKeyStoreRemoteImpl and corresponding
IAndroidKeyStoreRemote.aidl that together specify the interface and interaction
with a remote process managing an Android KeyStore
4) Alters the PKCS11-based authentication flow to only use out a remote Android
KeyStore
5) Adds a new method to the previous AndroidKeyStore interface to facilitate
clean up of remote keys

BUG=341500
CONTRIBUTOR=ppi@chromium.org
R=bulach@chromium.org, klobag@chromium.org
TBR=rsleevi
NOTRY=true

Review URL: https://codereview.chromium.org/166143002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@251461 0039d316-1c4b-4281-b951-d872f2087c98
parent 55d19d36
......@@ -6,7 +6,8 @@ package org.chromium.chrome.browser;
import android.content.Context;
import java.security.PrivateKey;
import org.chromium.net.AndroidPrivateKey;
import java.security.cert.X509Certificate;
/**
......@@ -33,14 +34,14 @@ public interface PKCS11AuthenticationManager {
*/
public X509Certificate[] getCertificateChain(String alias);
/**
* Returns the PrivateKey for the requested alias, or null if no there is no result.
*/
public PrivateKey getPrivateKey(String alias);
/**
* Performs necessary initializing for using a PKCS11-based KeysStore. Note that this can
* perform expensive operations and cannot be done on the UI thread.
*/
public void initialize(Context context);
/**
* Returns the AndroidPrivateKey for the requested alias, or null if there is no result.
*/
public AndroidPrivateKey getPrivateKey(String alias);
}
......@@ -16,9 +16,10 @@ import org.chromium.base.ActivityStatus;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
import org.chromium.base.ThreadUtils;
import org.chromium.net.AndroidPrivateKey;
import org.chromium.net.DefaultAndroidKeyStore;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
......@@ -34,9 +35,12 @@ import javax.security.auth.x500.X500Principal;
* finally pass the results back to the UI thread, which will return to the native code.
*/
@JNINamespace("chrome::android")
class SSLClientCertificateRequest {
public class SSLClientCertificateRequest {
static final String TAG = "SSLClientCertificateRequest";
private static final DefaultAndroidKeyStore sLocalKeyStore =
new DefaultAndroidKeyStore();
/**
* Common implementation for anynchronous task of handling the certificate request. This
* AsyncTask uses the abstract methods to retrieve the authentication material from a
......@@ -47,7 +51,7 @@ class SSLClientCertificateRequest {
// These fields will store the results computed in doInBackground so that they can be posted
// back in onPostExecute.
private byte[][] mEncodedChain;
private PrivateKey mPrivateKey;
private AndroidPrivateKey mAndroidPrivateKey;
// Pointer to the native certificate request needed to return the results.
private final int mNativePtr;
......@@ -58,7 +62,7 @@ class SSLClientCertificateRequest {
// These overriden methods will be used to access the key store.
abstract String getAlias();
abstract PrivateKey getPrivateKey(String alias);
abstract AndroidPrivateKey getPrivateKey(String alias);
abstract X509Certificate[] getCertificateChain(String alias);
@Override
......@@ -66,8 +70,9 @@ class SSLClientCertificateRequest {
String alias = getAlias();
if (alias == null) return null;
PrivateKey key = getPrivateKey(alias);
AndroidPrivateKey key = getPrivateKey(alias);
X509Certificate[] chain = getCertificateChain(alias);
if (key == null || chain == null || chain.length == 0) {
Log.w(TAG, "Empty client certificate chain?");
return null;
......@@ -85,14 +90,14 @@ class SSLClientCertificateRequest {
}
mEncodedChain = encodedChain;
mPrivateKey = key;
mAndroidPrivateKey = key;
return null;
}
@Override
protected void onPostExecute(Void result) {
ThreadUtils.assertOnUiThread();
nativeOnSystemRequestCompletion(mNativePtr, mEncodedChain, mPrivateKey);
nativeOnSystemRequestCompletion(mNativePtr, mEncodedChain, mAndroidPrivateKey);
}
}
......@@ -114,9 +119,9 @@ class SSLClientCertificateRequest {
}
@Override
PrivateKey getPrivateKey(String alias) {
AndroidPrivateKey getPrivateKey(String alias) {
try {
return KeyChain.getPrivateKey(mContext, alias);
return sLocalKeyStore.createKey(KeyChain.getPrivateKey(mContext, alias));
} catch (KeyChainException e) {
Log.w(TAG, "KeyChainException when looking for '" + alias + "' certificate");
return null;
......@@ -160,7 +165,7 @@ class SSLClientCertificateRequest {
}
@Override
PrivateKey getPrivateKey(String alias) {
AndroidPrivateKey getPrivateKey(String alias) {
return mPKCS11AuthManager.getPrivateKey(alias);
}
......@@ -290,5 +295,5 @@ class SSLClientCertificateRequest {
// Called to pass request results to native side.
private static native void nativeOnSystemRequestCompletion(
int requestPtr, byte[][] certChain, PrivateKey privateKey);
int requestPtr, byte[][] certChain, AndroidPrivateKey androidKey);
}
......@@ -7,8 +7,8 @@ package org.chromium.chrome.testshell;
import android.content.Context;
import org.chromium.chrome.browser.PKCS11AuthenticationManager;
import org.chromium.net.AndroidPrivateKey;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
/**
......@@ -36,7 +36,7 @@ public class TestShellPKCS11AuthenticationManager implements PKCS11Authenticatio
}
@Override
public PrivateKey getPrivateKey(String alias) {
public AndroidPrivateKey getPrivateKey(String alias) {
return null;
}
}
// Copyright 2014 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/android_private_key.h"
#include <vector>
#include "jni/AndroidPrivateKey_jni.h"
namespace net {
namespace android {
base::android::ScopedJavaLocalRef<jobject> GetKeyStore(
jobject private_key_ref) {
JNIEnv* env = base::android::AttachCurrentThread();
return Java_AndroidPrivateKey_getKeyStore(
env, private_key_ref);
}
bool RegisterAndroidPrivateKey(JNIEnv* env) {
return RegisterNativesImpl(env);
}
} // namespace android
} // namespace net
// Copyright 2014 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.
#ifndef NET_ANDROID_ANDROID_PRIVATE_KEY_H
#define NET_ANDROID_ANDROID_PRIVATE_KEY_H
#include <jni.h>
#include "base/android/scoped_java_ref.h"
#include "base/basictypes.h"
#include "net/base/net_export.h"
namespace net {
namespace android {
// Returns the KeyStore associated with a given AndroidPrivateKey
NET_EXPORT base::android::ScopedJavaLocalRef<jobject> GetKeyStore(
jobject private_key);
// Register JNI methods
NET_EXPORT bool RegisterAndroidPrivateKey(JNIEnv* env);
} // namespace android
} // namespace net
#endif // NET_ANDROID_ANDROID_PRIVATE_KEY_H
// Copyright 2014 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.
package org.chromium.net;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
/**
* Abstract private key that bundles the PrivateKey and AndroidKeyStore that it belongs to.
*/
@JNINamespace("net::android")
public interface AndroidPrivateKey {
/** @return AndroidKeyStore that handles this key. */
@CalledByNative
AndroidKeyStore getKeyStore();
}
// Copyright 2013 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.
package org.chromium.net;
import android.util.Log;
import java.lang.reflect.Method;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.interfaces.DSAKey;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.ECKey;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.RSAKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.ECParameterSpec;
/**
* Simple implementation of the AndroidKeyStore for use with an in-process Java KeyStore.
*/
public class DefaultAndroidKeyStore implements AndroidKeyStore {
private static final String TAG = "AndroidKeyStoreInProcessImpl";
private static class DefaultAndroidPrivateKey implements AndroidPrivateKey {
// The actual Java key being wrapped.
final PrivateKey mKey;
// Key store handling this key.
final DefaultAndroidKeyStore mStore;
DefaultAndroidPrivateKey(PrivateKey key, DefaultAndroidKeyStore store) {
mKey = key;
mStore = store;
}
PrivateKey getJavaKey() {
return mKey;
}
@Override
public AndroidKeyStore getKeyStore() {
return mStore;
}
}
public AndroidPrivateKey createKey(PrivateKey javaKey) {
return new DefaultAndroidPrivateKey(javaKey, this);
}
@Override
public byte[] getRSAKeyModulus(AndroidPrivateKey key) {
PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey();
if (javaKey instanceof RSAKey) {
return ((RSAKey) javaKey).getModulus().toByteArray();
}
Log.w(TAG, "Not a RSAKey instance!");
return null;
}
@Override
public byte[] getDSAKeyParamQ(AndroidPrivateKey key) {
PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey();
if (javaKey instanceof DSAKey) {
DSAParams params = ((DSAKey) javaKey).getParams();
return params.getQ().toByteArray();
}
Log.w(TAG, "Not a DSAKey instance!");
return null;
}
@Override
public byte[] getECKeyOrder(AndroidPrivateKey key) {
PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey();
if (javaKey instanceof ECKey) {
ECParameterSpec params = ((ECKey) javaKey).getParams();
return params.getOrder().toByteArray();
}
Log.w(TAG, "Not an ECKey instance!");
return null;
}
@Override
public byte[] getPrivateKeyEncodedBytes(AndroidPrivateKey key) {
PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey();
return javaKey.getEncoded();
}
@Override
public byte[] rawSignDigestWithPrivateKey(AndroidPrivateKey key,
byte[] message) {
PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey();
// Get the Signature for this key.
Signature signature = null;
// Hint: Algorithm names come from:
// http://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html
try {
if (javaKey instanceof RSAPrivateKey) {
// IMPORTANT: Due to a platform bug, this will throw NoSuchAlgorithmException
// on Android 4.0.x and 4.1.x. Fixed in 4.2 and higher.
// See https://android-review.googlesource.com/#/c/40352/
signature = Signature.getInstance("NONEwithRSA");
} else if (javaKey instanceof DSAPrivateKey) {
signature = Signature.getInstance("NONEwithDSA");
} else if (javaKey instanceof ECPrivateKey) {
signature = Signature.getInstance("NONEwithECDSA");
}
} catch (NoSuchAlgorithmException e) {
;
}
if (signature == null) {
Log.e(TAG, "Unsupported private key algorithm: " + javaKey.getAlgorithm());
return null;
}
// Sign the message.
try {
signature.initSign(javaKey);
signature.update(message);
return signature.sign();
} catch (Exception e) {
Log.e(TAG, "Exception while signing message with " + javaKey.getAlgorithm() +
" private key: " + e);
return null;
}
}
@Override
public int getPrivateKeyType(AndroidPrivateKey key) {
PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey();
if (javaKey instanceof RSAPrivateKey)
return PrivateKeyType.RSA;
if (javaKey instanceof DSAPrivateKey)
return PrivateKeyType.DSA;
if (javaKey instanceof ECPrivateKey)
return PrivateKeyType.ECDSA;
else
return PrivateKeyType.INVALID;
}
@Override
public int getOpenSSLHandleForPrivateKey(AndroidPrivateKey key) {
PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey();
// Sanity checks
if (javaKey == null) {
Log.e(TAG, "key == null");
return 0;
}
if (!(javaKey instanceof RSAPrivateKey)) {
Log.e(TAG, "does not implement RSAPrivateKey");
return 0;
}
// First, check that this is a proper instance of OpenSSLRSAPrivateKey
// or one of its sub-classes.
Class<?> superClass;
try {
superClass = Class.forName(
"org.apache.harmony.xnet.provider.jsse.OpenSSLRSAPrivateKey");
} catch (Exception e) {
// This may happen if the target device has a completely different
// implementation of the java.security APIs, compared to vanilla
// Android. Highly unlikely, but still possible.
Log.e(TAG, "Cannot find system OpenSSLRSAPrivateKey class: " + e);
return 0;
}
if (!superClass.isInstance(key)) {
// This may happen if the PrivateKey was not created by the "AndroidOpenSSL"
// provider, which should be the default. That could happen if an OEM decided
// to implement a different default provider. Also highly unlikely.
Log.e(TAG, "Private key is not an OpenSSLRSAPrivateKey instance, its class name is:" +
javaKey.getClass().getCanonicalName());
return 0;
}
try {
// Use reflection to invoke the 'getOpenSSLKey()' method on
// the private key. This returns another Java object that wraps
// a native EVP_PKEY. Note that the method is final, so calling
// the superclass implementation is ok.
Method getKey = superClass.getDeclaredMethod("getOpenSSLKey");
getKey.setAccessible(true);
Object opensslKey = null;
try {
opensslKey = getKey.invoke(javaKey);
} finally {
getKey.setAccessible(false);
}
if (opensslKey == null) {
// Bail when detecting OEM "enhancement".
Log.e(TAG, "getOpenSSLKey() returned null");
return 0;
}
// Use reflection to invoke the 'getPkeyContext' method on the
// result of the getOpenSSLKey(). This is an 32-bit integer
// which is the address of an EVP_PKEY object.
Method getPkeyContext;
try {
getPkeyContext = opensslKey.getClass().getDeclaredMethod("getPkeyContext");
} catch (Exception e) {
// Bail here too, something really not working as expected.
Log.e(TAG, "No getPkeyContext() method on OpenSSLKey member:" + e);
return 0;
}
getPkeyContext.setAccessible(true);
int evp_pkey = 0;
try {
evp_pkey = (Integer) getPkeyContext.invoke(opensslKey);
} finally {
getPkeyContext.setAccessible(false);
}
if (evp_pkey == 0) {
// The PrivateKey is probably rotten for some reason.
Log.e(TAG, "getPkeyContext() returned null");
}
return evp_pkey;
} catch (Exception e) {
Log.e(TAG, "Exception while trying to retrieve system EVP_PKEY handle: " + e);
return 0;
}
}
@Override
public void releaseKey(AndroidPrivateKey key) {
// no-op for in-process. GC will handle key collection
}
}
// Copyright 2014 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.
package org.chromium.net;
import org.chromium.net.IRemoteAndroidKeyStoreCallbacks;
/**
* Interface for communication with an Android KeyStore in another process.
*/
interface IRemoteAndroidKeyStore {
// Remote calls for SSlClientCertificateRequest - these allow retrieving
// the alias of the certificate to be used, its encoded chain and a handle
// for identifying a private key in the remote process.
String getClientCertificateAlias();
byte[] getEncodedCertificateChain(in String alias);
int getPrivateKeyHandle(in String alias);
// Registers callbacks for service->client communication.
void setClientCallbacks(IRemoteAndroidKeyStoreCallbacks callbacks);
// Remote calls for AndroidKeyStore - these functions are performing operations
// with a PrivateKey in the remote process using the handle provided by
// |getPrivateKeyHandle|.
byte[] getRSAKeyModulus(in int handle);
byte[] getPrivateKeyEncodedBytes(in int handle);
byte[] getDSAKeyParamQ(in int handle);
byte[] getECKeyOrder(in int handle);
byte[] rawSignDigestWithPrivateKey(in int handle, in byte[] message);
int getPrivateKeyType(in int handle);
void releaseKey(in int handle);
}
// Copyright 2014 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.
package org.chromium.net;
/**
* Interface for communication from the remote authentication service back to the client.
*/
interface IRemoteAndroidKeyStoreCallbacks {
/**
* A critical failure has occurred and the service won't be able to recover.
* The client should unbind and optionally rebind at a later time.
*/
void onDisabled();
/**
* The service has started up and is fully initialized. This allows for the
* service to take some time to initialize. Remote calls shouldn't be invoked
* until this call has fired.
*/
void onInitComplete();
}
// Copyright 2014 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.
interface org.chomium.net.IRemoteAndroidKeyStore;
interface org.chromium.net.IRemoteAndroidKeyStoreCallbacks;
\ No newline at end of file
// Copyright 2014 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.
package org.chromium.net;
import android.os.RemoteException;
import android.util.Log;
/**
* Provides a remoted implementation of AndroidKeyStore where all calls are forwarded via
* binder to an external process.
*/
public class RemoteAndroidKeyStore implements AndroidKeyStore {
private static final String TAG = "AndroidKeyStoreRemoteImpl";
private static class RemotePrivateKey implements AndroidPrivateKey {
// Reference to the key on a remote store.
final int mHandle;
// Key store handling this key.
final RemoteAndroidKeyStore mStore;
RemotePrivateKey(int handle, RemoteAndroidKeyStore store) {
mHandle = handle;
mStore = store;
}
public int getHandle() {
return mHandle;
}
@Override
public AndroidKeyStore getKeyStore() {
return mStore;
}
}
private final IRemoteAndroidKeyStore mRemoteManager;
public RemoteAndroidKeyStore(IRemoteAndroidKeyStore manager) {
mRemoteManager = manager;
}
@Override
public byte[] getRSAKeyModulus(AndroidPrivateKey key) {
RemotePrivateKey remoteKey = (RemotePrivateKey) key;
try {
Log.d(TAG, "getRSAKeyModulus");
return mRemoteManager.getRSAKeyModulus(remoteKey.getHandle());
} catch (RemoteException e) {
e.printStackTrace();
return null;
}
}
@Override
public byte[] getDSAKeyParamQ(AndroidPrivateKey key) {
RemotePrivateKey remoteKey = (RemotePrivateKey) key;
try {
Log.d(TAG, "getDSAKeyParamQ");
return mRemoteManager.getDSAKeyParamQ(remoteKey.getHandle());
} catch (RemoteException e) {
e.printStackTrace();
return null;
}
}
@Override
public byte[] getECKeyOrder(AndroidPrivateKey key) {
RemotePrivateKey remoteKey = (RemotePrivateKey) key;
try {
Log.d(TAG, "getECKeyOrder");
return mRemoteManager.getECKeyOrder(remoteKey.getHandle());
} catch (RemoteException e) {
e.printStackTrace();
return null;
}
}
@Override
public byte[] rawSignDigestWithPrivateKey(AndroidPrivateKey key, byte[] message) {
RemotePrivateKey remoteKey = (RemotePrivateKey) key;
try {
Log.d(TAG, "rawSignDigestWithPrivateKey");
return mRemoteManager.rawSignDigestWithPrivateKey(remoteKey.getHandle(), message);
} catch (RemoteException e) {
e.printStackTrace();
return null;
}
}
@Override
public int getPrivateKeyType(AndroidPrivateKey key) {
RemotePrivateKey remoteKey = (RemotePrivateKey) key;
try {
Log.d(TAG, "getPrivateKeyType");
return mRemoteManager.getPrivateKeyType(remoteKey.getHandle());
} catch (RemoteException e) {
e.printStackTrace();
return 0;
}
}
@Override
public byte[] getPrivateKeyEncodedBytes(AndroidPrivateKey key) {
// This should not be called as it's only for older versions of Android.
assert false;
return null;
}
@Override
public int getOpenSSLHandleForPrivateKey(AndroidPrivateKey privateKey) {
// This should not be called as it's only for older versions of Android.
assert false;
return 0;
}
public AndroidPrivateKey createKey(String alias) {
try {
int handle = mRemoteManager.getPrivateKeyHandle(alias);
return new RemotePrivateKey(handle, this);
} catch (RemoteException e) {
e.printStackTrace();
return null;
}
}
@Override
public void releaseKey(AndroidPrivateKey key) {
RemotePrivateKey remoteKey = (RemotePrivateKey) key;
try {
Log.d(TAG, "releaseKey");
mRemoteManager.releaseKey(remoteKey.getHandle());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
......@@ -9,8 +9,8 @@
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/logging.h"
#include "jni/AndroidKeyStore_jni.h"
#include "net/android/android_private_key.h"
using base::android::AttachCurrentThread;
using base::android::HasException;
......@@ -28,7 +28,9 @@ bool GetRSAKeyModulus(
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jbyteArray> modulus_ref =
Java_AndroidKeyStore_getRSAKeyModulus(env, private_key_ref);
Java_AndroidKeyStore_getRSAKeyModulus(env,
GetKeyStore(private_key_ref).obj(),
private_key_ref);
if (modulus_ref.is_null())
return false;
......@@ -41,7 +43,10 @@ bool GetDSAKeyParamQ(jobject private_key_ref,
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jbyteArray> q_ref =
Java_AndroidKeyStore_getDSAKeyParamQ(env, private_key_ref);
Java_AndroidKeyStore_getDSAKeyParamQ(
env,
GetKeyStore(private_key_ref).obj(),
private_key_ref);
if (q_ref.is_null())
return false;
......@@ -54,7 +59,11 @@ bool GetECKeyOrder(jobject private_key_ref,
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jbyteArray> order_ref =
Java_AndroidKeyStore_getECKeyOrder(env, private_key_ref);
Java_AndroidKeyStore_getECKeyOrder(
env,
GetKeyStore(private_key_ref).obj(),
private_key_ref);
if (order_ref.is_null())
return false;
......@@ -62,12 +71,15 @@ bool GetECKeyOrder(jobject private_key_ref,
return true;
}
bool GetPrivateKeyEncodedBytes(jobject private_key,
bool GetPrivateKeyEncodedBytes(jobject private_key_ref,
std::vector<uint8>* result) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jbyteArray> encoded_ref =
Java_AndroidKeyStore_getPrivateKeyEncodedBytes(env, private_key);
Java_AndroidKeyStore_getPrivateKeyEncodedBytes(
env,
GetKeyStore(private_key_ref).obj(),
private_key_ref);
if (encoded_ref.is_null())
return false;
......@@ -91,7 +103,10 @@ bool RawSignDigestWithPrivateKey(
// Invoke platform API
ScopedJavaLocalRef<jbyteArray> signature_ref =
Java_AndroidKeyStore_rawSignDigestWithPrivateKey(
env, private_key_ref, digest_ref.obj());
env,
GetKeyStore(private_key_ref).obj(),
private_key_ref,
digest_ref.obj());
if (HasException(env) || signature_ref.is_null())
return false;
......@@ -100,14 +115,16 @@ bool RawSignDigestWithPrivateKey(
return true;
}
PrivateKeyType GetPrivateKeyType(jobject private_key) {
PrivateKeyType GetPrivateKeyType(jobject private_key_ref) {
JNIEnv* env = AttachCurrentThread();
int type = Java_AndroidKeyStore_getPrivateKeyType(
env, private_key);
env,
GetKeyStore(private_key_ref).obj(),
private_key_ref);
return static_cast<PrivateKeyType>(type);
}
EVP_PKEY* GetOpenSSLSystemHandleForPrivateKey(jobject private_key) {
EVP_PKEY* GetOpenSSLSystemHandleForPrivateKey(jobject private_key_ref) {
JNIEnv* env = AttachCurrentThread();
// Note: the pointer is passed as a jint here because that's how it
// is stored in the Java object. Java doesn't have a primitive type
......@@ -117,11 +134,21 @@ EVP_PKEY* GetOpenSSLSystemHandleForPrivateKey(jobject private_key) {
// Given that this routine shall only be called on Android < 4.2,
// this won't be a problem in the far future (e.g. when Android gets
// ported to 64-bit environments, if ever).
int pkey =
Java_AndroidKeyStore_getOpenSSLHandleForPrivateKey(env, private_key);
int pkey = Java_AndroidKeyStore_getOpenSSLHandleForPrivateKey(
env,
GetKeyStore(private_key_ref).obj(),
private_key_ref);
return reinterpret_cast<EVP_PKEY*>(pkey);
}
void ReleaseKey(jobject private_key_ref) {
JNIEnv* env = AttachCurrentThread();
Java_AndroidKeyStore_releaseKey(env,
GetKeyStore(private_key_ref).obj(),
private_key_ref);
env->DeleteGlobalRef(private_key_ref);
}
bool RegisterKeyStore(JNIEnv* env) {
return RegisterNativesImpl(env);
}
......
......@@ -108,6 +108,8 @@ NET_EXPORT PrivateKeyType GetPrivateKeyType(jobject private_key);
// the returned key's reference count.
EVP_PKEY* GetOpenSSLSystemHandleForPrivateKey(jobject private_key);
NET_EXPORT void ReleaseKey(jobject private_key);
// Register JNI methods
NET_EXPORT bool RegisterKeyStore(JNIEnv* env);
......
......@@ -208,8 +208,7 @@ int RsaMethodFinish(RSA* rsa) {
jobject key = reinterpret_cast<jobject>(RSA_get_app_data(rsa));
if (key != NULL) {
RSA_set_app_data(rsa, NULL);
JNIEnv* env = base::android::AttachCurrentThread();
env->DeleteGlobalRef(key);
ReleaseKey(key);
}
// Actual return value is ignored by OpenSSL. There are no docs
// explaining what this is supposed to be.
......@@ -413,8 +412,7 @@ int DsaMethodFinish(DSA* dsa) {
jobject key = reinterpret_cast<jobject>(DSA_get_ex_data(dsa,0));
if (key != NULL) {
DSA_set_ex_data(dsa, 0, NULL);
JNIEnv* env = base::android::AttachCurrentThread();
env->DeleteGlobalRef(key);
ReleaseKey(key);
}
// Actual return value is ignored by OpenSSL. There are no docs
// explaining what this is supposed to be.
......@@ -493,9 +491,7 @@ void ExDataFree(void* parent,
return;
CRYPTO_set_ex_data(ad, idx, NULL);
JNIEnv* env = base::android::AttachCurrentThread();
env->DeleteGlobalRef(private_key);
ReleaseKey(private_key);
}
int ExDataDup(CRYPTO_EX_DATA* to,
......
......@@ -7,6 +7,7 @@
#include "base/basictypes.h"
#include "base/android/jni_android.h"
#include "base/android/jni_registrar.h"
#include "net/android/android_private_key.h"
#include "net/android/gurl_utils.h"
#include "net/android/keystore.h"
#include "net/android/network_change_notifier_android.h"
......@@ -19,6 +20,7 @@ namespace android {
static base::android::RegistrationMethod kNetRegisteredMethods[] = {
{ "AndroidCertVerifyResult", net::android::RegisterCertVerifyResult },
{ "AndroidPrivateKey", net::android::RegisterAndroidPrivateKey},
{ "AndroidKeyStore", net::android::RegisterKeyStore },
{ "AndroidNetworkLibrary", net::android::RegisterNetworkLibrary },
{ "GURLUtils", net::RegisterGURLUtils },
......
......@@ -65,6 +65,8 @@
'android/cert_verify_status_android_list.h',
'android/gurl_utils.cc',
'android/gurl_utils.h',
'android/android_private_key.cc',
'android/android_private_key.h',
'android/keystore.cc',
'android/keystore.h',
'android/keystore_openssl.cc',
......@@ -3035,6 +3037,7 @@
'android/java/src/org/chromium/net/AndroidCertVerifyResult.java',
'android/java/src/org/chromium/net/AndroidKeyStore.java',
'android/java/src/org/chromium/net/AndroidNetworkLibrary.java',
'android/java/src/org/chromium/net/AndroidPrivateKey.java',
'android/java/src/org/chromium/net/GURLUtils.java',
'android/java/src/org/chromium/net/NetworkChangeNotifier.java',
'android/java/src/org/chromium/net/ProxyChangeListener.java',
......@@ -3070,9 +3073,24 @@
'certificate_mime_types_java',
'net_errors_java',
'private_key_types_java',
'remote_android_keystore_aidl',
],
'includes': [ '../build/java.gypi' ],
},
{
# Processes the interface files for communication with an Android KeyStore
# running in a separate process.
'target_name': 'remote_android_keystore_aidl',
'type': 'none',
'variables': {
'aidl_interface_file': '../net/android/java/src/org/chromium/net/IRemoteAndroidKeyStoreInterface.aidl',
},
'sources': [
'../net/android/java/src/org/chromium/net/IRemoteAndroidKeyStore.aidl',
'../net/android/java/src/org/chromium/net/IRemoteAndroidKeyStoreCallbacks.aidl',
],
'includes': [ '../build/java_aidl.gypi' ],
},
{
'target_name': 'net_java_test_support',
'type': 'none',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment