Add RSA signing support.

Change-Id: Icdcbd978d58c8764618b995571d1e8b649959ef0
diff --git a/google_keymaster_test.cpp b/google_keymaster_test.cpp
index 945a0e6..4c8c28e 100644
--- a/google_keymaster_test.cpp
+++ b/google_keymaster_test.cpp
@@ -37,7 +37,8 @@
 
 class KeymasterTest : public testing::Test {
   protected:
-    KeymasterTest() {
+    KeymasterTest() : device(5) {
+        RAND_seed("foobar", 6);
     }
     ~KeymasterTest() {
     }
@@ -237,7 +238,7 @@
         Authorization(TAG_KEY_SIZE, 256),
         Authorization(TAG_USER_ID, 7),
         Authorization(TAG_USER_AUTH_ID, 8),
-        Authorization(TAG_APPLICATION_ID, reinterpret_cast<const uint8_t*>("app_id"), 6),
+        Authorization(TAG_APPLICATION_ID, "app_id", 6),
         Authorization(TAG_AUTH_TIMEOUT, 300),
     };
 
@@ -246,13 +247,11 @@
     GenerateKeyResponse gen_rsp;
 
     device.GenerateKey(gen_req, &gen_rsp);
+    ASSERT_EQ(KM_ERROR_OK, gen_rsp.error);
 
     GetKeyCharacteristicsRequest req;
     req.key_blob = gen_rsp.key_blob;
-    req.client_id.data = reinterpret_cast<const uint8_t*>("app_id");
-    req.client_id.data_length = 6;
-    req.app_data.data = NULL;
-    req.app_data.data_length = 0;
+    req.additional_params.push_back(TAG_APPLICATION_ID, "app_id", 6);
 
     GetKeyCharacteristicsResponse rsp;
     device.GetKeyCharacteristics(req, &rsp);
@@ -262,5 +261,186 @@
     EXPECT_EQ(gen_rsp.unenforced, rsp.unenforced);
 }
 
+class SigningOperationsTest : public KeymasterTest {
+  protected:
+    keymaster_key_blob_t* GenerateKey(keymaster_digest_t digest, keymaster_padding_t padding,
+                                      uint32_t key_size) {
+        keymaster_key_param_t params[] = {
+            Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+            Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+            Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
+            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 (digest != -1)
+            generate_request.key_description.push_back(TAG_DIGEST, digest);
+        if (padding != -1)
+            generate_request.key_description.push_back(TAG_PADDING, padding);
+        device.GenerateKey(generate_request, &generate_response_);
+        EXPECT_EQ(KM_ERROR_OK, generate_response_.error);
+
+        // This is safe because generate_response_ lives as long as the test and will keep the key
+        // blob around.
+        return &generate_response_.key_blob;
+    }
+
+  private:
+    GenerateKeyResponse generate_response_;
+};
+
+TEST_F(SigningOperationsTest, RsaSuccess) {
+    keymaster_key_blob_t* key = GenerateKey(KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
+    ASSERT_TRUE(key != NULL);
+
+    BeginOperationRequest begin_request;
+    BeginOperationResponse begin_response;
+    begin_request.key_blob = *key;
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    begin_request.additional_params.push_back(TAG_APPLICATION_ID, "app_id", 6);
+
+    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("012345678901234567890123456789012", 32);
+    EXPECT_EQ(32U, 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());
+
+    FinishOperationResponse finish_response;
+    device.FinishOperation(begin_response.op_handle, &finish_response);
+    ASSERT_EQ(KM_ERROR_OK, finish_response.error);
+    EXPECT_GT(finish_response.signature.available_read(), 0U);
+    EXPECT_EQ(0U, finish_response.output.available_read());
+
+    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
+}
+
+TEST_F(SigningOperationsTest, RsaAbort) {
+    keymaster_key_blob_t* key = GenerateKey(KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
+    ASSERT_TRUE(key != NULL);
+
+    BeginOperationRequest begin_request;
+    BeginOperationResponse begin_response;
+    begin_request.key_blob = *key;
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    begin_request.additional_params.push_back(TAG_APPLICATION_ID, "app_id", 6);
+
+    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) {
+    keymaster_key_blob_t* key = GenerateKey(KM_DIGEST_SHA_2_256, KM_PAD_NONE, 256 /* key size */);
+    ASSERT_TRUE(key != NULL);
+
+    BeginOperationRequest begin_request;
+    BeginOperationResponse begin_response;
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    begin_request.key_blob = *key;
+    begin_request.additional_params.push_back(TAG_APPLICATION_ID, "app_id", 6);
+
+    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) {
+    keymaster_key_blob_t* key = GenerateKey(KM_DIGEST_NONE, KM_PAD_RSA_OAEP, 256 /* key size */);
+    ASSERT_TRUE(key != NULL);
+
+    BeginOperationRequest begin_request;
+    BeginOperationResponse begin_response;
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    begin_request.key_blob = *key;
+    begin_request.additional_params.push_back(TAG_APPLICATION_ID, "app_id", 6);
+
+    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) {
+    keymaster_key_blob_t* key =
+        GenerateKey(static_cast<keymaster_digest_t>(-1), KM_PAD_NONE, 256 /* key size */);
+    ASSERT_TRUE(key != NULL);
+
+    BeginOperationRequest begin_request;
+    BeginOperationResponse begin_response;
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    begin_request.key_blob = *key;
+    begin_request.additional_params.push_back(TAG_APPLICATION_ID, "app_id", 6);
+
+    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) {
+    keymaster_key_blob_t* key =
+        GenerateKey(KM_DIGEST_NONE, static_cast<keymaster_padding_t>(-1), 256 /* key size */);
+    ASSERT_TRUE(key != NULL);
+
+    BeginOperationRequest begin_request;
+    BeginOperationResponse begin_response;
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    begin_request.key_blob = *key;
+    begin_request.additional_params.push_back(TAG_APPLICATION_ID, "app_id", 6);
+
+    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) {
+    keymaster_key_blob_t* key = GenerateKey(KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
+    ASSERT_TRUE(key != NULL);
+
+    BeginOperationRequest begin_request;
+    BeginOperationResponse begin_response;
+    begin_request.key_blob = *key;
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    begin_request.additional_params.push_back(TAG_APPLICATION_ID, "app_id", 6);
+
+    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());
+
+    FinishOperationResponse finish_response;
+    device.FinishOperation(begin_response.op_handle, &finish_response);
+    ASSERT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, finish_response.error);
+    EXPECT_EQ(0U, finish_response.signature.available_read());
+    EXPECT_EQ(0U, finish_response.output.available_read());
+
+    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
+}
+
 }  // namespace test
 }  // namespace keymaster