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