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,