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