e_chil.c revision 160814
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 (shenson@bigfoot.com)
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 or off (boolean)",
168		ENGINE_CMD_FLAG_NUMERIC},
169	{HWCRHK_CMD_THREAD_LOCKING,
170		"THREAD_LOCKING",
171		"Turns thread-safe locking on or off (boolean)",
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		else if (CRYPTO_get_locking_callback() != NULL)
593			{
594			HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_LOCKING_MISSING);
595			ERR_add_error_data(1,"You HAVE to add dynamic locking callbacks via CRYPTO_set_dynlock_{create,lock,destroy}_callback()");
596			goto err;
597			}
598		}
599
600	/* Try and get a context - if not, we may have a DSO but no
601	 * accelerator! */
602	if(!get_context(&hwcrhk_context, &password_context))
603		{
604		HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_UNIT_FAILURE);
605		goto err;
606		}
607	/* Everything's fine. */
608#ifndef OPENSSL_NO_RSA
609	if (hndidx_rsa == -1)
610		hndidx_rsa = RSA_get_ex_new_index(0,
611			"nFast HWCryptoHook RSA key handle",
612			NULL, NULL, hwcrhk_ex_free);
613#endif
614	return 1;
615err:
616	if(hwcrhk_dso)
617		DSO_free(hwcrhk_dso);
618	hwcrhk_dso = NULL;
619	p_hwcrhk_Init = NULL;
620	p_hwcrhk_Finish = NULL;
621	p_hwcrhk_ModExp = NULL;
622#ifndef OPENSSL_NO_RSA
623	p_hwcrhk_RSA = NULL;
624	p_hwcrhk_RSALoadKey = NULL;
625	p_hwcrhk_RSAGetPublicKey = NULL;
626	p_hwcrhk_RSAUnloadKey = NULL;
627#endif
628	p_hwcrhk_ModExpCRT = NULL;
629	p_hwcrhk_RandomBytes = NULL;
630	return 0;
631	}
632
633static int hwcrhk_finish(ENGINE *e)
634	{
635	int to_return = 1;
636	free_HWCRHK_LIBNAME();
637	if(hwcrhk_dso == NULL)
638		{
639		HWCRHKerr(HWCRHK_F_HWCRHK_FINISH,HWCRHK_R_NOT_LOADED);
640		to_return = 0;
641		goto err;
642		}
643	release_context(hwcrhk_context);
644	if(!DSO_free(hwcrhk_dso))
645		{
646		HWCRHKerr(HWCRHK_F_HWCRHK_FINISH,HWCRHK_R_DSO_FAILURE);
647		to_return = 0;
648		goto err;
649		}
650 err:
651	if (logstream)
652		BIO_free(logstream);
653	hwcrhk_dso = NULL;
654	p_hwcrhk_Init = NULL;
655	p_hwcrhk_Finish = NULL;
656	p_hwcrhk_ModExp = NULL;
657#ifndef OPENSSL_NO_RSA
658	p_hwcrhk_RSA = NULL;
659	p_hwcrhk_RSALoadKey = NULL;
660	p_hwcrhk_RSAGetPublicKey = NULL;
661	p_hwcrhk_RSAUnloadKey = NULL;
662#endif
663	p_hwcrhk_ModExpCRT = NULL;
664	p_hwcrhk_RandomBytes = NULL;
665	return to_return;
666	}
667
668static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void))
669	{
670	int to_return = 1;
671
672	switch(cmd)
673		{
674	case HWCRHK_CMD_SO_PATH:
675		if(hwcrhk_dso)
676			{
677			HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,HWCRHK_R_ALREADY_LOADED);
678			return 0;
679			}
680		if(p == NULL)
681			{
682			HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,ERR_R_PASSED_NULL_PARAMETER);
683			return 0;
684			}
685		return set_HWCRHK_LIBNAME((const char *)p);
686	case ENGINE_CTRL_SET_LOGSTREAM:
687		{
688		BIO *bio = (BIO *)p;
689
690		CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
691		if (logstream)
692			{
693			BIO_free(logstream);
694			logstream = NULL;
695			}
696		if (CRYPTO_add(&bio->references,1,CRYPTO_LOCK_BIO) > 1)
697			logstream = bio;
698		else
699			HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,HWCRHK_R_BIO_WAS_FREED);
700		}
701		CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
702		break;
703	case ENGINE_CTRL_SET_PASSWORD_CALLBACK:
704		CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
705		password_context.password_callback = (pem_password_cb *)f;
706		CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
707		break;
708	case ENGINE_CTRL_SET_USER_INTERFACE:
709	case HWCRHK_CMD_SET_USER_INTERFACE:
710		CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
711		password_context.ui_method = (UI_METHOD *)p;
712		CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
713		break;
714	case ENGINE_CTRL_SET_CALLBACK_DATA:
715	case HWCRHK_CMD_SET_CALLBACK_DATA:
716		CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
717		password_context.callback_data = p;
718		CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
719		break;
720	/* this enables or disables the "SimpleForkCheck" flag used in the
721	 * initialisation structure. */
722	case ENGINE_CTRL_CHIL_SET_FORKCHECK:
723	case HWCRHK_CMD_FORK_CHECK:
724		CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
725		if(i)
726			hwcrhk_globals.flags |=
727				HWCryptoHook_InitFlags_SimpleForkCheck;
728		else
729			hwcrhk_globals.flags &=
730				~HWCryptoHook_InitFlags_SimpleForkCheck;
731		CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
732		break;
733	/* This will prevent the initialisation function from "installing"
734	 * the mutex-handling callbacks, even if they are available from
735	 * within the library (or were provided to the library from the
736	 * calling application). This is to remove any baggage for
737	 * applications not using multithreading. */
738	case ENGINE_CTRL_CHIL_NO_LOCKING:
739		CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
740		disable_mutex_callbacks = 1;
741		CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
742		break;
743	case HWCRHK_CMD_THREAD_LOCKING:
744		CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
745		disable_mutex_callbacks = ((i == 0) ? 0 : 1);
746		CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
747		break;
748
749	/* The command isn't understood by this engine */
750	default:
751		HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,
752			HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
753		to_return = 0;
754		break;
755		}
756
757	return to_return;
758	}
759
760static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
761	UI_METHOD *ui_method, void *callback_data)
762	{
763#ifndef OPENSSL_NO_RSA
764	RSA *rtmp = NULL;
765#endif
766	EVP_PKEY *res = NULL;
767#ifndef OPENSSL_NO_RSA
768	HWCryptoHook_MPI e, n;
769	HWCryptoHook_RSAKeyHandle *hptr;
770#endif
771#if !defined(OPENSSL_NO_RSA)
772	char tempbuf[1024];
773	HWCryptoHook_ErrMsgBuf rmsg;
774	HWCryptoHook_PassphraseContext ppctx;
775#endif
776
777#if !defined(OPENSSL_NO_RSA)
778	rmsg.buf = tempbuf;
779	rmsg.size = sizeof(tempbuf);
780#endif
781
782	if(!hwcrhk_context)
783		{
784		HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
785			HWCRHK_R_NOT_INITIALISED);
786		goto err;
787		}
788#ifndef OPENSSL_NO_RSA
789	hptr = OPENSSL_malloc(sizeof(HWCryptoHook_RSAKeyHandle));
790	if (!hptr)
791		{
792		HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
793			ERR_R_MALLOC_FAILURE);
794		goto err;
795		}
796        ppctx.ui_method = ui_method;
797	ppctx.callback_data = callback_data;
798	if (p_hwcrhk_RSALoadKey(hwcrhk_context, key_id, hptr,
799		&rmsg, &ppctx))
800		{
801		HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
802			HWCRHK_R_CHIL_ERROR);
803		ERR_add_error_data(1,rmsg.buf);
804		goto err;
805		}
806	if (!*hptr)
807		{
808		HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
809			HWCRHK_R_NO_KEY);
810		goto err;
811		}
812#endif
813#ifndef OPENSSL_NO_RSA
814	rtmp = RSA_new_method(eng);
815	RSA_set_ex_data(rtmp, hndidx_rsa, (char *)hptr);
816	rtmp->e = BN_new();
817	rtmp->n = BN_new();
818	rtmp->flags |= RSA_FLAG_EXT_PKEY;
819	MPI2BN(rtmp->e, e);
820	MPI2BN(rtmp->n, n);
821	if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg)
822		!= HWCRYPTOHOOK_ERROR_MPISIZE)
823		{
824		HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,HWCRHK_R_CHIL_ERROR);
825		ERR_add_error_data(1,rmsg.buf);
826		goto err;
827		}
828
829	bn_expand2(rtmp->e, e.size/sizeof(BN_ULONG));
830	bn_expand2(rtmp->n, n.size/sizeof(BN_ULONG));
831	MPI2BN(rtmp->e, e);
832	MPI2BN(rtmp->n, n);
833
834	if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg))
835		{
836		HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
837			HWCRHK_R_CHIL_ERROR);
838		ERR_add_error_data(1,rmsg.buf);
839		goto err;
840		}
841	rtmp->e->top = e.size / sizeof(BN_ULONG);
842	bn_fix_top(rtmp->e);
843	rtmp->n->top = n.size / sizeof(BN_ULONG);
844	bn_fix_top(rtmp->n);
845
846	res = EVP_PKEY_new();
847	EVP_PKEY_assign_RSA(res, rtmp);
848#endif
849
850        if (!res)
851                HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
852                        HWCRHK_R_PRIVATE_KEY_ALGORITHMS_DISABLED);
853
854	return res;
855 err:
856	if (res)
857		EVP_PKEY_free(res);
858#ifndef OPENSSL_NO_RSA
859	if (rtmp)
860		RSA_free(rtmp);
861#endif
862	return NULL;
863	}
864
865static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
866	UI_METHOD *ui_method, void *callback_data)
867	{
868	EVP_PKEY *res = NULL;
869
870#ifndef OPENSSL_NO_RSA
871        res = hwcrhk_load_privkey(eng, key_id,
872                ui_method, callback_data);
873#endif
874
875	if (res)
876		switch(res->type)
877			{
878#ifndef OPENSSL_NO_RSA
879		case EVP_PKEY_RSA:
880			{
881			RSA *rsa = NULL;
882
883			CRYPTO_w_lock(CRYPTO_LOCK_EVP_PKEY);
884			rsa = res->pkey.rsa;
885			res->pkey.rsa = RSA_new();
886			res->pkey.rsa->n = rsa->n;
887			res->pkey.rsa->e = rsa->e;
888			rsa->n = NULL;
889			rsa->e = NULL;
890			CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY);
891			RSA_free(rsa);
892			}
893			break;
894#endif
895		default:
896			HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
897				HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
898			goto err;
899			}
900
901	return res;
902 err:
903	if (res)
904		EVP_PKEY_free(res);
905	return NULL;
906	}
907
908/* A little mod_exp */
909static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
910			const BIGNUM *m, BN_CTX *ctx)
911	{
912	char tempbuf[1024];
913	HWCryptoHook_ErrMsgBuf rmsg;
914	/* Since HWCryptoHook_MPI is pretty compatible with BIGNUM's,
915	   we use them directly, plus a little macro magic.  We only
916	   thing we need to make sure of is that enough space is allocated. */
917	HWCryptoHook_MPI m_a, m_p, m_n, m_r;
918	int to_return, ret;
919
920	to_return = 0; /* expect failure */
921	rmsg.buf = tempbuf;
922	rmsg.size = sizeof(tempbuf);
923
924	if(!hwcrhk_context)
925		{
926		HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_NOT_INITIALISED);
927		goto err;
928		}
929	/* Prepare the params */
930	bn_expand2(r, m->top);	/* Check for error !! */
931	BN2MPI(m_a, a);
932	BN2MPI(m_p, p);
933	BN2MPI(m_n, m);
934	MPI2BN(r, m_r);
935
936	/* Perform the operation */
937	ret = p_hwcrhk_ModExp(hwcrhk_context, m_a, m_p, m_n, &m_r, &rmsg);
938
939	/* Convert the response */
940	r->top = m_r.size / sizeof(BN_ULONG);
941	bn_fix_top(r);
942
943	if (ret < 0)
944		{
945		/* FIXME: When this error is returned, HWCryptoHook is
946		   telling us that falling back to software computation
947		   might be a good thing. */
948		if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
949			{
950			HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_REQUEST_FALLBACK);
951			}
952		else
953			{
954			HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_REQUEST_FAILED);
955			}
956		ERR_add_error_data(1,rmsg.buf);
957		goto err;
958		}
959
960	to_return = 1;
961err:
962	return to_return;
963	}
964
965#ifndef OPENSSL_NO_RSA
966static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
967	{
968	char tempbuf[1024];
969	HWCryptoHook_ErrMsgBuf rmsg;
970	HWCryptoHook_RSAKeyHandle *hptr;
971	int to_return = 0, ret;
972
973	rmsg.buf = tempbuf;
974	rmsg.size = sizeof(tempbuf);
975
976	if(!hwcrhk_context)
977		{
978		HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,HWCRHK_R_NOT_INITIALISED);
979		goto err;
980		}
981
982	/* This provides support for nForce keys.  Since that's opaque data
983	   all we do is provide a handle to the proper key and let HWCryptoHook
984	   take care of the rest. */
985	if ((hptr = (HWCryptoHook_RSAKeyHandle *) RSA_get_ex_data(rsa, hndidx_rsa))
986		!= NULL)
987		{
988		HWCryptoHook_MPI m_a, m_r;
989
990		if(!rsa->n)
991			{
992			HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
993				HWCRHK_R_MISSING_KEY_COMPONENTS);
994			goto err;
995			}
996
997		/* Prepare the params */
998		bn_expand2(r, rsa->n->top); /* Check for error !! */
999		BN2MPI(m_a, I);
1000		MPI2BN(r, m_r);
1001
1002		/* Perform the operation */
1003		ret = p_hwcrhk_RSA(m_a, *hptr, &m_r, &rmsg);
1004
1005		/* Convert the response */
1006		r->top = m_r.size / sizeof(BN_ULONG);
1007		bn_fix_top(r);
1008
1009		if (ret < 0)
1010			{
1011			/* FIXME: When this error is returned, HWCryptoHook is
1012			   telling us that falling back to software computation
1013			   might be a good thing. */
1014			if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1015				{
1016				HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1017					HWCRHK_R_REQUEST_FALLBACK);
1018				}
1019			else
1020				{
1021				HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1022					HWCRHK_R_REQUEST_FAILED);
1023				}
1024			ERR_add_error_data(1,rmsg.buf);
1025			goto err;
1026			}
1027		}
1028	else
1029		{
1030		HWCryptoHook_MPI m_a, m_p, m_q, m_dmp1, m_dmq1, m_iqmp, m_r;
1031
1032		if(!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp)
1033			{
1034			HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1035				HWCRHK_R_MISSING_KEY_COMPONENTS);
1036			goto err;
1037			}
1038
1039		/* Prepare the params */
1040		bn_expand2(r, rsa->n->top); /* Check for error !! */
1041		BN2MPI(m_a, I);
1042		BN2MPI(m_p, rsa->p);
1043		BN2MPI(m_q, rsa->q);
1044		BN2MPI(m_dmp1, rsa->dmp1);
1045		BN2MPI(m_dmq1, rsa->dmq1);
1046		BN2MPI(m_iqmp, rsa->iqmp);
1047		MPI2BN(r, m_r);
1048
1049		/* Perform the operation */
1050		ret = p_hwcrhk_ModExpCRT(hwcrhk_context, m_a, m_p, m_q,
1051			m_dmp1, m_dmq1, m_iqmp, &m_r, &rmsg);
1052
1053		/* Convert the response */
1054		r->top = m_r.size / sizeof(BN_ULONG);
1055		bn_fix_top(r);
1056
1057		if (ret < 0)
1058			{
1059			/* FIXME: When this error is returned, HWCryptoHook is
1060			   telling us that falling back to software computation
1061			   might be a good thing. */
1062			if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1063				{
1064				HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1065					HWCRHK_R_REQUEST_FALLBACK);
1066				}
1067			else
1068				{
1069				HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1070					HWCRHK_R_REQUEST_FAILED);
1071				}
1072			ERR_add_error_data(1,rmsg.buf);
1073			goto err;
1074			}
1075		}
1076	/* If we're here, we must be here with some semblance of success :-) */
1077	to_return = 1;
1078err:
1079	return to_return;
1080	}
1081#endif
1082
1083#ifndef OPENSSL_NO_RSA
1084/* This function is aliased to mod_exp (with the mont stuff dropped). */
1085static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
1086		const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1087	{
1088	return hwcrhk_mod_exp(r, a, p, m, ctx);
1089	}
1090#endif
1091
1092#ifndef OPENSSL_NO_DH
1093/* This function is aliased to mod_exp (with the dh and mont dropped). */
1094static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r,
1095		const BIGNUM *a, const BIGNUM *p,
1096		const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1097	{
1098	return hwcrhk_mod_exp(r, a, p, m, ctx);
1099	}
1100#endif
1101
1102/* Random bytes are good */
1103static int hwcrhk_rand_bytes(unsigned char *buf, int num)
1104	{
1105	char tempbuf[1024];
1106	HWCryptoHook_ErrMsgBuf rmsg;
1107	int to_return = 0; /* assume failure */
1108	int ret;
1109
1110	rmsg.buf = tempbuf;
1111	rmsg.size = sizeof(tempbuf);
1112
1113	if(!hwcrhk_context)
1114		{
1115		HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,HWCRHK_R_NOT_INITIALISED);
1116		goto err;
1117		}
1118
1119	ret = p_hwcrhk_RandomBytes(hwcrhk_context, buf, num, &rmsg);
1120	if (ret < 0)
1121		{
1122		/* FIXME: When this error is returned, HWCryptoHook is
1123		   telling us that falling back to software computation
1124		   might be a good thing. */
1125		if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1126			{
1127			HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,
1128				HWCRHK_R_REQUEST_FALLBACK);
1129			}
1130		else
1131			{
1132			HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,
1133				HWCRHK_R_REQUEST_FAILED);
1134			}
1135		ERR_add_error_data(1,rmsg.buf);
1136		goto err;
1137		}
1138	to_return = 1;
1139 err:
1140	return to_return;
1141	}
1142
1143static int hwcrhk_rand_status(void)
1144	{
1145	return 1;
1146	}
1147
1148/* This cleans up an RSA KM key, called when ex_data is freed */
1149#ifndef OPENSSL_NO_RSA
1150static void hwcrhk_ex_free(void *obj, void *item, CRYPTO_EX_DATA *ad,
1151	int ind,long argl, void *argp)
1152{
1153	char tempbuf[1024];
1154	HWCryptoHook_ErrMsgBuf rmsg;
1155#ifndef OPENSSL_NO_RSA
1156	HWCryptoHook_RSAKeyHandle *hptr;
1157#endif
1158#if !defined(OPENSSL_NO_RSA)
1159	int ret;
1160#endif
1161
1162	rmsg.buf = tempbuf;
1163	rmsg.size = sizeof(tempbuf);
1164
1165#ifndef OPENSSL_NO_RSA
1166	hptr = (HWCryptoHook_RSAKeyHandle *) item;
1167	if(hptr)
1168                {
1169                ret = p_hwcrhk_RSAUnloadKey(*hptr, NULL);
1170                OPENSSL_free(hptr);
1171                }
1172#endif
1173}
1174#endif
1175
1176/* Mutex calls: since the HWCryptoHook model closely follows the POSIX model
1177 * these just wrap the POSIX functions and add some logging.
1178 */
1179
1180static int hwcrhk_mutex_init(HWCryptoHook_Mutex* mt,
1181	HWCryptoHook_CallerContext *cactx)
1182	{
1183	mt->lockid = CRYPTO_get_new_dynlockid();
1184	if (mt->lockid == 0)
1185		return 1; /* failure */
1186	return 0; /* success */
1187	}
1188
1189static int hwcrhk_mutex_lock(HWCryptoHook_Mutex *mt)
1190	{
1191	CRYPTO_w_lock(mt->lockid);
1192	return 0;
1193	}
1194
1195static void hwcrhk_mutex_unlock(HWCryptoHook_Mutex * mt)
1196	{
1197	CRYPTO_w_unlock(mt->lockid);
1198	}
1199
1200static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex *mt)
1201	{
1202	CRYPTO_destroy_dynlockid(mt->lockid);
1203	}
1204
1205static int hwcrhk_get_pass(const char *prompt_info,
1206	int *len_io, char *buf,
1207	HWCryptoHook_PassphraseContext *ppctx,
1208	HWCryptoHook_CallerContext *cactx)
1209	{
1210	pem_password_cb *callback = NULL;
1211	void *callback_data = NULL;
1212        UI_METHOD *ui_method = NULL;
1213
1214        if (cactx)
1215                {
1216                if (cactx->ui_method)
1217                        ui_method = cactx->ui_method;
1218		if (cactx->password_callback)
1219			callback = cactx->password_callback;
1220		if (cactx->callback_data)
1221			callback_data = cactx->callback_data;
1222                }
1223	if (ppctx)
1224		{
1225                if (ppctx->ui_method)
1226                        {
1227                        ui_method = ppctx->ui_method;
1228                        callback = NULL;
1229                        }
1230		if (ppctx->callback_data)
1231			callback_data = ppctx->callback_data;
1232		}
1233	if (callback == NULL && ui_method == NULL)
1234		{
1235		HWCRHKerr(HWCRHK_F_HWCRHK_GET_PASS,HWCRHK_R_NO_CALLBACK);
1236		return -1;
1237		}
1238
1239        if (ui_method)
1240                {
1241                UI *ui = UI_new_method(ui_method);
1242                if (ui)
1243                        {
1244                        int ok;
1245                        char *prompt = UI_construct_prompt(ui,
1246                                "pass phrase", prompt_info);
1247
1248                        ok = UI_add_input_string(ui,prompt,
1249                                UI_INPUT_FLAG_DEFAULT_PWD,
1250				buf,0,(*len_io) - 1);
1251                        UI_add_user_data(ui, callback_data);
1252			UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0);
1253
1254			if (ok >= 0)
1255				do
1256					{
1257					ok=UI_process(ui);
1258					}
1259				while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0));
1260
1261                        if (ok >= 0)
1262                                *len_io = strlen(buf);
1263
1264                        UI_free(ui);
1265                        OPENSSL_free(prompt);
1266                        }
1267                }
1268        else
1269                {
1270                *len_io = callback(buf, *len_io, 0, callback_data);
1271                }
1272	if(!*len_io)
1273		return -1;
1274	return 0;
1275	}
1276
1277static int hwcrhk_insert_card(const char *prompt_info,
1278		      const char *wrong_info,
1279		      HWCryptoHook_PassphraseContext *ppctx,
1280		      HWCryptoHook_CallerContext *cactx)
1281        {
1282        int ok = -1;
1283        UI *ui;
1284	void *callback_data = NULL;
1285        UI_METHOD *ui_method = NULL;
1286
1287        if (cactx)
1288                {
1289                if (cactx->ui_method)
1290                        ui_method = cactx->ui_method;
1291		if (cactx->callback_data)
1292			callback_data = cactx->callback_data;
1293                }
1294	if (ppctx)
1295		{
1296                if (ppctx->ui_method)
1297                        ui_method = ppctx->ui_method;
1298		if (ppctx->callback_data)
1299			callback_data = ppctx->callback_data;
1300		}
1301	if (ui_method == NULL)
1302		{
1303		HWCRHKerr(HWCRHK_F_HWCRHK_INSERT_CARD,
1304			HWCRHK_R_NO_CALLBACK);
1305		return -1;
1306		}
1307
1308	ui = UI_new_method(ui_method);
1309
1310	if (ui)
1311		{
1312		char answer;
1313		char buf[BUFSIZ];
1314
1315		if (wrong_info)
1316			BIO_snprintf(buf, sizeof(buf)-1,
1317				"Current card: \"%s\"\n", wrong_info);
1318		ok = UI_dup_info_string(ui, buf);
1319		if (ok >= 0 && prompt_info)
1320			{
1321			BIO_snprintf(buf, sizeof(buf)-1,
1322				"Insert card \"%s\"", prompt_info);
1323			ok = UI_dup_input_boolean(ui, buf,
1324				"\n then hit <enter> or C<enter> to cancel\n",
1325				"\r\n", "Cc", UI_INPUT_FLAG_ECHO, &answer);
1326			}
1327		UI_add_user_data(ui, callback_data);
1328
1329		if (ok >= 0)
1330			ok = UI_process(ui);
1331		UI_free(ui);
1332
1333		if (ok == -2 || (ok >= 0 && answer == 'C'))
1334			ok = 1;
1335		else if (ok < 0)
1336			ok = -1;
1337		else
1338			ok = 0;
1339		}
1340	return ok;
1341	}
1342
1343static void hwcrhk_log_message(void *logstr, const char *message)
1344	{
1345	BIO *lstream = NULL;
1346
1347	CRYPTO_w_lock(CRYPTO_LOCK_BIO);
1348	if (logstr)
1349		lstream=*(BIO **)logstr;
1350	if (lstream)
1351		{
1352		BIO_printf(lstream, "%s\n", message);
1353		}
1354	CRYPTO_w_unlock(CRYPTO_LOCK_BIO);
1355	}
1356
1357/* This stuff is needed if this ENGINE is being compiled into a self-contained
1358 * shared-library. */
1359#ifndef OPENSSL_NO_DYNAMIC_ENGINE
1360static int bind_fn(ENGINE *e, const char *id)
1361	{
1362	if(id && (strcmp(id, engine_hwcrhk_id) != 0) &&
1363			(strcmp(id, engine_hwcrhk_id_alt) != 0))
1364		return 0;
1365	if(!bind_helper(e))
1366		return 0;
1367	return 1;
1368	}
1369IMPLEMENT_DYNAMIC_CHECK_FN()
1370IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
1371#endif /* OPENSSL_NO_DYNAMIC_ENGINE */
1372
1373#endif /* !OPENSSL_NO_HW_CHIL */
1374#endif /* !OPENSSL_NO_HW */
1375