Some more tweaks to ENGINE code.
[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 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 <openssl/crypto.h>
62 #include <openssl/pem.h>
63 #include "cryptlib.h"
64 #include <openssl/dso.h>
65 #include <openssl/engine.h>
66
67 #ifndef OPENSSL_NO_HW
68 #ifndef OPENSSL_NO_HW_NCIPHER
69
70 /* Attribution notice: nCipher have said several times that it's OK for
71  * us to implement a general interface to their boxes, and recently declared
72  * their HWCryptoHook to be public, and therefore available for us to use.
73  * Thanks, nCipher.
74  *
75  * The hwcryptohook.h included here is from May 2000.
76  * [Richard Levitte]
77  */
78 #ifdef FLAT_INC
79 #include "hwcryptohook.h"
80 #else
81 #include "vendor_defns/hwcryptohook.h"
82 #endif
83
84 static int hwcrhk_init(ENGINE *e);
85 static int hwcrhk_finish(ENGINE *e);
86 static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)()); 
87
88 /* Functions to handle mutexes */
89 static int hwcrhk_mutex_init(HWCryptoHook_Mutex*, HWCryptoHook_CallerContext*);
90 static int hwcrhk_mutex_lock(HWCryptoHook_Mutex*);
91 static void hwcrhk_mutex_unlock(HWCryptoHook_Mutex*);
92 static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex*);
93
94 /* BIGNUM stuff */
95 static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
96                 const BIGNUM *m, BN_CTX *ctx);
97
98 /* RSA stuff */
99 static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa);
100 /* This function is aliased to mod_exp (with the mont stuff dropped). */
101 static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
102                 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
103
104 /* DH stuff */
105 /* This function is alised to mod_exp (with the DH and mont dropped). */
106 static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r,
107         const BIGNUM *a, const BIGNUM *p,
108         const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
109
110 /* RAND stuff */
111 static int hwcrhk_rand_bytes(unsigned char *buf, int num);
112 static int hwcrhk_rand_status(void);
113
114 /* KM stuff */
115 static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
116         const char *passphrase);
117 static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
118         const char *passphrase);
119 static void hwcrhk_ex_free(void *obj, void *item, CRYPTO_EX_DATA *ad,
120         int ind,long argl, void *argp);
121
122 /* Interaction stuff */
123 static int hwcrhk_get_pass(const char *prompt_info,
124         int *len_io, char *buf,
125         HWCryptoHook_PassphraseContext *ppctx,
126         HWCryptoHook_CallerContext *cactx);
127 static void hwcrhk_log_message(void *logstr, const char *message);
128
129 /* The definitions for control commands specific to this engine */
130 #define HWCRHK_CMD_SO_PATH              ENGINE_CMD_BASE
131 #define HWCRHK_CMD_FORK_CHECK           (ENGINE_CMD_BASE + 1)
132 #define HWCRHK_CMD_THREAD_LOCKING       (ENGINE_CMD_BASE + 2)
133 static const ENGINE_CMD_DEFN hwcrhk_cmd_defns[] = {
134         {HWCRHK_CMD_SO_PATH,
135                 "SO_PATH",
136                 "Specifies the path to the 'hwcrhk' shared library",
137                 ENGINE_CMD_FLAG_STRING},
138         {HWCRHK_CMD_FORK_CHECK,
139                 "FORK_CHECK",
140                 "Turns fork() checking on or off (boolean)",
141                 ENGINE_CMD_FLAG_NUMERIC},
142         {HWCRHK_CMD_THREAD_LOCKING,
143                 "THREAD_LOCKING",
144                 "Turns thread-safe locking on or off (boolean)",
145                 ENGINE_CMD_FLAG_NUMERIC},
146         {0, NULL, NULL, 0}
147         };
148
149 /* Our internal RSA_METHOD that we provide pointers to */
150 static RSA_METHOD hwcrhk_rsa =
151         {
152         "nCipher RSA method",
153         NULL,
154         NULL,
155         NULL,
156         NULL,
157         hwcrhk_rsa_mod_exp,
158         hwcrhk_mod_exp_mont,
159         NULL,
160         NULL,
161         0,
162         NULL,
163         NULL,
164         NULL
165         };
166
167 /* Our internal DH_METHOD that we provide pointers to */
168 static DH_METHOD hwcrhk_dh =
169         {
170         "nCipher DH method",
171         NULL,
172         NULL,
173         hwcrhk_mod_exp_dh,
174         NULL,
175         NULL,
176         0,
177         NULL
178         };
179
180 static RAND_METHOD hwcrhk_rand =
181         {
182         /* "nCipher RAND method", */
183         NULL,
184         hwcrhk_rand_bytes,
185         NULL,
186         NULL,
187         hwcrhk_rand_bytes,
188         hwcrhk_rand_status,
189         };
190
191 /* Constants used when creating the ENGINE */
192 static const char *engine_hwcrhk_id = "chil";
193 static const char *engine_hwcrhk_name = "nCipher hardware engine support";
194
195 /* Internal stuff for HWCryptoHook */
196
197 /* Some structures needed for proper use of thread locks */
198 /* hwcryptohook.h has some typedefs that turn struct HWCryptoHook_MutexValue
199    into HWCryptoHook_Mutex */
200 struct HWCryptoHook_MutexValue
201         {
202         int lockid;
203         };
204
205 /* hwcryptohook.h has some typedefs that turn
206    struct HWCryptoHook_PassphraseContextValue
207    into HWCryptoHook_PassphraseContext */
208 struct HWCryptoHook_PassphraseContextValue
209         {
210         void *any;
211         };
212
213 /* hwcryptohook.h has some typedefs that turn
214    struct HWCryptoHook_CallerContextValue
215    into HWCryptoHook_CallerContext */
216 struct HWCryptoHook_CallerContextValue
217         {
218         void *any;
219         };
220
221 /* The MPI structure in HWCryptoHook is pretty compatible with OpenSSL
222    BIGNUM's, so lets define a couple of conversion macros */
223 #define BN2MPI(mp, bn) \
224     {mp.size = bn->top * sizeof(BN_ULONG); mp.buf = (unsigned char *)bn->d;}
225 #define MPI2BN(bn, mp) \
226     {mp.size = bn->dmax * sizeof(BN_ULONG); mp.buf = (unsigned char *)bn->d;}
227
228 #if 0 /* Card and password management is not yet supported */
229 /* HWCryptoHook callbacks.  insert_card() and get_pass() are not yet
230    defined, because we haven't quite decided on the proper form yet.
231    log_message() just adds an entry in the error stack.  I don't know
232    if that's good or bad...  */
233 static int insert_card(const char *prompt_info,
234         const char *wrong_info,
235         HWCryptoHook_PassphraseContext *ppctx,
236         HWCryptoHook_CallerContext *cactx);
237 static int get_pass(const char *prompt_info,
238         int *len_io, char *buf,
239         HWCryptoHook_PassphraseContext *ppctx,
240         HWCryptoHook_CallerContext *cactx);
241 #endif
242
243 static BIO *logstream = NULL;
244 static pem_password_cb *password_callback = NULL;
245 #if 0
246 static void *password_callback_userdata = NULL;
247 #endif
248 static int disable_mutex_callbacks = 0;
249
250 /* Stuff to pass to the HWCryptoHook library */
251 static HWCryptoHook_InitInfo hwcrhk_globals = {
252         0,                      /* Flags */
253         &logstream,             /* logstream */
254         sizeof(BN_ULONG),       /* limbsize */
255         0,                      /* mslimb first: false for BNs */
256         -1,                     /* msbyte first: use native */
257         0,                      /* Max mutexes, 0 = no small limit */
258         0,                      /* Max simultaneous, 0 = default */
259
260         /* The next few are mutex stuff: we write wrapper functions
261            around the OS mutex functions.  We initialise them to 0
262            here, and change that to actual function pointers in hwcrhk_init()
263            if dynamic locks are supported (that is, if the application
264            programmer has made sure of setting up callbacks bafore starting
265            this engine) *and* if disable_mutex_callbacks hasn't been set by
266            a call to ENGINE_ctrl(ENGINE_CTRL_CHIL_NO_LOCKING). */
267         sizeof(HWCryptoHook_Mutex),
268         0,
269         0,
270         0,
271         0,
272
273         /* The next few are condvar stuff: we write wrapper functions
274            round the OS functions.  Currently not implemented and not
275            and absolute necessity even in threaded programs, therefore
276            0'ed.  Will hopefully be implemented some day, since it
277            enhances the efficiency of HWCryptoHook.  */
278         0, /* sizeof(HWCryptoHook_CondVar), */
279         0, /* hwcrhk_cv_init, */
280         0, /* hwcrhk_cv_wait, */
281         0, /* hwcrhk_cv_signal, */
282         0, /* hwcrhk_cv_broadcast, */
283         0, /* hwcrhk_cv_destroy, */
284
285         hwcrhk_get_pass,        /* pass phrase */
286         0, /* insert_card, */   /* insert a card */
287         hwcrhk_log_message      /* Log message */
288 };
289
290
291 /* Now, to our own code */
292
293 /* As this is only ever called once, there's no need for locking
294  * (indeed - the lock will already be held by our caller!!!) */
295 ENGINE *ENGINE_ncipher()
296         {
297         const RSA_METHOD *meth1;
298         const DH_METHOD *meth2;
299         ENGINE *ret = ENGINE_new();
300         if(!ret)
301                 return NULL;
302         if(!ENGINE_set_id(ret, engine_hwcrhk_id) ||
303                         !ENGINE_set_name(ret, engine_hwcrhk_name) ||
304                         !ENGINE_set_RSA(ret, &hwcrhk_rsa) ||
305                         !ENGINE_set_DH(ret, &hwcrhk_dh) ||
306                         !ENGINE_set_RAND(ret, &hwcrhk_rand) ||
307                         !ENGINE_set_BN_mod_exp(ret, hwcrhk_mod_exp) ||
308                         !ENGINE_set_init_function(ret, hwcrhk_init) ||
309                         !ENGINE_set_finish_function(ret, hwcrhk_finish) ||
310                         !ENGINE_set_ctrl_function(ret, hwcrhk_ctrl) ||
311                         !ENGINE_set_load_privkey_function(ret, hwcrhk_load_privkey) ||
312                         !ENGINE_set_load_pubkey_function(ret, hwcrhk_load_pubkey) ||
313                         !ENGINE_set_cmd_defns(ret, hwcrhk_cmd_defns))
314                 {
315                 ENGINE_free(ret);
316                 return NULL;
317                 }
318
319         /* We know that the "PKCS1_SSLeay()" functions hook properly
320          * to the cswift-specific mod_exp and mod_exp_crt so we use
321          * those functions. NB: We don't use ENGINE_openssl() or
322          * anything "more generic" because something like the RSAref
323          * code may not hook properly, and if you own one of these
324          * cards then you have the right to do RSA operations on it
325          * anyway! */ 
326         meth1 = RSA_PKCS1_SSLeay();
327         hwcrhk_rsa.rsa_pub_enc = meth1->rsa_pub_enc;
328         hwcrhk_rsa.rsa_pub_dec = meth1->rsa_pub_dec;
329         hwcrhk_rsa.rsa_priv_enc = meth1->rsa_priv_enc;
330         hwcrhk_rsa.rsa_priv_dec = meth1->rsa_priv_dec;
331
332         /* Much the same for Diffie-Hellman */
333         meth2 = DH_OpenSSL();
334         hwcrhk_dh.generate_key = meth2->generate_key;
335         hwcrhk_dh.compute_key = meth2->compute_key;
336         return ret;
337         }
338
339 /* This is a process-global DSO handle used for loading and unloading
340  * the HWCryptoHook library. NB: This is only set (or unset) during an
341  * init() or finish() call (reference counts permitting) and they're
342  * operating with global locks, so this should be thread-safe
343  * implicitly. */
344 static DSO *hwcrhk_dso = NULL;
345 static HWCryptoHook_ContextHandle hwcrhk_context = 0;
346 static int hndidx = -1; /* Index for KM handle.  Not really used yet. */
347
348 /* These are the function pointers that are (un)set when the library has
349  * successfully (un)loaded. */
350 static HWCryptoHook_Init_t *p_hwcrhk_Init = NULL;
351 static HWCryptoHook_Finish_t *p_hwcrhk_Finish = NULL;
352 static HWCryptoHook_ModExp_t *p_hwcrhk_ModExp = NULL;
353 static HWCryptoHook_RSA_t *p_hwcrhk_RSA = NULL;
354 static HWCryptoHook_RandomBytes_t *p_hwcrhk_RandomBytes = NULL;
355 static HWCryptoHook_RSALoadKey_t *p_hwcrhk_RSALoadKey = NULL;
356 static HWCryptoHook_RSAGetPublicKey_t *p_hwcrhk_RSAGetPublicKey = NULL;
357 static HWCryptoHook_RSAUnloadKey_t *p_hwcrhk_RSAUnloadKey = NULL;
358 static HWCryptoHook_ModExpCRT_t *p_hwcrhk_ModExpCRT = NULL;
359
360 /* Used in the DSO operations. */
361 static const char def_HWCRHK_LIBNAME[] = "nfhwcrhk";
362 static const char *HWCRHK_LIBNAME = def_HWCRHK_LIBNAME;
363 static const char *n_hwcrhk_Init = "HWCryptoHook_Init";
364 static const char *n_hwcrhk_Finish = "HWCryptoHook_Finish";
365 static const char *n_hwcrhk_ModExp = "HWCryptoHook_ModExp";
366 static const char *n_hwcrhk_RSA = "HWCryptoHook_RSA";
367 static const char *n_hwcrhk_RandomBytes = "HWCryptoHook_RandomBytes";
368 static const char *n_hwcrhk_RSALoadKey = "HWCryptoHook_RSALoadKey";
369 static const char *n_hwcrhk_RSAGetPublicKey = "HWCryptoHook_RSAGetPublicKey";
370 static const char *n_hwcrhk_RSAUnloadKey = "HWCryptoHook_RSAUnloadKey";
371 static const char *n_hwcrhk_ModExpCRT = "HWCryptoHook_ModExpCRT";
372
373 /* HWCryptoHook library functions and mechanics - these are used by the
374  * higher-level functions further down. NB: As and where there's no
375  * error checking, take a look lower down where these functions are
376  * called, the checking and error handling is probably down there. */
377
378 /* utility function to obtain a context */
379 static int get_context(HWCryptoHook_ContextHandle *hac)
380         {
381         char tempbuf[1024];
382         HWCryptoHook_ErrMsgBuf rmsg;
383
384         rmsg.buf = tempbuf;
385         rmsg.size = 1024;
386
387         *hac = p_hwcrhk_Init(&hwcrhk_globals, sizeof(hwcrhk_globals), &rmsg,
388                 NULL);
389         if (!*hac)
390                 return 0;
391         return 1;
392         }
393  
394 /* similarly to release one. */
395 static void release_context(HWCryptoHook_ContextHandle hac)
396         {
397         p_hwcrhk_Finish(hac);
398         }
399
400 /* (de)initialisation functions. */
401 static int hwcrhk_init(ENGINE *e)
402         {
403         HWCryptoHook_Init_t *p1;
404         HWCryptoHook_Finish_t *p2;
405         HWCryptoHook_ModExp_t *p3;
406         HWCryptoHook_RSA_t *p4;
407         HWCryptoHook_RSALoadKey_t *p5;
408         HWCryptoHook_RSAGetPublicKey_t *p6;
409         HWCryptoHook_RSAUnloadKey_t *p7;
410         HWCryptoHook_RandomBytes_t *p8;
411         HWCryptoHook_ModExpCRT_t *p9;
412
413         if(hwcrhk_dso != NULL)
414                 {
415                 ENGINEerr(ENGINE_F_HWCRHK_INIT,ENGINE_R_ALREADY_LOADED);
416                 goto err;
417                 }
418         /* Attempt to load libnfhwcrhk.so/nfhwcrhk.dll/whatever. */
419         hwcrhk_dso = DSO_load(NULL, HWCRHK_LIBNAME, NULL, 0);
420         if(hwcrhk_dso == NULL)
421                 {
422                 ENGINEerr(ENGINE_F_HWCRHK_INIT,ENGINE_R_DSO_FAILURE);
423                 goto err;
424                 }
425         if(!(p1 = (HWCryptoHook_Init_t *)
426                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_Init)) ||
427                 !(p2 = (HWCryptoHook_Finish_t *)
428                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_Finish)) ||
429                 !(p3 = (HWCryptoHook_ModExp_t *)
430                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_ModExp)) ||
431                 !(p4 = (HWCryptoHook_RSA_t *)
432                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSA)) ||
433                 !(p5 = (HWCryptoHook_RSALoadKey_t *)
434                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSALoadKey)) ||
435                 !(p6 = (HWCryptoHook_RSAGetPublicKey_t *)
436                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSAGetPublicKey)) ||
437                 !(p7 = (HWCryptoHook_RSAUnloadKey_t *)
438                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSAUnloadKey)) ||
439                 !(p8 = (HWCryptoHook_RandomBytes_t *)
440                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_RandomBytes)) ||
441                 !(p9 = (HWCryptoHook_ModExpCRT_t *)
442                         DSO_bind_func(hwcrhk_dso, n_hwcrhk_ModExpCRT)))
443                 {
444                 ENGINEerr(ENGINE_F_HWCRHK_INIT,ENGINE_R_DSO_FAILURE);
445                 goto err;
446                 }
447         /* Copy the pointers */
448         p_hwcrhk_Init = p1;
449         p_hwcrhk_Finish = p2;
450         p_hwcrhk_ModExp = p3;
451         p_hwcrhk_RSA = p4;
452         p_hwcrhk_RSALoadKey = p5;
453         p_hwcrhk_RSAGetPublicKey = p6;
454         p_hwcrhk_RSAUnloadKey = p7;
455         p_hwcrhk_RandomBytes = p8;
456         p_hwcrhk_ModExpCRT = p9;
457
458         /* Check if the application decided to support dynamic locks,
459            and if it does, use them. */
460         if (disable_mutex_callbacks == 0 &&
461                 CRYPTO_get_dynlock_create_callback() != NULL &&
462                 CRYPTO_get_dynlock_lock_callback() != NULL &&
463                 CRYPTO_get_dynlock_destroy_callback() != NULL)
464                 {
465                 hwcrhk_globals.mutex_init = hwcrhk_mutex_init;
466                 hwcrhk_globals.mutex_acquire = hwcrhk_mutex_lock;
467                 hwcrhk_globals.mutex_release = hwcrhk_mutex_unlock;
468                 hwcrhk_globals.mutex_destroy = hwcrhk_mutex_destroy;
469                 }
470
471         /* Try and get a context - if not, we may have a DSO but no
472          * accelerator! */
473         if(!get_context(&hwcrhk_context))
474                 {
475                 ENGINEerr(ENGINE_F_HWCRHK_INIT,ENGINE_R_UNIT_FAILURE);
476                 goto err;
477                 }
478         /* Everything's fine. */
479         if (hndidx == -1)
480                 hndidx = RSA_get_ex_new_index(0,
481                         "nFast HWCryptoHook RSA key handle",
482                         NULL, NULL, hwcrhk_ex_free);
483         return 1;
484 err:
485         if(hwcrhk_dso)
486                 DSO_free(hwcrhk_dso);
487         hwcrhk_dso = NULL;
488         p_hwcrhk_Init = NULL;
489         p_hwcrhk_Finish = NULL;
490         p_hwcrhk_ModExp = NULL;
491         p_hwcrhk_RSA = NULL;
492         p_hwcrhk_RSALoadKey = NULL;
493         p_hwcrhk_RSAGetPublicKey = NULL;
494         p_hwcrhk_RSAUnloadKey = NULL;
495         p_hwcrhk_ModExpCRT = NULL;
496         p_hwcrhk_RandomBytes = NULL;
497         return 0;
498         }
499
500 static int hwcrhk_finish(ENGINE *e)
501         {
502         int to_return = 1;
503         if(hwcrhk_dso == NULL)
504                 {
505                 ENGINEerr(ENGINE_F_HWCRHK_FINISH,ENGINE_R_NOT_LOADED);
506                 to_return = 0;
507                 goto err;
508                 }
509         release_context(hwcrhk_context);
510         if(!DSO_free(hwcrhk_dso))
511                 {
512                 ENGINEerr(ENGINE_F_HWCRHK_FINISH,ENGINE_R_DSO_FAILURE);
513                 to_return = 0;
514                 goto err;
515                 }
516  err:
517         if (logstream)
518                 BIO_free(logstream);
519         hwcrhk_dso = NULL;
520         p_hwcrhk_Init = NULL;
521         p_hwcrhk_Finish = NULL;
522         p_hwcrhk_ModExp = NULL;
523         p_hwcrhk_RSA = NULL;
524         p_hwcrhk_RSALoadKey = NULL;
525         p_hwcrhk_RSAGetPublicKey = NULL;
526         p_hwcrhk_RSAUnloadKey = NULL;
527         p_hwcrhk_ModExpCRT = NULL;
528         p_hwcrhk_RandomBytes = NULL;
529         return to_return;
530         }
531
532 static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
533         {
534         int to_return = 1;
535
536         switch(cmd)
537                 {
538         case HWCRHK_CMD_SO_PATH:
539                 if(hwcrhk_dso)
540                         {
541                         ENGINEerr(ENGINE_F_HWCRHK_CTRL,ENGINE_R_ALREADY_LOADED);
542                         return 0;
543                         }
544                 if(p == NULL)
545                         {
546                         ENGINEerr(ENGINE_F_HWCRHK_CTRL,ERR_R_PASSED_NULL_PARAMETER);
547                         return 0;
548                         }
549                 HWCRHK_LIBNAME = (const char *)p;
550                 return 1;
551         case ENGINE_CTRL_SET_LOGSTREAM:
552                 {
553                 BIO *bio = (BIO *)p;
554
555                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
556                 if (logstream)
557                         {
558                         BIO_free(logstream);
559                         logstream = NULL;
560                         }
561                 if (CRYPTO_add(&bio->references,1,CRYPTO_LOCK_BIO) > 1)
562                         logstream = bio;
563                 else
564                         ENGINEerr(ENGINE_F_HWCRHK_CTRL,ENGINE_R_BIO_WAS_FREED);
565                 }
566                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
567                 break;
568         case ENGINE_CTRL_SET_PASSWORD_CALLBACK:
569                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
570                 password_callback = (pem_password_cb *)f;
571                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
572                 break;
573         /* this enables or disables the "SimpleForkCheck" flag used in the
574          * initialisation structure. */
575         case ENGINE_CTRL_CHIL_SET_FORKCHECK:
576         case HWCRHK_CMD_FORK_CHECK:
577                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
578                 if(i)
579                         hwcrhk_globals.flags |=
580                                 HWCryptoHook_InitFlags_SimpleForkCheck;
581                 else
582                         hwcrhk_globals.flags &=
583                                 ~HWCryptoHook_InitFlags_SimpleForkCheck;
584                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
585                 break;
586         /* This will prevent the initialisation function from "installing"
587          * the mutex-handling callbacks, even if they are available from
588          * within the library (or were provided to the library from the
589          * calling application). This is to remove any baggage for
590          * applications not using multithreading. */
591         case ENGINE_CTRL_CHIL_NO_LOCKING:
592                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
593                 disable_mutex_callbacks = 1;
594                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
595                 break;
596         case HWCRHK_CMD_THREAD_LOCKING:
597                 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
598                 disable_mutex_callbacks = ((i == 0) ? 0 : 1);
599                 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
600                 break;
601
602         /* The command isn't understood by this engine */
603         default:
604                 ENGINEerr(ENGINE_F_HWCRHK_CTRL,
605                         ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED);
606                 to_return = 0;
607                 break;
608                 }
609
610         return to_return;
611         }
612
613 static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
614         const char *passphrase)
615         {
616         RSA *rtmp = NULL;
617         EVP_PKEY *res = NULL;
618         HWCryptoHook_MPI e, n;
619         HWCryptoHook_RSAKeyHandle *hptr;
620         HWCryptoHook_ErrMsgBuf rmsg;
621
622         if(!hwcrhk_context)
623                 {
624                 ENGINEerr(ENGINE_F_HWCRHK_LOAD_PRIVKEY,
625                         ENGINE_R_NOT_INITIALISED);
626                 goto err;
627                 }
628         hptr = OPENSSL_malloc(sizeof(HWCryptoHook_RSAKeyHandle));
629         if (!hptr)
630                 {
631                 ENGINEerr(ENGINE_F_HWCRHK_LOAD_PRIVKEY,
632                         ERR_R_MALLOC_FAILURE);
633                 goto err;
634                 }
635         if (p_hwcrhk_RSALoadKey(hwcrhk_context, key_id, hptr,
636                 &rmsg, NULL))
637                 {
638                 ENGINEerr(ENGINE_F_HWCRHK_LOAD_PRIVKEY,
639                         ENGINE_R_CHIL_ERROR);
640                 ERR_add_error_data(1,rmsg.buf);
641                 goto err;
642                 }
643         if (!*hptr)
644                 {
645                 ENGINEerr(ENGINE_F_HWCRHK_LOAD_PRIVKEY,
646                         ENGINE_R_NO_KEY);
647                 goto err;
648                 }
649         rtmp = RSA_new_method(eng);
650         RSA_set_ex_data(rtmp, hndidx, (char *)hptr);
651         rtmp->e = BN_new();
652         rtmp->n = BN_new();
653         rtmp->flags |= RSA_FLAG_EXT_PKEY;
654         MPI2BN(rtmp->e, e);
655         MPI2BN(rtmp->n, n);
656         if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg)
657                 != HWCRYPTOHOOK_ERROR_MPISIZE)
658                 {
659                 ENGINEerr(ENGINE_F_HWCRHK_LOAD_PUBKEY,ENGINE_R_CHIL_ERROR);
660                 ERR_add_error_data(1,rmsg.buf);
661                 goto err;
662                 }
663                         
664         bn_expand2(rtmp->e, e.size/sizeof(BN_ULONG));
665         bn_expand2(rtmp->n, n.size/sizeof(BN_ULONG));
666         MPI2BN(rtmp->e, e);
667         MPI2BN(rtmp->n, n);
668
669         if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg))
670                 {
671                 ENGINEerr(ENGINE_F_HWCRHK_LOAD_PUBKEY,
672                         ENGINE_R_CHIL_ERROR);
673                 ERR_add_error_data(1,rmsg.buf);
674                 goto err;
675                 }
676         rtmp->e->top = e.size / sizeof(BN_ULONG);
677         bn_fix_top(rtmp->e);
678         rtmp->n->top = n.size / sizeof(BN_ULONG);
679         bn_fix_top(rtmp->n);
680
681         res = EVP_PKEY_new();
682         EVP_PKEY_assign_RSA(res, rtmp);
683
684         return res;
685  err:
686         if (res)
687                 EVP_PKEY_free(res);
688         if (rtmp)
689                 RSA_free(rtmp);
690         return NULL;
691         }
692
693 static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
694         const char *passphrase)
695         {
696         EVP_PKEY *res = hwcrhk_load_privkey(eng, key_id, passphrase);
697
698         if (res)
699                 switch(res->type)
700                         {
701                 case EVP_PKEY_RSA:
702                         {
703                         RSA *rsa = NULL;
704
705                         CRYPTO_w_lock(CRYPTO_LOCK_EVP_PKEY);
706                         rsa = res->pkey.rsa;
707                         res->pkey.rsa = RSA_new();
708                         res->pkey.rsa->n = rsa->n;
709                         res->pkey.rsa->e = rsa->e;
710                         CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY);
711                         RSA_free(rsa);
712                         }
713                 default:
714                         ENGINEerr(ENGINE_F_HWCRHK_LOAD_PUBKEY,
715                                 ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED);
716                         goto err;
717                         }
718
719         return res;
720  err:
721         if (res)
722                 EVP_PKEY_free(res);
723         return NULL;
724         }
725
726 /* A little mod_exp */
727 static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
728                         const BIGNUM *m, BN_CTX *ctx)
729         {
730         char tempbuf[1024];
731         HWCryptoHook_ErrMsgBuf rmsg;
732         /* Since HWCryptoHook_MPI is pretty compatible with BIGNUM's,
733            we use them directly, plus a little macro magic.  We only
734            thing we need to make sure of is that enough space is allocated. */
735         HWCryptoHook_MPI m_a, m_p, m_n, m_r;
736         int to_return, ret;
737  
738         to_return = 0; /* expect failure */
739         rmsg.buf = tempbuf;
740         rmsg.size = 1024;
741
742         if(!hwcrhk_context)
743                 {
744                 ENGINEerr(ENGINE_F_HWCRHK_MOD_EXP,ENGINE_R_NOT_INITIALISED);
745                 goto err;
746                 }
747         /* Prepare the params */
748         bn_expand2(r, m->top);  /* Check for error !! */
749         BN2MPI(m_a, a);
750         BN2MPI(m_p, p);
751         BN2MPI(m_n, m);
752         MPI2BN(r, m_r);
753
754         /* Perform the operation */
755         ret = p_hwcrhk_ModExp(hwcrhk_context, m_a, m_p, m_n, &m_r, &rmsg);
756
757         /* Convert the response */
758         r->top = m_r.size / sizeof(BN_ULONG);
759         bn_fix_top(r);
760
761         if (ret < 0)
762                 {
763                 /* FIXME: When this error is returned, HWCryptoHook is
764                    telling us that falling back to software computation
765                    might be a good thing. */
766                 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
767                         {
768                         ENGINEerr(ENGINE_F_HWCRHK_MOD_EXP,ENGINE_R_REQUEST_FALLBACK);
769                         }
770                 else
771                         {
772                         ENGINEerr(ENGINE_F_HWCRHK_MOD_EXP,ENGINE_R_REQUEST_FAILED);
773                         }
774                 ERR_add_error_data(1,rmsg.buf);
775                 goto err;
776                 }
777
778         to_return = 1;
779 err:
780         return to_return;
781         }
782  
783 static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa)
784         {
785         char tempbuf[1024];
786         HWCryptoHook_ErrMsgBuf rmsg;
787         HWCryptoHook_RSAKeyHandle *hptr;
788         int to_return = 0, ret;
789
790         if(!hwcrhk_context)
791                 {
792                 ENGINEerr(ENGINE_F_HWCRHK_MOD_EXP,ENGINE_R_NOT_INITIALISED);
793                 goto err;
794                 }
795
796         /* This provides support for nForce keys.  Since that's opaque data
797            all we do is provide a handle to the proper key and let HWCryptoHook
798            take care of the rest. */
799         if ((hptr = (HWCryptoHook_RSAKeyHandle *) RSA_get_ex_data(rsa, hndidx))
800                 != NULL)
801                 {
802                 HWCryptoHook_MPI m_a, m_r;
803
804                 if(!rsa->n)
805                         {
806                         ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,
807                                 ENGINE_R_MISSING_KEY_COMPONENTS);
808                         goto err;
809                         }
810
811                 rmsg.buf = tempbuf;
812                 rmsg.size = 1024;
813
814                 /* Prepare the params */
815                 bn_expand2(r, rsa->n->top); /* Check for error !! */
816                 BN2MPI(m_a, I);
817                 MPI2BN(r, m_r);
818
819                 /* Perform the operation */
820                 ret = p_hwcrhk_RSA(m_a, *hptr, &m_r, &rmsg);
821
822                 /* Convert the response */
823                 r->top = m_r.size / sizeof(BN_ULONG);
824                 bn_fix_top(r);
825
826                 if (ret < 0)
827                         {
828                         /* FIXME: When this error is returned, HWCryptoHook is
829                            telling us that falling back to software computation
830                            might be a good thing. */
831                         if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
832                                 {
833                                 ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,ENGINE_R_REQUEST_FALLBACK);
834                                 }
835                         else
836                                 {
837                                 ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,ENGINE_R_REQUEST_FAILED);
838                                 }
839                         ERR_add_error_data(1,rmsg.buf);
840                         goto err;
841                         }
842                 }
843         else
844                 {
845                 HWCryptoHook_MPI m_a, m_p, m_q, m_dmp1, m_dmq1, m_iqmp, m_r;
846
847                 if(!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp)
848                         {
849                         ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,
850                                 ENGINE_R_MISSING_KEY_COMPONENTS);
851                         goto err;
852                         }
853
854                 rmsg.buf = tempbuf;
855                 rmsg.size = 1024;
856
857                 /* Prepare the params */
858                 bn_expand2(r, rsa->n->top); /* Check for error !! */
859                 BN2MPI(m_a, I);
860                 BN2MPI(m_p, rsa->p);
861                 BN2MPI(m_q, rsa->q);
862                 BN2MPI(m_dmp1, rsa->dmp1);
863                 BN2MPI(m_dmq1, rsa->dmq1);
864                 BN2MPI(m_iqmp, rsa->iqmp);
865                 MPI2BN(r, m_r);
866
867                 /* Perform the operation */
868                 ret = p_hwcrhk_ModExpCRT(hwcrhk_context, m_a, m_p, m_q,
869                         m_dmp1, m_dmq1, m_iqmp, &m_r, NULL);
870
871                 /* Convert the response */
872                 r->top = m_r.size / sizeof(BN_ULONG);
873                 bn_fix_top(r);
874
875                 if (ret < 0)
876                         {
877                         /* FIXME: When this error is returned, HWCryptoHook is
878                            telling us that falling back to software computation
879                            might be a good thing. */
880                         if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
881                                 {
882                                 ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,ENGINE_R_REQUEST_FALLBACK);
883                                 }
884                         else
885                                 {
886                                 ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,ENGINE_R_REQUEST_FAILED);
887                                 }
888                         ERR_add_error_data(1,rmsg.buf);
889                         goto err;
890                         }
891                 }
892         /* If we're here, we must be here with some semblance of success :-) */
893         to_return = 1;
894 err:
895         return to_return;
896         }
897
898 /* This function is aliased to mod_exp (with the mont stuff dropped). */
899 static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
900                 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
901         {
902         return hwcrhk_mod_exp(r, a, p, m, ctx);
903         }
904
905 /* This function is aliased to mod_exp (with the dh and mont dropped). */
906 static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r,
907                 const BIGNUM *a, const BIGNUM *p,
908                 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
909         {
910         return hwcrhk_mod_exp(r, a, p, m, ctx);
911         }
912
913 /* Random bytes are good */
914 static int hwcrhk_rand_bytes(unsigned char *buf, int num)
915         {
916         char tempbuf[1024];
917         HWCryptoHook_ErrMsgBuf rmsg;
918         int to_return = 0; /* assume failure */
919         int ret;
920
921         rmsg.buf = tempbuf;
922         rmsg.size = 1024;
923
924         if(!hwcrhk_context)
925                 {
926                 ENGINEerr(ENGINE_F_HWCRHK_RAND_BYTES,ENGINE_R_NOT_INITIALISED);
927                 goto err;
928                 }
929
930         ret = p_hwcrhk_RandomBytes(hwcrhk_context, buf, num, &rmsg);
931         if (ret < 0)
932                 {
933                 /* FIXME: When this error is returned, HWCryptoHook is
934                    telling us that falling back to software computation
935                    might be a good thing. */
936                 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
937                         {
938                         ENGINEerr(ENGINE_F_HWCRHK_RAND_BYTES,ENGINE_R_REQUEST_FALLBACK);
939                         }
940                 else
941                         {
942                         ENGINEerr(ENGINE_F_HWCRHK_RAND_BYTES,ENGINE_R_REQUEST_FAILED);
943                         }
944                 ERR_add_error_data(1,rmsg.buf);
945                 goto err;
946                 }
947         to_return = 1;
948  err:
949         return to_return;
950         }
951
952 static int hwcrhk_rand_status(void)
953         {
954         return 1;
955         }
956
957 /* This cleans up an RSA KM key, called when ex_data is freed */
958
959 static void hwcrhk_ex_free(void *obj, void *item, CRYPTO_EX_DATA *ad,
960         int ind,long argl, void *argp)
961 {
962         char tempbuf[1024];
963         HWCryptoHook_ErrMsgBuf rmsg;
964         HWCryptoHook_RSAKeyHandle *hptr;
965         int ret;
966
967         rmsg.buf = tempbuf;
968         rmsg.size = 1024;
969
970         hptr = (HWCryptoHook_RSAKeyHandle *) item;
971         if(!hptr) return;
972         ret = p_hwcrhk_RSAUnloadKey(*hptr, NULL);
973         OPENSSL_free(hptr);
974 }
975
976 /* Mutex calls: since the HWCryptoHook model closely follows the POSIX model
977  * these just wrap the POSIX functions and add some logging.
978  */
979
980 static int hwcrhk_mutex_init(HWCryptoHook_Mutex* mt,
981         HWCryptoHook_CallerContext *cactx)
982         {
983         mt->lockid = CRYPTO_get_new_dynlockid();
984         if (mt->lockid == 0)
985                 return 0;
986         return 1;
987         }
988
989 static int hwcrhk_mutex_lock(HWCryptoHook_Mutex *mt)
990         {
991         CRYPTO_w_lock(mt->lockid);
992         return 1;
993         }
994
995 void hwcrhk_mutex_unlock(HWCryptoHook_Mutex * mt)
996         {
997         CRYPTO_w_unlock(mt->lockid);
998         }
999
1000 static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex *mt)
1001         {
1002         CRYPTO_destroy_dynlockid(mt->lockid);
1003         }
1004
1005 static int hwcrhk_get_pass(const char *prompt_info,
1006         int *len_io, char *buf,
1007         HWCryptoHook_PassphraseContext *ppctx,
1008         HWCryptoHook_CallerContext *cactx)
1009         {
1010         int l = 0;
1011         char prompt[1024];
1012
1013         if (password_callback == NULL)
1014                 {
1015                 ENGINEerr(ENGINE_F_HWCRHK_GET_PASS,ENGINE_R_NO_CALLBACK);
1016                 return -1;
1017                 }
1018         if (prompt_info)
1019                 {
1020                 strncpy(prompt, "Card: \"", sizeof(prompt));
1021                 l += 5;
1022                 strncpy(prompt + l, prompt_info, sizeof(prompt) - l);
1023                 l += strlen(prompt_info);
1024                 if (l + 2 < sizeof(prompt))
1025                         {
1026                         strncpy(prompt + l, "\"\n", sizeof(prompt) - l);
1027                         l += 2;
1028                         }
1029                 }
1030         if (l < sizeof(prompt) - 1)
1031                 {
1032                 strncpy(prompt, "Enter Passphrase <enter to cancel>:",
1033                         sizeof(prompt) - l);
1034                 l += 35;
1035                 }
1036         prompt[l] = '\0';
1037
1038         /* I know, passing on the prompt instead of the user data *is*
1039            a bad thing.  However, that's all we have right now.
1040            --  Richard Levitte */
1041         *len_io = password_callback(buf, *len_io, 0, prompt);
1042         if(!*len_io)
1043                 return -1;
1044         return 0;
1045         }
1046
1047 static void hwcrhk_log_message(void *logstr, const char *message)
1048         {
1049         BIO *lstream = NULL;
1050
1051         CRYPTO_w_lock(CRYPTO_LOCK_BIO);
1052         if (logstr)
1053                 lstream=*(BIO **)logstr;
1054         if (lstream)
1055                 {
1056                 BIO_write(lstream, message, strlen(message));
1057                 }
1058         CRYPTO_w_unlock(CRYPTO_LOCK_BIO);
1059         }
1060
1061 #endif /* !OPENSSL_NO_HW_NCIPHER */
1062 #endif /* !OPENSSL_NO_HW */