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