fix submitted by Andy Schneider <andy.schneider@bjss.co.uk>
[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 = 1024;
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         HWCryptoHook_ErrMsgBuf rmsg;
806 #endif
807         HWCryptoHook_PassphraseContext ppctx;
808
809         if(!hwcrhk_context)
810                 {
811                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
812                         HWCRHK_R_NOT_INITIALISED);
813                 goto err;
814                 }
815 #ifndef OPENSSL_NO_RSA
816         hptr = OPENSSL_malloc(sizeof(HWCryptoHook_RSAKeyHandle));
817         if (!hptr)
818                 {
819                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
820                         ERR_R_MALLOC_FAILURE);
821                 goto err;
822                 }
823         ppctx.ui_method = ui_method;
824         ppctx.callback_data = callback_data;
825         if (p_hwcrhk_RSALoadKey(hwcrhk_context, key_id, hptr,
826                 &rmsg, &ppctx))
827                 {
828                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
829                         HWCRHK_R_CHIL_ERROR);
830                 ERR_add_error_data(1,rmsg.buf);
831                 goto err;
832                 }
833         if (!*hptr)
834                 {
835                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
836                         HWCRHK_R_NO_KEY);
837                 goto err;
838                 }
839 #endif
840 #ifndef OPENSSL_NO_RSA
841         rtmp = RSA_new_method(eng);
842         RSA_set_ex_data(rtmp, hndidx_rsa, (char *)hptr);
843         rtmp->e = BN_new();
844         rtmp->n = BN_new();
845         rtmp->flags |= RSA_FLAG_EXT_PKEY;
846         MPI2BN(rtmp->e, e);
847         MPI2BN(rtmp->n, n);
848         if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg)
849                 != HWCRYPTOHOOK_ERROR_MPISIZE)
850                 {
851                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,HWCRHK_R_CHIL_ERROR);
852                 ERR_add_error_data(1,rmsg.buf);
853                 goto err;
854                 }
855
856         bn_expand2(rtmp->e, e.size/sizeof(BN_ULONG));
857         bn_expand2(rtmp->n, n.size/sizeof(BN_ULONG));
858         MPI2BN(rtmp->e, e);
859         MPI2BN(rtmp->n, n);
860
861         if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg))
862                 {
863                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
864                         HWCRHK_R_CHIL_ERROR);
865                 ERR_add_error_data(1,rmsg.buf);
866                 goto err;
867                 }
868         rtmp->e->top = e.size / sizeof(BN_ULONG);
869         bn_fix_top(rtmp->e);
870         rtmp->n->top = n.size / sizeof(BN_ULONG);
871         bn_fix_top(rtmp->n);
872
873         res = EVP_PKEY_new();
874         EVP_PKEY_assign_RSA(res, rtmp);
875 #endif
876
877         if (!res)
878                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
879                         HWCRHK_R_PRIVATE_KEY_ALGORITHMS_DISABLED);
880
881         return res;
882  err:
883         if (res)
884                 EVP_PKEY_free(res);
885 #ifndef OPENSSL_NO_RSA
886         if (rtmp)
887                 RSA_free(rtmp);
888 #endif
889         return NULL;
890         }
891
892 static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
893         UI_METHOD *ui_method, void *callback_data)
894         {
895         EVP_PKEY *res = NULL;
896
897 #ifndef OPENSSL_NO_RSA
898         res = hwcrhk_load_privkey(eng, key_id,
899                 ui_method, callback_data);
900 #endif
901
902         if (res)
903                 switch(res->type)
904                         {
905 #ifndef OPENSSL_NO_RSA
906                 case EVP_PKEY_RSA:
907                         {
908                         RSA *rsa = NULL;
909
910                         CRYPTO_w_lock(CRYPTO_LOCK_EVP_PKEY);
911                         rsa = res->pkey.rsa;
912                         res->pkey.rsa = RSA_new();
913                         res->pkey.rsa->n = rsa->n;
914                         res->pkey.rsa->e = rsa->e;
915                         CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY);
916                         RSA_free(rsa);
917                         }
918 #endif
919                 default:
920                         HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
921                                 HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
922                         goto err;
923                         }
924
925         return res;
926  err:
927         if (res)
928                 EVP_PKEY_free(res);
929         return NULL;
930         }
931
932 /* A little mod_exp */
933 static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
934                         const BIGNUM *m, BN_CTX *ctx)
935         {
936         char tempbuf[1024];
937         HWCryptoHook_ErrMsgBuf rmsg;
938         /* Since HWCryptoHook_MPI is pretty compatible with BIGNUM's,
939            we use them directly, plus a little macro magic.  We only
940            thing we need to make sure of is that enough space is allocated. */
941         HWCryptoHook_MPI m_a, m_p, m_n, m_r;
942         int to_return, ret;
943  
944         to_return = 0; /* expect failure */
945         rmsg.buf = tempbuf;
946         rmsg.size = 1024;
947
948         if(!hwcrhk_context)
949                 {
950                 HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_NOT_INITIALISED);
951                 goto err;
952                 }
953         /* Prepare the params */
954         bn_expand2(r, m->top);  /* Check for error !! */
955         BN2MPI(m_a, a);
956         BN2MPI(m_p, p);
957         BN2MPI(m_n, m);
958         MPI2BN(r, m_r);
959
960         /* Perform the operation */
961         ret = p_hwcrhk_ModExp(hwcrhk_context, m_a, m_p, m_n, &m_r, &rmsg);
962
963         /* Convert the response */
964         r->top = m_r.size / sizeof(BN_ULONG);
965         bn_fix_top(r);
966
967         if (ret < 0)
968                 {
969                 /* FIXME: When this error is returned, HWCryptoHook is
970                    telling us that falling back to software computation
971                    might be a good thing. */
972                 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
973                         {
974                         HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_REQUEST_FALLBACK);
975                         }
976                 else
977                         {
978                         HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_REQUEST_FAILED);
979                         }
980                 ERR_add_error_data(1,rmsg.buf);
981                 goto err;
982                 }
983
984         to_return = 1;
985 err:
986         return to_return;
987         }
988
989 #ifndef OPENSSL_NO_RSA 
990 static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa)
991         {
992         char tempbuf[1024];
993         HWCryptoHook_ErrMsgBuf rmsg;
994         HWCryptoHook_RSAKeyHandle *hptr;
995         int to_return = 0, ret;
996
997         if(!hwcrhk_context)
998                 {
999                 HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_NOT_INITIALISED);
1000                 goto err;
1001                 }
1002
1003         /* This provides support for nForce keys.  Since that's opaque data
1004            all we do is provide a handle to the proper key and let HWCryptoHook
1005            take care of the rest. */
1006         if ((hptr = (HWCryptoHook_RSAKeyHandle *) RSA_get_ex_data(rsa, hndidx_rsa))
1007                 != NULL)
1008                 {
1009                 HWCryptoHook_MPI m_a, m_r;
1010
1011                 if(!rsa->n)
1012                         {
1013                         HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1014                                 HWCRHK_R_MISSING_KEY_COMPONENTS);
1015                         goto err;
1016                         }
1017
1018                 rmsg.buf = tempbuf;
1019                 rmsg.size = 1024;
1020
1021                 /* Prepare the params */
1022                 bn_expand2(r, rsa->n->top); /* Check for error !! */
1023                 BN2MPI(m_a, I);
1024                 MPI2BN(r, m_r);
1025
1026                 /* Perform the operation */
1027                 ret = p_hwcrhk_RSA(m_a, *hptr, &m_r, &rmsg);
1028
1029                 /* Convert the response */
1030                 r->top = m_r.size / sizeof(BN_ULONG);
1031                 bn_fix_top(r);
1032
1033                 if (ret < 0)
1034                         {
1035                         /* FIXME: When this error is returned, HWCryptoHook is
1036                            telling us that falling back to software computation
1037                            might be a good thing. */
1038                         if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1039                                 {
1040                                 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1041                                         HWCRHK_R_REQUEST_FALLBACK);
1042                                 }
1043                         else
1044                                 {
1045                                 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1046                                         HWCRHK_R_REQUEST_FAILED);
1047                                 }
1048                         ERR_add_error_data(1,rmsg.buf);
1049                         goto err;
1050                         }
1051                 }
1052         else
1053                 {
1054                 HWCryptoHook_MPI m_a, m_p, m_q, m_dmp1, m_dmq1, m_iqmp, m_r;
1055
1056                 if(!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp)
1057                         {
1058                         HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1059                                 HWCRHK_R_MISSING_KEY_COMPONENTS);
1060                         goto err;
1061                         }
1062
1063                 rmsg.buf = tempbuf;
1064                 rmsg.size = 1024;
1065
1066                 /* Prepare the params */
1067                 bn_expand2(r, rsa->n->top); /* Check for error !! */
1068                 BN2MPI(m_a, I);
1069                 BN2MPI(m_p, rsa->p);
1070                 BN2MPI(m_q, rsa->q);
1071                 BN2MPI(m_dmp1, rsa->dmp1);
1072                 BN2MPI(m_dmq1, rsa->dmq1);
1073                 BN2MPI(m_iqmp, rsa->iqmp);
1074                 MPI2BN(r, m_r);
1075
1076                 /* Perform the operation */
1077                 ret = p_hwcrhk_ModExpCRT(hwcrhk_context, m_a, m_p, m_q,
1078                         m_dmp1, m_dmq1, m_iqmp, &m_r, NULL);
1079
1080                 /* Convert the response */
1081                 r->top = m_r.size / sizeof(BN_ULONG);
1082                 bn_fix_top(r);
1083
1084                 if (ret < 0)
1085                         {
1086                         /* FIXME: When this error is returned, HWCryptoHook is
1087                            telling us that falling back to software computation
1088                            might be a good thing. */
1089                         if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1090                                 {
1091                                 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1092                                         HWCRHK_R_REQUEST_FALLBACK);
1093                                 }
1094                         else
1095                                 {
1096                                 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1097                                         HWCRHK_R_REQUEST_FAILED);
1098                                 }
1099                         ERR_add_error_data(1,rmsg.buf);
1100                         goto err;
1101                         }
1102                 }
1103         /* If we're here, we must be here with some semblance of success :-) */
1104         to_return = 1;
1105 err:
1106         return to_return;
1107         }
1108 #endif
1109
1110 /* This function is aliased to mod_exp (with the mont stuff dropped). */
1111 static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
1112                 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1113         {
1114         return hwcrhk_mod_exp(r, a, p, m, ctx);
1115         }
1116
1117 /* This function is aliased to mod_exp (with the dh and mont dropped). */
1118 static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r,
1119                 const BIGNUM *a, const BIGNUM *p,
1120                 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1121         {
1122         return hwcrhk_mod_exp(r, a, p, m, ctx);
1123         }
1124
1125 /* Random bytes are good */
1126 static int hwcrhk_rand_bytes(unsigned char *buf, int num)
1127         {
1128         char tempbuf[1024];
1129         HWCryptoHook_ErrMsgBuf rmsg;
1130         int to_return = 0; /* assume failure */
1131         int ret;
1132
1133         rmsg.buf = tempbuf;
1134         rmsg.size = 1024;
1135
1136         if(!hwcrhk_context)
1137                 {
1138                 HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,HWCRHK_R_NOT_INITIALISED);
1139                 goto err;
1140                 }
1141
1142         ret = p_hwcrhk_RandomBytes(hwcrhk_context, buf, num, &rmsg);
1143         if (ret < 0)
1144                 {
1145                 /* FIXME: When this error is returned, HWCryptoHook is
1146                    telling us that falling back to software computation
1147                    might be a good thing. */
1148                 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1149                         {
1150                         HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,
1151                                 HWCRHK_R_REQUEST_FALLBACK);
1152                         }
1153                 else
1154                         {
1155                         HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,
1156                                 HWCRHK_R_REQUEST_FAILED);
1157                         }
1158                 ERR_add_error_data(1,rmsg.buf);
1159                 goto err;
1160                 }
1161         to_return = 1;
1162  err:
1163         return to_return;
1164         }
1165
1166 static int hwcrhk_rand_status(void)
1167         {
1168         return 1;
1169         }
1170
1171 /* This cleans up an RSA KM key, called when ex_data is freed */
1172
1173 static void hwcrhk_ex_free(void *obj, void *item, CRYPTO_EX_DATA *ad,
1174         int ind,long argl, void *argp)
1175 {
1176         char tempbuf[1024];
1177         HWCryptoHook_ErrMsgBuf rmsg;
1178 #ifndef OPENSSL_NO_RSA
1179         HWCryptoHook_RSAKeyHandle *hptr;
1180 #endif
1181 #if !defined(OPENSSL_NO_RSA)
1182         int ret;
1183 #endif
1184
1185         rmsg.buf = tempbuf;
1186         rmsg.size = 1024;
1187
1188 #ifndef OPENSSL_NO_RSA
1189         hptr = (HWCryptoHook_RSAKeyHandle *) item;
1190         if(hptr)
1191                 {
1192                 ret = p_hwcrhk_RSAUnloadKey(*hptr, NULL);
1193                 OPENSSL_free(hptr);
1194                 }
1195 #endif
1196 }
1197
1198 /* Mutex calls: since the HWCryptoHook model closely follows the POSIX model
1199  * these just wrap the POSIX functions and add some logging.
1200  */
1201
1202 static int hwcrhk_mutex_init(HWCryptoHook_Mutex* mt,
1203         HWCryptoHook_CallerContext *cactx)
1204         {
1205         mt->lockid = CRYPTO_get_new_dynlockid();
1206         if (mt->lockid == 0)
1207                 return 1; /* failure */
1208         return 0; /* success */
1209         }
1210
1211 static int hwcrhk_mutex_lock(HWCryptoHook_Mutex *mt)
1212         {
1213         CRYPTO_w_lock(mt->lockid);
1214         return 0;
1215         }
1216
1217 void hwcrhk_mutex_unlock(HWCryptoHook_Mutex * mt)
1218         {
1219         CRYPTO_w_unlock(mt->lockid);
1220         }
1221
1222 static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex *mt)
1223         {
1224         CRYPTO_destroy_dynlockid(mt->lockid);
1225         }
1226
1227 static int hwcrhk_get_pass(const char *prompt_info,
1228         int *len_io, char *buf,
1229         HWCryptoHook_PassphraseContext *ppctx,
1230         HWCryptoHook_CallerContext *cactx)
1231         {
1232         pem_password_cb *callback = NULL;
1233         void *callback_data = NULL;
1234         UI_METHOD *ui_method = NULL;
1235
1236         if (cactx)
1237                 {
1238                 if (cactx->ui_method)
1239                         ui_method = cactx->ui_method;
1240                 if (cactx->password_callback)
1241                         callback = cactx->password_callback;
1242                 if (cactx->callback_data)
1243                         callback_data = cactx->callback_data;
1244                 }
1245         if (ppctx)
1246                 {
1247                 if (ppctx->ui_method)
1248                         {
1249                         ui_method = ppctx->ui_method;
1250                         callback = NULL;
1251                         }
1252                 if (ppctx->callback_data)
1253                         callback_data = ppctx->callback_data;
1254                 }
1255         if (callback == NULL && ui_method == NULL)
1256                 {
1257                 HWCRHKerr(HWCRHK_F_HWCRHK_GET_PASS,HWCRHK_R_NO_CALLBACK);
1258                 return -1;
1259                 }
1260
1261         if (ui_method)
1262                 {
1263                 UI *ui = UI_new_method(ui_method);
1264                 if (ui)
1265                         {
1266                         int ok;
1267                         char *prompt = UI_construct_prompt(ui,
1268                                 "pass phrase", prompt_info);
1269
1270                         ok = UI_add_input_string(ui,prompt,
1271                                 UI_INPUT_FLAG_DEFAULT_PWD,
1272                                 buf,0,(*len_io) - 1);
1273                         UI_add_user_data(ui, callback_data);
1274                         UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0);
1275
1276                         if (ok >= 0)
1277                                 do
1278                                         {
1279                                         ok=UI_process(ui);
1280                                         }
1281                                 while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0));
1282
1283                         if (ok >= 0)
1284                                 *len_io = strlen(buf);
1285
1286                         UI_free(ui);
1287                         OPENSSL_free(prompt);
1288                         }
1289                 }
1290         else
1291                 {
1292                 *len_io = callback(buf, *len_io, 0, callback_data);
1293                 }
1294         if(!*len_io)
1295                 return -1;
1296         return 0;
1297         }
1298
1299 static int hwcrhk_insert_card(const char *prompt_info,
1300                       const char *wrong_info,
1301                       HWCryptoHook_PassphraseContext *ppctx,
1302                       HWCryptoHook_CallerContext *cactx)
1303         {
1304         int ok = -1;
1305         UI *ui;
1306         void *callback_data = NULL;
1307         UI_METHOD *ui_method = NULL;
1308
1309         if (cactx)
1310                 {
1311                 if (cactx->ui_method)
1312                         ui_method = cactx->ui_method;
1313                 if (cactx->callback_data)
1314                         callback_data = cactx->callback_data;
1315                 }
1316         if (ppctx)
1317                 {
1318                 if (ppctx->ui_method)
1319                         ui_method = ppctx->ui_method;
1320                 if (ppctx->callback_data)
1321                         callback_data = ppctx->callback_data;
1322                 }
1323         if (ui_method == NULL)
1324                 {
1325                 HWCRHKerr(HWCRHK_F_HWCRHK_INSERT_CARD,
1326                         HWCRHK_R_NO_CALLBACK);
1327                 return -1;
1328                 }
1329
1330         ui = UI_new_method(ui_method);
1331
1332         if (ui)
1333                 {
1334                 char answer;
1335                 char buf[BUFSIZ];
1336
1337                 if (wrong_info)
1338                         BIO_snprintf(buf, sizeof(buf)-1,
1339                                 "Current card: \"%s\"\n", wrong_info);
1340                 ok = UI_dup_info_string(ui, buf);
1341                 if (ok >= 0 && prompt_info)
1342                         {
1343                         BIO_snprintf(buf, sizeof(buf)-1,
1344                                 "Insert card \"%s\"", prompt_info);
1345                         ok = UI_dup_input_boolean(ui, buf,
1346                                 "\n then hit <enter> or C<enter> to cancel\n",
1347                                 "\r\n", "Cc", UI_INPUT_FLAG_ECHO, &answer);
1348                         }
1349                 UI_add_user_data(ui, callback_data);
1350
1351                 if (ok >= 0)
1352                         ok = UI_process(ui);
1353                 UI_free(ui);
1354
1355                 if (ok == -2 || (ok >= 0 && answer == 'C'))
1356                         ok = 1;
1357                 else if (ok < 0)
1358                         ok = -1;
1359                 else
1360                         ok = 0;
1361                 }
1362         return ok;
1363         }
1364
1365 static void hwcrhk_log_message(void *logstr, const char *message)
1366         {
1367         BIO *lstream = NULL;
1368
1369         CRYPTO_w_lock(CRYPTO_LOCK_BIO);
1370         if (logstr)
1371                 lstream=*(BIO **)logstr;
1372         if (lstream)
1373                 {
1374                 BIO_write(lstream, message, strlen(message));
1375                 }
1376         CRYPTO_w_unlock(CRYPTO_LOCK_BIO);
1377         }
1378
1379 /* This stuff is needed if this ENGINE is being compiled into a self-contained
1380  * shared-library. */      
1381 #ifdef ENGINE_DYNAMIC_SUPPORT
1382 static int bind_fn(ENGINE *e, const char *id)
1383         {
1384         if(id && (strcmp(id, engine_hwcrhk_id) != 0))
1385                 return 0;
1386         if(!bind_helper(e))
1387                 return 0;
1388         return 1;
1389         }       
1390 IMPLEMENT_DYNAMIC_CHECK_FN()
1391 IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
1392 #endif /* ENGINE_DYNAMIC_SUPPORT */
1393
1394 #endif /* !OPENSSL_NO_HW_NCIPHER */
1395 #endif /* !OPENSSL_NO_HW */