Add RSA signing support.
Change-Id: Icdcbd978d58c8764618b995571d1e8b649959ef0
diff --git a/google_keymaster.cpp b/google_keymaster.cpp
index 96cfbda..9849d2b 100644
--- a/google_keymaster.cpp
+++ b/google_keymaster.cpp
@@ -22,6 +22,7 @@
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
+#include <openssl/rand.h>
#include <UniquePtr.h>
@@ -29,12 +30,20 @@
#include "google_keymaster.h"
#include "google_keymaster_utils.h"
#include "key_blob.h"
+#include "rsa_operation.h"
namespace keymaster {
-GoogleKeymaster::GoogleKeymaster() {
+GoogleKeymaster::GoogleKeymaster(size_t operation_table_size)
+ : operation_table_(new OpTableEntry[operation_table_size]),
+ operation_table_size_(operation_table_size) {
+ if (operation_table_.get() == NULL)
+ operation_table_size_ = 0;
}
GoogleKeymaster::~GoogleKeymaster() {
+ for (size_t i = 0; i < operation_table_size_; ++i)
+ if (operation_table_[i].operation != NULL)
+ delete operation_table_[i].operation;
}
const int RSA_DEFAULT_KEY_SIZE = 2048;
@@ -197,7 +206,7 @@
GenerateKeyResponse* response) {
if (response == NULL)
return;
- response->error = KM_ERROR_OK;
+ response->error = KM_ERROR_UNKNOWN_ERROR;
if (!CopyAuthorizations(request.key_description, response))
return;
@@ -221,24 +230,92 @@
response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
return;
}
+
+ response->error = KM_ERROR_OK;
}
void GoogleKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
GetKeyCharacteristicsResponse* response) {
- AuthorizationSet hidden;
- hidden.push_back(TAG_APPLICATION_ID, request.client_id.data, request.client_id.data_length);
- if (request.app_data.data != NULL)
- hidden.push_back(TAG_APPLICATION_DATA, request.app_data.data, request.app_data.data_length);
- hidden.push_back(RootOfTrustTag());
+ if (response == NULL)
+ return;
+ response->error = KM_ERROR_UNKNOWN_ERROR;
- KeyBlob blob(request.key_blob, hidden, MasterKey());
- if (blob.error() != KM_ERROR_OK) {
- response->error = blob.error();
+ UniquePtr<KeyBlob> blob(
+ LoadKeyBlob(request.key_blob, request.additional_params, &(response->error)));
+ if (blob.get() == NULL)
+ return;
+
+ response->enforced.Reinitialize(blob->enforced());
+ response->unenforced.Reinitialize(blob->unenforced());
+ response->error = KM_ERROR_OK;
+}
+
+void GoogleKeymaster::BeginOperation(const BeginOperationRequest& request,
+ BeginOperationResponse* response) {
+ if (response == NULL)
+ return;
+ response->error = KM_ERROR_UNKNOWN_ERROR;
+ response->op_handle = 0;
+
+ UniquePtr<KeyBlob> key(
+ LoadKeyBlob(request.key_blob, request.additional_params, &response->error));
+ if (key.get() == NULL)
+ return;
+
+ UniquePtr<Operation> operation;
+ switch (key->algorithm()) {
+ case KM_ALGORITHM_RSA:
+ operation.reset(new RsaOperation(request.purpose, *key));
+ break;
+ default:
+ response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+ break;
+ }
+
+ if (operation.get() == NULL) {
return;
}
- response->enforced.Reinitialize(blob.enforced());
- response->unenforced.Reinitialize(blob.unenforced());
- response->error = KM_ERROR_OK;
+
+ response->error = operation->Begin();
+ if (response->error != KM_ERROR_OK)
+ return;
+
+ response->error = AddOperation(operation.release(), &response->op_handle);
+}
+
+void GoogleKeymaster::UpdateOperation(const UpdateOperationRequest& request,
+ UpdateOperationResponse* response) {
+ OpTableEntry* entry = FindOperation(request.op_handle);
+ if (entry == NULL) {
+ response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
+ return;
+ }
+
+ response->error = entry->operation->Update(request.input, &response->output);
+ if (response->error != KM_ERROR_OK) {
+ // Any error invalidates the operation.
+ DeleteOperation(entry);
+ }
+}
+
+void GoogleKeymaster::FinishOperation(const keymaster_operation_handle_t op_handle,
+ FinishOperationResponse* response) {
+ OpTableEntry* entry = FindOperation(op_handle);
+ if (entry == NULL) {
+ response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
+ return;
+ }
+
+ response->error = entry->operation->Finish(&response->signature, &response->output);
+ DeleteOperation(entry);
+}
+
+keymaster_error_t GoogleKeymaster::AbortOperation(const keymaster_operation_handle_t op_handle) {
+ OpTableEntry* entry = FindOperation(op_handle);
+ if (entry == NULL)
+ return KM_ERROR_INVALID_OPERATION_HANDLE;
+ DeleteOperation(entry);
+ return KM_ERROR_OK;
}
bool GoogleKeymaster::GenerateRsa(const AuthorizationSet& key_auths, GenerateKeyResponse* response,
@@ -320,6 +397,22 @@
return true;
}
+KeyBlob* GoogleKeymaster::LoadKeyBlob(const keymaster_key_blob_t& key,
+ const AuthorizationSet& client_params,
+ keymaster_error_t* error) {
+ AuthorizationSet hidden;
+ BuildHiddenAuthorizations(client_params, &hidden);
+ UniquePtr<KeyBlob> blob(new KeyBlob(key, hidden, MasterKey()));
+ if (blob.get() == NULL) {
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return NULL;
+ } else if (blob->error() != KM_ERROR_OK) {
+ *error = blob->error();
+ return NULL;
+ }
+ return blob.release();
+}
+
static keymaster_error_t CheckAuthorizationSet(const AuthorizationSet& set) {
switch (set.is_valid()) {
case AuthorizationSet::OK:
@@ -364,7 +457,7 @@
}
keymaster_error_t GoogleKeymaster::BuildHiddenAuthorizations(const AuthorizationSet& input_set,
- AuthorizationSet* hidden) {
+ AuthorizationSet* hidden) {
keymaster_blob_t entry;
if (input_set.GetTagValue(TAG_APPLICATION_ID, &entry))
hidden->push_back(TAG_APPLICATION_ID, entry.data, entry.data_length);
@@ -392,4 +485,42 @@
}
}
+keymaster_error_t GoogleKeymaster::AddOperation(Operation* operation,
+ keymaster_operation_handle_t* op_handle) {
+ UniquePtr<Operation> op(operation);
+ if (RAND_bytes(reinterpret_cast<uint8_t*>(op_handle), sizeof(*op_handle)) == 0)
+ return KM_ERROR_UNKNOWN_ERROR;
+ if (*op_handle == 0){
+ // Statistically this is vanishingly unlikely, which means if it ever happens in practice,
+ // it indicates a broken RNG.
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+ for (size_t i = 0; i < operation_table_size_; ++i) {
+ if (operation_table_[i].operation == NULL) {
+ operation_table_[i].operation = op.release();
+ operation_table_[i].handle = *op_handle;
+ return KM_ERROR_OK;
+ }
+ }
+ return KM_ERROR_TOO_MANY_OPERATIONS;
+}
+
+GoogleKeymaster::OpTableEntry*
+GoogleKeymaster::FindOperation(keymaster_operation_handle_t op_handle) {
+ if (op_handle == 0)
+ return NULL;
+
+ for (size_t i = 0; i < operation_table_size_; ++i) {
+ if (operation_table_[i].handle == op_handle)
+ return operation_table_.get() + i;
+ }
+ return NULL;
+}
+
+void GoogleKeymaster::DeleteOperation(OpTableEntry* entry) {
+ delete entry->operation;
+ entry->operation = NULL;
+ entry->handle = 0;
+}
+
} // namespace keymaster