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