Merge "Multi-threaded keystore" am: 9f248989bf am: cbd890315e

am: 444162a57c

Change-Id: I2c09961a74c7de92d85f3d2045dd065c94bc6fac
This commit is contained in:
Janis Danisevskis
2018-11-15 06:39:39 -08:00
committed by android-build-merger
8 changed files with 418 additions and 29 deletions

View File

@@ -38,11 +38,13 @@ import android.security.keymaster.KeymasterBlob;
import android.security.keymaster.KeymasterCertificateChain;
import android.security.keymaster.KeymasterDefs;
import android.security.keymaster.OperationResult;
import android.security.keystore.IKeystoreService;
import android.security.keystore.KeyExpiredException;
import android.security.keystore.KeyNotYetValidException;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
import android.security.keystore.KeystoreResponse;
import android.security.keystore.StrongBoxUnavailableException;
import android.security.keystore.UserNotAuthenticatedException;
import android.util.Log;
@@ -54,6 +56,8 @@ import java.io.IOException;
import java.security.InvalidKeyException;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import sun.security.util.ObjectIdentifier;
import sun.security.x509.AlgorithmId;
@@ -451,27 +455,107 @@ public class KeyStore {
public boolean addRngEntropy(byte[] data, int flags) {
try {
return mBinder.addRngEntropy(data, flags) == NO_ERROR;
KeystoreResultPromise promise = new KeystoreResultPromise();
int errorCode = mBinder.addRngEntropy(promise, data, flags);
if (errorCode == NO_ERROR) {
return promise.getFuture().get().getErrorCode() == NO_ERROR;
} else {
return false;
}
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return false;
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "AddRngEntropy completed with exception", e);
return false;
}
}
private class KeyCharacteristicsCallbackResult {
private KeystoreResponse keystoreResponse;
private KeyCharacteristics keyCharacteristics;
public KeyCharacteristicsCallbackResult(KeystoreResponse keystoreResponse,
KeyCharacteristics keyCharacteristics) {
this.keystoreResponse = keystoreResponse;
this.keyCharacteristics = keyCharacteristics;
}
public KeystoreResponse getKeystoreResponse() {
return keystoreResponse;
}
public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
this.keystoreResponse = keystoreResponse;
}
public KeyCharacteristics getKeyCharacteristics() {
return keyCharacteristics;
}
public void setKeyCharacteristics(KeyCharacteristics keyCharacteristics) {
this.keyCharacteristics = keyCharacteristics;
}
}
private class KeyCharacteristicsPromise
extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub {
final private CompletableFuture<KeyCharacteristicsCallbackResult> future =
new CompletableFuture<KeyCharacteristicsCallbackResult>();
@Override
public void onFinished(KeystoreResponse keystoreResponse,
KeyCharacteristics keyCharacteristics)
throws android.os.RemoteException {
future.complete(
new KeyCharacteristicsCallbackResult(keystoreResponse, keyCharacteristics));
}
public final CompletableFuture<KeyCharacteristicsCallbackResult> getFuture() {
return future;
}
};
private int generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid,
int flags, KeyCharacteristics outCharacteristics)
throws RemoteException, ExecutionException, InterruptedException {
KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
int error = mBinder.generateKey(promise, alias, args, entropy, uid, flags);
if (error != NO_ERROR) {
Log.e(TAG, "generateKeyInternal failed on request " + error);
return error;
}
KeyCharacteristicsCallbackResult result = promise.getFuture().get();
error = result.getKeystoreResponse().getErrorCode();
if (error != NO_ERROR) {
Log.e(TAG, "generateKeyInternal failed on response " + error);
return error;
}
KeyCharacteristics characteristics = result.getKeyCharacteristics();
if (characteristics == null) {
Log.e(TAG, "generateKeyInternal got empty key cheractariestics " + error);
return SYSTEM_ERROR;
}
outCharacteristics.shallowCopyFrom(characteristics);
return NO_ERROR;
}
public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
int flags, KeyCharacteristics outCharacteristics) {
try {
entropy = entropy != null ? entropy : new byte[0];
args = args != null ? args : new KeymasterArguments();
int error = mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
int error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
if (error == KEY_ALREADY_EXISTS) {
mBinder.del(alias, uid);
error = mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
}
return error;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "generateKey completed with exception", e);
return SYSTEM_ERROR;
}
}
@@ -485,10 +569,24 @@ public class KeyStore {
try {
clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
return mBinder.getKeyCharacteristics(alias, clientId, appId, uid, outCharacteristics);
KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid);
if (error != NO_ERROR) return error;
KeyCharacteristicsCallbackResult result = promise.getFuture().get();
error = result.getKeystoreResponse().getErrorCode();
if (error != NO_ERROR) return error;
KeyCharacteristics characteristics = result.getKeyCharacteristics();
if (characteristics == null) return SYSTEM_ERROR;
outCharacteristics.shallowCopyFrom(characteristics);
return NO_ERROR;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "GetKeyCharacteristics completed with exception", e);
return SYSTEM_ERROR;
}
}
@@ -497,20 +595,40 @@ public class KeyStore {
return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
}
private int importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData,
int uid, int flags, KeyCharacteristics outCharacteristics)
throws RemoteException, ExecutionException, InterruptedException {
KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags);
if (error != NO_ERROR) return error;
KeyCharacteristicsCallbackResult result = promise.getFuture().get();
error = result.getKeystoreResponse().getErrorCode();
if (error != NO_ERROR) return error;
KeyCharacteristics characteristics = result.getKeyCharacteristics();
if (characteristics == null) return SYSTEM_ERROR;
outCharacteristics.shallowCopyFrom(characteristics);
return NO_ERROR;
}
public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
int uid, int flags, KeyCharacteristics outCharacteristics) {
try {
int error = mBinder.importKey(alias, args, format, keyData, uid, flags,
int error = importKeyInternal(alias, args, format, keyData, uid, flags,
outCharacteristics);
if (error == KEY_ALREADY_EXISTS) {
mBinder.del(alias, uid);
error = mBinder.importKey(alias, args, format, keyData, uid, flags,
error = importKeyInternal(alias, args, format, keyData, uid, flags,
outCharacteristics);
}
return error;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "ImportKey completed with exception", e);
return SYSTEM_ERROR;
}
}
@@ -578,34 +696,79 @@ public class KeyStore {
return true;
}
private int importWrappedKeyInternal(String wrappedKeyAlias, byte[] wrappedKey,
String wrappingKeyAlias,
byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid,
KeyCharacteristics outCharacteristics)
throws RemoteException, ExecutionException, InterruptedException {
KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
maskingKey, args, rootSid, fingerprintSid);
if (error != NO_ERROR) return error;
KeyCharacteristicsCallbackResult result = promise.getFuture().get();
error = result.getKeystoreResponse().getErrorCode();
if (error != NO_ERROR) return error;
KeyCharacteristics characteristics = result.getKeyCharacteristics();
if (characteristics == null) return SYSTEM_ERROR;
outCharacteristics.shallowCopyFrom(characteristics);
return NO_ERROR;
}
public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
String wrappingKeyAlias,
byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid,
KeyCharacteristics outCharacteristics) {
// TODO b/119217337 uid parameter gets silently ignored.
try {
int error = mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
int error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
if (error == KEY_ALREADY_EXISTS) {
mBinder.del(wrappedKeyAlias, -1);
error = mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
mBinder.del(wrappedKeyAlias, UID_SELF);
error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
}
return error;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "ImportWrappedKey completed with exception", e);
return SYSTEM_ERROR;
}
}
private class ExportKeyPromise
extends android.security.keystore.IKeystoreExportKeyCallback.Stub {
final private CompletableFuture<ExportResult> future = new CompletableFuture<ExportResult>();
@Override
public void onFinished(ExportResult exportKeyResult) throws android.os.RemoteException {
future.complete(exportKeyResult);
}
public final CompletableFuture<ExportResult> getFuture() {
return future;
}
};
public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
KeymasterBlob appId, int uid) {
try {
clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
return mBinder.exportKey(alias, format, clientId, appId, uid);
ExportKeyPromise promise = new ExportKeyPromise();
int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid);
if (error == NO_ERROR) {
return promise.getFuture().get();
} else {
return new ExportResult(error);
}
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "ExportKey completed with exception", e);
return null;
}
}
public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
@@ -613,15 +776,37 @@ public class KeyStore {
return exportKey(alias, format, clientId, appId, UID_SELF);
}
private class OperationPromise
extends android.security.keystore.IKeystoreOperationResultCallback.Stub {
final private CompletableFuture<OperationResult> future = new CompletableFuture<OperationResult>();
@Override
public void onFinished(OperationResult operationResult) throws android.os.RemoteException {
future.complete(operationResult);
}
public final CompletableFuture<OperationResult> getFuture() {
return future;
}
};
public OperationResult begin(String alias, int purpose, boolean pruneable,
KeymasterArguments args, byte[] entropy, int uid) {
try {
args = args != null ? args : new KeymasterArguments();
entropy = entropy != null ? entropy : new byte[0];
return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
OperationPromise promise = new OperationPromise();
int errorCode = mBinder.begin(promise, getToken(), alias, purpose, pruneable, args,
entropy, uid);
if (errorCode == NO_ERROR) {
return promise.getFuture().get();
} else {
return new OperationResult(errorCode);
}
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "Begin completed with exception", e);
return null;
}
}
@@ -636,10 +821,19 @@ public class KeyStore {
try {
arguments = arguments != null ? arguments : new KeymasterArguments();
input = input != null ? input : new byte[0];
return mBinder.update(token, arguments, input);
OperationPromise promise = new OperationPromise();
int errorCode = mBinder.update(promise, token, arguments, input);
if (errorCode == NO_ERROR) {
return promise.getFuture().get();
} else {
return new OperationResult(errorCode);
}
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "Update completed with exception", e);
return null;
}
}
@@ -649,10 +843,19 @@ public class KeyStore {
arguments = arguments != null ? arguments : new KeymasterArguments();
entropy = entropy != null ? entropy : new byte[0];
signature = signature != null ? signature : new byte[0];
return mBinder.finish(token, arguments, signature, entropy);
OperationPromise promise = new OperationPromise();
int errorCode = mBinder.finish(promise, token, arguments, signature, entropy);
if (errorCode == NO_ERROR) {
return promise.getFuture().get();
} else {
return new OperationResult(errorCode);
}
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "Finish completed with exception", e);
return null;
}
}
@@ -660,12 +863,33 @@ public class KeyStore {
return finish(token, arguments, signature, null);
}
private class KeystoreResultPromise
extends android.security.keystore.IKeystoreResponseCallback.Stub {
final private CompletableFuture<KeystoreResponse> future = new CompletableFuture<KeystoreResponse>();
@Override
public void onFinished(KeystoreResponse keystoreResponse) throws android.os.RemoteException {
future.complete(keystoreResponse);
}
public final CompletableFuture<KeystoreResponse> getFuture() {
return future;
}
};
public int abort(IBinder token) {
try {
return mBinder.abort(token);
KeystoreResultPromise promise = new KeystoreResultPromise();
int errorCode = mBinder.abort(promise, token);
if (errorCode == NO_ERROR) {
return promise.getFuture().get().getErrorCode();
} else {
return errorCode;
}
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "Abort completed with exception", e);
return SYSTEM_ERROR;
}
}
@@ -747,6 +971,47 @@ public class KeyStore {
return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
}
private class KeyAttestationCallbackResult {
private KeystoreResponse keystoreResponse;
private KeymasterCertificateChain certificateChain;
public KeyAttestationCallbackResult(KeystoreResponse keystoreResponse,
KeymasterCertificateChain certificateChain) {
this.keystoreResponse = keystoreResponse;
this.certificateChain = certificateChain;
}
public KeystoreResponse getKeystoreResponse() {
return keystoreResponse;
}
public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
this.keystoreResponse = keystoreResponse;
}
public KeymasterCertificateChain getCertificateChain() {
return certificateChain;
}
public void setCertificateChain(KeymasterCertificateChain certificateChain) {
this.certificateChain = certificateChain;
}
}
private class CertificateChainPromise
extends android.security.keystore.IKeystoreCertificateChainCallback.Stub {
final private CompletableFuture<KeyAttestationCallbackResult> future = new CompletableFuture<KeyAttestationCallbackResult>();
@Override
public void onFinished(KeystoreResponse keystoreResponse,
KeymasterCertificateChain certificateChain) throws android.os.RemoteException {
future.complete(new KeyAttestationCallbackResult(keystoreResponse, certificateChain));
}
public final CompletableFuture<KeyAttestationCallbackResult> getFuture() {
return future;
}
};
public int attestKey(
String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
try {
@@ -756,10 +1021,21 @@ public class KeyStore {
if (outChain == null) {
outChain = new KeymasterCertificateChain();
}
return mBinder.attestKey(alias, params, outChain);
CertificateChainPromise promise = new CertificateChainPromise();
int error = mBinder.attestKey(promise, alias, params);
if (error != NO_ERROR) return error;
KeyAttestationCallbackResult result = promise.getFuture().get();
error = result.getKeystoreResponse().getErrorCode();
if (error == NO_ERROR) {
outChain.shallowCopyFrom(result.getCertificateChain());
}
return error;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "AttestKey completed with exception", e);
return SYSTEM_ERROR;
}
}
@@ -771,10 +1047,21 @@ public class KeyStore {
if (outChain == null) {
outChain = new KeymasterCertificateChain();
}
return mBinder.attestDeviceIds(params, outChain);
CertificateChainPromise promise = new CertificateChainPromise();
int error = mBinder.attestDeviceIds(promise, params);
if (error != NO_ERROR) return error;
KeyAttestationCallbackResult result = promise.getFuture().get();
error = result.getKeystoreResponse().getErrorCode();
if (error == NO_ERROR) {
outChain.shallowCopyFrom(result.getCertificateChain());
}
return error;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "AttestDevicdeIds completed with exception", e);
return SYSTEM_ERROR;
}
}