am 9976480a: Indicate that softkeymaster key blobs are standalone, meaning they don\'t require a functional file system or any other support infrastructure.
* commit '9976480a6e7fc53b40f0fe97aac29aa297bfd1b7':
Indicate that softkeymaster key blobs are standalone, meaning they don't require a functional file system or any other support infrastructure.
diff --git a/keystore-engine/Android.mk b/keystore-engine/Android.mk
index bd86b6a..b33a347 100644
--- a/keystore-engine/Android.mk
+++ b/keystore-engine/Android.mk
@@ -15,25 +15,33 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
+include $(TOP)/external/openssl/flavor.mk
-LOCAL_MODULE := libkeystore
+ifeq ($(OPENSSL_FLAVOR),BoringSSL)
+ LOCAL_MODULE := libkeystore-engine
-LOCAL_MODULE_TAGS := optional
+ LOCAL_SRC_FILES := \
+ android_engine.cpp
-LOCAL_MODULE_RELATIVE_PATH := ssl/engines
+ LOCAL_C_INCLUDES += \
+ external/openssl/src/include
+else
+ LOCAL_MODULE := libkeystore
-LOCAL_SRC_FILES := \
+ 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..ee16312
--- /dev/null
+++ b/keystore-engine/android_engine.cpp
@@ -0,0 +1,452 @@
+/* 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 */,
+};
+
+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/keystore.cpp b/keystore/keystore.cpp
index 63f7ee2..e56edfd 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -231,7 +231,7 @@
return uid / AID_USER;
}
-static bool keystore_selinux_check_access(uid_t uid, perm_t perm, pid_t spid) {
+static bool keystore_selinux_check_access(uid_t /*uid*/, perm_t perm, pid_t spid) {
if (!ks_is_selinux_enabled) {
return true;
}
diff --git a/softkeymaster/keymaster_openssl.cpp b/softkeymaster/keymaster_openssl.cpp
index 85ecc6e..2dc4109 100644
--- a/softkeymaster/keymaster_openssl.cpp
+++ b/softkeymaster/keymaster_openssl.cpp
@@ -118,7 +118,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 +291,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;
@@ -316,7 +313,9 @@
}
EC_GROUP_set_point_conversion_form(group.get(), POINT_CONVERSION_UNCOMPRESSED);
+#if !defined(OPENSSL_IS_BORINGSSL)
EC_GROUP_set_asn1_flag(group.get(), OPENSSL_EC_NAMED_CURVE);
+#endif
/* initialize EC key */
Unique_EC_KEY eckey(EC_KEY_new());