Add RSA verification.

Change-Id: Ie9ac37dba7ead62b0ca17054bbf6d2744cea5946
diff --git a/google_keymaster.cpp b/google_keymaster.cpp
index 9849d2b..d841b25 100644
--- a/google_keymaster.cpp
+++ b/google_keymaster.cpp
@@ -298,15 +298,15 @@
     }
 }
 
-void GoogleKeymaster::FinishOperation(const keymaster_operation_handle_t op_handle,
+void GoogleKeymaster::FinishOperation(const FinishOperationRequest& request,
                                       FinishOperationResponse* response) {
-    OpTableEntry* entry = FindOperation(op_handle);
+    OpTableEntry* entry = FindOperation(request.op_handle);
     if (entry == NULL) {
         response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
         return;
     }
 
-    response->error = entry->operation->Finish(&response->signature, &response->output);
+    response->error = entry->operation->Finish(request.signature, &response->output);
     DeleteOperation(entry);
 }
 
diff --git a/google_keymaster.h b/google_keymaster.h
index cf5bcb1..d8543e8 100644
--- a/google_keymaster.h
+++ b/google_keymaster.h
@@ -75,8 +75,7 @@
     }
     void BeginOperation(const BeginOperationRequest& request, BeginOperationResponse* response);
     void UpdateOperation(const UpdateOperationRequest& request, UpdateOperationResponse* response);
-    void FinishOperation(const keymaster_operation_handle_t op_handle,
-                         FinishOperationResponse* response);
+    void FinishOperation(const FinishOperationRequest& request, FinishOperationResponse* response);
     keymaster_error_t AbortOperation(const keymaster_operation_handle_t op_handle);
 
   private:
diff --git a/google_keymaster_messages.h b/google_keymaster_messages.h
index d116280..2825ab7 100644
--- a/google_keymaster_messages.h
+++ b/google_keymaster_messages.h
@@ -127,9 +127,13 @@
     Buffer output;
 };
 
+struct FinishOperationRequest {
+    keymaster_operation_handle_t op_handle;
+    Buffer signature;
+};
+
 struct FinishOperationResponse {
     keymaster_error_t error;
-    Buffer signature;
     Buffer output;
 };
 
diff --git a/google_keymaster_test.cpp b/google_keymaster_test.cpp
index 4c8c28e..cb9c32e 100644
--- a/google_keymaster_test.cpp
+++ b/google_keymaster_test.cpp
@@ -277,9 +277,9 @@
         };
         GenerateKeyRequest generate_request;
         generate_request.key_description.Reinitialize(params, array_length(params));
-        if (digest != -1)
+        if (static_cast<int>(digest) != -1)
             generate_request.key_description.push_back(TAG_DIGEST, digest);
-        if (padding != -1)
+        if (static_cast<int>(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);
@@ -316,11 +316,12 @@
     ASSERT_EQ(KM_ERROR_OK, update_response.error);
     EXPECT_EQ(0U, update_response.output.available_read());
 
+    FinishOperationRequest finish_request;
+    finish_request.op_handle = begin_response.op_handle;
     FinishOperationResponse finish_response;
-    device.FinishOperation(begin_response.op_handle, &finish_response);
+    device.FinishOperation(finish_request, &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_GT(finish_response.output.available_read(), 0U);
 
     EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
 }
@@ -433,10 +434,117 @@
     ASSERT_EQ(KM_ERROR_OK, update_response.error);
     EXPECT_EQ(0U, update_response.output.available_read());
 
+    FinishOperationRequest finish_request;
+    finish_request.op_handle = begin_response.op_handle;
     FinishOperationResponse finish_response;
-    device.FinishOperation(begin_response.op_handle, &finish_response);
+    device.FinishOperation(finish_request, &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));
+}
+
+class VerificationOperationsTest : public KeymasterTest {
+  protected:
+    VerificationOperationsTest() {
+        generate_response_.error = KM_ERROR_UNKNOWN_ERROR;
+        finish_response_.error = KM_ERROR_UNKNOWN_ERROR;
+    }
+
+    void 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 (static_cast<int>(digest) != -1)
+            generate_request.key_description.push_back(TAG_DIGEST, digest);
+        if (static_cast<int>(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);
+
+        BeginOperationRequest begin_request;
+        BeginOperationResponse begin_response;
+        begin_request.key_blob = generate_response_.key_blob;
+        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());
+
+        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);
+    }
+
+    keymaster_key_blob_t* key_blob() {
+        if (generate_response_.error == KM_ERROR_OK)
+            return &generate_response_.key_blob;
+        return NULL;
+    }
+
+    Buffer* signature() {
+        if (finish_response_.error == KM_ERROR_OK)
+            return &finish_response_.output;
+        return NULL;
+    }
+
+  private:
+    GenerateKeyResponse generate_response_;
+    FinishOperationResponse finish_response_;
+};
+
+TEST_F(VerificationOperationsTest, RsaSuccess) {
+    GenerateKey(KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
+    ASSERT_TRUE(key_blob() != NULL);
+    ASSERT_TRUE(signature() != NULL);
+
+    BeginOperationRequest begin_request;
+    BeginOperationResponse begin_response;
+    begin_request.key_blob = *key_blob();
+    begin_request.purpose = KM_PURPOSE_VERIFY;
+    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());
+
+    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));
diff --git a/google_keymaster_utils.cpp b/google_keymaster_utils.cpp
index bd44cfd..89e6968 100644
--- a/google_keymaster_utils.cpp
+++ b/google_keymaster_utils.cpp
@@ -71,4 +71,13 @@
     return true;
 }
 
+int memcmp_s(const void* p1, const void* p2, size_t length) {
+    const uint8_t* s1 = static_cast<const uint8_t*>(p1);
+    const uint8_t* s2 = static_cast<const uint8_t*>(p2);
+    uint8_t result = 0;
+    while (length-- > 0)
+        result |= *s1++ ^ *s2++;
+    return result == 0 ? 0 : 1;
+}
+
 }  // namespace keymaster
diff --git a/google_keymaster_utils.h b/google_keymaster_utils.h
index abef785..5d4c677 100644
--- a/google_keymaster_utils.h
+++ b/google_keymaster_utils.h
@@ -96,16 +96,22 @@
  * optimized away.  This is important because we often need to wipe blocks of sensitive data from
  * memory.
  */
-#ifndef KEYMASTER_CLANG_TEST_BUILD
-#pragma GCC push_options
-#pragma GCC optimize("O0")
-#endif  // not KEYMASTER_CLANG_TEST_BUILD
-inline void* memset_s(void* s, int c, size_t n) {
+#ifdef KEYMASTER_CLANG_TEST_BUILD
+#define OPTIMIZE(x)
+#else // not KEYMASTER_CLANG_TEST_BUILD
+#define OPTIMIZE(x) __attribute__((optimize(x)))
+#endif // not KEYMASTER_CLANG_TEST_BUILD
+inline OPTIMIZE("O0") void* memset_s(void* s, int c, size_t n) {
     return memset(s, c, n);
 }
-#ifndef KEYMASTER_CLANG_TEST_BUILD
-#pragma GCC pop_options
-#endif  // not KEYMASTER_CLANG_TEST_BUILD
+#undef OPTIMIZE
+
+/**
+ * Variant of memcmp that has the same runtime regardless of whether the data matches (i.e. doesn't
+ * short-circuit).  Not an exact equivalent to memcmp because it doesn't return <0 if p1 < p2, just
+ * 0 for match and non-zero for non-match.
+ */
+int memcmp_s(const void* p1, const void* p2, size_t length);
 
 /**
  * Eraser clears buffers.  Construct it with a buffer or object and the destructor will ensure that
@@ -156,6 +162,11 @@
     bool Reinitialize(size_t size);
     bool Reinitialize(const void* buf, size_t size);
 
+    // Reinitialize with a copy of the provided buffer's readable data.
+    bool Reinitialize(const Buffer& buffer) {
+        return Reinitialize(buffer.peek_read(), buffer.available_read());
+    }
+
     size_t available_write() const;
     size_t available_read() const;
     size_t buffer_size() const {
@@ -178,6 +189,10 @@
     }
 
   private:
+    // Disallow copy construction and assignment.
+    void operator=(const Buffer& other);
+    Buffer(const Buffer&);
+
     uint8_t* buffer_;
     size_t buffer_size_;
     int read_position_;
diff --git a/operation.h b/operation.h
index 222c24f..64ca40b 100644
--- a/operation.h
+++ b/operation.h
@@ -42,7 +42,7 @@
 
     virtual keymaster_error_t Begin() = 0;
     virtual keymaster_error_t Update(const Buffer& input, Buffer* output) = 0;
-    virtual keymaster_error_t Finish(Buffer* signature, Buffer* output) = 0;
+    virtual keymaster_error_t Finish(const Buffer& signature, Buffer* output) = 0;
     virtual keymaster_error_t Abort() = 0;
 
   private:
diff --git a/rsa_operation.cpp b/rsa_operation.cpp
index 4635154..620df65 100644
--- a/rsa_operation.cpp
+++ b/rsa_operation.cpp
@@ -66,7 +66,7 @@
 
     // Since we're not using a digest function, we just need to store the text, up to the key
     // size, until Finish is called, so we allocate a place to put it.
-    if (!data_to_sign_.Reinitialize(RSA_size(rsa_key_))) {
+    if (!data_.Reinitialize(RSA_size(rsa_key_))) {
         error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
         return;
     }
@@ -78,37 +78,54 @@
         RSA_free(rsa_key_);
 }
 
-keymaster_error_t RsaOperation::Update(const Buffer& input, Buffer* output) {
+keymaster_error_t RsaOperation::Update(const Buffer& input, Buffer* /* output */) {
     switch (purpose()) {
     default:
         return KM_ERROR_UNIMPLEMENTED;
     case KM_PURPOSE_SIGN:
-        return Sign(input, output);
+    case KM_PURPOSE_VERIFY:
+        return StoreData(input);
     }
 }
 
-keymaster_error_t RsaOperation::Sign(const Buffer& input, Buffer* /* output */) {
-    if (!data_to_sign_.write(input.peek_read(), input.available_read()))
+keymaster_error_t RsaOperation::StoreData(const Buffer& input) {
+    if (!data_.write(input.peek_read(), input.available_read()))
         return KM_ERROR_INVALID_INPUT_LENGTH;
     return KM_ERROR_OK;
 }
 
-keymaster_error_t RsaOperation::Finish(Buffer* signature, Buffer* /* output */) {
+keymaster_error_t RsaOperation::Finish(const Buffer& signature, Buffer* output) {
     switch (purpose()) {
     case KM_PURPOSE_SIGN: {
-        signature->Reinitialize(RSA_size(rsa_key_));
-        if (data_to_sign_.available_read() != signature->buffer_size())
+        output->Reinitialize(RSA_size(rsa_key_));
+        if (data_.available_read() != output->buffer_size())
             return KM_ERROR_INVALID_INPUT_LENGTH;
 
-        int bytes_encrypted =
-            RSA_private_encrypt(data_to_sign_.available_read(), data_to_sign_.peek_read(),
-                                signature->peek_write(), rsa_key_, RSA_NO_PADDING);
+        int bytes_encrypted = RSA_private_encrypt(data_.available_read(), data_.peek_read(),
+                                                  output->peek_write(), rsa_key_, RSA_NO_PADDING);
         if (bytes_encrypted < 0)
             return KM_ERROR_UNKNOWN_ERROR;
         assert(bytes_encrypted == RSA_size(rsa_key_));
-        signature->advance_write(bytes_encrypted);
+        output->advance_write(bytes_encrypted);
         return KM_ERROR_OK;
     }
+    case KM_PURPOSE_VERIFY: {
+        if ((int)data_.available_read() != RSA_size(rsa_key_))
+            return KM_ERROR_INVALID_INPUT_LENGTH;
+        if (data_.available_read() != signature.available_read())
+            return KM_ERROR_VERIFICATION_FAILED;
+
+        UniquePtr<uint8_t[]> decrypted_data(new uint8_t[RSA_size(rsa_key_)]);
+        int bytes_decrypted = RSA_public_decrypt(signature.available_read(), signature.peek_read(),
+                                                 decrypted_data.get(), rsa_key_, RSA_NO_PADDING);
+        if (bytes_decrypted < 0)
+            return KM_ERROR_UNKNOWN_ERROR;
+        assert(bytes_decrypted == RSA_size(rsa_key_));
+
+        if (memcmp_s(decrypted_data.get(), data_.peek_read(), data_.available_read()) == 0)
+            return KM_ERROR_OK;
+        return KM_ERROR_VERIFICATION_FAILED;
+    }
     default:
         return KM_ERROR_UNIMPLEMENTED;
     }
diff --git a/rsa_operation.h b/rsa_operation.h
index 1c88131..7884798 100644
--- a/rsa_operation.h
+++ b/rsa_operation.h
@@ -34,20 +34,20 @@
         return error_;
     }
     virtual keymaster_error_t Update(const Buffer& input, Buffer* output);
-    virtual keymaster_error_t Finish(Buffer* signature, Buffer* output);
+    virtual keymaster_error_t Finish(const Buffer& signature, Buffer* output);
     virtual keymaster_error_t Abort() {
         // Nothing to do.
         return KM_ERROR_OK;
     }
 
   private:
-    keymaster_error_t Sign(const Buffer& input, Buffer* output);
+    keymaster_error_t StoreData(const Buffer& input);
 
     keymaster_error_t error_;
     keymaster_digest_t digest_;
     keymaster_padding_t padding_;
     RSA* rsa_key_;
-    Buffer data_to_sign_;
+    Buffer data_;
 };
 
 }  // namespace keymaster