From 5423e68d5dbe048ec6f042cce52a33f94184e9fb Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Mon, 14 Nov 2011 08:43:13 -0800 Subject: Add signing to keystore Change the keystore to keep the private keys in keystore. When returned, it uses the OpenSSL representation of the key to allow users to use it in various operations through the OpenSSL ENGINE that connects to keystore. Change-Id: I3681f98cb2ec49ffc4a49f3821909313b4ab5735 --- keystore/java/android/security/Credentials.java | 32 ++++++++++ .../java/android/security/IKeyChainService.aidl | 2 +- keystore/java/android/security/KeyChain.java | 28 ++++----- keystore/java/android/security/KeyStore.java | 72 ++++++++++++++++++++++ 4 files changed, 118 insertions(+), 16 deletions(-) (limited to 'keystore/java/android') diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java index f75208d..68ba2b1 100644 --- a/keystore/java/android/security/Credentials.java +++ b/keystore/java/android/security/Credentials.java @@ -26,11 +26,13 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.io.ObjectOutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.nio.charset.Charsets; import java.security.KeyPair; +import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; @@ -73,6 +75,36 @@ public class Credentials { public static final String EXTENSION_PFX = ".pfx"; /** + * Intent extra: name for the user's private key. + */ + public static final String EXTRA_USER_PRIVATE_KEY_NAME = "user_private_key_name"; + + /** + * Intent extra: data for the user's private key in PEM-encoded PKCS#8. + */ + public static final String EXTRA_USER_PRIVATE_KEY_DATA = "user_private_key_data"; + + /** + * Intent extra: name for the user's certificate. + */ + public static final String EXTRA_USER_CERTIFICATE_NAME = "user_certificate_name"; + + /** + * Intent extra: data for the user's certificate in PEM-encoded X.509. + */ + public static final String EXTRA_USER_CERTIFICATE_DATA = "user_certificate_data"; + + /** + * Intent extra: name for CA certificate chain + */ + public static final String EXTRA_CA_CERTIFICATES_NAME = "ca_certificates_name"; + + /** + * Intent extra: data for CA certificate chain in PEM-encoded X.509. + */ + public static final String EXTRA_CA_CERTIFICATES_DATA = "ca_certificates_data"; + + /** * Convert objects to a PEM format, which is used for * CA_CERTIFICATE, USER_CERTIFICATE, and USER_PRIVATE_KEY * entries. diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl index f38f6ce..60fd7f7 100644 --- a/keystore/java/android/security/IKeyChainService.aidl +++ b/keystore/java/android/security/IKeyChainService.aidl @@ -23,7 +23,7 @@ package android.security; */ interface IKeyChainService { // APIs used by KeyChain - byte[] getPrivateKey(String alias); + String requestPrivateKey(String alias); byte[] getCertificate(String alias); // APIs used by CertInstaller diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java index fe03437..483ccb2 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -27,6 +27,7 @@ import android.os.RemoteException; import java.io.ByteArrayInputStream; import java.io.Closeable; import java.io.IOException; +import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.Principal; import java.security.PrivateKey; @@ -39,6 +40,8 @@ import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import libcore.util.Objects; + +import org.apache.harmony.xnet.provider.jsse.OpenSSLEngine; import org.apache.harmony.xnet.provider.jsse.TrustedCertificateStore; /** @@ -301,14 +304,21 @@ public final class KeyChain { } KeyChainConnection keyChainConnection = bind(context); try { - IKeyChainService keyChainService = keyChainConnection.getService(); - byte[] privateKeyBytes = keyChainService.getPrivateKey(alias); - return toPrivateKey(privateKeyBytes); + final IKeyChainService keyChainService = keyChainConnection.getService(); + final String keyId = keyChainService.requestPrivateKey(alias); + if (keyId == null) { + throw new KeyChainException("keystore had a problem"); + } + + final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore"); + return engine.getPrivateKeyById(keyId); } catch (RemoteException e) { throw new KeyChainException(e); } catch (RuntimeException e) { // only certain RuntimeExceptions can be propagated across the IKeyChainService call throw new KeyChainException(e); + } catch (InvalidKeyException e) { + throw new KeyChainException(e); } finally { keyChainConnection.close(); } @@ -356,18 +366,6 @@ public final class KeyChain { } } - private static PrivateKey toPrivateKey(byte[] bytes) { - if (bytes == null) { - throw new IllegalArgumentException("bytes == null"); - } - try { - KeyPair keyPair = (KeyPair) Credentials.convertFromPem(bytes).get(0); - return keyPair.getPrivate(); - } catch (IOException e) { - throw new AssertionError(e); - } - } - private static X509Certificate toCertificate(byte[] bytes) { if (bytes == null) { throw new IllegalArgumentException("bytes == null"); diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 9058cae..a32e469 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -155,6 +155,78 @@ public class KeyStore { return mError == KEY_NOT_FOUND; } + private boolean generate(byte[] key) { + execute('a', key); + return mError == NO_ERROR; + } + + public boolean generate(String key) { + return generate(getBytes(key)); + } + + private boolean importKey(byte[] keyName, byte[] key) { + execute('m', keyName, key); + return mError == NO_ERROR; + } + + public boolean importKey(String keyName, byte[] key) { + return importKey(getBytes(keyName), key); + } + + private byte[] getPubkey(byte[] key) { + ArrayList values = execute('b', key); + return (values == null || values.isEmpty()) ? null : values.get(0); + } + + public byte[] getPubkey(String key) { + return getPubkey(getBytes(key)); + } + + private boolean delKey(byte[] key) { + execute('k', key); + return mError == NO_ERROR; + } + + public boolean delKey(String key) { + return delKey(getBytes(key)); + } + + private byte[] sign(byte[] keyName, byte[] data) { + final ArrayList values = execute('n', keyName, data); + return (values == null || values.isEmpty()) ? null : values.get(0); + } + + public byte[] sign(String key, byte[] data) { + return sign(getBytes(key), data); + } + + private boolean verify(byte[] keyName, byte[] data, byte[] signature) { + execute('v', keyName, data, signature); + return mError == NO_ERROR; + } + + public boolean verify(String key, byte[] data, byte[] signature) { + return verify(getBytes(key), data, signature); + } + + private boolean grant(byte[] key, byte[] uid) { + execute('x', key, uid); + return mError == NO_ERROR; + } + + public boolean grant(String key, int uid) { + return grant(getBytes(key), Integer.toString(uid).getBytes()); + } + + private boolean ungrant(byte[] key, byte[] uid) { + execute('y', key, uid); + return mError == NO_ERROR; + } + + public boolean ungrant(String key, int uid) { + return ungrant(getBytes(key), Integer.toString(uid).getBytes()); + } + public int getLastError() { return mError; } -- cgit v1.1