summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenny Root <kroot@google.com>2012-02-15 17:20:23 -0800
committerKenny Root <kroot@google.com>2012-03-21 17:12:27 -0700
commit70e3a86abd2c412d602a018967c01c177eb6cf4e (patch)
treee59ab280a44ff7d4a408bd3dcb298f3840ba13ae
parent5187818895c4c5f650a611c40531b1dff7764c18 (diff)
downloadsystem_security-70e3a86abd2c412d602a018967c01c177eb6cf4e.zip
system_security-70e3a86abd2c412d602a018967c01c177eb6cf4e.tar.gz
system_security-70e3a86abd2c412d602a018967c01c177eb6cf4e.tar.bz2
Add keymaster to keystore with soft implementation
Add hardware crypto capabilities to keystore. This allows hardware escrow of private key material. There is also an OpenSSL engine that connects to keystore to allow use of the keystore keys from native code built into the platform. This includes a software implementation of keymaster using OpenSSL as the backend. This is just as insecure as the previous solution, but it's needed so devices without hardware support can continue to operate in the new scheme without a lot of compatibility code. Change-Id: I2bc67766e1f633ef1cbbd2874a65962074e84f4f
-rw-r--r--keystore-engine/Android.mk40
-rw-r--r--keystore-engine/eng_keystore.cpp338
-rw-r--r--keystore/Android.mk3
-rw-r--r--keystore/keystore.cpp460
-rw-r--r--keystore/keystore.h19
-rw-r--r--softkeymaster/Android.mk35
-rw-r--r--softkeymaster/keymaster_openssl.cpp502
7 files changed, 1381 insertions, 16 deletions
diff --git a/keystore-engine/Android.mk b/keystore-engine/Android.mk
new file mode 100644
index 0000000..989cf9a
--- /dev/null
+++ b/keystore-engine/Android.mk
@@ -0,0 +1,40 @@
+# Copyright (C) 2012 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)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libkeystore
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/ssl/engines
+
+LOCAL_SRC_FILES := eng_keystore.cpp
+
+LOCAL_CFLAGS := -fvisibility=hidden -Wall -Werror
+
+LOCAL_C_INCLUDES += \
+ libcore/include \
+ system/security/keystore \
+ external/openssl/include
+
+LOCAL_SHARED_LIBRARIES += \
+ libcrypto \
+ liblog \
+ libcutils \
+ libkeystore_client
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/keystore-engine/eng_keystore.cpp b/keystore-engine/eng_keystore.cpp
new file mode 100644
index 0000000..a202641
--- /dev/null
+++ b/keystore-engine/eng_keystore.cpp
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2012 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 <keystore.h>
+
+#include <UniquePtr.h>
+
+#include <sys/socket.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <openssl/objects.h>
+#include <openssl/engine.h>
+#include <openssl/evp.h>
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "OpenSSL-keystore"
+#include <cutils/log.h>
+
+#include <keystore_client.h>
+
+
+#define DYNAMIC_ENGINE
+#define KEYSTORE_ENGINE_ID "keystore"
+#define KEYSTORE_ENGINE_NAME "Android 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()
+
+struct ENGINE_Delete {
+ void operator()(ENGINE* p) const {
+ ENGINE_free(p);
+ }
+};
+typedef UniquePtr<ENGINE, ENGINE_Delete> Unique_ENGINE;
+
+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;
+
+
+/*
+ * RSA ex_data index for keystore's key handle.
+ */
+static int rsa_key_handle;
+
+
+/**
+ * Execute a keystore command. The number of arguments should be passed in
+ * "numArgs" and be preceeded by the length as a size_t.
+ *
+ * If a reply is expected, the "reply" field must be of size
+ * KEYSTORE_MESSAGE_SIZE.
+ *
+ * Example for numArgs == 2:
+ * keystore_cmd(cmd, reply, 2, size_t, char*, size_t, char*);
+ *
+ * The return value will be the length of the reply stored in "reply."
+ * If an error occurs, the return value will be -1.
+ */
+
+/**
+ * Makes sure the ex_data for the keyhandle is initially set to NULL.
+ */
+int keyhandle_new(void*, void*, CRYPTO_EX_DATA* ad, int idx, long, void*) {
+ return CRYPTO_set_ex_data(ad, idx, NULL);
+}
+
+/**
+ * Frees a previously allocated keyhandle stored in ex_data.
+ */
+void keyhandle_free(void *, void *ptr, CRYPTO_EX_DATA*, int, long, void*) {
+ char* keyhandle = reinterpret_cast<char*>(ptr);
+ if (keyhandle != NULL) {
+ free(keyhandle);
+ }
+}
+
+/**
+ * Duplicates a keyhandle stored in ex_data in case we copy a key.
+ */
+int keyhandle_dup(CRYPTO_EX_DATA* to, CRYPTO_EX_DATA*, void *ptrRef, int idx, long, void *) {
+ // This appears to be a bug in OpenSSL.
+ void** ptr = reinterpret_cast<void**>(ptrRef);
+ char* keyhandle = reinterpret_cast<char*>(*ptr);
+ if (keyhandle != NULL) {
+ char* keyhandle_copy = strdup(keyhandle);
+ *ptr = keyhandle_copy;
+
+ // Call this in case OpenSSL is fixed in the future.
+ (void) CRYPTO_set_ex_data(to, idx, keyhandle_copy);
+ }
+ return 1;
+}
+
+int keystore_rsa_priv_enc(int flen, const unsigned char* from, unsigned char* to, RSA* rsa,
+ int padding) {
+ ALOGV("keystore_rsa_sign(%d, %p, %p, %p, %d)", flen, from, to, rsa, padding);
+
+ int num = RSA_size(rsa);
+ UniquePtr<uint8_t> padded(new uint8_t[num]);
+ if (padded.get() == NULL) {
+ ALOGE("could not allocate padded signature");
+ return 0;
+ }
+
+ switch (padding) {
+ case RSA_PKCS1_PADDING:
+ if (!RSA_padding_add_PKCS1_type_1(padded.get(), num, from, flen)) {
+ return 0;
+ }
+ break;
+ case RSA_X931_PADDING:
+ if (!RSA_padding_add_X931(padded.get(), num, from, flen)) {
+ return 0;
+ }
+ break;
+ case RSA_NO_PADDING:
+ if (!RSA_padding_add_none(padded.get(), num, from, flen)) {
+ return 0;
+ }
+ break;
+ default:
+ ALOGE("Unknown padding type: %d", padding);
+ return 0;
+ }
+
+ uint8_t* key_id = reinterpret_cast<uint8_t*>(RSA_get_ex_data(rsa, rsa_key_handle));
+ if (key_id == NULL) {
+ ALOGE("key had no key_id!");
+ return 0;
+ }
+
+ Keystore_Reply reply;
+ if (keystore_cmd(CommandCodes[SIGN], &reply, 2, strlen(reinterpret_cast<const char*>(key_id)),
+ key_id, static_cast<size_t>(num), reinterpret_cast<const uint8_t*>(padded.get()))
+ != NO_ERROR) {
+ ALOGE("There was an error during rsa_mod_exp");
+ return 0;
+ }
+
+ const size_t replyLen = reply.length();
+ if (replyLen <= 0) {
+ ALOGW("No valid signature returned");
+ return 0;
+ }
+
+ memcpy(to, reply.get(), replyLen);
+
+ ALOGV("rsa=%p keystore_rsa_sign => returning %p len %llu", rsa, to,
+ (unsigned long long) replyLen);
+ return static_cast<int>(replyLen);
+}
+
+static RSA_METHOD keystore_rsa_meth = {
+ KEYSTORE_ENGINE_NAME,
+ NULL, /* rsa_pub_enc */
+ NULL, /* rsa_pub_dec (verification) */
+ keystore_rsa_priv_enc, /* rsa_priv_enc (signing) */
+ NULL, /* rsa_priv_dec */
+ NULL, /* rsa_mod_exp */
+ NULL, /* bn_mod_exp */
+ NULL, /* init */
+ NULL, /* finish */
+ RSA_FLAG_EXT_PKEY | RSA_FLAG_NO_BLINDING, /* flags */
+ NULL, /* app_data */
+ NULL, /* rsa_sign */
+ NULL, /* rsa_verify */
+ NULL, /* rsa_keygen */
+};
+
+static int register_rsa_methods() {
+ const RSA_METHOD* rsa_meth = RSA_PKCS1_SSLeay();
+
+ keystore_rsa_meth.rsa_pub_enc = rsa_meth->rsa_pub_enc;
+ keystore_rsa_meth.rsa_pub_dec = rsa_meth->rsa_pub_dec;
+ keystore_rsa_meth.rsa_priv_dec = rsa_meth->rsa_priv_dec;
+ keystore_rsa_meth.rsa_mod_exp = rsa_meth->rsa_mod_exp;
+ keystore_rsa_meth.bn_mod_exp = rsa_meth->bn_mod_exp;
+
+ return 1;
+}
+
+static EVP_PKEY* keystore_loadkey(ENGINE* e, const char* key_id, UI_METHOD *ui_method,
+ void *callback_data) {
+ ALOGV("keystore_loadkey(%p, \"%s\", %p, %p)", e, key_id, ui_method, callback_data);
+
+ Keystore_Reply reply;
+ if (keystore_cmd(CommandCodes[GET_PUBKEY], &reply, 1, strlen(key_id), key_id) != NO_ERROR) {
+ ALOGV("Cannot get public key for %s", key_id);
+ return NULL;
+ }
+
+ const unsigned char* tmp = reinterpret_cast<const unsigned char*>(reply.get());
+ Unique_EVP_PKEY pkey(d2i_PUBKEY(NULL, &tmp, reply.length()));
+ if (pkey.get() == NULL) {
+ ALOGW("Cannot convert pubkey");
+ return NULL;
+ }
+
+ switch (EVP_PKEY_type(pkey->type)) {
+ case EVP_PKEY_RSA: {
+ Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey.get()));
+ if (!RSA_set_ex_data(rsa.get(), rsa_key_handle, reinterpret_cast<void*>(strdup(key_id)))) {
+ ALOGW("Could not set ex_data for loaded RSA key");
+ return NULL;
+ }
+
+ RSA_set_method(rsa.get(), &keystore_rsa_meth);
+ RSA_blinding_off(rsa.get());
+
+ /*
+ * This should probably be an OpenSSL API, but EVP_PKEY_free calls
+ * ENGINE_finish(), so we need to call ENGINE_init() here.
+ */
+ ENGINE_init(e);
+ rsa->engine = e;
+ rsa->flags |= RSA_FLAG_EXT_PKEY;
+
+ break;
+ }
+ default:
+ ALOGE("Unsupported key type %d", EVP_PKEY_type(pkey->type));
+ return NULL;
+ }
+
+ return pkey.release();
+}
+
+static const ENGINE_CMD_DEFN keystore_cmd_defns[] = {
+ {0, NULL, NULL, 0}
+};
+
+static int keystore_engine_setup(ENGINE* e) {
+ ALOGV("keystore_engine_setup");
+
+ if (!ENGINE_set_id(e, KEYSTORE_ENGINE_ID)
+ || !ENGINE_set_name(e, KEYSTORE_ENGINE_NAME)
+ || !ENGINE_set_load_privkey_function(e, keystore_loadkey)
+ || !ENGINE_set_load_pubkey_function(e, keystore_loadkey)
+ || !ENGINE_set_cmd_defns(e, keystore_cmd_defns)) {
+ ALOGE("Could not set up keystore engine");
+ return 0;
+ }
+
+ if (!ENGINE_set_RSA(e, &keystore_rsa_meth)
+ || !register_rsa_methods()) {
+ ALOGE("Could not set up keystore RSA methods");
+ return 0;
+ }
+
+ /* We need a handle in the RSA keys as well for keygen. */
+ rsa_key_handle = RSA_get_ex_new_index(0, NULL, keyhandle_new, keyhandle_dup, keyhandle_free);
+ if (rsa_key_handle < 0) {
+ ALOGE("Could not set up RSA ex_data index");
+ return 0;
+ }
+
+ return 1;
+}
+
+ENGINE* ENGINE_keystore() {
+ ALOGV("ENGINE_keystore");
+
+ Unique_ENGINE engine(ENGINE_new());
+ if (engine.get() == NULL) {
+ return NULL;
+ }
+
+ if (!keystore_engine_setup(engine.get())) {
+ return NULL;
+ }
+
+ return engine.release();
+}
+
+static int keystore_bind_fn(ENGINE *e, const char *id) {
+ ALOGV("keystore_bind_fn");
+
+ if (!id) {
+ return 0;
+ }
+
+ if (strcmp(id, KEYSTORE_ENGINE_ID)) {
+ return 0;
+ }
+
+ if (!keystore_engine_setup(e)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+extern "C" {
+#undef OPENSSL_EXPORT
+#define OPENSSL_EXPORT extern __attribute__ ((visibility ("default")))
+
+IMPLEMENT_DYNAMIC_CHECK_FN()
+IMPLEMENT_DYNAMIC_BIND_FN(keystore_bind_fn)
+};
diff --git a/keystore/Android.mk b/keystore/Android.mk
index d0ab19d..548f783 100644
--- a/keystore/Android.mk
+++ b/keystore/Android.mk
@@ -19,8 +19,9 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := keystore.cpp
LOCAL_C_INCLUDES := external/openssl/include
-LOCAL_SHARED_LIBRARIES := libcutils libcrypto
+LOCAL_SHARED_LIBRARIES := libcutils libcrypto libhardware
LOCAL_MODULE := keystore
+LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 89d578e..6dfbff2 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -33,6 +33,11 @@
#include <openssl/evp.h>
#include <openssl/md5.h>
+#include <hardware/keymaster.h>
+
+#include <cutils/list.h>
+
+//#define LOG_NDEBUG 0
#define LOG_TAG "keystore"
#include <cutils/log.h>
#include <cutils/sockets.h>
@@ -55,6 +60,62 @@ struct Value {
uint8_t value[VALUE_SIZE];
};
+class ValueString {
+public:
+ ValueString(const Value* orig) {
+ length = orig->length;
+ value = new char[length + 1];
+ memcpy(value, orig->value, length);
+ value[length] = '\0';
+ }
+
+ ~ValueString() {
+ delete[] value;
+ }
+
+ const char* c_str() const {
+ return value;
+ }
+
+ char* release() {
+ char* ret = value;
+ value = NULL;
+ return ret;
+ }
+
+private:
+ char* value;
+ size_t length;
+};
+
+static int keymaster_device_initialize(keymaster_device_t** dev) {
+ int rc;
+
+ const hw_module_t* mod;
+ rc = hw_get_module_by_class(KEYSTORE_HARDWARE_MODULE_ID, NULL, &mod);
+ if (rc) {
+ ALOGE("could not find any keystore module");
+ goto out;
+ }
+
+ rc = keymaster_open(mod, dev);
+ if (rc) {
+ ALOGE("could not open keymaster device in %s (%s)",
+ KEYSTORE_HARDWARE_MODULE_ID, strerror(-rc));
+ goto out;
+ }
+
+ return 0;
+
+out:
+ *dev = NULL;
+ return rc;
+}
+
+static void keymaster_device_release(keymaster_device_t* dev) {
+ keymaster_close(dev);
+}
+
/* 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
@@ -62,9 +123,7 @@ struct Value {
* [0-o]. Therefore in the worst case the length of a key gets doubled. Note
* that Base64 cannot be used here due to the need of prefix match on keys. */
-static int encode_key(char* out, uid_t uid, const Value* key) {
- int n = snprintf(out, NAME_MAX, "%u_", uid);
- out += n;
+static int encode_key(char* out, const Value* key) {
const uint8_t* in = key->value;
int length = key->length;
for (int i = length; i > 0; --i, ++in, ++out) {
@@ -77,7 +136,14 @@ static int encode_key(char* out, uid_t uid, const Value* key) {
}
}
*out = '\0';
- return n + length;
+ return length;
+}
+
+static int encode_key_for_uid(char* out, uid_t uid, const Value* key) {
+ int n = snprintf(out, NAME_MAX, "%u_", uid);
+ out += n;
+
+ return n + encode_key(out, key);
}
static int decode_key(uint8_t* out, const char* in, int length) {
@@ -290,10 +356,18 @@ private:
struct blob mBlob;
};
+typedef struct {
+ uint32_t uid;
+ const uint8_t* keyName;
+
+ struct listnode plist;
+} grant_t;
+
class KeyStore {
public:
- KeyStore(Entropy* entropy)
+ KeyStore(Entropy* entropy, keymaster_device_t* device)
: mEntropy(entropy)
+ , mDevice(device)
, mRetry(MAX_RETRY)
{
if (access(MASTER_KEY_FILE, R_OK) == 0) {
@@ -301,6 +375,8 @@ public:
} else {
setState(STATE_UNINITIALIZED);
}
+
+ list_init(&mGrants);
}
State getState() const {
@@ -311,6 +387,10 @@ public:
return mRetry;
}
+ keymaster_device_t* getDevice() const {
+ return mDevice;
+ }
+
ResponseCode initialize(Value* pw) {
if (!generateMasterKey()) {
return SYSTEM_ERROR;
@@ -436,6 +516,44 @@ public:
return keyBlob->encryptBlob(filename, &mMasterKeyEncryption, mEntropy);
}
+ void addGrant(const char* filename, const Value* uidValue) {
+ uid_t uid;
+ if (!convertToUid(uidValue, &uid)) {
+ return;
+ }
+
+ grant_t *grant = getGrant(filename, uid);
+ if (grant == NULL) {
+ grant = new grant_t;
+ grant->uid = uid;
+ grant->keyName = reinterpret_cast<const uint8_t*>(strdup(filename));
+ list_add_tail(&mGrants, &grant->plist);
+ }
+ }
+
+ bool removeGrant(const Value* keyValue, const Value* uidValue) {
+ uid_t uid;
+ if (!convertToUid(uidValue, &uid)) {
+ return false;
+ }
+
+ ValueString keyString(keyValue);
+
+ grant_t *grant = getGrant(keyString.c_str(), uid);
+ if (grant != NULL) {
+ list_remove(&grant->plist);
+ delete grant;
+ return true;
+ }
+
+ return false;
+ }
+
+ bool hasGrant(const Value* keyValue, const uid_t uid) const {
+ ValueString keyString(keyValue);
+ return getGrant(keyString.c_str(), uid) != NULL;
+ }
+
private:
static const char* MASTER_KEY_FILE;
static const int MASTER_KEY_SIZE_BYTES = 16;
@@ -446,6 +564,8 @@ private:
Entropy* mEntropy;
+ keymaster_device_t* mDevice;
+
State mState;
int8_t mRetry;
@@ -455,6 +575,8 @@ private:
AES_KEY mMasterKeyEncryption;
AES_KEY mMasterKeyDecryption;
+ struct listnode mGrants;
+
void setState(State state) {
mState = state;
if (mState == STATE_NO_ERROR || mState == STATE_UNINITIALIZED) {
@@ -507,6 +629,29 @@ private:
&& (strcmp(filename, ".") != 0)
&& (strcmp(filename, "..") != 0));
}
+
+ grant_t* getGrant(const char* keyName, uid_t uid) const {
+ struct listnode *node;
+ grant_t *grant;
+
+ list_for_each(node, &mGrants) {
+ grant = node_to_item(node, grant_t, plist);
+ if (grant->uid == uid
+ && !strcmp(reinterpret_cast<const char*>(grant->keyName),
+ keyName)) {
+ return grant;
+ }
+ }
+
+ return NULL;
+ }
+
+ bool convertToUid(const Value* uidValue, uid_t* uid) const {
+ ValueString uidString(uidValue);
+ char* end = NULL;
+ *uid = strtol(uidString.c_str(), &end, 10);
+ return *end == '\0';
+ }
};
const char* KeyStore::MASTER_KEY_FILE = ".masterkey";
@@ -558,6 +703,36 @@ static void send_message(int sock, const uint8_t* message, int length) {
send(sock, message, length, 0);
}
+static ResponseCode get_key_for_name(KeyStore* keyStore, Blob* keyBlob, const Value* keyName,
+ const uid_t uid) {
+ char filename[NAME_MAX];
+
+ encode_key_for_uid(filename, uid, keyName);
+ ResponseCode responseCode = keyStore->get(filename, keyBlob);
+ if (responseCode == NO_ERROR) {
+ return responseCode;
+ }
+
+ // If this is the Wifi or VPN user, they actually want system
+ // UID keys.
+ if (uid == AID_WIFI || uid == AID_VPN) {
+ encode_key_for_uid(filename, AID_SYSTEM, keyName);
+ responseCode = keyStore->get(filename, keyBlob);
+ if (responseCode == NO_ERROR) {
+ return responseCode;
+ }
+ }
+
+ // They might be using a granted key.
+ if (!keyStore->hasGrant(keyName, uid)) {
+ return responseCode;
+ }
+
+ // It is a granted key. Try to load it.
+ encode_key(filename, keyName);
+ return keyStore->get(filename, keyBlob);
+}
+
/* Here are the actions. Each of them is a function without arguments. All
* information is defined in global variables, which are set properly before
* performing an action. The number of parameters required by each action is
@@ -574,7 +749,7 @@ static ResponseCode test(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*
static ResponseCode get(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*, Value*) {
char filename[NAME_MAX];
- encode_key(filename, uid, keyName);
+ encode_key_for_uid(filename, uid, keyName);
Blob keyBlob;
ResponseCode responseCode = keyStore->get(filename, &keyBlob);
if (responseCode != NO_ERROR) {
@@ -588,20 +763,20 @@ static ResponseCode get(KeyStore* keyStore, int sock, uid_t uid, Value* keyName,
static ResponseCode insert(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value* val,
Value*) {
char filename[NAME_MAX];
- encode_key(filename, uid, keyName);
+ encode_key_for_uid(filename, uid, keyName);
Blob keyBlob(val->value, val->length, NULL, 0);
return keyStore->put(filename, &keyBlob);
}
static ResponseCode del(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*, Value*) {
char filename[NAME_MAX];
- encode_key(filename, uid, keyName);
+ encode_key_for_uid(filename, uid, keyName);
return (unlink(filename) && errno != ENOENT) ? SYSTEM_ERROR : NO_ERROR;
}
static ResponseCode exist(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*, Value*) {
char filename[NAME_MAX];
- encode_key(filename, uid, keyName);
+ encode_key_for_uid(filename, uid, keyName);
if (access(filename, R_OK) == -1) {
return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
}
@@ -614,7 +789,7 @@ static ResponseCode saw(KeyStore* keyStore, int sock, uid_t uid, Value* keyPrefi
return SYSTEM_ERROR;
}
char filename[NAME_MAX];
- int n = encode_key(filename, uid, keyPrefix);
+ int n = encode_key_for_uid(filename, uid, keyPrefix);
send_code(sock, NO_ERROR);
struct dirent* file;
@@ -671,8 +846,239 @@ static ResponseCode zero(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*
return keyStore->isEmpty() ? KEY_NOT_FOUND : NO_ERROR;
}
-/* Here are the permissions, actions, users, and the main function. */
+static ResponseCode generate(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*,
+ Value*) {
+ char filename[NAME_MAX];
+ uint8_t* data;
+ size_t dataLength;
+ int rc;
+
+ const keymaster_device_t* device = keyStore->getDevice();
+ if (device == NULL) {
+ return SYSTEM_ERROR;
+ }
+ if (device->generate_keypair == NULL) {
+ return SYSTEM_ERROR;
+ }
+
+ keymaster_rsa_keygen_params_t rsa_params;
+ rsa_params.modulus_size = 2048;
+ rsa_params.public_exponent = 0x10001;
+
+ rc = device->generate_keypair(device, TYPE_RSA, &rsa_params, &data, &dataLength);
+ if (rc) {
+ return SYSTEM_ERROR;
+ }
+
+ encode_key_for_uid(filename, uid, keyName);
+
+ Blob keyBlob(data, dataLength, NULL, 0);
+ free(data);
+
+ return keyStore->put(filename, &keyBlob);
+}
+
+static ResponseCode import(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value* key,
+ Value*) {
+ char filename[NAME_MAX];
+ uint8_t* data;
+ size_t dataLength;
+ int rc;
+
+ const keymaster_device_t* device = keyStore->getDevice();
+ if (device == NULL) {
+ ALOGE("No keymaster device!");
+ return SYSTEM_ERROR;
+ }
+
+ if (device->import_keypair == NULL) {
+ ALOGE("Keymaster doesn't support import!");
+ return SYSTEM_ERROR;
+ }
+
+ rc = device->import_keypair(device, key->value, key->length, &data, &dataLength);
+ if (rc) {
+ ALOGE("Error while importing keypair: %d", rc);
+ return SYSTEM_ERROR;
+ }
+
+ encode_key_for_uid(filename, uid, keyName);
+
+ Blob keyBlob(data, dataLength, NULL, 0);
+ free(data);
+
+ return keyStore->put(filename, &keyBlob);
+}
+
+/*
+ * TODO: The abstraction between things stored in hardware and regular blobs
+ * of data stored on the filesystem should be moved down to keystore itself.
+ * Unfortunately the Java code that calls this has naming conventions that it
+ * knows about. Ideally keystore shouldn't be used to store random blobs of
+ * data.
+ *
+ * Until that happens, it's necessary to have a separate "get_pubkey" and
+ * "del_key" since the Java code doesn't really communicate what it's
+ * intentions are.
+ */
+static ResponseCode get_pubkey(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*, Value*) {
+ Blob keyBlob;
+ ALOGV("get_pubkey '%s' from uid %d", ValueString(keyName).c_str(), uid);
+
+ ResponseCode responseCode = get_key_for_name(keyStore, &keyBlob, keyName, uid);
+ if (responseCode != NO_ERROR) {
+ return responseCode;
+ }
+
+ const keymaster_device_t* device = keyStore->getDevice();
+ if (device == NULL) {
+ return SYSTEM_ERROR;
+ }
+
+ if (device->get_keypair_public == NULL) {
+ ALOGE("device has no get_keypair_public implementation!");
+ return SYSTEM_ERROR;
+ }
+
+ uint8_t* data = NULL;
+ size_t dataLength;
+
+ int rc = device->get_keypair_public(device, keyBlob.getValue(), keyBlob.getLength(), &data,
+ &dataLength);
+ if (rc) {
+ return SYSTEM_ERROR;
+ }
+
+ send_code(sock, NO_ERROR);
+ send_message(sock, data, dataLength);
+ free(data);
+
+ return NO_ERROR_RESPONSE_CODE_SENT;
+}
+
+static ResponseCode del_key(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*,
+ Value*) {
+ char filename[NAME_MAX];
+ encode_key_for_uid(filename, uid, keyName);
+ Blob keyBlob;
+ ResponseCode responseCode = keyStore->get(filename, &keyBlob);
+ if (responseCode != NO_ERROR) {
+ return responseCode;
+ }
+
+ const keymaster_device_t* device = keyStore->getDevice();
+ if (device == NULL) {
+ return SYSTEM_ERROR;
+ }
+
+ if (device->delete_keypair == NULL) {
+ ALOGE("device has no delete_keypair implementation!");
+ return SYSTEM_ERROR;
+ }
+
+ uint8_t* data = NULL;
+ size_t dataLength;
+
+ int rc = device->delete_keypair(device, keyBlob.getValue(), keyBlob.getLength());
+
+ return rc ? SYSTEM_ERROR : NO_ERROR;
+}
+
+static ResponseCode sign(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value* data,
+ Value*) {
+ ALOGV("sign %s from uid %d", ValueString(keyName).c_str(), uid);
+ Blob keyBlob;
+ int rc;
+
+ ResponseCode responseCode = get_key_for_name(keyStore, &keyBlob, keyName, uid);
+ if (responseCode != NO_ERROR) {
+ return responseCode;
+ }
+
+ uint8_t* signedData;
+ size_t signedDataLength;
+
+ const keymaster_device_t* device = keyStore->getDevice();
+ if (device == NULL) {
+ return SYSTEM_ERROR;
+ }
+
+ if (device->sign_data == NULL) {
+ return SYSTEM_ERROR;
+ }
+
+ keymaster_rsa_sign_params_t params;
+ params.digest_type = DIGEST_NONE;
+ params.padding_type = PADDING_NONE;
+
+ rc = device->sign_data(device, &params, keyBlob.getValue(), keyBlob.getLength(),
+ data->value, data->length, &signedData, &signedDataLength);
+ if (rc) {
+ return SYSTEM_ERROR;
+ }
+
+ send_code(sock, NO_ERROR);
+ send_message(sock, signedData, signedDataLength);
+ return NO_ERROR_RESPONSE_CODE_SENT;
+}
+
+static ResponseCode verify(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value* data,
+ Value* signature) {
+ Blob keyBlob;
+ int rc;
+
+ ResponseCode responseCode = get_key_for_name(keyStore, &keyBlob, keyName, uid);
+ if (responseCode != NO_ERROR) {
+ return responseCode;
+ }
+
+ const keymaster_device_t* device = keyStore->getDevice();
+ if (device == NULL) {
+ return SYSTEM_ERROR;
+ }
+
+ if (device->verify_data == NULL) {
+ return SYSTEM_ERROR;
+ }
+
+ keymaster_rsa_sign_params_t params;
+ params.digest_type = DIGEST_NONE;
+ params.padding_type = PADDING_NONE;
+
+ rc = device->verify_data(device, &params, keyBlob.getValue(), keyBlob.getLength(),
+ data->value, data->length, signature->value, signature->length);
+ if (rc) {
+ return SYSTEM_ERROR;
+ } else {
+ return NO_ERROR;
+ }
+}
+
+static ResponseCode grant(KeyStore* keyStore, int sock, uid_t uid, Value* keyName,
+ Value* granteeData, Value*) {
+ char filename[NAME_MAX];
+ encode_key_for_uid(filename, uid, keyName);
+ if (access(filename, R_OK) == -1) {
+ return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
+ }
+
+ keyStore->addGrant(filename, granteeData);
+ return NO_ERROR;
+}
+
+static ResponseCode ungrant(KeyStore* keyStore, int sock, uid_t uid, Value* keyName,
+ Value* granteeData, Value*) {
+ char filename[NAME_MAX];
+ encode_key_for_uid(filename, uid, keyName);
+ if (access(filename, R_OK) == -1) {
+ return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
+ }
+
+ return keyStore->removeGrant(keyName, granteeData) ? NO_ERROR : KEY_NOT_FOUND;
+}
+
+/* Here are the permissions, actions, users, and the main function. */
enum perm {
P_TEST = 1 << TEST,
P_GET = 1 << GET,
@@ -685,6 +1091,9 @@ enum perm {
P_LOCK = 1 << LOCK,
P_UNLOCK = 1 << UNLOCK,
P_ZERO = 1 << ZERO,
+ P_SIGN = 1 << SIGN,
+ P_VERIFY = 1 << VERIFY,
+ P_GRANT = 1 << GRANT,
};
static const int MAX_PARAM = 3;
@@ -710,6 +1119,14 @@ static struct action {
{lock, CommandCodes[LOCK], STATE_NO_ERROR, P_LOCK, {0, 0, 0}},
{unlock, CommandCodes[UNLOCK], STATE_LOCKED, P_UNLOCK, {PASSWORD_SIZE, 0, 0}},
{zero, CommandCodes[ZERO], STATE_ANY, P_ZERO, {0, 0, 0}},
+ {generate, CommandCodes[GENERATE], STATE_NO_ERROR, P_INSERT, {KEY_SIZE, 0, 0}},
+ {import, CommandCodes[IMPORT], STATE_NO_ERROR, P_INSERT, {KEY_SIZE, VALUE_SIZE, 0}},
+ {sign, CommandCodes[SIGN], STATE_NO_ERROR, P_SIGN, {KEY_SIZE, VALUE_SIZE, 0}},
+ {verify, CommandCodes[VERIFY], STATE_NO_ERROR, P_VERIFY, {KEY_SIZE, VALUE_SIZE, VALUE_SIZE}},
+ {get_pubkey, CommandCodes[GET_PUBKEY], STATE_NO_ERROR, P_GET, {KEY_SIZE, 0, 0}},
+ {del_key, CommandCodes[DEL_KEY], STATE_ANY, P_DELETE, {KEY_SIZE, 0, 0}},
+ {grant, CommandCodes[GRANT], STATE_NO_ERROR, P_GRANT, {KEY_SIZE, KEY_SIZE, 0}},
+ {ungrant, CommandCodes[UNGRANT], STATE_NO_ERROR, P_GRANT, {KEY_SIZE, KEY_SIZE, 0}},
{NULL, 0, STATE_ANY, 0, {0, 0, 0}},
};
@@ -719,10 +1136,11 @@ static struct user {
uint32_t perms;
} users[] = {
{AID_SYSTEM, ~0, ~0},
- {AID_VPN, AID_SYSTEM, P_GET},
- {AID_WIFI, AID_SYSTEM, P_GET},
+ {AID_VPN, AID_SYSTEM, P_GET | P_SIGN | P_VERIFY },
+ {AID_WIFI, AID_SYSTEM, P_GET | P_SIGN | P_VERIFY },
{AID_ROOT, AID_SYSTEM, P_GET},
- {~0, ~0, P_TEST | P_GET | P_INSERT | P_DELETE | P_EXIST | P_SAW},
+ {~0, ~0, P_TEST | P_GET | P_INSERT | P_DELETE | P_EXIST | P_SAW |
+ P_SIGN | P_VERIFY},
};
static ResponseCode process(KeyStore* keyStore, int sock, uid_t uid, int8_t code) {
@@ -762,6 +1180,8 @@ static ResponseCode process(KeyStore* keyStore, int sock, uid_t uid, int8_t code
}
int main(int argc, char* argv[]) {
+ void* hardwareContext = NULL;
+
int controlSocket = android_get_control_socket("keystore");
if (argc < 2) {
ALOGE("A directory must be specified!");
@@ -776,6 +1196,13 @@ int main(int argc, char* argv[]) {
if (!entropy.open()) {
return 1;
}
+
+ keymaster_device_t* dev;
+ if (keymaster_device_initialize(&dev)) {
+ ALOGE("keystore keymaster could not be initialized; exiting");
+ return 1;
+ }
+
if (listen(controlSocket, 3) == -1) {
ALOGE("listen: %s", strerror(errno));
return 1;
@@ -783,7 +1210,7 @@ int main(int argc, char* argv[]) {
signal(SIGPIPE, SIG_IGN);
- KeyStore keyStore(&entropy);
+ KeyStore keyStore(&entropy, dev);
int sock;
while ((sock = accept(controlSocket, NULL, 0)) != -1) {
struct timeval tv;
@@ -816,5 +1243,8 @@ int main(int argc, char* argv[]) {
close(sock);
}
ALOGE("accept: %s", strerror(errno));
+
+ keymaster_device_release(dev);
+
return 1;
}
diff --git a/keystore/keystore.h b/keystore/keystore.h
index 93eeb87..0c2dac5 100644
--- a/keystore/keystore.h
+++ b/keystore/keystore.h
@@ -40,6 +40,7 @@ enum ResponseCode {
WRONG_PASSWORD_1 = 11,
WRONG_PASSWORD_2 = 12,
WRONG_PASSWORD_3 = 13, // MAX_RETRY = 4
+ SIGNATURE_INVALID = 14,
};
enum CommandNames {
@@ -54,10 +55,20 @@ enum CommandNames {
LOCK = 8,
UNLOCK = 9,
ZERO = 10,
+ GENERATE = 11,
+ IMPORT = 12,
+ SIGN = 13,
+ VERIFY = 14,
+ GET_PUBKEY = 15,
+ DEL_KEY = 16,
+ GRANT = 17,
+ UNGRANT = 18,
};
typedef uint8_t command_code_t;
+// Taken: a b c d e f g h i j k l m n o p q r s t u v w x y z
+// * * * * * * * * * * * * * * * * * *
command_code_t CommandCodes[] = {
't', // TEST
'g', // GET
@@ -70,6 +81,14 @@ command_code_t CommandCodes[] = {
'l', // LOCK
'u', // UNLOCK
'z', // ZERO
+ 'a', // GENERATE
+ 'm', // IMPORT
+ 'n', // SIGN
+ 'v', // VERIFY
+ 'b', // GET_PUBKEY
+ 'k', // DEL_KEY
+ 'x', // GRANT
+ 'y', // UNGRANT
};
#endif
diff --git a/softkeymaster/Android.mk b/softkeymaster/Android.mk
new file mode 100644
index 0000000..6becd78
--- /dev/null
+++ b/softkeymaster/Android.mk
@@ -0,0 +1,35 @@
+# Copyright (C) 2012 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)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := keystore.default
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+
+LOCAL_SRC_FILES := keymaster_openssl.cpp
+
+LOCAL_C_INCLUDES := \
+ libcore/include \
+ external/openssl/include
+
+LOCAL_C_FLAGS = -fvisibility=hidden -Wall -Werror
+
+LOCAL_SHARED_LIBRARIES := libcrypto liblog
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/softkeymaster/keymaster_openssl.cpp b/softkeymaster/keymaster_openssl.cpp
new file mode 100644
index 0000000..7be00ea
--- /dev/null
+++ b/softkeymaster/keymaster_openssl.cpp
@@ -0,0 +1,502 @@
+/*
+ * Copyright (C) 2012 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 <errno.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <hardware/hardware.h>
+#include <hardware/keymaster.h>
+
+#include <openssl/evp.h>
+#include <openssl/bio.h>
+#include <openssl/rsa.h>
+#include <openssl/err.h>
+#include <openssl/x509.h>
+
+#include <UniquePtr.h>
+
+// For debugging
+//#define LOG_NDEBUG 0
+
+#define LOG_TAG "OpenSSLKeyMaster"
+#include <cutils/log.h>
+
+struct BIGNUM_Delete {
+ 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);
+ }
+};
+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);
+ }
+};
+typedef UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO;
+
+struct RSA_Delete {
+ void operator()(RSA* p) const {
+ RSA_free(p);
+ }
+};
+typedef UniquePtr<RSA, RSA_Delete> Unique_RSA;
+
+typedef UniquePtr<keymaster_device_t> Unique_keymaster_device_t;
+
+/**
+ * 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()
+
+
+/*
+ * Checks this thread's OpenSSL error queue and logs if
+ * necessary.
+ */
+static void logOpenSSLError(const char* location) {
+ int error = ERR_get_error();
+
+ if (error != 0) {
+ char message[256];
+ ERR_error_string_n(error, message, sizeof(message));
+ ALOGE("OpenSSL error in %s %d: %s", location, error, message);
+ }
+
+ ERR_clear_error();
+ ERR_remove_state(0);
+}
+
+static int wrap_key(EVP_PKEY* pkey, int type, uint8_t** keyBlob, size_t* keyBlobLength) {
+ /* Find the length of each size */
+ int publicLen = i2d_PublicKey(pkey, NULL);
+ int privateLen = i2d_PrivateKey(pkey, NULL);
+
+ if (privateLen <= 0 || publicLen <= 0) {
+ ALOGE("private or public key size was too big");
+ return -1;
+ }
+
+ /* int type + int size + private key data + int size + public key data */
+ *keyBlobLength = sizeof(int) + sizeof(int) + privateLen + sizeof(int) + publicLen;
+
+ UniquePtr<unsigned char[]> derData(new unsigned char[*keyBlobLength]);
+ if (derData.get() == NULL) {
+ ALOGE("could not allocate memory for key blob");
+ return -1;
+ }
+ unsigned char* p = derData.get();
+
+ /* Write key type to allocated buffer */
+ for (int i = sizeof(int) - 1; i >= 0; i--) {
+ *p++ = (type >> (8*i)) & 0xFF;
+ }
+
+ /* Write public key to allocated buffer */
+ for (int i = sizeof(int) - 1; i >= 0; i--) {
+ *p++ = (publicLen >> (8*i)) & 0xFF;
+ }
+ if (i2d_PublicKey(pkey, &p) != publicLen) {
+ logOpenSSLError("wrap_key");
+ return -1;
+ }
+
+ /* Write private key to allocated buffer */
+ for (int i = sizeof(int) - 1; i >= 0; i--) {
+ *p++ = (privateLen >> (8*i)) & 0xFF;
+ }
+ if (i2d_PrivateKey(pkey, &p) != privateLen) {
+ logOpenSSLError("wrap_key");
+ return -1;
+ }
+
+ *keyBlob = derData.release();
+
+ return 0;
+}
+
+static EVP_PKEY* unwrap_key(const uint8_t* keyBlob, const size_t keyBlobLength) {
+ long publicLen = 0;
+ long privateLen = 0;
+ const uint8_t* p = keyBlob;
+ const uint8_t *const end = keyBlob + keyBlobLength;
+
+ if (keyBlob == NULL) {
+ ALOGE("supplied key blob was NULL");
+ return NULL;
+ }
+
+ // Should be large enough for:
+ // int32 type, int32 pubLen, char* pub, int32 privLen, char* priv
+ if (keyBlobLength < (sizeof(int) + sizeof(int) + 1 + sizeof(int) + 1)) {
+ ALOGE("key blob appears to be truncated");
+ return NULL;
+ }
+
+ int type = 0;
+ for (size_t i = 0; i < sizeof(int); i++) {
+ type = (type << 8) | *p++;
+ }
+
+ Unique_EVP_PKEY pkey(EVP_PKEY_new());
+ if (pkey.get() == NULL) {
+ logOpenSSLError("unwrap_key");
+ return NULL;
+ }
+
+ for (size_t i = 0; i < sizeof(int); i++) {
+ publicLen = (publicLen << 8) | *p++;
+ }
+ if (p + publicLen > end) {
+ ALOGE("public key length encoding error: size=%ld, end=%d", publicLen, end - p);
+ return NULL;
+ }
+ EVP_PKEY* tmp = pkey.get();
+ d2i_PublicKey(type, &tmp, &p, publicLen);
+
+ if (end - p < 2) {
+ ALOGE("private key truncated");
+ return NULL;
+ }
+ for (size_t i = 0; i < sizeof(int); i++) {
+ privateLen = (privateLen << 8) | *p++;
+ }
+ if (p + privateLen > end) {
+ ALOGE("private key length encoding error: size=%ld, end=%d", privateLen, end - p);
+ return NULL;
+ }
+ d2i_PrivateKey(type, &tmp, &p, privateLen);
+
+ return pkey.release();
+}
+
+static int openssl_generate_keypair(const keymaster_device_t* dev,
+ const keymaster_keypair_t key_type, const void* key_params,
+ uint8_t** keyBlob, size_t* keyBlobLength) {
+ ssize_t privateLen, publicLen;
+
+ if (key_type != TYPE_RSA) {
+ ALOGW("Unsupported key type %d", key_type);
+ return -1;
+ } else if (key_params == NULL) {
+ ALOGW("key_params == null");
+ return -1;
+ }
+
+ keymaster_rsa_keygen_params_t* rsa_params = (keymaster_rsa_keygen_params_t*) key_params;
+
+ Unique_BIGNUM bn(BN_new());
+ if (bn.get() == NULL) {
+ logOpenSSLError("openssl_generate_keypair");
+ return -1;
+ }
+
+ if (BN_set_word(bn.get(), rsa_params->public_exponent) == 0) {
+ logOpenSSLError("openssl_generate_keypair");
+ return -1;
+ }
+
+ /* initialize RSA */
+ Unique_RSA rsa(RSA_new());
+ if (rsa.get() == NULL) {
+ logOpenSSLError("openssl_generate_keypair");
+ return -1;
+ }
+
+ if (!RSA_generate_key_ex(rsa.get(), rsa_params->modulus_size, bn.get(), NULL)
+ || RSA_check_key(rsa.get()) < 0) {
+ logOpenSSLError("openssl_generate_keypair");
+ return -1;
+ }
+
+ /* assign to EVP */
+ Unique_EVP_PKEY pkey(EVP_PKEY_new());
+ if (pkey.get() == NULL) {
+ logOpenSSLError("openssl_generate_keypair");
+ return -1;
+ }
+
+ if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) == 0) {
+ logOpenSSLError("openssl_generate_keypair");
+ return -1;
+ }
+ OWNERSHIP_TRANSFERRED(rsa);
+
+ if (wrap_key(pkey.get(), EVP_PKEY_RSA, keyBlob, keyBlobLength)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int openssl_import_keypair(const keymaster_device_t* dev,
+ const uint8_t* key, const size_t key_length,
+ uint8_t** key_blob, size_t* key_blob_length) {
+ int response = -1;
+
+ if (key == NULL) {
+ ALOGW("input key == NULL");
+ return -1;
+ } else if (key_blob == NULL || key_blob_length == NULL) {
+ ALOGW("output key blob or length == NULL");
+ return -1;
+ }
+
+ Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &key, key_length));
+ if (pkcs8.get() == NULL) {
+ logOpenSSLError("openssl_import_keypair");
+ return -1;
+ }
+
+ /* assign to EVP */
+ Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get()));
+ if (pkey.get() == NULL) {
+ logOpenSSLError("openssl_import_keypair");
+ return -1;
+ }
+ OWNERSHIP_TRANSFERRED(pkcs8);
+
+ if (wrap_key(pkey.get(), EVP_PKEY_type(pkey->type), key_blob, key_blob_length)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int openssl_get_keypair_public(const struct keymaster_device* dev,
+ 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;
+ }
+
+ Unique_EVP_PKEY pkey(unwrap_key(key_blob, key_blob_length));
+ if (pkey.get() == NULL) {
+ return -1;
+ }
+
+ int len = i2d_PUBKEY(pkey.get(), NULL);
+ if (len <= 0) {
+ logOpenSSLError("openssl_get_keypair_public");
+ return -1;
+ }
+
+ UniquePtr<uint8_t> key(static_cast<uint8_t*>(malloc(len)));
+ if (key.get() == NULL) {
+ ALOGE("Could not allocate memory for public key data");
+ return -1;
+ }
+
+ unsigned char* tmp = reinterpret_cast<unsigned char*>(key.get());
+ if (i2d_PUBKEY(pkey.get(), &tmp) != len) {
+ logOpenSSLError("openssl_get_keypair_public");
+ return -1;
+ }
+
+ ALOGV("Length of x509 data is %d", len);
+ *x509_data_length = len;
+ *x509_data = key.release();
+
+ return 0;
+}
+
+static int openssl_sign_data(const keymaster_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 result = -1;
+ EVP_MD_CTX ctx;
+ size_t maxSize;
+
+ if (data == NULL) {
+ ALOGW("input data to sign == NULL");
+ return -1;
+ } else if (signedData == NULL || signedDataLength == NULL) {
+ ALOGW("output signature buffer == NULL");
+ return -1;
+ }
+
+ Unique_EVP_PKEY pkey(unwrap_key(keyBlob, keyBlobLength));
+ if (pkey.get() == NULL) {
+ return -1;
+ }
+
+ if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) {
+ ALOGW("Cannot handle non-RSA keys yet");
+ return -1;
+ }
+
+ keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params;
+ if (sign_params->digest_type != DIGEST_NONE) {
+ ALOGW("Cannot handle digest type %d", sign_params->digest_type);
+ return -1;
+ } else if (sign_params->padding_type != PADDING_NONE) {
+ ALOGW("Cannot handle padding type %d", sign_params->padding_type);
+ return -1;
+ }
+
+ Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey.get()));
+ if (rsa.get() == NULL) {
+ logOpenSSLError("openssl_sign_data");
+ return -1;
+ }
+
+ UniquePtr<uint8_t> signedDataPtr(reinterpret_cast<uint8_t*>(malloc(dataLength)));
+ if (signedDataPtr.get() == NULL) {
+ logOpenSSLError("openssl_sign_data");
+ return -1;
+ }
+
+ unsigned char* tmp = reinterpret_cast<unsigned char*>(signedDataPtr.get());
+ if (RSA_private_encrypt(dataLength, data, tmp, rsa.get(), RSA_NO_PADDING) <= 0) {
+ logOpenSSLError("openssl_sign_data");
+ return -1;
+ }
+
+ *signedDataLength = dataLength;
+ *signedData = signedDataPtr.release();
+ return 0;
+}
+
+static int openssl_verify_data(const keymaster_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) {
+
+ if (signedData == NULL || signature == NULL) {
+ ALOGW("data or signature buffers == NULL");
+ return -1;
+ }
+
+ Unique_EVP_PKEY pkey(unwrap_key(keyBlob, keyBlobLength));
+ if (pkey.get() == NULL) {
+ return -1;
+ }
+
+ if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) {
+ ALOGW("Cannot handle non-RSA keys yet");
+ return -1;
+ }
+
+ keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params;
+ if (sign_params->digest_type != DIGEST_NONE) {
+ ALOGW("Cannot handle digest type %d", sign_params->digest_type);
+ return -1;
+ } else if (sign_params->padding_type != PADDING_NONE) {
+ ALOGW("Cannot handle padding type %d", sign_params->padding_type);
+ return -1;
+ } else if (signatureLength != signedDataLength) {
+ ALOGW("signed data length must be signature length");
+ return -1;
+ }
+
+ Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey.get()));
+ if (rsa.get() == NULL) {
+ logOpenSSLError("openssl_verify_data");
+ return -1;
+ }
+
+ UniquePtr<uint8_t> dataPtr(reinterpret_cast<uint8_t*>(malloc(signedDataLength)));
+ if (dataPtr.get() == NULL) {
+ logOpenSSLError("openssl_verify_data");
+ return -1;
+ }
+
+ unsigned char* tmp = reinterpret_cast<unsigned char*>(dataPtr.get());
+ if (!RSA_public_decrypt(signatureLength, signature, tmp, rsa.get(), RSA_NO_PADDING)) {
+ logOpenSSLError("openssl_verify_data");
+ return -1;
+ }
+
+ int result = 0;
+ for (size_t i = 0; i < signedDataLength; i++) {
+ result |= tmp[i] ^ signedData[i];
+ }
+
+ return result == 0 ? 0 : -1;
+}
+
+/* Close an opened OpenSSL instance */
+static int openssl_close(hw_device_t *dev) {
+ free(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->generate_keypair = openssl_generate_keypair;
+ dev->import_keypair = openssl_import_keypair;
+ dev->get_keypair_public = openssl_get_keypair_public;
+ dev->delete_keypair = 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,
+ version_major: 1,
+ version_minor: 0,
+ id: KEYSTORE_HARDWARE_MODULE_ID,
+ name: "Keymaster OpenSSL HAL",
+ author: "The Android Open Source Project",
+ methods: &keystore_module_methods,
+ dso: 0,
+ reserved: {},
+ },
+};