Fix RSA and ECDSA key import in softkeymaster.
Bug: 20055613
Change-Id: Ie1998476659cb4c9e1311f0391cc3a6ecb9204ca
diff --git a/google_keymaster_test.cpp b/google_keymaster_test.cpp
index 7284377..70201d4 100644
--- a/google_keymaster_test.cpp
+++ b/google_keymaster_test.cpp
@@ -20,6 +20,8 @@
#include <openssl/engine.h>
+#include <hardware/keymaster0.h>
+
#include <keymaster/google_keymaster_utils.h>
#include <keymaster/keymaster_tags.h>
#include <keymaster/soft_keymaster_device.h>
@@ -1083,6 +1085,25 @@
VerifyMessage(message, signature);
}
+TEST_F(ImportKeyTest, OldApiRsaSuccess) {
+ string pk8_key = read_file("rsa_privkey_pk8.der");
+ ASSERT_EQ(633U, pk8_key.size());
+
+ // NOTE: This will break when the keymaster0 APIs are removed from keymaster1. But at that
+ // point softkeymaster will no longer support keymaster0 APIs anyway.
+ uint8_t* key_blob;
+ size_t key_blob_length;
+ ASSERT_EQ(0,
+ device()->import_keypair(device(), reinterpret_cast<const uint8_t*>(pk8_key.data()),
+ pk8_key.size(), &key_blob, &key_blob_length));
+ set_key_blob(key_blob, key_blob_length);
+
+ string message(1024 / 8, 'a');
+ string signature;
+ SignMessage(message, &signature, false /* use_client_params */);
+ VerifyMessage(message, signature, false /* use_client_params */);
+}
+
TEST_F(ImportKeyTest, RsaKeySizeMismatch) {
string pk8_key = read_file("rsa_privkey_pk8.der");
ASSERT_EQ(633U, pk8_key.size());
diff --git a/google_keymaster_test_utils.cpp b/google_keymaster_test_utils.cpp
index 7f39478..34bc1dd 100644
--- a/google_keymaster_test_utils.cpp
+++ b/google_keymaster_test_utils.cpp
@@ -219,8 +219,11 @@
keymaster_error_t Keymaster1Test::BeginOperation(keymaster_purpose_t purpose,
const AuthorizationSet& input_set,
- AuthorizationSet* output_set) {
- AuthorizationSet additional_params(client_params_, array_length(client_params_));
+ AuthorizationSet* output_set,
+ bool use_client_params) {
+ AuthorizationSet additional_params;
+ if (use_client_params)
+ additional_params.push_back(AuthorizationSet(client_params_, array_length(client_params_)));
additional_params.push_back(input_set);
keymaster_key_param_t* out_params;
@@ -299,9 +302,11 @@
return device()->abort(device(), op_handle_);
}
-string Keymaster1Test::ProcessMessage(keymaster_purpose_t purpose, const string& message) {
+string Keymaster1Test::ProcessMessage(keymaster_purpose_t purpose, const string& message,
+ bool use_client_params) {
AuthorizationSet input_params;
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, input_params, NULL /* output_params */));
+ EXPECT_EQ(KM_ERROR_OK,
+ BeginOperation(purpose, input_params, NULL /* output_params */, use_client_params));
string result;
size_t input_consumed;
@@ -326,9 +331,10 @@
}
string Keymaster1Test::ProcessMessage(keymaster_purpose_t purpose, const string& message,
- const string& signature) {
+ const string& signature, bool use_client_params) {
AuthorizationSet input_params;
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, input_params, NULL /* output_params */));
+ EXPECT_EQ(KM_ERROR_OK,
+ BeginOperation(purpose, input_params, NULL /* output_params */, use_client_params));
string result;
size_t input_consumed;
@@ -338,15 +344,16 @@
return result;
}
-void Keymaster1Test::SignMessage(const string& message, string* signature) {
+void Keymaster1Test::SignMessage(const string& message, string* signature, bool use_client_params) {
SCOPED_TRACE("SignMessage");
- *signature = ProcessMessage(KM_PURPOSE_SIGN, message);
+ *signature = ProcessMessage(KM_PURPOSE_SIGN, message, use_client_params);
EXPECT_GT(signature->size(), 0);
}
-void Keymaster1Test::VerifyMessage(const string& message, const string& signature) {
+void Keymaster1Test::VerifyMessage(const string& message, const string& signature,
+ bool use_client_params) {
SCOPED_TRACE("VerifyMessage");
- ProcessMessage(KM_PURPOSE_VERIFY, message, signature);
+ ProcessMessage(KM_PURPOSE_VERIFY, message, signature, use_client_params);
}
string Keymaster1Test::EncryptMessage(const string& message, string* generated_nonce) {
diff --git a/google_keymaster_test_utils.h b/google_keymaster_test_utils.h
index 6e2444f..a9a2d8e 100644
--- a/google_keymaster_test_utils.h
+++ b/google_keymaster_test_utils.h
@@ -165,7 +165,8 @@
keymaster_error_t BeginOperation(keymaster_purpose_t purpose);
keymaster_error_t BeginOperation(keymaster_purpose_t purpose, const AuthorizationSet& input_set,
- AuthorizationSet* output_set = NULL);
+ AuthorizationSet* output_set = NULL,
+ bool use_client_params = true);
keymaster_error_t UpdateOperation(const std::string& message, std::string* output,
size_t* input_consumed);
@@ -185,17 +186,20 @@
keymaster_error_t Rescope(const AuthorizationSet& new_params,
keymaster_key_blob_t* rescoped_blob,
keymaster_key_characteristics_t** rescoped_characteristics);
- std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message);
+ std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message,
+ bool use_client_params = true);
std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message,
const AuthorizationSet& begin_params,
const AuthorizationSet& update_params,
AuthorizationSet* output_params = NULL);
std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message,
- const std::string& signature);
+ const std::string& signature, bool use_client_params = true);
- void SignMessage(const std::string& message, std::string* signature);
+ void SignMessage(const std::string& message, std::string* signature,
+ bool use_client_params = true);
- void VerifyMessage(const std::string& message, const std::string& signature);
+ void VerifyMessage(const std::string& message, const std::string& signature,
+ bool use_client_params = true);
std::string EncryptMessage(const std::string& message, std::string* generated_nonce = NULL);
std::string EncryptMessage(const AuthorizationSet& update_params, const std::string& message,
@@ -238,6 +242,12 @@
void corrupt_key_blob();
+ void set_key_blob(const uint8_t* key, size_t key_length) {
+ FreeKeyBlob();
+ blob_.key_material = key;
+ blob_.key_material_size = key_length;
+ }
+
private:
keymaster1_device_t* device_;
keymaster_blob_t client_id_ = {.data = reinterpret_cast<const uint8_t*>("app_id"),
diff --git a/include/keymaster/soft_keymaster_device.h b/include/keymaster/soft_keymaster_device.h
index 0a1e2f3..4accf74 100644
--- a/include/keymaster/soft_keymaster_device.h
+++ b/include/keymaster/soft_keymaster_device.h
@@ -55,6 +55,8 @@
const uint8_t* key_blob, size_t key_blob_length,
AuthorizationSet* auth_set);
static void StoreDefaultNewKeyParams(AuthorizationSet* auth_set);
+ static keymaster_error_t GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
+ keymaster_algorithm_t* algorithm);
static int close_device(hw_device_t* dev);
diff --git a/soft_keymaster_device.cpp b/soft_keymaster_device.cpp
index 3ddce33..b1e0161 100644
--- a/soft_keymaster_device.cpp
+++ b/soft_keymaster_device.cpp
@@ -27,6 +27,8 @@
#include <type_traits>
+#include <openssl/x509.h>
+
#include <hardware/keymaster1.h>
#define LOG_TAG "SoftKeymasterDevice"
#include <cutils/log.h>
@@ -228,6 +230,11 @@
ImportKeyRequest request;
StoreDefaultNewKeyParams(&request.key_description);
+ keymaster_algorithm_t algorithm;
+ keymaster_error_t err = GetPkcs8KeyAlgorithm(key, key_length, &algorithm);
+ if (err != KM_ERROR_OK)
+ return err;
+ request.key_description.push_back(TAG_ALGORITHM, algorithm);
request.SetKeyMaterial(key, key_length);
request.key_format = KM_KEY_FORMAT_PKCS8;
@@ -250,6 +257,50 @@
return KM_ERROR_OK;
}
+struct EVP_PKEY_Delete {
+ void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
+};
+
+struct PKCS8_PRIV_KEY_INFO_Delete {
+ void operator()(PKCS8_PRIV_KEY_INFO* p) const { PKCS8_PRIV_KEY_INFO_free(p); }
+};
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
+ keymaster_algorithm_t* algorithm) {
+ if (key == NULL) {
+ LOG_E("No key specified for import", 0);
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ }
+
+ UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> pkcs8(
+ d2i_PKCS8_PRIV_KEY_INFO(NULL, &key, key_length));
+ if (pkcs8.get() == NULL) {
+ LOG_E("Could not parse PKCS8 key blob", 0);
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKCS82PKEY(pkcs8.get()));
+ if (pkey.get() == NULL) {
+ LOG_E("Could not extract key from PKCS8 key blob", 0);
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+
+ switch (EVP_PKEY_type(pkey->type)) {
+ case EVP_PKEY_RSA:
+ *algorithm = KM_ALGORITHM_RSA;
+ break;
+ case EVP_PKEY_EC:
+ *algorithm = KM_ALGORITHM_ECDSA;
+ break;
+ default:
+ LOG_E("Unsupported algorithm %d", EVP_PKEY_type(pkey->type));
+ return KM_ERROR_UNSUPPORTED_ALGORITHM;
+ }
+
+ return KM_ERROR_OK;
+}
+
/* static */
int SoftKeymasterDevice::get_keypair_public(const struct keymaster1_device* dev,
const uint8_t* key_blob, const size_t key_blob_length,