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