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.
6 /* ====================================================================
7 * Copyright (c) 1999 The OpenSSL Project. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
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
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/)"
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.
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.
35 * 6. Redistributions of any form whatsoever must retain the following
37 * "This product includes software developed by the OpenSSL Project
38 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
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 * ====================================================================
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).
61 #include <openssl/crypto.h>
62 #include <openssl/pem.h>
64 #include <openssl/dso.h>
65 #include <openssl/engine.h>
68 #ifndef OPENSSL_NO_HW_NCIPHER
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.
75 * The hwcryptohook.h included here is from May 2000.
79 #include "hwcryptohook.h"
81 #include "vendor_defns/hwcryptohook.h"
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)());
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*);
95 static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
96 const BIGNUM *m, BN_CTX *ctx);
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);
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);
111 static int hwcrhk_rand_bytes(unsigned char *buf, int num);
112 static int hwcrhk_rand_status(void);
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);
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);
129 /* Our internal RSA_METHOD that we provide pointers to */
130 static RSA_METHOD hwcrhk_rsa =
132 "nCipher RSA method",
147 /* Our internal DH_METHOD that we provide pointers to */
148 static DH_METHOD hwcrhk_dh =
160 static RAND_METHOD hwcrhk_rand =
162 /* "nCipher RAND method", */
171 /* Constants used when creating the ENGINE */
172 static const char *engine_hwcrhk_id = "chil";
173 static const char *engine_hwcrhk_name = "nCipher hardware engine support";
175 /* Internal stuff for HWCryptoHook */
177 /* Some structures needed for proper use of thread locks */
178 /* hwcryptohook.h has some typedefs that turn struct HWCryptoHook_MutexValue
179 into HWCryptoHook_Mutex */
180 struct HWCryptoHook_MutexValue
185 /* hwcryptohook.h has some typedefs that turn
186 struct HWCryptoHook_PassphraseContextValue
187 into HWCryptoHook_PassphraseContext */
188 struct HWCryptoHook_PassphraseContextValue
193 /* hwcryptohook.h has some typedefs that turn
194 struct HWCryptoHook_CallerContextValue
195 into HWCryptoHook_CallerContext */
196 struct HWCryptoHook_CallerContextValue
201 /* The MPI structure in HWCryptoHook is pretty compatible with OpenSSL
202 BIGNUM's, so lets define a couple of conversion macros */
203 #define BN2MPI(mp, bn) \
204 {mp.size = bn->top * sizeof(BN_ULONG); mp.buf = (unsigned char *)bn->d;}
205 #define MPI2BN(bn, mp) \
206 {mp.size = bn->dmax * sizeof(BN_ULONG); mp.buf = (unsigned char *)bn->d;}
208 #if 0 /* Card and password management is not yet supported */
209 /* HWCryptoHook callbacks. insert_card() and get_pass() are not yet
210 defined, because we haven't quite decided on the proper form yet.
211 log_message() just adds an entry in the error stack. I don't know
212 if that's good or bad... */
213 static int insert_card(const char *prompt_info,
214 const char *wrong_info,
215 HWCryptoHook_PassphraseContext *ppctx,
216 HWCryptoHook_CallerContext *cactx);
217 static int get_pass(const char *prompt_info,
218 int *len_io, char *buf,
219 HWCryptoHook_PassphraseContext *ppctx,
220 HWCryptoHook_CallerContext *cactx);
223 static BIO *logstream = NULL;
224 static pem_password_cb *password_callback = NULL;
226 static void *password_callback_userdata = NULL;
228 static int disable_mutex_callbacks = 0;
230 /* Stuff to pass to the HWCryptoHook library */
231 static HWCryptoHook_InitInfo hwcrhk_globals = {
233 &logstream, /* logstream */
234 sizeof(BN_ULONG), /* limbsize */
235 0, /* mslimb first: false for BNs */
236 -1, /* msbyte first: use native */
237 0, /* Max mutexes, 0 = no small limit */
238 0, /* Max simultaneous, 0 = default */
240 /* The next few are mutex stuff: we write wrapper functions
241 around the OS mutex functions. We initialise them to 0
242 here, and change that to actual function pointers in hwcrhk_init()
243 if dynamic locks are supported (that is, if the application
244 programmer has made sure of setting up callbacks bafore starting
245 this engine) *and* if disable_mutex_callbacks hasn't been set by
246 a call to ENGINE_ctrl(ENGINE_CTRL_CHIL_NO_LOCKING). */
247 sizeof(HWCryptoHook_Mutex),
253 /* The next few are condvar stuff: we write wrapper functions
254 round the OS functions. Currently not implemented and not
255 and absolute necessity even in threaded programs, therefore
256 0'ed. Will hopefully be implemented some day, since it
257 enhances the efficiency of HWCryptoHook. */
258 0, /* sizeof(HWCryptoHook_CondVar), */
259 0, /* hwcrhk_cv_init, */
260 0, /* hwcrhk_cv_wait, */
261 0, /* hwcrhk_cv_signal, */
262 0, /* hwcrhk_cv_broadcast, */
263 0, /* hwcrhk_cv_destroy, */
265 hwcrhk_get_pass, /* pass phrase */
266 0, /* insert_card, */ /* insert a card */
267 hwcrhk_log_message /* Log message */
271 /* Now, to our own code */
273 /* As this is only ever called once, there's no need for locking
274 * (indeed - the lock will already be held by our caller!!!) */
275 ENGINE *ENGINE_ncipher()
277 const RSA_METHOD *meth1;
278 const DH_METHOD *meth2;
279 ENGINE *ret = ENGINE_new();
282 if(!ENGINE_set_id(ret, engine_hwcrhk_id) ||
283 !ENGINE_set_name(ret, engine_hwcrhk_name) ||
284 !ENGINE_set_RSA(ret, &hwcrhk_rsa) ||
285 !ENGINE_set_DH(ret, &hwcrhk_dh) ||
286 !ENGINE_set_RAND(ret, &hwcrhk_rand) ||
287 !ENGINE_set_BN_mod_exp(ret, hwcrhk_mod_exp) ||
288 !ENGINE_set_init_function(ret, hwcrhk_init) ||
289 !ENGINE_set_finish_function(ret, hwcrhk_finish) ||
290 !ENGINE_set_ctrl_function(ret, hwcrhk_ctrl) ||
291 !ENGINE_set_load_privkey_function(ret, hwcrhk_load_privkey) ||
292 !ENGINE_set_load_pubkey_function(ret, hwcrhk_load_pubkey))
298 /* We know that the "PKCS1_SSLeay()" functions hook properly
299 * to the cswift-specific mod_exp and mod_exp_crt so we use
300 * those functions. NB: We don't use ENGINE_openssl() or
301 * anything "more generic" because something like the RSAref
302 * code may not hook properly, and if you own one of these
303 * cards then you have the right to do RSA operations on it
305 meth1 = RSA_PKCS1_SSLeay();
306 hwcrhk_rsa.rsa_pub_enc = meth1->rsa_pub_enc;
307 hwcrhk_rsa.rsa_pub_dec = meth1->rsa_pub_dec;
308 hwcrhk_rsa.rsa_priv_enc = meth1->rsa_priv_enc;
309 hwcrhk_rsa.rsa_priv_dec = meth1->rsa_priv_dec;
311 /* Much the same for Diffie-Hellman */
312 meth2 = DH_OpenSSL();
313 hwcrhk_dh.generate_key = meth2->generate_key;
314 hwcrhk_dh.compute_key = meth2->compute_key;
318 /* This is a process-global DSO handle used for loading and unloading
319 * the HWCryptoHook library. NB: This is only set (or unset) during an
320 * init() or finish() call (reference counts permitting) and they're
321 * operating with global locks, so this should be thread-safe
323 static DSO *hwcrhk_dso = NULL;
324 static HWCryptoHook_ContextHandle hwcrhk_context = 0;
325 static int hndidx = -1; /* Index for KM handle. Not really used yet. */
327 /* These are the function pointers that are (un)set when the library has
328 * successfully (un)loaded. */
329 static HWCryptoHook_Init_t *p_hwcrhk_Init = NULL;
330 static HWCryptoHook_Finish_t *p_hwcrhk_Finish = NULL;
331 static HWCryptoHook_ModExp_t *p_hwcrhk_ModExp = NULL;
332 static HWCryptoHook_RSA_t *p_hwcrhk_RSA = NULL;
333 static HWCryptoHook_RandomBytes_t *p_hwcrhk_RandomBytes = NULL;
334 static HWCryptoHook_RSALoadKey_t *p_hwcrhk_RSALoadKey = NULL;
335 static HWCryptoHook_RSAGetPublicKey_t *p_hwcrhk_RSAGetPublicKey = NULL;
336 static HWCryptoHook_RSAUnloadKey_t *p_hwcrhk_RSAUnloadKey = NULL;
337 static HWCryptoHook_ModExpCRT_t *p_hwcrhk_ModExpCRT = NULL;
339 /* Used in the DSO operations. */
340 static const char *HWCRHK_LIBNAME = "nfhwcrhk";
341 static const char *n_hwcrhk_Init = "HWCryptoHook_Init";
342 static const char *n_hwcrhk_Finish = "HWCryptoHook_Finish";
343 static const char *n_hwcrhk_ModExp = "HWCryptoHook_ModExp";
344 static const char *n_hwcrhk_RSA = "HWCryptoHook_RSA";
345 static const char *n_hwcrhk_RandomBytes = "HWCryptoHook_RandomBytes";
346 static const char *n_hwcrhk_RSALoadKey = "HWCryptoHook_RSALoadKey";
347 static const char *n_hwcrhk_RSAGetPublicKey = "HWCryptoHook_RSAGetPublicKey";
348 static const char *n_hwcrhk_RSAUnloadKey = "HWCryptoHook_RSAUnloadKey";
349 static const char *n_hwcrhk_ModExpCRT = "HWCryptoHook_ModExpCRT";
351 /* HWCryptoHook library functions and mechanics - these are used by the
352 * higher-level functions further down. NB: As and where there's no
353 * error checking, take a look lower down where these functions are
354 * called, the checking and error handling is probably down there. */
356 /* utility function to obtain a context */
357 static int get_context(HWCryptoHook_ContextHandle *hac)
360 HWCryptoHook_ErrMsgBuf rmsg;
365 *hac = p_hwcrhk_Init(&hwcrhk_globals, sizeof(hwcrhk_globals), &rmsg,
372 /* similarly to release one. */
373 static void release_context(HWCryptoHook_ContextHandle hac)
375 p_hwcrhk_Finish(hac);
378 /* (de)initialisation functions. */
379 static int hwcrhk_init(ENGINE *e)
381 HWCryptoHook_Init_t *p1;
382 HWCryptoHook_Finish_t *p2;
383 HWCryptoHook_ModExp_t *p3;
384 HWCryptoHook_RSA_t *p4;
385 HWCryptoHook_RSALoadKey_t *p5;
386 HWCryptoHook_RSAGetPublicKey_t *p6;
387 HWCryptoHook_RSAUnloadKey_t *p7;
388 HWCryptoHook_RandomBytes_t *p8;
389 HWCryptoHook_ModExpCRT_t *p9;
391 if(hwcrhk_dso != NULL)
393 ENGINEerr(ENGINE_F_HWCRHK_INIT,ENGINE_R_ALREADY_LOADED);
396 /* Attempt to load libnfhwcrhk.so/nfhwcrhk.dll/whatever. */
397 hwcrhk_dso = DSO_load(NULL, HWCRHK_LIBNAME, NULL, 0);
398 if(hwcrhk_dso == NULL)
400 ENGINEerr(ENGINE_F_HWCRHK_INIT,ENGINE_R_DSO_FAILURE);
403 if(!(p1 = (HWCryptoHook_Init_t *)
404 DSO_bind_func(hwcrhk_dso, n_hwcrhk_Init)) ||
405 !(p2 = (HWCryptoHook_Finish_t *)
406 DSO_bind_func(hwcrhk_dso, n_hwcrhk_Finish)) ||
407 !(p3 = (HWCryptoHook_ModExp_t *)
408 DSO_bind_func(hwcrhk_dso, n_hwcrhk_ModExp)) ||
409 !(p4 = (HWCryptoHook_RSA_t *)
410 DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSA)) ||
411 !(p5 = (HWCryptoHook_RSALoadKey_t *)
412 DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSALoadKey)) ||
413 !(p6 = (HWCryptoHook_RSAGetPublicKey_t *)
414 DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSAGetPublicKey)) ||
415 !(p7 = (HWCryptoHook_RSAUnloadKey_t *)
416 DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSAUnloadKey)) ||
417 !(p8 = (HWCryptoHook_RandomBytes_t *)
418 DSO_bind_func(hwcrhk_dso, n_hwcrhk_RandomBytes)) ||
419 !(p9 = (HWCryptoHook_ModExpCRT_t *)
420 DSO_bind_func(hwcrhk_dso, n_hwcrhk_ModExpCRT)))
422 ENGINEerr(ENGINE_F_HWCRHK_INIT,ENGINE_R_DSO_FAILURE);
425 /* Copy the pointers */
427 p_hwcrhk_Finish = p2;
428 p_hwcrhk_ModExp = p3;
430 p_hwcrhk_RSALoadKey = p5;
431 p_hwcrhk_RSAGetPublicKey = p6;
432 p_hwcrhk_RSAUnloadKey = p7;
433 p_hwcrhk_RandomBytes = p8;
434 p_hwcrhk_ModExpCRT = p9;
436 /* Check if the application decided to support dynamic locks,
437 and if it does, use them. */
438 if (disable_mutex_callbacks == 0 &&
439 CRYPTO_get_dynlock_create_callback() != NULL &&
440 CRYPTO_get_dynlock_lock_callback() != NULL &&
441 CRYPTO_get_dynlock_destroy_callback() != NULL)
443 hwcrhk_globals.mutex_init = hwcrhk_mutex_init;
444 hwcrhk_globals.mutex_acquire = hwcrhk_mutex_lock;
445 hwcrhk_globals.mutex_release = hwcrhk_mutex_unlock;
446 hwcrhk_globals.mutex_destroy = hwcrhk_mutex_destroy;
449 /* Try and get a context - if not, we may have a DSO but no
451 if(!get_context(&hwcrhk_context))
453 ENGINEerr(ENGINE_F_HWCRHK_INIT,ENGINE_R_UNIT_FAILURE);
456 /* Everything's fine. */
458 hndidx = RSA_get_ex_new_index(0,
459 "nFast HWCryptoHook RSA key handle",
460 NULL, NULL, hwcrhk_ex_free);
464 DSO_free(hwcrhk_dso);
466 p_hwcrhk_Init = NULL;
467 p_hwcrhk_Finish = NULL;
468 p_hwcrhk_ModExp = NULL;
470 p_hwcrhk_RSALoadKey = NULL;
471 p_hwcrhk_RSAGetPublicKey = NULL;
472 p_hwcrhk_RSAUnloadKey = NULL;
473 p_hwcrhk_ModExpCRT = NULL;
474 p_hwcrhk_RandomBytes = NULL;
478 static int hwcrhk_finish(ENGINE *e)
481 if(hwcrhk_dso == NULL)
483 ENGINEerr(ENGINE_F_HWCRHK_FINISH,ENGINE_R_NOT_LOADED);
487 release_context(hwcrhk_context);
488 if(!DSO_free(hwcrhk_dso))
490 ENGINEerr(ENGINE_F_HWCRHK_FINISH,ENGINE_R_DSO_FAILURE);
498 p_hwcrhk_Init = NULL;
499 p_hwcrhk_Finish = NULL;
500 p_hwcrhk_ModExp = NULL;
502 p_hwcrhk_RSALoadKey = NULL;
503 p_hwcrhk_RSAGetPublicKey = NULL;
504 p_hwcrhk_RSAUnloadKey = NULL;
505 p_hwcrhk_ModExpCRT = NULL;
506 p_hwcrhk_RandomBytes = NULL;
510 static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
516 case ENGINE_CTRL_SET_LOGSTREAM:
520 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
526 if (CRYPTO_add(&bio->references,1,CRYPTO_LOCK_BIO) > 1)
529 ENGINEerr(ENGINE_F_HWCRHK_CTRL,ENGINE_R_BIO_WAS_FREED);
531 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
533 case ENGINE_CTRL_SET_PASSWORD_CALLBACK:
534 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
535 password_callback = (pem_password_cb *)f;
536 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
538 /* this enables or disables the "SimpleForkCheck" flag used in the
539 * initialisation structure. */
540 case ENGINE_CTRL_CHIL_SET_FORKCHECK:
541 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
543 hwcrhk_globals.flags |=
544 HWCryptoHook_InitFlags_SimpleForkCheck;
546 hwcrhk_globals.flags &=
547 ~HWCryptoHook_InitFlags_SimpleForkCheck;
548 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
550 /* This will prevent the initialisation function from "installing"
551 * the mutex-handling callbacks, even if they are available from
552 * within the library (or were provided to the library from the
553 * calling application). This is to remove any baggage for
554 * applications not using multithreading. */
555 case ENGINE_CTRL_CHIL_NO_LOCKING:
556 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
557 disable_mutex_callbacks = 1;
558 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
561 /* The command isn't understood by this engine */
563 ENGINEerr(ENGINE_F_HWCRHK_CTRL,
564 ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED);
572 static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
573 const char *passphrase)
576 EVP_PKEY *res = NULL;
577 HWCryptoHook_MPI e, n;
578 HWCryptoHook_RSAKeyHandle *hptr;
579 HWCryptoHook_ErrMsgBuf rmsg;
583 ENGINEerr(ENGINE_F_HWCRHK_LOAD_PRIVKEY,
584 ENGINE_R_NOT_INITIALISED);
587 hptr = OPENSSL_malloc(sizeof(HWCryptoHook_RSAKeyHandle));
590 ENGINEerr(ENGINE_F_HWCRHK_LOAD_PRIVKEY,
591 ERR_R_MALLOC_FAILURE);
594 if (p_hwcrhk_RSALoadKey(hwcrhk_context, key_id, hptr,
597 ENGINEerr(ENGINE_F_HWCRHK_LOAD_PRIVKEY,
598 ENGINE_R_CHIL_ERROR);
599 ERR_add_error_data(1,rmsg.buf);
604 ENGINEerr(ENGINE_F_HWCRHK_LOAD_PRIVKEY,
608 rtmp = RSA_new_method(eng);
609 RSA_set_ex_data(rtmp, hndidx, (char *)hptr);
612 rtmp->flags |= RSA_FLAG_EXT_PKEY;
615 if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg)
616 != HWCRYPTOHOOK_ERROR_MPISIZE)
618 ENGINEerr(ENGINE_F_HWCRHK_LOAD_PUBKEY,ENGINE_R_CHIL_ERROR);
619 ERR_add_error_data(1,rmsg.buf);
623 bn_expand2(rtmp->e, e.size/sizeof(BN_ULONG));
624 bn_expand2(rtmp->n, n.size/sizeof(BN_ULONG));
628 if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg))
630 ENGINEerr(ENGINE_F_HWCRHK_LOAD_PUBKEY,
631 ENGINE_R_CHIL_ERROR);
632 ERR_add_error_data(1,rmsg.buf);
635 rtmp->e->top = e.size / sizeof(BN_ULONG);
637 rtmp->n->top = n.size / sizeof(BN_ULONG);
640 res = EVP_PKEY_new();
641 EVP_PKEY_assign_RSA(res, rtmp);
652 static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
653 const char *passphrase)
655 EVP_PKEY *res = hwcrhk_load_privkey(eng, key_id, passphrase);
664 CRYPTO_w_lock(CRYPTO_LOCK_EVP_PKEY);
666 res->pkey.rsa = RSA_new();
667 res->pkey.rsa->n = rsa->n;
668 res->pkey.rsa->e = rsa->e;
669 CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY);
673 ENGINEerr(ENGINE_F_HWCRHK_LOAD_PUBKEY,
674 ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED);
685 /* A little mod_exp */
686 static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
687 const BIGNUM *m, BN_CTX *ctx)
690 HWCryptoHook_ErrMsgBuf rmsg;
691 /* Since HWCryptoHook_MPI is pretty compatible with BIGNUM's,
692 we use them directly, plus a little macro magic. We only
693 thing we need to make sure of is that enough space is allocated. */
694 HWCryptoHook_MPI m_a, m_p, m_n, m_r;
697 to_return = 0; /* expect failure */
703 ENGINEerr(ENGINE_F_HWCRHK_MOD_EXP,ENGINE_R_NOT_INITIALISED);
706 /* Prepare the params */
707 bn_expand2(r, m->top); /* Check for error !! */
713 /* Perform the operation */
714 ret = p_hwcrhk_ModExp(hwcrhk_context, m_a, m_p, m_n, &m_r, &rmsg);
716 /* Convert the response */
717 r->top = m_r.size / sizeof(BN_ULONG);
722 /* FIXME: When this error is returned, HWCryptoHook is
723 telling us that falling back to software computation
724 might be a good thing. */
725 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
727 ENGINEerr(ENGINE_F_HWCRHK_MOD_EXP,ENGINE_R_REQUEST_FALLBACK);
731 ENGINEerr(ENGINE_F_HWCRHK_MOD_EXP,ENGINE_R_REQUEST_FAILED);
733 ERR_add_error_data(1,rmsg.buf);
742 static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa)
745 HWCryptoHook_ErrMsgBuf rmsg;
746 HWCryptoHook_RSAKeyHandle *hptr;
747 int to_return = 0, ret;
751 ENGINEerr(ENGINE_F_HWCRHK_MOD_EXP,ENGINE_R_NOT_INITIALISED);
755 /* This provides support for nForce keys. Since that's opaque data
756 all we do is provide a handle to the proper key and let HWCryptoHook
757 take care of the rest. */
758 if ((hptr = (HWCryptoHook_RSAKeyHandle *) RSA_get_ex_data(rsa, hndidx))
761 HWCryptoHook_MPI m_a, m_r;
765 ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,
766 ENGINE_R_MISSING_KEY_COMPONENTS);
773 /* Prepare the params */
774 bn_expand2(r, rsa->n->top); /* Check for error !! */
778 /* Perform the operation */
779 ret = p_hwcrhk_RSA(m_a, *hptr, &m_r, &rmsg);
781 /* Convert the response */
782 r->top = m_r.size / sizeof(BN_ULONG);
787 /* FIXME: When this error is returned, HWCryptoHook is
788 telling us that falling back to software computation
789 might be a good thing. */
790 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
792 ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,ENGINE_R_REQUEST_FALLBACK);
796 ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,ENGINE_R_REQUEST_FAILED);
798 ERR_add_error_data(1,rmsg.buf);
804 HWCryptoHook_MPI m_a, m_p, m_q, m_dmp1, m_dmq1, m_iqmp, m_r;
806 if(!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp)
808 ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,
809 ENGINE_R_MISSING_KEY_COMPONENTS);
816 /* Prepare the params */
817 bn_expand2(r, rsa->n->top); /* Check for error !! */
821 BN2MPI(m_dmp1, rsa->dmp1);
822 BN2MPI(m_dmq1, rsa->dmq1);
823 BN2MPI(m_iqmp, rsa->iqmp);
826 /* Perform the operation */
827 ret = p_hwcrhk_ModExpCRT(hwcrhk_context, m_a, m_p, m_q,
828 m_dmp1, m_dmq1, m_iqmp, &m_r, NULL);
830 /* Convert the response */
831 r->top = m_r.size / sizeof(BN_ULONG);
836 /* FIXME: When this error is returned, HWCryptoHook is
837 telling us that falling back to software computation
838 might be a good thing. */
839 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
841 ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,ENGINE_R_REQUEST_FALLBACK);
845 ENGINEerr(ENGINE_F_HWCRHK_RSA_MOD_EXP,ENGINE_R_REQUEST_FAILED);
847 ERR_add_error_data(1,rmsg.buf);
851 /* If we're here, we must be here with some semblance of success :-) */
857 /* This function is aliased to mod_exp (with the mont stuff dropped). */
858 static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
859 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
861 return hwcrhk_mod_exp(r, a, p, m, ctx);
864 /* This function is aliased to mod_exp (with the dh and mont dropped). */
865 static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r,
866 const BIGNUM *a, const BIGNUM *p,
867 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
869 return hwcrhk_mod_exp(r, a, p, m, ctx);
872 /* Random bytes are good */
873 static int hwcrhk_rand_bytes(unsigned char *buf, int num)
876 HWCryptoHook_ErrMsgBuf rmsg;
877 int to_return = 0; /* assume failure */
885 ENGINEerr(ENGINE_F_HWCRHK_RAND_BYTES,ENGINE_R_NOT_INITIALISED);
889 ret = p_hwcrhk_RandomBytes(hwcrhk_context, buf, num, &rmsg);
892 /* FIXME: When this error is returned, HWCryptoHook is
893 telling us that falling back to software computation
894 might be a good thing. */
895 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
897 ENGINEerr(ENGINE_F_HWCRHK_RAND_BYTES,ENGINE_R_REQUEST_FALLBACK);
901 ENGINEerr(ENGINE_F_HWCRHK_RAND_BYTES,ENGINE_R_REQUEST_FAILED);
903 ERR_add_error_data(1,rmsg.buf);
911 static int hwcrhk_rand_status(void)
916 /* This cleans up an RSA KM key, called when ex_data is freed */
918 static void hwcrhk_ex_free(void *obj, void *item, CRYPTO_EX_DATA *ad,
919 int ind,long argl, void *argp)
922 HWCryptoHook_ErrMsgBuf rmsg;
923 HWCryptoHook_RSAKeyHandle *hptr;
929 hptr = (HWCryptoHook_RSAKeyHandle *) item;
931 ret = p_hwcrhk_RSAUnloadKey(*hptr, NULL);
935 /* Mutex calls: since the HWCryptoHook model closely follows the POSIX model
936 * these just wrap the POSIX functions and add some logging.
939 static int hwcrhk_mutex_init(HWCryptoHook_Mutex* mt,
940 HWCryptoHook_CallerContext *cactx)
942 mt->lockid = CRYPTO_get_new_dynlockid();
948 static int hwcrhk_mutex_lock(HWCryptoHook_Mutex *mt)
950 CRYPTO_w_lock(mt->lockid);
954 void hwcrhk_mutex_unlock(HWCryptoHook_Mutex * mt)
956 CRYPTO_w_unlock(mt->lockid);
959 static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex *mt)
961 CRYPTO_destroy_dynlockid(mt->lockid);
964 static int hwcrhk_get_pass(const char *prompt_info,
965 int *len_io, char *buf,
966 HWCryptoHook_PassphraseContext *ppctx,
967 HWCryptoHook_CallerContext *cactx)
972 if (password_callback == NULL)
974 ENGINEerr(ENGINE_F_HWCRHK_GET_PASS,ENGINE_R_NO_CALLBACK);
979 strncpy(prompt, "Card: \"", sizeof(prompt));
981 strncpy(prompt + l, prompt_info, sizeof(prompt) - l);
982 l += strlen(prompt_info);
983 if (l + 2 < sizeof(prompt))
985 strncpy(prompt + l, "\"\n", sizeof(prompt) - l);
989 if (l < sizeof(prompt) - 1)
991 strncpy(prompt, "Enter Passphrase <enter to cancel>:",
997 /* I know, passing on the prompt instead of the user data *is*
998 a bad thing. However, that's all we have right now.
999 -- Richard Levitte */
1000 *len_io = password_callback(buf, *len_io, 0, prompt);
1006 static void hwcrhk_log_message(void *logstr, const char *message)
1008 BIO *lstream = NULL;
1010 CRYPTO_w_lock(CRYPTO_LOCK_BIO);
1012 lstream=*(BIO **)logstr;
1015 BIO_write(lstream, message, strlen(message));
1017 CRYPTO_w_unlock(CRYPTO_LOCK_BIO);
1020 #endif /* !OPENSSL_NO_HW_NCIPHER */
1021 #endif /* !OPENSSL_NO_HW */