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