Revert "Add SoftKeymasterDevice"

This reverts commit 2079ae8a94f7f19e89d94c842a4f4055bb21c39a.
diff --git a/google_keymaster_test.cpp b/google_keymaster_test.cpp
index 6c672be..199b523 100644
--- a/google_keymaster_test.cpp
+++ b/google_keymaster_test.cpp
@@ -25,7 +25,7 @@
 #include <keymaster/keymaster_tags.h>
 
 #include "google_keymaster_test_utils.h"
-#include "soft_keymaster_device.h"
+#include "google_softkeymaster.h"
 
 using std::string;
 using std::ifstream;
@@ -72,189 +72,126 @@
 
 class KeymasterTest : public testing::Test {
   protected:
-    KeymasterTest() : device_(new StdoutLogger), characteristics_(NULL) {
-        blob_.key_material = NULL;
-        RAND_seed("foobar", 6);
-    }
-    ~KeymasterTest() {
-        FreeCharacteristics();
-        FreeKeyBlob();
+    KeymasterTest() : device(5, new StdoutLogger) { RAND_seed("foobar", 6); }
+    ~KeymasterTest() {}
+
+    template <typename T> void ExpectEmptyResponse(const SupportedResponse<T>& response) {
+        EXPECT_EQ(KM_ERROR_OK, response.error);
+        EXPECT_EQ(0U, response.results_length);
     }
 
-    keymaster_device* device() { return reinterpret_cast<keymaster_device*>(device_.hw_device()); }
-
-    template <typename T> void ExpectContains(T val, T* vals, size_t len) {
-        EXPECT_EQ(1U, len);
-        EXPECT_EQ(val, vals[0]);
+    template <typename T> void ExpectResponseContains(T val, const SupportedResponse<T>& response) {
+        EXPECT_EQ(KM_ERROR_OK, response.error);
+        EXPECT_EQ(1U, response.results_length);
+        EXPECT_EQ(val, response.results[0]);
     }
 
-    void FreeCharacteristics() {
-        keymaster_free_characteristics(characteristics_);
-        free(characteristics_);
-        characteristics_ = NULL;
-    }
-
-    void FreeKeyBlob() {
-        free(const_cast<uint8_t*>(blob_.key_material));
-        blob_.key_material = NULL;
-    }
-
-    SoftKeymasterDevice device_;
-
-    AuthorizationSet params_;
-    keymaster_key_blob_t blob_;
-    keymaster_key_characteristics_t* characteristics_;
+    GoogleSoftKeymaster device;
 };
 
 typedef KeymasterTest CheckSupported;
 TEST_F(CheckSupported, SupportedAlgorithms) {
-    EXPECT_EQ(KM_ERROR_OUTPUT_PARAMETER_NULL,
-              device()->get_supported_algorithms(device(), NULL, NULL));
+    // Shouldn't blow up on NULL.
+    device.SupportedAlgorithms(NULL);
 
-    size_t len;
-    keymaster_algorithm_t* algorithms;
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_algorithms(device(), &algorithms, &len));
-    ASSERT_EQ(4U, len);
-    EXPECT_EQ(KM_ALGORITHM_RSA, algorithms[0]);
-    EXPECT_EQ(KM_ALGORITHM_DSA, algorithms[1]);
-    EXPECT_EQ(KM_ALGORITHM_ECDSA, algorithms[2]);
-    EXPECT_EQ(KM_ALGORITHM_AES, algorithms[3]);
-
-    free(algorithms);
+    SupportedResponse<keymaster_algorithm_t> response;
+    device.SupportedAlgorithms(&response);
+    EXPECT_EQ(KM_ERROR_OK, response.error);
+    EXPECT_EQ(4U, response.results_length);
+    EXPECT_EQ(KM_ALGORITHM_RSA, response.results[0]);
+    EXPECT_EQ(KM_ALGORITHM_DSA, response.results[1]);
+    EXPECT_EQ(KM_ALGORITHM_ECDSA, response.results[2]);
+    EXPECT_EQ(KM_ALGORITHM_AES, response.results[3]);
 }
 
 TEST_F(CheckSupported, SupportedBlockModes) {
-    EXPECT_EQ(KM_ERROR_OUTPUT_PARAMETER_NULL,
-              device()->get_supported_block_modes(device(), KM_ALGORITHM_RSA, KM_PURPOSE_ENCRYPT,
-                                                  NULL, NULL));
+    // Shouldn't blow up on NULL.
+    device.SupportedBlockModes(KM_ALGORITHM_RSA, KM_PURPOSE_ENCRYPT, NULL);
 
-    size_t len;
-    keymaster_block_mode_t* modes;
-    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE,
-              device()->get_supported_block_modes(device(), KM_ALGORITHM_RSA, KM_PURPOSE_ENCRYPT,
-                                                  &modes, &len));
+    SupportedResponse<keymaster_block_mode_t> response;
+    device.SupportedBlockModes(KM_ALGORITHM_RSA, KM_PURPOSE_ENCRYPT, &response);
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE, response.error);
 
-    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE,
-              device()->get_supported_block_modes(device(), KM_ALGORITHM_DSA, KM_PURPOSE_ENCRYPT,
-                                                  &modes, &len));
+    device.SupportedBlockModes(KM_ALGORITHM_DSA, KM_PURPOSE_ENCRYPT, &response);
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE, response.error);
 
-    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE,
-              device()->get_supported_block_modes(device(), KM_ALGORITHM_ECDSA, KM_PURPOSE_ENCRYPT,
-                                                  &modes, &len));
+    device.SupportedBlockModes(KM_ALGORITHM_ECDSA, KM_PURPOSE_ENCRYPT, &response);
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE, response.error);
 
-    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE,
-              device()->get_supported_block_modes(device(), KM_ALGORITHM_AES, KM_PURPOSE_ENCRYPT,
-                                                  &modes, &len));
+    device.SupportedBlockModes(KM_ALGORITHM_AES, KM_PURPOSE_ENCRYPT, &response);
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE, response.error);
 }
 
 TEST_F(CheckSupported, SupportedPaddingModes) {
-    EXPECT_EQ(KM_ERROR_OUTPUT_PARAMETER_NULL,
-              device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA, KM_PURPOSE_ENCRYPT,
-                                                    NULL, NULL));
+    // Shouldn't blow up on NULL.
+    device.SupportedPaddingModes(KM_ALGORITHM_RSA, KM_PURPOSE_ENCRYPT, NULL);
 
-    size_t len;
-    keymaster_padding_t* modes;
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA,
-                                                                 KM_PURPOSE_SIGN, &modes, &len));
-    ExpectContains(KM_PAD_NONE, modes, len);
-    free(modes);
+    SupportedResponse<keymaster_padding_t> response;
+    device.SupportedPaddingModes(KM_ALGORITHM_RSA, KM_PURPOSE_SIGN, &response);
+    ExpectResponseContains(KM_PAD_NONE, response);
 
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_DSA,
-                                                                 KM_PURPOSE_SIGN, &modes, &len));
-    ExpectContains(KM_PAD_NONE, modes, len);
-    free(modes);
+    device.SupportedPaddingModes(KM_ALGORITHM_DSA, KM_PURPOSE_SIGN, &response);
+    ExpectResponseContains(KM_PAD_NONE, response);
 
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_ECDSA,
-                                                                 KM_PURPOSE_SIGN, &modes, &len));
-    ExpectContains(KM_PAD_NONE, modes, len);
-    free(modes);
+    device.SupportedPaddingModes(KM_ALGORITHM_ECDSA, KM_PURPOSE_SIGN, &response);
+    ExpectResponseContains(KM_PAD_NONE, response);
 
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_AES,
-                                                                 KM_PURPOSE_SIGN, &modes, &len));
-    EXPECT_EQ(0, len);
-    free(modes);
+    device.SupportedPaddingModes(KM_ALGORITHM_AES, KM_PURPOSE_SIGN, &response);
+    ExpectEmptyResponse(response);
 }
 
 TEST_F(CheckSupported, SupportedDigests) {
-    EXPECT_EQ(
-        KM_ERROR_OUTPUT_PARAMETER_NULL,
-        device()->get_supported_digests(device(), KM_ALGORITHM_RSA, KM_PURPOSE_SIGN, NULL, NULL));
+    // Shouldn't blow up on NULL.
+    device.SupportedDigests(KM_ALGORITHM_RSA, KM_PURPOSE_SIGN, NULL);
 
-    size_t len;
-    keymaster_digest_t* digests;
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_RSA,
-                                                           KM_PURPOSE_SIGN, &digests, &len));
-    ExpectContains(KM_DIGEST_NONE, digests, len);
-    free(digests);
+    SupportedResponse<keymaster_digest_t> response;
+    device.SupportedDigests(KM_ALGORITHM_RSA, KM_PURPOSE_SIGN, &response);
+    ExpectResponseContains(KM_DIGEST_NONE, response);
 
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_DSA,
-                                                           KM_PURPOSE_SIGN, &digests, &len));
-    ExpectContains(KM_DIGEST_NONE, digests, len);
-    free(digests);
+    device.SupportedDigests(KM_ALGORITHM_DSA, KM_PURPOSE_SIGN, &response);
+    ExpectResponseContains(KM_DIGEST_NONE, response);
 
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_ECDSA,
-                                                           KM_PURPOSE_SIGN, &digests, &len));
-    ExpectContains(KM_DIGEST_NONE, digests, len);
-    free(digests);
+    device.SupportedDigests(KM_ALGORITHM_ECDSA, KM_PURPOSE_SIGN, &response);
+    ExpectResponseContains(KM_DIGEST_NONE, response);
 
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_AES,
-                                                           KM_PURPOSE_SIGN, &digests, &len));
-    EXPECT_EQ(0, len);
-    free(digests);
+    device.SupportedDigests(KM_ALGORITHM_AES, KM_PURPOSE_SIGN, &response);
+    ExpectEmptyResponse(response);
 }
 
 TEST_F(CheckSupported, SupportedImportFormats) {
-    EXPECT_EQ(KM_ERROR_OUTPUT_PARAMETER_NULL,
-              device()->get_supported_import_formats(device(), KM_ALGORITHM_RSA, NULL, NULL));
+    // Shouldn't blow up on NULL.
+    device.SupportedImportFormats(KM_ALGORITHM_RSA, NULL);
 
-    size_t len;
-    keymaster_key_format_t* formats;
-    EXPECT_EQ(KM_ERROR_OK,
-              device()->get_supported_import_formats(device(), KM_ALGORITHM_RSA, &formats, &len));
-    ExpectContains(KM_KEY_FORMAT_PKCS8, formats, len);
-    free(formats);
+    SupportedResponse<keymaster_key_format_t> response;
+    device.SupportedImportFormats(KM_ALGORITHM_RSA, &response);
+    ExpectResponseContains(KM_KEY_FORMAT_PKCS8, response);
 
-    EXPECT_EQ(KM_ERROR_OK,
-              device()->get_supported_import_formats(device(), KM_ALGORITHM_DSA, &formats, &len));
-    ExpectContains(KM_KEY_FORMAT_PKCS8, formats, len);
-    free(formats);
+    device.SupportedImportFormats(KM_ALGORITHM_DSA, &response);
+    ExpectResponseContains(KM_KEY_FORMAT_PKCS8, response);
 
-    EXPECT_EQ(KM_ERROR_OK,
-              device()->get_supported_import_formats(device(), KM_ALGORITHM_ECDSA, &formats, &len));
-    ExpectContains(KM_KEY_FORMAT_PKCS8, formats, len);
-    free(formats);
+    device.SupportedImportFormats(KM_ALGORITHM_ECDSA, &response);
+    ExpectResponseContains(KM_KEY_FORMAT_PKCS8, response);
 
-    EXPECT_EQ(KM_ERROR_OK,
-              device()->get_supported_import_formats(device(), KM_ALGORITHM_AES, &formats, &len));
-    EXPECT_EQ(0, len);
-    free(formats);
+    device.SupportedImportFormats(KM_ALGORITHM_AES, &response);
+    ExpectEmptyResponse(response);
 }
 
 TEST_F(CheckSupported, SupportedExportFormats) {
-    EXPECT_EQ(KM_ERROR_OUTPUT_PARAMETER_NULL,
-              device()->get_supported_export_formats(device(), KM_ALGORITHM_RSA, NULL, NULL));
+    // Shouldn't blow up on NULL.
+    device.SupportedExportFormats(KM_ALGORITHM_RSA, NULL);
 
-    size_t len;
-    keymaster_key_format_t* formats;
-    EXPECT_EQ(KM_ERROR_OK,
-              device()->get_supported_export_formats(device(), KM_ALGORITHM_RSA, &formats, &len));
-    ExpectContains(KM_KEY_FORMAT_X509, formats, len);
-    free(formats);
+    SupportedResponse<keymaster_key_format_t> response;
+    device.SupportedExportFormats(KM_ALGORITHM_RSA, &response);
+    ExpectResponseContains(KM_KEY_FORMAT_X509, response);
 
-    EXPECT_EQ(KM_ERROR_OK,
-              device()->get_supported_export_formats(device(), KM_ALGORITHM_DSA, &formats, &len));
-    ExpectContains(KM_KEY_FORMAT_X509, formats, len);
-    free(formats);
+    device.SupportedExportFormats(KM_ALGORITHM_DSA, &response);
+    ExpectResponseContains(KM_KEY_FORMAT_X509, response);
 
-    EXPECT_EQ(KM_ERROR_OK,
-              device()->get_supported_export_formats(device(), KM_ALGORITHM_ECDSA, &formats, &len));
-    ExpectContains(KM_KEY_FORMAT_X509, formats, len);
-    free(formats);
+    device.SupportedExportFormats(KM_ALGORITHM_ECDSA, &response);
+    ExpectResponseContains(KM_KEY_FORMAT_X509, response);
 
-    EXPECT_EQ(KM_ERROR_OK,
-              device()->get_supported_export_formats(device(), KM_ALGORITHM_AES, &formats, &len));
-    EXPECT_EQ(0, len);
-    free(formats);
+    device.SupportedExportFormats(KM_ALGORITHM_AES, &response);
+    ExpectEmptyResponse(response);
 }
 
 keymaster_key_param_t key_generation_base_params[] = {
@@ -264,157 +201,114 @@
     Authorization(TAG_APPLICATION_DATA, "app_data", 8), Authorization(TAG_AUTH_TIMEOUT, 300),
 };
 
-TEST_F(KeymasterTest, TestFlags) {
-    EXPECT_TRUE(device()->flags & KEYMASTER_SOFTWARE_ONLY);
-    EXPECT_TRUE(device()->flags & KEYMASTER_BLOBS_ARE_STANDALONE);
-    EXPECT_FALSE(device()->flags & KEYMASTER_SUPPORTS_DSA);
-    EXPECT_TRUE(device()->flags & KEYMASTER_SUPPORTS_EC);
-}
-
-typedef KeymasterTest OldKeyGeneration;
-
-TEST_F(OldKeyGeneration, Rsa) {
-    keymaster_rsa_keygen_params_t params = {.modulus_size = 256, .public_exponent = 3};
-    uint8_t* key_blob;
-    size_t key_blob_length;
-    EXPECT_EQ(0,
-              device()->generate_keypair(device(), TYPE_RSA, &params, &key_blob, &key_blob_length));
-    EXPECT_GT(key_blob_length, 0);
-
-    free(key_blob);
-}
-
-TEST_F(OldKeyGeneration, Ecdsa) {
-
-    keymaster_ec_keygen_params_t params = {.field_size = 256};
-    uint8_t* key_blob;
-    size_t key_blob_length;
-    EXPECT_EQ(0,
-              device()->generate_keypair(device(), TYPE_EC, &params, &key_blob, &key_blob_length));
-    EXPECT_GT(key_blob_length, 0);
-
-    free(key_blob);
-}
-
 class NewKeyGeneration : public KeymasterTest {
   protected:
     NewKeyGeneration() {
-        params_.Reinitialize(key_generation_base_params, array_length(key_generation_base_params));
+        req_.key_description.Reinitialize(key_generation_base_params,
+                                          array_length(key_generation_base_params));
     }
 
-    void CheckBaseParams(const AuthorizationSet& auths) {
-        EXPECT_TRUE(contains(auths, TAG_PURPOSE, KM_PURPOSE_SIGN));
-        EXPECT_TRUE(contains(auths, TAG_PURPOSE, KM_PURPOSE_VERIFY));
-        EXPECT_TRUE(contains(auths, TAG_USER_ID, 7));
-        EXPECT_TRUE(contains(auths, TAG_USER_AUTH_ID, 8));
-        EXPECT_TRUE(contains(auths, TAG_AUTH_TIMEOUT, 300));
+    void CheckBaseParams(const GenerateKeyResponse& rsp) {
+        ASSERT_EQ(KM_ERROR_OK, rsp.error);
+        EXPECT_EQ(0U, rsp.enforced.size());
+        EXPECT_EQ(12U, rsp.enforced.SerializedSize());
+        EXPECT_GT(rsp.unenforced.SerializedSize(), 12U);
+
+        EXPECT_TRUE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_SIGN));
+        EXPECT_TRUE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_VERIFY));
+        EXPECT_TRUE(contains(rsp.unenforced, TAG_USER_ID, 7));
+        EXPECT_TRUE(contains(rsp.unenforced, TAG_USER_AUTH_ID, 8));
+        EXPECT_TRUE(contains(rsp.unenforced, TAG_AUTH_TIMEOUT, 300));
 
         // Verify that App ID, App data and ROT are NOT included.
-        EXPECT_FALSE(contains(auths, TAG_ROOT_OF_TRUST));
-        EXPECT_FALSE(contains(auths, TAG_APPLICATION_ID));
-        EXPECT_FALSE(contains(auths, TAG_APPLICATION_DATA));
+        EXPECT_FALSE(contains(rsp.unenforced, TAG_ROOT_OF_TRUST));
+        EXPECT_FALSE(contains(rsp.unenforced, TAG_APPLICATION_ID));
+        EXPECT_FALSE(contains(rsp.unenforced, TAG_APPLICATION_DATA));
 
         // Just for giggles, check that some unexpected tags/values are NOT present.
-        EXPECT_FALSE(contains(auths, TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
-        EXPECT_FALSE(contains(auths, TAG_PURPOSE, KM_PURPOSE_DECRYPT));
-        EXPECT_FALSE(contains(auths, TAG_AUTH_TIMEOUT, 301));
+        EXPECT_FALSE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
+        EXPECT_FALSE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_DECRYPT));
+        EXPECT_FALSE(contains(rsp.unenforced, TAG_AUTH_TIMEOUT, 301));
 
         // Now check that unspecified, defaulted tags are correct.
-        EXPECT_TRUE(contains(auths, TAG_ORIGIN, KM_ORIGIN_SOFTWARE));
-        EXPECT_TRUE(contains(auths, KM_TAG_CREATION_DATETIME));
+        EXPECT_TRUE(contains(rsp.unenforced, TAG_ORIGIN, KM_ORIGIN_SOFTWARE));
+        EXPECT_TRUE(contains(rsp.unenforced, KM_TAG_CREATION_DATETIME));
     }
-};
 
-struct ParamListDelete {
-    void operator()(keymaster_key_param_set_t* p) { keymaster_free_param_set(p); }
+    GenerateKeyRequest req_;
+    GenerateKeyResponse rsp_;
 };
 
-typedef UniquePtr<keymaster_key_param_set_t, ParamListDelete> UniqueParamSetPtr;
-
 TEST_F(NewKeyGeneration, Rsa) {
-    params_.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA));
-    params_.push_back(Authorization(TAG_KEY_SIZE, 256));
-    params_.push_back(Authorization(TAG_RSA_PUBLIC_EXPONENT, 3));
-    ASSERT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(), &blob_,
-                                                  &characteristics_));
-    EXPECT_EQ(0U, characteristics_->hw_enforced.length);
-    AuthorizationSet auths(characteristics_->sw_enforced);
-    CheckBaseParams(auths);
+    req_.key_description.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    req_.key_description.push_back(Authorization(TAG_KEY_SIZE, 256));
+    req_.key_description.push_back(Authorization(TAG_RSA_PUBLIC_EXPONENT, 3));
+    device.GenerateKey(req_, &rsp_);
 
-    // Check specified tags are all present in auths
-    EXPECT_TRUE(contains(auths, TAG_ALGORITHM, KM_ALGORITHM_RSA));
-    EXPECT_TRUE(contains(auths, TAG_KEY_SIZE, 256));
-    EXPECT_TRUE(contains(auths, TAG_RSA_PUBLIC_EXPONENT, 3));
+    CheckBaseParams(rsp_);
+
+    // Check specified tags are all present in unenforced characteristics
+    EXPECT_TRUE(contains(rsp_.unenforced, TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    EXPECT_TRUE(contains(rsp_.unenforced, TAG_KEY_SIZE, 256));
+    EXPECT_TRUE(contains(rsp_.unenforced, TAG_RSA_PUBLIC_EXPONENT, 3));
 }
 
 TEST_F(NewKeyGeneration, RsaDefaultSize) {
-    params_.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA));
-    ASSERT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(), &blob_,
-                                                  &characteristics_));
+    req_.key_description.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    device.GenerateKey(req_, &rsp_);
 
-    EXPECT_EQ(0U, characteristics_->hw_enforced.length);
-    AuthorizationSet auths(characteristics_->sw_enforced);
-    CheckBaseParams(auths);
+    CheckBaseParams(rsp_);
 
-    // Check specified tags are all present in auths
-    EXPECT_TRUE(contains(auths, TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    // Check specified tags are all present in unenforced characteristics
+    EXPECT_TRUE(contains(rsp_.unenforced, TAG_ALGORITHM, KM_ALGORITHM_RSA));
 
     // Now check that unspecified, defaulted tags are correct.
-    EXPECT_TRUE(contains(auths, TAG_RSA_PUBLIC_EXPONENT, 65537));
-    EXPECT_TRUE(contains(auths, TAG_KEY_SIZE, 2048));
+    EXPECT_TRUE(contains(rsp_.unenforced, TAG_RSA_PUBLIC_EXPONENT, 65537));
+    EXPECT_TRUE(contains(rsp_.unenforced, TAG_KEY_SIZE, 2048));
 }
 
 TEST_F(NewKeyGeneration, Ecdsa) {
-    params_.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
-    params_.push_back(Authorization(TAG_KEY_SIZE, 224));
-    EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(), &blob_,
-                                                  &characteristics_));
+    req_.key_description.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+    req_.key_description.push_back(Authorization(TAG_KEY_SIZE, 224));
+    device.GenerateKey(req_, &rsp_);
 
-    EXPECT_EQ(0U, characteristics_->hw_enforced.length);
-    AuthorizationSet auths(characteristics_->sw_enforced);
-    CheckBaseParams(auths);
+    CheckBaseParams(rsp_);
 
-    // Check specified tags are all present in auths characteristics
-    EXPECT_TRUE(contains(auths, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
-    EXPECT_TRUE(contains(auths, TAG_KEY_SIZE, 224));
+    // Check specified tags are all present in unenforced characteristics
+    EXPECT_TRUE(contains(rsp_.unenforced, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+    EXPECT_TRUE(contains(rsp_.unenforced, TAG_KEY_SIZE, 224));
 }
 
 TEST_F(NewKeyGeneration, EcdsaDefaultSize) {
-    params_.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
-    EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(), &blob_,
-                                                  &characteristics_));
+    req_.key_description.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+    device.GenerateKey(req_, &rsp_);
 
-    EXPECT_EQ(0U, characteristics_->hw_enforced.length);
-    AuthorizationSet auths(characteristics_->sw_enforced);
-    CheckBaseParams(auths);
+    CheckBaseParams(rsp_);
 
-    // Check specified tags are all present in auths
-    EXPECT_TRUE(contains(auths, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+    // Check specified tags are all present in unenforced characteristics
+    EXPECT_TRUE(contains(rsp_.unenforced, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
 
     // Now check that unspecified, defaulted tags are correct.
-    EXPECT_TRUE(contains(auths, TAG_KEY_SIZE, 224));
+    EXPECT_TRUE(contains(rsp_.unenforced, TAG_KEY_SIZE, 224));
 }
 
 TEST_F(NewKeyGeneration, EcdsaInvalidSize) {
-    params_.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
-    params_.push_back(Authorization(TAG_KEY_SIZE, 190));
-    EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE,
-              device()->generate_key(device(), params_.data(), params_.size(), &blob_,
-                                     &characteristics_));
+    req_.key_description.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+    req_.key_description.push_back(Authorization(TAG_KEY_SIZE, 190));
+    device.GenerateKey(req_, &rsp_);
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE, rsp_.error);
 }
 
 TEST_F(NewKeyGeneration, EcdsaAllValidSizes) {
     size_t valid_sizes[] = {224, 256, 384, 521};
     for (size_t size : valid_sizes) {
-        params_.Reinitialize(key_generation_base_params, array_length(key_generation_base_params));
-        params_.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
-        params_.push_back(Authorization(TAG_KEY_SIZE, size));
-        EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(),
-                                                      &blob_, &characteristics_))
-            << "Failed to generate size: " << size;
-
-        FreeCharacteristics();
-        FreeKeyBlob();
+        GenerateKeyResponse rsp;
+        req_.key_description.Reinitialize(key_generation_base_params,
+                                          array_length(key_generation_base_params));
+        req_.key_description.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+        req_.key_description.push_back(Authorization(TAG_KEY_SIZE, size));
+        device.GenerateKey(req_, &rsp);
+        EXPECT_EQ(KM_ERROR_OK, rsp.error) << "Failed to generate size: " << size;
     }
 }
 
@@ -426,9 +320,9 @@
         Authorization(TAG_BLOCK_MODE, KM_MODE_OCB), Authorization(TAG_CHUNK_LENGTH, 4096),
         Authorization(TAG_MAC_LENGTH, 16), Authorization(TAG_PADDING, KM_PAD_NONE),
     };
-    params_.Reinitialize(params, array_length(params));
-    EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(), &blob_,
-                                                  &characteristics_));
+    req_.key_description.Reinitialize(params, array_length(params));
+    device.GenerateKey(req_, &rsp_);
+    EXPECT_EQ(KM_ERROR_OK, rsp_.error);
 }
 
 TEST_F(NewKeyGeneration, AesOcbInvalidKeySize) {
@@ -439,10 +333,9 @@
         Authorization(TAG_BLOCK_MODE, KM_MODE_OCB), Authorization(TAG_CHUNK_LENGTH, 4096),
         Authorization(TAG_MAC_LENGTH, 16), Authorization(TAG_PADDING, KM_PAD_NONE),
     };
-    params_.Reinitialize(params, array_length(params));
-    EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE,
-              device()->generate_key(device(), params_.data(), params_.size(), &blob_,
-                                     &characteristics_));
+    req_.key_description.Reinitialize(params, array_length(params));
+    device.GenerateKey(req_, &rsp_);
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE, rsp_.error);
 }
 
 TEST_F(NewKeyGeneration, AesOcbAllValidSizes) {
@@ -456,14 +349,11 @@
 
     size_t valid_sizes[] = {128, 192, 256};
     for (size_t size : valid_sizes) {
-        params_.Reinitialize(params, array_length(params));
-        params_.push_back(Authorization(TAG_KEY_SIZE, size));
-        EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(),
-                                                      &blob_, &characteristics_))
-            << "Failed to generate size: " << size;
-
-        FreeCharacteristics();
-        FreeKeyBlob();
+        GenerateKeyResponse rsp;
+        req_.key_description.Reinitialize(params, array_length(params));
+        req_.key_description.push_back(Authorization(TAG_KEY_SIZE, size));
+        device.GenerateKey(req_, &rsp);
+        EXPECT_EQ(KM_ERROR_OK, rsp.error) << "Failed to generate size: " << size;
     }
 }
 
@@ -474,10 +364,9 @@
         Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES), Authorization(TAG_KEY_SIZE, 128),
         Authorization(TAG_BLOCK_MODE, KM_MODE_OCB), Authorization(TAG_PADDING, KM_PAD_NONE),
     };
-    params_.Reinitialize(params, array_length(params));
-    EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT,
-              device()->generate_key(device(), params_.data(), params_.size(), &blob_,
-                                     &characteristics_));
+    req_.key_description.Reinitialize(params, array_length(params));
+    device.GenerateKey(req_, &rsp_);
+    EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, rsp_.error);
 }
 
 TEST_F(NewKeyGeneration, AesEcbUnsupported) {
@@ -487,10 +376,9 @@
         Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES), Authorization(TAG_KEY_SIZE, 128),
         Authorization(TAG_BLOCK_MODE, KM_MODE_ECB), Authorization(TAG_PADDING, KM_PAD_NONE),
     };
-    params_.Reinitialize(params, array_length(params));
-    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE,
-              device()->generate_key(device(), params_.data(), params_.size(), &blob_,
-                                     &characteristics_));
+    req_.key_description.Reinitialize(params, array_length(params));
+    device.GenerateKey(req_, &rsp_);
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE, rsp_.error);
 }
 
 TEST_F(NewKeyGeneration, AesOcbPaddingUnsupported) {
@@ -501,10 +389,9 @@
         Authorization(TAG_BLOCK_MODE, KM_MODE_OCB), Authorization(TAG_CHUNK_LENGTH, 4096),
         Authorization(TAG_PADDING, KM_PAD_ZERO),
     };
-    params_.Reinitialize(params, array_length(params));
-    EXPECT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE,
-              device()->generate_key(device(), params_.data(), params_.size(), &blob_,
-                                     &characteristics_));
+    req_.key_description.Reinitialize(params, array_length(params));
+    device.GenerateKey(req_, &rsp_);
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, rsp_.error);
 }
 
 TEST_F(NewKeyGeneration, AesOcbInvalidMacLength) {
@@ -515,10 +402,9 @@
         Authorization(TAG_BLOCK_MODE, KM_MODE_OCB), Authorization(TAG_CHUNK_LENGTH, 4096),
         Authorization(TAG_MAC_LENGTH, 17), Authorization(TAG_PADDING, KM_PAD_NONE),
     };
-    params_.Reinitialize(params, array_length(params));
-    EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT,
-              device()->generate_key(device(), params_.data(), params_.size(), &blob_,
-                                     &characteristics_));
+    req_.key_description.Reinitialize(params, array_length(params));
+    device.GenerateKey(req_, &rsp_);
+    EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, rsp_.error);
 }
 
 typedef KeymasterTest GetKeyCharacteristics;
@@ -530,17 +416,23 @@
         Authorization(TAG_APPLICATION_ID, "app_id", 6), Authorization(TAG_AUTH_TIMEOUT, 300),
     };
 
-    ASSERT_EQ(KM_ERROR_OK, device()->generate_key(device(), params, array_length(params), &blob_,
-                                                  &characteristics_));
-    AuthorizationSet original(characteristics_->sw_enforced);
-    FreeCharacteristics();
+    GenerateKeyRequest gen_req;
+    gen_req.key_description.Reinitialize(params, array_length(params));
+    GenerateKeyResponse gen_rsp;
 
-    keymaster_blob_t client_id = {.data = reinterpret_cast<const uint8_t*>("app_id"),
-                                  .data_length = 6};
-    ASSERT_EQ(KM_ERROR_OK,
-              device()->get_key_characteristics(device(), &blob_, &client_id, NULL /* app_data */,
-                                                &characteristics_));
-    EXPECT_EQ(original, AuthorizationSet(characteristics_->sw_enforced));
+    device.GenerateKey(gen_req, &gen_rsp);
+    ASSERT_EQ(KM_ERROR_OK, gen_rsp.error);
+
+    GetKeyCharacteristicsRequest req;
+    req.SetKeyMaterial(gen_rsp.key_blob);
+    req.additional_params.push_back(TAG_APPLICATION_ID, "app_id", 6);
+
+    GetKeyCharacteristicsResponse rsp;
+    device.GetKeyCharacteristics(req, &rsp);
+    ASSERT_EQ(KM_ERROR_OK, rsp.error);
+
+    EXPECT_EQ(gen_rsp.enforced, rsp.enforced);
+    EXPECT_EQ(gen_rsp.unenforced, rsp.unenforced);
 }
 
 /**
@@ -548,80 +440,75 @@
  */
 class SigningOperationsTest : public KeymasterTest {
   protected:
-    SigningOperationsTest() : out_params_(NULL), output_(NULL), signature_(NULL) {}
-    ~SigningOperationsTest() {
-        // Clean up so (most) tests won't have to.
-        FreeOutput();
-        FreeSignature();
-    }
-
     void GenerateKey(keymaster_algorithm_t algorithm, keymaster_digest_t digest,
                      keymaster_padding_t padding, uint32_t key_size) {
-        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY));
-        params_.push_back(Authorization(TAG_ALGORITHM, algorithm));
-        params_.push_back(Authorization(TAG_KEY_SIZE, key_size));
-        params_.push_back(Authorization(TAG_USER_ID, 7));
-        params_.push_back(Authorization(TAG_USER_AUTH_ID, 8));
-        params_.push_back(Authorization(TAG_APPLICATION_ID, "app_id", 6));
-        params_.push_back(Authorization(TAG_AUTH_TIMEOUT, 300));
+        keymaster_key_param_t params[] = {
+            Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+            Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), Authorization(TAG_ALGORITHM, algorithm),
+            Authorization(TAG_KEY_SIZE, key_size), Authorization(TAG_USER_ID, 7),
+            Authorization(TAG_USER_AUTH_ID, 8), Authorization(TAG_APPLICATION_ID, "app_id", 6),
+            Authorization(TAG_AUTH_TIMEOUT, 300),
+        };
+        GenerateKeyRequest generate_request;
+        generate_request.key_description.Reinitialize(params, array_length(params));
         if (static_cast<int>(digest) != -1)
-            params_.push_back(TAG_DIGEST, digest);
+            generate_request.key_description.push_back(TAG_DIGEST, digest);
         if (static_cast<int>(padding) != -1)
-            params_.push_back(TAG_PADDING, padding);
-
-        EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(),
-                                                      &blob_, &characteristics_));
+            generate_request.key_description.push_back(TAG_PADDING, padding);
+        device.GenerateKey(generate_request, &generate_response_);
+        EXPECT_EQ(KM_ERROR_OK, generate_response_.error);
     }
 
     void SignMessage(const void* message, size_t size) {
-        EXPECT_EQ(KM_ERROR_OK, device()->begin(device(), KM_PURPOSE_SIGN, &blob_, client_params_,
-                                               array_length(client_params_), &out_params_,
-                                               &out_params_count_, &op_handle_));
-
-        EXPECT_EQ(KM_ERROR_OK,
-                  device()->update(device(), op_handle_, reinterpret_cast<const uint8_t*>(message),
-                                   size, &input_consumed_, &output_, &output_length_));
-        EXPECT_EQ(0, output_length_);
-        FreeOutput();
-        EXPECT_EQ(size, input_consumed_);
-
-        EXPECT_EQ(KM_ERROR_OK,
-                  device()->finish(device(), op_handle_, NULL /* signature to verify */,
-                                   0 /* signature to verify length */, &signature_,
-                                   &signature_length_));
-        EXPECT_GT(signature_length_, 0);
+        SignMessage(generate_response_.key_blob, message, size);
     }
 
-    void FreeOutput() {
-        free(out_params_);
-        out_params_ = NULL;
-        free(output_);
-        output_ = NULL;
+    void SignMessage(const keymaster_key_blob_t& key_blob, const void* message, size_t size) {
+        BeginOperationRequest begin_request;
+        BeginOperationResponse begin_response;
+        begin_request.SetKeyMaterial(key_blob);
+        begin_request.purpose = KM_PURPOSE_SIGN;
+        AddClientParams(&begin_request.additional_params);
+
+        device.BeginOperation(begin_request, &begin_response);
+        ASSERT_EQ(KM_ERROR_OK, begin_response.error);
+
+        UpdateOperationRequest update_request;
+        UpdateOperationResponse update_response;
+        update_request.op_handle = begin_response.op_handle;
+        update_request.input.Reinitialize(message, size);
+        EXPECT_EQ(size, update_request.input.available_read());
+
+        device.UpdateOperation(update_request, &update_response);
+        ASSERT_EQ(KM_ERROR_OK, update_response.error);
+        EXPECT_EQ(0U, update_response.output.available_read());
+        EXPECT_EQ(size, update_response.input_consumed);
+
+        FinishOperationRequest finish_request;
+        finish_request.op_handle = begin_response.op_handle;
+        device.FinishOperation(finish_request, &finish_response_);
+        ASSERT_EQ(KM_ERROR_OK, finish_response_.error);
+        EXPECT_GT(finish_response_.output.available_read(), 0U);
     }
 
-    void FreeSignature() {
-        free(signature_);
-        signature_ = NULL;
+    void AddClientParams(AuthorizationSet* set) { set->push_back(TAG_APPLICATION_ID, "app_id", 6); }
+
+    const keymaster_key_blob_t& key_blob() { return generate_response_.key_blob; }
+
+    const keymaster_key_blob_t& corrupt_key_blob() {
+        uint8_t* tmp = const_cast<uint8_t*>(generate_response_.key_blob.key_material);
+        ++tmp[generate_response_.key_blob.key_material_size / 2];
+        return generate_response_.key_blob;
     }
 
-    void corrupt_key_blob() {
-        uint8_t* tmp = const_cast<uint8_t*>(blob_.key_material);
-        ++tmp[blob_.key_material_size / 2];
+    Buffer* signature() {
+        if (finish_response_.error == KM_ERROR_OK)
+            return &finish_response_.output;
+        return NULL;
     }
 
-    keymaster_blob_t client_id_ = {.data = reinterpret_cast<const uint8_t*>("app_id"),
-                                   .data_length = 6};
-    keymaster_key_param_t client_params_[1] = {
-        Authorization(TAG_APPLICATION_ID, client_id_.data, client_id_.data_length)};
-    keymaster_key_param_t* out_params_;
-    size_t out_params_count_;
-    uint64_t op_handle_;
-    size_t input_consumed_;
-    uint8_t* output_;
-    size_t output_length_;
-    uint8_t* signature_;
-    size_t signature_length_;
+    GenerateKeyResponse generate_response_;
+    FinishOperationResponse finish_response_;
 };
 
 TEST_F(SigningOperationsTest, RsaSuccess) {
@@ -638,90 +525,157 @@
 
 TEST_F(SigningOperationsTest, RsaAbort) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
-    ASSERT_EQ(KM_ERROR_OK, device()->begin(device(), KM_PURPOSE_SIGN, &blob_, client_params_,
-                                           array_length(client_params_), &out_params_,
-                                           &out_params_count_, &op_handle_));
 
-    EXPECT_EQ(KM_ERROR_OK, device()->abort(device(), op_handle_));
-    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device()->abort(device(), op_handle_));
+    BeginOperationRequest begin_request;
+    BeginOperationResponse begin_response;
+    begin_request.SetKeyMaterial(key_blob());
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    AddClientParams(&begin_request.additional_params);
+
+    device.BeginOperation(begin_request, &begin_response);
+    ASSERT_EQ(KM_ERROR_OK, begin_response.error);
+
+    EXPECT_EQ(KM_ERROR_OK, device.AbortOperation(begin_response.op_handle));
+
+    // Another abort should fail
+    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
 }
 
 TEST_F(SigningOperationsTest, RsaUnsupportedDigest) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_SHA_2_256, KM_PAD_NONE, 256 /* key size */);
-    ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST,
-              device()->begin(device(), KM_PURPOSE_SIGN, &blob_, client_params_,
-                              array_length(client_params_), &out_params_, &out_params_count_,
-                              &op_handle_));
-    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device()->abort(device(), op_handle_));
+
+    BeginOperationRequest begin_request;
+    BeginOperationResponse begin_response;
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    begin_request.SetKeyMaterial(key_blob());
+    AddClientParams(&begin_request.additional_params);
+
+    device.BeginOperation(begin_request, &begin_response);
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST, begin_response.error);
+
+    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
 }
 
 TEST_F(SigningOperationsTest, RsaUnsupportedPadding) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_RSA_OAEP, 256 /* key size */);
-    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE,
-              device()->begin(device(), KM_PURPOSE_SIGN, &blob_, client_params_,
-                              array_length(client_params_), &out_params_, &out_params_count_,
-                              &op_handle_));
-    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device()->abort(device(), op_handle_));
+
+    BeginOperationRequest begin_request;
+    BeginOperationResponse begin_response;
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    begin_request.SetKeyMaterial(key_blob());
+    AddClientParams(&begin_request.additional_params);
+
+    device.BeginOperation(begin_request, &begin_response);
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, begin_response.error);
+
+    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
 }
 
 TEST_F(SigningOperationsTest, RsaNoDigest) {
     GenerateKey(KM_ALGORITHM_RSA, static_cast<keymaster_digest_t>(-1), KM_PAD_NONE,
                 256 /* key size */);
-    ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST,
-              device()->begin(device(), KM_PURPOSE_SIGN, &blob_, client_params_,
-                              array_length(client_params_), &out_params_, &out_params_count_,
-                              &op_handle_));
-    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device()->abort(device(), op_handle_));
+
+    BeginOperationRequest begin_request;
+    BeginOperationResponse begin_response;
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    begin_request.SetKeyMaterial(key_blob());
+    AddClientParams(&begin_request.additional_params);
+
+    device.BeginOperation(begin_request, &begin_response);
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST, begin_response.error);
+
+    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
 }
 
 TEST_F(SigningOperationsTest, RsaNoPadding) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, static_cast<keymaster_padding_t>(-1),
                 256 /* key size */);
-    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE,
-              device()->begin(device(), KM_PURPOSE_SIGN, &blob_, client_params_,
-                              array_length(client_params_), &out_params_, &out_params_count_,
-                              &op_handle_));
-    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device()->abort(device(), op_handle_));
+
+    BeginOperationRequest begin_request;
+    BeginOperationResponse begin_response;
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    begin_request.SetKeyMaterial(key_blob());
+    AddClientParams(&begin_request.additional_params);
+
+    device.BeginOperation(begin_request, &begin_response);
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, begin_response.error);
+
+    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
 }
 
 TEST_F(SigningOperationsTest, RsaTooShortMessage) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
-    ASSERT_EQ(KM_ERROR_OK, device()->begin(device(), KM_PURPOSE_SIGN, &blob_, client_params_,
-                                           array_length(client_params_), &out_params_,
-                                           &out_params_count_, &op_handle_));
-    ASSERT_EQ(KM_ERROR_OK,
-              device()->update(device(), op_handle_,
-                               reinterpret_cast<const uint8_t*>("01234567890123456789012345678901"),
-                               31, &input_consumed_, &output_, &output_length_));
-    EXPECT_EQ(0U, output_length_);
-    EXPECT_EQ(31U, input_consumed_);
 
-    ASSERT_EQ(KM_ERROR_UNKNOWN_ERROR,
-              device()->finish(device(), op_handle_, NULL, 0, &signature_, &signature_length_));
+    BeginOperationRequest begin_request;
+    BeginOperationResponse begin_response;
+    begin_request.SetKeyMaterial(key_blob());
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    AddClientParams(&begin_request.additional_params);
 
-    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device()->abort(device(), op_handle_));
+    device.BeginOperation(begin_request, &begin_response);
+    ASSERT_EQ(KM_ERROR_OK, begin_response.error);
+
+    UpdateOperationRequest update_request;
+    UpdateOperationResponse update_response;
+    update_request.op_handle = begin_response.op_handle;
+    update_request.input.Reinitialize("01234567890123456789012345678901", 31);
+    EXPECT_EQ(31U, update_request.input.available_read());
+
+    device.UpdateOperation(update_request, &update_response);
+    ASSERT_EQ(KM_ERROR_OK, update_response.error);
+    EXPECT_EQ(0U, update_response.output.available_read());
+    EXPECT_EQ(31U, update_response.input_consumed);
+
+    FinishOperationRequest finish_request;
+    finish_request.op_handle = begin_response.op_handle;
+    FinishOperationResponse finish_response;
+    device.FinishOperation(finish_request, &finish_response);
+    ASSERT_EQ(KM_ERROR_UNKNOWN_ERROR, finish_response.error);
+    EXPECT_EQ(0U, finish_response.output.available_read());
+
+    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
 }
 
 class VerificationOperationsTest : public SigningOperationsTest {
   protected:
     void VerifyMessage(const void* message, size_t message_len) {
-        EXPECT_TRUE(signature_ != NULL);
+        VerifyMessage(generate_response_.key_blob, message, message_len);
+    }
 
-        EXPECT_EQ(KM_ERROR_OK, device()->begin(device(), KM_PURPOSE_VERIFY, &blob_, client_params_,
-                                               array_length(client_params_), &out_params_,
-                                               &out_params_count_, &op_handle_));
-        ASSERT_EQ(KM_ERROR_OK,
-                  device()->update(device(), op_handle_, reinterpret_cast<const uint8_t*>(message),
-                                   message_len, &input_consumed_, &output_, &output_length_));
-        EXPECT_EQ(0U, output_length_);
-        FreeOutput();
-        EXPECT_EQ(message_len, input_consumed_);
+    void VerifyMessage(const keymaster_key_blob_t& key_blob, const void* message,
+                       size_t message_len) {
+        ASSERT_TRUE(signature() != NULL);
 
-        ASSERT_EQ(KM_ERROR_OK, device()->finish(device(), op_handle_, signature_, signature_length_,
-                                                &output_, &output_length_));
-        EXPECT_EQ(0U, output_length_);
+        BeginOperationRequest begin_request;
+        BeginOperationResponse begin_response;
+        begin_request.SetKeyMaterial(key_blob);
+        begin_request.purpose = KM_PURPOSE_VERIFY;
+        AddClientParams(&begin_request.additional_params);
 
-        EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device()->abort(device(), op_handle_));
+        device.BeginOperation(begin_request, &begin_response);
+        ASSERT_EQ(KM_ERROR_OK, begin_response.error);
+
+        UpdateOperationRequest update_request;
+        UpdateOperationResponse update_response;
+        update_request.op_handle = begin_response.op_handle;
+        update_request.input.Reinitialize(message, message_len);
+        EXPECT_EQ(message_len, update_request.input.available_read());
+
+        device.UpdateOperation(update_request, &update_response);
+        ASSERT_EQ(KM_ERROR_OK, update_response.error);
+        EXPECT_EQ(0U, update_response.output.available_read());
+        EXPECT_EQ(message_len, update_response.input_consumed);
+
+        FinishOperationRequest finish_request;
+        finish_request.op_handle = begin_response.op_handle;
+        finish_request.signature.Reinitialize(*signature());
+        FinishOperationResponse finish_response;
+        device.FinishOperation(finish_request, &finish_response);
+        ASSERT_EQ(KM_ERROR_OK, finish_response.error);
+        EXPECT_EQ(0U, finish_response.output.available_read());
+
+        EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE,
+                  device.AbortOperation(begin_response.op_handle));
     }
 };
 
@@ -739,60 +693,67 @@
     VerifyMessage(message, array_size(message) - 1);
 }
 
-typedef VerificationOperationsTest ExportKeyTest;
+typedef SigningOperationsTest ExportKeyTest;
 TEST_F(ExportKeyTest, RsaSuccess) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
 
-    uint8_t* export_data;
-    size_t export_data_length;
-    ASSERT_EQ(KM_ERROR_OK,
-              device()->export_key(device(), KM_KEY_FORMAT_X509, &blob_, &client_id_,
-                                   NULL /* app_data */, &export_data, &export_data_length));
-    EXPECT_TRUE(export_data != NULL);
-    EXPECT_GT(export_data_length, 0);
+    ExportKeyRequest request;
+    ExportKeyResponse response;
+    AddClientParams(&request.additional_params);
+    request.key_format = KM_KEY_FORMAT_X509;
+    request.SetKeyMaterial(key_blob());
+
+    device.ExportKey(request, &response);
+    ASSERT_EQ(KM_ERROR_OK, response.error);
+    EXPECT_TRUE(response.key_data != NULL);
 
     // TODO(swillden): Verify that the exported key is actually usable to verify signatures.
-    free(export_data);
 }
 
 TEST_F(ExportKeyTest, EcdsaSuccess) {
     GenerateKey(KM_ALGORITHM_ECDSA, KM_DIGEST_NONE, KM_PAD_NONE, 224 /* key size */);
 
-    uint8_t* export_data;
-    size_t export_data_length;
-    ASSERT_EQ(KM_ERROR_OK,
-              device()->export_key(device(), KM_KEY_FORMAT_X509, &blob_, &client_id_,
-                                   NULL /* app_data */, &export_data, &export_data_length));
-    EXPECT_TRUE(export_data != NULL);
-    EXPECT_GT(export_data_length, 0);
+    ExportKeyRequest request;
+    ExportKeyResponse response;
+    AddClientParams(&request.additional_params);
+    request.key_format = KM_KEY_FORMAT_X509;
+    request.SetKeyMaterial(key_blob());
+
+    device.ExportKey(request, &response);
+    ASSERT_EQ(KM_ERROR_OK, response.error);
+    EXPECT_TRUE(response.key_data != NULL);
 
     // TODO(swillden): Verify that the exported key is actually usable to verify signatures.
-    free(export_data);
 }
 
 TEST_F(ExportKeyTest, RsaUnsupportedKeyFormat) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256);
 
-    uint8_t dummy[] = {1};
-    uint8_t* export_data = dummy;  // So it's not NULL;
-    size_t export_data_length;
-    ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT,
-              device()->export_key(device(), KM_KEY_FORMAT_PKCS8, &blob_, &client_id_,
-                                   NULL /* app_data */, &export_data, &export_data_length));
-    ASSERT_TRUE(export_data == NULL);
+    ExportKeyRequest request;
+    ExportKeyResponse response;
+    AddClientParams(&request.additional_params);
+
+    /* We have no other defined export formats defined. */
+    request.key_format = KM_KEY_FORMAT_PKCS8;
+    request.SetKeyMaterial(key_blob());
+
+    device.ExportKey(request, &response);
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, response.error);
+    EXPECT_TRUE(response.key_data == NULL);
 }
 
 TEST_F(ExportKeyTest, RsaCorruptedKeyBlob) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256);
-    corrupt_key_blob();
 
-    uint8_t dummy[] = {1};
-    uint8_t* export_data = dummy;  // So it's not NULL
-    size_t export_data_length;
-    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB,
-              device()->export_key(device(), KM_KEY_FORMAT_X509, &blob_, &client_id_,
-                                   NULL /* app_data */, &export_data, &export_data_length));
-    ASSERT_TRUE(export_data == NULL);
+    ExportKeyRequest request;
+    ExportKeyResponse response;
+    AddClientParams(&request.additional_params);
+    request.key_format = KM_KEY_FORMAT_X509;
+    request.SetKeyMaterial(corrupt_key_blob());
+
+    device.ExportKey(request, &response);
+    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, response.error);
+    ASSERT_TRUE(response.key_data == NULL);
 }
 
 static string read_file(const string& file_name) {
@@ -802,114 +763,194 @@
     return string(file_begin, file_end);
 }
 
-class ImportKeyTest : public VerificationOperationsTest {
-  protected:
-    ImportKeyTest() {
-        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY));
-        params_.push_back(Authorization(TAG_DIGEST, KM_DIGEST_NONE));
-        params_.push_back(Authorization(TAG_PADDING, KM_PAD_NONE));
-        params_.push_back(Authorization(TAG_USER_ID, 7));
-        params_.push_back(Authorization(TAG_USER_AUTH_ID, 8));
-        params_.push_back(Authorization(TAG_APPLICATION_ID, "app_id", 6));
-        params_.push_back(Authorization(TAG_AUTH_TIMEOUT, 300));
-    }
-};
-
+typedef VerificationOperationsTest ImportKeyTest;
 TEST_F(ImportKeyTest, RsaSuccess) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_DIGEST, KM_DIGEST_NONE), Authorization(TAG_PADDING, KM_PAD_NONE),
+        Authorization(TAG_USER_ID, 7), Authorization(TAG_USER_AUTH_ID, 8),
+        Authorization(TAG_APPLICATION_ID, "app_id", 6), Authorization(TAG_AUTH_TIMEOUT, 300),
+    };
+
     string pk8_key = read_file("rsa_privkey_pk8.der");
     ASSERT_EQ(633U, pk8_key.size());
 
-    ASSERT_EQ(KM_ERROR_OK,
-              device()->import_key(device(), params_.data(), params_.size(), KM_KEY_FORMAT_PKCS8,
-                                   reinterpret_cast<const uint8_t*>(pk8_key.data()), pk8_key.size(),
-                                   &blob_, &characteristics_));
-    EXPECT_EQ(0U, characteristics_->hw_enforced.length);
-    AuthorizationSet auths(characteristics_->sw_enforced);
+    ImportKeyRequest import_request;
+    import_request.key_description.Reinitialize(params, array_length(params));
+    import_request.key_format = KM_KEY_FORMAT_PKCS8;
+    import_request.SetKeyMaterial(pk8_key.data(), pk8_key.size());
+
+    ImportKeyResponse import_response;
+    device.ImportKey(import_request, &import_response);
+    ASSERT_EQ(KM_ERROR_OK, import_response.error);
+    EXPECT_EQ(0U, import_response.enforced.size());
+    EXPECT_GT(import_response.unenforced.size(), 0U);
 
     // Check values derived from the key.
-    EXPECT_TRUE(contains(auths, TAG_ALGORITHM, KM_ALGORITHM_RSA));
-    EXPECT_TRUE(contains(auths, TAG_KEY_SIZE, 1024));
-    EXPECT_TRUE(contains(auths, TAG_RSA_PUBLIC_EXPONENT, 65537U));
+    EXPECT_TRUE(contains(import_response.unenforced, TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    EXPECT_TRUE(contains(import_response.unenforced, TAG_KEY_SIZE, 1024));
+    EXPECT_TRUE(contains(import_response.unenforced, TAG_RSA_PUBLIC_EXPONENT, 65537U));
 
     // And values provided by GoogleKeymaster
-    EXPECT_TRUE(contains(auths, TAG_ORIGIN, KM_ORIGIN_IMPORTED));
-    EXPECT_TRUE(contains(auths, KM_TAG_CREATION_DATETIME));
+    EXPECT_TRUE(contains(import_response.unenforced, TAG_ORIGIN, KM_ORIGIN_IMPORTED));
+    EXPECT_TRUE(contains(import_response.unenforced, KM_TAG_CREATION_DATETIME));
 
     size_t message_len = 1024 / 8;
     UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
     std::fill(message.get(), message.get() + message_len, 'a');
-    SignMessage(message.get(), message_len);
-    VerifyMessage(message.get(), message_len);
+    SignMessage(import_response.key_blob, message.get(), message_len);
+    ASSERT_TRUE(signature() != NULL);
+    VerifyMessage(import_response.key_blob, message.get(), message_len);
 }
 
 TEST_F(ImportKeyTest, RsaKeySizeMismatch) {
-    params_.push_back(Authorization(TAG_KEY_SIZE, 2048));  // Doesn't match key
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_DIGEST, KM_DIGEST_NONE), Authorization(TAG_PADDING, KM_PAD_NONE),
+        Authorization(TAG_KEY_SIZE, 2048),  // Doesn't match key
+        Authorization(TAG_USER_ID, 7), Authorization(TAG_USER_AUTH_ID, 8),
+        Authorization(TAG_APPLICATION_ID, "app_id", 6), Authorization(TAG_AUTH_TIMEOUT, 300),
+    };
 
     string pk8_key = read_file("rsa_privkey_pk8.der");
     ASSERT_EQ(633U, pk8_key.size());
 
-    ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
-              device()->import_key(device(), params_.data(), params_.size(), KM_KEY_FORMAT_PKCS8,
-                                   reinterpret_cast<const uint8_t*>(pk8_key.data()), pk8_key.size(),
-                                   &blob_, &characteristics_));
+    ImportKeyRequest import_request;
+    import_request.key_description.Reinitialize(params, array_length(params));
+    import_request.key_format = KM_KEY_FORMAT_PKCS8;
+    import_request.SetKeyMaterial(pk8_key.data(), pk8_key.size());
+
+    ImportKeyResponse import_response;
+    device.ImportKey(import_request, &import_response);
+    ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH, import_response.error);
 }
 
 TEST_F(ImportKeyTest, RsaPublicExponenMismatch) {
-    params_.push_back(Authorization(TAG_RSA_PUBLIC_EXPONENT, 3));  // Doesn't match key
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_DIGEST, KM_DIGEST_NONE), Authorization(TAG_PADDING, KM_PAD_NONE),
+        Authorization(TAG_RSA_PUBLIC_EXPONENT, 3), Authorization(TAG_USER_ID, 7),
+        Authorization(TAG_USER_AUTH_ID, 8), Authorization(TAG_APPLICATION_ID, "app_id", 6),
+        Authorization(TAG_AUTH_TIMEOUT, 300),
+    };
 
     string pk8_key = read_file("rsa_privkey_pk8.der");
     ASSERT_EQ(633U, pk8_key.size());
 
-    ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
-              device()->import_key(device(), params_.data(), params_.size(), KM_KEY_FORMAT_PKCS8,
-                                   reinterpret_cast<const uint8_t*>(pk8_key.data()), pk8_key.size(),
-                                   &blob_, &characteristics_));
+    ImportKeyRequest import_request;
+    import_request.key_description.Reinitialize(params, array_length(params));
+    import_request.key_format = KM_KEY_FORMAT_PKCS8;
+    import_request.SetKeyMaterial(pk8_key.data(), pk8_key.size());
+
+    ImportKeyResponse import_response;
+    device.ImportKey(import_request, &import_response);
+    ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH, import_response.error);
 }
 
 TEST_F(ImportKeyTest, EcdsaSuccess) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_DIGEST, KM_DIGEST_NONE), Authorization(TAG_PADDING, KM_PAD_NONE),
+        Authorization(TAG_USER_ID, 7), Authorization(TAG_USER_AUTH_ID, 8),
+        Authorization(TAG_APPLICATION_ID, "app_id", 6), Authorization(TAG_AUTH_TIMEOUT, 300),
+    };
+
     string pk8_key = read_file("ec_privkey_pk8.der");
     ASSERT_EQ(138U, pk8_key.size());
 
-    ASSERT_EQ(KM_ERROR_OK,
-              device()->import_key(device(), params_.data(), params_.size(), KM_KEY_FORMAT_PKCS8,
-                                   reinterpret_cast<const uint8_t*>(pk8_key.data()), pk8_key.size(),
-                                   &blob_, &characteristics_));
-    EXPECT_EQ(0U, characteristics_->hw_enforced.length);
-    AuthorizationSet auths(characteristics_->sw_enforced);
+    ImportKeyRequest import_request;
+    import_request.key_description.Reinitialize(params, array_length(params));
+    import_request.key_format = KM_KEY_FORMAT_PKCS8;
+    import_request.SetKeyMaterial(pk8_key.data(), pk8_key.size());
+
+    ImportKeyResponse import_response;
+    device.ImportKey(import_request, &import_response);
+    ASSERT_EQ(KM_ERROR_OK, import_response.error);
+    EXPECT_EQ(0U, import_response.enforced.size());
+    EXPECT_GT(import_response.unenforced.size(), 0U);
 
     // Check values derived from the key.
-    EXPECT_TRUE(contains(auths, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
-    EXPECT_TRUE(contains(auths, TAG_KEY_SIZE, 256));
+    EXPECT_TRUE(contains(import_response.unenforced, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+    EXPECT_TRUE(contains(import_response.unenforced, TAG_KEY_SIZE, 256));
 
     // And values provided by GoogleKeymaster
-    EXPECT_TRUE(contains(auths, TAG_ORIGIN, KM_ORIGIN_IMPORTED));
-    EXPECT_TRUE(contains(auths, KM_TAG_CREATION_DATETIME));
+    EXPECT_TRUE(contains(import_response.unenforced, TAG_ORIGIN, KM_ORIGIN_IMPORTED));
+    EXPECT_TRUE(contains(import_response.unenforced, KM_TAG_CREATION_DATETIME));
 
-    size_t message_len = 1024;
+    size_t message_len = 1024 / 8;
     UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
     std::fill(message.get(), message.get() + message_len, 'a');
-    SignMessage(message.get(), message_len);
-    VerifyMessage(message.get(), message_len);
+    SignMessage(import_response.key_blob, message.get(), message_len);
+    ASSERT_TRUE(signature() != NULL);
+    VerifyMessage(import_response.key_blob, message.get(), message_len);
 }
 
-TEST_F(ImportKeyTest, EcdsaKeySizeMismatch) {
-    params_.push_back(Authorization(TAG_KEY_SIZE, 224));  // Doesn't match key
+TEST_F(ImportKeyTest, EcdsaSizeSpecified) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_DIGEST, KM_DIGEST_NONE), Authorization(TAG_PADDING, KM_PAD_NONE),
+        Authorization(TAG_USER_ID, 7), Authorization(TAG_USER_AUTH_ID, 8),
+        Authorization(TAG_APPLICATION_ID, "app_id", 6), Authorization(TAG_AUTH_TIMEOUT, 300),
+        Authorization(TAG_KEY_SIZE, 256),
+    };
 
-    string pk8_key = read_file("rsa_privkey_pk8.der");
-    ASSERT_EQ(633U, pk8_key.size());
+    string pk8_key = read_file("ec_privkey_pk8.der");
+    ASSERT_EQ(138U, pk8_key.size());
 
-    ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
-              device()->import_key(device(), params_.data(), params_.size(), KM_KEY_FORMAT_PKCS8,
-                                   reinterpret_cast<const uint8_t*>(pk8_key.data()), pk8_key.size(),
-                                   &blob_, &characteristics_));
+    ImportKeyRequest import_request;
+    import_request.key_description.Reinitialize(params, array_length(params));
+    import_request.key_format = KM_KEY_FORMAT_PKCS8;
+    import_request.SetKeyMaterial(pk8_key.data(), pk8_key.size());
+
+    ImportKeyResponse import_response;
+    device.ImportKey(import_request, &import_response);
+    ASSERT_EQ(KM_ERROR_OK, import_response.error);
+    EXPECT_EQ(0U, import_response.enforced.size());
+    EXPECT_GT(import_response.unenforced.size(), 0U);
+
+    // Check values derived from the key.
+    EXPECT_TRUE(contains(import_response.unenforced, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+    EXPECT_TRUE(contains(import_response.unenforced, TAG_KEY_SIZE, 256));
+
+    // And values provided by GoogleKeymaster
+    EXPECT_TRUE(contains(import_response.unenforced, TAG_ORIGIN, KM_ORIGIN_IMPORTED));
+    EXPECT_TRUE(contains(import_response.unenforced, KM_TAG_CREATION_DATETIME));
+
+    size_t message_len = 1024 / 8;
+    UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+    std::fill(message.get(), message.get() + message_len, 'a');
+    SignMessage(import_response.key_blob, message.get(), message_len);
+    ASSERT_TRUE(signature() != NULL);
+    VerifyMessage(import_response.key_blob, message.get(), message_len);
+}
+
+TEST_F(ImportKeyTest, EcdsaSizeMismatch) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_DIGEST, KM_DIGEST_NONE), Authorization(TAG_PADDING, KM_PAD_NONE),
+        Authorization(TAG_USER_ID, 7), Authorization(TAG_USER_AUTH_ID, 8),
+        Authorization(TAG_APPLICATION_ID, "app_id", 6), Authorization(TAG_AUTH_TIMEOUT, 300),
+        Authorization(TAG_KEY_SIZE, 224),
+    };
+
+    string pk8_key = read_file("ec_privkey_pk8.der");
+    ASSERT_EQ(138U, pk8_key.size());
+
+    ImportKeyRequest import_request;
+    import_request.key_description.Reinitialize(params, array_length(params));
+    import_request.key_format = KM_KEY_FORMAT_PKCS8;
+    import_request.SetKeyMaterial(pk8_key.data(), pk8_key.size());
+
+    ImportKeyResponse import_response;
+    device.ImportKey(import_request, &import_response);
+    ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH, import_response.error);
 }
 
 typedef KeymasterTest VersionTest;
 TEST_F(VersionTest, GetVersion) {
     GetVersionRequest req;
     GetVersionResponse rsp;
-    device_.GetVersion(req, &rsp);
+    device.GetVersion(req, &rsp);
     EXPECT_EQ(KM_ERROR_OK, rsp.error);
     EXPECT_EQ(1, rsp.major_ver);
     EXPECT_EQ(0, rsp.minor_ver);
@@ -923,67 +964,75 @@
   protected:
     void GenerateKey(keymaster_algorithm_t algorithm, keymaster_padding_t padding,
                      uint32_t key_size) {
-        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
-        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT));
-        params_.push_back(Authorization(TAG_ALGORITHM, algorithm));
-        params_.push_back(Authorization(TAG_KEY_SIZE, key_size));
-        params_.push_back(Authorization(TAG_USER_ID, 7));
-        params_.push_back(Authorization(TAG_USER_AUTH_ID, 8));
-        params_.push_back(Authorization(TAG_APPLICATION_ID, "app_id", 6));
-        params_.push_back(Authorization(TAG_AUTH_TIMEOUT, 300));
+        keymaster_key_param_t params[] = {
+            Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT),
+            Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT), Authorization(TAG_ALGORITHM, algorithm),
+            Authorization(TAG_KEY_SIZE, key_size), Authorization(TAG_USER_ID, 7),
+            Authorization(TAG_USER_AUTH_ID, 8), Authorization(TAG_APPLICATION_ID, "app_id", 6),
+            Authorization(TAG_AUTH_TIMEOUT, 300),
+        };
+        GenerateKeyRequest generate_request;
+        generate_request.key_description.Reinitialize(params, array_length(params));
         if (static_cast<int>(padding) != -1)
-            params_.push_back(TAG_PADDING, padding);
-        EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(),
-                                                      &blob_, &characteristics_));
+            generate_request.key_description.push_back(TAG_PADDING, padding);
+        device.GenerateKey(generate_request, &generate_response_);
+        EXPECT_EQ(KM_ERROR_OK, generate_response_.error);
     }
 
     void GenerateSymmetricKey(keymaster_algorithm_t algorithm, uint32_t key_size,
                               keymaster_block_mode_t block_mode, uint32_t chunk_length) {
-        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
-        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT));
-        params_.push_back(Authorization(TAG_ALGORITHM, algorithm));
-        params_.push_back(Authorization(TAG_BLOCK_MODE, block_mode));
-        params_.push_back(Authorization(TAG_CHUNK_LENGTH, chunk_length));
-        params_.push_back(Authorization(TAG_KEY_SIZE, key_size));
-        params_.push_back(Authorization(TAG_MAC_LENGTH, 16));
-        params_.push_back(Authorization(TAG_USER_ID, 7));
-        params_.push_back(Authorization(TAG_USER_AUTH_ID, 8));
-        params_.push_back(Authorization(TAG_APPLICATION_ID, "app_id", 6));
-        params_.push_back(Authorization(TAG_AUTH_TIMEOUT, 300));
-
-        EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(),
-                                                      &blob_, &characteristics_));
+        keymaster_key_param_t params[] = {
+            Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT),
+            Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT), Authorization(TAG_ALGORITHM, algorithm),
+            Authorization(TAG_BLOCK_MODE, block_mode),
+            Authorization(TAG_CHUNK_LENGTH, chunk_length), Authorization(TAG_KEY_SIZE, key_size),
+            Authorization(TAG_MAC_LENGTH, 16), Authorization(TAG_USER_ID, 7),
+            Authorization(TAG_USER_AUTH_ID, 8), Authorization(TAG_APPLICATION_ID, "app_id", 6),
+            Authorization(TAG_AUTH_TIMEOUT, 300),
+        };
+        GenerateKeyRequest generate_request;
+        generate_request.key_description.Reinitialize(params, array_length(params));
+        device.GenerateKey(generate_request, &generate_response_);
+        EXPECT_EQ(KM_ERROR_OK, generate_response_.error);
     }
 
     keymaster_error_t BeginOperation(keymaster_purpose_t purpose,
                                      const keymaster_key_blob_t& key_blob, uint64_t* op_handle) {
-        return device()->begin(device(), purpose, &key_blob, client_params_,
-                               array_length(client_params_), &out_params_, &out_params_count_,
-                               op_handle);
+        BeginOperationRequest begin_request;
+        begin_request.SetKeyMaterial(key_blob);
+        begin_request.purpose = purpose;
+        AddClientParams(&begin_request.additional_params);
+
+        BeginOperationResponse begin_response;
+        device.BeginOperation(begin_request, &begin_response);
+        *op_handle = begin_response.op_handle;
+        return begin_response.error;
     }
 
     keymaster_error_t UpdateOperation(uint64_t op_handle, const void* message, size_t size,
                                       string* output, size_t* input_consumed) {
-        uint8_t* out_tmp = NULL;
-        size_t out_length;
-        keymaster_error_t error =
-            device()->update(device(), op_handle, reinterpret_cast<const uint8_t*>(message), size,
-                             input_consumed, &out_tmp, &out_length);
-        if (out_tmp)
-            *output = string(reinterpret_cast<char*>(out_tmp), out_length);
-        free(out_tmp);
-        return error;
+        UpdateOperationRequest update_request;
+        update_request.op_handle = op_handle;
+        update_request.input.Reinitialize(message, size);
+
+        UpdateOperationResponse update_response;
+        device.UpdateOperation(update_request, &update_response);
+        if (update_response.error == KM_ERROR_OK)
+            output->append(reinterpret_cast<const char*>(update_response.output.peek_read()),
+                           update_response.output.available_read());
+        *input_consumed = update_response.input_consumed;
+        return update_response.error;
     }
 
     keymaster_error_t FinishOperation(uint64_t op_handle, string* output) {
-        uint8_t* out_tmp = NULL;
-        size_t out_length;
-        keymaster_error_t error = device()->finish(device(), op_handle, NULL /* signature */,
-                                                   0 /* signature_length */, &out_tmp, &out_length);
-        if (out_tmp)
-            *output = string(reinterpret_cast<char*>(out_tmp), out_length);
-        free(out_tmp);
-        return error;
+        FinishOperationRequest finish_request;
+        finish_request.op_handle = op_handle;
+        FinishOperationResponse finish_response;
+        device.FinishOperation(finish_request, &finish_response);
+        if (finish_response.error == KM_ERROR_OK)
+            output->append(reinterpret_cast<const char*>(finish_response.output.peek_read()),
+                           finish_response.output.available_read());
+        return finish_response.error;
     }
 
     string ProcessMessage(keymaster_purpose_t purpose, const keymaster_key_blob_t& key_blob,
@@ -1001,27 +1050,25 @@
     }
 
     string EncryptMessage(const void* message, size_t size) {
-        return ProcessMessage(KM_PURPOSE_ENCRYPT, blob_, message, size);
+        return ProcessMessage(KM_PURPOSE_ENCRYPT, generate_response_.key_blob, message, size);
     }
 
     string DecryptMessage(const void* ciphertext, size_t size) {
-        return ProcessMessage(KM_PURPOSE_DECRYPT, blob_, ciphertext, size);
+        return ProcessMessage(KM_PURPOSE_DECRYPT, generate_response_.key_blob, ciphertext, size);
     }
 
     void AddClientParams(AuthorizationSet* set) { set->push_back(TAG_APPLICATION_ID, "app_id", 6); }
 
-    const void corrupt_key_blob() {
-        uint8_t* tmp = const_cast<uint8_t*>(blob_.key_material);
-        ++tmp[blob_.key_material_size / 2];
+    const keymaster_key_blob_t& key_blob() { return generate_response_.key_blob; }
+
+    const keymaster_key_blob_t& corrupt_key_blob() {
+        uint8_t* tmp = const_cast<uint8_t*>(generate_response_.key_blob.key_material);
+        ++tmp[generate_response_.key_blob.key_material_size / 2];
+        return generate_response_.key_blob;
     }
 
-    keymaster_blob_t client_id_ = {.data = reinterpret_cast<const uint8_t*>("app_id"),
-                                   .data_length = 6};
-    keymaster_key_param_t client_params_[1] = {
-        Authorization(TAG_APPLICATION_ID, client_id_.data, client_id_.data_length)};
-
-    keymaster_key_param_t* out_params_;
-    size_t out_params_count_;
+  protected:
+    GenerateKeyResponse generate_response_;
 };
 
 TEST_F(EncryptionOperationsTest, RsaOaepSuccess) {
@@ -1054,7 +1101,8 @@
     string result;
     size_t input_consumed;
 
-    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, blob_, &op_handle));
+    EXPECT_EQ(KM_ERROR_OK,
+              BeginOperation(KM_PURPOSE_ENCRYPT, generate_response_.key_blob, &op_handle));
     EXPECT_EQ(KM_ERROR_OK,
               UpdateOperation(op_handle, message, array_size(message), &result, &input_consumed));
     EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(op_handle, &result));
@@ -1073,7 +1121,8 @@
     uint64_t op_handle;
     string result;
     size_t input_consumed;
-    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, blob_, &op_handle));
+    EXPECT_EQ(KM_ERROR_OK,
+              BeginOperation(KM_PURPOSE_DECRYPT, generate_response_.key_blob, &op_handle));
     EXPECT_EQ(KM_ERROR_OK, UpdateOperation(op_handle, ciphertext.data(), ciphertext.size(), &result,
                                            &input_consumed));
     EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(op_handle, &result));
@@ -1110,7 +1159,8 @@
     string result;
     size_t input_consumed;
 
-    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, blob_, &op_handle));
+    EXPECT_EQ(KM_ERROR_OK,
+              BeginOperation(KM_PURPOSE_ENCRYPT, generate_response_.key_blob, &op_handle));
     EXPECT_EQ(KM_ERROR_OK,
               UpdateOperation(op_handle, message, array_size(message), &result, &input_consumed));
     EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(op_handle, &result));
@@ -1129,7 +1179,8 @@
     uint64_t op_handle;
     string result;
     size_t input_consumed;
-    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, blob_, &op_handle));
+    EXPECT_EQ(KM_ERROR_OK,
+              BeginOperation(KM_PURPOSE_DECRYPT, generate_response_.key_blob, &op_handle));
     EXPECT_EQ(KM_ERROR_OK, UpdateOperation(op_handle, ciphertext.data(), ciphertext.size(), &result,
                                            &input_consumed));
     EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(op_handle, &result));