summaryrefslogtreecommitdiffstats
path: root/keystore
diff options
context:
space:
mode:
Diffstat (limited to 'keystore')
-rw-r--r--keystore/java/android/security/IKeyChainAliasCallback.aidl (renamed from keystore/java/android/security/IKeyChainAliasResponse.aidl)2
-rw-r--r--keystore/java/android/security/KeyChain.java124
-rw-r--r--keystore/java/android/security/KeyChainAliasCallback.java (renamed from keystore/java/android/security/KeyChainAliasResponse.java)8
-rw-r--r--keystore/java/android/security/KeyChainException.java67
4 files changed, 186 insertions, 15 deletions
diff --git a/keystore/java/android/security/IKeyChainAliasResponse.aidl b/keystore/java/android/security/IKeyChainAliasCallback.aidl
index e042001..1ea9521 100644
--- a/keystore/java/android/security/IKeyChainAliasResponse.aidl
+++ b/keystore/java/android/security/IKeyChainAliasCallback.aidl
@@ -20,7 +20,7 @@ package android.security;
*
* @hide
*/
-interface IKeyChainAliasResponse {
+interface IKeyChainAliasCallback {
void alias(String alias);
}
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index ba784ed..39d65be 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -36,6 +36,7 @@ import java.io.IOException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
@@ -47,8 +48,38 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
- * @hide
+ * The {@code KeyChain} class provides access to private keys and
+ * their corresponding certificate chains in credential storage.
+ *
+ * <p>Applications accessing the {@code KeyChain} normally go through
+ * these steps:
+ *
+ * <ol>
+ *
+ * <li>Receive a callback from an {@link javax.net.ssl.X509KeyManager
+ * X509KeyManager} that a private key is requested.
+ *
+ * <li>Call {@link #choosePrivateKeyAlias
+ * choosePrivateKeyAlias} to allow the user to select from a
+ * list of currently available private keys and corresponding
+ * certificate chains. The chosen alias will be returned by the
+ * callback {@link KeyChainAliasCallback#alias}, or null if no private
+ * key is available or the user cancels the request.
+ *
+ * <li>Call {@link #getPrivateKey} and {@link #getCertificateChain} to
+ * retrieve the credentials to return to the corresponding {@link
+ * javax.net.ssl.X509KeyManager} callbacks.
+ *
+ * </ol>
+ *
+ * <p>An application may remember the value of a selected alias to
+ * avoid prompting the user with {@link #choosePrivateKeyAlias
+ * choosePrivateKeyAlias} on subsequent connections. If the alias is
+ * no longer valid, null will be returned on lookups using that value
+ *
+ * @hide to be unhidden as part of KeyChain API
*/
+// TODO reference intent for credential installation when public
public final class KeyChain {
private static final String TAG = "KeyChain";
@@ -67,9 +98,58 @@ public final class KeyChain {
* Launches an {@code Activity} for the user to select the alias
* for a private key and certificate pair for authentication. The
* selected alias or null will be returned via the
- * IKeyChainAliasResponse callback.
+ * KeyChainAliasCallback callback.
+ *
+ * <p>{@code keyTypes} and {@code issuers} may be used to
+ * highlight suggested choices to the user, although to cope with
+ * sometimes erroneous values provided by servers, the user may be
+ * able to override these suggestions.
+ *
+ * <p>{@code host} and {@code port} may be used to give the user
+ * more context about the server requesting the credentials.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#USE_CREDENTIALS}.
+ *
+ * @param activity The {@link Activity} context to use for
+ * launching the new sub-Activity to prompt the user to select
+ * a private key; used only to call startActivity(); must not
+ * be null.
+ * @param response Callback to invoke when the request completes;
+ * must not be null
+ * @param keyTypes The acceptable types of asymmetric keys such as
+ * "RSA" or "DSA", or a null array.
+ * @param issuers The acceptable certificate issuers for the
+ * certificate matching the private key, or null.
+ * @param host The host name of the server requesting the
+ * certificate, or null if unavailable.
+ * @param port The port number of the server requesting the
+ * certificate, or -1 if unavailable.
*/
- public static void choosePrivateKeyAlias(Activity activity, KeyChainAliasResponse response) {
+ public static void choosePrivateKeyAlias(Activity activity, KeyChainAliasCallback response,
+ String[] keyTypes, Principal[] issuers,
+ String host, int port) {
+ /*
+ * TODO currently keyTypes, issuers, host, and port are
+ * unused. They are meant to follow the semantics and purpose
+ * of X509KeyManager method arguments.
+ *
+ * keyTypes would allow the list to be filtered and typically
+ * will be set correctly by the server. In practice today,
+ * most all users will want only RSA, rarely DSA, and usually
+ * only a small number of certs will be available.
+ *
+ * issuers is typically not useful. Some servers historically
+ * will send the entire list of public CAs known to the
+ * server. Others will send none. If this is used, if there
+ * are no matches after applying the constraint, it should be
+ * ignored.
+ *
+ * host and port may be shown to the user if available, but it
+ * should be clear that they are not validated values, perhaps
+ * shown along with requesting application identity to clarify
+ * the source of the request.
+ */
if (activity == null) {
throw new NullPointerException("activity == null");
}
@@ -81,10 +161,10 @@ public final class KeyChain {
activity.startActivity(intent);
}
- private static class AliasResponse extends IKeyChainAliasResponse.Stub {
+ private static class AliasResponse extends IKeyChainAliasCallback.Stub {
private final Activity activity;
- private final KeyChainAliasResponse keyChainAliasResponse;
- private AliasResponse(Activity activity, KeyChainAliasResponse keyChainAliasResponse) {
+ private final KeyChainAliasCallback keyChainAliasResponse;
+ private AliasResponse(Activity activity, KeyChainAliasCallback keyChainAliasResponse) {
this.activity = activity;
this.keyChainAliasResponse = keyChainAliasResponse;
}
@@ -105,9 +185,9 @@ public final class KeyChain {
}
private static class AliasAccountManagerCallback implements AccountManagerCallback<Bundle> {
- private final KeyChainAliasResponse keyChainAliasResponse;
+ private final KeyChainAliasCallback keyChainAliasResponse;
private final String alias;
- private AliasAccountManagerCallback(KeyChainAliasResponse keyChainAliasResponse,
+ private AliasAccountManagerCallback(KeyChainAliasCallback keyChainAliasResponse,
String alias) {
this.keyChainAliasResponse = keyChainAliasResponse;
this.alias = alias;
@@ -138,9 +218,16 @@ public final class KeyChain {
/**
* Returns the {@code PrivateKey} for the requested alias, or null
* if no there is no result.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#USE_CREDENTIALS}.
+ *
+ * @param alias The alias of the desired private key, typically
+ * returned via {@link KeyChainAliasCallback#alias}.
+ * @throws KeyChainException if the alias was valid but there was some problem accessing it.
*/
public static PrivateKey getPrivateKey(Context context, String alias)
- throws InterruptedException, RemoteException {
+ throws KeyChainException, InterruptedException {
if (alias == null) {
throw new NullPointerException("alias == null");
}
@@ -153,6 +240,11 @@ public final class KeyChain {
IKeyChainService keyChainService = keyChainConnection.getService();
byte[] privateKeyBytes = keyChainService.getPrivateKey(alias, authToken);
return toPrivateKey(privateKeyBytes);
+ } catch (RemoteException e) {
+ throw new KeyChainException(e);
+ } catch (RuntimeException e) {
+ // only certain RuntimeExceptions can be propagated across the IKeyChainService call
+ throw new KeyChainException(e);
} finally {
keyChainConnection.close();
}
@@ -161,9 +253,16 @@ public final class KeyChain {
/**
* Returns the {@code X509Certificate} chain for the requested
* alias, or null if no there is no result.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#USE_CREDENTIALS}.
+ *
+ * @param alias The alias of the desired certificate chain, typically
+ * returned via {@link KeyChainAliasCallback#alias}.
+ * @throws KeyChainException if the alias was valid but there was some problem accessing it.
*/
public static X509Certificate[] getCertificateChain(Context context, String alias)
- throws InterruptedException, RemoteException {
+ throws KeyChainException, InterruptedException {
if (alias == null) {
throw new NullPointerException("alias == null");
}
@@ -176,6 +275,11 @@ public final class KeyChain {
IKeyChainService keyChainService = keyChainConnection.getService();
byte[] certificateBytes = keyChainService.getCertificate(alias, authToken);
return new X509Certificate[] { toCertificate(certificateBytes) };
+ } catch (RemoteException e) {
+ throw new KeyChainException(e);
+ } catch (RuntimeException e) {
+ // only certain RuntimeExceptions can be propagated across the IKeyChainService call
+ throw new KeyChainException(e);
} finally {
keyChainConnection.close();
}
diff --git a/keystore/java/android/security/KeyChainAliasResponse.java b/keystore/java/android/security/KeyChainAliasCallback.java
index bcca123..daa348b 100644
--- a/keystore/java/android/security/KeyChainAliasResponse.java
+++ b/keystore/java/android/security/KeyChainAliasCallback.java
@@ -20,12 +20,12 @@ import java.security.PrivateKey;
import java.security.cert.X509Certificate;
/**
- * The KeyChainAliasResponse is the callback for {@link
- * KeyChain#chooseAlias}.
+ * The KeyChainAliasCallback is the callback for {@link
+ * KeyChain#choosePrivateKeyAlias}.
*
- * @hide
+ * @hide to be unhidden as part of KeyChain API
*/
-public interface KeyChainAliasResponse {
+public interface KeyChainAliasCallback {
/**
* Called with the alias of the certificate chosen by the user, or
diff --git a/keystore/java/android/security/KeyChainException.java b/keystore/java/android/security/KeyChainException.java
new file mode 100644
index 0000000..3953f58
--- /dev/null
+++ b/keystore/java/android/security/KeyChainException.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * Thrown on problems accessing the {@link KeyChain}.
+ *
+ * @hide to be unhidden as part of KeyChain API
+ */
+public class KeyChainException extends Exception {
+
+ /**
+ * Constructs a new {@code KeyChainException} that includes the
+ * current stack trace.
+ */
+ public KeyChainException() {
+ }
+
+ /**
+ * Constructs a new {@code KeyChainException} with the current stack
+ * trace and the specified detail message.
+ *
+ * @param detailMessage
+ * the detail message for this exception.
+ */
+ public KeyChainException(String detailMessage) {
+ super(detailMessage);
+ }
+
+ /**
+ * Constructs a new {@code KeyChainException} with the current stack
+ * trace, the specified detail message and the specified cause.
+ *
+ * @param message
+ * the detail message for this exception.
+ * @param cause
+ * the cause of this exception, may be {@code null}.
+ */
+ public KeyChainException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a new {@code KeyChainException} with the current stack
+ * trace and the specified cause.
+ *
+ * @param cause
+ * the cause of this exception, may be {@code null}.
+ */
+ public KeyChainException(Throwable cause) {
+ super((cause == null ? null : cause.toString()), cause);
+ }
+}