From aa4d426b4d3527d7e166df1a05058c9a4a0f6683 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Fri, 30 Apr 2021 00:33:56 +0200 Subject: initial/final commit --- openssl-1.1.0h/engines/e_chil.c | 1285 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1285 insertions(+) create mode 100644 openssl-1.1.0h/engines/e_chil.c (limited to 'openssl-1.1.0h/engines/e_chil.c') diff --git a/openssl-1.1.0h/engines/e_chil.c b/openssl-1.1.0h/engines/e_chil.c new file mode 100644 index 0000000..8d81b46 --- /dev/null +++ b/openssl-1.1.0h/engines/e_chil.c @@ -0,0 +1,1285 @@ +/* + * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include +#include "internal/dso.h" +#include +#include +#include +#ifndef OPENSSL_NO_RSA +# include +#endif +#ifndef OPENSSL_NO_DH +# include +#endif +#include + +#ifndef OPENSSL_NO_HW +# ifndef OPENSSL_NO_HW_CHIL + +/*- + * Attribution notice: nCipher have said several times that it's OK for + * us to implement a general interface to their boxes, and recently declared + * their HWCryptoHook to be public, and therefore available for us to use. + * Thanks, nCipher. + * + * The hwcryptohook.h included here is from May 2000. + * [Richard Levitte] + */ +# ifdef FLAT_INC +# include "hwcryptohook.h" +# else +# include "vendor_defns/hwcryptohook.h" +# endif + +# define HWCRHK_LIB_NAME "CHIL engine" +# include "e_chil_err.c" + +static CRYPTO_RWLOCK *chil_lock; + +static int hwcrhk_destroy(ENGINE *e); +static int hwcrhk_init(ENGINE *e); +static int hwcrhk_finish(ENGINE *e); +static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)); + +/* Functions to handle mutexes */ +static int hwcrhk_mutex_init(HWCryptoHook_Mutex *, + HWCryptoHook_CallerContext *); +static int hwcrhk_mutex_lock(HWCryptoHook_Mutex *); +static void hwcrhk_mutex_unlock(HWCryptoHook_Mutex *); +static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex *); + +/* BIGNUM stuff */ +static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx); + +# ifndef OPENSSL_NO_RSA +/* RSA stuff */ +static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa, + BN_CTX *ctx); +/* This function is aliased to mod_exp (with the mont stuff dropped). */ +static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx); +static int hwcrhk_rsa_finish(RSA *rsa); +# endif + +# ifndef OPENSSL_NO_DH +/* DH stuff */ +/* This function is alised to mod_exp (with the DH and mont dropped). */ +static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r, + const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx); +# endif + +/* RAND stuff */ +static int hwcrhk_rand_bytes(unsigned char *buf, int num); +static int hwcrhk_rand_status(void); + +/* KM stuff */ +static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id, + UI_METHOD *ui_method, + void *callback_data); +static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id, + UI_METHOD *ui_method, + void *callback_data); + +/* Interaction stuff */ +static int hwcrhk_insert_card(const char *prompt_info, + const char *wrong_info, + HWCryptoHook_PassphraseContext * ppctx, + HWCryptoHook_CallerContext * cactx); +static int hwcrhk_get_pass(const char *prompt_info, + int *len_io, char *buf, + HWCryptoHook_PassphraseContext * ppctx, + HWCryptoHook_CallerContext * cactx); +static void hwcrhk_log_message(void *logstr, const char *message); + +/* The definitions for control commands specific to this engine */ +# define HWCRHK_CMD_SO_PATH ENGINE_CMD_BASE +# define HWCRHK_CMD_FORK_CHECK (ENGINE_CMD_BASE + 1) +# define HWCRHK_CMD_THREAD_LOCKING (ENGINE_CMD_BASE + 2) +# define HWCRHK_CMD_SET_USER_INTERFACE (ENGINE_CMD_BASE + 3) +# define HWCRHK_CMD_SET_CALLBACK_DATA (ENGINE_CMD_BASE + 4) +static const ENGINE_CMD_DEFN hwcrhk_cmd_defns[] = { + {HWCRHK_CMD_SO_PATH, + "SO_PATH", + "Specifies the path to the 'hwcrhk' shared library", + ENGINE_CMD_FLAG_STRING}, + {HWCRHK_CMD_FORK_CHECK, + "FORK_CHECK", + "Turns fork() checking on (non-zero) or off (zero)", + ENGINE_CMD_FLAG_NUMERIC}, + {HWCRHK_CMD_THREAD_LOCKING, + "THREAD_LOCKING", + "Turns thread-safe locking on (zero) or off (non-zero)", + ENGINE_CMD_FLAG_NUMERIC}, + {HWCRHK_CMD_SET_USER_INTERFACE, + "SET_USER_INTERFACE", + "Set the global user interface (internal)", + ENGINE_CMD_FLAG_INTERNAL}, + {HWCRHK_CMD_SET_CALLBACK_DATA, + "SET_CALLBACK_DATA", + "Set the global user interface extra data (internal)", + ENGINE_CMD_FLAG_INTERNAL}, + {0, NULL, NULL, 0} +}; + +# ifndef OPENSSL_NO_RSA +/* Our internal RSA_METHOD that we provide pointers to */ +static RSA_METHOD hwcrhk_rsa = { + "CHIL RSA method", + NULL, + NULL, + NULL, + NULL, + hwcrhk_rsa_mod_exp, + hwcrhk_mod_exp_mont, + NULL, + hwcrhk_rsa_finish, + 0, + NULL, + NULL, + NULL, + NULL +}; +# endif + +# ifndef OPENSSL_NO_DH +/* Our internal DH_METHOD that we provide pointers to */ +static DH_METHOD hwcrhk_dh = { + "CHIL DH method", + NULL, + NULL, + hwcrhk_mod_exp_dh, + NULL, + NULL, + 0, + NULL, + NULL +}; +# endif + +static RAND_METHOD hwcrhk_rand = { + /* "CHIL RAND method", */ + NULL, + hwcrhk_rand_bytes, + NULL, + NULL, + hwcrhk_rand_bytes, + hwcrhk_rand_status, +}; + +/* Constants used when creating the ENGINE */ +static const char *engine_hwcrhk_id = "chil"; +static const char *engine_hwcrhk_name = "CHIL hardware engine support"; +# ifndef OPENSSL_NO_DYNAMIC_ENGINE +/* Compatibility hack, the dynamic library uses this form in the path */ +static const char *engine_hwcrhk_id_alt = "ncipher"; +# endif + +/* Internal stuff for HWCryptoHook */ + +/* Some structures needed for proper use of thread locks */ +/* + * hwcryptohook.h has some typedefs that turn struct HWCryptoHook_MutexValue + * into HWCryptoHook_Mutex + */ +struct HWCryptoHook_MutexValue { + CRYPTO_RWLOCK *lock; +}; + +/* + * hwcryptohook.h has some typedefs that turn struct + * HWCryptoHook_PassphraseContextValue into HWCryptoHook_PassphraseContext + */ +struct HWCryptoHook_PassphraseContextValue { + UI_METHOD *ui_method; + void *callback_data; +}; + +/* + * hwcryptohook.h has some typedefs that turn struct + * HWCryptoHook_CallerContextValue into HWCryptoHook_CallerContext + */ +struct HWCryptoHook_CallerContextValue { + pem_password_cb *password_callback; /* Deprecated! Only present for + * backward compatibility! */ + UI_METHOD *ui_method; + void *callback_data; +}; + +/* + * The MPI structure in HWCryptoHook is pretty compatible with OpenSSL + * BIGNUM's, so lets define a couple of conversion macros + */ +# define BN2MPI(mp, bn) \ + {mp.size = bn->top * sizeof(BN_ULONG); mp.buf = (unsigned char *)bn->d;} +# define MPI2BN(bn, mp) \ + {mp.size = bn->dmax * sizeof(BN_ULONG); mp.buf = (unsigned char *)bn->d;} + +static BIO *logstream = NULL; +static int disable_mutex_callbacks = 0; + +/* + * One might wonder why these are needed, since one can pass down at least a + * UI_METHOD and a pointer to callback data to the key-loading functions. The + * thing is that the ModExp and RSAImmed functions can load keys as well, if + * the data they get is in a special, nCipher-defined format (hint: if you + * look at the private exponent of the RSA data as a string, you'll see this + * string: "nCipher KM tool key id", followed by some bytes, followed a key + * identity string, followed by more bytes. This happens when you use + * "embed" keys instead of "hwcrhk" keys). Unfortunately, those functions do + * not take any passphrase or caller context, and our functions can't really + * take any callback data either. Still, the "insert_card" and + * "get_passphrase" callbacks may be called down the line, and will need to + * know what user interface callbacks to call, and having callback data from + * the application may be a nice thing as well, so we need to keep track of + * that globally. + */ +static HWCryptoHook_CallerContext password_context = { NULL, NULL, NULL }; + +/* Stuff to pass to the HWCryptoHook library */ +static HWCryptoHook_InitInfo hwcrhk_globals = { + HWCryptoHook_InitFlags_SimpleForkCheck, /* Flags */ + &logstream, /* logstream */ + sizeof(BN_ULONG), /* limbsize */ + 0, /* mslimb first: false for BNs */ + -1, /* msbyte first: use native */ + 0, /* Max mutexes, 0 = no small limit */ + 0, /* Max simultaneous, 0 = default */ + + /* + * The next few are mutex stuff: we write wrapper functions around the OS + * mutex functions. We initialise them to 0 here, and change that to + * actual function pointers in hwcrhk_init() if dynamic locks are + * supported (that is, if the application programmer has made sure of + * setting up callbacks bafore starting this engine) *and* if + * disable_mutex_callbacks hasn't been set by a call to + * ENGINE_ctrl(ENGINE_CTRL_CHIL_NO_LOCKING). + */ + sizeof(HWCryptoHook_Mutex), + 0, + 0, + 0, + 0, + + /* + * The next few are condvar stuff: we write wrapper functions round the + * OS functions. Currently not implemented and not and absolute + * necessity even in threaded programs, therefore 0'ed. Will hopefully + * be implemented some day, since it enhances the efficiency of + * HWCryptoHook. + */ + 0, /* sizeof(HWCryptoHook_CondVar), */ + 0, /* hwcrhk_cv_init, */ + 0, /* hwcrhk_cv_wait, */ + 0, /* hwcrhk_cv_signal, */ + 0, /* hwcrhk_cv_broadcast, */ + 0, /* hwcrhk_cv_destroy, */ + + hwcrhk_get_pass, /* pass phrase */ + hwcrhk_insert_card, /* insert a card */ + hwcrhk_log_message /* Log message */ +}; + +/* Now, to our own code */ + +/* + * This internal function is used by ENGINE_chil() and possibly by the + * "dynamic" ENGINE support too + */ +static int bind_helper(ENGINE *e) +{ +# ifndef OPENSSL_NO_RSA + const RSA_METHOD *meth1; +# endif +# ifndef OPENSSL_NO_DH + const DH_METHOD *meth2; +# endif + + chil_lock = CRYPTO_THREAD_lock_new(); + if (chil_lock == NULL) { + HWCRHKerr(HWCRHK_F_BIND_HELPER, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (!ENGINE_set_id(e, engine_hwcrhk_id) || + !ENGINE_set_name(e, engine_hwcrhk_name) || +# ifndef OPENSSL_NO_RSA + !ENGINE_set_RSA(e, &hwcrhk_rsa) || +# endif +# ifndef OPENSSL_NO_DH + !ENGINE_set_DH(e, &hwcrhk_dh) || +# endif + !ENGINE_set_RAND(e, &hwcrhk_rand) || + !ENGINE_set_destroy_function(e, hwcrhk_destroy) || + !ENGINE_set_init_function(e, hwcrhk_init) || + !ENGINE_set_finish_function(e, hwcrhk_finish) || + !ENGINE_set_ctrl_function(e, hwcrhk_ctrl) || + !ENGINE_set_load_privkey_function(e, hwcrhk_load_privkey) || + !ENGINE_set_load_pubkey_function(e, hwcrhk_load_pubkey) || + !ENGINE_set_cmd_defns(e, hwcrhk_cmd_defns)) + return 0; + +# ifndef OPENSSL_NO_RSA + /* + * We know that the "PKCS1_OpenSSL()" functions hook properly to the + * cswift-specific mod_exp and mod_exp_crt so we use those functions. NB: + * We don't use ENGINE_openssl() or anything "more generic" because + * something like the RSAref code may not hook properly, and if you own + * one of these cards then you have the right to do RSA operations on it + * anyway! + */ + meth1 = RSA_PKCS1_OpenSSL(); + hwcrhk_rsa.rsa_pub_enc = meth1->rsa_pub_enc; + hwcrhk_rsa.rsa_pub_dec = meth1->rsa_pub_dec; + hwcrhk_rsa.rsa_priv_enc = meth1->rsa_priv_enc; + hwcrhk_rsa.rsa_priv_dec = meth1->rsa_priv_dec; +# endif + +# ifndef OPENSSL_NO_DH + /* Much the same for Diffie-Hellman */ + meth2 = DH_OpenSSL(); + hwcrhk_dh.generate_key = meth2->generate_key; + hwcrhk_dh.compute_key = meth2->compute_key; +# endif + + /* Ensure the hwcrhk error handling is set up */ + ERR_load_HWCRHK_strings(); + + return 1; +} + +# ifdef OPENSSL_NO_DYNAMIC_ENGINE +static ENGINE *engine_chil(void) +{ + ENGINE *ret = ENGINE_new(); + if (ret == NULL) + return NULL; + if (!bind_helper(ret)) { + ENGINE_free(ret); + return NULL; + } + return ret; +} + +void ENGINE_load_chil(void) +{ + /* Copied from eng_[openssl|dyn].c */ + ENGINE *toadd = engine_chil(); + if (!toadd) + return; + ENGINE_add(toadd); + ENGINE_free(toadd); + ERR_clear_error(); +} +# endif + +/* + * This is a process-global DSO handle used for loading and unloading the + * HWCryptoHook library. NB: This is only set (or unset) during an init() or + * finish() call (reference counts permitting) and they're operating with + * global locks, so this should be thread-safe implicitly. + */ +static DSO *hwcrhk_dso = NULL; +static HWCryptoHook_ContextHandle hwcrhk_context = 0; +# ifndef OPENSSL_NO_RSA +/* Index for KM handle. Not really used yet. */ +static int hndidx_rsa = -1; +# endif + +/* + * These are the function pointers that are (un)set when the library has + * successfully (un)loaded. + */ +static HWCryptoHook_Init_t *p_hwcrhk_Init = NULL; +static HWCryptoHook_Finish_t *p_hwcrhk_Finish = NULL; +static HWCryptoHook_ModExp_t *p_hwcrhk_ModExp = NULL; +# ifndef OPENSSL_NO_RSA +static HWCryptoHook_RSA_t *p_hwcrhk_RSA = NULL; +# endif +static HWCryptoHook_RandomBytes_t *p_hwcrhk_RandomBytes = NULL; +# ifndef OPENSSL_NO_RSA +static HWCryptoHook_RSALoadKey_t *p_hwcrhk_RSALoadKey = NULL; +static HWCryptoHook_RSAGetPublicKey_t *p_hwcrhk_RSAGetPublicKey = NULL; +static HWCryptoHook_RSAUnloadKey_t *p_hwcrhk_RSAUnloadKey = NULL; +# endif +static HWCryptoHook_ModExpCRT_t *p_hwcrhk_ModExpCRT = NULL; + +/* Used in the DSO operations. */ +static const char *HWCRHK_LIBNAME = NULL; +static void free_HWCRHK_LIBNAME(void) +{ + OPENSSL_free(HWCRHK_LIBNAME); + HWCRHK_LIBNAME = NULL; +} + +static const char *get_HWCRHK_LIBNAME(void) +{ + if (HWCRHK_LIBNAME) + return HWCRHK_LIBNAME; + return "nfhwcrhk"; +} + +static long set_HWCRHK_LIBNAME(const char *name) +{ + free_HWCRHK_LIBNAME(); + return (((HWCRHK_LIBNAME = OPENSSL_strdup(name)) != NULL) ? 1 : 0); +} + +static const char *n_hwcrhk_Init = "HWCryptoHook_Init"; +static const char *n_hwcrhk_Finish = "HWCryptoHook_Finish"; +static const char *n_hwcrhk_ModExp = "HWCryptoHook_ModExp"; +# ifndef OPENSSL_NO_RSA +static const char *n_hwcrhk_RSA = "HWCryptoHook_RSA"; +# endif +static const char *n_hwcrhk_RandomBytes = "HWCryptoHook_RandomBytes"; +# ifndef OPENSSL_NO_RSA +static const char *n_hwcrhk_RSALoadKey = "HWCryptoHook_RSALoadKey"; +static const char *n_hwcrhk_RSAGetPublicKey = "HWCryptoHook_RSAGetPublicKey"; +static const char *n_hwcrhk_RSAUnloadKey = "HWCryptoHook_RSAUnloadKey"; +# endif +static const char *n_hwcrhk_ModExpCRT = "HWCryptoHook_ModExpCRT"; + +/* + * HWCryptoHook library functions and mechanics - these are used by the + * higher-level functions further down. NB: As and where there's no error + * checking, take a look lower down where these functions are called, the + * checking and error handling is probably down there. + */ + +/* utility function to obtain a context */ +static int get_context(HWCryptoHook_ContextHandle * hac, + HWCryptoHook_CallerContext * cac) +{ + char tempbuf[1024]; + HWCryptoHook_ErrMsgBuf rmsg; + + rmsg.buf = tempbuf; + rmsg.size = sizeof(tempbuf); + + *hac = p_hwcrhk_Init(&hwcrhk_globals, sizeof(hwcrhk_globals), &rmsg, cac); + if (!*hac) + return 0; + return 1; +} + +/* similarly to release one. */ +static void release_context(HWCryptoHook_ContextHandle hac) +{ + p_hwcrhk_Finish(hac); +} + +/* Destructor (complements the "ENGINE_chil()" constructor) */ +static int hwcrhk_destroy(ENGINE *e) +{ + free_HWCRHK_LIBNAME(); + ERR_unload_HWCRHK_strings(); + CRYPTO_THREAD_lock_free(chil_lock); + return 1; +} + +/* (de)initialisation functions. */ +static int hwcrhk_init(ENGINE *e) +{ + HWCryptoHook_Init_t *p1; + HWCryptoHook_Finish_t *p2; + HWCryptoHook_ModExp_t *p3; +# ifndef OPENSSL_NO_RSA + HWCryptoHook_RSA_t *p4; + HWCryptoHook_RSALoadKey_t *p5; + HWCryptoHook_RSAGetPublicKey_t *p6; + HWCryptoHook_RSAUnloadKey_t *p7; +# endif + HWCryptoHook_RandomBytes_t *p8; + HWCryptoHook_ModExpCRT_t *p9; + + if (hwcrhk_dso != NULL) { + HWCRHKerr(HWCRHK_F_HWCRHK_INIT, HWCRHK_R_ALREADY_LOADED); + goto err; + } + /* Attempt to load libnfhwcrhk.so/nfhwcrhk.dll/whatever. */ + hwcrhk_dso = DSO_load(NULL, get_HWCRHK_LIBNAME(), NULL, 0); + if (hwcrhk_dso == NULL) { + HWCRHKerr(HWCRHK_F_HWCRHK_INIT, HWCRHK_R_DSO_FAILURE); + goto err; + } + +#define BINDIT(t, name) (t *)DSO_bind_func(hwcrhk_dso, name) + if ((p1 = BINDIT(HWCryptoHook_Init_t, n_hwcrhk_Init)) == NULL + || (p2 = BINDIT(HWCryptoHook_Finish_t, n_hwcrhk_Finish)) == NULL + || (p3 = BINDIT(HWCryptoHook_ModExp_t, n_hwcrhk_ModExp)) == NULL +# ifndef OPENSSL_NO_RSA + || (p4 = BINDIT(HWCryptoHook_RSA_t, n_hwcrhk_RSA)) == NULL + || (p5 = BINDIT(HWCryptoHook_RSALoadKey_t, n_hwcrhk_RSALoadKey)) == NULL + || (p6 = BINDIT(HWCryptoHook_RSAGetPublicKey_t, n_hwcrhk_RSAGetPublicKey)) == NULL + || (p7 = BINDIT(HWCryptoHook_RSAUnloadKey_t, n_hwcrhk_RSAUnloadKey)) == NULL +# endif + || (p8 = BINDIT(HWCryptoHook_RandomBytes_t, n_hwcrhk_RandomBytes)) == NULL + || (p9 = BINDIT(HWCryptoHook_ModExpCRT_t, n_hwcrhk_ModExpCRT)) == NULL) { + HWCRHKerr(HWCRHK_F_HWCRHK_INIT, HWCRHK_R_DSO_FAILURE); + goto err; + } + /* Copy the pointers */ + p_hwcrhk_Init = p1; + p_hwcrhk_Finish = p2; + p_hwcrhk_ModExp = p3; +# ifndef OPENSSL_NO_RSA + p_hwcrhk_RSA = p4; + p_hwcrhk_RSALoadKey = p5; + p_hwcrhk_RSAGetPublicKey = p6; + p_hwcrhk_RSAUnloadKey = p7; +# endif + p_hwcrhk_RandomBytes = p8; + p_hwcrhk_ModExpCRT = p9; + + /* + * Check if the application decided to support dynamic locks, and if it + * does, use them. + */ + if (disable_mutex_callbacks == 0) { + hwcrhk_globals.mutex_init = hwcrhk_mutex_init; + hwcrhk_globals.mutex_acquire = hwcrhk_mutex_lock; + hwcrhk_globals.mutex_release = hwcrhk_mutex_unlock; + hwcrhk_globals.mutex_destroy = hwcrhk_mutex_destroy; + } + + /* + * Try and get a context - if not, we may have a DSO but no accelerator! + */ + if (!get_context(&hwcrhk_context, &password_context)) { + HWCRHKerr(HWCRHK_F_HWCRHK_INIT, HWCRHK_R_UNIT_FAILURE); + goto err; + } + /* Everything's fine. */ +# ifndef OPENSSL_NO_RSA + if (hndidx_rsa == -1) + hndidx_rsa = RSA_get_ex_new_index(0, + "nFast HWCryptoHook RSA key handle", + NULL, NULL, NULL); +# endif + return 1; + err: + DSO_free(hwcrhk_dso); + hwcrhk_dso = NULL; + p_hwcrhk_Init = NULL; + p_hwcrhk_Finish = NULL; + p_hwcrhk_ModExp = NULL; +# ifndef OPENSSL_NO_RSA + p_hwcrhk_RSA = NULL; + p_hwcrhk_RSALoadKey = NULL; + p_hwcrhk_RSAGetPublicKey = NULL; + p_hwcrhk_RSAUnloadKey = NULL; +# endif + p_hwcrhk_ModExpCRT = NULL; + p_hwcrhk_RandomBytes = NULL; + return 0; +} + +static int hwcrhk_finish(ENGINE *e) +{ + int to_return = 1; + free_HWCRHK_LIBNAME(); + if (hwcrhk_dso == NULL) { + HWCRHKerr(HWCRHK_F_HWCRHK_FINISH, HWCRHK_R_NOT_LOADED); + to_return = 0; + goto err; + } + release_context(hwcrhk_context); + if (!DSO_free(hwcrhk_dso)) { + HWCRHKerr(HWCRHK_F_HWCRHK_FINISH, HWCRHK_R_DSO_FAILURE); + to_return = 0; + goto err; + } + err: + BIO_free(logstream); + hwcrhk_dso = NULL; + p_hwcrhk_Init = NULL; + p_hwcrhk_Finish = NULL; + p_hwcrhk_ModExp = NULL; +# ifndef OPENSSL_NO_RSA + p_hwcrhk_RSA = NULL; + p_hwcrhk_RSALoadKey = NULL; + p_hwcrhk_RSAGetPublicKey = NULL; + p_hwcrhk_RSAUnloadKey = NULL; +# endif + p_hwcrhk_ModExpCRT = NULL; + p_hwcrhk_RandomBytes = NULL; + return to_return; +} + +static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) +{ + int to_return = 1; + + switch (cmd) { + case HWCRHK_CMD_SO_PATH: + if (hwcrhk_dso) { + HWCRHKerr(HWCRHK_F_HWCRHK_CTRL, HWCRHK_R_ALREADY_LOADED); + return 0; + } + if (p == NULL) { + HWCRHKerr(HWCRHK_F_HWCRHK_CTRL, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + return set_HWCRHK_LIBNAME((const char *)p); + case ENGINE_CTRL_SET_LOGSTREAM: + { + BIO *bio = (BIO *)p; + + CRYPTO_THREAD_write_lock(chil_lock); + BIO_free(logstream); + logstream = NULL; + if (BIO_up_ref(bio)) + logstream = bio; + else + HWCRHKerr(HWCRHK_F_HWCRHK_CTRL, HWCRHK_R_BIO_WAS_FREED); + } + CRYPTO_THREAD_unlock(chil_lock); + break; + case ENGINE_CTRL_SET_PASSWORD_CALLBACK: + CRYPTO_THREAD_write_lock(chil_lock); + password_context.password_callback = (pem_password_cb *)f; + CRYPTO_THREAD_unlock(chil_lock); + break; + case ENGINE_CTRL_SET_USER_INTERFACE: + case HWCRHK_CMD_SET_USER_INTERFACE: + CRYPTO_THREAD_write_lock(chil_lock); + password_context.ui_method = (UI_METHOD *)p; + CRYPTO_THREAD_unlock(chil_lock); + break; + case ENGINE_CTRL_SET_CALLBACK_DATA: + case HWCRHK_CMD_SET_CALLBACK_DATA: + CRYPTO_THREAD_write_lock(chil_lock); + password_context.callback_data = p; + CRYPTO_THREAD_unlock(chil_lock); + break; + /* + * this enables or disables the "SimpleForkCheck" flag used in the + * initialisation structure. + */ + case ENGINE_CTRL_CHIL_SET_FORKCHECK: + case HWCRHK_CMD_FORK_CHECK: + CRYPTO_THREAD_write_lock(chil_lock); + if (i) + hwcrhk_globals.flags |= HWCryptoHook_InitFlags_SimpleForkCheck; + else + hwcrhk_globals.flags &= ~HWCryptoHook_InitFlags_SimpleForkCheck; + CRYPTO_THREAD_unlock(chil_lock); + break; + /* + * This will prevent the initialisation function from "installing" + * the mutex-handling callbacks, even if they are available from + * within the library (or were provided to the library from the + * calling application). This is to remove any baggage for + * applications not using multithreading. + */ + case ENGINE_CTRL_CHIL_NO_LOCKING: + CRYPTO_THREAD_write_lock(chil_lock); + disable_mutex_callbacks = 1; + CRYPTO_THREAD_unlock(chil_lock); + break; + case HWCRHK_CMD_THREAD_LOCKING: + CRYPTO_THREAD_write_lock(chil_lock); + disable_mutex_callbacks = ((i == 0) ? 0 : 1); + CRYPTO_THREAD_unlock(chil_lock); + break; + + /* The command isn't understood by this engine */ + default: + HWCRHKerr(HWCRHK_F_HWCRHK_CTRL, + HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED); + to_return = 0; + break; + } + + return to_return; +} + +static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id, + UI_METHOD *ui_method, + void *callback_data) +{ +# ifndef OPENSSL_NO_RSA + RSA *rtmp = NULL; +# endif + EVP_PKEY *res = NULL; +# ifndef OPENSSL_NO_RSA + HWCryptoHook_MPI e, n; + HWCryptoHook_RSAKeyHandle *hptr; +# endif +# if !defined(OPENSSL_NO_RSA) + char tempbuf[1024]; + HWCryptoHook_ErrMsgBuf rmsg; + HWCryptoHook_PassphraseContext ppctx; +# endif + +# if !defined(OPENSSL_NO_RSA) + rmsg.buf = tempbuf; + rmsg.size = sizeof(tempbuf); +# endif + + if (!hwcrhk_context) { + HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_NOT_INITIALISED); + goto err; + } +# ifndef OPENSSL_NO_RSA + hptr = OPENSSL_malloc(sizeof(*hptr)); + if (hptr == NULL) { + HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, ERR_R_MALLOC_FAILURE); + goto err; + } + ppctx.ui_method = ui_method; + ppctx.callback_data = callback_data; + if (p_hwcrhk_RSALoadKey(hwcrhk_context, key_id, hptr, &rmsg, &ppctx)) { + HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_CHIL_ERROR); + ERR_add_error_data(1, rmsg.buf); + goto err; + } + if (!*hptr) { + HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_NO_KEY); + goto err; + } +# endif +# ifndef OPENSSL_NO_RSA + rtmp = RSA_new_method(eng); + RSA_set_ex_data(rtmp, hndidx_rsa, (char *)hptr); + rtmp->e = BN_new(); + rtmp->n = BN_new(); + rtmp->flags |= RSA_FLAG_EXT_PKEY; + MPI2BN(rtmp->e, e); + MPI2BN(rtmp->n, n); + if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg) + != HWCRYPTOHOOK_ERROR_MPISIZE) { + HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_CHIL_ERROR); + ERR_add_error_data(1, rmsg.buf); + goto err; + } + + bn_expand2(rtmp->e, e.size / sizeof(BN_ULONG)); + bn_expand2(rtmp->n, n.size / sizeof(BN_ULONG)); + MPI2BN(rtmp->e, e); + MPI2BN(rtmp->n, n); + + if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg)) { + HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_CHIL_ERROR); + ERR_add_error_data(1, rmsg.buf); + goto err; + } + rtmp->e->top = e.size / sizeof(BN_ULONG); + bn_fix_top(rtmp->e); + rtmp->n->top = n.size / sizeof(BN_ULONG); + bn_fix_top(rtmp->n); + + res = EVP_PKEY_new(); + if (res == NULL) { + HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_CHIL_ERROR); + goto err; + } + EVP_PKEY_assign_RSA(res, rtmp); +# endif + + if (res == NULL) + HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, + HWCRHK_R_PRIVATE_KEY_ALGORITHMS_DISABLED); + + return res; + err: +# ifndef OPENSSL_NO_RSA + RSA_free(rtmp); +# endif + return NULL; +} + +static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id, + UI_METHOD *ui_method, void *callback_data) +{ + EVP_PKEY *res = NULL; + +# ifndef OPENSSL_NO_RSA + res = hwcrhk_load_privkey(eng, key_id, ui_method, callback_data); +# endif + + if (res) + switch (res->type) { +# ifndef OPENSSL_NO_RSA + case EVP_PKEY_RSA: + { + RSA *rsa = NULL; + + CRYPTO_THREAD_write_lock(chil_lock); + rsa = res->pkey.rsa; + res->pkey.rsa = RSA_new(); + res->pkey.rsa->n = rsa->n; + res->pkey.rsa->e = rsa->e; + rsa->n = NULL; + rsa->e = NULL; + CRYPTO_THREAD_unlock(chil_lock); + RSA_free(rsa); + } + break; +# endif + default: + HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY, + HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED); + goto err; + } + + return res; + err: + EVP_PKEY_free(res); + return NULL; +} + +/* A little mod_exp */ +static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx) +{ + char tempbuf[1024]; + HWCryptoHook_ErrMsgBuf rmsg; + /* + * Since HWCryptoHook_MPI is pretty compatible with BIGNUM's, we use them + * directly, plus a little macro magic. We only thing we need to make + * sure of is that enough space is allocated. + */ + HWCryptoHook_MPI m_a, m_p, m_n, m_r; + int to_return, ret; + + to_return = 0; /* expect failure */ + rmsg.buf = tempbuf; + rmsg.size = sizeof(tempbuf); + + if (!hwcrhk_context) { + HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP, HWCRHK_R_NOT_INITIALISED); + goto err; + } + /* Prepare the params */ + bn_expand2(r, m->top); /* Check for error !! */ + BN2MPI(m_a, a); + BN2MPI(m_p, p); + BN2MPI(m_n, m); + MPI2BN(r, m_r); + + /* Perform the operation */ + ret = p_hwcrhk_ModExp(hwcrhk_context, m_a, m_p, m_n, &m_r, &rmsg); + + /* Convert the response */ + r->top = m_r.size / sizeof(BN_ULONG); + bn_fix_top(r); + + if (ret < 0) { + /* + * FIXME: When this error is returned, HWCryptoHook is telling us + * that falling back to software computation might be a good thing. + */ + if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) { + HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP, HWCRHK_R_REQUEST_FALLBACK); + } else { + HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP, HWCRHK_R_REQUEST_FAILED); + } + ERR_add_error_data(1, rmsg.buf); + goto err; + } + + to_return = 1; + err: + return to_return; +} + +# ifndef OPENSSL_NO_RSA +static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa, + BN_CTX *ctx) +{ + char tempbuf[1024]; + HWCryptoHook_ErrMsgBuf rmsg; + HWCryptoHook_RSAKeyHandle *hptr; + int to_return = 0, ret; + + rmsg.buf = tempbuf; + rmsg.size = sizeof(tempbuf); + + if (!hwcrhk_context) { + HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, HWCRHK_R_NOT_INITIALISED); + goto err; + } + + /* + * This provides support for nForce keys. Since that's opaque data all + * we do is provide a handle to the proper key and let HWCryptoHook take + * care of the rest. + */ + if ((hptr = + (HWCryptoHook_RSAKeyHandle *) RSA_get_ex_data(rsa, hndidx_rsa)) + != NULL) { + HWCryptoHook_MPI m_a, m_r; + + if (!rsa->n) { + HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, + HWCRHK_R_MISSING_KEY_COMPONENTS); + goto err; + } + + /* Prepare the params */ + bn_expand2(r, rsa->n->top); /* Check for error !! */ + BN2MPI(m_a, I); + MPI2BN(r, m_r); + + /* Perform the operation */ + ret = p_hwcrhk_RSA(m_a, *hptr, &m_r, &rmsg); + + /* Convert the response */ + r->top = m_r.size / sizeof(BN_ULONG); + bn_fix_top(r); + + if (ret < 0) { + /* + * FIXME: When this error is returned, HWCryptoHook is telling us + * that falling back to software computation might be a good + * thing. + */ + if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) { + HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, + HWCRHK_R_REQUEST_FALLBACK); + } else { + HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, + HWCRHK_R_REQUEST_FAILED); + } + ERR_add_error_data(1, rmsg.buf); + goto err; + } + } else { + HWCryptoHook_MPI m_a, m_p, m_q, m_dmp1, m_dmq1, m_iqmp, m_r; + + if (!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp) { + HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, + HWCRHK_R_MISSING_KEY_COMPONENTS); + goto err; + } + + /* Prepare the params */ + bn_expand2(r, rsa->n->top); /* Check for error !! */ + BN2MPI(m_a, I); + BN2MPI(m_p, rsa->p); + BN2MPI(m_q, rsa->q); + BN2MPI(m_dmp1, rsa->dmp1); + BN2MPI(m_dmq1, rsa->dmq1); + BN2MPI(m_iqmp, rsa->iqmp); + MPI2BN(r, m_r); + + /* Perform the operation */ + ret = p_hwcrhk_ModExpCRT(hwcrhk_context, m_a, m_p, m_q, + m_dmp1, m_dmq1, m_iqmp, &m_r, &rmsg); + + /* Convert the response */ + r->top = m_r.size / sizeof(BN_ULONG); + bn_fix_top(r); + + if (ret < 0) { + /* + * FIXME: When this error is returned, HWCryptoHook is telling us + * that falling back to software computation might be a good + * thing. + */ + if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) { + HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, + HWCRHK_R_REQUEST_FALLBACK); + } else { + HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, + HWCRHK_R_REQUEST_FAILED); + } + ERR_add_error_data(1, rmsg.buf); + goto err; + } + } + /* + * If we're here, we must be here with some semblance of success :-) + */ + to_return = 1; + err: + return to_return; +} +# endif + +# ifndef OPENSSL_NO_RSA +/* This function is aliased to mod_exp (with the mont stuff dropped). */ +static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx) +{ + return hwcrhk_mod_exp(r, a, p, m, ctx); +} + +static int hwcrhk_rsa_finish(RSA *rsa) +{ + HWCryptoHook_RSAKeyHandle *hptr; + + hptr = RSA_get_ex_data(rsa, hndidx_rsa); + if (hptr) { + p_hwcrhk_RSAUnloadKey(*hptr, NULL); + OPENSSL_free(hptr); + RSA_set_ex_data(rsa, hndidx_rsa, NULL); + } + return 1; +} + +# endif + +# ifndef OPENSSL_NO_DH +/* This function is aliased to mod_exp (with the dh and mont dropped). */ +static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r, + const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) +{ + return hwcrhk_mod_exp(r, a, p, m, ctx); +} +# endif + +/* Random bytes are good */ +static int hwcrhk_rand_bytes(unsigned char *buf, int num) +{ + char tempbuf[1024]; + HWCryptoHook_ErrMsgBuf rmsg; + int to_return = 0; /* assume failure */ + int ret; + + rmsg.buf = tempbuf; + rmsg.size = sizeof(tempbuf); + + if (!hwcrhk_context) { + HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES, HWCRHK_R_NOT_INITIALISED); + goto err; + } + + ret = p_hwcrhk_RandomBytes(hwcrhk_context, buf, num, &rmsg); + if (ret < 0) { + /* + * FIXME: When this error is returned, HWCryptoHook is telling us + * that falling back to software computation might be a good thing. + */ + if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) { + HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES, HWCRHK_R_REQUEST_FALLBACK); + } else { + HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES, HWCRHK_R_REQUEST_FAILED); + } + ERR_add_error_data(1, rmsg.buf); + goto err; + } + to_return = 1; + err: + return to_return; +} + +static int hwcrhk_rand_status(void) +{ + return 1; +} + +/* + * Mutex calls: since the HWCryptoHook model closely follows the POSIX model + * these just wrap the POSIX functions and add some logging. + */ + +static int hwcrhk_mutex_init(HWCryptoHook_Mutex * mt, + HWCryptoHook_CallerContext * cactx) +{ + mt->lock = CRYPTO_THREAD_lock_new(); + if (mt->lock == NULL) { + HWCRHKerr(HWCRHK_F_HWCRHK_MUTEX_INIT, ERR_R_MALLOC_FAILURE); + return 1; /* failure */ + } + return 0; /* success */ +} + +static int hwcrhk_mutex_lock(HWCryptoHook_Mutex * mt) +{ + CRYPTO_THREAD_write_lock(mt->lock); + return 0; +} + +static void hwcrhk_mutex_unlock(HWCryptoHook_Mutex * mt) +{ + CRYPTO_THREAD_unlock(mt->lock); +} + +static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex * mt) +{ + CRYPTO_THREAD_lock_free(mt->lock); +} + +static int hwcrhk_get_pass(const char *prompt_info, + int *len_io, char *buf, + HWCryptoHook_PassphraseContext * ppctx, + HWCryptoHook_CallerContext * cactx) +{ + pem_password_cb *callback = NULL; + void *callback_data = NULL; + UI_METHOD *ui_method = NULL; + /* + * Despite what the documentation says prompt_info can be an empty + * string. + */ + if (prompt_info && !*prompt_info) + prompt_info = NULL; + + if (cactx) { + if (cactx->ui_method) + ui_method = cactx->ui_method; + if (cactx->password_callback) + callback = cactx->password_callback; + if (cactx->callback_data) + callback_data = cactx->callback_data; + } + if (ppctx) { + if (ppctx->ui_method) { + ui_method = ppctx->ui_method; + callback = NULL; + } + if (ppctx->callback_data) + callback_data = ppctx->callback_data; + } + if (callback == NULL && ui_method == NULL) { + HWCRHKerr(HWCRHK_F_HWCRHK_GET_PASS, HWCRHK_R_NO_CALLBACK); + return -1; + } + + if (ui_method) { + UI *ui = UI_new_method(ui_method); + if (ui) { + int ok; + char *prompt = UI_construct_prompt(ui, + "pass phrase", prompt_info); + + ok = UI_add_input_string(ui, prompt, + UI_INPUT_FLAG_DEFAULT_PWD, + buf, 0, (*len_io) - 1); + UI_add_user_data(ui, callback_data); + UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0); + + if (ok >= 0) + do { + ok = UI_process(ui); + } + while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0)); + + if (ok >= 0) + *len_io = strlen(buf); + + UI_free(ui); + OPENSSL_free(prompt); + } + } else { + *len_io = callback(buf, *len_io, 0, callback_data); + } + if (!*len_io) + return -1; + return 0; +} + +static int hwcrhk_insert_card(const char *prompt_info, + const char *wrong_info, + HWCryptoHook_PassphraseContext * ppctx, + HWCryptoHook_CallerContext * cactx) +{ + int ok = -1; + UI *ui; + void *callback_data = NULL; + UI_METHOD *ui_method = NULL; + + if (cactx) { + if (cactx->ui_method) + ui_method = cactx->ui_method; + if (cactx->callback_data) + callback_data = cactx->callback_data; + } + if (ppctx) { + if (ppctx->ui_method) + ui_method = ppctx->ui_method; + if (ppctx->callback_data) + callback_data = ppctx->callback_data; + } + if (ui_method == NULL) { + HWCRHKerr(HWCRHK_F_HWCRHK_INSERT_CARD, HWCRHK_R_NO_CALLBACK); + return -1; + } + + ui = UI_new_method(ui_method); + + if (ui) { + char answer = '\0'; + char buf[BUFSIZ]; + /* + * Despite what the documentation says wrong_info can be an empty + * string. + */ + if (wrong_info && *wrong_info) + BIO_snprintf(buf, sizeof(buf) - 1, + "Current card: \"%s\"\n", wrong_info); + else + buf[0] = 0; + ok = UI_dup_info_string(ui, buf); + if (ok >= 0 && prompt_info) { + BIO_snprintf(buf, sizeof(buf) - 1, + "Insert card \"%s\"", prompt_info); + ok = UI_dup_input_boolean(ui, buf, + "\n then hit or C to cancel\n", + "\r\n", "Cc", UI_INPUT_FLAG_ECHO, + &answer); + } + UI_add_user_data(ui, callback_data); + + if (ok >= 0) + ok = UI_process(ui); + UI_free(ui); + + if (ok == -2 || (ok >= 0 && answer == 'C')) + ok = 1; + else if (ok < 0) + ok = -1; + else + ok = 0; + } + return ok; +} + +static void hwcrhk_log_message(void *logstr, const char *message) +{ + BIO *lstream = NULL; + + if (logstr) + lstream = *(BIO **)logstr; + if (lstream) { + BIO_printf(lstream, "%s\n", message); + } +} + +/* + * This stuff is needed if this ENGINE is being compiled into a + * self-contained shared-library. + */ +# ifndef OPENSSL_NO_DYNAMIC_ENGINE +static int bind_fn(ENGINE *e, const char *id) +{ + if (id && (strcmp(id, engine_hwcrhk_id) != 0) && + (strcmp(id, engine_hwcrhk_id_alt) != 0)) + return 0; + if (!bind_helper(e)) + return 0; + return 1; +} + +IMPLEMENT_DYNAMIC_CHECK_FN() + IMPLEMENT_DYNAMIC_BIND_FN(bind_fn) +# endif /* OPENSSL_NO_DYNAMIC_ENGINE */ +# endif /* !OPENSSL_NO_HW_CHIL */ +#endif /* !OPENSSL_NO_HW */ -- cgit v1.2.3