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