408db08b9849a28c94578f4759dc68ab1db8cc9c
[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_BN_mod_exp(e, hwcrhk_mod_exp) ||
421                         !ENGINE_set_destroy_function(e, hwcrhk_destroy) ||
422                         !ENGINE_set_init_function(e, hwcrhk_init) ||
423                         !ENGINE_set_finish_function(e, hwcrhk_finish) ||
424                         !ENGINE_set_ctrl_function(e, hwcrhk_ctrl) ||
425                         !ENGINE_set_load_privkey_function(e, hwcrhk_load_privkey) ||
426                         !ENGINE_set_load_pubkey_function(e, hwcrhk_load_pubkey) ||
427                         !ENGINE_set_cmd_defns(e, hwcrhk_cmd_defns))
428                 return 0;
429
430 #ifndef OPENSSL_NO_RSA
431         /* We know that the "PKCS1_SSLeay()" functions hook properly
432          * to the cswift-specific mod_exp and mod_exp_crt so we use
433          * those functions. NB: We don't use ENGINE_openssl() or
434          * anything "more generic" because something like the RSAref
435          * code may not hook properly, and if you own one of these
436          * cards then you have the right to do RSA operations on it
437          * anyway! */ 
438         meth1 = RSA_PKCS1_SSLeay();
439         hwcrhk_rsa.rsa_pub_enc = meth1->rsa_pub_enc;
440         hwcrhk_rsa.rsa_pub_dec = meth1->rsa_pub_dec;
441         hwcrhk_rsa.rsa_priv_enc = meth1->rsa_priv_enc;
442         hwcrhk_rsa.rsa_priv_dec = meth1->rsa_priv_dec;
443 #endif
444
445 #ifndef OPENSSL_NO_DH
446         /* Much the same for Diffie-Hellman */
447         meth2 = DH_OpenSSL();
448         hwcrhk_dh.generate_key = meth2->generate_key;
449         hwcrhk_dh.compute_key = meth2->compute_key;
450 #endif
451
452         /* Ensure the hwcrhk error handling is set up */
453         hwcrhk_load_error_strings();
454         return 1;
455         }
456
457 /* As this is only ever called once, there's no need for locking
458  * (indeed - the lock will already be held by our caller!!!) */
459 ENGINE *ENGINE_ncipher(void)
460         {
461         ENGINE *ret = ENGINE_new();
462         if(!ret)
463                 return NULL;
464         if(!bind_helper(ret))
465                 {
466                 ENGINE_free(ret);
467                 return NULL;
468                 }
469         return ret;
470         }
471
472 /* This is a process-global DSO handle used for loading and unloading
473  * the HWCryptoHook library. NB: This is only set (or unset) during an
474  * init() or finish() call (reference counts permitting) and they're
475  * operating with global locks, so this should be thread-safe
476  * implicitly. */
477 static DSO *hwcrhk_dso = NULL;
478 static HWCryptoHook_ContextHandle hwcrhk_context = 0;
479 #ifndef OPENSSL_NO_RSA
480 static int hndidx_rsa = -1;    /* Index for KM handle.  Not really used yet. */
481 #endif
482
483 /* These are the function pointers that are (un)set when the library has
484  * successfully (un)loaded. */
485 static HWCryptoHook_Init_t *p_hwcrhk_Init = NULL;
486 static HWCryptoHook_Finish_t *p_hwcrhk_Finish = NULL;
487 static HWCryptoHook_ModExp_t *p_hwcrhk_ModExp = NULL;
488 #ifndef OPENSSL_NO_RSA
489 static HWCryptoHook_RSA_t *p_hwcrhk_RSA = NULL;
490 #endif
491 static HWCryptoHook_RandomBytes_t *p_hwcrhk_RandomBytes = NULL;
492 #ifndef OPENSSL_NO_RSA
493 static HWCryptoHook_RSALoadKey_t *p_hwcrhk_RSALoadKey = NULL;
494 static HWCryptoHook_RSAGetPublicKey_t *p_hwcrhk_RSAGetPublicKey = NULL;
495 static HWCryptoHook_RSAUnloadKey_t *p_hwcrhk_RSAUnloadKey = NULL;
496 #endif
497 static HWCryptoHook_ModExpCRT_t *p_hwcrhk_ModExpCRT = NULL;
498
499 /* Used in the DSO operations. */
500 static const char def_HWCRHK_LIBNAME[] = "nfhwcrhk";
501 static const char *HWCRHK_LIBNAME = def_HWCRHK_LIBNAME;
502 static const char *n_hwcrhk_Init = "HWCryptoHook_Init";
503 static const char *n_hwcrhk_Finish = "HWCryptoHook_Finish";
504 static const char *n_hwcrhk_ModExp = "HWCryptoHook_ModExp";
505 #ifndef OPENSSL_NO_RSA
506 static const char *n_hwcrhk_RSA = "HWCryptoHook_RSA";
507 #endif
508 static const char *n_hwcrhk_RandomBytes = "HWCryptoHook_RandomBytes";
509 #ifndef OPENSSL_NO_RSA
510 static const char *n_hwcrhk_RSALoadKey = "HWCryptoHook_RSALoadKey";
511 static const char *n_hwcrhk_RSAGetPublicKey = "HWCryptoHook_RSAGetPublicKey";
512 static const char *n_hwcrhk_RSAUnloadKey = "HWCryptoHook_RSAUnloadKey";
513 #endif
514 static const char *n_hwcrhk_ModExpCRT = "HWCryptoHook_ModExpCRT";
515
516 /* HWCryptoHook library functions and mechanics - these are used by the
517  * higher-level functions further down. NB: As and where there's no
518  * error checking, take a look lower down where these functions are
519  * called, the checking and error handling is probably down there. */
520
521 /* utility function to obtain a context */
522 static int get_context(HWCryptoHook_ContextHandle *hac,
523         HWCryptoHook_CallerContext *cac)
524         {
525         char tempbuf[1024];
526         HWCryptoHook_ErrMsgBuf rmsg;
527
528         rmsg.buf = tempbuf;
529         rmsg.size = 1024;
530
531         *hac = p_hwcrhk_Init(&hwcrhk_globals, sizeof(hwcrhk_globals), &rmsg,
532                 cac);
533         if (!*hac)
534                 return 0;
535         return 1;
536         }
537  
538 /* similarly to release one. */
539 static void release_context(HWCryptoHook_ContextHandle hac)
540         {
541         p_hwcrhk_Finish(hac);
542         }
543
544 /* Destructor (complements the "ENGINE_ncipher()" constructor) */
545 static int hwcrhk_destroy(ENGINE *e)
546         {
547         hwcrhk_unload_error_strings();
548         return 1;
549         }
550
551 /* (de)initialisation functions. */
552 static int hwcrhk_init(ENGINE *e)
553         {
554         HWCryptoHook_Init_t *p1;
555         HWCryptoHook_Finish_t *p2;
556         HWCryptoHook_ModExp_t *p3;
557 #ifndef OPENSSL_NO_RSA
558         HWCryptoHook_RSA_t *p4;
559         HWCryptoHook_RSALoadKey_t *p5;
560         HWCryptoHook_RSAGetPublicKey_t *p6;
561         HWCryptoHook_RSAUnloadKey_t *p7;
562 #endif
563         HWCryptoHook_RandomBytes_t *p8;
564         HWCryptoHook_ModExpCRT_t *p9;
565
566         if(hwcrhk_dso != NULL)
567                 {
568                 HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_ALREADY_LOADED);
569                 goto err;
570                 }
571         /* Attempt to load libnfhwcrhk.so/nfhwcrhk.dll/whatever. */
572         hwcrhk_dso = DSO_load(NULL, HWCRHK_LIBNAME, NULL, 0);
573         if(hwcrhk_dso == NULL)
574                 {
575                 HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_DSO_FAILURE);
576                 goto err;
577                 }
578         if(!(p1 = (HWCryptoHook_Init_t *)
579                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_Init)) ||
580                 !(p2 = (HWCryptoHook_Finish_t *)
581                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_Finish)) ||
582                 !(p3 = (HWCryptoHook_ModExp_t *)
583                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_ModExp)) ||
584 #ifndef OPENSSL_NO_RSA
585                 !(p4 = (HWCryptoHook_RSA_t *)
586                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSA)) ||
587                 !(p5 = (HWCryptoHook_RSALoadKey_t *)
588                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSALoadKey)) ||
589                 !(p6 = (HWCryptoHook_RSAGetPublicKey_t *)
590                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSAGetPublicKey)) ||
591                 !(p7 = (HWCryptoHook_RSAUnloadKey_t *)
592                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSAUnloadKey)) ||
593 #endif
594                 !(p8 = (HWCryptoHook_RandomBytes_t *)
595                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_RandomBytes)) ||
596                 !(p9 = (HWCryptoHook_ModExpCRT_t *)
597                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_ModExpCRT)))
598                 {
599                 HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_DSO_FAILURE);
600                 goto err;
601                 }
602         /* Copy the pointers */
603         p_hwcrhk_Init = p1;
604         p_hwcrhk_Finish = p2;
605         p_hwcrhk_ModExp = p3;
606 #ifndef OPENSSL_NO_RSA
607         p_hwcrhk_RSA = p4;
608         p_hwcrhk_RSALoadKey = p5;
609         p_hwcrhk_RSAGetPublicKey = p6;
610         p_hwcrhk_RSAUnloadKey = p7;
611 #endif
612         p_hwcrhk_RandomBytes = p8;
613         p_hwcrhk_ModExpCRT = p9;
614
615         /* Check if the application decided to support dynamic locks,
616            and if it does, use them. */
617         if (disable_mutex_callbacks == 0 &&
618                 CRYPTO_get_dynlock_create_callback() != NULL &&
619                 CRYPTO_get_dynlock_lock_callback() != NULL &&
620                 CRYPTO_get_dynlock_destroy_callback() != NULL)
621                 {
622                 hwcrhk_globals.mutex_init = hwcrhk_mutex_init;
623                 hwcrhk_globals.mutex_acquire = hwcrhk_mutex_lock;
624                 hwcrhk_globals.mutex_release = hwcrhk_mutex_unlock;
625                 hwcrhk_globals.mutex_destroy = hwcrhk_mutex_destroy;
626                 }
627
628         /* Try and get a context - if not, we may have a DSO but no
629          * accelerator! */
630         if(!get_context(&hwcrhk_context, &password_context))
631                 {
632                 HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_UNIT_FAILURE);
633                 goto err;
634                 }
635         /* Everything's fine. */
636 #ifndef OPENSSL_NO_RSA
637         if (hndidx_rsa == -1)
638                 hndidx_rsa = RSA_get_ex_new_index(0,
639                         "nFast HWCryptoHook RSA key handle",
640                         NULL, NULL, hwcrhk_ex_free);
641 #endif
642         return 1;
643 err:
644         if(hwcrhk_dso)
645                 DSO_free(hwcrhk_dso);
646         hwcrhk_dso = NULL;
647         p_hwcrhk_Init = NULL;
648         p_hwcrhk_Finish = NULL;
649         p_hwcrhk_ModExp = NULL;
650 #ifndef OPENSSL_NO_RSA
651         p_hwcrhk_RSA = NULL;
652         p_hwcrhk_RSALoadKey = NULL;
653         p_hwcrhk_RSAGetPublicKey = NULL;
654         p_hwcrhk_RSAUnloadKey = NULL;
655 #endif
656         p_hwcrhk_ModExpCRT = NULL;
657         p_hwcrhk_RandomBytes = NULL;
658         return 0;
659         }
660
661 static int hwcrhk_finish(ENGINE *e)
662         {
663         int to_return = 1;
664         if(hwcrhk_dso == NULL)
665                 {
666                 HWCRHKerr(HWCRHK_F_HWCRHK_FINISH,HWCRHK_R_NOT_LOADED);
667                 to_return = 0;
668                 goto err;
669                 }
670         release_context(hwcrhk_context);
671         if(!DSO_free(hwcrhk_dso))
672                 {
673                 HWCRHKerr(HWCRHK_F_HWCRHK_FINISH,HWCRHK_R_DSO_FAILURE);
674                 to_return = 0;
675                 goto err;
676                 }
677  err:
678         if (logstream)
679                 BIO_free(logstream);
680         hwcrhk_dso = NULL;
681         p_hwcrhk_Init = NULL;
682         p_hwcrhk_Finish = NULL;
683         p_hwcrhk_ModExp = NULL;
684 #ifndef OPENSSL_NO_RSA
685         p_hwcrhk_RSA = NULL;
686         p_hwcrhk_RSALoadKey = NULL;
687         p_hwcrhk_RSAGetPublicKey = NULL;
688         p_hwcrhk_RSAUnloadKey = NULL;
689 #endif
690         p_hwcrhk_ModExpCRT = NULL;
691         p_hwcrhk_RandomBytes = NULL;
692         return to_return;
693         }
694
695 static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
696         {
697         int to_return = 1;
698
699         switch(cmd)
700                 {
701         case HWCRHK_CMD_SO_PATH:
702                 if(hwcrhk_dso)
703                         {
704                         HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,HWCRHK_R_ALREADY_LOADED);
705                         return 0;
706                         }
707                 if(p == NULL)
708                         {
709                         HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,ERR_R_PASSED_NULL_PARAMETER);
710                         return 0;
711                         }
712                 HWCRHK_LIBNAME = (const char *)p;
713                 return 1;
714         case ENGINE_CTRL_SET_LOGSTREAM:
715                 {
716                 BIO *bio = (BIO *)p;
717
718                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
719                 if (logstream)
720                         {
721                         BIO_free(logstream);
722                         logstream = NULL;
723                         }
724                 if (CRYPTO_add(&bio->references,1,CRYPTO_LOCK_BIO) > 1)
725                         logstream = bio;
726                 else
727                         HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,HWCRHK_R_BIO_WAS_FREED);
728                 }
729                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
730                 break;
731         case ENGINE_CTRL_SET_PASSWORD_CALLBACK:
732                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
733                 password_context.password_callback = (pem_password_cb *)f;
734                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
735                 break;
736         case ENGINE_CTRL_SET_USER_INTERFACE:
737                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
738                 password_context.ui_method = (UI_METHOD *)p;
739                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
740                 break;
741         case ENGINE_CTRL_SET_CALLBACK_DATA:
742                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
743                 password_context.callback_data = p;
744                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
745                 break;
746         /* this enables or disables the "SimpleForkCheck" flag used in the
747          * initialisation structure. */
748         case ENGINE_CTRL_CHIL_SET_FORKCHECK:
749         case HWCRHK_CMD_FORK_CHECK:
750                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
751                 if(i)
752                         hwcrhk_globals.flags |=
753                                 HWCryptoHook_InitFlags_SimpleForkCheck;
754                 else
755                         hwcrhk_globals.flags &=
756                                 ~HWCryptoHook_InitFlags_SimpleForkCheck;
757                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
758                 break;
759         /* This will prevent the initialisation function from "installing"
760          * the mutex-handling callbacks, even if they are available from
761          * within the library (or were provided to the library from the
762          * calling application). This is to remove any baggage for
763          * applications not using multithreading. */
764         case ENGINE_CTRL_CHIL_NO_LOCKING:
765                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
766                 disable_mutex_callbacks = 1;
767                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
768                 break;
769         case HWCRHK_CMD_THREAD_LOCKING:
770                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
771                 disable_mutex_callbacks = ((i == 0) ? 0 : 1);
772                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
773                 break;
774
775         /* The command isn't understood by this engine */
776         default:
777                 HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,
778                         HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
779                 to_return = 0;
780                 break;
781                 }
782
783         return to_return;
784         }
785
786 static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
787         UI_METHOD *ui_method, void *callback_data)
788         {
789 #ifndef OPENSSL_NO_RSA
790         RSA *rtmp = NULL;
791 #endif
792         EVP_PKEY *res = NULL;
793 #ifndef OPENSSL_NO_RSA
794         HWCryptoHook_MPI e, n;
795         HWCryptoHook_RSAKeyHandle *hptr;
796 #endif
797 #if !defined(OPENSSL_NO_RSA)
798         HWCryptoHook_ErrMsgBuf rmsg;
799 #endif
800         HWCryptoHook_PassphraseContext ppctx;
801
802         if(!hwcrhk_context)
803                 {
804                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
805                         HWCRHK_R_NOT_INITIALISED);
806                 goto err;
807                 }
808 #ifndef OPENSSL_NO_RSA
809         hptr = OPENSSL_malloc(sizeof(HWCryptoHook_RSAKeyHandle));
810         if (!hptr)
811                 {
812                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
813                         ERR_R_MALLOC_FAILURE);
814                 goto err;
815                 }
816         ppctx.ui_method = ui_method;
817         ppctx.callback_data = callback_data;
818         if (p_hwcrhk_RSALoadKey(hwcrhk_context, key_id, hptr,
819                 &rmsg, &ppctx))
820                 {
821                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
822                         HWCRHK_R_CHIL_ERROR);
823                 ERR_add_error_data(1,rmsg.buf);
824                 goto err;
825                 }
826         if (!*hptr)
827                 {
828                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
829                         HWCRHK_R_NO_KEY);
830                 goto err;
831                 }
832 #endif
833 #ifndef OPENSSL_NO_RSA
834         rtmp = RSA_new_method(eng);
835         RSA_set_ex_data(rtmp, hndidx_rsa, (char *)hptr);
836         rtmp->e = BN_new();
837         rtmp->n = BN_new();
838         rtmp->flags |= RSA_FLAG_EXT_PKEY;
839         MPI2BN(rtmp->e, e);
840         MPI2BN(rtmp->n, n);
841         if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg)
842                 != HWCRYPTOHOOK_ERROR_MPISIZE)
843                 {
844                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,HWCRHK_R_CHIL_ERROR);
845                 ERR_add_error_data(1,rmsg.buf);
846                 goto err;
847                 }
848
849         bn_expand2(rtmp->e, e.size/sizeof(BN_ULONG));
850         bn_expand2(rtmp->n, n.size/sizeof(BN_ULONG));
851         MPI2BN(rtmp->e, e);
852         MPI2BN(rtmp->n, n);
853
854         if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg))
855                 {
856                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
857                         HWCRHK_R_CHIL_ERROR);
858                 ERR_add_error_data(1,rmsg.buf);
859                 goto err;
860                 }
861         rtmp->e->top = e.size / sizeof(BN_ULONG);
862         bn_fix_top(rtmp->e);
863         rtmp->n->top = n.size / sizeof(BN_ULONG);
864         bn_fix_top(rtmp->n);
865
866         res = EVP_PKEY_new();
867         EVP_PKEY_assign_RSA(res, rtmp);
868 #endif
869
870         if (!res)
871                 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
872                         HWCRHK_R_PRIVATE_KEY_ALGORITHMS_DISABLED);
873
874         return res;
875  err:
876         if (res)
877                 EVP_PKEY_free(res);
878 #ifndef OPENSSL_NO_RSA
879         if (rtmp)
880                 RSA_free(rtmp);
881 #endif
882         return NULL;
883         }
884
885 static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
886         UI_METHOD *ui_method, void *callback_data)
887         {
888         EVP_PKEY *res = NULL;
889
890 #ifndef OPENSSL_NO_RSA
891         res = hwcrhk_load_privkey(eng, key_id,
892                 ui_method, callback_data);
893 #endif
894
895         if (res)
896                 switch(res->type)
897                         {
898 #ifndef OPENSSL_NO_RSA
899                 case EVP_PKEY_RSA:
900                         {
901                         RSA *rsa = NULL;
902
903                         CRYPTO_w_lock(CRYPTO_LOCK_EVP_PKEY);
904                         rsa = res->pkey.rsa;
905                         res->pkey.rsa = RSA_new();
906                         res->pkey.rsa->n = rsa->n;
907                         res->pkey.rsa->e = rsa->e;
908                         CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY);
909                         RSA_free(rsa);
910                         }
911 #endif
912                 default:
913                         HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
914                                 HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
915                         goto err;
916                         }
917
918         return res;
919  err:
920         if (res)
921                 EVP_PKEY_free(res);
922         return NULL;
923         }
924
925 /* A little mod_exp */
926 static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
927                         const BIGNUM *m, BN_CTX *ctx)
928         {
929         char tempbuf[1024];
930         HWCryptoHook_ErrMsgBuf rmsg;
931         /* Since HWCryptoHook_MPI is pretty compatible with BIGNUM's,
932            we use them directly, plus a little macro magic.  We only
933            thing we need to make sure of is that enough space is allocated. */
934         HWCryptoHook_MPI m_a, m_p, m_n, m_r;
935         int to_return, ret;
936  
937         to_return = 0; /* expect failure */
938         rmsg.buf = tempbuf;
939         rmsg.size = 1024;
940
941         if(!hwcrhk_context)
942                 {
943                 HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_NOT_INITIALISED);
944                 goto err;
945                 }
946         /* Prepare the params */
947         bn_expand2(r, m->top);  /* Check for error !! */
948         BN2MPI(m_a, a);
949         BN2MPI(m_p, p);
950         BN2MPI(m_n, m);
951         MPI2BN(r, m_r);
952
953         /* Perform the operation */
954         ret = p_hwcrhk_ModExp(hwcrhk_context, m_a, m_p, m_n, &m_r, &rmsg);
955
956         /* Convert the response */
957         r->top = m_r.size / sizeof(BN_ULONG);
958         bn_fix_top(r);
959
960         if (ret < 0)
961                 {
962                 /* FIXME: When this error is returned, HWCryptoHook is
963                    telling us that falling back to software computation
964                    might be a good thing. */
965                 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
966                         {
967                         HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_REQUEST_FALLBACK);
968                         }
969                 else
970                         {
971                         HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_REQUEST_FAILED);
972                         }
973                 ERR_add_error_data(1,rmsg.buf);
974                 goto err;
975                 }
976
977         to_return = 1;
978 err:
979         return to_return;
980         }
981
982 #ifndef OPENSSL_NO_RSA 
983 static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa)
984         {
985         char tempbuf[1024];
986         HWCryptoHook_ErrMsgBuf rmsg;
987         HWCryptoHook_RSAKeyHandle *hptr;
988         int to_return = 0, ret;
989
990         if(!hwcrhk_context)
991                 {
992                 HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_NOT_INITIALISED);
993                 goto err;
994                 }
995
996         /* This provides support for nForce keys.  Since that's opaque data
997            all we do is provide a handle to the proper key and let HWCryptoHook
998            take care of the rest. */
999         if ((hptr = (HWCryptoHook_RSAKeyHandle *) RSA_get_ex_data(rsa, hndidx_rsa))
1000                 != NULL)
1001                 {
1002                 HWCryptoHook_MPI m_a, m_r;
1003
1004                 if(!rsa->n)
1005                         {
1006                         HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1007                                 HWCRHK_R_MISSING_KEY_COMPONENTS);
1008                         goto err;
1009                         }
1010
1011                 rmsg.buf = tempbuf;
1012                 rmsg.size = 1024;
1013
1014                 /* Prepare the params */
1015                 bn_expand2(r, rsa->n->top); /* Check for error !! */
1016                 BN2MPI(m_a, I);
1017                 MPI2BN(r, m_r);
1018
1019                 /* Perform the operation */
1020                 ret = p_hwcrhk_RSA(m_a, *hptr, &m_r, &rmsg);
1021
1022                 /* Convert the response */
1023                 r->top = m_r.size / sizeof(BN_ULONG);
1024                 bn_fix_top(r);
1025
1026                 if (ret < 0)
1027                         {
1028                         /* FIXME: When this error is returned, HWCryptoHook is
1029                            telling us that falling back to software computation
1030                            might be a good thing. */
1031                         if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1032                                 {
1033                                 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1034                                         HWCRHK_R_REQUEST_FALLBACK);
1035                                 }
1036                         else
1037                                 {
1038                                 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1039                                         HWCRHK_R_REQUEST_FAILED);
1040                                 }
1041                         ERR_add_error_data(1,rmsg.buf);
1042                         goto err;
1043                         }
1044                 }
1045         else
1046                 {
1047                 HWCryptoHook_MPI m_a, m_p, m_q, m_dmp1, m_dmq1, m_iqmp, m_r;
1048
1049                 if(!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp)
1050                         {
1051                         HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1052                                 HWCRHK_R_MISSING_KEY_COMPONENTS);
1053                         goto err;
1054                         }
1055
1056                 rmsg.buf = tempbuf;
1057                 rmsg.size = 1024;
1058
1059                 /* Prepare the params */
1060                 bn_expand2(r, rsa->n->top); /* Check for error !! */
1061                 BN2MPI(m_a, I);
1062                 BN2MPI(m_p, rsa->p);
1063                 BN2MPI(m_q, rsa->q);
1064                 BN2MPI(m_dmp1, rsa->dmp1);
1065                 BN2MPI(m_dmq1, rsa->dmq1);
1066                 BN2MPI(m_iqmp, rsa->iqmp);
1067                 MPI2BN(r, m_r);
1068
1069                 /* Perform the operation */
1070                 ret = p_hwcrhk_ModExpCRT(hwcrhk_context, m_a, m_p, m_q,
1071                         m_dmp1, m_dmq1, m_iqmp, &m_r, NULL);
1072
1073                 /* Convert the response */
1074                 r->top = m_r.size / sizeof(BN_ULONG);
1075                 bn_fix_top(r);
1076
1077                 if (ret < 0)
1078                         {
1079                         /* FIXME: When this error is returned, HWCryptoHook is
1080                            telling us that falling back to software computation
1081                            might be a good thing. */
1082                         if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1083                                 {
1084                                 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1085                                         HWCRHK_R_REQUEST_FALLBACK);
1086                                 }
1087                         else
1088                                 {
1089                                 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1090                                         HWCRHK_R_REQUEST_FAILED);
1091                                 }
1092                         ERR_add_error_data(1,rmsg.buf);
1093                         goto err;
1094                         }
1095                 }
1096         /* If we're here, we must be here with some semblance of success :-) */
1097         to_return = 1;
1098 err:
1099         return to_return;
1100         }
1101 #endif
1102
1103 /* This function is aliased to mod_exp (with the mont stuff dropped). */
1104 static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
1105                 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1106         {
1107         return hwcrhk_mod_exp(r, a, p, m, ctx);
1108         }
1109
1110 /* This function is aliased to mod_exp (with the dh and mont dropped). */
1111 static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r,
1112                 const BIGNUM *a, const BIGNUM *p,
1113                 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1114         {
1115         return hwcrhk_mod_exp(r, a, p, m, ctx);
1116         }
1117
1118 /* Random bytes are good */
1119 static int hwcrhk_rand_bytes(unsigned char *buf, int num)
1120         {
1121         char tempbuf[1024];
1122         HWCryptoHook_ErrMsgBuf rmsg;
1123         int to_return = 0; /* assume failure */
1124         int ret;
1125
1126         rmsg.buf = tempbuf;
1127         rmsg.size = 1024;
1128
1129         if(!hwcrhk_context)
1130                 {
1131                 HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,HWCRHK_R_NOT_INITIALISED);
1132                 goto err;
1133                 }
1134
1135         ret = p_hwcrhk_RandomBytes(hwcrhk_context, buf, num, &rmsg);
1136         if (ret < 0)
1137                 {
1138                 /* FIXME: When this error is returned, HWCryptoHook is
1139                    telling us that falling back to software computation
1140                    might be a good thing. */
1141                 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1142                         {
1143                         HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,
1144                                 HWCRHK_R_REQUEST_FALLBACK);
1145                         }
1146                 else
1147                         {
1148                         HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,
1149                                 HWCRHK_R_REQUEST_FAILED);
1150                         }
1151                 ERR_add_error_data(1,rmsg.buf);
1152                 goto err;
1153                 }
1154         to_return = 1;
1155  err:
1156         return to_return;
1157         }
1158
1159 static int hwcrhk_rand_status(void)
1160         {
1161         return 1;
1162         }
1163
1164 /* This cleans up an RSA KM key, called when ex_data is freed */
1165
1166 static void hwcrhk_ex_free(void *obj, void *item, CRYPTO_EX_DATA *ad,
1167         int ind,long argl, void *argp)
1168 {
1169         char tempbuf[1024];
1170         HWCryptoHook_ErrMsgBuf rmsg;
1171 #ifndef OPENSSL_NO_RSA
1172         HWCryptoHook_RSAKeyHandle *hptr;
1173 #endif
1174 #if !defined(OPENSSL_NO_RSA)
1175         int ret;
1176 #endif
1177
1178         rmsg.buf = tempbuf;
1179         rmsg.size = 1024;
1180
1181 #ifndef OPENSSL_NO_RSA
1182         hptr = (HWCryptoHook_RSAKeyHandle *) item;
1183         if(hptr)
1184                 {
1185                 ret = p_hwcrhk_RSAUnloadKey(*hptr, NULL);
1186                 OPENSSL_free(hptr);
1187                 }
1188 #endif
1189 }
1190
1191 /* Mutex calls: since the HWCryptoHook model closely follows the POSIX model
1192  * these just wrap the POSIX functions and add some logging.
1193  */
1194
1195 static int hwcrhk_mutex_init(HWCryptoHook_Mutex* mt,
1196         HWCryptoHook_CallerContext *cactx)
1197         {
1198         mt->lockid = CRYPTO_get_new_dynlockid();
1199         if (mt->lockid == 0)
1200                 return -1;
1201         return 0;
1202         }
1203
1204 static int hwcrhk_mutex_lock(HWCryptoHook_Mutex *mt)
1205         {
1206         CRYPTO_w_lock(mt->lockid);
1207         return 0;
1208         }
1209
1210 void hwcrhk_mutex_unlock(HWCryptoHook_Mutex * mt)
1211         {
1212         CRYPTO_w_unlock(mt->lockid);
1213         }
1214
1215 static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex *mt)
1216         {
1217         CRYPTO_destroy_dynlockid(mt->lockid);
1218         }
1219
1220 static int hwcrhk_get_pass(const char *prompt_info,
1221         int *len_io, char *buf,
1222         HWCryptoHook_PassphraseContext *ppctx,
1223         HWCryptoHook_CallerContext *cactx)
1224         {
1225         pem_password_cb *callback = NULL;
1226         void *callback_data = NULL;
1227         UI_METHOD *ui_method = NULL;
1228
1229         if (cactx)
1230                 {
1231                 if (cactx->ui_method)
1232                         ui_method = cactx->ui_method;
1233                 if (cactx->password_callback)
1234                         callback = cactx->password_callback;
1235                 if (cactx->callback_data)
1236                         callback_data = cactx->callback_data;
1237                 }
1238         if (ppctx)
1239                 {
1240                 if (ppctx->ui_method)
1241                         {
1242                         ui_method = ppctx->ui_method;
1243                         callback = NULL;
1244                         }
1245                 if (ppctx->callback_data)
1246                         callback_data = ppctx->callback_data;
1247                 }
1248         if (callback == NULL && ui_method == NULL)
1249                 {
1250                 HWCRHKerr(HWCRHK_F_HWCRHK_GET_PASS,HWCRHK_R_NO_CALLBACK);
1251                 return -1;
1252                 }
1253
1254         if (ui_method)
1255                 {
1256                 UI *ui = UI_new_method(ui_method);
1257                 if (ui)
1258                         {
1259                         int ok;
1260                         char *prompt = UI_construct_prompt(ui,
1261                                 "pass phrase", prompt_info);
1262
1263                         ok = UI_add_input_string(ui,prompt,
1264                                 UI_INPUT_FLAG_DEFAULT_PWD,
1265                                 buf,0,(*len_io) - 1);
1266                         UI_add_user_data(ui, callback_data);
1267                         UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0);
1268
1269                         if (ok >= 0)
1270                                 do
1271                                         {
1272                                         ok=UI_process(ui);
1273                                         }
1274                                 while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0));
1275
1276                         if (ok >= 0)
1277                                 *len_io = strlen(buf);
1278
1279                         UI_free(ui);
1280                         OPENSSL_free(prompt);
1281                         }
1282                 }
1283         else
1284                 {
1285                 *len_io = callback(buf, *len_io, 0, callback_data);
1286                 }
1287         if(!*len_io)
1288                 return -1;
1289         return 0;
1290         }
1291
1292 static int hwcrhk_insert_card(const char *prompt_info,
1293                       const char *wrong_info,
1294                       HWCryptoHook_PassphraseContext *ppctx,
1295                       HWCryptoHook_CallerContext *cactx)
1296         {
1297         int ok = -1;
1298         UI *ui;
1299         void *callback_data = NULL;
1300         UI_METHOD *ui_method = NULL;
1301
1302         if (cactx)
1303                 {
1304                 if (cactx->ui_method)
1305                         ui_method = cactx->ui_method;
1306                 if (cactx->callback_data)
1307                         callback_data = cactx->callback_data;
1308                 }
1309         if (ppctx)
1310                 {
1311                 if (ppctx->ui_method)
1312                         ui_method = ppctx->ui_method;
1313                 if (ppctx->callback_data)
1314                         callback_data = ppctx->callback_data;
1315                 }
1316         if (ui_method == NULL)
1317                 {
1318                 HWCRHKerr(HWCRHK_F_HWCRHK_INSERT_CARD,
1319                         HWCRHK_R_NO_CALLBACK);
1320                 return -1;
1321                 }
1322
1323         ui = UI_new_method(ui_method);
1324
1325         if (ui)
1326                 {
1327                 char answer;
1328                 char buf[BUFSIZ];
1329
1330                 if (wrong_info)
1331                         BIO_snprintf(buf, sizeof(buf)-1,
1332                                 "Current card: \"%s\"\n", wrong_info);
1333                 ok = UI_dup_info_string(ui, buf);
1334                 if (ok >= 0 && prompt_info)
1335                         {
1336                         BIO_snprintf(buf, sizeof(buf)-1,
1337                                 "Insert card \"%s\"", prompt_info);
1338                         ok = UI_dup_input_boolean(ui, buf,
1339                                 "\n then hit <enter> or C<enter> to cancel\n",
1340                                 "\r\n", "Cc", UI_INPUT_FLAG_ECHO, &answer);
1341                         }
1342                 UI_add_user_data(ui, callback_data);
1343
1344                 if (ok >= 0)
1345                         ok = UI_process(ui);
1346                 UI_free(ui);
1347
1348                 if (ok == -2 || (ok >= 0 && answer == 'C'))
1349                         ok = 1;
1350                 else if (ok < 0)
1351                         ok = -1;
1352                 else
1353                         ok = 0;
1354                 }
1355         return ok;
1356         }
1357
1358 static void hwcrhk_log_message(void *logstr, const char *message)
1359         {
1360         BIO *lstream = NULL;
1361
1362         CRYPTO_w_lock(CRYPTO_LOCK_BIO);
1363         if (logstr)
1364                 lstream=*(BIO **)logstr;
1365         if (lstream)
1366                 {
1367                 BIO_write(lstream, message, strlen(message));
1368                 }
1369         CRYPTO_w_unlock(CRYPTO_LOCK_BIO);
1370         }
1371
1372 /* This stuff is needed if this ENGINE is being compiled into a self-contained
1373  * shared-library. */      
1374 #ifdef ENGINE_DYNAMIC_SUPPORT
1375 static int bind_fn(ENGINE *e, const char *id)
1376         {
1377         if(id && (strcmp(id, engine_hwcrhk_id) != 0))
1378                 return 0;
1379         if(!bind_helper(e))
1380                 return 0;
1381         return 1;
1382         }       
1383 IMPLEMENT_DYNAMIC_CHECK_FN()
1384 IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
1385 #endif /* ENGINE_DYNAMIC_SUPPORT */
1386
1387 #endif /* !OPENSSL_NO_HW_NCIPHER */
1388 #endif /* !OPENSSL_NO_HW */