Merge "Refactor GoogleKeymaster's operation table to a new class."
diff --git a/Android.mk b/Android.mk
index cc4f20a..a614e03 100644
--- a/Android.mk
+++ b/Android.mk
@@ -62,6 +62,7 @@
 		openssl_err.cpp \
 		openssl_utils.cpp \
 		operation.cpp \
+		operation_table.cpp \
 		rsa_key.cpp \
 		rsa_operation.cpp \
 		serializable.cpp \
diff --git a/Makefile b/Makefile
index 5ca2992..c5b04c5 100644
--- a/Makefile
+++ b/Makefile
@@ -55,6 +55,7 @@
 	openssl_err.cpp \
 	openssl_utils.cpp \
 	operation.cpp \
+	operation_table.cpp \
 	rsa_key.cpp \
 	rsa_operation.cpp \
 	serializable.cpp \
@@ -162,9 +163,10 @@
 	key_blob.o \
 	logger.o \
 	ocb.o \
-	operation.o \
 	openssl_err.o \
 	openssl_utils.o \
+	operation.o \
+	operation_table.cpp \
 	rsa_key.o \
 	rsa_operation.o \
 	serializable.o \
diff --git a/google_keymaster.cpp b/google_keymaster.cpp
index 0778887..334dd8f 100644
--- a/google_keymaster.cpp
+++ b/google_keymaster.cpp
@@ -32,6 +32,7 @@
 #include "key.h"
 #include "openssl_err.h"
 #include "operation.h"
+#include "operation_table.h"
 #include "unencrypted_key_blob.h"
 
 namespace keymaster {
@@ -41,16 +42,10 @@
 const uint8_t SUBMINOR_VER = 0;
 
 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;
+    : operation_table_(new OperationTable(operation_table_size)) {
 }
 
 GoogleKeymaster::~GoogleKeymaster() {
-    for (size_t i = 0; i < operation_table_size_; ++i)
-        if (operation_table_[i].operation != NULL)
-            delete operation_table_[i].operation;
 }
 
 struct AE_CTX_Delete {
@@ -250,7 +245,7 @@
     if (response->error != KM_ERROR_OK)
         return;
 
-    response->error = AddOperation(operation.release(), &response->op_handle);
+    response->error = operation_table_->Add(operation.release(), &response->op_handle);
 }
 
 void GoogleKeymaster::UpdateOperation(const UpdateOperationRequest& request,
@@ -258,17 +253,16 @@
     if (response == NULL)
         return;
 
-    OpTableEntry* entry = FindOperation(request.op_handle);
-    if (entry == NULL) {
-        response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
+    response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
+    Operation* operation = operation_table_->Find(request.op_handle);
+    if (operation == NULL)
         return;
-    }
 
-    response->error = entry->operation->Update(request.additional_params, request.input,
-                                               &response->output, &response->input_consumed);
+    response->error = operation->Update(request.additional_params, request.input, &response->output,
+                                        &response->input_consumed);
     if (response->error != KM_ERROR_OK) {
         // Any error invalidates the operation.
-        DeleteOperation(entry);
+        operation_table_->Delete(request.op_handle);
     }
 }
 
@@ -277,23 +271,23 @@
     if (response == NULL)
         return;
 
-    OpTableEntry* entry = FindOperation(request.op_handle);
-    if (entry == NULL) {
-        response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
+    response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
+    Operation* operation = operation_table_->Find(request.op_handle);
+    if (operation == NULL)
         return;
-    }
 
     response->error =
-        entry->operation->Finish(request.additional_params, request.signature, &response->output);
-    DeleteOperation(entry);
+        operation->Finish(request.additional_params, request.signature, &response->output);
+    operation_table_->Delete(request.op_handle);
 }
 
 keymaster_error_t GoogleKeymaster::AbortOperation(const keymaster_operation_handle_t op_handle) {
-    OpTableEntry* entry = FindOperation(op_handle);
-    if (entry == NULL)
+    Operation* operation = operation_table_->Find(op_handle);
+    if (operation == NULL)
         return KM_ERROR_INVALID_OPERATION_HANDLE;
-    keymaster_error_t error = entry->operation->Abort();
-    DeleteOperation(entry);
+
+    keymaster_error_t error = operation->Abort();
+    operation_table_->Delete(op_handle);
     if (error != KM_ERROR_OK)
         return error;
     return KM_ERROR_OK;
@@ -513,42 +507,4 @@
         unenforced->push_back(auth);
 }
 
-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 TranslateLastOpenSslError();
-    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
diff --git a/include/keymaster/google_keymaster.h b/include/keymaster/google_keymaster.h
index 2b49f59..bdfe9f4 100644
--- a/include/keymaster/google_keymaster.h
+++ b/include/keymaster/google_keymaster.h
@@ -23,8 +23,8 @@
 namespace keymaster {
 
 class Key;
-class Operation;
 class UnencryptedKeyBlob;
+class OperationTable;
 
 /**
  * OpenSSL-based Keymaster backing implementation, for use as a pure software implmentation
@@ -96,21 +96,7 @@
     void AddAuthorization(const keymaster_key_param_t& auth, AuthorizationSet* enforced,
                           AuthorizationSet* unenforced);
 
-    struct OpTableEntry {
-        OpTableEntry() {
-            handle = 0;
-            operation = NULL;
-        }
-        keymaster_operation_handle_t handle;
-        Operation* operation;
-    };
-
-    keymaster_error_t AddOperation(Operation* operation, keymaster_operation_handle_t* op_handle);
-    OpTableEntry* FindOperation(keymaster_operation_handle_t op_handle);
-    void DeleteOperation(OpTableEntry* entry);
-
-    UniquePtr<OpTableEntry[]> operation_table_;
-    size_t operation_table_size_;
+    UniquePtr<OperationTable> operation_table_;
 };
 
 }  // namespace keymaster
diff --git a/operation.h b/operation.h
index a046aab..24878ca 100644
--- a/operation.h
+++ b/operation.h
@@ -91,7 +91,7 @@
                                     AuthorizationSet* output_params) = 0;
     virtual keymaster_error_t Update(const AuthorizationSet& additional_params, const Buffer& input,
                                      Buffer* output, size_t* input_consumed) = 0;
-    virtual keymaster_error_t Finish(const AuthorizationSet& /* additional_params */,
+    virtual keymaster_error_t Finish(const AuthorizationSet& additional_params,
                                      const Buffer& signature, Buffer* output) = 0;
     virtual keymaster_error_t Abort() = 0;
 
diff --git a/operation_table.cpp b/operation_table.cpp
new file mode 100644
index 0000000..bd110df
--- /dev/null
+++ b/operation_table.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "operation_table.h"
+
+#include <openssl/rand.h>
+
+#include "openssl_err.h"
+#include "operation.h"
+
+namespace keymaster {
+
+OperationTable::Entry::~Entry() {
+    delete operation;
+    operation = NULL;
+    handle = 0;
+}
+
+keymaster_error_t OperationTable::Add(Operation* operation,
+                                      keymaster_operation_handle_t* op_handle) {
+    if (!table_.get()) {
+        table_.reset(new Entry[table_size_]);
+        if (!table_.get())
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    UniquePtr<Operation> op(operation);
+    if (RAND_bytes(reinterpret_cast<uint8_t*>(op_handle), sizeof(*op_handle)) == 0)
+        return TranslateLastOpenSslError();
+    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 < table_size_; ++i) {
+        if (table_[i].operation == NULL) {
+            table_[i].operation = op.release();
+            table_[i].handle = *op_handle;
+            return KM_ERROR_OK;
+        }
+    }
+    return KM_ERROR_TOO_MANY_OPERATIONS;
+}
+
+Operation* OperationTable::Find(keymaster_operation_handle_t op_handle) {
+    if (op_handle == 0)
+        return NULL;
+
+    if (!table_.get())
+        return NULL;
+
+    for (size_t i = 0; i < table_size_; ++i) {
+        if (table_[i].handle == op_handle)
+            return table_[i].operation;
+    }
+    return NULL;
+}
+
+bool OperationTable::Delete(keymaster_operation_handle_t op_handle) {
+    if (!table_.get())
+        return false;
+
+    for (size_t i = 0; i < table_size_; ++i) {
+        if (table_[i].handle == op_handle) {
+            // Destructor does the right thing, call it.
+            table_[i].Entry::~Entry();
+            return true;
+        }
+    }
+    return false;
+}
+
+}  // namespace keymaster
diff --git a/operation_table.h b/operation_table.h
new file mode 100644
index 0000000..f27c1cd
--- /dev/null
+++ b/operation_table.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYSTEM_KEYMASTER_OPERATION_TABLE_H
+#define SYSTEM_KEYMASTER_OPERATION_TABLE_H
+
+#include <UniquePtr.h>
+
+#include <hardware/keymaster1.h>
+
+namespace keymaster {
+
+class Operation;
+
+class OperationTable {
+  public:
+    OperationTable(size_t table_size) : table_size_(table_size) {}
+
+    struct Entry {
+        Entry() {
+            handle = 0;
+            operation = NULL;
+        };
+        ~Entry();
+        keymaster_operation_handle_t handle;
+        Operation* operation;
+    };
+
+    keymaster_error_t Add(Operation* operation, keymaster_operation_handle_t* op_handle);
+    Operation* Find(keymaster_operation_handle_t op_handle);
+    bool Delete(keymaster_operation_handle_t);
+
+  private:
+    UniquePtr<Entry[]> table_;
+    size_t table_size_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_OPERATION_TABLE_H