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