From 96427baf0094d50047049d329b0779c3c910402c Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Fri, 16 Aug 2013 14:02:41 -0700 Subject: [PATCH] Add support for DSA and ECDSA key types (cherry picked from commit 6071179a371fcd4c238375068ffd7d3cedea615d) Bug: 10600582 Change-Id: I0d851bbe1230a31033614c9f9b9de94f1f842618 --- keystore-engine/Android.mk | 1 + keystore-engine/dsa_meth.cpp | 152 ++++++ keystore-engine/eng_keystore.cpp | 175 ++++++- keystore-engine/keyhandle.cpp | 16 + keystore-engine/methods.h | 34 ++ keystore-engine/rsa_meth.cpp | 38 +- keystore/IKeystoreService.cpp | 47 +- keystore/defaults.h | 42 ++ keystore/include/keystore/IKeystoreService.h | 16 +- keystore/keystore.cpp | 106 ++++- softkeymaster/keymaster_openssl.cpp | 473 +++++++++++++++---- 11 files changed, 960 insertions(+), 140 deletions(-) create mode 100644 keystore-engine/dsa_meth.cpp create mode 100644 keystore/defaults.h diff --git a/keystore-engine/Android.mk b/keystore-engine/Android.mk index cb1a4b01..b975629d 100644 --- a/keystore-engine/Android.mk +++ b/keystore-engine/Android.mk @@ -25,6 +25,7 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/ssl/engines LOCAL_SRC_FILES := \ eng_keystore.cpp \ keyhandle.cpp \ + dsa_meth.cpp \ rsa_meth.cpp LOCAL_CFLAGS := -fvisibility=hidden -Wall -Werror diff --git a/keystore-engine/dsa_meth.cpp b/keystore-engine/dsa_meth.cpp new file mode 100644 index 00000000..6adfa2dc --- /dev/null +++ b/keystore-engine/dsa_meth.cpp @@ -0,0 +1,152 @@ +/* + * Copyright 2013 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 + +//#define LOG_NDEBUG 0 +#define LOG_TAG "OpenSSL-keystore-dsa" +#include + +#include +#include + +#include +#include + +#include "methods.h" + + +using namespace android; + +struct DSA_SIG_Delete { + void operator()(DSA_SIG* p) const { + DSA_SIG_free(p); + } +}; +typedef UniquePtr Unique_DSA_SIG; + +static DSA_SIG* keystore_dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa) { + ALOGV("keystore_dsa_do_sign(%p, %d, %p)", dgst, dlen, dsa); + + uint8_t* key_id = reinterpret_cast(DSA_get_ex_data(dsa, dsa_key_handle)); + if (key_id == NULL) { + ALOGE("key had no key_id!"); + return 0; + } + + sp sm = defaultServiceManager(); + sp binder = sm->getService(String16("android.security.keystore")); + sp service = interface_cast(binder); + + if (service == NULL) { + ALOGE("could not contact keystore"); + return 0; + } + + int num = DSA_size(dsa); + + uint8_t* reply = NULL; + size_t replyLen; + int32_t ret = service->sign(String16(reinterpret_cast(key_id)), dgst, + dlen, &reply, &replyLen); + if (ret < 0) { + ALOGW("There was an error during dsa_do_sign: could not connect"); + return 0; + } else if (ret != 0) { + ALOGW("Error during sign from keystore: %d", ret); + return 0; + } else if (replyLen <= 0) { + ALOGW("No valid signature returned"); + return 0; + } else if (replyLen > (size_t) num) { + ALOGW("Signature is too large"); + return 0; + } + + Unique_DSA_SIG dsa_sig(d2i_DSA_SIG(NULL, + const_cast(reinterpret_cast(&reply)), + replyLen)); + if (dsa_sig.get() == NULL) { + ALOGW("conversion from DER to DSA_SIG failed"); + return 0; + } + + ALOGV("keystore_dsa_do_sign(%p, %d, %p) => returning %p len %llu", dgst, dlen, dsa, + dsa_sig.get(), replyLen); + return dsa_sig.release(); +} + +static DSA_METHOD keystore_dsa_meth = { + kKeystoreEngineId, /* name */ + keystore_dsa_do_sign, /* dsa_do_sign */ + NULL, /* dsa_sign_setup */ + NULL, /* dsa_do_verify */ + NULL, /* dsa_mod_exp */ + NULL, /* bn_mod_exp */ + NULL, /* init */ + NULL, /* finish */ + 0, /* flags */ + NULL, /* app_data */ + NULL, /* dsa_paramgen */ + NULL, /* dsa_keygen */ +}; + +static int register_dsa_methods() { + const DSA_METHOD* dsa_meth = DSA_OpenSSL(); + + keystore_dsa_meth.dsa_do_verify = dsa_meth->dsa_do_verify; + + return 1; +} + +int dsa_pkey_setup(ENGINE *e, EVP_PKEY *pkey, const char *key_id) { + Unique_DSA dsa(EVP_PKEY_get1_DSA(pkey)); + if (!DSA_set_ex_data(dsa.get(), dsa_key_handle, reinterpret_cast(strdup(key_id)))) { + ALOGW("Could not set ex_data for loaded DSA key"); + return 0; + } + + DSA_set_method(dsa.get(), &keystore_dsa_meth); + + /* + * "DSA_set_ENGINE()" should probably be an OpenSSL API. Since it isn't, + * and EVP_PKEY_free() calls ENGINE_finish(), we need to call ENGINE_init() + * here. + */ + ENGINE_init(e); + dsa->engine = e; + + return 1; +} + +int dsa_register(ENGINE* e) { + if (!ENGINE_set_DSA(e, &keystore_dsa_meth) + || !register_dsa_methods()) { + ALOGE("Could not set up keystore DSA methods"); + return 0; + } + + return 1; +} diff --git a/keystore-engine/eng_keystore.cpp b/keystore-engine/eng_keystore.cpp index 30cad7cb..9397e53b 100644 --- a/keystore-engine/eng_keystore.cpp +++ b/keystore-engine/eng_keystore.cpp @@ -30,9 +30,12 @@ #include #include -#include +#include #include +#include #include +#include +#include //#define LOG_NDEBUG 0 #define LOG_TAG "OpenSSL-keystore" @@ -50,6 +53,24 @@ using namespace android; const char* kKeystoreEngineId = "keystore"; static const char* kKeystoreEngineDesc = "Android keystore engine"; + +/* + * ex_data index for keystore's key alias. + */ +int rsa_key_handle; +int dsa_key_handle; + + +/* + * Only initialize the *_key_handle once. + */ +static pthread_once_t key_handle_control = PTHREAD_ONCE_INIT; + +/* + * Used for generic EVP_PKEY* handling (only for EC stuff currently) + */ +static EVP_PKEY_METHOD* keystore_pkey_ec_methods; + /** * 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, @@ -58,6 +79,7 @@ static const char* kKeystoreEngineDesc = "Android keystore engine"; #define OWNERSHIP_TRANSFERRED(obj) \ typeof (obj.release()) _dummy __attribute__((unused)) = obj.release() + struct ENGINE_Delete { void operator()(ENGINE* p) const { ENGINE_free(p); @@ -72,6 +94,41 @@ struct EVP_PKEY_Delete { }; typedef UniquePtr Unique_EVP_PKEY; +/** + * Called to initialize RSA's ex_data for the key_id handle. This should + * only be called when protected by a lock. + */ +static void init_key_handle() { + rsa_key_handle = RSA_get_ex_new_index(0, NULL, keyhandle_new, keyhandle_dup, keyhandle_free); + dsa_key_handle = DSA_get_ex_new_index(0, NULL, keyhandle_new, keyhandle_dup, keyhandle_free); +} + +static int pkey_setup(ENGINE *e, EVP_PKEY *pkey, const char *key_id) { + int ret = 1; + switch (EVP_PKEY_type(pkey->type)) { + case EVP_PKEY_EC: { + Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey)); + void* oldData = EC_KEY_insert_key_method_data(eckey.get(), + reinterpret_cast(strdup(key_id)), ex_data_dup, ex_data_free, + ex_data_clear_free); + if (oldData != NULL) { + free(oldData); + } + } break; + default: + ALOGW("Unsupported key type during setup %d", EVP_PKEY_type(pkey->type)); + return 0; + } + + if (ret != 1) { + return ret; + } + + ENGINE_init(e); + pkey->engine = e; + + return 1; +} static EVP_PKEY* keystore_loadkey(ENGINE* e, const char* key_id, UI_METHOD* ui_method, void* callback_data) { @@ -113,10 +170,18 @@ static EVP_PKEY* keystore_loadkey(ENGINE* e, const char* key_id, UI_METHOD* ui_m } switch (EVP_PKEY_type(pkey->type)) { + case EVP_PKEY_DSA: { + dsa_pkey_setup(e, pkey.get(), key_id); + break; + } case EVP_PKEY_RSA: { rsa_pkey_setup(e, pkey.get(), key_id); break; } + case EVP_PKEY_EC: { + pkey_setup(e, pkey.get(), key_id); + break; + } default: ALOGE("Unsupported key type %d", EVP_PKEY_type(pkey->type)); return NULL; @@ -129,11 +194,107 @@ static const ENGINE_CMD_DEFN keystore_cmd_defns[] = { {0, NULL, NULL, 0} }; +static uint8_t* get_key_id(EVP_PKEY* pkey) { + switch (EVP_PKEY_type(pkey->type)) { + case EVP_PKEY_EC: { + Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey)); + return reinterpret_cast(EC_KEY_get_key_method_data(eckey.get(), + ex_data_dup, ex_data_free, ex_data_clear_free)); + } break; + } + + return NULL; +} + +static int keystore_pkey_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbs_len) { + EVP_PKEY* pkey = EVP_PKEY_CTX_get0_pkey(ctx); + + const uint8_t* key_id = get_key_id(pkey); + if (key_id == NULL) { + ALOGW("key_id is empty"); + return 0; + } + + sp sm = defaultServiceManager(); + sp binder = sm->getService(String16("android.security.keystore")); + sp service = interface_cast(binder); + + if (service == NULL) { + ALOGE("could not contact keystore"); + return 0; + } + + uint8_t* reply = NULL; + size_t replyLen; + int32_t ret = service->sign(String16(reinterpret_cast(key_id)), tbs, tbs_len, + &reply, &replyLen); + if (ret < 0) { + ALOGW("There was an error during signing: could not connect"); + free(reply); + return 0; + } else if (ret != 0) { + ALOGW("Error during signing from keystore: %d", ret); + free(reply); + return 0; + } else if (replyLen <= 0) { + ALOGW("No valid signature returned"); + return 0; + } + + memcpy(sig, reply, replyLen); + free(reply); + *siglen = replyLen; + + return 1; +} + +static int register_pkey_methods(EVP_PKEY_METHOD** meth, int nid) { + *meth = EVP_PKEY_meth_new(nid, 0); + if (*meth == NULL) { + ALOGE("Failure allocating PKEY methods for NID %d", nid); + return 0; + } + + const EVP_PKEY_METHOD* orig = EVP_PKEY_meth_find(nid); + EVP_PKEY_meth_copy(*meth, orig); + + EVP_PKEY_meth_set_sign(*meth, NULL, keystore_pkey_sign); + + return 1; +} + +static int keystore_nids[] = { + EVP_PKEY_EC, +}; + +static int keystore_pkey_meths(ENGINE*, EVP_PKEY_METHOD** meth, const int **nids, int nid) { + if (meth == NULL) { + *nids = keystore_nids; + return sizeof(keystore_nids) / sizeof(keystore_nids[0]); + } + + switch (nid) { + case EVP_PKEY_EC: + *meth = keystore_pkey_ec_methods; + return 1; + } + + *meth = NULL; + return 0; +} + static int keystore_engine_setup(ENGINE* e) { ALOGV("keystore_engine_setup"); + if (!register_pkey_methods(&keystore_pkey_ec_methods, EVP_PKEY_EC)) { + ALOGE("Could not set up keystore engine"); + return 0; + } + if (!ENGINE_set_id(e, kKeystoreEngineId) || !ENGINE_set_name(e, kKeystoreEngineDesc) + || !ENGINE_set_pkey_meths(e, keystore_pkey_meths) || !ENGINE_set_load_privkey_function(e, keystore_loadkey) || !ENGINE_set_load_pubkey_function(e, keystore_loadkey) || !ENGINE_set_flags(e, 0) @@ -142,7 +303,17 @@ static int keystore_engine_setup(ENGINE* e) { return 0; } - if (!rsa_register(e)) { + /* We need a handle in the keys types as well for keygen if it's not already initialized. */ + pthread_once(&key_handle_control, init_key_handle); + if ((rsa_key_handle < 0) || (dsa_key_handle < 0)) { + ALOGE("Could not set up ex_data index"); + return 0; + } + + if (!dsa_register(e)) { + ALOGE("DSA registration failed"); + return 0; + } else if (!rsa_register(e)) { ALOGE("RSA registration failed"); return 0; } diff --git a/keystore-engine/keyhandle.cpp b/keystore-engine/keyhandle.cpp index 786934b1..17997351 100644 --- a/keystore-engine/keyhandle.cpp +++ b/keystore-engine/keyhandle.cpp @@ -58,3 +58,19 @@ int keyhandle_dup(CRYPTO_EX_DATA* to, CRYPTO_EX_DATA*, void *ptrRef, int idx, lo } return 1; } + +void *ex_data_dup(void *data) { + char* keyhandle = reinterpret_cast(data); + return strdup(keyhandle); +} + +void ex_data_free(void *data) { + char* keyhandle = reinterpret_cast(data); + free(keyhandle); +} + +void ex_data_clear_free(void *data) { + char* keyhandle = reinterpret_cast(data); + memset(data, '\0', strlen(keyhandle)); + free(keyhandle); +} diff --git a/keystore-engine/methods.h b/keystore-engine/methods.h index 16a7ba8f..8535ac99 100644 --- a/keystore-engine/methods.h +++ b/keystore-engine/methods.h @@ -26,11 +26,45 @@ /* For ENGINE method registration purposes. */ extern const char* kKeystoreEngineId; +extern int dsa_key_handle; +extern int rsa_key_handle; + +struct DSA_Delete { + void operator()(DSA* p) const { + DSA_free(p); + } +}; +typedef UniquePtr Unique_DSA; + +struct EC_KEY_Delete { + void operator()(EC_KEY* p) const { + EC_KEY_free(p); + } +}; +typedef UniquePtr Unique_EC_KEY; + +struct RSA_Delete { + void operator()(RSA* p) const { + RSA_free(p); + } +}; +typedef UniquePtr Unique_RSA; + + /* Keyhandles for ENGINE metadata */ int keyhandle_new(void*, void*, CRYPTO_EX_DATA* ad, int idx, long, void*); void keyhandle_free(void *, void *ptr, CRYPTO_EX_DATA*, int, long, void*); int keyhandle_dup(CRYPTO_EX_DATA* to, CRYPTO_EX_DATA*, void *ptrRef, int idx, long, void *); +/* For EC_EX_DATA stuff */ +void *ex_data_dup(void *); +void ex_data_free(void *); +void ex_data_clear_free(void *); + +/* DSA */ +int dsa_register(ENGINE *); +int dsa_pkey_setup(ENGINE *, EVP_PKEY*, const char*); + /* RSA */ int rsa_register(ENGINE *); int rsa_pkey_setup(ENGINE *, EVP_PKEY*, const char*); diff --git a/keystore-engine/rsa_meth.cpp b/keystore-engine/rsa_meth.cpp index c1d643ce..b949fa41 100644 --- a/keystore-engine/rsa_meth.cpp +++ b/keystore-engine/rsa_meth.cpp @@ -38,34 +38,8 @@ #include "methods.h" -/* - * RSA ex_data index for keystore's key handle. - */ -static int rsa_key_handle; - -/* - * Only initialize the rsa_key_handle once. - */ -static pthread_once_t rsa_key_handle_control = PTHREAD_ONCE_INIT; - -struct RSA_Delete { - void operator()(RSA* p) const { - RSA_free(p); - } -}; -typedef UniquePtr Unique_RSA; - - using namespace android; -/** - * Called to initialize RSA's ex_data for the key_id handle. This should - * only be called when protected by a lock. - */ -static void init_rsa_key_handle() { - rsa_key_handle = RSA_get_ex_new_index(0, NULL, keyhandle_new, keyhandle_dup, - keyhandle_free); -} int keystore_rsa_priv_enc(int flen, const unsigned char* from, unsigned char* to, RSA* rsa, int padding) { @@ -246,8 +220,9 @@ int rsa_pkey_setup(ENGINE *e, EVP_PKEY *pkey, const char *key_id) { 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. + * "RSA_set_ENGINE()" should probably be an OpenSSL API. Since it isn't, + * and EVP_PKEY_free() calls ENGINE_finish(), we need to call ENGINE_init() + * here. */ ENGINE_init(e); rsa->engine = e; @@ -263,12 +238,5 @@ int rsa_register(ENGINE* e) { return 0; } - /* We need a handle in the RSA keys as well for keygen if it's not already initialized. */ - pthread_once(&rsa_key_handle_control, init_rsa_key_handle); - if (rsa_key_handle < 0) { - ALOGE("Could not set up RSA ex_data index"); - return 0; - } - return 1; } diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp index 46f7244a..21dce27e 100644 --- a/keystore/IKeystoreService.cpp +++ b/keystore/IKeystoreService.cpp @@ -29,6 +29,21 @@ namespace android { +KeystoreArg::KeystoreArg(const void* data, size_t len) + : mData(data), mSize(len) { +} + +KeystoreArg::~KeystoreArg() { +} + +const void *KeystoreArg::data() const { + return mData; +} + +size_t KeystoreArg::size() const { + return mSize; +} + class BpKeystoreService: public BpInterface { public: @@ -270,13 +285,24 @@ public: return ret; } - virtual int32_t generate(const String16& name, int uid, int32_t flags) + virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize, + int32_t flags, Vector >* args) { Parcel data, reply; data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); data.writeString16(name); data.writeInt32(uid); + data.writeInt32(keyType); + data.writeInt32(keySize); data.writeInt32(flags); + data.writeInt32(args->size()); + for (Vector >::iterator it = args->begin(); it != args->end(); ++it) { + sp item = *it; + size_t keyLength = item->size(); + data.writeInt32(keyLength); + void* buf = data.writeInplace(keyLength); + memcpy(buf, item->data(), keyLength); + } status_t status = remote()->transact(BnKeystoreService::GENERATE, data, &reply); if (status != NO_ERROR) { ALOGD("generate() could not contact remote: %d\n", status); @@ -677,9 +703,24 @@ status_t BnKeystoreService::onTransact( case GENERATE: { CHECK_INTERFACE(IKeystoreService, data, reply); String16 name = data.readString16(); - int uid = data.readInt32(); + int32_t uid = data.readInt32(); + int32_t keyType = data.readInt32(); + int32_t keySize = data.readInt32(); int32_t flags = data.readInt32(); - int32_t ret = generate(name, uid, flags); + Vector > 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 arg = new KeystoreArg(data.readInplace(inSize), inSize); + args.push_back(arg); + } else { + args.push_back(NULL); + } + } + } + int32_t ret = generate(name, uid, keyType, keySize, flags, &args); reply->writeNoException(); reply->writeInt32(ret); return NO_ERROR; diff --git a/keystore/defaults.h b/keystore/defaults.h new file mode 100644 index 00000000..9232dd0a --- /dev/null +++ b/keystore/defaults.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 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_DEFAULTS_H_ +#define KEYSTORE_DEFAULTS_H_ + +/* + * These must be kept in sync with + * frameworks/base/keystore/java/android/security/KeyPairGeneratorSpec.java + */ + +/* DSA */ +#define DSA_DEFAULT_KEY_SIZE 1024 +#define DSA_MIN_KEY_SIZE 512 +#define DSA_MAX_KEY_SIZE 8192 + +/* EC */ +#define EC_DEFAULT_KEY_SIZE 256 +#define EC_MIN_KEY_SIZE 192 +#define EC_MAX_KEY_SIZE 521 + +/* RSA */ +#define RSA_DEFAULT_KEY_SIZE 2048 +#define RSA_DEFAULT_EXPONENT 0x10001 +#define RSA_MIN_KEY_SIZE 512 +#define RSA_MAX_KEY_SIZE 8192 + +#endif /* KEYSTORE_DEFAULTS_H_ */ diff --git a/keystore/include/keystore/IKeystoreService.h b/keystore/include/keystore/IKeystoreService.h index 9b54454c..7c508a84 100644 --- a/keystore/include/keystore/IKeystoreService.h +++ b/keystore/include/keystore/IKeystoreService.h @@ -23,6 +23,19 @@ namespace android { +class KeystoreArg : public RefBase { +public: + KeystoreArg(const void *data, size_t len); + ~KeystoreArg(); + + const void* data() const; + size_t size() const; + +private: + const void* mData; + size_t mSize; +}; + /* * This must be kept manually in sync with frameworks/base's IKeystoreService.java */ @@ -79,7 +92,8 @@ public: virtual int32_t zero() = 0; - virtual int32_t generate(const String16& name, int uid, int32_t flags) = 0; + virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize, + int32_t flags, Vector >* args) = 0; virtual int32_t import(const String16& name, const uint8_t* data, size_t length, int uid, int32_t flags) = 0; diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp index 2859caf7..12d3b44a 100644 --- a/keystore/keystore.cpp +++ b/keystore/keystore.cpp @@ -56,6 +56,8 @@ #include +#include "defaults.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 * values are encrypted with checksums. The encryption key is protected by a @@ -67,6 +69,13 @@ #define PASSWORD_SIZE VALUE_SIZE +struct BIGNUM_Delete { + void operator()(BIGNUM* p) const { + BN_free(p); + } +}; +typedef UniquePtr Unique_BIGNUM; + struct BIO_Delete { void operator()(BIO* p) const { BIO_free(p); @@ -1656,7 +1665,8 @@ public: return mKeyStore->isEmpty(callingUid) ? ::KEY_NOT_FOUND : ::NO_ERROR; } - int32_t generate(const String16& name, int targetUid, int32_t flags) { + int32_t generate(const String16& name, int32_t targetUid, int32_t keyType, int32_t keySize, + int32_t flags, Vector >* args) { uid_t callingUid = IPCThreadState::self()->getCallingUid(); if (!has_permission(callingUid, P_INSERT)) { ALOGW("permission denied for %d: generate", callingUid); @@ -1688,11 +1698,97 @@ public: return ::SYSTEM_ERROR; } - keymaster_rsa_keygen_params_t rsa_params; - rsa_params.modulus_size = 2048; - rsa_params.public_exponent = 0x10001; + if (keyType == EVP_PKEY_DSA && device->client_version >= 2) { + keymaster_dsa_keygen_params_t dsa_params; + memset(&dsa_params, '\0', sizeof(dsa_params)); + + if (keySize == -1) { + keySize = DSA_DEFAULT_KEY_SIZE; + } else if ((keySize % 64) != 0 || keySize < DSA_MIN_KEY_SIZE + || keySize > DSA_MAX_KEY_SIZE) { + ALOGI("invalid key size %d", keySize); + return ::SYSTEM_ERROR; + } + dsa_params.key_size = keySize; + + if (args->size() == 3) { + sp gArg = args->itemAt(0); + sp pArg = args->itemAt(1); + sp qArg = args->itemAt(2); + + if (gArg != NULL && pArg != NULL && qArg != NULL) { + dsa_params.generator = reinterpret_cast(gArg->data()); + dsa_params.generator_len = gArg->size(); + + dsa_params.prime_p = reinterpret_cast(pArg->data()); + dsa_params.prime_p_len = pArg->size(); + + dsa_params.prime_q = reinterpret_cast(qArg->data()); + dsa_params.prime_q_len = qArg->size(); + } else { + ALOGI("not all DSA parameters were read"); + return ::SYSTEM_ERROR; + } + } else if (args->size() != 0) { + ALOGI("DSA args must be 3"); + return ::SYSTEM_ERROR; + } + + rc = device->generate_keypair(device, TYPE_DSA, &dsa_params, &data, &dataLength); + } else if (keyType == EVP_PKEY_EC && device->client_version >= 2) { + keymaster_ec_keygen_params_t ec_params; + memset(&ec_params, '\0', sizeof(ec_params)); + + if (keySize == -1) { + keySize = EC_DEFAULT_KEY_SIZE; + } else if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) { + ALOGI("invalid key size %d", keySize); + return ::SYSTEM_ERROR; + } + ec_params.field_size = keySize; + + rc = device->generate_keypair(device, TYPE_EC, &ec_params, &data, &dataLength); + } else if (keyType == EVP_PKEY_RSA) { + keymaster_rsa_keygen_params_t rsa_params; + memset(&rsa_params, '\0', sizeof(rsa_params)); + rsa_params.public_exponent = RSA_DEFAULT_EXPONENT; + + if (keySize == -1) { + keySize = RSA_DEFAULT_KEY_SIZE; + } else if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) { + ALOGI("invalid key size %d", keySize); + return ::SYSTEM_ERROR; + } + rsa_params.modulus_size = keySize; + + if (args->size() > 1) { + ALOGI("invalid number of arguments: %d", args->size()); + return ::SYSTEM_ERROR; + } else if (args->size() == 1) { + sp pubExpBlob = args->itemAt(0); + if (pubExpBlob != NULL) { + Unique_BIGNUM pubExpBn( + BN_bin2bn(reinterpret_cast(pubExpBlob->data()), + pubExpBlob->size(), NULL)); + if (pubExpBn.get() == NULL) { + ALOGI("Could not convert public exponent to BN"); + return ::SYSTEM_ERROR; + } + unsigned long pubExp = BN_get_word(pubExpBn.get()); + if (pubExp == 0xFFFFFFFFL) { + ALOGI("cannot represent public exponent as a long value"); + return ::SYSTEM_ERROR; + } + rsa_params.public_exponent = pubExp; + } + } + + rc = device->generate_keypair(device, TYPE_RSA, &rsa_params, &data, &dataLength); + } else { + ALOGW("Unsupported key type %d", keyType); + rc = -1; + } - rc = device->generate_keypair(device, TYPE_RSA, &rsa_params, &data, &dataLength); if (rc) { return ::SYSTEM_ERROR; } diff --git a/softkeymaster/keymaster_openssl.cpp b/softkeymaster/keymaster_openssl.cpp index 36204505..19ec9993 100644 --- a/softkeymaster/keymaster_openssl.cpp +++ b/softkeymaster/keymaster_openssl.cpp @@ -57,6 +57,20 @@ struct PKCS8_PRIV_KEY_INFO_Delete { }; typedef UniquePtr Unique_PKCS8_PRIV_KEY_INFO; +struct DSA_Delete { + void operator()(DSA* p) const { + DSA_free(p); + } +}; +typedef UniquePtr Unique_DSA; + +struct EC_KEY_Delete { + void operator()(EC_KEY* p) const { + EC_KEY_free(p); + } +}; +typedef UniquePtr Unique_EC_KEY; + struct RSA_Delete { void operator()(RSA* p) const { RSA_free(p); @@ -93,12 +107,15 @@ static void logOpenSSLError(const char* location) { } 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); + /* + * Find the length of each size. Public key is not needed anymore but must be kept for + * alignment purposes. + */ + int publicLen = 0; int privateLen = i2d_PrivateKey(pkey, NULL); - if (privateLen <= 0 || publicLen <= 0) { - ALOGE("private or public key size was too big"); + if (privateLen <= 0) { + ALOGE("private key size was too big"); return -1; } @@ -106,7 +123,7 @@ static int wrap_key(EVP_PKEY* pkey, int type, uint8_t** keyBlob, size_t* keyBlob *keyBlobLength = get_softkey_header_size() + sizeof(int) + sizeof(int) + privateLen + sizeof(int) + publicLen; - UniquePtr derData(new unsigned char[*keyBlobLength]); + UniquePtr derData(new unsigned char[*keyBlobLength]); if (derData.get() == NULL) { ALOGE("could not allocate memory for key blob"); return -1; @@ -125,10 +142,6 @@ static int wrap_key(EVP_PKEY* pkey, int type, uint8_t** keyBlob, size_t* keyBlob 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--) { @@ -174,12 +187,6 @@ static EVP_PKEY* unwrap_key(const uint8_t* keyBlob, const size_t keyBlobLength) 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++; } @@ -187,9 +194,9 @@ static EVP_PKEY* unwrap_key(const uint8_t* keyBlob, const size_t keyBlobLength) 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); + const uint8_t *pubKey = p; + p += publicLen; if (end - p < 2) { ALOGE("private key truncated"); return NULL; @@ -201,64 +208,208 @@ static EVP_PKEY* unwrap_key(const uint8_t* keyBlob, const size_t keyBlobLength) ALOGE("private key length encoding error: size=%ld, end=%d", privateLen, end - p); return NULL; } - d2i_PrivateKey(type, &tmp, &p, privateLen); + + Unique_EVP_PKEY pkey(EVP_PKEY_new()); + if (pkey.get() == NULL) { + logOpenSSLError("unwrap_key"); + return NULL; + } + EVP_PKEY* tmp = pkey.get(); + + if (d2i_PrivateKey(type, &tmp, &p, privateLen) == NULL) { + logOpenSSLError("unwrap_key"); + return NULL; + } return pkey.release(); } +static int generate_dsa_keypair(EVP_PKEY* pkey, const keymaster_dsa_keygen_params_t* dsa_params) +{ + if (dsa_params->key_size < 512) { + ALOGI("Requested DSA key size is too small (<512)"); + return -1; + } + + Unique_DSA dsa(DSA_new()); + + if (dsa_params->generator_len == 0 || + dsa_params->prime_p_len == 0 || + dsa_params->prime_q_len == 0 || + dsa_params->generator == NULL|| + dsa_params->prime_p == NULL || + dsa_params->prime_q == NULL) { + if (DSA_generate_parameters_ex(dsa.get(), dsa_params->key_size, NULL, 0, NULL, NULL, + NULL) != 1) { + logOpenSSLError("generate_dsa_keypair"); + return -1; + } + } else { + dsa->g = BN_bin2bn(dsa_params->generator, + dsa_params->generator_len, + NULL); + if (dsa->g == NULL) { + logOpenSSLError("generate_dsa_keypair"); + return -1; + } + + dsa->p = BN_bin2bn(dsa_params->prime_p, + dsa_params->prime_p_len, + NULL); + if (dsa->p == NULL) { + logOpenSSLError("generate_dsa_keypair"); + return -1; + } + + dsa->q = BN_bin2bn(dsa_params->prime_q, + dsa_params->prime_q_len, + NULL); + if (dsa->q == NULL) { + logOpenSSLError("generate_dsa_keypair"); + return -1; + } + } + + if (DSA_generate_key(dsa.get()) != 1) { + logOpenSSLError("generate_dsa_keypair"); + return -1; + } + + if (EVP_PKEY_assign_DSA(pkey, dsa.get()) == 0) { + logOpenSSLError("generate_dsa_keypair"); + return -1; + } + OWNERSHIP_TRANSFERRED(dsa); + + return 0; +} + +static int generate_ec_keypair(EVP_PKEY* pkey, const keymaster_ec_keygen_params_t* ec_params) +{ + EC_GROUP* group; + switch (ec_params->field_size) { + case 192: + group = EC_GROUP_new_by_curve_name(NID_X9_62_prime192v1); + break; + case 224: + group = EC_GROUP_new_by_curve_name(NID_secp224r1); + break; + case 256: + group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + break; + case 384: + group = EC_GROUP_new_by_curve_name(NID_secp384r1); + break; + case 521: + group = EC_GROUP_new_by_curve_name(NID_secp521r1); + break; + default: + group = NULL; + break; + } + + if (group == NULL) { + logOpenSSLError("generate_ec_keypair"); + return -1; + } + + EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED); + EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); + + /* initialize EC key */ + Unique_EC_KEY eckey(EC_KEY_new()); + if (eckey.get() == NULL) { + logOpenSSLError("generate_ec_keypair"); + return -1; + } + + if (EC_KEY_set_group(eckey.get(), group) != 1) { + logOpenSSLError("generate_ec_keypair"); + return -1; + } + + if (EC_KEY_generate_key(eckey.get()) != 1 + || EC_KEY_check_key(eckey.get()) < 0) { + logOpenSSLError("generate_ec_keypair"); + return -1; + } + + if (EVP_PKEY_assign_EC_KEY(pkey, eckey.get()) == 0) { + logOpenSSLError("generate_ec_keypair"); + return -1; + } + OWNERSHIP_TRANSFERRED(eckey); + + return 0; +} + +static int generate_rsa_keypair(EVP_PKEY* pkey, const keymaster_rsa_keygen_params_t* rsa_params) +{ + Unique_BIGNUM bn(BN_new()); + if (bn.get() == NULL) { + logOpenSSLError("generate_rsa_keypair"); + return -1; + } + + if (BN_set_word(bn.get(), rsa_params->public_exponent) == 0) { + logOpenSSLError("generate_rsa_keypair"); + return -1; + } + + /* initialize RSA */ + Unique_RSA rsa(RSA_new()); + if (rsa.get() == NULL) { + logOpenSSLError("generate_rsa_keypair"); + return -1; + } + + if (!RSA_generate_key_ex(rsa.get(), rsa_params->modulus_size, bn.get(), NULL) + || RSA_check_key(rsa.get()) < 0) { + logOpenSSLError("generate_rsa_keypair"); + return -1; + } + + if (EVP_PKEY_assign_RSA(pkey, rsa.get()) == 0) { + logOpenSSLError("generate_rsa_keypair"); + return -1; + } + OWNERSHIP_TRANSFERRED(rsa); + + return 0; +} + 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"); + if (key_params == NULL) { + ALOGW("key_params == null"); + return -1; + } else if (key_type == TYPE_DSA) { + const keymaster_dsa_keygen_params_t* dsa_params = + (const keymaster_dsa_keygen_params_t*) key_params; + generate_dsa_keypair(pkey.get(), dsa_params); + } else if (key_type == TYPE_EC) { + const keymaster_ec_keygen_params_t* ec_params = + (const keymaster_ec_keygen_params_t*) key_params; + generate_ec_keypair(pkey.get(), ec_params); + } else if (key_type == TYPE_RSA) { + const keymaster_rsa_keygen_params_t* rsa_params = + (const keymaster_rsa_keygen_params_t*) key_params; + generate_rsa_keypair(pkey.get(), rsa_params); + } else { + ALOGW("Unsupported key type %d", key_type); return -1; } - OWNERSHIP_TRANSFERRED(rsa); - if (wrap_key(pkey.get(), EVP_PKEY_RSA, keyBlob, keyBlobLength)) { + if (wrap_key(pkey.get(), EVP_PKEY_type(pkey->type), keyBlob, keyBlobLength)) { return -1; } @@ -338,6 +489,105 @@ static int openssl_get_keypair_public(const struct keymaster_device* dev, return 0; } +static int sign_dsa(EVP_PKEY* pkey, keymaster_dsa_sign_params_t* sign_params, const uint8_t* data, + const size_t dataLength, uint8_t** signedData, size_t* signedDataLength) { + if (sign_params->digest_type != DIGEST_NONE) { + ALOGW("Cannot handle digest type %d", sign_params->digest_type); + return -1; + } + + Unique_DSA dsa(EVP_PKEY_get1_DSA(pkey)); + if (dsa.get() == NULL) { + logOpenSSLError("openssl_sign_dsa"); + return -1; + } + + unsigned int dsaSize = DSA_size(dsa.get()); + UniquePtr signedDataPtr(reinterpret_cast(malloc(dsaSize))); + if (signedDataPtr.get() == NULL) { + logOpenSSLError("openssl_sign_dsa"); + return -1; + } + + unsigned char* tmp = reinterpret_cast(signedDataPtr.get()); + if (DSA_sign(0, data, dataLength, tmp, &dsaSize, dsa.get()) <= 0) { + logOpenSSLError("openssl_sign_dsa"); + return -1; + } + + *signedDataLength = dsaSize; + *signedData = signedDataPtr.release(); + + return 0; +} + +static int sign_ec(EVP_PKEY* pkey, keymaster_ec_sign_params_t* sign_params, const uint8_t* data, + const size_t dataLength, uint8_t** signedData, size_t* signedDataLength) { + if (sign_params->digest_type != DIGEST_NONE) { + ALOGW("Cannot handle digest type %d", sign_params->digest_type); + return -1; + } + + Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey)); + if (eckey.get() == NULL) { + logOpenSSLError("openssl_sign_ec"); + return -1; + } + + unsigned int ecdsaSize = ECDSA_size(eckey.get()); + UniquePtr signedDataPtr(reinterpret_cast(malloc(ecdsaSize))); + if (signedDataPtr.get() == NULL) { + logOpenSSLError("openssl_sign_ec"); + return -1; + } + + unsigned char* tmp = reinterpret_cast(signedDataPtr.get()); + if (ECDSA_sign(0, data, dataLength, tmp, &ecdsaSize, eckey.get()) <= 0) { + logOpenSSLError("openssl_sign_ec"); + return -1; + } + + *signedDataLength = ecdsaSize; + *signedData = signedDataPtr.release(); + + return 0; +} + + +static int sign_rsa(EVP_PKEY* pkey, keymaster_rsa_sign_params_t* sign_params, const uint8_t* data, + const size_t dataLength, uint8_t** signedData, size_t* signedDataLength) { + 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)); + if (rsa.get() == NULL) { + logOpenSSLError("openssl_sign_rsa"); + return -1; + } + + UniquePtr signedDataPtr(reinterpret_cast(malloc(dataLength))); + if (signedDataPtr.get() == NULL) { + logOpenSSLError("openssl_sign_rsa"); + return -1; + } + + unsigned char* tmp = reinterpret_cast(signedDataPtr.get()); + if (RSA_private_encrypt(dataLength, data, tmp, rsa.get(), RSA_NO_PADDING) <= 0) { + logOpenSSLError("openssl_sign_rsa"); + return -1; + } + + *signedDataLength = dataLength; + *signedData = signedDataPtr.release(); + + return 0; +} + static int openssl_sign_data(const keymaster_device_t* dev, const void* params, const uint8_t* keyBlob, const size_t keyBlobLength, @@ -361,65 +611,69 @@ static int openssl_sign_data(const keymaster_device_t* dev, return -1; } - if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) { - ALOGW("Cannot handle non-RSA keys yet"); + int type = EVP_PKEY_type(pkey->type); + if (type == EVP_PKEY_DSA) { + keymaster_dsa_sign_params_t* sign_params = (keymaster_dsa_sign_params_t*) params; + return sign_dsa(pkey.get(), sign_params, data, dataLength, signedData, signedDataLength); + } else if (type == EVP_PKEY_EC) { + keymaster_ec_sign_params_t* sign_params = (keymaster_ec_sign_params_t*) params; + return sign_ec(pkey.get(), sign_params, data, dataLength, signedData, signedDataLength); + } else if (type == EVP_PKEY_RSA) { + keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params; + return sign_rsa(pkey.get(), sign_params, data, dataLength, signedData, signedDataLength); + } else { + ALOGW("Unsupported key type"); return -1; } +} - keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params; +static int verify_dsa(EVP_PKEY* pkey, keymaster_dsa_sign_params_t* sign_params, + const uint8_t* signedData, const size_t signedDataLength, const uint8_t* signature, + const size_t signatureLength) { 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); + } + + Unique_DSA dsa(EVP_PKEY_get1_DSA(pkey)); + if (dsa.get() == NULL) { + logOpenSSLError("openssl_verify_dsa"); return -1; } - Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey.get())); - if (rsa.get() == NULL) { - logOpenSSLError("openssl_sign_data"); + if (DSA_verify(0, signedData, signedDataLength, signature, signatureLength, dsa.get()) <= 0) { + logOpenSSLError("openssl_verify_dsa"); return -1; } - UniquePtr signedDataPtr(reinterpret_cast(malloc(dataLength))); - if (signedDataPtr.get() == NULL) { - logOpenSSLError("openssl_sign_data"); - return -1; - } - - unsigned char* tmp = reinterpret_cast(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"); +static int verify_ec(EVP_PKEY* pkey, keymaster_ec_sign_params_t* sign_params, + const uint8_t* signedData, const size_t signedDataLength, const uint8_t* signature, + const size_t signatureLength) { + if (sign_params->digest_type != DIGEST_NONE) { + ALOGW("Cannot handle digest type %d", sign_params->digest_type); return -1; } - Unique_EVP_PKEY pkey(unwrap_key(keyBlob, keyBlobLength)); - if (pkey.get() == NULL) { + Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey)); + if (eckey.get() == NULL) { + logOpenSSLError("openssl_verify_ec"); return -1; } - if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) { - ALOGW("Cannot handle non-RSA keys yet"); + if (ECDSA_verify(0, signedData, signedDataLength, signature, signatureLength, eckey.get()) <= 0) { + logOpenSSLError("openssl_verify_ec"); return -1; } - keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params; + return 0; +} + +static int verify_rsa(EVP_PKEY* pkey, keymaster_rsa_sign_params_t* sign_params, + const uint8_t* signedData, const size_t signedDataLength, const uint8_t* signature, + const size_t signatureLength) { if (sign_params->digest_type != DIGEST_NONE) { ALOGW("Cannot handle digest type %d", sign_params->digest_type); return -1; @@ -431,7 +685,7 @@ static int openssl_verify_data(const keymaster_device_t* dev, return -1; } - Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey.get())); + Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey)); if (rsa.get() == NULL) { logOpenSSLError("openssl_verify_data"); return -1; @@ -457,9 +711,40 @@ static int openssl_verify_data(const keymaster_device_t* dev, return result == 0 ? 0 : -1; } +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; + } + + int type = EVP_PKEY_type(pkey->type); + if (type == EVP_PKEY_RSA) { + keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params; + return verify_rsa(pkey.get(), sign_params, signedData, signedDataLength, signature, + signatureLength); + } else if (type == EVP_PKEY_EC) { + keymaster_ec_sign_params_t* sign_params = (keymaster_ec_sign_params_t*) params; + return verify_ec(pkey.get(), sign_params, signedData, signedDataLength, signature, + signatureLength); + } else { + ALOGW("Unsupported key type %d", type); + return -1; + } +} + /* Close an opened OpenSSL instance */ static int openssl_close(hw_device_t *dev) { - free(dev); + delete dev; return 0; }