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