Some of the ENGINE file names were changed for 8.3 filename uniqueness
[openssl.git] / crypto / engine / hw_ncipher.c
index 2879a10a68699f29b9b6fa83c10bf505975f44bf..408db08b9849a28c94578f4759dc68ab1db8cc9c 100644 (file)
@@ -4,7 +4,7 @@
  * for the OpenSSL project 2000.
  */
 /* ====================================================================
- * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1999-2001 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -64,6 +64,7 @@
 #include "cryptlib.h"
 #include <openssl/dso.h>
 #include <openssl/engine.h>
+#include <openssl/ui.h>
 
 #ifndef OPENSSL_NO_HW
 #ifndef OPENSSL_NO_HW_NCIPHER
@@ -82,6 +83,7 @@
 #include "vendor_defns/hwcryptohook.h"
 #endif
 
+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)()); 
@@ -116,13 +118,17 @@ static int hwcrhk_rand_status(void);
 
 /* KM stuff */
 static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
-       pem_password_cb *callback, void *callback_data);
+       UI_METHOD *ui_method, void *callback_data);
 static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
-       pem_password_cb *callback, void *callback_data);
+       UI_METHOD *ui_method, void *callback_data);
 static void hwcrhk_ex_free(void *obj, void *item, CRYPTO_EX_DATA *ad,
        int ind,long argl, void *argp);
 
 /* 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,
@@ -133,6 +139,8 @@ static void hwcrhk_log_message(void *logstr, const char *message);
 #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",
@@ -146,6 +154,14 @@ static const ENGINE_CMD_DEFN hwcrhk_cmd_defns[] = {
                "THREAD_LOCKING",
                "Turns thread-safe locking on or off (boolean)",
                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}
        };
 
@@ -195,6 +211,91 @@ static RAND_METHOD hwcrhk_rand =
        hwcrhk_rand_status,
        };
 
+#ifndef OPENSSL_NO_ERR
+/* Error function codes for use in hwcrhk operation */
+#define HWCRHK_F_HWCRHK_INIT                   100
+#define HWCRHK_F_HWCRHK_FINISH                 101
+#define HWCRHK_F_HWCRHK_CTRL                   102
+#define HWCRHK_F_HWCRHK_LOAD_PRIVKEY           103
+#define HWCRHK_F_HWCRHK_LOAD_PUBKEY            104
+#define HWCRHK_F_HWCRHK_MOD_EXP                        105
+#define HWCRHK_F_HWCRHK_RSA_MOD_EXP            106
+#define HWCRHK_F_HWCRHK_RAND_BYTES             107
+#define HWCRHK_F_HWCRHK_GET_PASS               108
+#define HWCRHK_F_HWCRHK_INSERT_CARD            109
+/* Error reason codes */
+#define HWCRHK_R_ALREADY_LOADED                        110
+#define HWCRHK_R_DSO_FAILURE                   111
+#define HWCRHK_R_UNIT_FAILURE                  112
+#define HWCRHK_R_NOT_LOADED                    113
+#define HWCRHK_R_BIO_WAS_FREED                 114
+#define HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED  115
+#define HWCRHK_R_NOT_INITIALISED               116
+#define HWCRHK_R_CHIL_ERROR                    117
+#define HWCRHK_R_NO_KEY                                118
+#define HWCRHK_R_PRIVATE_KEY_ALGORITHMS_DISABLED 119
+#define HWCRHK_R_REQUEST_FALLBACK              120
+#define HWCRHK_R_REQUEST_FAILED                        121
+#define HWCRHK_R_MISSING_KEY_COMPONENTS                122
+#define HWCRHK_R_NO_CALLBACK                   123
+static ERR_STRING_DATA hwcrhk_str_functs[] =
+       {
+       /* This first element is changed to match the dynamic 'lib' number */
+{ERR_PACK(0,0,0),                              "hwcrhk engine code"},
+{ERR_PACK(0,HWCRHK_F_HWCRHK_INIT,0),           "hwcrhk_init"},
+{ERR_PACK(0,HWCRHK_F_HWCRHK_FINISH,0),                         ""},
+{ERR_PACK(0,HWCRHK_F_HWCRHK_CTRL,0),                           ""},
+{ERR_PACK(0,HWCRHK_F_HWCRHK_LOAD_PRIVKEY,0),                           ""},
+{ERR_PACK(0,HWCRHK_F_HWCRHK_LOAD_PUBKEY,0),                            ""},
+{ERR_PACK(0,HWCRHK_F_HWCRHK_MOD_EXP,0),                                ""},
+{ERR_PACK(0,HWCRHK_F_HWCRHK_RSA_MOD_EXP,0),                            ""},
+{ERR_PACK(0,HWCRHK_F_HWCRHK_RAND_BYTES,0),                             ""},
+{ERR_PACK(0,HWCRHK_F_HWCRHK_GET_PASS,0),                               ""},
+{ERR_PACK(0,HWCRHK_F_HWCRHK_INSERT_CARD,0),                            ""},
+/* Error reason codes */
+{HWCRHK_R_ALREADY_LOADED               ,"already loaded"},
+{HWCRHK_R_DSO_FAILURE                  ,"DSO failure"},
+{HWCRHK_R_UNIT_FAILURE                 ,"unit failure"},
+{HWCRHK_R_NOT_LOADED                   ,"not loaded"},
+{HWCRHK_R_BIO_WAS_FREED                        ,"BIO was freed"},
+{HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED ,"ctrl command not implemented"},
+{HWCRHK_R_NOT_INITIALISED              ,"not initialised"},
+{HWCRHK_R_CHIL_ERROR                   ,"'chil' error"},
+{HWCRHK_R_NO_KEY                       ,"no key"},
+{HWCRHK_R_PRIVATE_KEY_ALGORITHMS_DISABLED,"private key algorithms disabled"},
+{HWCRHK_R_REQUEST_FALLBACK             ,"request fallback"},
+{HWCRHK_R_REQUEST_FAILED               ,"request failed"},
+{HWCRHK_R_MISSING_KEY_COMPONENTS       ,"missing key components"},
+{HWCRHK_R_NO_CALLBACK                  ,"no callback"},
+{0,NULL}
+       };
+/* The library number we obtain dynamically from the ERR code */
+static int hwcrhk_err_lib = -1;
+#define HWCRHKerr(f,r) ERR_PUT_error(hwcrhk_err_lib,(f),(r),__FILE__,__LINE__)
+static void hwcrhk_load_error_strings(void)
+       {
+       if(hwcrhk_err_lib < 0)
+               {
+               if((hwcrhk_err_lib = ERR_get_next_error_library()) <= 0)
+                       return;
+               hwcrhk_str_functs[0].error = ERR_PACK(hwcrhk_err_lib,0,0);
+               ERR_load_strings(hwcrhk_err_lib, hwcrhk_str_functs);
+               }
+       }
+static void hwcrhk_unload_error_strings(void)
+       {
+       if(hwcrhk_err_lib >= 0)
+               {
+               ERR_unload_strings(hwcrhk_err_lib, hwcrhk_str_functs);
+               hwcrhk_err_lib = -1;
+               }
+       }
+#else
+#define HWCRHKerr(f,r)                                 /* NOP */
+static void hwcrhk_load_error_strings(void) { }                /* NOP */
+static void hwcrhk_unload_error_strings(void) { }      /* NOP */
+#endif
+
 /* Constants used when creating the ENGINE */
 static const char *engine_hwcrhk_id = "chil";
 static const char *engine_hwcrhk_name = "nCipher hardware engine support";
@@ -214,7 +315,7 @@ struct HWCryptoHook_MutexValue
    into HWCryptoHook_PassphraseContext */
 struct HWCryptoHook_PassphraseContextValue
        {
-       pem_password_cb *password_callback; /* If != NULL, will be called */
+        UI_METHOD *ui_method;
        void *callback_data;
        };
 
@@ -223,7 +324,10 @@ struct HWCryptoHook_PassphraseContextValue
    into HWCryptoHook_CallerContext */
 struct HWCryptoHook_CallerContextValue
        {
-       void *any;
+       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
@@ -233,28 +337,24 @@ struct HWCryptoHook_CallerContextValue
 #define MPI2BN(bn, mp) \
     {mp.size = bn->dmax * sizeof(BN_ULONG); mp.buf = (unsigned char *)bn->d;}
 
-#if 0 /* Card and password management is not yet supported */
-/* HWCryptoHook callbacks.  insert_card() and get_pass() are not yet
-   defined, because we haven't quite decided on the proper form yet.
-   log_message() just adds an entry in the error stack.  I don't know
-   if that's good or bad...  */
-static int insert_card(const char *prompt_info,
-       const char *wrong_info,
-       HWCryptoHook_PassphraseContext *ppctx,
-       HWCryptoHook_CallerContext *cactx);
-static int get_pass(const char *prompt_info,
-       int *len_io, char *buf,
-       HWCryptoHook_PassphraseContext *ppctx,
-       HWCryptoHook_CallerContext *cactx);
-#endif
-
 static BIO *logstream = NULL;
-static pem_password_cb *password_callback = NULL;
-#if 0
-static void *password_callback_userdata = NULL;
-#endif
 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 = {
        0,                      /* Flags */
@@ -291,16 +391,16 @@ static HWCryptoHook_InitInfo hwcrhk_globals = {
        0, /* hwcrhk_cv_destroy, */
 
        hwcrhk_get_pass,        /* pass phrase */
-       0, /* insert_card, */   /* insert a card */
+       hwcrhk_insert_card,     /* insert a card */
        hwcrhk_log_message      /* Log message */
 };
 
 
 /* Now, to our own code */
 
-/* As this is only ever called once, there's no need for locking
- * (indeed - the lock will already be held by our caller!!!) */
-ENGINE *ENGINE_ncipher()
+/* This internal function is used by ENGINE_ncipher() and possibly by the
+ * "dynamic" ENGINE support too */
+static int bind_helper(ENGINE *e)
        {
 #ifndef OPENSSL_NO_RSA
        const RSA_METHOD *meth1;
@@ -308,29 +408,24 @@ ENGINE *ENGINE_ncipher()
 #ifndef OPENSSL_NO_DH
        const DH_METHOD *meth2;
 #endif
-       ENGINE *ret = ENGINE_new();
-       if(!ret)
-               return NULL;
-       if(!ENGINE_set_id(ret, engine_hwcrhk_id) ||
-                       !ENGINE_set_name(ret, engine_hwcrhk_name) ||
+       if(!ENGINE_set_id(e, engine_hwcrhk_id) ||
+                       !ENGINE_set_name(e, engine_hwcrhk_name) ||
 #ifndef OPENSSL_NO_RSA
-                       !ENGINE_set_RSA(ret, &hwcrhk_rsa) ||
+                       !ENGINE_set_RSA(e, &hwcrhk_rsa) ||
 #endif
 #ifndef OPENSSL_NO_DH
-                       !ENGINE_set_DH(ret, &hwcrhk_dh) ||
+                       !ENGINE_set_DH(e, &hwcrhk_dh) ||
 #endif
-                       !ENGINE_set_RAND(ret, &hwcrhk_rand) ||
-                       !ENGINE_set_BN_mod_exp(ret, hwcrhk_mod_exp) ||
-                       !ENGINE_set_init_function(ret, hwcrhk_init) ||
-                       !ENGINE_set_finish_function(ret, hwcrhk_finish) ||
-                       !ENGINE_set_ctrl_function(ret, hwcrhk_ctrl) ||
-                       !ENGINE_set_load_privkey_function(ret, hwcrhk_load_privkey) ||
-                       !ENGINE_set_load_pubkey_function(ret, hwcrhk_load_pubkey) ||
-                       !ENGINE_set_cmd_defns(ret, hwcrhk_cmd_defns))
-               {
-               ENGINE_free(ret);
-               return NULL;
-               }
+                       !ENGINE_set_RAND(e, &hwcrhk_rand) ||
+                       !ENGINE_set_BN_mod_exp(e, hwcrhk_mod_exp) ||
+                       !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_SSLeay()" functions hook properly
@@ -353,6 +448,24 @@ ENGINE *ENGINE_ncipher()
        hwcrhk_dh.generate_key = meth2->generate_key;
        hwcrhk_dh.compute_key = meth2->compute_key;
 #endif
+
+       /* Ensure the hwcrhk error handling is set up */
+       hwcrhk_load_error_strings();
+       return 1;
+       }
+
+/* As this is only ever called once, there's no need for locking
+ * (indeed - the lock will already be held by our caller!!!) */
+ENGINE *ENGINE_ncipher(void)
+       {
+       ENGINE *ret = ENGINE_new();
+       if(!ret)
+               return NULL;
+       if(!bind_helper(ret))
+               {
+               ENGINE_free(ret);
+               return NULL;
+               }
        return ret;
        }
 
@@ -406,7 +519,8 @@ static const char *n_hwcrhk_ModExpCRT = "HWCryptoHook_ModExpCRT";
  * called, the checking and error handling is probably down there. */
 
 /* utility function to obtain a context */
-static int get_context(HWCryptoHook_ContextHandle *hac)
+static int get_context(HWCryptoHook_ContextHandle *hac,
+        HWCryptoHook_CallerContext *cac)
        {
        char tempbuf[1024];
        HWCryptoHook_ErrMsgBuf rmsg;
@@ -415,7 +529,7 @@ static int get_context(HWCryptoHook_ContextHandle *hac)
        rmsg.size = 1024;
 
         *hac = p_hwcrhk_Init(&hwcrhk_globals, sizeof(hwcrhk_globals), &rmsg,
-               NULL);
+               cac);
        if (!*hac)
                 return 0;
         return 1;
@@ -427,6 +541,13 @@ static void release_context(HWCryptoHook_ContextHandle hac)
        p_hwcrhk_Finish(hac);
        }
 
+/* Destructor (complements the "ENGINE_ncipher()" constructor) */
+static int hwcrhk_destroy(ENGINE *e)
+       {
+       hwcrhk_unload_error_strings();
+       return 1;
+       }
+
 /* (de)initialisation functions. */
 static int hwcrhk_init(ENGINE *e)
        {
@@ -444,14 +565,14 @@ static int hwcrhk_init(ENGINE *e)
 
        if(hwcrhk_dso != NULL)
                {
-               ENGINEerr(ENGINE_F_HWCRHK_INIT,ENGINE_R_ALREADY_LOADED);
+               HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_ALREADY_LOADED);
                goto err;
                }
        /* Attempt to load libnfhwcrhk.so/nfhwcrhk.dll/whatever. */
        hwcrhk_dso = DSO_load(NULL, HWCRHK_LIBNAME, NULL, 0);
        if(hwcrhk_dso == NULL)
                {
-               ENGINEerr(ENGINE_F_HWCRHK_INIT,ENGINE_R_DSO_FAILURE);
+               HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_DSO_FAILURE);
                goto err;
                }
        if(!(p1 = (HWCryptoHook_Init_t *)
@@ -475,7 +596,7 @@ static int hwcrhk_init(ENGINE *e)
                !(p9 = (HWCryptoHook_ModExpCRT_t *)
                        DSO_bind_func(hwcrhk_dso, n_hwcrhk_ModExpCRT)))
                {
-               ENGINEerr(ENGINE_F_HWCRHK_INIT,ENGINE_R_DSO_FAILURE);
+               HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_DSO_FAILURE);
                goto err;
                }
        /* Copy the pointers */
@@ -506,9 +627,9 @@ static int hwcrhk_init(ENGINE *e)
 
        /* Try and get a context - if not, we may have a DSO but no
         * accelerator! */
-       if(!get_context(&hwcrhk_context))
+       if(!get_context(&hwcrhk_context, &password_context))
                {
-               ENGINEerr(ENGINE_F_HWCRHK_INIT,ENGINE_R_UNIT_FAILURE);
+               HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_UNIT_FAILURE);
                goto err;
                }
        /* Everything's fine. */
@@ -542,14 +663,14 @@ static int hwcrhk_finish(ENGINE *e)
        int to_return = 1;
        if(hwcrhk_dso == NULL)
                {
-               ENGINEerr(ENGINE_F_HWCRHK_FINISH,ENGINE_R_NOT_LOADED);
+               HWCRHKerr(HWCRHK_F_HWCRHK_FINISH,HWCRHK_R_NOT_LOADED);
                to_return = 0;
                goto err;
                }
        release_context(hwcrhk_context);
        if(!DSO_free(hwcrhk_dso))
                {
-               ENGINEerr(ENGINE_F_HWCRHK_FINISH,ENGINE_R_DSO_FAILURE);
+               HWCRHKerr(HWCRHK_F_HWCRHK_FINISH,HWCRHK_R_DSO_FAILURE);
                to_return = 0;
                goto err;
                }
@@ -580,12 +701,12 @@ static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
        case HWCRHK_CMD_SO_PATH:
                if(hwcrhk_dso)
                        {
-                       ENGINEerr(ENGINE_F_HWCRHK_CTRL,ENGINE_R_ALREADY_LOADED);
+                       HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,HWCRHK_R_ALREADY_LOADED);
                        return 0;
                        }
                if(p == NULL)
                        {
-                       ENGINEerr(ENGINE_F_HWCRHK_CTRL,ERR_R_PASSED_NULL_PARAMETER);
+                       HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,ERR_R_PASSED_NULL_PARAMETER);
                        return 0;
                        }
                HWCRHK_LIBNAME = (const char *)p;
@@ -603,13 +724,23 @@ static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
                if (CRYPTO_add(&bio->references,1,CRYPTO_LOCK_BIO) > 1)
                        logstream = bio;
                else
-                       ENGINEerr(ENGINE_F_HWCRHK_CTRL,ENGINE_R_BIO_WAS_FREED);
+                       HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,HWCRHK_R_BIO_WAS_FREED);
                }
                CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
                break;
        case ENGINE_CTRL_SET_PASSWORD_CALLBACK:
                CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
-               password_callback = (pem_password_cb *)f;
+               password_context.password_callback = (pem_password_cb *)f;
+               CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
+               break;
+       case ENGINE_CTRL_SET_USER_INTERFACE:
+               CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
+               password_context.ui_method = (UI_METHOD *)p;
+               CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
+               break;
+       case ENGINE_CTRL_SET_CALLBACK_DATA:
+               CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
+               password_context.callback_data = p;
                CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
                break;
        /* this enables or disables the "SimpleForkCheck" flag used in the
@@ -643,8 +774,8 @@ static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
 
        /* The command isn't understood by this engine */
        default:
-               ENGINEerr(ENGINE_F_HWCRHK_CTRL,
-                       ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED);
+               HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,
+                       HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
                to_return = 0;
                break;
                }
@@ -653,7 +784,7 @@ static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
        }
 
 static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
-       pem_password_cb *callback, void *callback_data)
+       UI_METHOD *ui_method, void *callback_data)
        {
 #ifndef OPENSSL_NO_RSA
        RSA *rtmp = NULL;
@@ -670,32 +801,32 @@ static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
 
        if(!hwcrhk_context)
                {
-               ENGINEerr(ENGINE_F_HWCRHK_LOAD_PRIVKEY,
-                       ENGINE_R_NOT_INITIALISED);
+               HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
+                       HWCRHK_R_NOT_INITIALISED);
                goto err;
                }
 #ifndef OPENSSL_NO_RSA
        hptr = OPENSSL_malloc(sizeof(HWCryptoHook_RSAKeyHandle));
        if (!hptr)
                {
-               ENGINEerr(ENGINE_F_HWCRHK_LOAD_PRIVKEY,
+               HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
                        ERR_R_MALLOC_FAILURE);
                goto err;
                }
-       ppctx.password_callback = callback;
+        ppctx.ui_method = ui_method;
        ppctx.callback_data = callback_data;
        if (p_hwcrhk_RSALoadKey(hwcrhk_context, key_id, hptr,
                &rmsg, &ppctx))
                {
-               ENGINEerr(ENGINE_F_HWCRHK_LOAD_PRIVKEY,
-                       ENGINE_R_CHIL_ERROR);
+               HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
+                       HWCRHK_R_CHIL_ERROR);
                ERR_add_error_data(1,rmsg.buf);
                goto err;
                }
        if (!*hptr)
                {
-               ENGINEerr(ENGINE_F_HWCRHK_LOAD_PRIVKEY,
-                       ENGINE_R_NO_KEY);
+               HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
+                       HWCRHK_R_NO_KEY);
                goto err;
                }
 #endif
@@ -710,7 +841,7 @@ static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
        if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg)
                != HWCRYPTOHOOK_ERROR_MPISIZE)
                {
-               ENGINEerr(ENGINE_F_HWCRHK_LOAD_PUBKEY,ENGINE_R_CHIL_ERROR);
+               HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,HWCRHK_R_CHIL_ERROR);
                ERR_add_error_data(1,rmsg.buf);
                goto err;
                }
@@ -722,8 +853,8 @@ static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
 
        if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg))
                {
-               ENGINEerr(ENGINE_F_HWCRHK_LOAD_PUBKEY,
-                       ENGINE_R_CHIL_ERROR);
+               HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
+                       HWCRHK_R_CHIL_ERROR);
                ERR_add_error_data(1,rmsg.buf);
                goto err;
                }
@@ -737,8 +868,8 @@ static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
 #endif
 
         if (!res)
-                ENGINEerr(ENGINE_F_HWCRHK_LOAD_PUBKEY,
-                        ENGINE_R_PRIVATE_KEY_ALGORITHMS_DISABLED);
+                HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
+                        HWCRHK_R_PRIVATE_KEY_ALGORITHMS_DISABLED);
 
        return res;
  err:
@@ -752,12 +883,13 @@ static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
        }
 
 static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
-       pem_password_cb *callback, void *callback_data)
+       UI_METHOD *ui_method, void *callback_data)
        {
        EVP_PKEY *res = NULL;
 
 #ifndef OPENSSL_NO_RSA
-        res = hwcrhk_load_privkey(eng, key_id, callback, callback_data);
+        res = hwcrhk_load_privkey(eng, key_id,
+                ui_method, callback_data);
 #endif
 
        if (res)
@@ -778,8 +910,8 @@ static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
                        }
 #endif
                default:
-                       ENGINEerr(ENGINE_F_HWCRHK_LOAD_PUBKEY,
-                               ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED);
+                       HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
+                               HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
                        goto err;
                        }
 
@@ -808,7 +940,7 @@ static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
 
        if(!hwcrhk_context)
                {
-               ENGINEerr(ENGINE_F_HWCRHK_MOD_EXP,ENGINE_R_NOT_INITIALISED);
+               HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_NOT_INITIALISED);
                goto err;
                }
        /* Prepare the params */
@@ -832,11 +964,11 @@ static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
                   might be a good thing. */
                if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
                        {
-                       ENGINEerr(ENGINE_F_HWCRHK_MOD_EXP,ENGINE_R_REQUEST_FALLBACK);
+                       HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_REQUEST_FALLBACK);
                        }
                else
                        {
-                       ENGINEerr(ENGINE_F_HWCRHK_MOD_EXP,ENGINE_R_REQUEST_FAILED);
+                       HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_REQUEST_FAILED);
                        }
                ERR_add_error_data(1,rmsg.buf);
                goto err;
@@ -857,7 +989,7 @@ static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa)
 
        if(!hwcrhk_context)
                {
-               ENGINEerr(ENGINE_F_HWCRHK_MOD_EXP,ENGINE_R_NOT_INITIALISED);
+               HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_NOT_INITIALISED);
                goto err;
                }
 
@@ -871,8 +1003,8 @@ static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa)
 
                if(!rsa->n)
                        {
-                       ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,
-                               ENGINE_R_MISSING_KEY_COMPONENTS);
+                       HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
+                               HWCRHK_R_MISSING_KEY_COMPONENTS);
                        goto err;
                        }
 
@@ -898,11 +1030,13 @@ static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa)
                           might be a good thing. */
                        if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
                                {
-                               ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,ENGINE_R_REQUEST_FALLBACK);
+                               HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
+                                       HWCRHK_R_REQUEST_FALLBACK);
                                }
                        else
                                {
-                               ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,ENGINE_R_REQUEST_FAILED);
+                               HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
+                                       HWCRHK_R_REQUEST_FAILED);
                                }
                        ERR_add_error_data(1,rmsg.buf);
                        goto err;
@@ -914,8 +1048,8 @@ static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa)
 
                if(!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp)
                        {
-                       ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,
-                               ENGINE_R_MISSING_KEY_COMPONENTS);
+                       HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
+                               HWCRHK_R_MISSING_KEY_COMPONENTS);
                        goto err;
                        }
 
@@ -947,11 +1081,13 @@ static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa)
                           might be a good thing. */
                        if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
                                {
-                               ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,ENGINE_R_REQUEST_FALLBACK);
+                               HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
+                                       HWCRHK_R_REQUEST_FALLBACK);
                                }
                        else
                                {
-                               ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,ENGINE_R_REQUEST_FAILED);
+                               HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
+                                       HWCRHK_R_REQUEST_FAILED);
                                }
                        ERR_add_error_data(1,rmsg.buf);
                        goto err;
@@ -992,7 +1128,7 @@ static int hwcrhk_rand_bytes(unsigned char *buf, int num)
 
        if(!hwcrhk_context)
                {
-               ENGINEerr(ENGINE_F_HWCRHK_RAND_BYTES,ENGINE_R_NOT_INITIALISED);
+               HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,HWCRHK_R_NOT_INITIALISED);
                goto err;
                }
 
@@ -1004,11 +1140,13 @@ static int hwcrhk_rand_bytes(unsigned char *buf, int num)
                   might be a good thing. */
                if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
                        {
-                       ENGINEerr(ENGINE_F_HWCRHK_RAND_BYTES,ENGINE_R_REQUEST_FALLBACK);
+                       HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,
+                               HWCRHK_R_REQUEST_FALLBACK);
                        }
                else
                        {
-                       ENGINEerr(ENGINE_F_HWCRHK_RAND_BYTES,ENGINE_R_REQUEST_FAILED);
+                       HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,
+                               HWCRHK_R_REQUEST_FAILED);
                        }
                ERR_add_error_data(1,rmsg.buf);
                goto err;
@@ -1084,28 +1222,139 @@ static int hwcrhk_get_pass(const char *prompt_info,
        HWCryptoHook_PassphraseContext *ppctx,
        HWCryptoHook_CallerContext *cactx)
        {
-       pem_password_cb *callback = password_callback;
+       pem_password_cb *callback = NULL;
        void *callback_data = NULL;
+        UI_METHOD *ui_method = 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->password_callback)
-                       callback = ppctx->password_callback;
+                if (ppctx->ui_method)
+                        {
+                        ui_method = ppctx->ui_method;
+                        callback = NULL;
+                        }
                if (ppctx->callback_data)
                        callback_data = ppctx->callback_data;
                }
-       if (callback == NULL)
+       if (callback == NULL && ui_method == NULL)
                {
-               ENGINEerr(ENGINE_F_HWCRHK_GET_PASS,ENGINE_R_NO_CALLBACK);
+               HWCRHKerr(HWCRHK_F_HWCRHK_GET_PASS,HWCRHK_R_NO_CALLBACK);
                return -1;
                }
 
-       *len_io = callback(buf, *len_io, 0, callback_data);
+        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;
+               char buf[BUFSIZ];
+
+               if (wrong_info)
+                       BIO_snprintf(buf, sizeof(buf)-1,
+                               "Current card: \"%s\"\n", wrong_info);
+               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 <enter> or C<enter> 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;
@@ -1120,5 +1369,20 @@ static void hwcrhk_log_message(void *logstr, const char *message)
        CRYPTO_w_unlock(CRYPTO_LOCK_BIO);
        }
 
+/* This stuff is needed if this ENGINE is being compiled into a self-contained
+ * shared-library. */     
+#ifdef ENGINE_DYNAMIC_SUPPORT
+static int bind_fn(ENGINE *e, const char *id)
+       {
+       if(id && (strcmp(id, engine_hwcrhk_id) != 0))
+               return 0;
+       if(!bind_helper(e))
+               return 0;
+       return 1;
+       }       
+IMPLEMENT_DYNAMIC_CHECK_FN()
+IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
+#endif /* ENGINE_DYNAMIC_SUPPORT */
+
 #endif /* !OPENSSL_NO_HW_NCIPHER */
 #endif /* !OPENSSL_NO_HW */