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, ¶m)) {
+ 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, ¶ms, keyBlob.getValue(), keyBlob.getLength(), data,
- length, out, outLength);
- } else {
- rc = device->sign_data(device, ¶ms, keyBlob.getValue(), keyBlob.getLength(), data,
- length, out, outLength);
- }
+ int rc = device->sign_data(device, ¶ms, 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, ¶ms, keyBlob.getValue(), keyBlob.getLength(), data,
- dataLength, signature, signatureLength);
- } else {
- rc = device->verify_data(device, ¶ms, keyBlob.getValue(), keyBlob.getLength(), data,
- dataLength, signature, signatureLength);
- }
+ rc = device->verify_data(device, ¶ms, 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;