Merge "Cleanup logic for per-op auth keys." into mnc-dev

This commit is contained in:
Alex Klyubin
2015-04-30 19:44:13 +00:00
committed by Android (Google) Code Review
5 changed files with 174 additions and 66 deletions

View File

@@ -22,6 +22,7 @@ import android.security.keymaster.KeymasterDefs;
import android.security.keymaster.OperationResult;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
@@ -298,38 +299,36 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
mAdditionalEntropyForBegin = null;
if (opResult == null) {
throw new KeyStoreConnectException();
} else if ((opResult.resultCode != KeyStore.NO_ERROR)
&& (opResult.resultCode != KeyStore.OP_AUTH_NEEDED)) {
switch (opResult.resultCode) {
case KeymasterDefs.KM_ERROR_INVALID_NONCE:
throw new InvalidAlgorithmParameterException("Invalid IV");
}
throw mKeyStore.getInvalidKeyException(mKey.getAlias(), opResult.resultCode);
}
if (opResult.token == null) {
throw new IllegalStateException("Keystore returned null operation token");
}
// The operation handle/token is now either valid for use immediately or needs to be
// authorized through user authentication (if the error code was OP_AUTH_NEEDED).
// Store operation token and handle regardless of the error code returned by KeyStore to
// ensure that the operation gets aborted immediately if the code below throws an exception.
mOperationToken = opResult.token;
mOperationHandle = opResult.operationHandle;
// If necessary, throw an exception due to KeyStore operation having failed.
GeneralSecurityException e = KeyStoreCryptoOperationUtils.getExceptionForCipherInit(
mKeyStore, mKey, opResult.resultCode);
if (e != null) {
if (e instanceof InvalidKeyException) {
throw (InvalidKeyException) e;
} else if (e instanceof InvalidAlgorithmParameterException) {
throw (InvalidAlgorithmParameterException) e;
} else {
throw new RuntimeException("Unexpected exception type", e);
}
}
if (mOperationToken == null) {
throw new IllegalStateException("Keystore returned null operation token");
}
loadAlgorithmSpecificParametersFromBeginResult(keymasterOutputArgs);
mFirstOperationInitiated = true;
mIvHasBeenUsed = true;
mMainDataStreamer = new KeyStoreCryptoOperationChunkedStreamer(
new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
mKeyStore, opResult.token));
if (opResult.resultCode != KeyStore.NO_ERROR) {
// The operation requires user authentication. Check whether such authentication is
// possible (e.g., the key may have been permanently invalidated).
InvalidKeyException e =
mKeyStore.getInvalidKeyException(mKey.getAlias(), opResult.resultCode);
if (!(e instanceof UserNotAuthenticatedException)) {
throw e;
}
}
}
@Override

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2015 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;
import android.security.keymaster.KeymasterDefs;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
/**
* Assorted utility methods for implementing crypto operations on top of KeyStore.
*
* @hide
*/
abstract class KeyStoreCryptoOperationUtils {
private KeyStoreCryptoOperationUtils() {}
/**
* Returns the {@link InvalidKeyException} to be thrown by the {@code init} method of
* the crypto operation in response to {@code KeyStore.begin} operation or {@code null} if
* the {@code init} method should succeed.
*/
static InvalidKeyException getInvalidKeyExceptionForInit(
KeyStore keyStore, KeyStoreKey key, int beginOpResultCode) {
if (beginOpResultCode == KeyStore.NO_ERROR) {
return null;
}
// An error occured. However, some errors should not lead to init throwing an exception.
// See below.
InvalidKeyException e =
keyStore.getInvalidKeyException(key.getAlias(), beginOpResultCode);
switch (beginOpResultCode) {
case KeyStore.OP_AUTH_NEEDED:
// Operation needs to be authorized by authenticating the user. Don't throw an
// exception is such authentication is possible for this key
// (UserNotAuthenticatedException). An example of when it's not possible is where
// the key is permanently invalidated (KeyPermanentlyInvalidatedException).
if (e instanceof UserNotAuthenticatedException) {
return null;
}
break;
}
return e;
}
/**
* Returns the exception to be thrown by the {@code Cipher.init} method of the crypto operation
* in response to {@code KeyStore.begin} operation or {@code null} if the {@code init} method
* should succeed.
*/
static GeneralSecurityException getExceptionForCipherInit(
KeyStore keyStore, KeyStoreKey key, int beginOpResultCode) {
if (beginOpResultCode == KeyStore.NO_ERROR) {
return null;
}
// Cipher-specific cases
switch (beginOpResultCode) {
case KeymasterDefs.KM_ERROR_INVALID_NONCE:
return new InvalidAlgorithmParameterException("Invalid IV");
}
// General cases
return getInvalidKeyExceptionForInit(keyStore, key, beginOpResultCode);
}
}

View File

@@ -170,31 +170,27 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp
keymasterOutputArgs);
if (opResult == null) {
throw new KeyStoreConnectException();
} else if ((opResult.resultCode != KeyStore.NO_ERROR)
&& (opResult.resultCode != KeyStore.OP_AUTH_NEEDED)) {
throw mKeyStore.getInvalidKeyException(mKey.getAlias(), opResult.resultCode);
}
if (opResult.token == null) {
throw new IllegalStateException("Keystore returned null operation token");
}
// The operation handle/token is now either valid for use immediately or needs to be
// authorized through user authentication (if the error code was OP_AUTH_NEEDED).
// Store operation token and handle regardless of the error code returned by KeyStore to
// ensure that the operation gets aborted immediately if the code below throws an exception.
mOperationToken = opResult.token;
mOperationHandle = opResult.operationHandle;
// If necessary, throw an exception due to KeyStore operation having failed.
InvalidKeyException e = KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit(
mKeyStore, mKey, opResult.resultCode);
if (e != null) {
throw e;
}
if (mOperationToken == null) {
throw new IllegalStateException("Keystore returned null operation token");
}
mChunkedStreamer = new KeyStoreCryptoOperationChunkedStreamer(
new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
mKeyStore, mOperationToken));
if (opResult.resultCode != KeyStore.NO_ERROR) {
// The operation requires user authentication. Check whether such authentication is
// possible (e.g., the key may have been permanently invalidated).
InvalidKeyException e =
mKeyStore.getInvalidKeyException(mKey.getAlias(), opResult.resultCode);
if (!(e instanceof UserNotAuthenticatedException)) {
throw e;
}
}
}
@Override

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2015 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;
import java.security.Key;
/**
* {@link Key} backed by AndroidKeyStore.
*
* @hide
*/
public class KeyStoreKey implements Key {
private final String mAlias;
private final String mAlgorithm;
public KeyStoreKey(String alias, String algorithm) {
mAlias = alias;
mAlgorithm = algorithm;
}
String getAlias() {
return mAlias;
}
@Override
public String getAlgorithm() {
return mAlgorithm;
}
@Override
public String getFormat() {
// This key does not export its key material
return null;
}
@Override
public byte[] getEncoded() {
// This key does not export its key material
return null;
}
}

View File

@@ -23,33 +23,9 @@ import javax.crypto.SecretKey;
*
* @hide
*/
public class KeyStoreSecretKey implements SecretKey {
private final String mAlias;
private final String mAlgorithm;
public class KeyStoreSecretKey extends KeyStoreKey implements SecretKey {
public KeyStoreSecretKey(String alias, String algorithm) {
mAlias = alias;
mAlgorithm = algorithm;
}
String getAlias() {
return mAlias;
}
@Override
public String getAlgorithm() {
return mAlgorithm;
}
@Override
public String getFormat() {
// This key does not export its key material
return null;
}
@Override
public byte[] getEncoded() {
// This key does not export its key material
return null;
super(alias, algorithm);
}
}