Home | History | Annotate | Download | only in keystore-engine
      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 
     45 using namespace android;
     46 
     47 struct ECDSA_SIG_Delete {
     48     void operator()(ECDSA_SIG* p) const {
     49         ECDSA_SIG_free(p);
     50     }
     51 };
     52 typedef UniquePtr<ECDSA_SIG, struct ECDSA_SIG_Delete> Unique_ECDSA_SIG;
     53 
     54 static 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 
    107 static 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 
    116 static 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 
    124 int 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 
    147 int 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