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