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