e_chil.c revision 206046
1/* crypto/engine/e_chil.c -*- mode: C; c-file-style: "eay" -*- */
2/* Written by Richard Levitte (richard@levitte.org), Geoff Thorpe
3 * (geoff@geoffthorpe.net) and Dr Stephen N Henson (steve@openssl.org)
4 * for the OpenSSL project 2000.
5 */
6/* ====================================================================
7 * Copyright (c) 1999-2001 The OpenSSL Project.  All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in
18 *    the documentation and/or other materials provided with the
19 *    distribution.
20 *
21 * 3. All advertising materials mentioning features or use of this
22 *    software must display the following acknowledgment:
23 *    "This product includes software developed by the OpenSSL Project
24 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25 *
26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27 *    endorse or promote products derived from this software without
28 *    prior written permission. For written permission, please contact
29 *    licensing@OpenSSL.org.
30 *
31 * 5. Products derived from this software may not be called "OpenSSL"
32 *    nor may "OpenSSL" appear in their names without prior written
33 *    permission of the OpenSSL Project.
34 *
35 * 6. Redistributions of any form whatsoever must retain the following
36 *    acknowledgment:
37 *    "This product includes software developed by the OpenSSL Project
38 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51 * OF THE POSSIBILITY OF SUCH DAMAGE.
52 * ====================================================================
53 *
54 * This product includes cryptographic software written by Eric Young
55 * (eay@cryptsoft.com).  This product includes software written by Tim
56 * Hudson (tjh@cryptsoft.com).
57 *
58 */
59
60#include <stdio.h>
61#include <string.h>
62#include <openssl/crypto.h>
63#include <openssl/pem.h>
64#include <openssl/dso.h>
65#include <openssl/engine.h>
66#include <openssl/ui.h>
67#include <openssl/rand.h>
68#ifndef OPENSSL_NO_RSA
69#include <openssl/rsa.h>
70#endif
71#ifndef OPENSSL_NO_DH
72#include <openssl/dh.h>
73#endif
74#include <openssl/bn.h>
75
76#ifndef OPENSSL_NO_HW
77#ifndef OPENSSL_NO_HW_CHIL
78
79/* Attribution notice: nCipher have said several times that it's OK for
80 * us to implement a general interface to their boxes, and recently declared
81 * their HWCryptoHook to be public, and therefore available for us to use.
82 * Thanks, nCipher.
83 *
84 * The hwcryptohook.h included here is from May 2000.
85 * [Richard Levitte]
86 */
87#ifdef FLAT_INC
88#include "hwcryptohook.h"
89#else
90#include "vendor_defns/hwcryptohook.h"
91#endif
92
93#define HWCRHK_LIB_NAME "CHIL engine"
94#include "e_chil_err.c"
95
96static int hwcrhk_destroy(ENGINE *e);
97static int hwcrhk_init(ENGINE *e);
98static int hwcrhk_finish(ENGINE *e);
99static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void));
100
101/* Functions to handle mutexes */
102static int hwcrhk_mutex_init(HWCryptoHook_Mutex*, HWCryptoHook_CallerContext*);
103static int hwcrhk_mutex_lock(HWCryptoHook_Mutex*);
104static void hwcrhk_mutex_unlock(HWCryptoHook_Mutex*);
105static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex*);
106
107/* BIGNUM stuff */
108static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
109		const BIGNUM *m, BN_CTX *ctx);
110
111#ifndef OPENSSL_NO_RSA
112/* RSA stuff */
113static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa, BN_CTX *ctx);
114#endif
115#ifndef OPENSSL_NO_RSA
116/* This function is aliased to mod_exp (with the mont stuff dropped). */
117static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
118		const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
119#endif
120
121#ifndef OPENSSL_NO_DH
122/* DH stuff */
123/* This function is alised to mod_exp (with the DH and mont dropped). */
124static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r,
125	const BIGNUM *a, const BIGNUM *p,
126	const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
127#endif
128
129/* RAND stuff */
130static int hwcrhk_rand_bytes(unsigned char *buf, int num);
131static int hwcrhk_rand_status(void);
132
133/* KM stuff */
134static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
135	UI_METHOD *ui_method, void *callback_data);
136static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
137	UI_METHOD *ui_method, void *callback_data);
138#ifndef OPENSSL_NO_RSA
139static void hwcrhk_ex_free(void *obj, void *item, CRYPTO_EX_DATA *ad,
140	int ind,long argl, void *argp);
141#endif
142
143/* Interaction stuff */
144static int hwcrhk_insert_card(const char *prompt_info,
145	const char *wrong_info,
146	HWCryptoHook_PassphraseContext *ppctx,
147	HWCryptoHook_CallerContext *cactx);
148static int hwcrhk_get_pass(const char *prompt_info,
149	int *len_io, char *buf,
150	HWCryptoHook_PassphraseContext *ppctx,
151	HWCryptoHook_CallerContext *cactx);
152static void hwcrhk_log_message(void *logstr, const char *message);
153
154/* The definitions for control commands specific to this engine */
155#define HWCRHK_CMD_SO_PATH		ENGINE_CMD_BASE
156#define HWCRHK_CMD_FORK_CHECK		(ENGINE_CMD_BASE + 1)
157#define HWCRHK_CMD_THREAD_LOCKING	(ENGINE_CMD_BASE + 2)
158#define HWCRHK_CMD_SET_USER_INTERFACE   (ENGINE_CMD_BASE + 3)
159#define HWCRHK_CMD_SET_CALLBACK_DATA    (ENGINE_CMD_BASE + 4)
160static const ENGINE_CMD_DEFN hwcrhk_cmd_defns[] = {
161	{HWCRHK_CMD_SO_PATH,
162		"SO_PATH",
163		"Specifies the path to the 'hwcrhk' shared library",
164		ENGINE_CMD_FLAG_STRING},
165	{HWCRHK_CMD_FORK_CHECK,
166		"FORK_CHECK",
167		"Turns fork() checking on (non-zero) or off (zero)",
168		ENGINE_CMD_FLAG_NUMERIC},
169	{HWCRHK_CMD_THREAD_LOCKING,
170		"THREAD_LOCKING",
171		"Turns thread-safe locking on (zero) or off (non-zero)",
172		ENGINE_CMD_FLAG_NUMERIC},
173	{HWCRHK_CMD_SET_USER_INTERFACE,
174		"SET_USER_INTERFACE",
175		"Set the global user interface (internal)",
176		ENGINE_CMD_FLAG_INTERNAL},
177	{HWCRHK_CMD_SET_CALLBACK_DATA,
178		"SET_CALLBACK_DATA",
179		"Set the global user interface extra data (internal)",
180		ENGINE_CMD_FLAG_INTERNAL},
181	{0, NULL, NULL, 0}
182	};
183
184#ifndef OPENSSL_NO_RSA
185/* Our internal RSA_METHOD that we provide pointers to */
186static RSA_METHOD hwcrhk_rsa =
187	{
188	"CHIL RSA method",
189	NULL,
190	NULL,
191	NULL,
192	NULL,
193	hwcrhk_rsa_mod_exp,
194	hwcrhk_mod_exp_mont,
195	NULL,
196	NULL,
197	0,
198	NULL,
199	NULL,
200	NULL,
201	NULL
202	};
203#endif
204
205#ifndef OPENSSL_NO_DH
206/* Our internal DH_METHOD that we provide pointers to */
207static DH_METHOD hwcrhk_dh =
208	{
209	"CHIL DH method",
210	NULL,
211	NULL,
212	hwcrhk_mod_exp_dh,
213	NULL,
214	NULL,
215	0,
216	NULL,
217	NULL
218	};
219#endif
220
221static RAND_METHOD hwcrhk_rand =
222	{
223	/* "CHIL RAND method", */
224	NULL,
225	hwcrhk_rand_bytes,
226	NULL,
227	NULL,
228	hwcrhk_rand_bytes,
229	hwcrhk_rand_status,
230	};
231
232/* Constants used when creating the ENGINE */
233static const char *engine_hwcrhk_id = "chil";
234static const char *engine_hwcrhk_name = "CHIL hardware engine support";
235
236#ifndef OPENSSL_NO_DYNAMIC_ENGINE
237/* Compatibility hack, the dynamic library uses this form in the path */
238static const char *engine_hwcrhk_id_alt = "ncipher";
239#endif
240
241/* Internal stuff for HWCryptoHook */
242
243/* Some structures needed for proper use of thread locks */
244/* hwcryptohook.h has some typedefs that turn struct HWCryptoHook_MutexValue
245   into HWCryptoHook_Mutex */
246struct HWCryptoHook_MutexValue
247	{
248	int lockid;
249	};
250
251/* hwcryptohook.h has some typedefs that turn
252   struct HWCryptoHook_PassphraseContextValue
253   into HWCryptoHook_PassphraseContext */
254struct HWCryptoHook_PassphraseContextValue
255	{
256        UI_METHOD *ui_method;
257	void *callback_data;
258	};
259
260/* hwcryptohook.h has some typedefs that turn
261   struct HWCryptoHook_CallerContextValue
262   into HWCryptoHook_CallerContext */
263struct HWCryptoHook_CallerContextValue
264	{
265	pem_password_cb *password_callback; /* Deprecated!  Only present for
266                                               backward compatibility! */
267        UI_METHOD *ui_method;
268	void *callback_data;
269	};
270
271/* The MPI structure in HWCryptoHook is pretty compatible with OpenSSL
272   BIGNUM's, so lets define a couple of conversion macros */
273#define BN2MPI(mp, bn) \
274    {mp.size = bn->top * sizeof(BN_ULONG); mp.buf = (unsigned char *)bn->d;}
275#define MPI2BN(bn, mp) \
276    {mp.size = bn->dmax * sizeof(BN_ULONG); mp.buf = (unsigned char *)bn->d;}
277
278static BIO *logstream = NULL;
279static int disable_mutex_callbacks = 0;
280
281/* One might wonder why these are needed, since one can pass down at least
282   a UI_METHOD and a pointer to callback data to the key-loading functions.
283   The thing is that the ModExp and RSAImmed functions can load keys as well,
284   if the data they get is in a special, nCipher-defined format (hint: if you
285   look at the private exponent of the RSA data as a string, you'll see this
286   string: "nCipher KM tool key id", followed by some bytes, followed a key
287   identity string, followed by more bytes.  This happens when you use "embed"
288   keys instead of "hwcrhk" keys).  Unfortunately, those functions do not take
289   any passphrase or caller context, and our functions can't really take any
290   callback data either.  Still, the "insert_card" and "get_passphrase"
291   callbacks may be called down the line, and will need to know what user
292   interface callbacks to call, and having callback data from the application
293   may be a nice thing as well, so we need to keep track of that globally. */
294static HWCryptoHook_CallerContext password_context = { NULL, NULL, NULL };
295
296/* Stuff to pass to the HWCryptoHook library */
297static HWCryptoHook_InitInfo hwcrhk_globals = {
298	HWCryptoHook_InitFlags_SimpleForkCheck,	/* Flags */
299	&logstream,		/* logstream */
300	sizeof(BN_ULONG),	/* limbsize */
301	0,			/* mslimb first: false for BNs */
302	-1,			/* msbyte first: use native */
303	0,			/* Max mutexes, 0 = no small limit */
304	0,			/* Max simultaneous, 0 = default */
305
306	/* The next few are mutex stuff: we write wrapper functions
307	   around the OS mutex functions.  We initialise them to 0
308	   here, and change that to actual function pointers in hwcrhk_init()
309	   if dynamic locks are supported (that is, if the application
310	   programmer has made sure of setting up callbacks bafore starting
311	   this engine) *and* if disable_mutex_callbacks hasn't been set by
312	   a call to ENGINE_ctrl(ENGINE_CTRL_CHIL_NO_LOCKING). */
313	sizeof(HWCryptoHook_Mutex),
314	0,
315	0,
316	0,
317	0,
318
319	/* The next few are condvar stuff: we write wrapper functions
320	   round the OS functions.  Currently not implemented and not
321	   and absolute necessity even in threaded programs, therefore
322	   0'ed.  Will hopefully be implemented some day, since it
323	   enhances the efficiency of HWCryptoHook.  */
324	0, /* sizeof(HWCryptoHook_CondVar), */
325	0, /* hwcrhk_cv_init, */
326	0, /* hwcrhk_cv_wait, */
327	0, /* hwcrhk_cv_signal, */
328	0, /* hwcrhk_cv_broadcast, */
329	0, /* hwcrhk_cv_destroy, */
330
331	hwcrhk_get_pass,	/* pass phrase */
332	hwcrhk_insert_card,	/* insert a card */
333	hwcrhk_log_message	/* Log message */
334};
335
336
337/* Now, to our own code */
338
339/* This internal function is used by ENGINE_chil() and possibly by the
340 * "dynamic" ENGINE support too */
341static int bind_helper(ENGINE *e)
342	{
343#ifndef OPENSSL_NO_RSA
344	const RSA_METHOD *meth1;
345#endif
346#ifndef OPENSSL_NO_DH
347	const DH_METHOD *meth2;
348#endif
349	if(!ENGINE_set_id(e, engine_hwcrhk_id) ||
350			!ENGINE_set_name(e, engine_hwcrhk_name) ||
351#ifndef OPENSSL_NO_RSA
352			!ENGINE_set_RSA(e, &hwcrhk_rsa) ||
353#endif
354#ifndef OPENSSL_NO_DH
355			!ENGINE_set_DH(e, &hwcrhk_dh) ||
356#endif
357			!ENGINE_set_RAND(e, &hwcrhk_rand) ||
358			!ENGINE_set_destroy_function(e, hwcrhk_destroy) ||
359			!ENGINE_set_init_function(e, hwcrhk_init) ||
360			!ENGINE_set_finish_function(e, hwcrhk_finish) ||
361			!ENGINE_set_ctrl_function(e, hwcrhk_ctrl) ||
362			!ENGINE_set_load_privkey_function(e, hwcrhk_load_privkey) ||
363			!ENGINE_set_load_pubkey_function(e, hwcrhk_load_pubkey) ||
364			!ENGINE_set_cmd_defns(e, hwcrhk_cmd_defns))
365		return 0;
366
367#ifndef OPENSSL_NO_RSA
368	/* We know that the "PKCS1_SSLeay()" functions hook properly
369	 * to the cswift-specific mod_exp and mod_exp_crt so we use
370	 * those functions. NB: We don't use ENGINE_openssl() or
371	 * anything "more generic" because something like the RSAref
372	 * code may not hook properly, and if you own one of these
373	 * cards then you have the right to do RSA operations on it
374	 * anyway! */
375	meth1 = RSA_PKCS1_SSLeay();
376	hwcrhk_rsa.rsa_pub_enc = meth1->rsa_pub_enc;
377	hwcrhk_rsa.rsa_pub_dec = meth1->rsa_pub_dec;
378	hwcrhk_rsa.rsa_priv_enc = meth1->rsa_priv_enc;
379	hwcrhk_rsa.rsa_priv_dec = meth1->rsa_priv_dec;
380#endif
381
382#ifndef OPENSSL_NO_DH
383	/* Much the same for Diffie-Hellman */
384	meth2 = DH_OpenSSL();
385	hwcrhk_dh.generate_key = meth2->generate_key;
386	hwcrhk_dh.compute_key = meth2->compute_key;
387#endif
388
389	/* Ensure the hwcrhk error handling is set up */
390	ERR_load_HWCRHK_strings();
391	return 1;
392	}
393
394#ifdef OPENSSL_NO_DYNAMIC_ENGINE
395static ENGINE *engine_chil(void)
396	{
397	ENGINE *ret = ENGINE_new();
398	if(!ret)
399		return NULL;
400	if(!bind_helper(ret))
401		{
402		ENGINE_free(ret);
403		return NULL;
404		}
405	return ret;
406	}
407
408void ENGINE_load_chil(void)
409	{
410	/* Copied from eng_[openssl|dyn].c */
411	ENGINE *toadd = engine_chil();
412	if(!toadd) return;
413	ENGINE_add(toadd);
414	ENGINE_free(toadd);
415	ERR_clear_error();
416	}
417#endif
418
419/* This is a process-global DSO handle used for loading and unloading
420 * the HWCryptoHook library. NB: This is only set (or unset) during an
421 * init() or finish() call (reference counts permitting) and they're
422 * operating with global locks, so this should be thread-safe
423 * implicitly. */
424static DSO *hwcrhk_dso = NULL;
425static HWCryptoHook_ContextHandle hwcrhk_context = 0;
426#ifndef OPENSSL_NO_RSA
427static int hndidx_rsa = -1;    /* Index for KM handle.  Not really used yet. */
428#endif
429
430/* These are the function pointers that are (un)set when the library has
431 * successfully (un)loaded. */
432static HWCryptoHook_Init_t *p_hwcrhk_Init = NULL;
433static HWCryptoHook_Finish_t *p_hwcrhk_Finish = NULL;
434static HWCryptoHook_ModExp_t *p_hwcrhk_ModExp = NULL;
435#ifndef OPENSSL_NO_RSA
436static HWCryptoHook_RSA_t *p_hwcrhk_RSA = NULL;
437#endif
438static HWCryptoHook_RandomBytes_t *p_hwcrhk_RandomBytes = NULL;
439#ifndef OPENSSL_NO_RSA
440static HWCryptoHook_RSALoadKey_t *p_hwcrhk_RSALoadKey = NULL;
441static HWCryptoHook_RSAGetPublicKey_t *p_hwcrhk_RSAGetPublicKey = NULL;
442static HWCryptoHook_RSAUnloadKey_t *p_hwcrhk_RSAUnloadKey = NULL;
443#endif
444static HWCryptoHook_ModExpCRT_t *p_hwcrhk_ModExpCRT = NULL;
445
446/* Used in the DSO operations. */
447static const char *HWCRHK_LIBNAME = NULL;
448static void free_HWCRHK_LIBNAME(void)
449	{
450	if(HWCRHK_LIBNAME)
451		OPENSSL_free((void*)HWCRHK_LIBNAME);
452	HWCRHK_LIBNAME = NULL;
453	}
454static const char *get_HWCRHK_LIBNAME(void)
455	{
456	if(HWCRHK_LIBNAME)
457		return HWCRHK_LIBNAME;
458	return "nfhwcrhk";
459	}
460static long set_HWCRHK_LIBNAME(const char *name)
461	{
462	free_HWCRHK_LIBNAME();
463	return (((HWCRHK_LIBNAME = BUF_strdup(name)) != NULL) ? 1 : 0);
464	}
465static const char *n_hwcrhk_Init = "HWCryptoHook_Init";
466static const char *n_hwcrhk_Finish = "HWCryptoHook_Finish";
467static const char *n_hwcrhk_ModExp = "HWCryptoHook_ModExp";
468#ifndef OPENSSL_NO_RSA
469static const char *n_hwcrhk_RSA = "HWCryptoHook_RSA";
470#endif
471static const char *n_hwcrhk_RandomBytes = "HWCryptoHook_RandomBytes";
472#ifndef OPENSSL_NO_RSA
473static const char *n_hwcrhk_RSALoadKey = "HWCryptoHook_RSALoadKey";
474static const char *n_hwcrhk_RSAGetPublicKey = "HWCryptoHook_RSAGetPublicKey";
475static const char *n_hwcrhk_RSAUnloadKey = "HWCryptoHook_RSAUnloadKey";
476#endif
477static const char *n_hwcrhk_ModExpCRT = "HWCryptoHook_ModExpCRT";
478
479/* HWCryptoHook library functions and mechanics - these are used by the
480 * higher-level functions further down. NB: As and where there's no
481 * error checking, take a look lower down where these functions are
482 * called, the checking and error handling is probably down there. */
483
484/* utility function to obtain a context */
485static int get_context(HWCryptoHook_ContextHandle *hac,
486        HWCryptoHook_CallerContext *cac)
487	{
488	char tempbuf[1024];
489	HWCryptoHook_ErrMsgBuf rmsg;
490
491	rmsg.buf = tempbuf;
492	rmsg.size = sizeof(tempbuf);
493
494        *hac = p_hwcrhk_Init(&hwcrhk_globals, sizeof(hwcrhk_globals), &rmsg,
495		cac);
496	if (!*hac)
497                return 0;
498        return 1;
499	}
500
501/* similarly to release one. */
502static void release_context(HWCryptoHook_ContextHandle hac)
503	{
504	p_hwcrhk_Finish(hac);
505	}
506
507/* Destructor (complements the "ENGINE_chil()" constructor) */
508static int hwcrhk_destroy(ENGINE *e)
509	{
510	free_HWCRHK_LIBNAME();
511	ERR_unload_HWCRHK_strings();
512	return 1;
513	}
514
515/* (de)initialisation functions. */
516static int hwcrhk_init(ENGINE *e)
517	{
518	HWCryptoHook_Init_t *p1;
519	HWCryptoHook_Finish_t *p2;
520	HWCryptoHook_ModExp_t *p3;
521#ifndef OPENSSL_NO_RSA
522	HWCryptoHook_RSA_t *p4;
523	HWCryptoHook_RSALoadKey_t *p5;
524	HWCryptoHook_RSAGetPublicKey_t *p6;
525	HWCryptoHook_RSAUnloadKey_t *p7;
526#endif
527	HWCryptoHook_RandomBytes_t *p8;
528	HWCryptoHook_ModExpCRT_t *p9;
529
530	if(hwcrhk_dso != NULL)
531		{
532		HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_ALREADY_LOADED);
533		goto err;
534		}
535	/* Attempt to load libnfhwcrhk.so/nfhwcrhk.dll/whatever. */
536	hwcrhk_dso = DSO_load(NULL, get_HWCRHK_LIBNAME(), NULL, 0);
537	if(hwcrhk_dso == NULL)
538		{
539		HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_DSO_FAILURE);
540		goto err;
541		}
542	if(!(p1 = (HWCryptoHook_Init_t *)
543			DSO_bind_func(hwcrhk_dso, n_hwcrhk_Init)) ||
544		!(p2 = (HWCryptoHook_Finish_t *)
545			DSO_bind_func(hwcrhk_dso, n_hwcrhk_Finish)) ||
546		!(p3 = (HWCryptoHook_ModExp_t *)
547			DSO_bind_func(hwcrhk_dso, n_hwcrhk_ModExp)) ||
548#ifndef OPENSSL_NO_RSA
549		!(p4 = (HWCryptoHook_RSA_t *)
550			DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSA)) ||
551		!(p5 = (HWCryptoHook_RSALoadKey_t *)
552			DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSALoadKey)) ||
553		!(p6 = (HWCryptoHook_RSAGetPublicKey_t *)
554			DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSAGetPublicKey)) ||
555		!(p7 = (HWCryptoHook_RSAUnloadKey_t *)
556			DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSAUnloadKey)) ||
557#endif
558		!(p8 = (HWCryptoHook_RandomBytes_t *)
559			DSO_bind_func(hwcrhk_dso, n_hwcrhk_RandomBytes)) ||
560		!(p9 = (HWCryptoHook_ModExpCRT_t *)
561			DSO_bind_func(hwcrhk_dso, n_hwcrhk_ModExpCRT)))
562		{
563		HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_DSO_FAILURE);
564		goto err;
565		}
566	/* Copy the pointers */
567	p_hwcrhk_Init = p1;
568	p_hwcrhk_Finish = p2;
569	p_hwcrhk_ModExp = p3;
570#ifndef OPENSSL_NO_RSA
571	p_hwcrhk_RSA = p4;
572	p_hwcrhk_RSALoadKey = p5;
573	p_hwcrhk_RSAGetPublicKey = p6;
574	p_hwcrhk_RSAUnloadKey = p7;
575#endif
576	p_hwcrhk_RandomBytes = p8;
577	p_hwcrhk_ModExpCRT = p9;
578
579	/* Check if the application decided to support dynamic locks,
580	   and if it does, use them. */
581	if (disable_mutex_callbacks == 0)
582		{
583		if (CRYPTO_get_dynlock_create_callback() != NULL &&
584			CRYPTO_get_dynlock_lock_callback() != NULL &&
585			CRYPTO_get_dynlock_destroy_callback() != NULL)
586			{
587			hwcrhk_globals.mutex_init = hwcrhk_mutex_init;
588			hwcrhk_globals.mutex_acquire = hwcrhk_mutex_lock;
589			hwcrhk_globals.mutex_release = hwcrhk_mutex_unlock;
590			hwcrhk_globals.mutex_destroy = hwcrhk_mutex_destroy;
591			}
592		}
593
594	/* Try and get a context - if not, we may have a DSO but no
595	 * accelerator! */
596	if(!get_context(&hwcrhk_context, &password_context))
597		{
598		HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_UNIT_FAILURE);
599		goto err;
600		}
601	/* Everything's fine. */
602#ifndef OPENSSL_NO_RSA
603	if (hndidx_rsa == -1)
604		hndidx_rsa = RSA_get_ex_new_index(0,
605			"nFast HWCryptoHook RSA key handle",
606			NULL, NULL, hwcrhk_ex_free);
607#endif
608	return 1;
609err:
610	if(hwcrhk_dso)
611		DSO_free(hwcrhk_dso);
612	hwcrhk_dso = NULL;
613	p_hwcrhk_Init = NULL;
614	p_hwcrhk_Finish = NULL;
615	p_hwcrhk_ModExp = NULL;
616#ifndef OPENSSL_NO_RSA
617	p_hwcrhk_RSA = NULL;
618	p_hwcrhk_RSALoadKey = NULL;
619	p_hwcrhk_RSAGetPublicKey = NULL;
620	p_hwcrhk_RSAUnloadKey = NULL;
621#endif
622	p_hwcrhk_ModExpCRT = NULL;
623	p_hwcrhk_RandomBytes = NULL;
624	return 0;
625	}
626
627static int hwcrhk_finish(ENGINE *e)
628	{
629	int to_return = 1;
630	free_HWCRHK_LIBNAME();
631	if(hwcrhk_dso == NULL)
632		{
633		HWCRHKerr(HWCRHK_F_HWCRHK_FINISH,HWCRHK_R_NOT_LOADED);
634		to_return = 0;
635		goto err;
636		}
637	release_context(hwcrhk_context);
638	if(!DSO_free(hwcrhk_dso))
639		{
640		HWCRHKerr(HWCRHK_F_HWCRHK_FINISH,HWCRHK_R_DSO_FAILURE);
641		to_return = 0;
642		goto err;
643		}
644 err:
645	if (logstream)
646		BIO_free(logstream);
647	hwcrhk_dso = NULL;
648	p_hwcrhk_Init = NULL;
649	p_hwcrhk_Finish = NULL;
650	p_hwcrhk_ModExp = NULL;
651#ifndef OPENSSL_NO_RSA
652	p_hwcrhk_RSA = NULL;
653	p_hwcrhk_RSALoadKey = NULL;
654	p_hwcrhk_RSAGetPublicKey = NULL;
655	p_hwcrhk_RSAUnloadKey = NULL;
656#endif
657	p_hwcrhk_ModExpCRT = NULL;
658	p_hwcrhk_RandomBytes = NULL;
659	return to_return;
660	}
661
662static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void))
663	{
664	int to_return = 1;
665
666	switch(cmd)
667		{
668	case HWCRHK_CMD_SO_PATH:
669		if(hwcrhk_dso)
670			{
671			HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,HWCRHK_R_ALREADY_LOADED);
672			return 0;
673			}
674		if(p == NULL)
675			{
676			HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,ERR_R_PASSED_NULL_PARAMETER);
677			return 0;
678			}
679		return set_HWCRHK_LIBNAME((const char *)p);
680	case ENGINE_CTRL_SET_LOGSTREAM:
681		{
682		BIO *bio = (BIO *)p;
683
684		CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
685		if (logstream)
686			{
687			BIO_free(logstream);
688			logstream = NULL;
689			}
690		if (CRYPTO_add(&bio->references,1,CRYPTO_LOCK_BIO) > 1)
691			logstream = bio;
692		else
693			HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,HWCRHK_R_BIO_WAS_FREED);
694		}
695		CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
696		break;
697	case ENGINE_CTRL_SET_PASSWORD_CALLBACK:
698		CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
699		password_context.password_callback = (pem_password_cb *)f;
700		CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
701		break;
702	case ENGINE_CTRL_SET_USER_INTERFACE:
703	case HWCRHK_CMD_SET_USER_INTERFACE:
704		CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
705		password_context.ui_method = (UI_METHOD *)p;
706		CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
707		break;
708	case ENGINE_CTRL_SET_CALLBACK_DATA:
709	case HWCRHK_CMD_SET_CALLBACK_DATA:
710		CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
711		password_context.callback_data = p;
712		CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
713		break;
714	/* this enables or disables the "SimpleForkCheck" flag used in the
715	 * initialisation structure. */
716	case ENGINE_CTRL_CHIL_SET_FORKCHECK:
717	case HWCRHK_CMD_FORK_CHECK:
718		CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
719		if(i)
720			hwcrhk_globals.flags |=
721				HWCryptoHook_InitFlags_SimpleForkCheck;
722		else
723			hwcrhk_globals.flags &=
724				~HWCryptoHook_InitFlags_SimpleForkCheck;
725		CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
726		break;
727	/* This will prevent the initialisation function from "installing"
728	 * the mutex-handling callbacks, even if they are available from
729	 * within the library (or were provided to the library from the
730	 * calling application). This is to remove any baggage for
731	 * applications not using multithreading. */
732	case ENGINE_CTRL_CHIL_NO_LOCKING:
733		CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
734		disable_mutex_callbacks = 1;
735		CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
736		break;
737	case HWCRHK_CMD_THREAD_LOCKING:
738		CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
739		disable_mutex_callbacks = ((i == 0) ? 0 : 1);
740		CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
741		break;
742
743	/* The command isn't understood by this engine */
744	default:
745		HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,
746			HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
747		to_return = 0;
748		break;
749		}
750
751	return to_return;
752	}
753
754static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
755	UI_METHOD *ui_method, void *callback_data)
756	{
757#ifndef OPENSSL_NO_RSA
758	RSA *rtmp = NULL;
759#endif
760	EVP_PKEY *res = NULL;
761#ifndef OPENSSL_NO_RSA
762	HWCryptoHook_MPI e, n;
763	HWCryptoHook_RSAKeyHandle *hptr;
764#endif
765#if !defined(OPENSSL_NO_RSA)
766	char tempbuf[1024];
767	HWCryptoHook_ErrMsgBuf rmsg;
768	HWCryptoHook_PassphraseContext ppctx;
769#endif
770
771#if !defined(OPENSSL_NO_RSA)
772	rmsg.buf = tempbuf;
773	rmsg.size = sizeof(tempbuf);
774#endif
775
776	if(!hwcrhk_context)
777		{
778		HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
779			HWCRHK_R_NOT_INITIALISED);
780		goto err;
781		}
782#ifndef OPENSSL_NO_RSA
783	hptr = OPENSSL_malloc(sizeof(HWCryptoHook_RSAKeyHandle));
784	if (!hptr)
785		{
786		HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
787			ERR_R_MALLOC_FAILURE);
788		goto err;
789		}
790        ppctx.ui_method = ui_method;
791	ppctx.callback_data = callback_data;
792	if (p_hwcrhk_RSALoadKey(hwcrhk_context, key_id, hptr,
793		&rmsg, &ppctx))
794		{
795		HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
796			HWCRHK_R_CHIL_ERROR);
797		ERR_add_error_data(1,rmsg.buf);
798		goto err;
799		}
800	if (!*hptr)
801		{
802		HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
803			HWCRHK_R_NO_KEY);
804		goto err;
805		}
806#endif
807#ifndef OPENSSL_NO_RSA
808	rtmp = RSA_new_method(eng);
809	RSA_set_ex_data(rtmp, hndidx_rsa, (char *)hptr);
810	rtmp->e = BN_new();
811	rtmp->n = BN_new();
812	rtmp->flags |= RSA_FLAG_EXT_PKEY;
813	MPI2BN(rtmp->e, e);
814	MPI2BN(rtmp->n, n);
815	if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg)
816		!= HWCRYPTOHOOK_ERROR_MPISIZE)
817		{
818		HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,HWCRHK_R_CHIL_ERROR);
819		ERR_add_error_data(1,rmsg.buf);
820		goto err;
821		}
822
823	bn_expand2(rtmp->e, e.size/sizeof(BN_ULONG));
824	bn_expand2(rtmp->n, n.size/sizeof(BN_ULONG));
825	MPI2BN(rtmp->e, e);
826	MPI2BN(rtmp->n, n);
827
828	if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg))
829		{
830		HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
831			HWCRHK_R_CHIL_ERROR);
832		ERR_add_error_data(1,rmsg.buf);
833		goto err;
834		}
835	rtmp->e->top = e.size / sizeof(BN_ULONG);
836	bn_fix_top(rtmp->e);
837	rtmp->n->top = n.size / sizeof(BN_ULONG);
838	bn_fix_top(rtmp->n);
839
840	res = EVP_PKEY_new();
841	EVP_PKEY_assign_RSA(res, rtmp);
842#endif
843
844        if (!res)
845                HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
846                        HWCRHK_R_PRIVATE_KEY_ALGORITHMS_DISABLED);
847
848	return res;
849 err:
850	if (res)
851		EVP_PKEY_free(res);
852#ifndef OPENSSL_NO_RSA
853	if (rtmp)
854		RSA_free(rtmp);
855#endif
856	return NULL;
857	}
858
859static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
860	UI_METHOD *ui_method, void *callback_data)
861	{
862	EVP_PKEY *res = NULL;
863
864#ifndef OPENSSL_NO_RSA
865        res = hwcrhk_load_privkey(eng, key_id,
866                ui_method, callback_data);
867#endif
868
869	if (res)
870		switch(res->type)
871			{
872#ifndef OPENSSL_NO_RSA
873		case EVP_PKEY_RSA:
874			{
875			RSA *rsa = NULL;
876
877			CRYPTO_w_lock(CRYPTO_LOCK_EVP_PKEY);
878			rsa = res->pkey.rsa;
879			res->pkey.rsa = RSA_new();
880			res->pkey.rsa->n = rsa->n;
881			res->pkey.rsa->e = rsa->e;
882			rsa->n = NULL;
883			rsa->e = NULL;
884			CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY);
885			RSA_free(rsa);
886			}
887			break;
888#endif
889		default:
890			HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
891				HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
892			goto err;
893			}
894
895	return res;
896 err:
897	if (res)
898		EVP_PKEY_free(res);
899	return NULL;
900	}
901
902/* A little mod_exp */
903static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
904			const BIGNUM *m, BN_CTX *ctx)
905	{
906	char tempbuf[1024];
907	HWCryptoHook_ErrMsgBuf rmsg;
908	/* Since HWCryptoHook_MPI is pretty compatible with BIGNUM's,
909	   we use them directly, plus a little macro magic.  We only
910	   thing we need to make sure of is that enough space is allocated. */
911	HWCryptoHook_MPI m_a, m_p, m_n, m_r;
912	int to_return, ret;
913
914	to_return = 0; /* expect failure */
915	rmsg.buf = tempbuf;
916	rmsg.size = sizeof(tempbuf);
917
918	if(!hwcrhk_context)
919		{
920		HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_NOT_INITIALISED);
921		goto err;
922		}
923	/* Prepare the params */
924	bn_expand2(r, m->top);	/* Check for error !! */
925	BN2MPI(m_a, a);
926	BN2MPI(m_p, p);
927	BN2MPI(m_n, m);
928	MPI2BN(r, m_r);
929
930	/* Perform the operation */
931	ret = p_hwcrhk_ModExp(hwcrhk_context, m_a, m_p, m_n, &m_r, &rmsg);
932
933	/* Convert the response */
934	r->top = m_r.size / sizeof(BN_ULONG);
935	bn_fix_top(r);
936
937	if (ret < 0)
938		{
939		/* FIXME: When this error is returned, HWCryptoHook is
940		   telling us that falling back to software computation
941		   might be a good thing. */
942		if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
943			{
944			HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_REQUEST_FALLBACK);
945			}
946		else
947			{
948			HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_REQUEST_FAILED);
949			}
950		ERR_add_error_data(1,rmsg.buf);
951		goto err;
952		}
953
954	to_return = 1;
955err:
956	return to_return;
957	}
958
959#ifndef OPENSSL_NO_RSA
960static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
961	{
962	char tempbuf[1024];
963	HWCryptoHook_ErrMsgBuf rmsg;
964	HWCryptoHook_RSAKeyHandle *hptr;
965	int to_return = 0, ret;
966
967	rmsg.buf = tempbuf;
968	rmsg.size = sizeof(tempbuf);
969
970	if(!hwcrhk_context)
971		{
972		HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,HWCRHK_R_NOT_INITIALISED);
973		goto err;
974		}
975
976	/* This provides support for nForce keys.  Since that's opaque data
977	   all we do is provide a handle to the proper key and let HWCryptoHook
978	   take care of the rest. */
979	if ((hptr = (HWCryptoHook_RSAKeyHandle *) RSA_get_ex_data(rsa, hndidx_rsa))
980		!= NULL)
981		{
982		HWCryptoHook_MPI m_a, m_r;
983
984		if(!rsa->n)
985			{
986			HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
987				HWCRHK_R_MISSING_KEY_COMPONENTS);
988			goto err;
989			}
990
991		/* Prepare the params */
992		bn_expand2(r, rsa->n->top); /* Check for error !! */
993		BN2MPI(m_a, I);
994		MPI2BN(r, m_r);
995
996		/* Perform the operation */
997		ret = p_hwcrhk_RSA(m_a, *hptr, &m_r, &rmsg);
998
999		/* Convert the response */
1000		r->top = m_r.size / sizeof(BN_ULONG);
1001		bn_fix_top(r);
1002
1003		if (ret < 0)
1004			{
1005			/* FIXME: When this error is returned, HWCryptoHook is
1006			   telling us that falling back to software computation
1007			   might be a good thing. */
1008			if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1009				{
1010				HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1011					HWCRHK_R_REQUEST_FALLBACK);
1012				}
1013			else
1014				{
1015				HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1016					HWCRHK_R_REQUEST_FAILED);
1017				}
1018			ERR_add_error_data(1,rmsg.buf);
1019			goto err;
1020			}
1021		}
1022	else
1023		{
1024		HWCryptoHook_MPI m_a, m_p, m_q, m_dmp1, m_dmq1, m_iqmp, m_r;
1025
1026		if(!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp)
1027			{
1028			HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1029				HWCRHK_R_MISSING_KEY_COMPONENTS);
1030			goto err;
1031			}
1032
1033		/* Prepare the params */
1034		bn_expand2(r, rsa->n->top); /* Check for error !! */
1035		BN2MPI(m_a, I);
1036		BN2MPI(m_p, rsa->p);
1037		BN2MPI(m_q, rsa->q);
1038		BN2MPI(m_dmp1, rsa->dmp1);
1039		BN2MPI(m_dmq1, rsa->dmq1);
1040		BN2MPI(m_iqmp, rsa->iqmp);
1041		MPI2BN(r, m_r);
1042
1043		/* Perform the operation */
1044		ret = p_hwcrhk_ModExpCRT(hwcrhk_context, m_a, m_p, m_q,
1045			m_dmp1, m_dmq1, m_iqmp, &m_r, &rmsg);
1046
1047		/* Convert the response */
1048		r->top = m_r.size / sizeof(BN_ULONG);
1049		bn_fix_top(r);
1050
1051		if (ret < 0)
1052			{
1053			/* FIXME: When this error is returned, HWCryptoHook is
1054			   telling us that falling back to software computation
1055			   might be a good thing. */
1056			if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1057				{
1058				HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1059					HWCRHK_R_REQUEST_FALLBACK);
1060				}
1061			else
1062				{
1063				HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1064					HWCRHK_R_REQUEST_FAILED);
1065				}
1066			ERR_add_error_data(1,rmsg.buf);
1067			goto err;
1068			}
1069		}
1070	/* If we're here, we must be here with some semblance of success :-) */
1071	to_return = 1;
1072err:
1073	return to_return;
1074	}
1075#endif
1076
1077#ifndef OPENSSL_NO_RSA
1078/* This function is aliased to mod_exp (with the mont stuff dropped). */
1079static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
1080		const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1081	{
1082	return hwcrhk_mod_exp(r, a, p, m, ctx);
1083	}
1084#endif
1085
1086#ifndef OPENSSL_NO_DH
1087/* This function is aliased to mod_exp (with the dh and mont dropped). */
1088static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r,
1089		const BIGNUM *a, const BIGNUM *p,
1090		const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1091	{
1092	return hwcrhk_mod_exp(r, a, p, m, ctx);
1093	}
1094#endif
1095
1096/* Random bytes are good */
1097static int hwcrhk_rand_bytes(unsigned char *buf, int num)
1098	{
1099	char tempbuf[1024];
1100	HWCryptoHook_ErrMsgBuf rmsg;
1101	int to_return = 0; /* assume failure */
1102	int ret;
1103
1104	rmsg.buf = tempbuf;
1105	rmsg.size = sizeof(tempbuf);
1106
1107	if(!hwcrhk_context)
1108		{
1109		HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,HWCRHK_R_NOT_INITIALISED);
1110		goto err;
1111		}
1112
1113	ret = p_hwcrhk_RandomBytes(hwcrhk_context, buf, num, &rmsg);
1114	if (ret < 0)
1115		{
1116		/* FIXME: When this error is returned, HWCryptoHook is
1117		   telling us that falling back to software computation
1118		   might be a good thing. */
1119		if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1120			{
1121			HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,
1122				HWCRHK_R_REQUEST_FALLBACK);
1123			}
1124		else
1125			{
1126			HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,
1127				HWCRHK_R_REQUEST_FAILED);
1128			}
1129		ERR_add_error_data(1,rmsg.buf);
1130		goto err;
1131		}
1132	to_return = 1;
1133 err:
1134	return to_return;
1135	}
1136
1137static int hwcrhk_rand_status(void)
1138	{
1139	return 1;
1140	}
1141
1142/* This cleans up an RSA KM key, called when ex_data is freed */
1143#ifndef OPENSSL_NO_RSA
1144static void hwcrhk_ex_free(void *obj, void *item, CRYPTO_EX_DATA *ad,
1145	int ind,long argl, void *argp)
1146{
1147	char tempbuf[1024];
1148	HWCryptoHook_ErrMsgBuf rmsg;
1149#ifndef OPENSSL_NO_RSA
1150	HWCryptoHook_RSAKeyHandle *hptr;
1151#endif
1152#if !defined(OPENSSL_NO_RSA)
1153	int ret;
1154#endif
1155
1156	rmsg.buf = tempbuf;
1157	rmsg.size = sizeof(tempbuf);
1158
1159#ifndef OPENSSL_NO_RSA
1160	hptr = (HWCryptoHook_RSAKeyHandle *) item;
1161	if(hptr)
1162                {
1163                ret = p_hwcrhk_RSAUnloadKey(*hptr, NULL);
1164                OPENSSL_free(hptr);
1165                }
1166#endif
1167}
1168#endif
1169
1170/* Mutex calls: since the HWCryptoHook model closely follows the POSIX model
1171 * these just wrap the POSIX functions and add some logging.
1172 */
1173
1174static int hwcrhk_mutex_init(HWCryptoHook_Mutex* mt,
1175	HWCryptoHook_CallerContext *cactx)
1176	{
1177	mt->lockid = CRYPTO_get_new_dynlockid();
1178	if (mt->lockid == 0)
1179		return 1; /* failure */
1180	return 0; /* success */
1181	}
1182
1183static int hwcrhk_mutex_lock(HWCryptoHook_Mutex *mt)
1184	{
1185	CRYPTO_w_lock(mt->lockid);
1186	return 0;
1187	}
1188
1189static void hwcrhk_mutex_unlock(HWCryptoHook_Mutex * mt)
1190	{
1191	CRYPTO_w_unlock(mt->lockid);
1192	}
1193
1194static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex *mt)
1195	{
1196	CRYPTO_destroy_dynlockid(mt->lockid);
1197	}
1198
1199static int hwcrhk_get_pass(const char *prompt_info,
1200	int *len_io, char *buf,
1201	HWCryptoHook_PassphraseContext *ppctx,
1202	HWCryptoHook_CallerContext *cactx)
1203	{
1204	pem_password_cb *callback = NULL;
1205	void *callback_data = NULL;
1206        UI_METHOD *ui_method = NULL;
1207	/* Despite what the documentation says prompt_info can be
1208	 * an empty string.
1209	 */
1210	if (prompt_info && !*prompt_info)
1211		prompt_info = NULL;
1212
1213        if (cactx)
1214                {
1215                if (cactx->ui_method)
1216                        ui_method = cactx->ui_method;
1217		if (cactx->password_callback)
1218			callback = cactx->password_callback;
1219		if (cactx->callback_data)
1220			callback_data = cactx->callback_data;
1221                }
1222	if (ppctx)
1223		{
1224                if (ppctx->ui_method)
1225                        {
1226                        ui_method = ppctx->ui_method;
1227                        callback = NULL;
1228                        }
1229		if (ppctx->callback_data)
1230			callback_data = ppctx->callback_data;
1231		}
1232	if (callback == NULL && ui_method == NULL)
1233		{
1234		HWCRHKerr(HWCRHK_F_HWCRHK_GET_PASS,HWCRHK_R_NO_CALLBACK);
1235		return -1;
1236		}
1237
1238        if (ui_method)
1239                {
1240                UI *ui = UI_new_method(ui_method);
1241                if (ui)
1242                        {
1243                        int ok;
1244                        char *prompt = UI_construct_prompt(ui,
1245                                "pass phrase", prompt_info);
1246
1247                        ok = UI_add_input_string(ui,prompt,
1248                                UI_INPUT_FLAG_DEFAULT_PWD,
1249				buf,0,(*len_io) - 1);
1250                        UI_add_user_data(ui, callback_data);
1251			UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0);
1252
1253			if (ok >= 0)
1254				do
1255					{
1256					ok=UI_process(ui);
1257					}
1258				while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0));
1259
1260                        if (ok >= 0)
1261                                *len_io = strlen(buf);
1262
1263                        UI_free(ui);
1264                        OPENSSL_free(prompt);
1265                        }
1266                }
1267        else
1268                {
1269                *len_io = callback(buf, *len_io, 0, callback_data);
1270                }
1271	if(!*len_io)
1272		return -1;
1273	return 0;
1274	}
1275
1276static int hwcrhk_insert_card(const char *prompt_info,
1277		      const char *wrong_info,
1278		      HWCryptoHook_PassphraseContext *ppctx,
1279		      HWCryptoHook_CallerContext *cactx)
1280        {
1281        int ok = -1;
1282        UI *ui;
1283	void *callback_data = NULL;
1284        UI_METHOD *ui_method = NULL;
1285
1286        if (cactx)
1287                {
1288                if (cactx->ui_method)
1289                        ui_method = cactx->ui_method;
1290		if (cactx->callback_data)
1291			callback_data = cactx->callback_data;
1292                }
1293	if (ppctx)
1294		{
1295                if (ppctx->ui_method)
1296                        ui_method = ppctx->ui_method;
1297		if (ppctx->callback_data)
1298			callback_data = ppctx->callback_data;
1299		}
1300	if (ui_method == NULL)
1301		{
1302		HWCRHKerr(HWCRHK_F_HWCRHK_INSERT_CARD,
1303			HWCRHK_R_NO_CALLBACK);
1304		return -1;
1305		}
1306
1307	ui = UI_new_method(ui_method);
1308
1309	if (ui)
1310		{
1311		char answer;
1312		char buf[BUFSIZ];
1313		/* Despite what the documentation says wrong_info can be
1314	 	 * an empty string.
1315		 */
1316		if (wrong_info && *wrong_info)
1317			BIO_snprintf(buf, sizeof(buf)-1,
1318				"Current card: \"%s\"\n", wrong_info);
1319		ok = UI_dup_info_string(ui, buf);
1320		if (ok >= 0 && prompt_info)
1321			{
1322			BIO_snprintf(buf, sizeof(buf)-1,
1323				"Insert card \"%s\"", prompt_info);
1324			ok = UI_dup_input_boolean(ui, buf,
1325				"\n then hit <enter> or C<enter> to cancel\n",
1326				"\r\n", "Cc", UI_INPUT_FLAG_ECHO, &answer);
1327			}
1328		UI_add_user_data(ui, callback_data);
1329
1330		if (ok >= 0)
1331			ok = UI_process(ui);
1332		UI_free(ui);
1333
1334		if (ok == -2 || (ok >= 0 && answer == 'C'))
1335			ok = 1;
1336		else if (ok < 0)
1337			ok = -1;
1338		else
1339			ok = 0;
1340		}
1341	return ok;
1342	}
1343
1344static void hwcrhk_log_message(void *logstr, const char *message)
1345	{
1346	BIO *lstream = NULL;
1347
1348	CRYPTO_w_lock(CRYPTO_LOCK_BIO);
1349	if (logstr)
1350		lstream=*(BIO **)logstr;
1351	if (lstream)
1352		{
1353		BIO_printf(lstream, "%s\n", message);
1354		}
1355	CRYPTO_w_unlock(CRYPTO_LOCK_BIO);
1356	}
1357
1358/* This stuff is needed if this ENGINE is being compiled into a self-contained
1359 * shared-library. */
1360#ifndef OPENSSL_NO_DYNAMIC_ENGINE
1361static int bind_fn(ENGINE *e, const char *id)
1362	{
1363	if(id && (strcmp(id, engine_hwcrhk_id) != 0) &&
1364			(strcmp(id, engine_hwcrhk_id_alt) != 0))
1365		return 0;
1366	if(!bind_helper(e))
1367		return 0;
1368	return 1;
1369	}
1370IMPLEMENT_DYNAMIC_CHECK_FN()
1371IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
1372#endif /* OPENSSL_NO_DYNAMIC_ENGINE */
1373
1374#endif /* !OPENSSL_NO_HW_CHIL */
1375#endif /* !OPENSSL_NO_HW */
1376