When build as dynamic engines, the loading functions should be defined
[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 #ifdef OPENSSL_NO_DYNAMIC_ENGINE
376 static ENGINE *engine_ncipher(void)
377         {
378         ENGINE *ret = ENGINE_new();
379         if(!ret)
380                 return NULL;
381         if(!bind_helper(ret))
382                 {
383                 ENGINE_free(ret);
384                 return NULL;
385                 }
386         return ret;
387         }
388
389 void ENGINE_load_chil(void)
390         {
391         /* Copied from eng_[openssl|dyn].c */
392         ENGINE *toadd = engine_ncipher();
393         if(!toadd) return;
394         ENGINE_add(toadd);
395         ENGINE_free(toadd);
396         ERR_clear_error();
397         }
398 #endif
399
400 /* This is a process-global DSO handle used for loading and unloading
401  * the HWCryptoHook library. NB: This is only set (or unset) during an
402  * init() or finish() call (reference counts permitting) and they're
403  * operating with global locks, so this should be thread-safe
404  * implicitly. */
405 static DSO *hwcrhk_dso = NULL;
406 static HWCryptoHook_ContextHandle hwcrhk_context = 0;
407 #ifndef OPENSSL_NO_RSA
408 static int hndidx_rsa = -1;    /* Index for KM handle.  Not really used yet. */
409 #endif
410
411 /* These are the function pointers that are (un)set when the library has
412  * successfully (un)loaded. */
413 static HWCryptoHook_Init_t *p_hwcrhk_Init = NULL;
414 static HWCryptoHook_Finish_t *p_hwcrhk_Finish = NULL;
415 static HWCryptoHook_ModExp_t *p_hwcrhk_ModExp = NULL;
416 #ifndef OPENSSL_NO_RSA
417 static HWCryptoHook_RSA_t *p_hwcrhk_RSA = NULL;
418 #endif
419 static HWCryptoHook_RandomBytes_t *p_hwcrhk_RandomBytes = NULL;
420 #ifndef OPENSSL_NO_RSA
421 static HWCryptoHook_RSALoadKey_t *p_hwcrhk_RSALoadKey = NULL;
422 static HWCryptoHook_RSAGetPublicKey_t *p_hwcrhk_RSAGetPublicKey = NULL;
423 static HWCryptoHook_RSAUnloadKey_t *p_hwcrhk_RSAUnloadKey = NULL;
424 #endif
425 static HWCryptoHook_ModExpCRT_t *p_hwcrhk_ModExpCRT = NULL;
426
427 /* Used in the DSO operations. */
428 static const char *HWCRHK_LIBNAME = NULL;
429 static void free_HWCRHK_LIBNAME(void)
430         {
431         if(HWCRHK_LIBNAME)
432                 OPENSSL_free((void*)HWCRHK_LIBNAME);
433         HWCRHK_LIBNAME = NULL;
434         }
435 static const char *get_HWCRHK_LIBNAME(void)
436         {
437         if(HWCRHK_LIBNAME)
438                 return HWCRHK_LIBNAME;
439         return "nfhwcrhk";
440         }
441 static long set_HWCRHK_LIBNAME(const char *name)
442         {
443         free_HWCRHK_LIBNAME();
444         return (((HWCRHK_LIBNAME = BUF_strdup(name)) != NULL) ? 1 : 0);
445         }
446 static const char *n_hwcrhk_Init = "HWCryptoHook_Init";
447 static const char *n_hwcrhk_Finish = "HWCryptoHook_Finish";
448 static const char *n_hwcrhk_ModExp = "HWCryptoHook_ModExp";
449 #ifndef OPENSSL_NO_RSA
450 static const char *n_hwcrhk_RSA = "HWCryptoHook_RSA";
451 #endif
452 static const char *n_hwcrhk_RandomBytes = "HWCryptoHook_RandomBytes";
453 #ifndef OPENSSL_NO_RSA
454 static const char *n_hwcrhk_RSALoadKey = "HWCryptoHook_RSALoadKey";
455 static const char *n_hwcrhk_RSAGetPublicKey = "HWCryptoHook_RSAGetPublicKey";
456 static const char *n_hwcrhk_RSAUnloadKey = "HWCryptoHook_RSAUnloadKey";
457 #endif
458 static const char *n_hwcrhk_ModExpCRT = "HWCryptoHook_ModExpCRT";
459
460 /* HWCryptoHook library functions and mechanics - these are used by the
461  * higher-level functions further down. NB: As and where there's no
462  * error checking, take a look lower down where these functions are
463  * called, the checking and error handling is probably down there. */
464
465 /* utility function to obtain a context */
466 static int get_context(HWCryptoHook_ContextHandle *hac,
467         HWCryptoHook_CallerContext *cac)
468         {
469         char tempbuf[1024];
470         HWCryptoHook_ErrMsgBuf rmsg;
471
472         rmsg.buf = tempbuf;
473         rmsg.size = sizeof(tempbuf);
474
475         *hac = p_hwcrhk_Init(&hwcrhk_globals, sizeof(hwcrhk_globals), &rmsg,
476                 cac);
477         if (!*hac)
478                 return 0;
479         return 1;
480         }
481  
482 /* similarly to release one. */
483 static void release_context(HWCryptoHook_ContextHandle hac)
484         {
485         p_hwcrhk_Finish(hac);
486         }
487
488 /* Destructor (complements the "ENGINE_ncipher()" constructor) */
489 static int hwcrhk_destroy(ENGINE *e)
490         {
491         free_HWCRHK_LIBNAME();
492         ERR_unload_HWCRHK_strings();
493         return 1;
494         }
495
496 /* (de)initialisation functions. */
497 static int hwcrhk_init(ENGINE *e)
498         {
499         HWCryptoHook_Init_t *p1;
500         HWCryptoHook_Finish_t *p2;
501         HWCryptoHook_ModExp_t *p3;
502 #ifndef OPENSSL_NO_RSA
503         HWCryptoHook_RSA_t *p4;
504         HWCryptoHook_RSALoadKey_t *p5;
505         HWCryptoHook_RSAGetPublicKey_t *p6;
506         HWCryptoHook_RSAUnloadKey_t *p7;
507 #endif
508         HWCryptoHook_RandomBytes_t *p8;
509         HWCryptoHook_ModExpCRT_t *p9;
510
511         if(hwcrhk_dso != NULL)
512                 {
513                 HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_ALREADY_LOADED);
514                 goto err;
515                 }
516         /* Attempt to load libnfhwcrhk.so/nfhwcrhk.dll/whatever. */
517         hwcrhk_dso = DSO_load(NULL, get_HWCRHK_LIBNAME(), NULL, 0);
518         if(hwcrhk_dso == NULL)
519                 {
520                 HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_DSO_FAILURE);
521                 goto err;
522                 }
523         if(!(p1 = (HWCryptoHook_Init_t *)
524                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_Init)) ||
525                 !(p2 = (HWCryptoHook_Finish_t *)
526                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_Finish)) ||
527                 !(p3 = (HWCryptoHook_ModExp_t *)
528                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_ModExp)) ||
529 #ifndef OPENSSL_NO_RSA
530                 !(p4 = (HWCryptoHook_RSA_t *)
531                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSA)) ||
532                 !(p5 = (HWCryptoHook_RSALoadKey_t *)
533                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSALoadKey)) ||
534                 !(p6 = (HWCryptoHook_RSAGetPublicKey_t *)
535                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSAGetPublicKey)) ||
536                 !(p7 = (HWCryptoHook_RSAUnloadKey_t *)
537                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSAUnloadKey)) ||
538 #endif
539                 !(p8 = (HWCryptoHook_RandomBytes_t *)
540                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_RandomBytes)) ||
541                 !(p9 = (HWCryptoHook_ModExpCRT_t *)
542                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_ModExpCRT)))
543                 {
544                 HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_DSO_FAILURE);
545                 goto err;
546                 }
547         /* Copy the pointers */
548         p_hwcrhk_Init = p1;
549         p_hwcrhk_Finish = p2;
550         p_hwcrhk_ModExp = p3;
551 #ifndef OPENSSL_NO_RSA
552         p_hwcrhk_RSA = p4;
553         p_hwcrhk_RSALoadKey = p5;
554         p_hwcrhk_RSAGetPublicKey = p6;
555         p_hwcrhk_RSAUnloadKey = p7;
556 #endif
557         p_hwcrhk_RandomBytes = p8;
558         p_hwcrhk_ModExpCRT = p9;
559
560         /* Check if the application decided to support dynamic locks,
561            and if it does, use them. */
562         if (disable_mutex_callbacks == 0 &&
563                 CRYPTO_get_dynlock_create_callback() != NULL &&
564                 CRYPTO_get_dynlock_lock_callback() != NULL &&
565                 CRYPTO_get_dynlock_destroy_callback() != NULL)
566                 {
567                 hwcrhk_globals.mutex_init = hwcrhk_mutex_init;
568                 hwcrhk_globals.mutex_acquire = hwcrhk_mutex_lock;
569                 hwcrhk_globals.mutex_release = hwcrhk_mutex_unlock;
570                 hwcrhk_globals.mutex_destroy = hwcrhk_mutex_destroy;
571                 }
572
573         /* Try and get a context - if not, we may have a DSO but no
574          * accelerator! */
575         if(!get_context(&hwcrhk_context, &password_context))
576                 {
577                 HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_UNIT_FAILURE);
578                 goto err;
579                 }
580         /* Everything's fine. */
581 #ifndef OPENSSL_NO_RSA
582         if (hndidx_rsa == -1)
583                 hndidx_rsa = RSA_get_ex_new_index(0,
584                         "nFast HWCryptoHook RSA key handle",
585                         NULL, NULL, hwcrhk_ex_free);
586 #endif
587         return 1;
588 err:
589         if(hwcrhk_dso)
590                 DSO_free(hwcrhk_dso);
591         hwcrhk_dso = NULL;
592         p_hwcrhk_Init = NULL;
593         p_hwcrhk_Finish = NULL;
594         p_hwcrhk_ModExp = NULL;
595 #ifndef OPENSSL_NO_RSA
596         p_hwcrhk_RSA = NULL;
597         p_hwcrhk_RSALoadKey = NULL;
598         p_hwcrhk_RSAGetPublicKey = NULL;
599         p_hwcrhk_RSAUnloadKey = NULL;
600 #endif
601         p_hwcrhk_ModExpCRT = NULL;
602         p_hwcrhk_RandomBytes = NULL;
603         return 0;
604         }
605
606 static int hwcrhk_finish(ENGINE *e)
607         {
608         int to_return = 1;
609         free_HWCRHK_LIBNAME();
610         if(hwcrhk_dso == NULL)
611                 {
612                 HWCRHKerr(HWCRHK_F_HWCRHK_FINISH,HWCRHK_R_NOT_LOADED);
613                 to_return = 0;
614                 goto err;
615                 }
616         release_context(hwcrhk_context);
617         if(!DSO_free(hwcrhk_dso))
618                 {
619                 HWCRHKerr(HWCRHK_F_HWCRHK_FINISH,HWCRHK_R_DSO_FAILURE);
620                 to_return = 0;
621                 goto err;
622                 }
623  err:
624         if (logstream)
625                 BIO_free(logstream);
626         hwcrhk_dso = NULL;
627         p_hwcrhk_Init = NULL;
628         p_hwcrhk_Finish = NULL;
629         p_hwcrhk_ModExp = NULL;
630 #ifndef OPENSSL_NO_RSA
631         p_hwcrhk_RSA = NULL;
632         p_hwcrhk_RSALoadKey = NULL;
633         p_hwcrhk_RSAGetPublicKey = NULL;
634         p_hwcrhk_RSAUnloadKey = NULL;
635 #endif
636         p_hwcrhk_ModExpCRT = NULL;
637         p_hwcrhk_RandomBytes = NULL;
638         return to_return;
639         }
640
641 static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
642         {
643         int to_return = 1;
644
645         switch(cmd)
646                 {
647         case HWCRHK_CMD_SO_PATH:
648                 if(hwcrhk_dso)
649                         {
650                         HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,HWCRHK_R_ALREADY_LOADED);
651                         return 0;
652                         }
653                 if(p == NULL)
654                         {
655                         HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,ERR_R_PASSED_NULL_PARAMETER);
656                         return 0;
657                         }
658                 return set_HWCRHK_LIBNAME((const char *)p);
659         case ENGINE_CTRL_SET_LOGSTREAM:
660                 {
661                 BIO *bio = (BIO *)p;
662
663                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
664                 if (logstream)
665                         {
666                         BIO_free(logstream);
667                         logstream = NULL;
668                         }
669                 if (CRYPTO_add(&bio->references,1,CRYPTO_LOCK_BIO) > 1)
670                         logstream = bio;
671                 else
672                         HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,HWCRHK_R_BIO_WAS_FREED);
673                 }
674                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
675                 break;
676         case ENGINE_CTRL_SET_PASSWORD_CALLBACK:
677                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
678                 password_context.password_callback = (pem_password_cb *)f;
679                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
680                 break;
681         case ENGINE_CTRL_SET_USER_INTERFACE:
682         case HWCRHK_CMD_SET_USER_INTERFACE:
683                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
684                 password_context.ui_method = (UI_METHOD *)p;
685                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
686                 break;
687         case ENGINE_CTRL_SET_CALLBACK_DATA:
688         case HWCRHK_CMD_SET_CALLBACK_DATA:
689                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
690                 password_context.callback_data = p;
691                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
692                 break;
693         /* this enables or disables the "SimpleForkCheck" flag used in the
694          * initialisation structure. */
695         case ENGINE_CTRL_CHIL_SET_FORKCHECK:
696         case HWCRHK_CMD_FORK_CHECK:
697                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
698                 if(i)
699                         hwcrhk_globals.flags |=
700                                 HWCryptoHook_InitFlags_SimpleForkCheck;
701                 else
702                         hwcrhk_globals.flags &=
703                                 ~HWCryptoHook_InitFlags_SimpleForkCheck;
704                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
705                 break;
706         /* This will prevent the initialisation function from "installing"
707          * the mutex-handling callbacks, even if they are available from
708          * within the library (or were provided to the library from the
709          * calling application). This is to remove any baggage for
710          * applications not using multithreading. */
711         case ENGINE_CTRL_CHIL_NO_LOCKING:
712                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
713                 disable_mutex_callbacks = 1;
714                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
715                 break;
716         case HWCRHK_CMD_THREAD_LOCKING:
717                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
718                 disable_mutex_callbacks = ((i == 0) ? 0 : 1);
719                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
720                 break;
721
722         /* The command isn't understood by this engine */
723         default:
724                 HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,
725                         HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
726                 to_return = 0;
727                 break;
728                 }
729
730         return to_return;
731         }
732
733 static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
734         UI_METHOD *ui_method, void *callback_data)
735         {
736 #ifndef OPENSSL_NO_RSA
737         RSA *rtmp = NULL;
738 #endif
739         EVP_PKEY *res = NULL;
740 #ifndef OPENSSL_NO_RSA
741         HWCryptoHook_MPI e, n;
742         HWCryptoHook_RSAKeyHandle *hptr;
743 #endif
744 #if !defined(OPENSSL_NO_RSA)
745         char tempbuf[1024];
746         HWCryptoHook_ErrMsgBuf rmsg;
747 #endif
748         HWCryptoHook_PassphraseContext ppctx;
749
750 #if !defined(OPENSSL_NO_RSA)
751         rmsg.buf = tempbuf;
752         rmsg.size = sizeof(tempbuf);
753 #endif
754
755         if(!hwcrhk_context)
756                 {
757                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
758                         HWCRHK_R_NOT_INITIALISED);
759                 goto err;
760                 }
761 #ifndef OPENSSL_NO_RSA
762         hptr = OPENSSL_malloc(sizeof(HWCryptoHook_RSAKeyHandle));
763         if (!hptr)
764                 {
765                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
766                         ERR_R_MALLOC_FAILURE);
767                 goto err;
768                 }
769         ppctx.ui_method = ui_method;
770         ppctx.callback_data = callback_data;
771         if (p_hwcrhk_RSALoadKey(hwcrhk_context, key_id, hptr,
772                 &rmsg, &ppctx))
773                 {
774                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
775                         HWCRHK_R_CHIL_ERROR);
776                 ERR_add_error_data(1,rmsg.buf);
777                 goto err;
778                 }
779         if (!*hptr)
780                 {
781                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
782                         HWCRHK_R_NO_KEY);
783                 goto err;
784                 }
785 #endif
786 #ifndef OPENSSL_NO_RSA
787         rtmp = RSA_new_method(eng);
788         RSA_set_ex_data(rtmp, hndidx_rsa, (char *)hptr);
789         rtmp->e = BN_new();
790         rtmp->n = BN_new();
791         rtmp->flags |= RSA_FLAG_EXT_PKEY;
792         MPI2BN(rtmp->e, e);
793         MPI2BN(rtmp->n, n);
794         if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg)
795                 != HWCRYPTOHOOK_ERROR_MPISIZE)
796                 {
797                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,HWCRHK_R_CHIL_ERROR);
798                 ERR_add_error_data(1,rmsg.buf);
799                 goto err;
800                 }
801
802         bn_expand2(rtmp->e, e.size/sizeof(BN_ULONG));
803         bn_expand2(rtmp->n, n.size/sizeof(BN_ULONG));
804         MPI2BN(rtmp->e, e);
805         MPI2BN(rtmp->n, n);
806
807         if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg))
808                 {
809                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
810                         HWCRHK_R_CHIL_ERROR);
811                 ERR_add_error_data(1,rmsg.buf);
812                 goto err;
813                 }
814         rtmp->e->top = e.size / sizeof(BN_ULONG);
815         bn_fix_top(rtmp->e);
816         rtmp->n->top = n.size / sizeof(BN_ULONG);
817         bn_fix_top(rtmp->n);
818
819         res = EVP_PKEY_new();
820         EVP_PKEY_assign_RSA(res, rtmp);
821 #endif
822
823         if (!res)
824                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
825                         HWCRHK_R_PRIVATE_KEY_ALGORITHMS_DISABLED);
826
827         return res;
828  err:
829         if (res)
830                 EVP_PKEY_free(res);
831 #ifndef OPENSSL_NO_RSA
832         if (rtmp)
833                 RSA_free(rtmp);
834 #endif
835         return NULL;
836         }
837
838 static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
839         UI_METHOD *ui_method, void *callback_data)
840         {
841         EVP_PKEY *res = NULL;
842
843 #ifndef OPENSSL_NO_RSA
844         res = hwcrhk_load_privkey(eng, key_id,
845                 ui_method, callback_data);
846 #endif
847
848         if (res)
849                 switch(res->type)
850                         {
851 #ifndef OPENSSL_NO_RSA
852                 case EVP_PKEY_RSA:
853                         {
854                         RSA *rsa = NULL;
855
856                         CRYPTO_w_lock(CRYPTO_LOCK_EVP_PKEY);
857                         rsa = res->pkey.rsa;
858                         res->pkey.rsa = RSA_new();
859                         res->pkey.rsa->n = rsa->n;
860                         res->pkey.rsa->e = rsa->e;
861                         rsa->n = NULL;
862                         rsa->e = NULL;
863                         CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY);
864                         RSA_free(rsa);
865                         }
866                         break;
867 #endif
868                 default:
869                         HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
870                                 HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
871                         goto err;
872                         }
873
874         return res;
875  err:
876         if (res)
877                 EVP_PKEY_free(res);
878         return NULL;
879         }
880
881 /* A little mod_exp */
882 static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
883                         const BIGNUM *m, BN_CTX *ctx)
884         {
885         char tempbuf[1024];
886         HWCryptoHook_ErrMsgBuf rmsg;
887         /* Since HWCryptoHook_MPI is pretty compatible with BIGNUM's,
888            we use them directly, plus a little macro magic.  We only
889            thing we need to make sure of is that enough space is allocated. */
890         HWCryptoHook_MPI m_a, m_p, m_n, m_r;
891         int to_return, ret;
892  
893         to_return = 0; /* expect failure */
894         rmsg.buf = tempbuf;
895         rmsg.size = sizeof(tempbuf);
896
897         if(!hwcrhk_context)
898                 {
899                 HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_NOT_INITIALISED);
900                 goto err;
901                 }
902         /* Prepare the params */
903         bn_expand2(r, m->top);  /* Check for error !! */
904         BN2MPI(m_a, a);
905         BN2MPI(m_p, p);
906         BN2MPI(m_n, m);
907         MPI2BN(r, m_r);
908
909         /* Perform the operation */
910         ret = p_hwcrhk_ModExp(hwcrhk_context, m_a, m_p, m_n, &m_r, &rmsg);
911
912         /* Convert the response */
913         r->top = m_r.size / sizeof(BN_ULONG);
914         bn_fix_top(r);
915
916         if (ret < 0)
917                 {
918                 /* FIXME: When this error is returned, HWCryptoHook is
919                    telling us that falling back to software computation
920                    might be a good thing. */
921                 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
922                         {
923                         HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_REQUEST_FALLBACK);
924                         }
925                 else
926                         {
927                         HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_REQUEST_FAILED);
928                         }
929                 ERR_add_error_data(1,rmsg.buf);
930                 goto err;
931                 }
932
933         to_return = 1;
934 err:
935         return to_return;
936         }
937
938 #ifndef OPENSSL_NO_RSA 
939 static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa)
940         {
941         char tempbuf[1024];
942         HWCryptoHook_ErrMsgBuf rmsg;
943         HWCryptoHook_RSAKeyHandle *hptr;
944         int to_return = 0, ret;
945
946         rmsg.buf = tempbuf;
947         rmsg.size = sizeof(tempbuf);
948
949         if(!hwcrhk_context)
950                 {
951                 HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_NOT_INITIALISED);
952                 goto err;
953                 }
954
955         /* This provides support for nForce keys.  Since that's opaque data
956            all we do is provide a handle to the proper key and let HWCryptoHook
957            take care of the rest. */
958         if ((hptr = (HWCryptoHook_RSAKeyHandle *) RSA_get_ex_data(rsa, hndidx_rsa))
959                 != NULL)
960                 {
961                 HWCryptoHook_MPI m_a, m_r;
962
963                 if(!rsa->n)
964                         {
965                         HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
966                                 HWCRHK_R_MISSING_KEY_COMPONENTS);
967                         goto err;
968                         }
969
970                 /* Prepare the params */
971                 bn_expand2(r, rsa->n->top); /* Check for error !! */
972                 BN2MPI(m_a, I);
973                 MPI2BN(r, m_r);
974
975                 /* Perform the operation */
976                 ret = p_hwcrhk_RSA(m_a, *hptr, &m_r, &rmsg);
977
978                 /* Convert the response */
979                 r->top = m_r.size / sizeof(BN_ULONG);
980                 bn_fix_top(r);
981
982                 if (ret < 0)
983                         {
984                         /* FIXME: When this error is returned, HWCryptoHook is
985                            telling us that falling back to software computation
986                            might be a good thing. */
987                         if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
988                                 {
989                                 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
990                                         HWCRHK_R_REQUEST_FALLBACK);
991                                 }
992                         else
993                                 {
994                                 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
995                                         HWCRHK_R_REQUEST_FAILED);
996                                 }
997                         ERR_add_error_data(1,rmsg.buf);
998                         goto err;
999                         }
1000                 }
1001         else
1002                 {
1003                 HWCryptoHook_MPI m_a, m_p, m_q, m_dmp1, m_dmq1, m_iqmp, m_r;
1004
1005                 if(!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp)
1006                         {
1007                         HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1008                                 HWCRHK_R_MISSING_KEY_COMPONENTS);
1009                         goto err;
1010                         }
1011
1012                 /* Prepare the params */
1013                 bn_expand2(r, rsa->n->top); /* Check for error !! */
1014                 BN2MPI(m_a, I);
1015                 BN2MPI(m_p, rsa->p);
1016                 BN2MPI(m_q, rsa->q);
1017                 BN2MPI(m_dmp1, rsa->dmp1);
1018                 BN2MPI(m_dmq1, rsa->dmq1);
1019                 BN2MPI(m_iqmp, rsa->iqmp);
1020                 MPI2BN(r, m_r);
1021
1022                 /* Perform the operation */
1023                 ret = p_hwcrhk_ModExpCRT(hwcrhk_context, m_a, m_p, m_q,
1024                         m_dmp1, m_dmq1, m_iqmp, &m_r, NULL);
1025
1026                 /* Convert the response */
1027                 r->top = m_r.size / sizeof(BN_ULONG);
1028                 bn_fix_top(r);
1029
1030                 if (ret < 0)
1031                         {
1032                         /* FIXME: When this error is returned, HWCryptoHook is
1033                            telling us that falling back to software computation
1034                            might be a good thing. */
1035                         if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1036                                 {
1037                                 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1038                                         HWCRHK_R_REQUEST_FALLBACK);
1039                                 }
1040                         else
1041                                 {
1042                                 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1043                                         HWCRHK_R_REQUEST_FAILED);
1044                                 }
1045                         ERR_add_error_data(1,rmsg.buf);
1046                         goto err;
1047                         }
1048                 }
1049         /* If we're here, we must be here with some semblance of success :-) */
1050         to_return = 1;
1051 err:
1052         return to_return;
1053         }
1054 #endif
1055
1056 /* This function is aliased to mod_exp (with the mont stuff dropped). */
1057 static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
1058                 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1059         {
1060         return hwcrhk_mod_exp(r, a, p, m, ctx);
1061         }
1062
1063 #ifndef OPENSSL_NO_DH
1064 /* This function is aliased to mod_exp (with the dh and mont dropped). */
1065 static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r,
1066                 const BIGNUM *a, const BIGNUM *p,
1067                 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1068         {
1069         return hwcrhk_mod_exp(r, a, p, m, ctx);
1070         }
1071 #endif
1072
1073 /* Random bytes are good */
1074 static int hwcrhk_rand_bytes(unsigned char *buf, int num)
1075         {
1076         char tempbuf[1024];
1077         HWCryptoHook_ErrMsgBuf rmsg;
1078         int to_return = 0; /* assume failure */
1079         int ret;
1080
1081         rmsg.buf = tempbuf;
1082         rmsg.size = sizeof(tempbuf);
1083
1084         if(!hwcrhk_context)
1085                 {
1086                 HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,HWCRHK_R_NOT_INITIALISED);
1087                 goto err;
1088                 }
1089
1090         ret = p_hwcrhk_RandomBytes(hwcrhk_context, buf, num, &rmsg);
1091         if (ret < 0)
1092                 {
1093                 /* FIXME: When this error is returned, HWCryptoHook is
1094                    telling us that falling back to software computation
1095                    might be a good thing. */
1096                 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1097                         {
1098                         HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,
1099                                 HWCRHK_R_REQUEST_FALLBACK);
1100                         }
1101                 else
1102                         {
1103                         HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,
1104                                 HWCRHK_R_REQUEST_FAILED);
1105                         }
1106                 ERR_add_error_data(1,rmsg.buf);
1107                 goto err;
1108                 }
1109         to_return = 1;
1110  err:
1111         return to_return;
1112         }
1113
1114 static int hwcrhk_rand_status(void)
1115         {
1116         return 1;
1117         }
1118
1119 /* This cleans up an RSA KM key, called when ex_data is freed */
1120
1121 static void hwcrhk_ex_free(void *obj, void *item, CRYPTO_EX_DATA *ad,
1122         int ind,long argl, void *argp)
1123 {
1124         char tempbuf[1024];
1125         HWCryptoHook_ErrMsgBuf rmsg;
1126 #ifndef OPENSSL_NO_RSA
1127         HWCryptoHook_RSAKeyHandle *hptr;
1128 #endif
1129 #if !defined(OPENSSL_NO_RSA)
1130         int ret;
1131 #endif
1132
1133         rmsg.buf = tempbuf;
1134         rmsg.size = sizeof(tempbuf);
1135
1136 #ifndef OPENSSL_NO_RSA
1137         hptr = (HWCryptoHook_RSAKeyHandle *) item;
1138         if(hptr)
1139                 {
1140                 ret = p_hwcrhk_RSAUnloadKey(*hptr, NULL);
1141                 OPENSSL_free(hptr);
1142                 }
1143 #endif
1144 }
1145
1146 /* Mutex calls: since the HWCryptoHook model closely follows the POSIX model
1147  * these just wrap the POSIX functions and add some logging.
1148  */
1149
1150 static int hwcrhk_mutex_init(HWCryptoHook_Mutex* mt,
1151         HWCryptoHook_CallerContext *cactx)
1152         {
1153         mt->lockid = CRYPTO_get_new_dynlockid();
1154         if (mt->lockid == 0)
1155                 return 1; /* failure */
1156         return 0; /* success */
1157         }
1158
1159 static int hwcrhk_mutex_lock(HWCryptoHook_Mutex *mt)
1160         {
1161         CRYPTO_w_lock(mt->lockid);
1162         return 0;
1163         }
1164
1165 static void hwcrhk_mutex_unlock(HWCryptoHook_Mutex * mt)
1166         {
1167         CRYPTO_w_unlock(mt->lockid);
1168         }
1169
1170 static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex *mt)
1171         {
1172         CRYPTO_destroy_dynlockid(mt->lockid);
1173         }
1174
1175 static int hwcrhk_get_pass(const char *prompt_info,
1176         int *len_io, char *buf,
1177         HWCryptoHook_PassphraseContext *ppctx,
1178         HWCryptoHook_CallerContext *cactx)
1179         {
1180         pem_password_cb *callback = NULL;
1181         void *callback_data = NULL;
1182         UI_METHOD *ui_method = NULL;
1183
1184         if (cactx)
1185                 {
1186                 if (cactx->ui_method)
1187                         ui_method = cactx->ui_method;
1188                 if (cactx->password_callback)
1189                         callback = cactx->password_callback;
1190                 if (cactx->callback_data)
1191                         callback_data = cactx->callback_data;
1192                 }
1193         if (ppctx)
1194                 {
1195                 if (ppctx->ui_method)
1196                         {
1197                         ui_method = ppctx->ui_method;
1198                         callback = NULL;
1199                         }
1200                 if (ppctx->callback_data)
1201                         callback_data = ppctx->callback_data;
1202                 }
1203         if (callback == NULL && ui_method == NULL)
1204                 {
1205                 HWCRHKerr(HWCRHK_F_HWCRHK_GET_PASS,HWCRHK_R_NO_CALLBACK);
1206                 return -1;
1207                 }
1208
1209         if (ui_method)
1210                 {
1211                 UI *ui = UI_new_method(ui_method);
1212                 if (ui)
1213                         {
1214                         int ok;
1215                         char *prompt = UI_construct_prompt(ui,
1216                                 "pass phrase", prompt_info);
1217
1218                         ok = UI_add_input_string(ui,prompt,
1219                                 UI_INPUT_FLAG_DEFAULT_PWD,
1220                                 buf,0,(*len_io) - 1);
1221                         UI_add_user_data(ui, callback_data);
1222                         UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0);
1223
1224                         if (ok >= 0)
1225                                 do
1226                                         {
1227                                         ok=UI_process(ui);
1228                                         }
1229                                 while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0));
1230
1231                         if (ok >= 0)
1232                                 *len_io = strlen(buf);
1233
1234                         UI_free(ui);
1235                         OPENSSL_free(prompt);
1236                         }
1237                 }
1238         else
1239                 {
1240                 *len_io = callback(buf, *len_io, 0, callback_data);
1241                 }
1242         if(!*len_io)
1243                 return -1;
1244         return 0;
1245         }
1246
1247 static int hwcrhk_insert_card(const char *prompt_info,
1248                       const char *wrong_info,
1249                       HWCryptoHook_PassphraseContext *ppctx,
1250                       HWCryptoHook_CallerContext *cactx)
1251         {
1252         int ok = -1;
1253         UI *ui;
1254         void *callback_data = NULL;
1255         UI_METHOD *ui_method = NULL;
1256
1257         if (cactx)
1258                 {
1259                 if (cactx->ui_method)
1260                         ui_method = cactx->ui_method;
1261                 if (cactx->callback_data)
1262                         callback_data = cactx->callback_data;
1263                 }
1264         if (ppctx)
1265                 {
1266                 if (ppctx->ui_method)
1267                         ui_method = ppctx->ui_method;
1268                 if (ppctx->callback_data)
1269                         callback_data = ppctx->callback_data;
1270                 }
1271         if (ui_method == NULL)
1272                 {
1273                 HWCRHKerr(HWCRHK_F_HWCRHK_INSERT_CARD,
1274                         HWCRHK_R_NO_CALLBACK);
1275                 return -1;
1276                 }
1277
1278         ui = UI_new_method(ui_method);
1279
1280         if (ui)
1281                 {
1282                 char answer;
1283                 char buf[BUFSIZ];
1284
1285                 if (wrong_info)
1286                         BIO_snprintf(buf, sizeof(buf)-1,
1287                                 "Current card: \"%s\"\n", wrong_info);
1288                 ok = UI_dup_info_string(ui, buf);
1289                 if (ok >= 0 && prompt_info)
1290                         {
1291                         BIO_snprintf(buf, sizeof(buf)-1,
1292                                 "Insert card \"%s\"", prompt_info);
1293                         ok = UI_dup_input_boolean(ui, buf,
1294                                 "\n then hit <enter> or C<enter> to cancel\n",
1295                                 "\r\n", "Cc", UI_INPUT_FLAG_ECHO, &answer);
1296                         }
1297                 UI_add_user_data(ui, callback_data);
1298
1299                 if (ok >= 0)
1300                         ok = UI_process(ui);
1301                 UI_free(ui);
1302
1303                 if (ok == -2 || (ok >= 0 && answer == 'C'))
1304                         ok = 1;
1305                 else if (ok < 0)
1306                         ok = -1;
1307                 else
1308                         ok = 0;
1309                 }
1310         return ok;
1311         }
1312
1313 static void hwcrhk_log_message(void *logstr, const char *message)
1314         {
1315         BIO *lstream = NULL;
1316
1317         CRYPTO_w_lock(CRYPTO_LOCK_BIO);
1318         if (logstr)
1319                 lstream=*(BIO **)logstr;
1320         if (lstream)
1321                 {
1322                 BIO_write(lstream, message, strlen(message));
1323                 }
1324         CRYPTO_w_unlock(CRYPTO_LOCK_BIO);
1325         }
1326
1327 /* This stuff is needed if this ENGINE is being compiled into a self-contained
1328  * shared-library. */      
1329 #ifndef OPENSSL_NO_DYNAMIC_ENGINE
1330 static int bind_fn(ENGINE *e, const char *id)
1331         {
1332         if(id && (strcmp(id, engine_hwcrhk_id) != 0))
1333                 return 0;
1334         if(!bind_helper(e))
1335                 return 0;
1336         return 1;
1337         }       
1338 IMPLEMENT_DYNAMIC_CHECK_FN()
1339 IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
1340 #endif /* OPENSSL_NO_DYNAMIC_ENGINE */
1341
1342 #endif /* !OPENSSL_NO_HW_NCIPHER */
1343 #endif /* !OPENSSL_NO_HW */