KeyChain: Implement key generation in Keystore
These are the KeyChain-side changes for implementing generation of
Keystore keys directly by KeyChain.
The core functionality is in this CL, where Keystore (via the standard
Android API) is requested to generate a key whose specification was
provided by the user via the DevicePolicyManager.
See the frameworks/base CL for more details.
Bug: 63388672
Test: cts-tradefed run commandAndExit cts-dev -a armeabi-v7a -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.DeviceOwnerTest#testKeyManagement -l DEBUG
Change-Id: I1f53cec0c31adef3b850282aaff11b655a54a760
diff --git a/src/com/android/keychain/KeyChainService.java b/src/com/android/keychain/KeyChainService.java
index 419da2e..d8bf264 100644
--- a/src/com/android/keychain/KeyChainService.java
+++ b/src/com/android/keychain/KeyChainService.java
@@ -36,10 +36,18 @@
import android.security.IKeyChainService;
import android.security.KeyChain;
import android.security.KeyStore;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.ParcelableKeyGenParameterSpec;
+import android.text.TextUtils;
import android.util.Log;
import com.android.keychain.internal.GrantsDatabase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateFactory;
@@ -109,6 +117,42 @@
mGrantsDb.setIsUserSelectable(alias, isUserSelectable);
}
+ @Override public boolean generateKeyPair(
+ String algorithm, ParcelableKeyGenParameterSpec parcelableSpec) {
+ checkSystemCaller();
+ final KeyGenParameterSpec spec = parcelableSpec.getSpec();
+ final String alias = spec.getKeystoreAlias();
+ // Validate the alias here to avoid relying on KeyGenParameterSpec c'tor preventing
+ // the creation of a KeyGenParameterSpec instance with a non-empty alias.
+ if (TextUtils.isEmpty(alias) || spec.getUid() != KeyStore.UID_SELF) {
+ Log.e(TAG, "Cannot generate key pair with empty alias or specified uid.");
+ return false;
+ }
+
+ try {
+ KeyPairGenerator generator = KeyPairGenerator.getInstance(
+ algorithm, "AndroidKeyStore");
+ // Do not prepend USER_PRIVATE_KEY to the alias because
+ // AndroidKeyStoreKeyPairGeneratorSpi will helpfully prepend that in
+ // generateKeyPair.
+ generator.initialize(spec);
+ KeyPair kp = generator.generateKeyPair();
+ if (kp == null) {
+ Log.e(TAG, "Key generation failed.");
+ return false;
+ }
+ return true;
+ } catch (NoSuchAlgorithmException e) {
+ Log.e(TAG, "Invalid algorithm requested", e);
+ } catch (InvalidAlgorithmParameterException e) {
+ Log.e(TAG, "Invalid algorithm params", e);
+ } catch (NoSuchProviderException e) {
+ Log.e(TAG, "Could not find Keystore.", e);
+ }
+
+ return false;
+ }
+
private void validateAlias(String alias) {
if (alias == null) {
throw new NullPointerException("alias == null");