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