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