Provide fallback for keymaster implementations
Some implementations won't support ECDSA or DSA, so provide a fallback
for them by using the softkeymaster implementation. This will allow us
to universally support ECDSA and DSA on all platforms regardless of HAL
version.
(cherry picked from commit 17208e0de5a42722901d803118745cca25fd10c1)
Bug: 10600582
Change-Id: Ic02102cb2b7f66e2ad3469f4edd9d03c4ae3fdf4
diff --git a/keystore/Android.mk b/keystore/Android.mk
index f495f34..47b7e84 100644
--- a/keystore/Android.mk
+++ b/keystore/Android.mk
@@ -20,7 +20,15 @@
LOCAL_CFLAGS := -Wall -Wextra -Werror
LOCAL_SRC_FILES := keystore.cpp keyblob_utils.cpp
LOCAL_C_INCLUDES := external/openssl/include
-LOCAL_SHARED_LIBRARIES := libcutils libcrypto libhardware libkeystore_binder libutils liblog libbinder
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libcutils \
+ libcrypto \
+ libhardware \
+ libkeystore_binder \
+ liblog \
+ libsoftkeymaster \
+ libutils
LOCAL_MODULE := keystore
LOCAL_MODULE_TAGS := optional
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
diff --git a/keystore/include/keystore/keystore.h b/keystore/include/keystore/keystore.h
index 973c447..32354df 100644
--- a/keystore/include/keystore/keystore.h
+++ b/keystore/include/keystore/keystore.h
@@ -48,7 +48,8 @@
*/
enum {
KEYSTORE_FLAG_NONE = 0,
- KEYSTORE_FLAG_ENCRYPTED = 1,
+ KEYSTORE_FLAG_ENCRYPTED = 1 << 0,
+ KEYSTORE_FLAG_FALLBACK = 1 << 1,
};
/**
diff --git a/keystore/keyblob_utils.cpp b/keystore/keyblob_utils.cpp
index fd82d2a..b208073 100644
--- a/keystore/keyblob_utils.cpp
+++ b/keystore/keyblob_utils.cpp
@@ -26,9 +26,11 @@
*
* 4-byte SOFT_KEY_MAGIC
*
- * 4-byte 32-bit integer big endian for public_key_length
+ * 4-byte 32-bit integer big endian for public_key_length. This may be zero
+ * length which indicates the public key should be derived from the
+ * private key.
*
- * public_key_length bytes of public key
+ * public_key_length bytes of public key (may be empty)
*
* 4-byte 32-bit integer big endian for private_key_length
*
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 12d3b44..b4cb64d 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -42,6 +42,8 @@
#include <hardware/keymaster.h>
+#include <keymaster/softkeymaster.h>
+
#include <utils/String8.h>
#include <utils/UniquePtr.h>
#include <utils/Vector.h>
@@ -471,6 +473,18 @@
}
}
+ bool isFallback() const {
+ return mBlob.flags & KEYSTORE_FLAG_FALLBACK;
+ }
+
+ void setFallback(bool fallback) {
+ if (fallback) {
+ mBlob.flags |= KEYSTORE_FLAG_FALLBACK;
+ } else {
+ mBlob.flags &= ~KEYSTORE_FLAG_FALLBACK;
+ }
+ }
+
void setVersion(uint8_t version) {
mBlob.version = version;
}
@@ -1004,6 +1018,23 @@
}
}
+ /*
+ * This will upgrade software-backed keys to hardware-backed keys when
+ * the HAL for the device supports the newer key types.
+ */
+ if (rc == NO_ERROR && type == TYPE_KEY_PAIR
+ && mDevice->common.module->module_api_version >= KEYMASTER_MODULE_API_VERSION_0_2
+ && keyBlob->isFallback()) {
+ ResponseCode imported = importKey(keyBlob->getValue(), keyBlob->getLength(), filename,
+ uid, keyBlob->isEncrypted() ? KEYSTORE_FLAG_ENCRYPTED : KEYSTORE_FLAG_NONE);
+
+ // The HAL allowed the import, reget the key to have the "fresh"
+ // version.
+ if (imported == NO_ERROR) {
+ rc = get(filename, keyBlob, TYPE_KEY_PAIR, uid);
+ }
+ }
+
if (type != TYPE_ANY && keyBlob->getType() != type) {
ALOGW("key found but type doesn't match: %d vs %d", keyBlob->getType(), type);
return KEY_NOT_FOUND;
@@ -1056,16 +1087,26 @@
return SYSTEM_ERROR;
}
+ bool isFallback = false;
rc = mDevice->import_keypair(mDevice, key, keyLen, &data, &dataLength);
if (rc) {
- ALOGE("Error while importing keypair: %d", rc);
- return SYSTEM_ERROR;
+ // If this is an old device HAL, try to fall back to an old version
+ if (mDevice->common.module->module_api_version < KEYMASTER_MODULE_API_VERSION_0_2) {
+ rc = openssl_import_keypair(mDevice, key, keyLen, &data, &dataLength);
+ isFallback = true;
+ }
+
+ if (rc) {
+ ALOGE("Error while importing keypair: %d", rc);
+ return SYSTEM_ERROR;
+ }
}
Blob keyBlob(data, dataLength, NULL, 0, TYPE_KEY_PAIR);
free(data);
keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
+ keyBlob.setFallback(isFallback);
return put(filename, &keyBlob, uid);
}
@@ -1688,6 +1729,7 @@
uint8_t* data;
size_t dataLength;
int rc;
+ bool isFallback = false;
const keymaster_device_t* device = mKeyStore->getDevice();
if (device == NULL) {
@@ -1698,7 +1740,7 @@
return ::SYSTEM_ERROR;
}
- if (keyType == EVP_PKEY_DSA && device->client_version >= 2) {
+ if (keyType == EVP_PKEY_DSA) {
keymaster_dsa_keygen_params_t dsa_params;
memset(&dsa_params, '\0', sizeof(dsa_params));
@@ -1734,8 +1776,13 @@
return ::SYSTEM_ERROR;
}
- rc = device->generate_keypair(device, TYPE_DSA, &dsa_params, &data, &dataLength);
- } else if (keyType == EVP_PKEY_EC && device->client_version >= 2) {
+ if (device->common.module->module_api_version >= KEYMASTER_MODULE_API_VERSION_0_2) {
+ rc = device->generate_keypair(device, TYPE_DSA, &dsa_params, &data, &dataLength);
+ } else {
+ isFallback = true;
+ rc = openssl_generate_keypair(device, TYPE_DSA, &dsa_params, &data, &dataLength);
+ }
+ } else if (keyType == EVP_PKEY_EC) {
keymaster_ec_keygen_params_t ec_params;
memset(&ec_params, '\0', sizeof(ec_params));
@@ -1747,7 +1794,12 @@
}
ec_params.field_size = keySize;
- rc = device->generate_keypair(device, TYPE_EC, &ec_params, &data, &dataLength);
+ if (device->common.module->module_api_version >= KEYMASTER_MODULE_API_VERSION_0_2) {
+ rc = device->generate_keypair(device, TYPE_EC, &ec_params, &data, &dataLength);
+ } else {
+ isFallback = true;
+ rc = openssl_generate_keypair(device, TYPE_EC, &ec_params, &data, &dataLength);
+ }
} else if (keyType == EVP_PKEY_RSA) {
keymaster_rsa_keygen_params_t rsa_params;
memset(&rsa_params, '\0', sizeof(rsa_params));
@@ -1799,6 +1851,8 @@
Blob keyBlob(data, dataLength, NULL, 0, TYPE_KEY_PAIR);
free(data);
+ keyBlob.setFallback(isFallback);
+
return mKeyStore->put(filename.string(), &keyBlob, callingUid);
}
@@ -1863,8 +1917,13 @@
params.digest_type = DIGEST_NONE;
params.padding_type = PADDING_NONE;
- rc = device->sign_data(device, ¶ms, keyBlob.getValue(), keyBlob.getLength(),
- data, length, out, outLength);
+ if (keyBlob.isFallback()) {
+ rc = openssl_sign_data(device, ¶ms, keyBlob.getValue(), keyBlob.getLength(), data,
+ length, out, outLength);
+ } else {
+ rc = device->sign_data(device, ¶ms, keyBlob.getValue(), keyBlob.getLength(), data,
+ length, out, outLength);
+ }
if (rc) {
ALOGW("device couldn't sign data");
return ::SYSTEM_ERROR;
@@ -1910,8 +1969,13 @@
params.digest_type = DIGEST_NONE;
params.padding_type = PADDING_NONE;
- rc = device->verify_data(device, ¶ms, keyBlob.getValue(), keyBlob.getLength(),
- data, dataLength, signature, signatureLength);
+ if (keyBlob.isFallback()) {
+ rc = openssl_verify_data(device, ¶ms, keyBlob.getValue(), keyBlob.getLength(), data,
+ dataLength, signature, signatureLength);
+ } else {
+ rc = device->verify_data(device, ¶ms, keyBlob.getValue(), keyBlob.getLength(), data,
+ dataLength, signature, signatureLength);
+ }
if (rc) {
return ::SYSTEM_ERROR;
} else {
@@ -1958,8 +2022,14 @@
return ::SYSTEM_ERROR;
}
- int rc = device->get_keypair_public(device, keyBlob.getValue(), keyBlob.getLength(), pubkey,
- pubkeyLength);
+ int rc;
+ if (keyBlob.isFallback()) {
+ rc = openssl_get_keypair_public(device, keyBlob.getValue(), keyBlob.getLength(), pubkey,
+ pubkeyLength);
+ } else {
+ rc = device->get_keypair_public(device, keyBlob.getValue(), keyBlob.getLength(), pubkey,
+ pubkeyLength);
+ }
if (rc) {
return ::SYSTEM_ERROR;
}
@@ -1997,7 +2067,7 @@
rc = ::SYSTEM_ERROR;
} else {
// A device doesn't have to implement delete_keypair.
- if (device->delete_keypair != NULL) {
+ if (device->delete_keypair != NULL && !keyBlob.isFallback()) {
if (device->delete_keypair(device, keyBlob.getValue(), keyBlob.getLength())) {
rc = ::SYSTEM_ERROR;
}
@@ -2210,7 +2280,7 @@
if (keyBlob.getType() == ::TYPE_KEY_PAIR) {
// A device doesn't have to implement delete_keypair.
- if (device->delete_keypair != NULL) {
+ if (device->delete_keypair != NULL && !keyBlob.isFallback()) {
if (device->delete_keypair(device, keyBlob.getValue(), keyBlob.getLength())) {
rc = ::SYSTEM_ERROR;
ALOGW("device couldn't remove %s", filename.string());