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