am 48d998cd: am aca71139: am 738d1e9d: am 1b8885ba: am 0d593526: Properly check for Blob max length

* commit '48d998cd4982554f9b66b029331dab17154299cc':
  Properly check for Blob max length
diff --git a/keystore-engine/Android.mk b/keystore-engine/Android.mk
index bd86b6a..1f5d903 100644
--- a/keystore-engine/Android.mk
+++ b/keystore-engine/Android.mk
@@ -16,24 +16,36 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := libkeystore
 
-LOCAL_MODULE_TAGS := optional
+ifneq (,$(wildcard $(TOP)/external/boringssl/flavor.mk))
+	include $(TOP)/external/boringssl/flavor.mk
+else
+	include $(TOP)/external/openssl/flavor.mk
+endif
+ifeq ($(OPENSSL_FLAVOR),BoringSSL)
+  LOCAL_MODULE := libkeystore-engine
 
-LOCAL_MODULE_RELATIVE_PATH := ssl/engines
+  LOCAL_SRC_FILES := \
+	android_engine.cpp
+else
+  LOCAL_MODULE := libkeystore
 
-LOCAL_SRC_FILES := \
+  LOCAL_MODULE_RELATIVE_PATH := ssl/engines
+
+  LOCAL_SRC_FILES := \
 	eng_keystore.cpp \
 	keyhandle.cpp \
 	ecdsa_meth.cpp \
 	dsa_meth.cpp \
 	rsa_meth.cpp
 
-LOCAL_CFLAGS := -fvisibility=hidden -Wall -Werror
-
-LOCAL_C_INCLUDES += \
+  LOCAL_C_INCLUDES += \
 	external/openssl/include \
 	external/openssl
+endif
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -fvisibility=hidden -Wall -Werror
 
 LOCAL_SHARED_LIBRARIES += \
 	libcrypto \
diff --git a/keystore-engine/android_engine.cpp b/keystore-engine/android_engine.cpp
new file mode 100644
index 0000000..aa7bcbc
--- /dev/null
+++ b/keystore-engine/android_engine.cpp
@@ -0,0 +1,453 @@
+/* Copyright 2014 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+#include <UniquePtr.h>
+
+#include <sys/socket.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/ec_key.h>
+#include <openssl/ecdsa.h>
+#include <openssl/engine.h>
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+
+#include <binder/IServiceManager.h>
+#include <keystore/keystore.h>
+#include <keystore/IKeystoreService.h>
+
+using namespace android;
+
+namespace {
+
+extern const RSA_METHOD keystore_rsa_method;
+extern const ECDSA_METHOD keystore_ecdsa_method;
+
+/* key_id_dup is called when one of the RSA or EC_KEY objects is duplicated. */
+int key_id_dup(CRYPTO_EX_DATA* /* to */,
+               const CRYPTO_EX_DATA* /* from */,
+               void** from_d,
+               int /* index */,
+               long /* argl */,
+               void* /* argp */) {
+    char *key_id = reinterpret_cast<char *>(*from_d);
+    if (key_id != NULL) {
+        *from_d = strdup(key_id);
+    }
+    return 1;
+}
+
+/* key_id_free is called when one of the RSA, DSA or EC_KEY object is freed. */
+void key_id_free(void* /* parent */,
+                 void* ptr,
+                 CRYPTO_EX_DATA* /* ad */,
+                 int /* index */,
+                 long /* argl */,
+                 void* /* argp */) {
+    char *key_id = reinterpret_cast<char *>(ptr);
+    free(key_id);
+}
+
+/* KeystoreEngine is a BoringSSL ENGINE that implements RSA and ECDSA by
+ * forwarding the requested operations to Keystore. */
+class KeystoreEngine {
+ public:
+  KeystoreEngine()
+      : rsa_index_(RSA_get_ex_new_index(0 /* argl */,
+                                        NULL /* argp */,
+                                        NULL /* new_func */,
+                                        key_id_dup,
+                                        key_id_free)),
+        ec_key_index_(EC_KEY_get_ex_new_index(0 /* argl */,
+                                              NULL /* argp */,
+                                              NULL /* new_func */,
+                                              key_id_dup,
+                                              key_id_free)),
+        engine_(ENGINE_new()) {
+    ENGINE_set_RSA_method(
+        engine_, &keystore_rsa_method, sizeof(keystore_rsa_method));
+    ENGINE_set_ECDSA_method(
+        engine_, &keystore_ecdsa_method, sizeof(keystore_ecdsa_method));
+  }
+
+  int rsa_ex_index() const { return rsa_index_; }
+  int ec_key_ex_index() const { return ec_key_index_; }
+
+  const ENGINE* engine() const { return engine_; }
+
+ private:
+  const int rsa_index_;
+  const int ec_key_index_;
+  ENGINE* const engine_;
+};
+
+pthread_once_t g_keystore_engine_once = PTHREAD_ONCE_INIT;
+KeystoreEngine *g_keystore_engine;
+
+/* init_keystore_engine is called to initialize |g_keystore_engine|. This
+ * should only be called by |pthread_once|. */
+void init_keystore_engine() {
+    g_keystore_engine = new KeystoreEngine;
+}
+
+/* ensure_keystore_engine ensures that |g_keystore_engine| is pointing to a
+ * valid |KeystoreEngine| object and creates one if not. */
+void ensure_keystore_engine() {
+    pthread_once(&g_keystore_engine_once, init_keystore_engine);
+}
+
+/* Many OpenSSL APIs take ownership of an argument on success but don't free
+ * the argument on failure. This means we need to tell our scoped pointers when
+ * we've transferred ownership, without triggering a warning by not using the
+ * result of release(). */
+#define OWNERSHIP_TRANSFERRED(obj) \
+    typeof (obj.release()) _dummy __attribute__((unused)) = obj.release()
+
+const char* rsa_get_key_id(const RSA* rsa) {
+  return reinterpret_cast<char*>(
+      RSA_get_ex_data(rsa, g_keystore_engine->rsa_ex_index()));
+}
+
+/* rsa_private_transform takes a big-endian integer from |in|, calculates the
+ * d'th power of it, modulo the RSA modulus, and writes the result as a
+ * big-endian integer to |out|. Both |in| and |out| are |len| bytes long. It
+ * returns one on success and zero otherwise. */
+int rsa_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in, size_t len) {
+    ALOGV("rsa_private_transform(%p, %p, %p, %u)", rsa, out, in, (unsigned) len);
+
+    const char *key_id = rsa_get_key_id(rsa);
+    if (key_id == NULL) {
+        ALOGE("key had no key_id!");
+        return 0;
+    }
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
+    sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
+
+    if (service == NULL) {
+        ALOGE("could not contact keystore");
+        return 0;
+    }
+
+    uint8_t* reply = NULL;
+    size_t reply_len;
+    int32_t ret = service->sign(String16(key_id), in, len, &reply, &reply_len);
+    if (ret < 0) {
+        ALOGW("There was an error during rsa_decrypt: could not connect");
+        return 0;
+    } else if (ret != 0) {
+        ALOGW("Error during sign from keystore: %d", ret);
+        return 0;
+    } else if (reply_len == 0) {
+        ALOGW("No valid signature returned");
+        free(reply);
+        return 0;
+    }
+
+    if (reply_len > len) {
+        /* The result of the RSA operation can never be larger than the size of
+         * the modulus so we assume that the result has extra zeros on the
+         * left. This provides attackers with an oracle, but there's nothing
+         * that we can do about it here. */
+        memcpy(out, reply + reply_len - len, len);
+    } else if (reply_len < len) {
+        /* If the Keystore implementation returns a short value we assume that
+         * it's because it removed leading zeros from the left side. This is
+         * bad because it provides attackers with an oracle but we cannot do
+         * anything about a broken Keystore implementation here. */
+        memset(out, 0, len);
+        memcpy(out + len - reply_len, reply, reply_len);
+    } else {
+        memcpy(out, reply, len);
+    }
+
+    free(reply);
+
+    ALOGV("rsa=%p keystore_rsa_priv_dec successful", rsa);
+    return 1;
+}
+
+const struct rsa_meth_st keystore_rsa_method = {
+  {
+    0 /* references */,
+    1 /* is_static */,
+  },
+  NULL /* app_data */,
+
+  NULL /* init */,
+  NULL /* finish */,
+
+  NULL /* size */,
+
+  NULL /* sign */,
+  NULL /* verify */,
+
+  NULL /* encrypt */,
+  NULL /* sign_raw */,
+  NULL /* decrypt */,
+  NULL /* verify_raw */,
+
+  rsa_private_transform,
+
+  NULL /* mod_exp */,
+  NULL /* bn_mod_exp */,
+
+  RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_OPAQUE | RSA_FLAG_EXT_PKEY,
+
+  NULL /* keygen */,
+  NULL /* supports_digest */,
+};
+
+const char* ecdsa_get_key_id(const EC_KEY* ec_key) {
+    return reinterpret_cast<char*>(
+        EC_KEY_get_ex_data(ec_key, g_keystore_engine->ec_key_ex_index()));
+}
+
+/* ecdsa_sign signs |digest_len| bytes from |digest| with |ec_key| and writes
+ * the resulting signature (an ASN.1 encoded blob) to |sig|. It returns one on
+ * success and zero otherwise. */
+static int ecdsa_sign(const uint8_t* digest, size_t digest_len, uint8_t* sig,
+                      unsigned int* sig_len, EC_KEY* ec_key) {
+    ALOGV("ecdsa_sign(%p, %u, %p)", digest, (unsigned) digest_len, ec_key);
+
+    const char *key_id = ecdsa_get_key_id(ec_key);
+    if (key_id == NULL) {
+        ALOGE("key had no key_id!");
+        return 0;
+    }
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
+    sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
+
+    if (service == NULL) {
+        ALOGE("could not contact keystore");
+        return 0;
+    }
+
+    size_t ecdsa_size = ECDSA_size(ec_key);
+
+    uint8_t* reply = NULL;
+    size_t reply_len;
+    int32_t ret = service->sign(String16(reinterpret_cast<const char*>(key_id)),
+                                digest, digest_len, &reply, &reply_len);
+    if (ret < 0) {
+        ALOGW("There was an error during ecdsa_sign: could not connect");
+        return 0;
+    } else if (ret != 0) {
+        ALOGW("Error during sign from keystore: %d", ret);
+        return 0;
+    } else if (reply_len == 0) {
+        ALOGW("No valid signature returned");
+        free(reply);
+        return 0;
+    } else if (reply_len > ecdsa_size) {
+        ALOGW("Signature is too large");
+        free(reply);
+        return 0;
+    }
+
+    memcpy(sig, reply, reply_len);
+    *sig_len = reply_len;
+
+    ALOGV("ecdsa_sign(%p, %u, %p) => success", digest, (unsigned)digest_len,
+          ec_key);
+    return 1;
+}
+
+const ECDSA_METHOD keystore_ecdsa_method = {
+    {
+     0 /* references */,
+     1 /* is_static */
+    } /* common */,
+    NULL /* app_data */,
+
+    NULL /* init */,
+    NULL /* finish */,
+    NULL /* group_order_size */,
+    ecdsa_sign,
+    NULL /* verify */,
+    ECDSA_FLAG_OPAQUE,
+};
+
+struct EVP_PKEY_Delete {
+    void operator()(EVP_PKEY* p) const {
+        EVP_PKEY_free(p);
+    }
+};
+typedef UniquePtr<EVP_PKEY, EVP_PKEY_Delete> Unique_EVP_PKEY;
+
+struct RSA_Delete {
+    void operator()(RSA* p) const {
+        RSA_free(p);
+    }
+};
+typedef UniquePtr<RSA, RSA_Delete> Unique_RSA;
+
+struct EC_KEY_Delete {
+    void operator()(EC_KEY* ec) const {
+        EC_KEY_free(ec);
+    }
+};
+typedef UniquePtr<EC_KEY, EC_KEY_Delete> Unique_EC_KEY;
+
+/* wrap_rsa returns an |EVP_PKEY| that contains an RSA key where the public
+ * part is taken from |public_rsa| and the private operations are forwarded to
+ * KeyStore and operate on the key named |key_id|. */
+static EVP_PKEY *wrap_rsa(const char *key_id, const RSA *public_rsa) {
+    Unique_RSA rsa(RSA_new_method(g_keystore_engine->engine()));
+    if (rsa.get() == NULL) {
+        return NULL;
+    }
+
+    char *key_id_copy = strdup(key_id);
+    if (key_id_copy == NULL) {
+        return NULL;
+    }
+
+    if (!RSA_set_ex_data(rsa.get(), g_keystore_engine->rsa_ex_index(),
+                         key_id_copy)) {
+        free(key_id_copy);
+        return NULL;
+    }
+
+    rsa->n = BN_dup(public_rsa->n);
+    rsa->e = BN_dup(public_rsa->e);
+    if (rsa->n == NULL || rsa->e == NULL) {
+        return NULL;
+    }
+
+    Unique_EVP_PKEY result(EVP_PKEY_new());
+    if (result.get() == NULL ||
+        !EVP_PKEY_assign_RSA(result.get(), rsa.get())) {
+        return NULL;
+    }
+    OWNERSHIP_TRANSFERRED(rsa);
+
+    return result.release();
+}
+
+/* wrap_ecdsa returns an |EVP_PKEY| that contains an ECDSA key where the public
+ * part is taken from |public_rsa| and the private operations are forwarded to
+ * KeyStore and operate on the key named |key_id|. */
+static EVP_PKEY *wrap_ecdsa(const char *key_id, const EC_KEY *public_ecdsa) {
+    Unique_EC_KEY ec(EC_KEY_new_method(g_keystore_engine->engine()));
+    if (ec.get() == NULL) {
+        return NULL;
+    }
+
+    if (!EC_KEY_set_group(ec.get(), EC_KEY_get0_group(public_ecdsa)) ||
+        !EC_KEY_set_public_key(ec.get(), EC_KEY_get0_public_key(public_ecdsa))) {
+        return NULL;
+    }
+
+    char *key_id_copy = strdup(key_id);
+    if (key_id_copy == NULL) {
+        return NULL;
+    }
+
+    if (!EC_KEY_set_ex_data(ec.get(), g_keystore_engine->ec_key_ex_index(),
+                            key_id_copy)) {
+        free(key_id_copy);
+        return NULL;
+    }
+
+    Unique_EVP_PKEY result(EVP_PKEY_new());
+    if (result.get() == NULL ||
+        !EVP_PKEY_assign_EC_KEY(result.get(), ec.get())) {
+        return NULL;
+    }
+    OWNERSHIP_TRANSFERRED(ec);
+
+    return result.release();
+}
+
+}  /* anonymous namespace */
+
+extern "C" {
+
+EVP_PKEY* EVP_PKEY_from_keystore(const char* key_id) __attribute__((visibility("default")));
+
+/* EVP_PKEY_from_keystore returns an |EVP_PKEY| that contains either an RSA or
+ * ECDSA key where the public part of the key reflects the value of the key
+ * named |key_id| in Keystore and the private operations are forwarded onto
+ * KeyStore. */
+EVP_PKEY* EVP_PKEY_from_keystore(const char* key_id) {
+    ALOGV("EVP_PKEY_from_keystore(\"%s\")", key_id);
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
+    sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
+
+    if (service == NULL) {
+        ALOGE("could not contact keystore");
+        return 0;
+    }
+
+    uint8_t *pubkey = NULL;
+    size_t pubkey_len;
+    int32_t ret = service->get_pubkey(String16(key_id), &pubkey, &pubkey_len);
+    if (ret < 0) {
+        ALOGW("could not contact keystore");
+        return NULL;
+    } else if (ret != 0) {
+        ALOGW("keystore reports error: %d", ret);
+        return NULL;
+    }
+
+    const uint8_t *inp = pubkey;
+    Unique_EVP_PKEY pkey(d2i_PUBKEY(NULL, &inp, pubkey_len));
+    free(pubkey);
+    if (pkey.get() == NULL) {
+        ALOGW("Cannot convert pubkey");
+        return NULL;
+    }
+
+    ensure_keystore_engine();
+
+    EVP_PKEY *result;
+    switch (EVP_PKEY_type(pkey->type)) {
+    case EVP_PKEY_RSA: {
+        Unique_RSA public_rsa(EVP_PKEY_get1_RSA(pkey.get()));
+        result = wrap_rsa(key_id, public_rsa.get());
+        break;
+    }
+    case EVP_PKEY_EC: {
+        Unique_EC_KEY public_ecdsa(EVP_PKEY_get1_EC_KEY(pkey.get()));
+        result = wrap_ecdsa(key_id, public_ecdsa.get());
+        break;
+    }
+    default:
+        ALOGE("Unsupported key type %d", EVP_PKEY_type(pkey->type));
+        result = NULL;
+    }
+
+    return result;
+}
+
+}  // extern "C"
diff --git a/keystore-engine/keyhandle.cpp b/keystore-engine/keyhandle.cpp
index 1799735..aeba896 100644
--- a/keystore-engine/keyhandle.cpp
+++ b/keystore-engine/keyhandle.cpp
@@ -25,6 +25,8 @@
 
 #include <openssl/engine.h>
 
+#include <string.h>
+
 /**
  * Makes sure the ex_data for the keyhandle is initially set to NULL.
  */
diff --git a/keystore/.clang-format b/keystore/.clang-format
new file mode 100644
index 0000000..5747e19
--- /dev/null
+++ b/keystore/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: LLVM
+IndentWidth: 4
+UseTab: Never
+BreakBeforeBraces: Attach
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: false
+IndentCaseLabels: false
+ColumnLimit: 100
+PointerBindsToType: true
+SpacesBeforeTrailingComments: 2
diff --git a/keystore/Android.mk b/keystore/Android.mk
index 9dca502..9463f3d 100644
--- a/keystore/Android.mk
+++ b/keystore/Android.mk
@@ -20,9 +20,8 @@
 ifeq ($(USE_32_BIT_KEYSTORE), true)
 LOCAL_MULTILIB := 32
 endif
-LOCAL_CFLAGS := -Wall -Wextra -Werror
-LOCAL_SRC_FILES := keystore.cpp keyblob_utils.cpp
-LOCAL_C_INCLUDES := external/openssl/include
+LOCAL_CFLAGS := -Wall -Wextra -Werror -Wunused
+LOCAL_SRC_FILES := keystore.cpp keyblob_utils.cpp operation.cpp auth_token_table.cpp
 LOCAL_SHARED_LIBRARIES := \
 	libbinder \
 	libcutils \
@@ -32,9 +31,12 @@
 	liblog \
 	libsoftkeymaster \
 	libutils \
-	libselinux
+	libselinux \
+	libsoftkeymasterdevice \
+	libkeymaster_messages
 LOCAL_MODULE := keystore
 LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUES := system/keymaster/
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_EXECUTABLE)
 
@@ -44,7 +46,6 @@
 endif
 LOCAL_CFLAGS := -Wall -Wextra -Werror
 LOCAL_SRC_FILES := keystore_cli.cpp
-LOCAL_C_INCLUDES := external/openssl/include
 LOCAL_SHARED_LIBRARIES := libcutils libcrypto libkeystore_binder libutils liblog libbinder
 LOCAL_MODULE := keystore_cli
 LOCAL_MODULE_TAGS := debug
@@ -58,10 +59,25 @@
 endif
 LOCAL_CFLAGS := -Wall -Wextra -Werror
 LOCAL_SRC_FILES := IKeystoreService.cpp keystore_get.cpp keyblob_utils.cpp
-LOCAL_SHARED_LIBRARIES := libbinder libutils liblog
+LOCAL_SHARED_LIBRARIES := libbinder libutils liblog libsoftkeymasterdevice
 LOCAL_MODULE := libkeystore_binder
 LOCAL_MODULE_TAGS := optional
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_SHARED_LIBRARY)
+
+# Library for unit tests
+include $(CLEAR_VARS)
+ifeq ($(USE_32_BIT_KEYSTORE), true)
+LOCAL_MULTILIB := 32
+endif
+LOCAL_CFLAGS := -Wall -Wextra -Werror
+LOCAL_SRC_FILES := auth_token_table.cpp
+LOCAL_MODULE := libkeystore_test
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libgtest_main
+LOCAL_SHARED_LIBRARIES := libkeymaster_messages
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp
index 40fbe0e..f920095 100644
--- a/keystore/IKeystoreService.cpp
+++ b/keystore/IKeystoreService.cpp
@@ -16,6 +16,7 @@
 */
 
 #include <stdint.h>
+#include <sys/limits.h>
 #include <sys/types.h>
 
 #define LOG_TAG "KeystoreService"
@@ -29,6 +30,8 @@
 
 namespace android {
 
+static keymaster_key_param_t* readParamList(const Parcel& in, size_t* length);
+
 KeystoreArg::KeystoreArg(const void* data, size_t len)
     : mData(data), mSize(len) {
 }
@@ -44,6 +47,346 @@
     return mSize;
 }
 
+OperationResult::OperationResult() : resultCode(0), token(), handle(0), inputConsumed(0),
+    data(NULL), dataLength(0) {
+}
+
+OperationResult::~OperationResult() {
+}
+
+void OperationResult::readFromParcel(const Parcel& in) {
+    resultCode = in.readInt32();
+    token = in.readStrongBinder();
+    handle = static_cast<keymaster_operation_handle_t>(in.readInt64());
+    inputConsumed = in.readInt32();
+    ssize_t length = in.readInt32();
+    dataLength = 0;
+    if (length > 0) {
+        const void* buf = in.readInplace(length);
+        if (buf) {
+            data.reset(reinterpret_cast<uint8_t*>(malloc(length)));
+            if (data.get()) {
+                memcpy(data.get(), buf, length);
+                dataLength = (size_t) length;
+            } else {
+                ALOGE("Failed to allocate OperationResult buffer");
+            }
+        } else {
+            ALOGE("Failed to readInplace OperationResult data");
+        }
+    }
+}
+
+void OperationResult::writeToParcel(Parcel* out) const {
+    out->writeInt32(resultCode);
+    out->writeStrongBinder(token);
+    out->writeInt64(handle);
+    out->writeInt32(inputConsumed);
+    out->writeInt32(dataLength);
+    if (dataLength && data) {
+        void* buf = out->writeInplace(dataLength);
+        if (buf) {
+            memcpy(buf, data.get(), dataLength);
+        } else {
+            ALOGE("Failed to writeInplace OperationResult data.");
+        }
+    }
+}
+
+ExportResult::ExportResult() : resultCode(0), exportData(NULL), dataLength(0) {
+}
+
+ExportResult::~ExportResult() {
+}
+
+void ExportResult::readFromParcel(const Parcel& in) {
+    resultCode = in.readInt32();
+    ssize_t length = in.readInt32();
+    dataLength = 0;
+    if (length > 0) {
+        const void* buf = in.readInplace(length);
+        if (buf) {
+            exportData.reset(reinterpret_cast<uint8_t*>(malloc(length)));
+            if (exportData.get()) {
+                memcpy(exportData.get(), buf, length);
+                dataLength = (size_t) length;
+            } else {
+                ALOGE("Failed to allocate ExportData buffer");
+            }
+        } else {
+            ALOGE("Failed to readInplace ExportData data");
+        }
+    }
+}
+
+void ExportResult::writeToParcel(Parcel* out) const {
+    out->writeInt32(resultCode);
+    out->writeInt32(dataLength);
+    if (exportData && dataLength) {
+        void* buf = out->writeInplace(dataLength);
+        if (buf) {
+            memcpy(buf, exportData.get(), dataLength);
+        } else {
+            ALOGE("Failed to writeInplace ExportResult data.");
+        }
+    }
+}
+
+KeymasterArguments::KeymasterArguments() {
+}
+
+KeymasterArguments::~KeymasterArguments() {
+    keymaster_free_param_values(params.data(), params.size());
+}
+
+void KeymasterArguments::readFromParcel(const Parcel& in) {
+    ssize_t length = in.readInt32();
+    size_t ulength = (size_t) length;
+    if (length < 0) {
+        ulength = 0;
+    }
+    keymaster_free_param_values(params.data(), params.size());
+    params.clear();
+    for(size_t i = 0; i < ulength; i++) {
+        keymaster_key_param_t param;
+        if (!readKeymasterArgumentFromParcel(in, &param)) {
+            ALOGE("Error reading keymaster argument from parcel");
+            break;
+        }
+        params.push_back(param);
+    }
+}
+
+void KeymasterArguments::writeToParcel(Parcel* out) const {
+    out->writeInt32(params.size());
+    for (auto param : params) {
+        out->writeInt32(1);
+        writeKeymasterArgumentToParcel(param, out);
+    }
+}
+
+KeyCharacteristics::KeyCharacteristics() {
+    memset((void*) &characteristics, 0, sizeof(characteristics));
+}
+
+KeyCharacteristics::~KeyCharacteristics() {
+    keymaster_free_characteristics(&characteristics);
+}
+
+void KeyCharacteristics::readFromParcel(const Parcel& in) {
+    size_t length = 0;
+    keymaster_key_param_t* params = readParamList(in, &length);
+    characteristics.sw_enforced.params = params;
+    characteristics.sw_enforced.length = length;
+
+    params = readParamList(in, &length);
+    characteristics.hw_enforced.params = params;
+    characteristics.hw_enforced.length = length;
+}
+
+void KeyCharacteristics::writeToParcel(Parcel* out) const {
+    if (characteristics.sw_enforced.params) {
+        out->writeInt32(characteristics.sw_enforced.length);
+        for (size_t i = 0; i < characteristics.sw_enforced.length; i++) {
+            out->writeInt32(1);
+            writeKeymasterArgumentToParcel(characteristics.sw_enforced.params[i], out);
+        }
+    } else {
+        out->writeInt32(0);
+    }
+    if (characteristics.hw_enforced.params) {
+        out->writeInt32(characteristics.hw_enforced.length);
+        for (size_t i = 0; i < characteristics.hw_enforced.length; i++) {
+            out->writeInt32(1);
+            writeKeymasterArgumentToParcel(characteristics.hw_enforced.params[i], out);
+        }
+    } else {
+        out->writeInt32(0);
+    }
+}
+
+void writeKeymasterArgumentToParcel(const keymaster_key_param_t& param, Parcel* out) {
+    switch (keymaster_tag_get_type(param.tag)) {
+        case KM_ENUM:
+        case KM_ENUM_REP: {
+            out->writeInt32(param.tag);
+            out->writeInt32(param.enumerated);
+            break;
+        }
+        case KM_INT:
+        case KM_INT_REP: {
+            out->writeInt32(param.tag);
+            out->writeInt32(param.integer);
+            break;
+        }
+        case KM_LONG:
+        case KM_LONG_REP: {
+            out->writeInt32(param.tag);
+            out->writeInt64(param.long_integer);
+            break;
+        }
+        case KM_DATE: {
+            out->writeInt32(param.tag);
+            out->writeInt64(param.date_time);
+            break;
+        }
+        case KM_BOOL: {
+            out->writeInt32(param.tag);
+            break;
+        }
+        case KM_BIGNUM:
+        case KM_BYTES: {
+            out->writeInt32(param.tag);
+            out->writeInt32(param.blob.data_length);
+            void* buf = out->writeInplace(param.blob.data_length);
+            if (buf) {
+                memcpy(buf, param.blob.data, param.blob.data_length);
+            } else {
+                ALOGE("Failed to writeInplace keymaster blob param");
+            }
+            break;
+        }
+        default: {
+            ALOGE("Failed to write argument: Unsupported keymaster_tag_t %d", param.tag);
+        }
+    }
+}
+
+
+bool readKeymasterArgumentFromParcel(const Parcel& in, keymaster_key_param_t* out) {
+    if (in.readInt32() == 0) {
+        return false;
+    }
+    keymaster_tag_t tag = static_cast<keymaster_tag_t>(in.readInt32());
+    switch (keymaster_tag_get_type(tag)) {
+        case KM_ENUM:
+        case KM_ENUM_REP: {
+            uint32_t value = in.readInt32();
+            *out = keymaster_param_enum(tag, value);
+            break;
+        }
+        case KM_INT:
+        case KM_INT_REP: {
+            uint32_t value = in.readInt32();
+            *out = keymaster_param_int(tag, value);
+            break;
+        }
+        case KM_LONG:
+        case KM_LONG_REP: {
+            uint64_t value = in.readInt64();
+            *out = keymaster_param_long(tag, value);
+            break;
+        }
+        case KM_DATE: {
+            uint64_t value = in.readInt64();
+            *out = keymaster_param_date(tag, value);
+            break;
+        }
+        case KM_BOOL: {
+            *out = keymaster_param_bool(tag);
+            break;
+        }
+        case KM_BIGNUM:
+        case KM_BYTES: {
+            ssize_t length = in.readInt32();
+            uint8_t* data = NULL;
+            size_t ulength = 0;
+            if (length >= 0) {
+                ulength = (size_t) length;
+                // use malloc here so we can use keymaster_free_param_values
+                // consistently.
+                data = reinterpret_cast<uint8_t*>(malloc(ulength));
+                const void* buf = in.readInplace(ulength);
+                if (!buf || !data) {
+                    ALOGE("Failed to allocate buffer for keymaster blob param");
+                    return false;
+                }
+                memcpy(data, buf, ulength);
+            }
+            *out = keymaster_param_blob(tag, data, ulength);
+            break;
+        }
+        default: {
+            ALOGE("Unsupported keymaster_tag_t %d", tag);
+            return false;
+        }
+    }
+    return true;
+}
+
+/**
+ * Read a byte array from in. The data at *data is still owned by the parcel
+ */
+static void readByteArray(const Parcel& in, const uint8_t** data, size_t* length) {
+    ssize_t slength = in.readInt32();
+    if (slength > 0) {
+        *data = reinterpret_cast<const uint8_t*>(in.readInplace(slength));
+        if (*data) {
+            *length = static_cast<size_t>(slength);
+        } else {
+            *length = 0;
+        }
+    } else {
+        *data = NULL;
+        *length = 0;
+    }
+}
+
+// Read a keymaster_key_param_t* from a Parcel for use in a
+// keymaster_key_characteristics_t. This will be free'd by calling
+// keymaster_free_key_characteristics.
+static keymaster_key_param_t* readParamList(const Parcel& in, size_t* length) {
+    ssize_t slength = in.readInt32();
+    *length = 0;
+    if (slength < 0) {
+        return NULL;
+    }
+    *length = (size_t) slength;
+    if (*length >= UINT_MAX / sizeof(keymaster_key_param_t)) {
+        return NULL;
+    }
+    keymaster_key_param_t* list =
+            reinterpret_cast<keymaster_key_param_t*>(malloc(*length *
+                                                            sizeof(keymaster_key_param_t)));
+    if (!list) {
+        ALOGD("Failed to allocate buffer for generateKey outCharacteristics");
+        goto err;
+    }
+    for (size_t i = 0; i < *length ; i++) {
+        if (!readKeymasterArgumentFromParcel(in, &list[i])) {
+            ALOGE("Failed to read keymaster argument");
+            keymaster_free_param_values(list, i);
+            goto err;
+        }
+    }
+    return list;
+err:
+    free(list);
+    return NULL;
+}
+
+static std::unique_ptr<keymaster_blob_t> readKeymasterBlob(const Parcel& in) {
+    std::unique_ptr<keymaster_blob_t> blob;
+    if (in.readInt32() != 1) {
+        blob.reset(NULL);
+        return blob;
+    }
+    ssize_t length = in.readInt32();
+    blob.reset(new keymaster_blob_t);
+    if (length > 0) {
+        blob->data = reinterpret_cast<const uint8_t*>(in.readInplace(length));
+        if (blob->data) {
+            blob->data_length = static_cast<size_t>(length);
+        } else {
+            blob->data_length = 0;
+        }
+    } else {
+        blob->data = NULL;
+        blob->data_length = 0;
+    }
+    return blob;
+}
+
 class BpKeystoreService: public BpInterface<IKeystoreService>
 {
 public:
@@ -295,6 +638,7 @@
         data.writeInt32(keyType);
         data.writeInt32(keySize);
         data.writeInt32(flags);
+        data.writeInt32(1);
         data.writeInt32(args->size());
         for (Vector<sp<KeystoreArg> >::iterator it = args->begin(); it != args->end(); ++it) {
             sp<KeystoreArg> item = *it;
@@ -638,9 +982,314 @@
         }
         return ret;
     }
+    virtual int32_t addRngEntropy(const uint8_t* buf, size_t bufLength)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeByteArray(bufLength, buf);
+        status_t status = remote()->transact(BnKeystoreService::ADD_RNG_ENTROPY, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("addRngEntropy() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("addRngEntropy() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    };
+
+    virtual int32_t generateKey(const String16& name, const KeymasterArguments& params,
+                                const uint8_t* entropy, size_t entropyLength, int uid, int flags,
+                                KeyCharacteristics* outCharacteristics)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        data.writeInt32(1);
+        params.writeToParcel(&data);
+        data.writeByteArray(entropyLength, entropy);
+        data.writeInt32(uid);
+        data.writeInt32(flags);
+        status_t status = remote()->transact(BnKeystoreService::GENERATE_KEY, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("generateKey() could not contact remote: %d\n", status);
+            return KM_ERROR_UNKNOWN_ERROR;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("generateKey() caught exception %d\n", err);
+            return KM_ERROR_UNKNOWN_ERROR;
+        }
+        if (reply.readInt32() != 0 && outCharacteristics) {
+            outCharacteristics->readFromParcel(reply);
+        }
+        return ret;
+    }
+    virtual int32_t getKeyCharacteristics(const String16& name,
+                                          const keymaster_blob_t* clientId,
+                                          const keymaster_blob_t* appData,
+                                          KeyCharacteristics* outCharacteristics)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        if (clientId) {
+            data.writeByteArray(clientId->data_length, clientId->data);
+        } else {
+            data.writeInt32(-1);
+        }
+        if (appData) {
+            data.writeByteArray(appData->data_length, appData->data);
+        } else {
+            data.writeInt32(-1);
+        }
+        status_t status = remote()->transact(BnKeystoreService::GET_KEY_CHARACTERISTICS,
+                                             data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("getKeyCharacteristics() could not contact remote: %d\n", status);
+            return KM_ERROR_UNKNOWN_ERROR;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("getKeyCharacteristics() caught exception %d\n", err);
+            return KM_ERROR_UNKNOWN_ERROR;
+        }
+        if (reply.readInt32() != 0 && outCharacteristics) {
+            outCharacteristics->readFromParcel(reply);
+        }
+        return ret;
+    }
+    virtual int32_t importKey(const String16& name, const KeymasterArguments&  params,
+                              keymaster_key_format_t format, const uint8_t *keyData,
+                              size_t keyLength, int uid, int flags,
+                              KeyCharacteristics* outCharacteristics)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        data.writeInt32(1);
+        params.writeToParcel(&data);
+        data.writeInt32(format);
+        data.writeByteArray(keyLength, keyData);
+        data.writeInt32(uid);
+        data.writeInt32(flags);
+        status_t status = remote()->transact(BnKeystoreService::IMPORT_KEY, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("importKey() could not contact remote: %d\n", status);
+            return KM_ERROR_UNKNOWN_ERROR;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("importKey() caught exception %d\n", err);
+            return KM_ERROR_UNKNOWN_ERROR;
+        }
+        if (reply.readInt32() != 0 && outCharacteristics) {
+            outCharacteristics->readFromParcel(reply);
+        }
+        return ret;
+    }
+
+    virtual void exportKey(const String16& name, keymaster_key_format_t format,
+                           const keymaster_blob_t* clientId,
+                           const keymaster_blob_t* appData, ExportResult* result)
+    {
+        if (!result) {
+            return;
+        }
+
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        data.writeInt32(format);
+        if (clientId) {
+            data.writeByteArray(clientId->data_length, clientId->data);
+        } else {
+            data.writeInt32(-1);
+        }
+        if (appData) {
+            data.writeByteArray(appData->data_length, appData->data);
+        } else {
+            data.writeInt32(-1);
+        }
+        status_t status = remote()->transact(BnKeystoreService::EXPORT_KEY, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("exportKey() could not contact remote: %d\n", status);
+            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
+            return;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            ALOGD("exportKey() caught exception %d\n", err);
+            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
+            return;
+        }
+        if (reply.readInt32() != 0) {
+            result->readFromParcel(reply);
+        }
+    }
+
+    virtual void begin(const sp<IBinder>& appToken, const String16& name,
+                       keymaster_purpose_t purpose, bool pruneable,
+                       const KeymasterArguments& params, const uint8_t* entropy,
+                       size_t entropyLength, KeymasterArguments* outParams,
+                       OperationResult* result)
+    {
+        if (!result || !outParams) {
+            return;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeStrongBinder(appToken);
+        data.writeString16(name);
+        data.writeInt32(purpose);
+        data.writeInt32(pruneable ? 1 : 0);
+        data.writeInt32(1);
+        params.writeToParcel(&data);
+        data.writeByteArray(entropyLength, entropy);
+        status_t status = remote()->transact(BnKeystoreService::BEGIN, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("begin() could not contact remote: %d\n", status);
+            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
+            return;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            ALOGD("begin() caught exception %d\n", err);
+            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
+            return;
+        }
+        if (reply.readInt32() != 0) {
+            result->readFromParcel(reply);
+        }
+        if (reply.readInt32() != 0) {
+            outParams->readFromParcel(reply);
+        }
+    }
+
+    virtual void update(const sp<IBinder>& token, const KeymasterArguments& params,
+                        const uint8_t* opData, size_t dataLength, OperationResult* result)
+    {
+        if (!result) {
+            return;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeStrongBinder(token);
+        data.writeInt32(1);
+        params.writeToParcel(&data);
+        data.writeByteArray(dataLength, opData);
+        status_t status = remote()->transact(BnKeystoreService::UPDATE, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("update() could not contact remote: %d\n", status);
+            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
+            return;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            ALOGD("update() caught exception %d\n", err);
+            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
+            return;
+        }
+        if (reply.readInt32() != 0) {
+            result->readFromParcel(reply);
+        }
+    }
+
+    virtual void finish(const sp<IBinder>& token, const KeymasterArguments& params,
+                        const uint8_t* signature, size_t signatureLength, OperationResult* result)
+    {
+        if (!result) {
+            return;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeStrongBinder(token);
+        data.writeInt32(1);
+        params.writeToParcel(&data);
+        data.writeByteArray(signatureLength, signature);
+        status_t status = remote()->transact(BnKeystoreService::FINISH, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("finish() could not contact remote: %d\n", status);
+            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
+            return;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            ALOGD("finish() caught exception %d\n", err);
+            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
+            return;
+        }
+        if (reply.readInt32() != 0) {
+            result->readFromParcel(reply);
+        }
+    }
+
+    virtual int32_t abort(const sp<IBinder>& token)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeStrongBinder(token);
+        status_t status = remote()->transact(BnKeystoreService::ABORT, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("abort() could not contact remote: %d\n", status);
+            return KM_ERROR_UNKNOWN_ERROR;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("abort() caught exception %d\n", err);
+            return KM_ERROR_UNKNOWN_ERROR;
+        }
+        return ret;
+    }
+
+    virtual bool isOperationAuthorized(const sp<IBinder>& token)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeStrongBinder(token);
+        status_t status = remote()->transact(BnKeystoreService::IS_OPERATION_AUTHORIZED, data,
+                                             &reply);
+        if (status != NO_ERROR) {
+            ALOGD("isOperationAuthorized() could not contact remote: %d\n", status);
+            return false;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("isOperationAuthorized() caught exception %d\n", err);
+            return false;
+        }
+        return ret == 1;
+    }
+
+    virtual int32_t addAuthToken(const uint8_t* token, size_t length)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeByteArray(length, token);
+        status_t status = remote()->transact(BnKeystoreService::ADD_AUTH_TOKEN, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("addAuthToken() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("addAuthToken() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    };
 };
 
-IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.keystore");
+IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.IKeystoreService");
 
 // ----------------------------------------------------------------------
 
@@ -768,15 +1417,19 @@
             int32_t keySize = data.readInt32();
             int32_t flags = data.readInt32();
             Vector<sp<KeystoreArg> > args;
-            ssize_t numArgs = data.readInt32();
-            if (numArgs > 0) {
-                for (size_t i = 0; i < (size_t) numArgs; i++) {
-                    ssize_t inSize = data.readInt32();
-                    if (inSize >= 0 && (size_t) inSize <= data.dataAvail()) {
-                        sp<KeystoreArg> arg = new KeystoreArg(data.readInplace(inSize), inSize);
-                        args.push_back(arg);
-                    } else {
-                        args.push_back(NULL);
+            int32_t argsPresent = data.readInt32();
+            if (argsPresent == 1) {
+                ssize_t numArgs = data.readInt32();
+                if (numArgs > 0) {
+                    for (size_t i = 0; i < (size_t) numArgs; i++) {
+                        ssize_t inSize = data.readInt32();
+                        if (inSize >= 0 && (size_t) inSize <= data.dataAvail()) {
+                            sp<KeystoreArg> arg = new KeystoreArg(data.readInplace(inSize),
+                                                                  inSize);
+                            args.push_back(arg);
+                        } else {
+                            args.push_back(NULL);
+                        }
                     }
                 }
             }
@@ -960,6 +1613,178 @@
             reply->writeInt32(ret);
             return NO_ERROR;
         }
+        case ADD_RNG_ENTROPY: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            const uint8_t* bytes = NULL;
+            size_t size = 0;
+            readByteArray(data, &bytes, &size);
+            int32_t ret = addRngEntropy(bytes, size);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case GENERATE_KEY: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            KeymasterArguments args;
+            if (data.readInt32() != 0) {
+                args.readFromParcel(data);
+            }
+            const uint8_t* entropy = NULL;
+            size_t entropyLength = 0;
+            readByteArray(data, &entropy, &entropyLength);
+            int32_t uid = data.readInt32();
+            int32_t flags = data.readInt32();
+            KeyCharacteristics outCharacteristics;
+            int32_t ret = generateKey(name, args, entropy, entropyLength, uid, flags,
+                                      &outCharacteristics);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            reply->writeInt32(1);
+            outCharacteristics.writeToParcel(reply);
+            return NO_ERROR;
+        }
+        case GET_KEY_CHARACTERISTICS: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            std::unique_ptr<keymaster_blob_t> clientId = readKeymasterBlob(data);
+            std::unique_ptr<keymaster_blob_t> appData = readKeymasterBlob(data);
+            KeyCharacteristics outCharacteristics;
+            int ret = getKeyCharacteristics(name, clientId.get(), appData.get(),
+                                            &outCharacteristics);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            reply->writeInt32(1);
+            outCharacteristics.writeToParcel(reply);
+            return NO_ERROR;
+        }
+        case IMPORT_KEY: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            KeymasterArguments args;
+            if (data.readInt32() != 0) {
+                args.readFromParcel(data);
+            }
+            keymaster_key_format_t format = static_cast<keymaster_key_format_t>(data.readInt32());
+            const uint8_t* keyData = NULL;
+            size_t keyLength = 0;
+            readByteArray(data, &keyData, &keyLength);
+            int32_t uid = data.readInt32();
+            int32_t flags = data.readInt32();
+            KeyCharacteristics outCharacteristics;
+            int32_t ret = importKey(name, args, format, keyData, keyLength, uid, flags,
+                                    &outCharacteristics);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            reply->writeInt32(1);
+            outCharacteristics.writeToParcel(reply);
+
+            return NO_ERROR;
+        }
+        case EXPORT_KEY: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            keymaster_key_format_t format = static_cast<keymaster_key_format_t>(data.readInt32());
+            std::unique_ptr<keymaster_blob_t> clientId = readKeymasterBlob(data);
+            std::unique_ptr<keymaster_blob_t> appData = readKeymasterBlob(data);
+            ExportResult result;
+            exportKey(name, format, clientId.get(), appData.get(), &result);
+            reply->writeNoException();
+            reply->writeInt32(1);
+            result.writeToParcel(reply);
+
+            return NO_ERROR;
+        }
+        case BEGIN: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            sp<IBinder> token = data.readStrongBinder();
+            String16 name = data.readString16();
+            keymaster_purpose_t purpose = static_cast<keymaster_purpose_t>(data.readInt32());
+            bool pruneable = data.readInt32() != 0;
+            KeymasterArguments args;
+            if (data.readInt32() != 0) {
+                args.readFromParcel(data);
+            }
+            const uint8_t* entropy = NULL;
+            size_t entropyLength = 0;
+            readByteArray(data, &entropy, &entropyLength);
+            KeymasterArguments outArgs;
+            OperationResult result;
+            begin(token, name, purpose, pruneable, args, entropy, entropyLength, &outArgs,
+                  &result);
+            reply->writeNoException();
+            reply->writeInt32(1);
+            result.writeToParcel(reply);
+            reply->writeInt32(1);
+            outArgs.writeToParcel(reply);
+
+            return NO_ERROR;
+        }
+        case UPDATE: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            sp<IBinder> token = data.readStrongBinder();
+            KeymasterArguments args;
+            if (data.readInt32() != 0) {
+                args.readFromParcel(data);
+            }
+            const uint8_t* buf = NULL;
+            size_t bufLength = 0;
+            readByteArray(data, &buf, &bufLength);
+            OperationResult result;
+            update(token, args, buf, bufLength, &result);
+            reply->writeNoException();
+            reply->writeInt32(1);
+            result.writeToParcel(reply);
+
+            return NO_ERROR;
+        }
+        case FINISH: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            sp<IBinder> token = data.readStrongBinder();
+            KeymasterArguments args;
+            if (data.readInt32() != 0) {
+                args.readFromParcel(data);
+            }
+            const uint8_t* buf = NULL;
+            size_t bufLength = 0;
+            readByteArray(data, &buf, &bufLength);
+            OperationResult result;
+            finish(token, args, buf, bufLength, &result);
+            reply->writeNoException();
+            reply->writeInt32(1);
+            result.writeToParcel(reply);
+
+            return NO_ERROR;
+        }
+        case ABORT: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            sp<IBinder> token = data.readStrongBinder();
+            int32_t result = abort(token);
+            reply->writeNoException();
+            reply->writeInt32(result);
+
+            return NO_ERROR;
+        }
+        case IS_OPERATION_AUTHORIZED: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            sp<IBinder> token = data.readStrongBinder();
+            bool result = isOperationAuthorized(token);
+            reply->writeNoException();
+            reply->writeInt32(result ? 1 : 0);
+
+            return NO_ERROR;
+        }
+        case ADD_AUTH_TOKEN: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            const uint8_t* token_bytes = NULL;
+            size_t size = 0;
+            readByteArray(data, &token_bytes, &size);
+            int32_t result = addAuthToken(token_bytes, size);
+            reply->writeNoException();
+            reply->writeInt32(result);
+
+            return NO_ERROR;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/keystore/auth_token_table.cpp b/keystore/auth_token_table.cpp
new file mode 100644
index 0000000..de5d41d
--- /dev/null
+++ b/keystore/auth_token_table.cpp
@@ -0,0 +1,202 @@
+/*
+ * 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 "auth_token_table.h"
+
+#include <assert.h>
+#include <time.h>
+
+#include <algorithm>
+
+#include <keymaster/google_keymaster_utils.h>
+#include <keymaster/logger.h>
+
+namespace keymaster {
+
+//
+// Some trivial template wrappers around std algorithms, so they take containers not ranges.
+//
+template <typename Container, typename Predicate>
+typename Container::iterator find_if(Container& container, Predicate pred) {
+    return std::find_if(container.begin(), container.end(), pred);
+}
+
+template <typename Container, typename Predicate>
+typename Container::iterator remove_if(Container& container, Predicate pred) {
+    return std::remove_if(container.begin(), container.end(), pred);
+}
+
+template <typename Container> typename Container::iterator min_element(Container& container) {
+    return std::min_element(container.begin(), container.end());
+}
+
+time_t clock_gettime_raw() {
+    struct timespec time;
+    clock_gettime(CLOCK_MONOTONIC_RAW, &time);
+    return time.tv_sec;
+}
+
+void AuthTokenTable::AddAuthenticationToken(const hw_auth_token_t* auth_token) {
+    Entry new_entry(auth_token, clock_function_());
+    RemoveEntriesSupersededBy(new_entry);
+    if (entries_.size() >= max_entries_) {
+        LOG_W("Auth token table filled up; replacing oldest entry", 0);
+        *min_element(entries_) = std::move(new_entry);
+    } else {
+        entries_.push_back(std::move(new_entry));
+    }
+}
+
+inline bool KeyRequiresAuthentication(const AuthorizationSet& key_info) {
+    return key_info.find(TAG_NO_AUTH_REQUIRED) == -1;
+}
+
+inline bool KeyRequiresAuthPerOperation(const AuthorizationSet& key_info) {
+    return key_info.find(TAG_AUTH_TIMEOUT) == -1;
+}
+
+AuthTokenTable::Error AuthTokenTable::FindAuthorization(const AuthorizationSet& key_info,
+                                                        keymaster_operation_handle_t op_handle,
+                                                        const hw_auth_token_t** found) {
+    if (!KeyRequiresAuthentication(key_info))
+        return AUTH_NOT_REQUIRED;
+
+    hw_authenticator_type_t auth_type = HW_AUTH_NONE;
+    key_info.GetTagValue(TAG_USER_AUTH_TYPE, &auth_type);
+
+    std::vector<uint64_t> key_sids;
+    ExtractSids(key_info, &key_sids);
+
+    if (KeyRequiresAuthPerOperation(key_info))
+        return FindAuthPerOpAuthorization(key_sids, auth_type, op_handle, found);
+    else
+        return FindTimedAuthorization(key_sids, auth_type, key_info, found);
+}
+
+AuthTokenTable::Error AuthTokenTable::FindAuthPerOpAuthorization(
+    const std::vector<uint64_t>& sids, hw_authenticator_type_t auth_type,
+    keymaster_operation_handle_t op_handle, const hw_auth_token_t** found) {
+    if (op_handle == 0)
+        return OP_HANDLE_REQUIRED;
+
+    auto matching_op = find_if(
+        entries_, [&](Entry& e) { return e.token()->challenge == op_handle && !e.completed(); });
+
+    if (matching_op == entries_.end())
+        return AUTH_TOKEN_NOT_FOUND;
+
+    if (!matching_op->SatisfiesAuth(sids, auth_type))
+        return AUTH_TOKEN_WRONG_SID;
+
+    *found = matching_op->token();
+    return OK;
+}
+
+AuthTokenTable::Error AuthTokenTable::FindTimedAuthorization(const std::vector<uint64_t>& sids,
+                                                             hw_authenticator_type_t auth_type,
+                                                             const AuthorizationSet& key_info,
+                                                             const hw_auth_token_t** found) {
+    Entry* newest_match = NULL;
+    for (auto& entry : entries_)
+        if (entry.SatisfiesAuth(sids, auth_type) && entry.is_newer_than(newest_match))
+            newest_match = &entry;
+
+    if (!newest_match)
+        return AUTH_TOKEN_NOT_FOUND;
+
+    uint32_t timeout;
+    key_info.GetTagValue(TAG_AUTH_TIMEOUT, &timeout);
+    time_t now = clock_function_();
+    if (static_cast<int64_t>(newest_match->time_received()) + timeout < static_cast<int64_t>(now))
+        return AUTH_TOKEN_EXPIRED;
+
+    newest_match->UpdateLastUse(now);
+    *found = newest_match->token();
+    return OK;
+}
+
+void AuthTokenTable::ExtractSids(const AuthorizationSet& key_info, std::vector<uint64_t>* sids) {
+    assert(sids);
+    for (auto& param : key_info)
+        if (param.tag == TAG_USER_SECURE_ID)
+            sids->push_back(param.long_integer);
+}
+
+void AuthTokenTable::RemoveEntriesSupersededBy(const Entry& entry) {
+    entries_.erase(remove_if(entries_, [&](Entry& e) { return entry.Supersedes(e); }),
+                   entries_.end());
+}
+
+void AuthTokenTable::Clear() {
+    entries_.clear();
+}
+
+bool AuthTokenTable::IsSupersededBySomeEntry(const Entry& entry) {
+    return std::any_of(entries_.begin(), entries_.end(),
+                       [&](Entry& e) { return e.Supersedes(entry); });
+}
+
+void AuthTokenTable::MarkCompleted(const keymaster_operation_handle_t op_handle) {
+    auto found = find_if(entries_, [&](Entry& e) { return e.token()->challenge == op_handle; });
+    if (found == entries_.end())
+        return;
+
+    assert(!IsSupersededBySomeEntry(*found));
+    found->mark_completed();
+
+    if (IsSupersededBySomeEntry(*found))
+        entries_.erase(found);
+}
+
+AuthTokenTable::Entry::Entry(const hw_auth_token_t* token, time_t current_time)
+    : token_(token), time_received_(current_time), last_use_(current_time),
+      operation_completed_(token_->challenge == 0) {
+}
+
+uint32_t AuthTokenTable::Entry::timestamp_host_order() const {
+    return ntoh(token_->timestamp);
+}
+
+hw_authenticator_type_t AuthTokenTable::Entry::authenticator_type() const {
+    hw_authenticator_type_t result = static_cast<hw_authenticator_type_t>(
+        ntoh(static_cast<uint32_t>(token_->authenticator_type)));
+    return result;
+}
+
+bool AuthTokenTable::Entry::SatisfiesAuth(const std::vector<uint64_t>& sids,
+                                          hw_authenticator_type_t auth_type) {
+    for (auto sid : sids)
+        if ((sid == token_->authenticator_id) ||
+            (sid == token_->user_id && (auth_type & authenticator_type()) != 0))
+            return true;
+    return false;
+}
+
+void AuthTokenTable::Entry::UpdateLastUse(time_t time) {
+    this->last_use_ = time;
+}
+
+bool AuthTokenTable::Entry::Supersedes(const Entry& entry) const {
+    if (!entry.completed())
+        return false;
+
+    return (token_->user_id == entry.token_->user_id &&
+            token_->authenticator_type == entry.token_->authenticator_type &&
+            token_->authenticator_type == entry.token_->authenticator_type &&
+            timestamp_host_order() > entry.timestamp_host_order());
+}
+
+}  // namespace keymaster
diff --git a/keystore/auth_token_table.h b/keystore/auth_token_table.h
new file mode 100644
index 0000000..7a9cc34
--- /dev/null
+++ b/keystore/auth_token_table.h
@@ -0,0 +1,163 @@
+/*
+ * 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 <memory>
+#include <vector>
+
+#include <hardware/hw_auth_token.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/key_blob.h>
+
+#ifndef SYSTEM_KEYMASTER_AUTH_TOKEN_TABLE_H
+#define SYSTEM_KEYMASTER_AUTH_TOKEN_TABLE_H
+
+namespace keymaster {
+
+namespace test {
+class AuthTokenTableTest;
+}  // namespace test
+
+time_t clock_gettime_raw();
+
+/**
+ * AuthTokenTable manages a set of received authorization tokens and can provide the appropriate
+ * token for authorizing a key operation.
+ *
+ * To keep the table from growing without bound, superseded entries are removed when possible, and
+ * least recently used entries are automatically pruned when when the table exceeds a size limit,
+ * which is expected to be relatively small, since the implementation uses a linear search.
+ */
+class AuthTokenTable {
+  public:
+    AuthTokenTable(size_t max_entries = 32, time_t (*clock_function)() = clock_gettime_raw)
+        : max_entries_(max_entries), clock_function_(clock_function) {}
+
+    enum Error {
+        OK,
+        AUTH_NOT_REQUIRED = -1,
+        AUTH_TOKEN_EXPIRED = -2,    // Found a matching token, but it's too old.
+        AUTH_TOKEN_WRONG_SID = -3,  // Found a token with the right challenge, but wrong SID.  This
+                                    // most likely indicates that the authenticator was updated
+                                    // (e.g. new fingerprint enrolled).
+        OP_HANDLE_REQUIRED = -4,    // The key requires auth per use but op_handle was zero.
+        AUTH_TOKEN_NOT_FOUND = -5,
+    };
+
+    /**
+     * Add an authorization token to the table.  The table takes ownership of the argument.
+     */
+    void AddAuthenticationToken(const hw_auth_token_t* token);
+
+    /**
+     * Find an authorization token that authorizes the operation specified by \p operation_handle on
+     * a key with the characteristics specified in \p key_info.
+     *
+     * This method is O(n * m), where n is the number of KM_TAG_USER_SECURE_ID entries in key_info
+     * and m is the number of entries in the table.  It could be made better, but n and m should
+     * always be small.
+     *
+     * The table retains ownership of the returned object.
+     */
+    Error FindAuthorization(const AuthorizationSet& key_info,
+                            keymaster_operation_handle_t op_handle, const hw_auth_token_t** found);
+
+    /**
+     * Find an authorization token that authorizes the operation specified by \p operation_handle on
+     * a key with the characteristics specified in \p key_info.
+     *
+     * This method is O(n * m), where n is the number of KM_TAG_USER_SECURE_ID entries in key_info
+     * and m is the number of entries in the table.  It could be made better, but n and m should
+     * always be small.
+     *
+     * The table retains ownership of the returned object.
+     */
+    Error FindAuthorization(const keymaster_key_param_t* params, size_t params_count,
+                            keymaster_operation_handle_t op_handle, const hw_auth_token_t** found) {
+        return FindAuthorization(AuthorizationSet(params, params_count), op_handle, found);
+    }
+
+    /**
+     * Mark operation completed.  This allows tokens associated with the specified operation to be
+     * superseded by new tokens.
+     */
+    void MarkCompleted(const keymaster_operation_handle_t op_handle);
+
+    void Clear();
+
+    size_t size() { return entries_.size(); }
+
+  private:
+    friend class AuthTokenTableTest;
+
+    class Entry {
+      public:
+        Entry(const hw_auth_token_t* token, time_t current_time);
+        Entry(Entry&& entry) { *this = std::move(entry); }
+
+        void operator=(Entry&& rhs) {
+            token_ = std::move(rhs.token_);
+            time_received_ = rhs.time_received_;
+            last_use_ = rhs.last_use_;
+            operation_completed_ = rhs.operation_completed_;
+        }
+
+        bool operator<(const Entry& rhs) const { return last_use_ < rhs.last_use_; }
+
+        void UpdateLastUse(time_t time);
+
+        bool Supersedes(const Entry& entry) const;
+        bool SatisfiesAuth(const std::vector<uint64_t>& sids, hw_authenticator_type_t auth_type);
+
+        bool is_newer_than(const Entry* entry) {
+            if (!entry)
+                return true;
+            return timestamp_host_order() > entry->timestamp_host_order();
+        }
+
+        void mark_completed() { operation_completed_ = true; }
+
+        const hw_auth_token_t* token() { return token_.get(); }
+        time_t time_received() const { return time_received_; }
+        bool completed() const { return operation_completed_; }
+        uint32_t timestamp_host_order() const;
+        hw_authenticator_type_t authenticator_type() const;
+
+      private:
+        std::unique_ptr<const hw_auth_token_t> token_;
+        time_t time_received_;
+        time_t last_use_;
+        bool operation_completed_;
+    };
+
+    Error FindAuthPerOpAuthorization(const std::vector<uint64_t>& sids,
+                                     hw_authenticator_type_t auth_type,
+                                     keymaster_operation_handle_t op_handle,
+                                     const hw_auth_token_t** found);
+    Error FindTimedAuthorization(const std::vector<uint64_t>& sids,
+                                 hw_authenticator_type_t auth_type,
+                                 const AuthorizationSet& key_info, const hw_auth_token_t** found);
+    void ExtractSids(const AuthorizationSet& key_info, std::vector<uint64_t>* sids);
+    void RemoveEntriesSupersededBy(const Entry& entry);
+    bool IsSupersededBySomeEntry(const Entry& entry);
+
+    std::vector<Entry> entries_;
+    size_t max_entries_;
+    time_t (*clock_function_)();
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_AUTH_TOKEN_TABLE_H
diff --git a/keystore/include/keystore/IKeystoreService.h b/keystore/include/keystore/IKeystoreService.h
index afdff8d..8b5b5d3 100644
--- a/keystore/include/keystore/IKeystoreService.h
+++ b/keystore/include/keystore/IKeystoreService.h
@@ -17,9 +17,11 @@
 #ifndef KEYSTORE_IKEYSTORESERVICE_H
 #define KEYSTORE_IKEYSTORESERVICE_H
 
+#include <hardware/keymaster_defs.h>
 #include <utils/RefBase.h>
 #include <binder/IInterface.h>
 #include <binder/Parcel.h>
+#include <vector>
 
 namespace android {
 
@@ -36,6 +38,60 @@
     size_t mSize;
 };
 
+struct MallocDeleter {
+    void operator()(uint8_t* p) { free(p); }
+};
+
+// struct for serializing the results of begin/update/finish
+struct OperationResult {
+    OperationResult();
+    ~OperationResult();
+    void readFromParcel(const Parcel& in);
+    void writeToParcel(Parcel* out) const;
+
+    int resultCode;
+    sp<IBinder> token;
+    keymaster_operation_handle_t handle;
+    int inputConsumed;
+    std::unique_ptr<uint8_t[], MallocDeleter> data;
+    size_t dataLength;
+};
+
+// struct for serializing the results of export
+struct ExportResult {
+    ExportResult();
+    ~ExportResult();
+    void readFromParcel(const Parcel& in);
+    void writeToParcel(Parcel* out) const;
+
+    int resultCode;
+    std::unique_ptr<uint8_t[], MallocDeleter> exportData;
+    size_t dataLength;
+};
+
+// struct for serializing/deserializing a list of keymaster_key_param_t's
+struct KeymasterArguments {
+    KeymasterArguments();
+    ~KeymasterArguments();
+    void readFromParcel(const Parcel& in);
+    void writeToParcel(Parcel* out) const;
+
+    std::vector<keymaster_key_param_t> params;
+};
+
+// struct for serializing keymaster_key_characteristics_t's
+struct KeyCharacteristics {
+    KeyCharacteristics();
+    ~KeyCharacteristics();
+    void readFromParcel(const Parcel& in);
+    void writeToParcel(Parcel* out) const;
+
+    keymaster_key_characteristics_t characteristics;
+};
+
+bool readKeymasterArgumentFromParcel(const Parcel& in, keymaster_key_param_t* out);
+void writeKeymasterArgumentToParcel(const keymaster_key_param_t& param, Parcel* out);
+
 /*
  * This must be kept manually in sync with frameworks/base's IKeystoreService.java
  */
@@ -68,6 +124,17 @@
         RESET_UID = IBinder::FIRST_CALL_TRANSACTION + 23,
         SYNC_UID = IBinder::FIRST_CALL_TRANSACTION + 24,
         PASSWORD_UID = IBinder::FIRST_CALL_TRANSACTION + 25,
+        ADD_RNG_ENTROPY = IBinder::FIRST_CALL_TRANSACTION + 26,
+        GENERATE_KEY = IBinder::FIRST_CALL_TRANSACTION + 27,
+        GET_KEY_CHARACTERISTICS = IBinder::FIRST_CALL_TRANSACTION + 28,
+        IMPORT_KEY = IBinder::FIRST_CALL_TRANSACTION + 29,
+        EXPORT_KEY = IBinder::FIRST_CALL_TRANSACTION + 30,
+        BEGIN = IBinder::FIRST_CALL_TRANSACTION + 31,
+        UPDATE = IBinder::FIRST_CALL_TRANSACTION + 32,
+        FINISH = IBinder::FIRST_CALL_TRANSACTION + 33,
+        ABORT = IBinder::FIRST_CALL_TRANSACTION + 34,
+        IS_OPERATION_AUTHORIZED = IBinder::FIRST_CALL_TRANSACTION + 35,
+        ADD_AUTH_TOKEN = IBinder::FIRST_CALL_TRANSACTION + 36,
     };
 
     DECLARE_META_INTERFACE(KeystoreService);
@@ -129,6 +196,46 @@
     virtual int32_t sync_uid(int32_t sourceUid, int32_t targetUid) = 0;
 
     virtual int32_t password_uid(const String16& password, int32_t uid) = 0;
+
+    virtual int32_t addRngEntropy(const uint8_t* data, size_t dataLength) = 0;
+
+    virtual int32_t generateKey(const String16& name, const KeymasterArguments& params,
+                                const uint8_t* entropy, size_t entropyLength, int uid, int flags,
+                                KeyCharacteristics* outCharacteristics) = 0;
+
+    virtual int32_t getKeyCharacteristics(const String16& name,
+                                          const keymaster_blob_t* clientId,
+                                          const keymaster_blob_t* appData,
+                                          KeyCharacteristics* outCharacteristics) = 0;
+
+    virtual int32_t importKey(const String16& name, const KeymasterArguments&  params,
+                              keymaster_key_format_t format, const uint8_t *keyData,
+                              size_t keyLength, int uid, int flags,
+                              KeyCharacteristics* outCharacteristics) = 0;
+
+    virtual void exportKey(const String16& name, keymaster_key_format_t format,
+                           const keymaster_blob_t* clientId,
+                           const keymaster_blob_t* appData, ExportResult* result) = 0;
+
+    virtual void begin(const sp<IBinder>& apptoken, const String16& name,
+                       keymaster_purpose_t purpose, bool pruneable,
+                       const KeymasterArguments& params, const uint8_t* entropy,
+                       size_t entropyLength, KeymasterArguments* outParams,
+                       OperationResult* result) = 0;
+
+    virtual void update(const sp<IBinder>& token, const KeymasterArguments& params,
+                        const uint8_t* data, size_t dataLength, OperationResult* result) = 0;
+
+    virtual void finish(const sp<IBinder>& token, const KeymasterArguments& params,
+                        const uint8_t* signature, size_t signatureLength,
+                        OperationResult* result) = 0;
+
+    virtual int32_t abort(const sp<IBinder>& handle) = 0;
+
+    virtual bool isOperationAuthorized(const sp<IBinder>& handle) = 0;
+
+    virtual int32_t addAuthToken(const uint8_t* token, size_t length) = 0;
+
 };
 
 // ----------------------------------------------------------------------------
diff --git a/keystore/keyblob_utils.cpp b/keystore/keyblob_utils.cpp
index b208073..3616822 100644
--- a/keystore/keyblob_utils.cpp
+++ b/keystore/keyblob_utils.cpp
@@ -14,9 +14,13 @@
  * limitations under the License.
  */
 
+#include <stdint.h>
+#include <string.h>
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <keystore/keystore.h>
+
 /**
  * When a key is being migrated from a software keymaster implementation
  * to a hardware keymaster implementation, the first 4 bytes of the key_blob
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index c1ce584..2144de2 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <stdint.h>
 #include <string.h>
+#include <strings.h>
 #include <unistd.h>
 #include <signal.h>
 #include <errno.h>
@@ -40,9 +41,10 @@
 #include <openssl/md5.h>
 #include <openssl/pem.h>
 
-#include <hardware/keymaster.h>
+#include <hardware/keymaster0.h>
 
 #include <keymaster/softkeymaster.h>
+#include <keymaster/soft_keymaster_device.h>
 
 #include <UniquePtr.h>
 #include <utils/String8.h>
@@ -60,7 +62,9 @@
 
 #include <selinux/android.h>
 
+#include "auth_token_table.h"
 #include "defaults.h"
+#include "operation.h"
 
 /* KeyStore is a secured storage for key-value pairs. In this implementation,
  * each file stores one key-value pair. Keys are encoded in file names, and
@@ -101,8 +105,7 @@
 };
 typedef UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO;
 
-
-static int keymaster_device_initialize(keymaster_device_t** dev) {
+static int keymaster_device_initialize(keymaster0_device_t** dev) {
     int rc;
 
     const hw_module_t* mod;
@@ -112,7 +115,7 @@
         goto out;
     }
 
-    rc = keymaster_open(mod, dev);
+    rc = keymaster0_open(mod, dev);
     if (rc) {
         ALOGE("could not open keymaster device in %s (%s)",
             KEYSTORE_HARDWARE_MODULE_ID, strerror(-rc));
@@ -126,8 +129,16 @@
     return rc;
 }
 
-static void keymaster_device_release(keymaster_device_t* dev) {
-    keymaster_close(dev);
+static int fallback_keymaster_device_initialize(keymaster1_device_t** dev) {
+    keymaster::SoftKeymasterDevice* softkeymaster =
+            new keymaster::SoftKeymasterDevice();
+    // SoftKeymasterDevice is designed to make this cast safe.
+    *dev = reinterpret_cast<keymaster1_device_t*>(softkeymaster);
+    return 0;
+}
+
+static void keymaster_device_release(keymaster0_device_t* dev) {
+    keymaster0_close(dev);
 }
 
 /***************
@@ -155,6 +166,7 @@
     P_RESET_UID     = 1 << 16,
     P_SYNC_UID      = 1 << 17,
     P_PASSWORD_UID  = 1 << 18,
+    P_ADD_AUTH      = 1 << 19,
 } perm_t;
 
 static struct user_euid {
@@ -187,6 +199,7 @@
     "reset_uid",
     "sync_uid",
     "password_uid",
+    "add_auth",
 };
 
 static struct user_perm {
@@ -294,6 +307,9 @@
  * namespace.
  */
 static bool is_granted_to(uid_t callingUid, uid_t targetUid) {
+    if (callingUid == targetUid) {
+        return true;
+    }
     for (size_t i = 0; i < sizeof(user_euids)/sizeof(user_euids[0]); i++) {
         struct user_euid user = user_euids[i];
         if (user.euid == callingUid && user.uid == targetUid) {
@@ -304,15 +320,6 @@
     return false;
 }
 
-/**
- * Allow the system to perform some privileged tasks that have to do with
- * system maintenance. This should not be used for any function that uses
- * the keys in any way (e.g., signing).
- */
-static bool is_self_or_system(uid_t callingUid, uid_t targetUid) {
-    return callingUid == targetUid || callingUid == AID_SYSTEM;
-}
-
 /* Here is the encoding of keys. This is necessary in order to allow arbitrary
  * characters in keys. Characters in [0-~] are not encoded. Others are encoded
  * into two bytes. The first byte is one of [+-.] which represents the first
@@ -479,6 +486,7 @@
     TYPE_GENERIC = 1,
     TYPE_MASTER_KEY = 2,
     TYPE_KEY_PAIR = 3,
+    TYPE_KEYMASTER_10 = 4,
 } BlobType;
 
 static const uint8_t CURRENT_BLOB_VERSION = 2;
@@ -952,9 +960,10 @@
 
 class KeyStore {
 public:
-    KeyStore(Entropy* entropy, keymaster_device_t* device)
+    KeyStore(Entropy* entropy, keymaster1_device_t* device, keymaster1_device_t* fallback)
         : mEntropy(entropy)
         , mDevice(device)
+        , mFallbackDevice(fallback)
     {
         memset(&mMetaData, '\0', sizeof(mMetaData));
     }
@@ -973,10 +982,24 @@
         mMasterKeys.clear();
     }
 
-    keymaster_device_t* getDevice() const {
+    /**
+     * Depending on the hardware keymaster version is this may return a
+     * keymaster0_device_t* cast to a keymaster1_device_t*. All methods from
+     * keymaster0 are safe to call, calls to keymaster1_device_t methods should
+     * be guarded by a check on the device's version.
+     */
+    keymaster1_device_t *getDevice() const {
         return mDevice;
     }
 
+    keymaster1_device_t *getFallbackDevice() const {
+        return mFallbackDevice;
+    }
+
+    keymaster1_device_t *getDeviceForBlob(const Blob& blob) const {
+        return blob.isFallback() ? mFallbackDevice: mDevice;
+    }
+
     ResponseCode initialize() {
         readMetaData();
         if (upgradeKeystore()) {
@@ -1156,6 +1179,15 @@
                 }
             }
         }
+        if (keyBlob.getType() == ::TYPE_KEYMASTER_10) {
+            keymaster1_device_t* dev = getDeviceForBlob(keyBlob);
+            if (dev->delete_key) {
+                keymaster_key_blob_t blob;
+                blob.key_material = keyBlob.getValue();
+                blob.key_material_size = keyBlob.getLength();
+                dev->delete_key(dev, &blob);
+            }
+        }
         if (rc != ::NO_ERROR) {
             return rc;
         }
@@ -1253,7 +1285,7 @@
              * lazier than checking the PKCS#8 key type, but the software
              * implementation will do that anyway.
              */
-            rc = openssl_import_keypair(mDevice, key, keyLen, &data, &dataLength);
+            rc = mFallbackDevice->import_keypair(mFallbackDevice, key, keyLen, &data, &dataLength);
             isFallback = true;
 
             if (rc) {
@@ -1371,7 +1403,8 @@
     static const android::String16 sRSAKeyType;
     Entropy* mEntropy;
 
-    keymaster_device_t* mDevice;
+    keymaster1_device_t* mDevice;
+    keymaster1_device_t* mFallbackDevice;
 
     android::Vector<UserState*> mMasterKeys;
 
@@ -1591,33 +1624,32 @@
 class KeyStoreProxy : public BnKeystoreService, public IBinder::DeathRecipient {
 public:
     KeyStoreProxy(KeyStore* keyStore)
-        : mKeyStore(keyStore)
+        : mKeyStore(keyStore),
+          mOperationMap(this)
     {
     }
 
-    void binderDied(const wp<IBinder>&) {
-        ALOGE("binder death detected");
+    void binderDied(const wp<IBinder>& who) {
+        auto operations = mOperationMap.getOperationsForToken(who.unsafe_get());
+        for (auto token: operations) {
+            abort(token);
+        }
     }
 
     int32_t test() {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_TEST, spid)) {
-            ALOGW("permission denied for %d: test", callingUid);
+        if (!checkBinderPermission(P_TEST)) {
             return ::PERMISSION_DENIED;
         }
 
-        return mKeyStore->getState(callingUid);
+        return mKeyStore->getState(IPCThreadState::self()->getCallingUid());
     }
 
     int32_t get(const String16& name, uint8_t** item, size_t* itemLength) {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_GET, spid)) {
-            ALOGW("permission denied for %d: get", callingUid);
+        if (!checkBinderPermission(P_GET)) {
             return ::PERMISSION_DENIED;
         }
 
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
         String8 name8(name);
         Blob keyBlob;
 
@@ -1639,23 +1671,11 @@
 
     int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int targetUid,
             int32_t flags) {
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        if (!has_permission(callingUid, P_INSERT, spid)) {
-            ALOGW("permission denied for %d: insert", callingUid);
-            return ::PERMISSION_DENIED;
-        }
-
-        State state = mKeyStore->getState(callingUid);
-        if ((flags & KEYSTORE_FLAG_ENCRYPTED) && !isKeystoreUnlocked(state)) {
-            ALOGD("calling get in state: %d", state);
-            return state;
-        }
-
-        if (targetUid == -1) {
-            targetUid = callingUid;
-        } else if (!is_granted_to(callingUid, targetUid)) {
-            return ::PERMISSION_DENIED;
+        targetUid = getEffectiveUid(targetUid);
+        int32_t result = checkBinderPermissionAndKeystoreState(P_INSERT, targetUid,
+                                                    flags & KEYSTORE_FLAG_ENCRYPTED);
+        if (result != ::NO_ERROR) {
+            return result;
         }
 
         String8 name8(name);
@@ -1668,35 +1688,18 @@
     }
 
     int32_t del(const String16& name, int targetUid) {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_DELETE, spid)) {
-            ALOGW("permission denied for %d: del", callingUid);
+        targetUid = getEffectiveUid(targetUid);
+        if (!checkBinderPermission(P_DELETE, targetUid)) {
             return ::PERMISSION_DENIED;
         }
-
-        if (targetUid == -1) {
-            targetUid = callingUid;
-        } else if (!is_granted_to(callingUid, targetUid)) {
-            return ::PERMISSION_DENIED;
-        }
-
         String8 name8(name);
         String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid));
-        return mKeyStore->del(filename.string(), ::TYPE_GENERIC, targetUid);
+        return mKeyStore->del(filename.string(), ::TYPE_ANY, targetUid);
     }
 
     int32_t exist(const String16& name, int targetUid) {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_EXIST, spid)) {
-            ALOGW("permission denied for %d: exist", callingUid);
-            return ::PERMISSION_DENIED;
-        }
-
-        if (targetUid == -1) {
-            targetUid = callingUid;
-        } else if (!is_granted_to(callingUid, targetUid)) {
+        targetUid = getEffectiveUid(targetUid);
+        if (!checkBinderPermission(P_EXIST, targetUid)) {
             return ::PERMISSION_DENIED;
         }
 
@@ -1710,19 +1713,10 @@
     }
 
     int32_t saw(const String16& prefix, int targetUid, Vector<String16>* matches) {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_SAW, spid)) {
-            ALOGW("permission denied for %d: saw", callingUid);
+        targetUid = getEffectiveUid(targetUid);
+        if (!checkBinderPermission(P_SAW, targetUid)) {
             return ::PERMISSION_DENIED;
         }
-
-        if (targetUid == -1) {
-            targetUid = callingUid;
-        } else if (!is_granted_to(callingUid, targetUid)) {
-            return ::PERMISSION_DENIED;
-        }
-
         const String8 prefix8(prefix);
         String8 filename(mKeyStore->getKeyNameForUid(prefix8, targetUid));
 
@@ -1733,13 +1727,11 @@
     }
 
     int32_t reset() {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_RESET, spid)) {
-            ALOGW("permission denied for %d: reset", callingUid);
+        if (!checkBinderPermission(P_RESET)) {
             return ::PERMISSION_DENIED;
         }
 
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
         return mKeyStore->reset(callingUid) ? ::NO_ERROR : ::SYSTEM_ERROR;
     }
 
@@ -1751,14 +1743,12 @@
      * the old one. This avoids permanent damages of the existing data.
      */
     int32_t password(const String16& password) {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_PASSWORD, spid)) {
-            ALOGW("permission denied for %d: password", callingUid);
+        if (!checkBinderPermission(P_PASSWORD)) {
             return ::PERMISSION_DENIED;
         }
 
         const String8 password8(password);
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
 
         switch (mKeyStore->getState(callingUid)) {
             case ::STATE_UNINITIALIZED: {
@@ -1778,13 +1768,11 @@
     }
 
     int32_t lock() {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_LOCK, spid)) {
-            ALOGW("permission denied for %d: lock", callingUid);
+        if (!checkBinderPermission(P_LOCK)) {
             return ::PERMISSION_DENIED;
         }
 
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
         State state = mKeyStore->getState(callingUid);
         if (state != ::STATE_NO_ERROR) {
             ALOGD("calling lock in state: %d", state);
@@ -1796,13 +1784,11 @@
     }
 
     int32_t unlock(const String16& pw) {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_UNLOCK, spid)) {
-            ALOGW("permission denied for %d: unlock", callingUid);
+        if (!checkBinderPermission(P_UNLOCK)) {
             return ::PERMISSION_DENIED;
         }
 
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
         State state = mKeyStore->getState(callingUid);
         if (state != ::STATE_LOCKED) {
             ALOGD("calling unlock when not locked");
@@ -1814,43 +1800,29 @@
     }
 
     int32_t zero() {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_ZERO, spid)) {
-            ALOGW("permission denied for %d: zero", callingUid);
+        if (!checkBinderPermission(P_ZERO)) {
             return -1;
         }
 
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
         return mKeyStore->isEmpty(callingUid) ? ::KEY_NOT_FOUND : ::NO_ERROR;
     }
 
     int32_t generate(const String16& name, int32_t targetUid, int32_t keyType, int32_t keySize,
             int32_t flags, Vector<sp<KeystoreArg> >* args) {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_INSERT, spid)) {
-            ALOGW("permission denied for %d: generate", callingUid);
-            return ::PERMISSION_DENIED;
+        targetUid = getEffectiveUid(targetUid);
+        int32_t result = checkBinderPermissionAndKeystoreState(P_INSERT, targetUid,
+                                                       flags & KEYSTORE_FLAG_ENCRYPTED);
+        if (result != ::NO_ERROR) {
+            return result;
         }
-
-        if (targetUid == -1) {
-            targetUid = callingUid;
-        } else if (!is_granted_to(callingUid, targetUid)) {
-            return ::PERMISSION_DENIED;
-        }
-
-        State state = mKeyStore->getState(callingUid);
-        if ((flags & KEYSTORE_FLAG_ENCRYPTED) && !isKeystoreUnlocked(state)) {
-            ALOGW("calling generate in state: %d", state);
-            return state;
-        }
-
         uint8_t* data;
         size_t dataLength;
         int rc;
         bool isFallback = false;
 
-        const keymaster_device_t* device = mKeyStore->getDevice();
+        const keymaster1_device_t* device = mKeyStore->getDevice();
+        const keymaster1_device_t* fallback = mKeyStore->getFallbackDevice();
         if (device == NULL) {
             return ::SYSTEM_ERROR;
         }
@@ -1899,7 +1871,8 @@
                 rc = device->generate_keypair(device, TYPE_DSA, &dsa_params, &data, &dataLength);
             } else {
                 isFallback = true;
-                rc = openssl_generate_keypair(device, TYPE_DSA, &dsa_params, &data, &dataLength);
+                rc = fallback->generate_keypair(fallback, TYPE_DSA, &dsa_params, &data,
+                                                &dataLength);
             }
         } else if (keyType == EVP_PKEY_EC) {
             keymaster_ec_keygen_params_t ec_params;
@@ -1917,7 +1890,7 @@
                 rc = device->generate_keypair(device, TYPE_EC, &ec_params, &data, &dataLength);
             } else {
                 isFallback = true;
-                rc = openssl_generate_keypair(device, TYPE_EC, &ec_params, &data, &dataLength);
+                rc = fallback->generate_keypair(fallback, TYPE_EC, &ec_params, &data, &dataLength);
             }
         } else if (keyType == EVP_PKEY_RSA) {
             keymaster_rsa_keygen_params_t rsa_params;
@@ -1965,7 +1938,7 @@
         }
 
         String8 name8(name);
-        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid));
+        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid));
 
         Blob keyBlob(data, dataLength, NULL, 0, TYPE_KEY_PAIR);
         free(data);
@@ -1973,30 +1946,17 @@
         keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
         keyBlob.setFallback(isFallback);
 
-        return mKeyStore->put(filename.string(), &keyBlob, callingUid);
+        return mKeyStore->put(filename.string(), &keyBlob, targetUid);
     }
 
     int32_t import(const String16& name, const uint8_t* data, size_t length, int targetUid,
             int32_t flags) {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_INSERT, spid)) {
-            ALOGW("permission denied for %d: import", callingUid);
-            return ::PERMISSION_DENIED;
+        targetUid = getEffectiveUid(targetUid);
+        int32_t result = checkBinderPermissionAndKeystoreState(P_INSERT, targetUid,
+                                                       flags & KEYSTORE_FLAG_ENCRYPTED);
+        if (result != ::NO_ERROR) {
+            return result;
         }
-
-        if (targetUid == -1) {
-            targetUid = callingUid;
-        } else if (!is_granted_to(callingUid, targetUid)) {
-            return ::PERMISSION_DENIED;
-        }
-
-        State state = mKeyStore->getState(targetUid);
-        if ((flags & KEYSTORE_FLAG_ENCRYPTED) && !isKeystoreUnlocked(state)) {
-            ALOGD("calling import in state: %d", state);
-            return state;
-        }
-
         String8 name8(name);
         String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid));
 
@@ -2005,18 +1965,15 @@
 
     int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out,
             size_t* outLength) {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_SIGN, spid)) {
-            ALOGW("permission denied for %d: saw", callingUid);
+        if (!checkBinderPermission(P_SIGN)) {
             return ::PERMISSION_DENIED;
         }
 
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
         Blob keyBlob;
         String8 name8(name);
 
         ALOGV("sign %s from uid %d", name8.string(), callingUid);
-        int rc;
 
         ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, callingUid,
                 ::TYPE_KEY_PAIR);
@@ -2024,7 +1981,7 @@
             return responseCode;
         }
 
-        const keymaster_device_t* device = mKeyStore->getDevice();
+        const keymaster1_device_t* device = mKeyStore->getDeviceForBlob(keyBlob);
         if (device == NULL) {
             ALOGE("no keymaster device; cannot sign");
             return ::SYSTEM_ERROR;
@@ -2038,14 +1995,8 @@
         keymaster_rsa_sign_params_t params;
         params.digest_type = DIGEST_NONE;
         params.padding_type = PADDING_NONE;
-
-        if (keyBlob.isFallback()) {
-            rc = openssl_sign_data(device, &params, keyBlob.getValue(), keyBlob.getLength(), data,
-                    length, out, outLength);
-        } else {
-            rc = device->sign_data(device, &params, keyBlob.getValue(), keyBlob.getLength(), data,
-                    length, out, outLength);
-        }
+        int rc = device->sign_data(device, &params, keyBlob.getValue(), keyBlob.getLength(), data,
+                length, out, outLength);
         if (rc) {
             ALOGW("device couldn't sign data");
             return ::SYSTEM_ERROR;
@@ -2056,19 +2007,11 @@
 
     int32_t verify(const String16& name, const uint8_t* data, size_t dataLength,
             const uint8_t* signature, size_t signatureLength) {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_VERIFY, spid)) {
-            ALOGW("permission denied for %d: verify", callingUid);
+        if (!checkBinderPermission(P_VERIFY)) {
             return ::PERMISSION_DENIED;
         }
 
-        State state = mKeyStore->getState(callingUid);
-        if (!isKeystoreUnlocked(state)) {
-            ALOGD("calling verify in state: %d", state);
-            return state;
-        }
-
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
         Blob keyBlob;
         String8 name8(name);
         int rc;
@@ -2079,7 +2022,7 @@
             return responseCode;
         }
 
-        const keymaster_device_t* device = mKeyStore->getDevice();
+        const keymaster1_device_t* device = mKeyStore->getDeviceForBlob(keyBlob);
         if (device == NULL) {
             return ::SYSTEM_ERROR;
         }
@@ -2092,13 +2035,8 @@
         params.digest_type = DIGEST_NONE;
         params.padding_type = PADDING_NONE;
 
-        if (keyBlob.isFallback()) {
-            rc = openssl_verify_data(device, &params, keyBlob.getValue(), keyBlob.getLength(), data,
-                    dataLength, signature, signatureLength);
-        } else {
-            rc = device->verify_data(device, &params, keyBlob.getValue(), keyBlob.getLength(), data,
-                    dataLength, signature, signatureLength);
-        }
+        rc = device->verify_data(device, &params, keyBlob.getValue(), keyBlob.getLength(), data,
+                dataLength, signature, signatureLength);
         if (rc) {
             return ::SYSTEM_ERROR;
         } else {
@@ -2119,8 +2057,7 @@
      */
     int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength) {
         uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_GET, spid)) {
+        if (!checkBinderPermission(P_GET)) {
             ALOGW("permission denied for %d: get_pubkey", callingUid);
             return ::PERMISSION_DENIED;
         }
@@ -2136,7 +2073,7 @@
             return responseCode;
         }
 
-        const keymaster_device_t* device = mKeyStore->getDevice();
+        const keymaster1_device_t* device = mKeyStore->getDeviceForBlob(keyBlob);
         if (device == NULL) {
             return ::SYSTEM_ERROR;
         }
@@ -2147,13 +2084,8 @@
         }
 
         int rc;
-        if (keyBlob.isFallback()) {
-            rc = openssl_get_keypair_public(device, keyBlob.getValue(), keyBlob.getLength(), pubkey,
-                    pubkeyLength);
-        } else {
-            rc = device->get_keypair_public(device, keyBlob.getValue(), keyBlob.getLength(), pubkey,
-                    pubkeyLength);
-        }
+        rc = device->get_keypair_public(device, keyBlob.getValue(), keyBlob.getLength(), pubkey,
+                pubkeyLength);
         if (rc) {
             return ::SYSTEM_ERROR;
         }
@@ -2162,36 +2094,14 @@
     }
 
     int32_t del_key(const String16& name, int targetUid) {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_DELETE, spid)) {
-            ALOGW("permission denied for %d: del_key", callingUid);
-            return ::PERMISSION_DENIED;
-        }
-
-        if (targetUid == -1) {
-            targetUid = callingUid;
-        } else if (!is_granted_to(callingUid, targetUid)) {
-            return ::PERMISSION_DENIED;
-        }
-
-        String8 name8(name);
-        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid));
-        return mKeyStore->del(filename.string(), ::TYPE_KEY_PAIR, targetUid);
+        return del(name, targetUid);
     }
 
     int32_t grant(const String16& name, int32_t granteeUid) {
         uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_GRANT, spid)) {
-            ALOGW("permission denied for %d: grant", callingUid);
-            return ::PERMISSION_DENIED;
-        }
-
-        State state = mKeyStore->getState(callingUid);
-        if (!isKeystoreUnlocked(state)) {
-            ALOGD("calling grant in state: %d", state);
-            return state;
+        int32_t result = checkBinderPermissionAndKeystoreState(P_GRANT);
+        if (result != ::NO_ERROR) {
+            return result;
         }
 
         String8 name8(name);
@@ -2207,16 +2117,9 @@
 
     int32_t ungrant(const String16& name, int32_t granteeUid) {
         uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_GRANT, spid)) {
-            ALOGW("permission denied for %d: ungrant", callingUid);
-            return ::PERMISSION_DENIED;
-        }
-
-        State state = mKeyStore->getState(callingUid);
-        if (!isKeystoreUnlocked(state)) {
-            ALOGD("calling ungrant in state: %d", state);
-            return state;
+        int32_t result = checkBinderPermissionAndKeystoreState(P_GRANT);
+        if (result != ::NO_ERROR) {
+            return result;
         }
 
         String8 name8(name);
@@ -2231,8 +2134,7 @@
 
     int64_t getmtime(const String16& name) {
         uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_GET, spid)) {
+        if (!checkBinderPermission(P_GET)) {
             ALOGW("permission denied for %d: getmtime", callingUid);
             return -1L;
         }
@@ -2327,27 +2229,11 @@
     }
 
     int32_t clear_uid(int64_t targetUid64) {
-        uid_t targetUid = static_cast<uid_t>(targetUid64);
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_CLEAR_UID, spid)) {
-            ALOGW("permission denied for %d: clear_uid", callingUid);
+        uid_t targetUid = getEffectiveUid(targetUid64);
+        if (!checkBinderPermission(P_CLEAR_UID, targetUid)) {
             return ::PERMISSION_DENIED;
         }
 
-        if (targetUid64 == -1) {
-            targetUid = callingUid;
-        } else if (!is_self_or_system(callingUid, targetUid)) {
-            ALOGW("permission denied for %d: clear_uid %d", callingUid, targetUid);
-            return ::PERMISSION_DENIED;
-        }
-
-        const keymaster_device_t* device = mKeyStore->getDevice();
-        if (device == NULL) {
-            ALOGW("can't get keymaster device");
-            return ::SYSTEM_ERROR;
-        }
-
         String8 prefix = String8::format("%u_", targetUid);
         Vector<String16> aliases;
         if (mKeyStore->saw(prefix, &aliases, targetUid) != ::NO_ERROR) {
@@ -2363,32 +2249,22 @@
     }
 
     int32_t reset_uid(int32_t targetUid) {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-
-        if (!has_permission(callingUid, P_RESET_UID, spid)) {
-            ALOGW("permission denied for %d: reset_uid %d", callingUid, targetUid);
+        targetUid = getEffectiveUid(targetUid);
+        if (!checkBinderPermission(P_RESET_UID, targetUid)) {
             return ::PERMISSION_DENIED;
         }
-        if (!is_self_or_system(callingUid, targetUid)) {
-            ALOGW("permission denied for %d: reset_uid %d", callingUid, targetUid);
-            return ::PERMISSION_DENIED;
-        }
+        // Flush the auth token table to prevent stale tokens from sticking
+        // around.
+        mAuthTokenTable.Clear();
 
         return mKeyStore->reset(targetUid) ? ::NO_ERROR : ::SYSTEM_ERROR;
     }
 
     int32_t sync_uid(int32_t sourceUid, int32_t targetUid) {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_SYNC_UID, spid)) {
-            ALOGW("permission denied for %d: sync_uid %d -> %d", callingUid, sourceUid, targetUid);
+        if (!checkBinderPermission(P_SYNC_UID, targetUid)) {
             return ::PERMISSION_DENIED;
         }
-        if (callingUid != AID_SYSTEM) {
-            ALOGW("permission denied for %d: sync_uid %d -> %d", callingUid, sourceUid, targetUid);
-            return ::PERMISSION_DENIED;
-        }
+
         if (sourceUid == targetUid) {
             return ::SYSTEM_ERROR;
         }
@@ -2398,17 +2274,10 @@
     }
 
     int32_t password_uid(const String16& pw, int32_t targetUid) {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        pid_t spid = IPCThreadState::self()->getCallingPid();
-        if (!has_permission(callingUid, P_PASSWORD_UID, spid)) {
-            ALOGW("permission denied for %d: password_uid %d", callingUid, targetUid);
+        targetUid = getEffectiveUid(targetUid);
+        if (!checkBinderPermission(P_PASSWORD, targetUid)) {
             return ::PERMISSION_DENIED;
         }
-        if (callingUid != AID_SYSTEM) {
-            ALOGW("permission denied for %d: password_uid %d", callingUid, targetUid);
-            return ::PERMISSION_DENIED;
-        }
-
         const String8 password8(pw);
 
         switch (mKeyStore->getState(targetUid)) {
@@ -2428,7 +2297,579 @@
         return ::SYSTEM_ERROR;
     }
 
+    int32_t addRngEntropy(const uint8_t* data, size_t dataLength) {
+        const keymaster1_device_t* device = mKeyStore->getDevice();
+        const keymaster1_device_t* fallback = mKeyStore->getFallbackDevice();
+        int32_t devResult = KM_ERROR_UNIMPLEMENTED;
+        int32_t fallbackResult = KM_ERROR_UNIMPLEMENTED;
+        if (device->common.module->module_api_version >= KEYMASTER_MODULE_API_VERSION_1_0 &&
+                device->add_rng_entropy != NULL) {
+            devResult = device->add_rng_entropy(device, data, dataLength);
+        }
+        if (fallback->add_rng_entropy) {
+            fallbackResult = fallback->add_rng_entropy(fallback, data, dataLength);
+        }
+        if (devResult) {
+            return devResult;
+        }
+        if (fallbackResult) {
+            return fallbackResult;
+        }
+        return ::NO_ERROR;
+    }
+
+    int32_t generateKey(const String16& name, const KeymasterArguments& params,
+                        const uint8_t* entropy, size_t entropyLength, int uid, int flags,
+                        KeyCharacteristics* outCharacteristics) {
+        uid = getEffectiveUid(uid);
+        int rc = checkBinderPermissionAndKeystoreState(P_INSERT, uid,
+                                                       flags & KEYSTORE_FLAG_ENCRYPTED);
+        if (rc != ::NO_ERROR) {
+            return rc;
+        }
+
+        rc = KM_ERROR_UNIMPLEMENTED;
+        bool isFallback = false;
+        keymaster_key_blob_t blob;
+        keymaster_key_characteristics_t *out = NULL;
+
+        const keymaster1_device_t* device = mKeyStore->getDevice();
+        const keymaster1_device_t* fallback = mKeyStore->getFallbackDevice();
+        if (device == NULL) {
+            return ::SYSTEM_ERROR;
+        }
+        // TODO: Seed from Linux RNG before this.
+        if (device->common.module->module_api_version >= KEYMASTER_MODULE_API_VERSION_1_0 &&
+                device->generate_key != NULL) {
+            if (!entropy) {
+                rc = KM_ERROR_OK;
+            } else if (device->add_rng_entropy) {
+                rc = device->add_rng_entropy(device, entropy, entropyLength);
+            } else {
+                rc = KM_ERROR_UNIMPLEMENTED;
+            }
+            if (rc == KM_ERROR_OK) {
+                rc = device->generate_key(device, params.params.data(), params.params.size(),
+                                          &blob, &out);
+            }
+        }
+        // If the HW device didn't support generate_key or generate_key failed
+        // fall back to the software implementation.
+        if (rc && fallback->generate_key != NULL) {
+            isFallback = true;
+            if (!entropy) {
+                rc = KM_ERROR_OK;
+            } else if (fallback->add_rng_entropy) {
+                rc = fallback->add_rng_entropy(fallback, entropy, entropyLength);
+            } else {
+                rc = KM_ERROR_UNIMPLEMENTED;
+            }
+            if (rc == KM_ERROR_OK) {
+                rc = fallback->generate_key(fallback, params.params.data(), params.params.size(),
+                                            &blob,
+                                            &out);
+            }
+        }
+
+        if (out) {
+            if (outCharacteristics) {
+                outCharacteristics->characteristics = *out;
+            } else {
+                keymaster_free_characteristics(out);
+            }
+            free(out);
+        }
+
+        if (rc) {
+            return rc;
+        }
+
+        String8 name8(name);
+        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid));
+
+        Blob keyBlob(blob.key_material, blob.key_material_size, NULL, 0, ::TYPE_KEYMASTER_10);
+        keyBlob.setFallback(isFallback);
+        keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
+
+        free(const_cast<uint8_t*>(blob.key_material));
+
+        return mKeyStore->put(filename.string(), &keyBlob, uid);
+    }
+
+    int32_t getKeyCharacteristics(const String16& name,
+                                  const keymaster_blob_t* clientId,
+                                  const keymaster_blob_t* appData,
+                                  KeyCharacteristics* outCharacteristics) {
+        if (!outCharacteristics) {
+            return KM_ERROR_UNEXPECTED_NULL_POINTER;
+        }
+
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
+
+        Blob keyBlob;
+        String8 name8(name);
+        int rc;
+
+        ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, callingUid,
+                TYPE_KEYMASTER_10);
+        if (responseCode != ::NO_ERROR) {
+            return responseCode;
+        }
+        keymaster_key_blob_t key;
+        key.key_material_size = keyBlob.getLength();
+        key.key_material = keyBlob.getValue();
+        keymaster1_device_t* dev = mKeyStore->getDeviceForBlob(keyBlob);
+        keymaster_key_characteristics_t *out = NULL;
+        if (!dev->get_key_characteristics) {
+            ALOGW("device does not implement get_key_characteristics");
+            return KM_ERROR_UNIMPLEMENTED;
+        }
+        rc = dev->get_key_characteristics(dev, &key, clientId, appData, &out);
+        if (out) {
+            outCharacteristics->characteristics = *out;
+            free(out);
+        }
+        return rc ? rc : ::NO_ERROR;
+    }
+
+    int32_t importKey(const String16& name, const KeymasterArguments& params,
+                                keymaster_key_format_t format, const uint8_t *keyData,
+                                size_t keyLength, int uid, int flags,
+                                KeyCharacteristics* outCharacteristics) {
+        uid = getEffectiveUid(uid);
+        int rc = checkBinderPermissionAndKeystoreState(P_INSERT, uid,
+                                                       flags & KEYSTORE_FLAG_ENCRYPTED);
+        if (rc != ::NO_ERROR) {
+            return rc;
+        }
+
+        rc = KM_ERROR_UNIMPLEMENTED;
+        bool isFallback = false;
+        keymaster_key_blob_t blob;
+        keymaster_key_characteristics_t *out = NULL;
+
+        const keymaster1_device_t* device = mKeyStore->getDevice();
+        const keymaster1_device_t* fallback = mKeyStore->getFallbackDevice();
+        if (device == NULL) {
+            return ::SYSTEM_ERROR;
+        }
+        if (device->common.module->module_api_version >= KEYMASTER_MODULE_API_VERSION_1_0 &&
+                device->import_key != NULL) {
+            rc = device->import_key(device, params.params.data(), params.params.size(),
+                                    format, keyData, keyLength, &blob, &out);
+        }
+        if (rc && fallback->import_key != NULL) {
+            isFallback = true;
+            rc = fallback->import_key(fallback, params.params.data(), params.params.size(),
+                                      format, keyData, keyLength, &blob, &out);
+        }
+        if (out) {
+            if (outCharacteristics) {
+                outCharacteristics->characteristics = *out;
+            } else {
+                keymaster_free_characteristics(out);
+            }
+            free(out);
+        }
+        if (rc) {
+            return rc;
+        }
+
+        String8 name8(name);
+        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid));
+
+        Blob keyBlob(blob.key_material, blob.key_material_size, NULL, 0, ::TYPE_KEYMASTER_10);
+        keyBlob.setFallback(isFallback);
+        keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
+
+        free((void*) blob.key_material);
+
+        return mKeyStore->put(filename.string(), &keyBlob, uid);
+    }
+
+    void exportKey(const String16& name, keymaster_key_format_t format,
+                           const keymaster_blob_t* clientId,
+                           const keymaster_blob_t* appData, ExportResult* result) {
+
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
+
+        Blob keyBlob;
+        String8 name8(name);
+        int rc;
+
+        ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, callingUid,
+                TYPE_KEYMASTER_10);
+        if (responseCode != ::NO_ERROR) {
+            result->resultCode = responseCode;
+            return;
+        }
+        keymaster_key_blob_t key;
+        key.key_material_size = keyBlob.getLength();
+        key.key_material = keyBlob.getValue();
+        keymaster1_device_t* dev = mKeyStore->getDeviceForBlob(keyBlob);
+        if (!dev->export_key) {
+            result->resultCode = KM_ERROR_UNIMPLEMENTED;
+            return;
+        }
+        uint8_t* ptr = NULL;
+        rc = dev->export_key(dev, format, &key, clientId, appData,
+                                             &ptr, &result->dataLength);
+        result->exportData.reset(ptr);
+        result->resultCode = rc ? rc : ::NO_ERROR;
+    }
+
+    /**
+     * Check that all keymaster_key_param_t's provided by the application are
+     * allowed. Any parameter that keystore adds itself should be disallowed here.
+     */
+    bool checkAllowedOperationParams(const std::vector<keymaster_key_param_t>& params) {
+        for (auto param: params) {
+            switch (param.tag) {
+                case KM_TAG_AUTH_TOKEN:
+                    return false;
+                default:
+                    break;
+            }
+        }
+        return true;
+    }
+
+    int authorizeOperation(const keymaster_key_characteristics_t& characteristics,
+                            keymaster_operation_handle_t handle,
+                            std::vector<keymaster_key_param_t>* params,
+                            bool failOnTokenMissing=true) {
+        if (!checkAllowedOperationParams(*params)) {
+            return KM_ERROR_INVALID_ARGUMENT;
+        }
+        std::vector<keymaster_key_param_t> allCharacteristics;
+        for (size_t i = 0; i < characteristics.sw_enforced.length; i++) {
+            allCharacteristics.push_back(characteristics.sw_enforced.params[i]);
+        }
+        for (size_t i = 0; i < characteristics.hw_enforced.length; i++) {
+            allCharacteristics.push_back(characteristics.hw_enforced.params[i]);
+        }
+        // Check for auth token and add it to the param list if present.
+        const hw_auth_token_t* authToken;
+        switch (mAuthTokenTable.FindAuthorization(allCharacteristics.data(),
+                                                  allCharacteristics.size(), handle, &authToken)) {
+        case keymaster::AuthTokenTable::OK:
+            // Auth token found.
+            params->push_back(keymaster_param_blob(KM_TAG_AUTH_TOKEN,
+                                                   reinterpret_cast<const uint8_t*>(authToken),
+                                                   sizeof(hw_auth_token_t)));
+            break;
+        case keymaster::AuthTokenTable::AUTH_NOT_REQUIRED:
+            return KM_ERROR_OK;
+        case keymaster::AuthTokenTable::AUTH_TOKEN_NOT_FOUND:
+        case keymaster::AuthTokenTable::OP_HANDLE_REQUIRED:
+        case keymaster::AuthTokenTable::AUTH_TOKEN_EXPIRED:
+            if (failOnTokenMissing) {
+                return KM_ERROR_KEY_USER_NOT_AUTHENTICATED;
+            }
+            break;
+        case keymaster::AuthTokenTable::AUTH_TOKEN_WRONG_SID:
+            return KM_ERROR_KEY_USER_NOT_AUTHENTICATED;
+        default:
+            return KM_ERROR_INVALID_ARGUMENT;
+        }
+        // TODO: Enforce the rest of authorization
+        return KM_ERROR_OK;
+    }
+
+    keymaster_error_t getOperationCharacteristics(const keymaster_key_blob_t& key,
+                                    const keymaster1_device_t* dev,
+                                    const std::vector<keymaster_key_param_t>& params,
+                                    keymaster_key_characteristics_t* out) {
+        UniquePtr<keymaster_blob_t> appId;
+        UniquePtr<keymaster_blob_t> appData;
+        for (auto param : params) {
+            if (param.tag == KM_TAG_APPLICATION_ID) {
+                appId.reset(new keymaster_blob_t);
+                appId->data = param.blob.data;
+                appId->data_length = param.blob.data_length;
+            } else if (param.tag == KM_TAG_APPLICATION_DATA) {
+                appData.reset(new keymaster_blob_t);
+                appData->data = param.blob.data;
+                appData->data_length = param.blob.data_length;
+            }
+        }
+        keymaster_key_characteristics_t* result = NULL;
+        if (!dev->get_key_characteristics) {
+            return KM_ERROR_UNIMPLEMENTED;
+        }
+        keymaster_error_t error = dev->get_key_characteristics(dev, &key, appId.get(),
+                                                               appData.get(), &result);
+        if (result) {
+            *out = *result;
+            free(result);
+        }
+        return error;
+    }
+
+    void begin(const sp<IBinder>& appToken, const String16& name, keymaster_purpose_t purpose,
+               bool pruneable, const KeymasterArguments& params, const uint8_t* entropy,
+               size_t entropyLength, KeymasterArguments* outParams, OperationResult* result) {
+        if (!result || !outParams) {
+            ALOGE("Unexpected null arguments to begin()");
+            return;
+        }
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
+        if (!pruneable && get_app_id(callingUid) != AID_SYSTEM) {
+            ALOGE("Non-system uid %d trying to start non-pruneable operation", callingUid);
+            result->resultCode = ::PERMISSION_DENIED;
+            return;
+        }
+        Blob keyBlob;
+        String8 name8(name);
+        ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, callingUid,
+                TYPE_KEYMASTER_10);
+        if (responseCode != ::NO_ERROR) {
+            result->resultCode = responseCode;
+            return;
+        }
+        keymaster_key_blob_t key;
+        key.key_material_size = keyBlob.getLength();
+        key.key_material = keyBlob.getValue();
+        keymaster_key_param_t* out;
+        size_t outSize;
+        keymaster_operation_handle_t handle;
+        keymaster1_device_t* dev = mKeyStore->getDeviceForBlob(keyBlob);
+        keymaster_error_t err = KM_ERROR_UNIMPLEMENTED;
+        std::vector<keymaster_key_param_t> opParams(params.params);
+        Unique_keymaster_key_characteristics characteristics;
+        characteristics.reset(new keymaster_key_characteristics_t);
+        err = getOperationCharacteristics(key, dev, opParams, characteristics.get());
+        if (err) {
+            result->resultCode = err;
+            return;
+        }
+        // Don't require an auth token for the call to begin, authentication can
+        // require an operation handle. Update and finish will require the token
+        // be present and valid.
+        int32_t authResult = authorizeOperation(*characteristics, 0, &opParams,
+                                                /*failOnTokenMissing*/ false);
+        if (authResult) {
+            result->resultCode = err;
+            return;
+        }
+        // Add entropy to the device first.
+        if (entropy) {
+            if (dev->add_rng_entropy) {
+                err = dev->add_rng_entropy(dev, entropy, entropyLength);
+            } else {
+                err = KM_ERROR_UNIMPLEMENTED;
+            }
+            if (err) {
+                result->resultCode = err;
+                return;
+            }
+        }
+        // Don't do an auth check here, we need begin to succeed for
+        // per-operation auth. update/finish will be doing the auth checks.
+        err = dev->begin(dev, purpose, &key, opParams.data(), opParams.size(), &out, &outSize,
+                         &handle);
+
+        // If there are too many operations abort the oldest operation that was
+        // started as pruneable and try again.
+        while (err == KM_ERROR_TOO_MANY_OPERATIONS && mOperationMap.hasPruneableOperation()) {
+            sp<IBinder> oldest = mOperationMap.getOldestPruneableOperation();
+            ALOGD("Ran out of operation handles, trying to prune %p", oldest.get());
+            if (abort(oldest) != ::NO_ERROR) {
+                break;
+            }
+            err = dev->begin(dev, purpose, &key, params.params.data(),
+                             params.params.size(), &out, &outSize,
+                             &handle);
+        }
+        if (err) {
+            result->resultCode = err;
+            return;
+        }
+        if (out) {
+            outParams->params.assign(out, out + outSize);
+            free(out);
+        }
+
+        sp<IBinder> operationToken = mOperationMap.addOperation(handle, dev, appToken,
+                                                                characteristics.release(),
+                                                                pruneable);
+        result->resultCode = ::NO_ERROR;
+        result->token = operationToken;
+        result->handle = handle;
+    }
+
+    void update(const sp<IBinder>& token, const KeymasterArguments& params, const uint8_t* data,
+                size_t dataLength, OperationResult* result) {
+        const keymaster1_device_t* dev;
+        keymaster_operation_handle_t handle;
+        const keymaster_key_characteristics_t* characteristics;
+        if (!mOperationMap.getOperation(token, &handle, &dev, &characteristics)) {
+            result->resultCode = KM_ERROR_INVALID_OPERATION_HANDLE;
+            return;
+        }
+        uint8_t* output_buf = NULL;
+        size_t output_length = 0;
+        size_t consumed = 0;
+        std::vector<keymaster_key_param_t> opParams(params.params);
+        int32_t authResult = authorizeOperation(*characteristics, handle, &opParams);
+        if (authResult) {
+            result->resultCode = authResult;
+            return;
+        }
+        keymaster_error_t err = dev->update(dev, handle, opParams.data(), opParams.size(), data,
+                                            dataLength, &consumed, &output_buf, &output_length);
+        result->data.reset(output_buf);
+        result->dataLength = output_length;
+        result->inputConsumed = consumed;
+        result->resultCode = err ? (int32_t) err : ::NO_ERROR;
+    }
+
+    void finish(const sp<IBinder>& token, const KeymasterArguments& params,
+                const uint8_t* signature, size_t signatureLength, OperationResult* result) {
+        const keymaster1_device_t* dev;
+        keymaster_operation_handle_t handle;
+        const keymaster_key_characteristics_t* characteristics;
+        if (!mOperationMap.getOperation(token, &handle, &dev, &characteristics)) {
+            result->resultCode = KM_ERROR_INVALID_OPERATION_HANDLE;
+            return;
+        }
+        uint8_t* output_buf = NULL;
+        size_t output_length = 0;
+        std::vector<keymaster_key_param_t> opParams(params.params);
+        int32_t authResult = authorizeOperation(*characteristics, handle, &opParams);
+        if (authResult) {
+            result->resultCode = authResult;
+            return;
+        }
+        keymaster_error_t err = dev->finish(dev, handle, opParams.data(), opParams.size(),
+                                            signature, signatureLength, &output_buf,
+                                            &output_length);
+        // Remove the operation regardless of the result
+        mOperationMap.removeOperation(token);
+        mAuthTokenTable.MarkCompleted(handle);
+        result->data.reset(output_buf);
+        result->dataLength = output_length;
+        result->resultCode = err ? (int32_t) err : ::NO_ERROR;
+    }
+
+    int32_t abort(const sp<IBinder>& token) {
+        const keymaster1_device_t* dev;
+        keymaster_operation_handle_t handle;
+        if (!mOperationMap.getOperation(token, &handle, &dev, NULL)) {
+            return KM_ERROR_INVALID_OPERATION_HANDLE;
+        }
+        mOperationMap.removeOperation(token);
+        int32_t rc;
+        if (!dev->abort) {
+            rc = KM_ERROR_UNIMPLEMENTED;
+        } else {
+            rc = dev->abort(dev, handle);
+        }
+        mAuthTokenTable.MarkCompleted(handle);
+        if (rc) {
+            return rc;
+        }
+        return ::NO_ERROR;
+    }
+
+    bool isOperationAuthorized(const sp<IBinder>& token) {
+        const keymaster1_device_t* dev;
+        keymaster_operation_handle_t handle;
+        const keymaster_key_characteristics_t* characteristics;
+        if (!mOperationMap.getOperation(token, &handle, &dev, &characteristics)) {
+            return false;
+        }
+        std::vector<keymaster_key_param_t> ignored;
+        int32_t authResult = authorizeOperation(*characteristics, handle, &ignored);
+        return authResult == KM_ERROR_OK;
+    }
+
+    int32_t addAuthToken(const uint8_t* token, size_t length) {
+        if (!checkBinderPermission(P_ADD_AUTH)) {
+            ALOGW("addAuthToken: permission denied for %d",
+                  IPCThreadState::self()->getCallingUid());
+            return ::PERMISSION_DENIED;
+        }
+        if (length != sizeof(hw_auth_token_t)) {
+            return KM_ERROR_INVALID_ARGUMENT;
+        }
+        hw_auth_token_t* authToken = new hw_auth_token_t;
+        memcpy(reinterpret_cast<void*>(authToken), token, sizeof(hw_auth_token_t));
+        // The table takes ownership of authToken.
+        mAuthTokenTable.AddAuthenticationToken(authToken);
+        return ::NO_ERROR;
+    }
+
 private:
+    static const int32_t UID_SELF = -1;
+
+    /**
+     * Get the effective target uid for a binder operation that takes an
+     * optional uid as the target.
+     */
+    inline uid_t getEffectiveUid(int32_t targetUid) {
+        if (targetUid == UID_SELF) {
+            return IPCThreadState::self()->getCallingUid();
+        }
+        return static_cast<uid_t>(targetUid);
+    }
+
+    /**
+     * Check if the caller of the current binder method has the required
+     * permission and if acting on other uids the grants to do so.
+     */
+    inline bool checkBinderPermission(perm_t permission, int32_t targetUid = UID_SELF) {
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
+        pid_t spid = IPCThreadState::self()->getCallingPid();
+        if (!has_permission(callingUid, permission, spid)) {
+            ALOGW("permission %s denied for %d", get_perm_label(permission), callingUid);
+            return false;
+        }
+        if (!is_granted_to(callingUid, getEffectiveUid(targetUid))) {
+            ALOGW("uid %d not granted to act for %d", callingUid, targetUid);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Check if the caller of the current binder method has the required
+     * permission or the target of the operation is the caller's uid. This is
+     * for operation where the permission is only for cross-uid activity and all
+     * uids are allowed to act on their own (ie: clearing all entries for a
+     * given uid).
+     */
+    inline bool checkBinderPermissionOrSelfTarget(perm_t permission, int32_t targetUid) {
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
+        if (getEffectiveUid(targetUid) == callingUid) {
+            return true;
+        } else {
+            return checkBinderPermission(permission, targetUid);
+        }
+    }
+
+    /**
+     * Helper method to check that the caller has the required permission as
+     * well as the keystore is in the unlocked state if checkUnlocked is true.
+     *
+     * Returns NO_ERROR on success, PERMISSION_DENIED on a permission error and
+     * otherwise the state of keystore when not unlocked and checkUnlocked is
+     * true.
+     */
+    inline int32_t checkBinderPermissionAndKeystoreState(perm_t permission, int32_t targetUid = -1,
+                                                 bool checkUnlocked = true) {
+        if (!checkBinderPermission(permission, targetUid)) {
+            return ::PERMISSION_DENIED;
+        }
+        State state = mKeyStore->getState(getEffectiveUid(targetUid));
+        if (checkUnlocked && !isKeystoreUnlocked(state)) {
+            return state;
+        }
+
+        return ::NO_ERROR;
+
+    }
+
     inline bool isKeystoreUnlocked(State state) {
         switch (state) {
         case ::STATE_NO_ERROR:
@@ -2440,7 +2881,7 @@
         return false;
     }
 
-    bool isKeyTypeSupported(const keymaster_device_t* device, keymaster_keypair_t keyType) {
+    bool isKeyTypeSupported(const keymaster1_device_t* device, keymaster_keypair_t keyType) {
         const int32_t device_api = device->common.module->module_api_version;
         if (device_api == KEYMASTER_MODULE_API_VERSION_0_2) {
             switch (keyType) {
@@ -2468,6 +2909,8 @@
     }
 
     ::KeyStore* mKeyStore;
+    OperationMap mOperationMap;
+    keymaster::AuthTokenTable mAuthTokenTable;
 };
 
 }; // namespace android
@@ -2487,12 +2930,18 @@
         return 1;
     }
 
-    keymaster_device_t* dev;
+    keymaster0_device_t* dev;
     if (keymaster_device_initialize(&dev)) {
         ALOGE("keystore keymaster could not be initialized; exiting");
         return 1;
     }
 
+    keymaster1_device_t* fallback;
+    if (fallback_keymaster_device_initialize(&fallback)) {
+        ALOGE("software keymaster could not be initialized; exiting");
+        return 1;
+    }
+
     ks_is_selinux_enabled = is_selinux_enabled();
     if (ks_is_selinux_enabled) {
         union selinux_callback cb;
@@ -2506,7 +2955,7 @@
         ALOGI("SELinux: Keystore SELinux is disabled.\n");
     }
 
-    KeyStore keyStore(&entropy, dev);
+    KeyStore keyStore(&entropy, reinterpret_cast<keymaster1_device_t*>(dev), fallback);
     keyStore.initialize();
     android::sp<android::IServiceManager> sm = android::defaultServiceManager();
     android::sp<android::KeyStoreProxy> proxy = new android::KeyStoreProxy(&keyStore);
diff --git a/keystore/operation.cpp b/keystore/operation.cpp
new file mode 100644
index 0000000..e871f83
--- /dev/null
+++ b/keystore/operation.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "KeystoreOperation"
+
+#include "operation.h"
+
+#include <algorithm>
+
+namespace android {
+OperationMap::OperationMap(IBinder::DeathRecipient* deathRecipient)
+        : mDeathRecipient(deathRecipient) {
+}
+
+sp<IBinder> OperationMap::addOperation(keymaster_operation_handle_t handle,
+                                       const keymaster1_device_t* dev,
+                                       sp<IBinder> appToken,
+                                       keymaster_key_characteristics_t* characteristics,
+                                       bool pruneable) {
+    sp<IBinder> token = new BBinder();
+    mMap[token] = std::move(Operation(handle, dev, characteristics, appToken));
+    if (pruneable) {
+        mLru.push_back(token);
+    }
+    if (mAppTokenMap.find(appToken) == mAppTokenMap.end()) {
+        appToken->linkToDeath(mDeathRecipient);
+    }
+    mAppTokenMap[appToken].push_back(token);
+    return token;
+}
+
+bool OperationMap::getOperation(sp<IBinder> token, keymaster_operation_handle_t* outHandle,
+                                const keymaster1_device_t** outDevice,
+                                const keymaster_key_characteristics_t** outCharacteristics) {
+    if (!outHandle || !outDevice) {
+        return false;
+    }
+    auto entry = mMap.find(token);
+    if (entry == mMap.end()) {
+        return false;
+    }
+    updateLru(token);
+
+    *outHandle = entry->second.handle;
+    *outDevice = entry->second.device;
+    if (outCharacteristics) {
+        *outCharacteristics = entry->second.characteristics.get();
+    }
+    return true;
+}
+
+void OperationMap::updateLru(sp<IBinder> token) {
+    auto lruEntry = std::find(mLru.begin(), mLru.end(), token);
+    if (lruEntry != mLru.end()) {
+        mLru.erase(lruEntry);
+        mLru.push_back(token);
+    }
+}
+
+bool OperationMap::removeOperation(sp<IBinder> token) {
+    auto entry = mMap.find(token);
+    if (entry == mMap.end()) {
+        return false;
+    }
+    sp<IBinder> appToken = entry->second.appToken;
+    mMap.erase(entry);
+    auto lruEntry = std::find(mLru.begin(), mLru.end(), token);
+    if (lruEntry != mLru.end()) {
+        mLru.erase(lruEntry);
+    }
+    removeOperationTracking(token, appToken);
+    return true;
+}
+
+void OperationMap::removeOperationTracking(sp<IBinder> token, sp<IBinder> appToken) {
+    auto appEntry = mAppTokenMap.find(appToken);
+    if (appEntry == mAppTokenMap.end()) {
+        ALOGE("Entry for %p contains unmapped application token %p", token.get(), appToken.get());
+        return;
+    }
+    auto tokenEntry = std::find(appEntry->second.begin(), appEntry->second.end(), token);
+    appEntry->second.erase(tokenEntry);
+    // Stop listening for death if all operations tied to the token have finished.
+    if (appEntry->second.size() == 0) {
+        appToken->unlinkToDeath(mDeathRecipient);
+        mAppTokenMap.erase(appEntry);
+    }
+}
+
+bool OperationMap::hasPruneableOperation() {
+    return mLru.size() != 0;
+}
+
+sp<IBinder> OperationMap::getOldestPruneableOperation() {
+    if (!hasPruneableOperation()) {
+        return sp<IBinder>(NULL);
+    }
+    return mLru[0];
+}
+
+std::vector<sp<IBinder>> OperationMap::getOperationsForToken(sp<IBinder> appToken) {
+    auto appEntry = mAppTokenMap.find(appToken);
+    if (appEntry != mAppTokenMap.end()) {
+        return appEntry->second;
+    } else {
+        return std::vector<sp<IBinder>>();
+    }
+}
+
+OperationMap::Operation::Operation(keymaster_operation_handle_t handle_,
+                                   const keymaster1_device_t* device_,
+                                   keymaster_key_characteristics_t* characteristics_,
+                                   sp<IBinder> appToken_)
+    : handle(handle_),
+      device(device_),
+      characteristics(characteristics_),
+      appToken(appToken_) {
+}
+
+OperationMap::Operation::Operation() : handle(0), device(NULL), characteristics(), appToken(NULL) {
+}
+} // namespace android
diff --git a/keystore/operation.h b/keystore/operation.h
new file mode 100644
index 0000000..a312528
--- /dev/null
+++ b/keystore/operation.h
@@ -0,0 +1,78 @@
+/*
+ * 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 KEYSTORE_OPERATION_H_
+#define KEYSTORE_OPERATION_H_
+
+#include <hardware/keymaster1.h>
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <utils/LruCache.h>
+#include <utils/StrongPointer.h>
+#include <map>
+#include <vector>
+
+namespace android {
+
+struct keymaster_key_characteristics_t_Delete {
+    void operator()(keymaster_key_characteristics_t* characteristics) const {
+        keymaster_free_characteristics(characteristics);
+        delete characteristics;
+    }
+};
+typedef std::unique_ptr<keymaster_key_characteristics_t, keymaster_key_characteristics_t_Delete>
+    Unique_keymaster_key_characteristics;
+
+/**
+ * OperationMap handles the translation of keymaster_operation_handle_t's and
+ * keymaster1_device_t's to opaque binder tokens that can be used to reference
+ * that operation at a later time by applications. It also does LRU tracking
+ * for operation pruning and keeps a mapping of clients to operations to allow
+ * for graceful handling of application death.
+ */
+class OperationMap {
+public:
+    OperationMap(IBinder::DeathRecipient* deathRecipient);
+    sp<IBinder> addOperation(keymaster_operation_handle_t handle,
+                             const keymaster1_device_t* dev, sp<IBinder> appToken,
+                             keymaster_key_characteristics_t* characteristics, bool pruneable);
+    bool getOperation(sp<IBinder> token, keymaster_operation_handle_t* outHandle,
+                      const keymaster1_device_t** outDev,
+                      const keymaster_key_characteristics_t** outCharacteristics);
+    bool removeOperation(sp<IBinder> token);
+    bool hasPruneableOperation();
+    sp<IBinder> getOldestPruneableOperation();
+    std::vector<sp<IBinder>> getOperationsForToken(sp<IBinder> appToken);
+
+private:
+    void updateLru(sp<IBinder> token);
+    void removeOperationTracking(sp<IBinder> token, sp<IBinder> appToken);
+    struct Operation {
+        Operation();
+        Operation(keymaster_operation_handle_t handle, const keymaster1_device_t* device,
+                  keymaster_key_characteristics_t* characteristics, sp<IBinder> appToken);
+        keymaster_operation_handle_t handle;
+        const keymaster1_device_t* device;
+        Unique_keymaster_key_characteristics characteristics;
+        sp<IBinder> appToken;
+    };
+    std::map<sp<IBinder>, struct Operation> mMap;
+    std::vector<sp<IBinder>> mLru;
+    std::map<sp<IBinder>, std::vector<sp<IBinder>>> mAppTokenMap;
+    IBinder::DeathRecipient* mDeathRecipient;
+};
+} // namespace android
+#endif
diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk
new file mode 100644
index 0000000..be8c426
--- /dev/null
+++ b/keystore/tests/Android.mk
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# Unit test for AuthTokenTable
+include $(CLEAR_VARS)
+ifeq ($(USE_32_BIT_KEYSTORE), true)
+LOCAL_MULTILIB := 32
+endif
+LOCAL_CFLAGS := -Wall -Wextra -Werror
+LOCAL_SRC_FILES := auth_token_table_test.cpp
+LOCAL_MODULE := auth_token_table_test
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libgtest_main libkeystore_test
+LOCAL_SHARED_LIBRARIES := libkeymaster_messages
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_NATIVE_TEST)
diff --git a/keystore/tests/Makefile b/keystore/tests/Makefile
new file mode 100644
index 0000000..5c1117f
--- /dev/null
+++ b/keystore/tests/Makefile
@@ -0,0 +1,116 @@
+##########
+# This makefile builds local unit tests that run locally on the development machine.  Note
+# that it may be necessary to install some libraries on the dev maching to make the tests
+# build.
+#
+# The same unit tests are also built by Android.mk to run on the target device.  The tests
+# should always build and pass in both places.  The on-device test is what really matters,
+# of course, but debugging is often somewhat easier on the dev platform.
+##########
+
+BASE=../../../..
+SUBS=system/core \
+	system/keymaster\
+	hardware/libhardware \
+	external/gtest
+GTEST=$(BASE)/external/gtest
+KEYMASTER=$(BASE)/system/keymaster
+
+INCLUDES=$(foreach dir,$(SUBS),-I $(BASE)/$(dir)/include) \
+	-I $(BASE)/libnativehelper/include/nativehelper \
+	-I $(GTEST) -Iinclude
+
+# Add USE_CLANG=1 to the make command line to build with clang, which has better error
+# reporting and diagnoses some conditions that GCC doesn't.
+ifdef USE_CLANG
+CC=/usr/bin/clang
+CXX=/usr/bin/clang
+CLANG_TEST_DEFINE=-DKEYMASTER_CLANG_TEST_BUILD
+COMPILER_SPECIFIC_ARGS=-std=c++11 $(CLANG_TEST_DEFINE)
+else
+COMPILER_SPECIFIC_ARGS=-std=c++0x -fprofile-arcs
+endif
+
+CPPFLAGS=$(INCLUDES) -g -O0 -MD
+CXXFLAGS=-Wall -Werror -Wno-unused -Winit-self -Wpointer-arith	-Wunused-parameter \
+        -Werror=sign-compare -Wmissing-declarations -ftest-coverage -fno-permissive \
+	-Wno-deprecated-declarations -fno-exceptions -DKEYMASTER_NAME_TAGS \
+	$(COMPILER_SPECIFIC_ARGS)
+
+# Uncomment to enable debug logging.
+# CXXFLAGS += -DDEBUG
+
+LDLIBS=-lpthread -lstdc++ -lgcov
+
+# This list of sources is used for dependency generation and cleanup.  Add each new source
+# file here (not headers).
+CPPSRCS=\
+	../auth_token_table.cpp \
+	auth_token_table_test.cpp
+
+# This list of binaries determes what gets built and run.  Add each new test binary here.
+BINARIES=\
+	auth_token_table_test
+
+.PHONY: coverage memcheck massif clean run
+
+%.run: %
+	./$<
+	touch $@
+
+run: $(BINARIES:=.run)
+
+auth_token_table_test: auth_token_table_test.o \
+	../auth_token_table.o \
+	$(GTEST)/src/gtest-all.o \
+	$(KEYMASTER)/authorization_set.o \
+	$(KEYMASTER)/logger.o \
+	$(KEYMASTER)/serializable.o
+
+coverage: coverage.info
+	genhtml coverage.info --output-directory coverage
+
+coverage.info: run
+	lcov --capture --directory=. --directory=.. -b . --output-file coverage.info
+
+%.coverage : %
+	$(MAKE) clean && $(MAKE) $<
+	./$<
+	lcov --capture --directory=. --output-file coverage.info
+	genhtml coverage.info --output-directory coverage
+#UNINIT_OPTS=--track-origins=yes
+UNINIT_OPTS=--undef-value-errors=no
+
+MEMCHECK_OPTS=--leak-check=full \
+	--show-reachable=yes \
+	--vgdb=full \
+	$(UNINIT_OPTS) \
+	--error-exitcode=1
+
+MASSIF_OPTS=--tool=massif \
+	--stacks=yes
+
+%.memcheck : %
+	valgrind $(MEMCHECK_OPTS) ./$< && \
+	touch $@
+
+%.massif : %
+	valgrind $(MASSIF_OPTS) --massif-out-file=$@ ./$<
+
+memcheck: $(BINARIES:=.memcheck)
+
+massif: $(BINARIES:=.massif)
+
+OBJS=$(CPPSRCS:.cpp=.o)
+DEPS=$(CPPSRCS:.cpp=.d)
+GCOV=$(CPPSRCS:.cpp=.gcov) $(CPPSRCS:.cpp=.gcda) $(CPPSRCS:.cpp=.gcno)
+
+clean:
+	rm -f $(OBJS) $(DEPS) $(BINARIES) $(GCOV) \
+		$(BINARIES:=.run) $(BINARIES:=.memcheck) $(BINARIES:=.massif) \
+		*gcov *gcno *gcda coverage.info
+	rm -rf coverage
+
+-include $(CPPSRCS:.cpp=.d)
+-include $(CCSRCS:.cc=.d)
+
diff --git a/keystore/tests/auth_token_table_test.cpp b/keystore/tests/auth_token_table_test.cpp
new file mode 100644
index 0000000..fec7e43
--- /dev/null
+++ b/keystore/tests/auth_token_table_test.cpp
@@ -0,0 +1,410 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <keymaster/google_keymaster_utils.h>
+#include <keymaster/logger.h>
+
+#include "../auth_token_table.h"
+
+using std::vector;
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    int result = RUN_ALL_TESTS();
+}
+
+inline bool operator==(const hw_auth_token_t& a, const hw_auth_token_t& b) {
+    return (memcmp(&a, &b, sizeof(a)) == 0);
+}
+
+namespace keymaster {
+namespace test {
+
+class StdoutLogger : public Logger {
+  public:
+    StdoutLogger() { set_instance(this); }
+
+    int log_msg(LogLevel level, const char* fmt, va_list args) const {
+        int output_len = 0;
+        switch (level) {
+        case DEBUG_LVL:
+            output_len = printf("DEBUG: ");
+            break;
+        case INFO_LVL:
+            output_len = printf("INFO: ");
+            break;
+        case WARNING_LVL:
+            output_len = printf("WARNING: ");
+            break;
+        case ERROR_LVL:
+            output_len = printf("ERROR: ");
+            break;
+        case SEVERE_LVL:
+            output_len = printf("SEVERE: ");
+            break;
+        }
+
+        output_len += vprintf(fmt, args);
+        output_len += printf("\n");
+        return output_len;
+    }
+};
+
+StdoutLogger logger;
+
+TEST(AuthTokenTableTest, Create) {
+    AuthTokenTable table;
+}
+
+static hw_auth_token_t* make_token(uint64_t rsid, uint64_t ssid = 0, uint64_t challenge = 0,
+                                   uint64_t timestamp = 0) {
+    hw_auth_token_t* token = new hw_auth_token_t;
+    token->user_id = rsid;
+    token->authenticator_id = ssid;
+    token->authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+    token->challenge = challenge;
+    token->timestamp = hton(timestamp);
+    return token;
+}
+
+static AuthorizationSet make_set(uint64_t rsid, uint32_t timeout = 10000) {
+    AuthorizationSetBuilder builder;
+    builder.Authorization(TAG_USER_ID, 10)
+        .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
+        .Authorization(TAG_USER_SECURE_ID, rsid);
+    // Use timeout == 0 to indicate tags that require auth per operation.
+    if (timeout != 0)
+        builder.Authorization(TAG_AUTH_TIMEOUT, timeout);
+    return builder.build();
+}
+
+// Tests obviously run so fast that a real-time clock with a one-second granularity rarely changes
+// output during a test run.  This test clock "ticks" one second every time it's called.
+static time_t monotonic_clock() {
+    static time_t time = 0;
+    return time++;
+}
+
+TEST(AuthTokenTableTest, SimpleAddAndFindTokens) {
+    AuthTokenTable table;
+
+    table.AddAuthenticationToken(make_token(1, 2));
+    table.AddAuthenticationToken(make_token(3, 4));
+    EXPECT_EQ(2U, table.size());
+
+    const hw_auth_token_t* found;
+
+    ASSERT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(1), 0, &found));
+    EXPECT_EQ(1U, found->user_id);
+    EXPECT_EQ(2U, found->authenticator_id);
+
+    ASSERT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(2), 0, &found));
+    EXPECT_EQ(1U, found->user_id);
+    EXPECT_EQ(2U, found->authenticator_id);
+
+    ASSERT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(3), 0, &found));
+    EXPECT_EQ(3U, found->user_id);
+    EXPECT_EQ(4U, found->authenticator_id);
+
+    ASSERT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(4), 0, &found));
+    EXPECT_EQ(3U, found->user_id);
+    EXPECT_EQ(4U, found->authenticator_id);
+
+    ASSERT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+              table.FindAuthorization(make_set(5), 0, &found));
+}
+
+TEST(AuthTokenTableTest, FlushTable) {
+    AuthTokenTable table(3, monotonic_clock);
+
+    table.AddAuthenticationToken(make_token(1));
+    table.AddAuthenticationToken(make_token(2));
+    table.AddAuthenticationToken(make_token(3));
+
+    const hw_auth_token_t* found;
+
+    // All three should be in the table.
+    EXPECT_EQ(3U, table.size());
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(1), 0, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(2), 0, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(3), 0, &found));
+
+    table.Clear();
+    EXPECT_EQ(0U, table.size());
+}
+
+TEST(AuthTokenTableTest, TableOverflow) {
+    AuthTokenTable table(3, monotonic_clock);
+
+    table.AddAuthenticationToken(make_token(1));
+    table.AddAuthenticationToken(make_token(2));
+    table.AddAuthenticationToken(make_token(3));
+
+    const hw_auth_token_t* found;
+
+    // All three should be in the table.
+    EXPECT_EQ(3U, table.size());
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(1), 0, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(2), 0, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(3), 0, &found));
+
+    table.AddAuthenticationToken(make_token(4));
+
+    // Oldest should be gone.
+    EXPECT_EQ(3U, table.size());
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+              table.FindAuthorization(make_set(1), 0, &found));
+
+    // Others should be there, including the new one (4).  Search for it first, then the others, so
+    // 4 becomes the least recently used.
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(4), 0, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(2), 0, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(3), 0, &found));
+
+    table.AddAuthenticationToken(make_token(5));
+
+    // 5 should have replaced 4.
+    EXPECT_EQ(3U, table.size());
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+              table.FindAuthorization(make_set(4), 0, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(2), 0, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(5), 0, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(3), 0, &found));
+
+    table.AddAuthenticationToken(make_token(6));
+    table.AddAuthenticationToken(make_token(7));
+
+    // 2 and 5 should be gone
+    EXPECT_EQ(3U, table.size());
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+              table.FindAuthorization(make_set(2), 0, &found));
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+              table.FindAuthorization(make_set(5), 0, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(6), 0, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(7), 0, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(3), 0, &found));
+
+    table.AddAuthenticationToken(make_token(8));
+    table.AddAuthenticationToken(make_token(9));
+    table.AddAuthenticationToken(make_token(10));
+
+    // Only the three most recent should be there.
+    EXPECT_EQ(3U, table.size());
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+              table.FindAuthorization(make_set(1), 0, &found));
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+              table.FindAuthorization(make_set(2), 0, &found));
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+              table.FindAuthorization(make_set(3), 0, &found));
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+              table.FindAuthorization(make_set(4), 0, &found));
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+              table.FindAuthorization(make_set(5), 0, &found));
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+              table.FindAuthorization(make_set(6), 0, &found));
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+              table.FindAuthorization(make_set(7), 0, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(8), 0, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(9), 0, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(10), 0, &found));
+}
+
+TEST(AuthTokenTableTest, AuthenticationNotRequired) {
+    AuthTokenTable table;
+    const hw_auth_token_t* found;
+
+    EXPECT_EQ(AuthTokenTable::AUTH_NOT_REQUIRED,
+              table.FindAuthorization(AuthorizationSetBuilder().Authorization(TAG_NO_AUTH_REQUIRED),
+                                      0 /* no challenge */, &found));
+}
+
+TEST(AuthTokenTableTest, OperationHandleNotFound) {
+    AuthTokenTable table;
+    const hw_auth_token_t* found;
+
+    table.AddAuthenticationToken(make_token(1, 0, 1, 5));
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+              table.FindAuthorization(make_set(1, 0 /* no timeout */),
+                                      2 /* non-matching challenge */, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(1, 0 /* no timeout */),
+                                                          1 /* matching challenge */, &found));
+    table.MarkCompleted(1);
+    EXPECT_EQ(
+        AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+        table.FindAuthorization(make_set(1, 0 /* no timeout */), 1 /* used challenge */, &found));
+}
+
+TEST(AuthTokenTableTest, OperationHandleRequired) {
+    AuthTokenTable table;
+    const hw_auth_token_t* found;
+
+    table.AddAuthenticationToken(make_token(1));
+    EXPECT_EQ(
+        AuthTokenTable::OP_HANDLE_REQUIRED,
+        table.FindAuthorization(make_set(1, 0 /* no timeout */), 0 /* no op handle */, &found));
+}
+
+TEST(AuthTokenTableTest, AuthSidChanged) {
+    AuthTokenTable table;
+    const hw_auth_token_t* found;
+
+    table.AddAuthenticationToken(make_token(1, 3, /* op handle */ 1));
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_WRONG_SID,
+              table.FindAuthorization(make_set(2, 0 /* no timeout */), 1 /* op handle */, &found));
+}
+
+TEST(AuthTokenTableTest, TokenExpired) {
+    AuthTokenTable table(5, monotonic_clock);
+    const hw_auth_token_t* found;
+
+    auto key_info = make_set(1, 5 /* five second timeout */);
+
+    // monotonic_clock "ticks" one second each time it's called, which is once per request, so the
+    // sixth request should fail, since key_info says the key is good for five seconds.
+    //
+    // Note that this tests the decision of the AuthTokenTable to reject a request it knows is
+    // expired.  An additional check of the secure timestamp (in the token) will be made by
+    // keymaster when the found token is passed to it.
+    table.AddAuthenticationToken(make_token(1, 0));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(key_info, 0 /* no op handle */, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(key_info, 0 /* no op handle */, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(key_info, 0 /* no op handle */, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(key_info, 0 /* no op handle */, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(key_info, 0 /* no op handle */, &found));
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_EXPIRED,
+              table.FindAuthorization(key_info, 0 /* no op handle */, &found));
+}
+
+TEST(AuthTokenTableTest, MarkNonexistentEntryCompleted) {
+    AuthTokenTable table;
+    // Marking a nonexistent entry completed is ignored.  This test is mainly for code coverage.
+    table.MarkCompleted(1);
+}
+
+TEST(AuthTokenTableTest, SupersededEntries) {
+    AuthTokenTable table;
+    const hw_auth_token_t* found;
+
+    // Add two identical tokens, without challenges.  The second should supersede the first, based
+    // on timestamp (fourth arg to make_token).
+    table.AddAuthenticationToken(make_token(1, 0, 0, 0));
+    table.AddAuthenticationToken(make_token(1, 0, 0, 1));
+    EXPECT_EQ(1U, table.size());
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(1), 0, &found));
+    EXPECT_EQ(1U, ntoh(found->timestamp));
+
+    // Add a third token, this with a different RSID.  It should not be superseded.
+    table.AddAuthenticationToken(make_token(2, 0, 0, 2));
+    EXPECT_EQ(2U, table.size());
+
+    // Add two more, superseding each of the two in the table.
+    table.AddAuthenticationToken(make_token(1, 0, 0, 3));
+    table.AddAuthenticationToken(make_token(2, 0, 0, 4));
+    EXPECT_EQ(2U, table.size());
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(1), 0, &found));
+    EXPECT_EQ(3U, ntoh(found->timestamp));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(2), 0, &found));
+    EXPECT_EQ(4U, ntoh(found->timestamp));
+
+    // Add another, this one with a challenge value.  It should supersede the old one since it is
+    // newer, and matches other than the challenge.
+    table.AddAuthenticationToken(make_token(1, 0, 1, 5));
+    EXPECT_EQ(2U, table.size());
+
+    // And another, also with a challenge.  Because of the challenge values, the one just added
+    // cannot be superseded.
+    table.AddAuthenticationToken(make_token(1, 0, 2, 6));
+    EXPECT_EQ(3U, table.size());
+
+    // Should be able to find each of them, by specifying their challenge, with a key that is not
+    // timed (timed keys don't care about challenges).
+    EXPECT_EQ(AuthTokenTable::OK,
+              table.FindAuthorization(make_set(1, 0 /* no timeout*/), 1 /* challenge */, &found));
+    EXPECT_EQ(5U, ntoh(found->timestamp));
+    EXPECT_EQ(AuthTokenTable::OK,
+              table.FindAuthorization(make_set(1, 0 /* no timeout */), 2 /* challenge */, &found));
+    EXPECT_EQ(6U, ntoh(found->timestamp));
+
+    // Add another, without a challenge, and the same timestamp as the last one.  This new one
+    // actually could be considered already-superseded, but the table doesn't handle that case,
+    // since it seems unlikely to occur in practice.
+    table.AddAuthenticationToken(make_token(1, 0, 0, 6));
+    EXPECT_EQ(4U, table.size());
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(1), 0 /* challenge */, &found));
+    EXPECT_EQ(6U, ntoh(found->timestamp));
+
+    // Add another without a challenge but an increased timestamp. This should supersede the
+    // previous challenge-free entry.
+    table.AddAuthenticationToken(make_token(1, 0, 0, 7));
+    EXPECT_EQ(4U, table.size());
+    EXPECT_EQ(AuthTokenTable::OK,
+              table.FindAuthorization(make_set(1, 0 /* no timeout */), 2 /* challenge */, &found));
+    EXPECT_EQ(6U, ntoh(found->timestamp));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(1), 0 /* challenge */, &found));
+    EXPECT_EQ(7U, ntoh(found->timestamp));
+
+    // Mark the entry with challenge 2 as complete.  Since there's a newer challenge-free entry, the
+    // challenge entry will be superseded.
+    table.MarkCompleted(2);
+    EXPECT_EQ(3U, table.size());
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+              table.FindAuthorization(make_set(1, 0 /* no timeout */), 2 /* challenge */, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(1), 0 /* challenge */, &found));
+    EXPECT_EQ(7U, ntoh(found->timestamp));
+
+    // Add another SID 1 entry with a challenge.  It supersedes the previous SID 1 entry with
+    // no challenge (timestamp 7), but not the one with challenge 1 (timestamp 5).
+    table.AddAuthenticationToken(make_token(1, 0, 3, 8));
+    EXPECT_EQ(3U, table.size());
+
+    EXPECT_EQ(AuthTokenTable::OK,
+              table.FindAuthorization(make_set(1, 0 /* no timeout */), 1 /* challenge */, &found));
+    EXPECT_EQ(5U, ntoh(found->timestamp));
+
+    EXPECT_EQ(AuthTokenTable::OK,
+              table.FindAuthorization(make_set(1, 0 /* no timeout */), 3 /* challenge */, &found));
+    EXPECT_EQ(8U, ntoh(found->timestamp));
+
+    // SID 2 entry is still there.
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(2), 0 /* challenge */, &found));
+    EXPECT_EQ(4U, ntoh(found->timestamp));
+
+    // Mark the entry with challenge 3 as complete.  Since the older challenge 1 entry is
+    // incomplete, nothing is superseded.
+    table.MarkCompleted(3);
+    EXPECT_EQ(3U, table.size());
+
+    EXPECT_EQ(AuthTokenTable::OK,
+              table.FindAuthorization(make_set(1, 0 /* no timeout */), 1 /* challenge */, &found));
+    EXPECT_EQ(5U, ntoh(found->timestamp));
+
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(1), 0 /* challenge */, &found));
+    EXPECT_EQ(8U, ntoh(found->timestamp));
+
+    // Mark the entry with challenge 1 as complete.  Since there's a newer one (with challenge 3,
+    // completed), the challenge 1 entry is superseded and removed.
+    table.MarkCompleted(1);
+    EXPECT_EQ(2U, table.size());
+    EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+              table.FindAuthorization(make_set(1, 0 /* no timeout */), 1 /* challenge */, &found));
+    EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(1), 0 /* challenge */, &found));
+    EXPECT_EQ(8U, ntoh(found->timestamp));
+}
+
+}  // namespace keymaster
+}  // namespace test
diff --git a/softkeymaster/Android.mk b/softkeymaster/Android.mk
index 0c733aa..eb32c87 100644
--- a/softkeymaster/Android.mk
+++ b/softkeymaster/Android.mk
@@ -21,9 +21,7 @@
 LOCAL_MODULE := keystore.default
 LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_SRC_FILES := module.cpp
-LOCAL_C_INCLUDES := \
-	system/security/keystore \
-	external/openssl/include
+LOCAL_C_INCLUDES := system/security/keystore
 LOCAL_CFLAGS = -fvisibility=hidden -Wall -Werror
 LOCAL_SHARED_LIBRARIES := libcrypto liblog libkeystore_binder libsoftkeymaster
 LOCAL_MODULE_TAGS := optional
@@ -36,9 +34,8 @@
 endif
 LOCAL_MODULE := libsoftkeymaster
 LOCAL_SRC_FILES := keymaster_openssl.cpp
-LOCAL_C_INCLUDES := \
-	system/security/keystore \
-	external/openssl/include
+LOCAL_C_INCLUDES := system/security/keystore \
+	$(LOCAL_PATH)/include
 LOCAL_CFLAGS = -fvisibility=hidden -Wall -Werror
 LOCAL_SHARED_LIBRARIES := libcrypto liblog libkeystore_binder
 LOCAL_MODULE_TAGS := optional
diff --git a/softkeymaster/include/keymaster/softkeymaster.h b/softkeymaster/include/keymaster/softkeymaster.h
index f304aed..e86ba3d 100644
--- a/softkeymaster/include/keymaster/softkeymaster.h
+++ b/softkeymaster/include/keymaster/softkeymaster.h
@@ -14,28 +14,32 @@
  * limitations under the License.
  */
 
-#include <hardware/keymaster.h>
+#include <hardware/keymaster0.h>
 
 #ifndef SOFTKEYMASTER_INCLUDE_KEYMASTER_SOFTKEYMASTER_H_
 #define SOFTKEYMASTER_INCLUDE_KEYMASTER_SOFTKEYMASTER_H_
 
-int openssl_generate_keypair(const keymaster_device_t* dev, const keymaster_keypair_t key_type,
+int openssl_generate_keypair(const keymaster0_device_t* dev, const keymaster_keypair_t key_type,
                              const void* key_params, uint8_t** keyBlob, size_t* keyBlobLength);
 
-int openssl_import_keypair(const keymaster_device_t* dev, const uint8_t* key,
+int openssl_import_keypair(const keymaster0_device_t* dev, const uint8_t* key,
                            const size_t key_length, uint8_t** key_blob, size_t* key_blob_length);
 
-int openssl_get_keypair_public(const struct keymaster_device* dev, const uint8_t* key_blob,
+int openssl_get_keypair_public(const struct keymaster0_device* dev, const uint8_t* key_blob,
                                const size_t key_blob_length, uint8_t** x509_data,
                                size_t* x509_data_length);
 
-int openssl_sign_data(const keymaster_device_t* dev, const void* params, const uint8_t* keyBlob,
+int openssl_sign_data(const keymaster0_device_t* dev, const void* params, const uint8_t* keyBlob,
                       const size_t keyBlobLength, const uint8_t* data, const size_t dataLength,
                       uint8_t** signedData, size_t* signedDataLength);
 
-int openssl_verify_data(const keymaster_device_t* dev, const void* params, const uint8_t* keyBlob,
+int openssl_verify_data(const keymaster0_device_t* dev, const void* params, const uint8_t* keyBlob,
                         const size_t keyBlobLength, const uint8_t* signedData,
                         const size_t signedDataLength, const uint8_t* signature,
                         const size_t signatureLength);
 
+int openssl_open(const hw_module_t* module, const char* name, hw_device_t** device);
+
+extern struct keystore_module softkeymaster_module;
+
 #endif  // SOFTKEYMASTER_INCLUDE_KEYMASTER_SOFTKEYMASTER_H_
diff --git a/softkeymaster/keymaster_openssl.cpp b/softkeymaster/keymaster_openssl.cpp
index 85ecc6e..edf4db2 100644
--- a/softkeymaster/keymaster_openssl.cpp
+++ b/softkeymaster/keymaster_openssl.cpp
@@ -18,9 +18,10 @@
 #include <stdint.h>
 
 #include <keystore/keystore.h>
+#include <keymaster/softkeymaster.h>
 
 #include <hardware/hardware.h>
-#include <hardware/keymaster.h>
+#include <hardware/keymaster0.h>
 
 #include <openssl/evp.h>
 #include <openssl/bio.h>
@@ -37,61 +38,45 @@
 #include <cutils/log.h>
 
 struct BIGNUM_Delete {
-    void operator()(BIGNUM* p) const {
-        BN_free(p);
-    }
+    void operator()(BIGNUM* p) const { BN_free(p); }
 };
 typedef UniquePtr<BIGNUM, BIGNUM_Delete> Unique_BIGNUM;
 
 struct EVP_PKEY_Delete {
-    void operator()(EVP_PKEY* p) const {
-        EVP_PKEY_free(p);
-    }
+    void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
 };
 typedef UniquePtr<EVP_PKEY, EVP_PKEY_Delete> Unique_EVP_PKEY;
 
 struct PKCS8_PRIV_KEY_INFO_Delete {
-    void operator()(PKCS8_PRIV_KEY_INFO* p) const {
-        PKCS8_PRIV_KEY_INFO_free(p);
-    }
+    void operator()(PKCS8_PRIV_KEY_INFO* p) const { PKCS8_PRIV_KEY_INFO_free(p); }
 };
 typedef UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO;
 
 struct DSA_Delete {
-    void operator()(DSA* p) const {
-        DSA_free(p);
-    }
+    void operator()(DSA* p) const { DSA_free(p); }
 };
 typedef UniquePtr<DSA, DSA_Delete> Unique_DSA;
 
 struct EC_KEY_Delete {
-    void operator()(EC_KEY* p) const {
-        EC_KEY_free(p);
-    }
+    void operator()(EC_KEY* p) const { EC_KEY_free(p); }
 };
 typedef UniquePtr<EC_KEY, EC_KEY_Delete> Unique_EC_KEY;
 
 struct EC_GROUP_Delete {
-    void operator()(EC_GROUP* p) const {
-        EC_GROUP_free(p);
-    }
+    void operator()(EC_GROUP* p) const { EC_GROUP_free(p); }
 };
 typedef UniquePtr<EC_GROUP, EC_GROUP_Delete> Unique_EC_GROUP;
 
 struct RSA_Delete {
-    void operator()(RSA* p) const {
-        RSA_free(p);
-    }
+    void operator()(RSA* p) const { RSA_free(p); }
 };
 typedef UniquePtr<RSA, RSA_Delete> Unique_RSA;
 
 struct Malloc_Free {
-    void operator()(void* p) const {
-        free(p);
-    }
+    void operator()(void* p) const { free(p); }
 };
 
-typedef UniquePtr<keymaster_device_t> Unique_keymaster_device_t;
+typedef UniquePtr<keymaster0_device_t> Unique_keymaster_device_t;
 
 /**
  * Many OpenSSL APIs take ownership of an argument on success but
@@ -118,7 +103,7 @@
     }
 
     ERR_clear_error();
-    ERR_remove_state(0);
+    ERR_remove_thread_state(NULL);
 }
 
 static int wrap_key(EVP_PKEY* pkey, int type, uint8_t** keyBlob, size_t* keyBlobLength) {
@@ -291,9 +276,6 @@
 static int generate_ec_keypair(EVP_PKEY* pkey, const keymaster_ec_keygen_params_t* ec_params) {
     Unique_EC_GROUP group;
     switch (ec_params->field_size) {
-    case 192:
-        group.reset(EC_GROUP_new_by_curve_name(NID_X9_62_prime192v1));
-        break;
     case 224:
         group.reset(EC_GROUP_new_by_curve_name(NID_secp224r1));
         break;
@@ -315,8 +297,10 @@
         return -1;
     }
 
+#if !defined(OPENSSL_IS_BORINGSSL)
     EC_GROUP_set_point_conversion_form(group.get(), POINT_CONVERSION_UNCOMPRESSED);
     EC_GROUP_set_asn1_flag(group.get(), OPENSSL_EC_NAMED_CURVE);
+#endif
 
     /* initialize EC key */
     Unique_EC_KEY eckey(EC_KEY_new());
@@ -379,7 +363,7 @@
 }
 
 __attribute__((visibility("default"))) int openssl_generate_keypair(
-    const keymaster_device_t*, const keymaster_keypair_t key_type, const void* key_params,
+    const keymaster0_device_t*, const keymaster_keypair_t key_type, const void* key_params,
     uint8_t** keyBlob, size_t* keyBlobLength) {
     Unique_EVP_PKEY pkey(EVP_PKEY_new());
     if (pkey.get() == NULL) {
@@ -414,7 +398,7 @@
     return 0;
 }
 
-__attribute__((visibility("default"))) int openssl_import_keypair(const keymaster_device_t*,
+__attribute__((visibility("default"))) int openssl_import_keypair(const keymaster0_device_t*,
                                                                   const uint8_t* key,
                                                                   const size_t key_length,
                                                                   uint8_t** key_blob,
@@ -439,7 +423,6 @@
         logOpenSSLError("openssl_import_keypair");
         return -1;
     }
-    release_because_ownership_transferred(pkcs8);
 
     if (wrap_key(pkey.get(), EVP_PKEY_type(pkey->type), key_blob, key_blob_length)) {
         return -1;
@@ -448,10 +431,11 @@
     return 0;
 }
 
-__attribute__((visibility("default"))) int openssl_get_keypair_public(
-    const struct keymaster_device*, const uint8_t* key_blob, const size_t key_blob_length,
-    uint8_t** x509_data, size_t* x509_data_length) {
-
+__attribute__((visibility("default"))) int openssl_get_keypair_public(const keymaster0_device_t*,
+                                                                      const uint8_t* key_blob,
+                                                                      const size_t key_blob_length,
+                                                                      uint8_t** x509_data,
+                                                                      size_t* x509_data_length) {
     if (x509_data == NULL || x509_data_length == NULL) {
         ALOGW("output public key buffer == NULL");
         return -1;
@@ -586,7 +570,7 @@
 }
 
 __attribute__((visibility("default"))) int openssl_sign_data(
-    const keymaster_device_t*, const void* params, const uint8_t* keyBlob,
+    const keymaster0_device_t*, const void* params, const uint8_t* keyBlob,
     const size_t keyBlobLength, const uint8_t* data, const size_t dataLength, uint8_t** signedData,
     size_t* signedDataLength) {
     if (data == NULL) {
@@ -710,10 +694,9 @@
 }
 
 __attribute__((visibility("default"))) int openssl_verify_data(
-    const keymaster_device_t*, const void* params, const uint8_t* keyBlob,
+    const keymaster0_device_t*, const void* params, const uint8_t* keyBlob,
     const size_t keyBlobLength, const uint8_t* signedData, const size_t signedDataLength,
     const uint8_t* signature, const size_t signatureLength) {
-
     if (signedData == NULL || signature == NULL) {
         ALOGW("data or signature buffers == NULL");
         return -1;
@@ -745,3 +728,63 @@
         return -1;
     }
 }
+
+/* Close an opened OpenSSL instance */
+static int openssl_close(hw_device_t* dev) {
+    delete dev;
+    return 0;
+}
+
+/*
+ * Generic device handling
+ */
+__attribute__((visibility("default"))) int openssl_open(const hw_module_t* module, const char* name,
+                                                        hw_device_t** device) {
+    if (strcmp(name, KEYSTORE_KEYMASTER) != 0)
+        return -EINVAL;
+
+    Unique_keymaster_device_t dev(new keymaster0_device_t);
+    if (dev.get() == NULL)
+        return -ENOMEM;
+
+    dev->common.tag = HARDWARE_DEVICE_TAG;
+    dev->common.version = 1;
+    dev->common.module = (struct hw_module_t*)module;
+    dev->common.close = openssl_close;
+
+    dev->flags = KEYMASTER_SOFTWARE_ONLY;
+
+    dev->generate_keypair = openssl_generate_keypair;
+    dev->import_keypair = openssl_import_keypair;
+    dev->get_keypair_public = openssl_get_keypair_public;
+    dev->delete_keypair = NULL;
+    dev->delete_all = NULL;
+    dev->sign_data = openssl_sign_data;
+    dev->verify_data = openssl_verify_data;
+
+    ERR_load_crypto_strings();
+    ERR_load_BIO_strings();
+
+    *device = reinterpret_cast<hw_device_t*>(dev.release());
+
+    return 0;
+}
+
+static struct hw_module_methods_t keystore_module_methods = {
+    .open = openssl_open,
+};
+
+struct keystore_module softkeymaster_module __attribute__((visibility("default"))) = {
+    .common =
+        {
+         .tag = HARDWARE_MODULE_TAG,
+         .module_api_version = KEYMASTER_MODULE_API_VERSION_0_2,
+         .hal_api_version = HARDWARE_HAL_API_VERSION,
+         .id = KEYSTORE_HARDWARE_MODULE_ID,
+         .name = "Keymaster OpenSSL HAL",
+         .author = "The Android Open Source Project",
+         .methods = &keystore_module_methods,
+         .dso = 0,
+         .reserved = {},
+        },
+};
diff --git a/softkeymaster/module.cpp b/softkeymaster/module.cpp
index 9eeb9b4..0dcbadd 100644
--- a/softkeymaster/module.cpp
+++ b/softkeymaster/module.cpp
@@ -13,83 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <errno.h>
-#include <string.h>
-#include <stdint.h>
-
 #include <keymaster/softkeymaster.h>
 
 #include <keystore/keystore.h>
 
 #include <hardware/hardware.h>
-#include <hardware/keymaster.h>
+#include <hardware/keymaster0.h>
 
-#include <openssl/err.h>
-
-#include <UniquePtr.h>
-
-// For debugging
-// #define LOG_NDEBUG 0
-
-#define LOG_TAG "OpenSSLKeyMaster"
-#include <cutils/log.h>
-
-typedef UniquePtr<keymaster_device_t> Unique_keymaster_device_t;
-
-/* Close an opened OpenSSL instance */
-static int openssl_close(hw_device_t* dev) {
-    delete dev;
-    return 0;
-}
-
-/*
- * Generic device handling
- */
-static int openssl_open(const hw_module_t* module, const char* name, hw_device_t** device) {
-    if (strcmp(name, KEYSTORE_KEYMASTER) != 0)
-        return -EINVAL;
-
-    Unique_keymaster_device_t dev(new keymaster_device_t);
-    if (dev.get() == NULL)
-        return -ENOMEM;
-
-    dev->common.tag = HARDWARE_DEVICE_TAG;
-    dev->common.version = 1;
-    dev->common.module = (struct hw_module_t*)module;
-    dev->common.close = openssl_close;
-
-    dev->flags = KEYMASTER_SOFTWARE_ONLY | KEYMASTER_BLOBS_ARE_STANDALONE;
-
-    dev->generate_keypair = openssl_generate_keypair;
-    dev->import_keypair = openssl_import_keypair;
-    dev->get_keypair_public = openssl_get_keypair_public;
-    dev->delete_keypair = NULL;
-    dev->delete_all = NULL;
-    dev->sign_data = openssl_sign_data;
-    dev->verify_data = openssl_verify_data;
-
-    ERR_load_crypto_strings();
-    ERR_load_BIO_strings();
-
-    *device = reinterpret_cast<hw_device_t*>(dev.release());
-
-    return 0;
-}
-
-static struct hw_module_methods_t keystore_module_methods = {
-    .open = openssl_open,
-};
-
-struct keystore_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
-    .common = {
-        .tag = HARDWARE_MODULE_TAG,
-        .module_api_version = KEYMASTER_MODULE_API_VERSION_0_2,
-        .hal_api_version = HARDWARE_HAL_API_VERSION,
-        .id = KEYSTORE_HARDWARE_MODULE_ID,
-        .name = "Keymaster OpenSSL HAL",
-        .author = "The Android Open Source Project",
-        .methods = &keystore_module_methods,
-        .dso = 0,
-        .reserved = {},
-    },
-};
+struct keystore_module HAL_MODULE_INFO_SYM __attribute__((visibility("default")))
+    = softkeymaster_module;