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