From 839590f5761db68ee733a422648ab2ec8e0a4f14 Mon Sep 17 00:00:00 2001
From: Richard Levitte <levitte@openssl.org>
Date: Tue, 19 Jun 2001 16:12:18 +0000
Subject: [PATCH] - 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.

---
 CHANGES                    |   9 ++
 crypto/engine/engine.h     |  25 ++++-
 crypto/engine/engine_err.c |   2 +
 crypto/engine/engine_lib.c |  45 ++++++++-
 crypto/engine/hw_ncipher.c | 198 ++++++++++++++++++++++++++++++-------
 5 files changed, 235 insertions(+), 44 deletions(-)

diff --git a/CHANGES b/CHANGES
index ef113ed413..589b1059aa 100644
--- a/CHANGES
+++ b/CHANGES
@@ -11,6 +11,15 @@
          *) 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)
diff --git a/crypto/engine/engine.h b/crypto/engine/engine.h
index dc0b5233c3..5f79ece06e 100644
--- a/crypto/engine/engine.h
+++ b/crypto/engine/engine.h
@@ -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
diff --git a/crypto/engine/engine_err.c b/crypto/engine/engine_err.c
index 33e1ede2db..6f21e7c66a 100644
--- a/crypto/engine/engine_err.c
+++ b/crypto/engine/engine_err.c
@@ -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"},
diff --git a/crypto/engine/engine_lib.c b/crypto/engine/engine_lib.c
index 594e4ddc94..84efe96163 100644
--- a/crypto/engine/engine_lib.c
+++ b/crypto/engine/engine_lib.c
@@ -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)
 	{
diff --git a/crypto/engine/hw_ncipher.c b/crypto/engine/hw_ncipher.c
index 2879a10a68..1b9254c321 100644
--- a/crypto/engine/hw_ncipher.c
+++ b/crypto/engine/hw_ncipher.c
@@ -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;
-- 
2.25.1