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