- Add the possibility to control engines through control names but
authorRichard Levitte <levitte@openssl.org>
Tue, 19 Jun 2001 16:12:18 +0000 (16:12 +0000)
committerRichard Levitte <levitte@openssl.org>
Tue, 19 Jun 2001 16:12:18 +0000 (16:12 +0000)
  with arbitrary arguments instead of just a string.
- Change the key loaders to take a UI_METHOD instead of a callback
  function pointer.  NOTE: this breaks binary compatibility with
  earlier versions of OpenSSL [engine].
- Addapt the nCipher code for these new conditions and add a card
  insertion callback.

CHANGES
crypto/engine/engine.h
crypto/engine/engine_err.c
crypto/engine/engine_lib.c
crypto/engine/hw_ncipher.c

diff --git a/CHANGES b/CHANGES
index ef113ed..589b105 100644 (file)
--- a/CHANGES
+++ b/CHANGES
          *) applies to 0.9.6a (/0.9.6b) and 0.9.7
          +) applies to 0.9.7 only
 
+  +) Add the possibility to control engines through control names but with
+     arbitrary arguments instead of just a string.
+     Change the key loaders to take a UI_METHOD instead of a callback
+     function pointer.  NOTE: this breaks binary compatibility with earlier
+     versions of OpenSSL [engine].
+     Addapt the nCipher code for these new conditions and add a card insertion
+     callback.
+     [Richard Levitte]
+
   +) Enhance the general user interface with mechanisms to better support
      dialog box interfaces, application-defined prompts, the possibility
      to use defaults (for example default passwords from somewhere else)
index dc0b523..5f79ece 100644 (file)
@@ -72,6 +72,7 @@
 #include <openssl/rand.h>
 #include <openssl/evp.h>
 #include <openssl/pem.h>
+#include <openssl/ui.h>
 #include <openssl/symhacks.h>
 
 #ifdef  __cplusplus
@@ -136,6 +137,10 @@ typedef void DH_METHOD;
 /* Indicates that the control command takes *no* input. Ie. the control command
  * is unparameterised. */
 #define ENGINE_CMD_FLAG_NO_INPUT       (unsigned int)0x0004
+/* Indicates that the control command is internal. This control command won't
+ * be shown in any output, and is only usable through the ENGINE_ctrl_cmd()
+ * function. */
+#define ENGINE_CMD_FLAG_INTERNAL       (unsigned int)0x0008
 
 /* NB: These 3 control commands are deprecated and should not be used. ENGINEs
  * relying on these commands should compile conditional support for
@@ -154,6 +159,11 @@ typedef void DH_METHOD;
 #define ENGINE_CTRL_SET_PASSWORD_CALLBACK      2
 #define ENGINE_CTRL_HUP                                3 /* Close and reinitialise any
                                                     handles/connections etc. */
+#define ENGINE_CTRL_SET_USER_INTERFACE          4 /* Alternative to callback */
+#define ENGINE_CTRL_SET_CALLBACK_DATA           5 /* User-specific data, used
+                                                     when calling the password
+                                                     callback and the user
+                                                     interface */
 
 /* These control commands allow an application to deal with an arbitrary engine
  * in a dynamic way. Warn: Negative return values indicate errors FOR THESE
@@ -264,7 +274,7 @@ typedef int (*ENGINE_GEN_INT_FUNC_PTR)(ENGINE *);
 typedef int (*ENGINE_CTRL_FUNC_PTR)(ENGINE *, int, long, void *, void (*f)());
 /* Generic load_key function pointer */
 typedef EVP_PKEY * (*ENGINE_LOAD_KEY_PTR)(ENGINE *, const char *,
-       pem_password_cb *callback, void *callback_data);
+       UI_METHOD *ui_method, void *callback_data);
 
 /* STRUCTURE functions ... all of these functions deal with pointers to ENGINE
  * structures where the pointers have a "structural reference". This means that
@@ -312,6 +322,13 @@ int ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)());
  * ENGINE_ctrl_cmd_string(), only ENGINE_ctrl(). */
 int ENGINE_cmd_is_executable(ENGINE *e, int cmd);
 
+/* This function works like ENGINE_ctrl() with the exception of taking a
+ * command name instead of a command number, and can handle optional commands.
+ * See the comment on ENGINE_ctrl_cmd_string() for an explanation on how to
+ * use the cmd_name and cmd_optional. */
+int ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name,
+        long i, void *p, void (*f)(), int cmd_optional);
+
 /* This function passes a command-name and argument to an ENGINE. The cmd_name
  * is converted to a command number and the control command is called using
  * 'arg' as an argument (unless the ENGINE doesn't support such a command, in
@@ -419,9 +436,9 @@ int ENGINE_finish(ENGINE *e);
  * location, handled by the engine.  The storage may be on a card or
  * whatever. */
 EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id,
-       pem_password_cb *callback, void *callback_data);
+       UI_METHOD *ui_method, void *callback_data);
 EVP_PKEY *ENGINE_load_public_key(ENGINE *e, const char *key_id,
-       pem_password_cb *callback, void *callback_data);
+       UI_METHOD *ui_method, void *callback_data);
 
 /* This returns a pointer for the current ENGINE structure that
  * is (by default) performing any RSA operations. The value returned
@@ -486,6 +503,7 @@ void ERR_load_ENGINE_strings(void);
 #define ENGINE_F_ENGINE_BY_ID                           106
 #define ENGINE_F_ENGINE_CMD_IS_EXECUTABLE               170
 #define ENGINE_F_ENGINE_CTRL                            142
+#define ENGINE_F_ENGINE_CTRL_CMD                        178
 #define ENGINE_F_ENGINE_CTRL_CMD_STRING                         171
 #define ENGINE_F_ENGINE_FINISH                          107
 #define ENGINE_F_ENGINE_FREE                            108
@@ -507,6 +525,7 @@ void ERR_load_ENGINE_strings(void);
 #define ENGINE_F_HWCRHK_FINISH                          135
 #define ENGINE_F_HWCRHK_GET_PASS                        155
 #define ENGINE_F_HWCRHK_INIT                            136
+#define ENGINE_F_HWCRHK_INSERT_CARD                     179
 #define ENGINE_F_HWCRHK_LOAD_PRIVKEY                    153
 #define ENGINE_F_HWCRHK_LOAD_PUBKEY                     154
 #define ENGINE_F_HWCRHK_MOD_EXP                                 137
index 33e1ede..6f21e7c 100644 (file)
@@ -83,6 +83,7 @@ static ERR_STRING_DATA ENGINE_str_functs[]=
 {ERR_PACK(0,ENGINE_F_ENGINE_BY_ID,0),  "ENGINE_by_id"},
 {ERR_PACK(0,ENGINE_F_ENGINE_CMD_IS_EXECUTABLE,0),      "ENGINE_cmd_is_executable"},
 {ERR_PACK(0,ENGINE_F_ENGINE_CTRL,0),   "ENGINE_ctrl"},
+{ERR_PACK(0,ENGINE_F_ENGINE_CTRL_CMD,0),       "ENGINE_ctrl_cmd"},
 {ERR_PACK(0,ENGINE_F_ENGINE_CTRL_CMD_STRING,0),        "ENGINE_ctrl_cmd_string"},
 {ERR_PACK(0,ENGINE_F_ENGINE_FINISH,0), "ENGINE_finish"},
 {ERR_PACK(0,ENGINE_F_ENGINE_FREE,0),   "ENGINE_free"},
@@ -104,6 +105,7 @@ static ERR_STRING_DATA ENGINE_str_functs[]=
 {ERR_PACK(0,ENGINE_F_HWCRHK_FINISH,0), "HWCRHK_FINISH"},
 {ERR_PACK(0,ENGINE_F_HWCRHK_GET_PASS,0),       "HWCRHK_GET_PASS"},
 {ERR_PACK(0,ENGINE_F_HWCRHK_INIT,0),   "HWCRHK_INIT"},
+{ERR_PACK(0,ENGINE_F_HWCRHK_INSERT_CARD,0),    "HWCRHK_INSERT_CARD"},
 {ERR_PACK(0,ENGINE_F_HWCRHK_LOAD_PRIVKEY,0),   "HWCRHK_LOAD_PRIVKEY"},
 {ERR_PACK(0,ENGINE_F_HWCRHK_LOAD_PUBKEY,0),    "HWCRHK_LOAD_PUBKEY"},
 {ERR_PACK(0,ENGINE_F_HWCRHK_MOD_EXP,0),        "HWCRHK_MOD_EXP"},
index 594e4dd..84efe96 100644 (file)
@@ -232,7 +232,7 @@ int ENGINE_finish(ENGINE *e)
        }
 
 EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id,
-       pem_password_cb *callback, void *callback_data)
+       UI_METHOD *ui_method, void *callback_data)
        {
        EVP_PKEY *pkey;
 
@@ -257,7 +257,7 @@ EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id,
                        ENGINE_R_NO_LOAD_FUNCTION);
                return 0;
                }
-       pkey = e->load_privkey(e, key_id, callback, callback_data);
+       pkey = e->load_privkey(e, key_id, ui_method, callback_data);
        if (!pkey)
                {
                ENGINEerr(ENGINE_F_ENGINE_LOAD_PRIVATE_KEY,
@@ -268,7 +268,7 @@ EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id,
        }
 
 EVP_PKEY *ENGINE_load_public_key(ENGINE *e, const char *key_id,
-       pem_password_cb *callback, void *callback_data)
+       UI_METHOD *ui_method, void *callback_data)
        {
        EVP_PKEY *pkey;
 
@@ -293,7 +293,7 @@ EVP_PKEY *ENGINE_load_public_key(ENGINE *e, const char *key_id,
                        ENGINE_R_NO_LOAD_FUNCTION);
                return 0;
                }
-       pkey = e->load_pubkey(e, key_id, callback, callback_data);
+       pkey = e->load_pubkey(e, key_id, ui_method, callback_data);
        if (!pkey)
                {
                ENGINEerr(ENGINE_F_ENGINE_LOAD_PUBLIC_KEY,
@@ -487,6 +487,43 @@ int ENGINE_cmd_is_executable(ENGINE *e, int cmd)
        return 1;
        }
 
+int ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name,
+        long i, void *p, void (*f)(), int cmd_optional)
+        {
+       int num;
+
+       if((e == NULL) || (cmd_name == NULL))
+               {
+               ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
+                       ERR_R_PASSED_NULL_PARAMETER);
+               return 0;
+               }
+       if((e->ctrl == NULL) || ((num = ENGINE_ctrl(e,
+                                       ENGINE_CTRL_GET_CMD_FROM_NAME,
+                                       0, (void *)cmd_name, NULL)) <= 0))
+               {
+               /* If the command didn't *have* to be supported, we fake
+                * success. This allows certain settings to be specified for
+                * multiple ENGINEs and only require a change of ENGINE id
+                * (without having to selectively apply settings). Eg. changing
+                * from a hardware device back to the regular software ENGINE
+                * without editing the config file, etc. */
+               if(cmd_optional)
+                       {
+                       ERR_clear_error();
+                       return 1;
+                       }
+               ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD,
+                       ENGINE_R_INVALID_CMD_NAME);
+               return 0;
+               }
+       /* Force the result of the control command to 0 or 1, for the reasons
+        * mentioned before. */
+        if (ENGINE_ctrl(e, num, i, p, f))
+                return 1;
+        return 0;
+        }
+
 int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg,
                                int cmd_optional)
        {
index 2879a10..1b9254c 100644 (file)
@@ -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
@@ -116,13 +117,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 +138,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 +153,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}
        };
 
@@ -214,7 +229,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 +238,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 +251,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,7 +305,7 @@ 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 */
 };
 
@@ -406,7 +420,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 +430,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;
@@ -506,7 +521,7 @@ 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);
                goto err;
@@ -609,7 +624,17 @@ static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
                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
@@ -653,7 +678,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;
@@ -682,7 +707,7 @@ static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
                        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))
@@ -752,12 +777,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)
@@ -1084,28 +1110,126 @@ 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);
                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);
+                        if (ok >= 0)
+                                ok=UI_process(ui);
+                        if (ok >= 0)
+                                *len_io = strlen(buf);
+
+                        OPENSSL_free(prompt);
+                        UI_free(ui);
+                        }
+                }
+        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)
+               {
+               ENGINEerr(ENGINE_F_HWCRHK_INSERT_CARD,ENGINE_R_NO_CALLBACK);
+               return -1;
+               }
+
+        ui = UI_new_method(ui_method);
+
+        if (ui)
+                {
+                char answer[10];
+                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\"\n then hit <enter> or C<enter> to cancel\n", prompt_info);
+                        ok = UI_dup_input_string(ui, buf, 1,
+                                answer, 0, sizeof(answer)-1);
+                        }
+                UI_add_user_data(ui, callback_data);
+                if (ok == 0)
+                        ok = UI_process(ui);
+                UI_free(ui);
+                if (strchr("Cc",answer[0]) == 0)
+                        ok = 1;
+                }
+        if (ok == 0)
+                return 0;
+        return -1;
+        }
+
 static void hwcrhk_log_message(void *logstr, const char *message)
        {
        BIO *lstream = NULL;