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