1/* 2 * Copyright 2013 The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 */ 25 26#include <utils/UniquePtr.h> 27 28//#define LOG_NDEBUG 0 29#define LOG_TAG "OpenSSL-keystore-ecdsa" 30#include <cutils/log.h> 31 32#include <binder/IServiceManager.h> 33#include <keystore/IKeystoreService.h> 34 35#include <openssl/ecdsa.h> 36#include <openssl/engine.h> 37 38// TODO replace this with real OpenSSL API when it exists 39#include "crypto/ec/ec_lcl.h" 40#include "crypto/ecdsa/ecs_locl.h" 41 42#include "methods.h" 43 44 45using namespace android; 46 47struct ECDSA_SIG_Delete { 48 void operator()(ECDSA_SIG* p) const { 49 ECDSA_SIG_free(p); 50 } 51}; 52typedef UniquePtr<ECDSA_SIG, struct ECDSA_SIG_Delete> Unique_ECDSA_SIG; 53 54static ECDSA_SIG* keystore_ecdsa_do_sign(const unsigned char *dgst, int dlen, 55 const BIGNUM*, const BIGNUM*, EC_KEY *eckey) { 56 ALOGV("keystore_ecdsa_do_sign(%p, %d, %p)", dgst, dlen, eckey); 57 58 uint8_t* key_id = reinterpret_cast<uint8_t*>(EC_KEY_get_key_method_data(eckey, 59 ex_data_dup, ex_data_free, ex_data_clear_free)); 60 if (key_id == NULL) { 61 ALOGE("key had no key_id!"); 62 return 0; 63 } 64 65 sp<IServiceManager> sm = defaultServiceManager(); 66 sp<IBinder> binder = sm->getService(String16("android.security.keystore")); 67 sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder); 68 69 if (service == NULL) { 70 ALOGE("could not contact keystore"); 71 return 0; 72 } 73 74 int num = ECDSA_size(eckey); 75 76 uint8_t* reply = NULL; 77 size_t replyLen; 78 int32_t ret = service->sign(String16(reinterpret_cast<const char*>(key_id)), dgst, 79 dlen, &reply, &replyLen); 80 if (ret < 0) { 81 ALOGW("There was an error during dsa_do_sign: could not connect"); 82 return 0; 83 } else if (ret != 0) { 84 ALOGW("Error during sign from keystore: %d", ret); 85 return 0; 86 } else if (replyLen <= 0) { 87 ALOGW("No valid signature returned"); 88 return 0; 89 } else if (replyLen > (size_t) num) { 90 ALOGW("Signature is too large"); 91 return 0; 92 } 93 94 Unique_ECDSA_SIG ecdsa_sig(d2i_ECDSA_SIG(NULL, 95 const_cast<const unsigned char**>(reinterpret_cast<unsigned char**>(&reply)), 96 replyLen)); 97 if (ecdsa_sig.get() == NULL) { 98 ALOGW("conversion from DER to ECDSA_SIG failed"); 99 return 0; 100 } 101 102 ALOGV("keystore_ecdsa_do_sign(%p, %d, %p) => returning %p len %llu", dgst, dlen, eckey, 103 ecdsa_sig.get(), replyLen); 104 return ecdsa_sig.release(); 105} 106 107static ECDSA_METHOD keystore_ecdsa_meth = { 108 kKeystoreEngineId, /* name */ 109 keystore_ecdsa_do_sign, /* ecdsa_do_sign */ 110 NULL, /* ecdsa_sign_setup */ 111 NULL, /* ecdsa_do_verify */ 112 0, /* flags */ 113 NULL, /* app_data */ 114}; 115 116static int register_ecdsa_methods() { 117 const ECDSA_METHOD* ecdsa_meth = ECDSA_OpenSSL(); 118 119 keystore_ecdsa_meth.ecdsa_do_verify = ecdsa_meth->ecdsa_do_verify; 120 121 return 1; 122} 123 124int ecdsa_pkey_setup(ENGINE *e, EVP_PKEY *pkey, const char *key_id) { 125 Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey)); 126 void* oldData = EC_KEY_insert_key_method_data(eckey.get(), 127 reinterpret_cast<void*>(strdup(key_id)), ex_data_dup, ex_data_free, 128 ex_data_clear_free); 129 if (oldData != NULL) { 130 free(oldData); 131 } 132 133 ECDSA_set_method(eckey.get(), &keystore_ecdsa_meth); 134 135 /* 136 * "ECDSA_set_ENGINE()" should probably be an OpenSSL API. Since it isn't, 137 * and EC_KEY_free() calls ENGINE_finish(), we need to call ENGINE_init() 138 * here. 139 */ 140 ECDSA_DATA *ecdsa = ecdsa_check(eckey.get()); 141 ENGINE_init(e); 142 ecdsa->engine = e; 143 144 return 1; 145} 146 147int ecdsa_register(ENGINE* e) { 148 if (!ENGINE_set_ECDSA(e, &keystore_ecdsa_meth) 149 || !register_ecdsa_methods()) { 150 ALOGE("Could not set up keystore ECDSA methods"); 151 return 0; 152 } 153 154 return 1; 155} 156