提交 839590f5 编写于 作者: R Richard Levitte

- 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.
上级 e0a8d1f9
......@@ -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)
......
......@@ -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
......
......@@ -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"},
......
......@@ -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)
{
......
......@@ -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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册