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