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-2001 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).
62 #include <openssl/crypto.h>
63 #include <openssl/pem.h>
65 #include <openssl/dso.h>
66 #include <openssl/engine.h>
67 #include <openssl/ui.h>
70 #ifndef OPENSSL_NO_HW_NCIPHER
72 /* Attribution notice: nCipher have said several times that it's OK for
73 * us to implement a general interface to their boxes, and recently declared
74 * their HWCryptoHook to be public, and therefore available for us to use.
77 * The hwcryptohook.h included here is from May 2000.
81 #include "hwcryptohook.h"
83 #include "vendor_defns/hwcryptohook.h"
86 #define HWCRHK_LIB_NAME "hwcrhk engine"
87 #include "hw_ncipher_err.c"
89 static int hwcrhk_destroy(ENGINE *e);
90 static int hwcrhk_init(ENGINE *e);
91 static int hwcrhk_finish(ENGINE *e);
92 static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)());
94 /* Functions to handle mutexes */
95 static int hwcrhk_mutex_init(HWCryptoHook_Mutex*, HWCryptoHook_CallerContext*);
96 static int hwcrhk_mutex_lock(HWCryptoHook_Mutex*);
97 static void hwcrhk_mutex_unlock(HWCryptoHook_Mutex*);
98 static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex*);
101 static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
102 const BIGNUM *m, BN_CTX *ctx);
104 #ifndef OPENSSL_NO_RSA
106 static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa);
108 /* This function is aliased to mod_exp (with the mont stuff dropped). */
109 static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
110 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
113 /* This function is alised to mod_exp (with the DH and mont dropped). */
114 static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r,
115 const BIGNUM *a, const BIGNUM *p,
116 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
119 static int hwcrhk_rand_bytes(unsigned char *buf, int num);
120 static int hwcrhk_rand_status(void);
123 static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
124 UI_METHOD *ui_method, void *callback_data);
125 static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
126 UI_METHOD *ui_method, void *callback_data);
127 static void hwcrhk_ex_free(void *obj, void *item, CRYPTO_EX_DATA *ad,
128 int ind,long argl, void *argp);
130 /* Interaction stuff */
131 static int hwcrhk_insert_card(const char *prompt_info,
132 const char *wrong_info,
133 HWCryptoHook_PassphraseContext *ppctx,
134 HWCryptoHook_CallerContext *cactx);
135 static int hwcrhk_get_pass(const char *prompt_info,
136 int *len_io, char *buf,
137 HWCryptoHook_PassphraseContext *ppctx,
138 HWCryptoHook_CallerContext *cactx);
139 static void hwcrhk_log_message(void *logstr, const char *message);
141 /* The definitions for control commands specific to this engine */
142 #define HWCRHK_CMD_SO_PATH ENGINE_CMD_BASE
143 #define HWCRHK_CMD_FORK_CHECK (ENGINE_CMD_BASE + 1)
144 #define HWCRHK_CMD_THREAD_LOCKING (ENGINE_CMD_BASE + 2)
145 #define HWCRHK_CMD_SET_USER_INTERFACE (ENGINE_CMD_BASE + 3)
146 #define HWCRHK_CMD_SET_CALLBACK_DATA (ENGINE_CMD_BASE + 4)
147 static const ENGINE_CMD_DEFN hwcrhk_cmd_defns[] = {
150 "Specifies the path to the 'hwcrhk' shared library",
151 ENGINE_CMD_FLAG_STRING},
152 {HWCRHK_CMD_FORK_CHECK,
154 "Turns fork() checking on or off (boolean)",
155 ENGINE_CMD_FLAG_NUMERIC},
156 {HWCRHK_CMD_THREAD_LOCKING,
158 "Turns thread-safe locking on or off (boolean)",
159 ENGINE_CMD_FLAG_NUMERIC},
160 {HWCRHK_CMD_SET_USER_INTERFACE,
161 "SET_USER_INTERFACE",
162 "Set the global user interface (internal)",
163 ENGINE_CMD_FLAG_INTERNAL},
164 {HWCRHK_CMD_SET_CALLBACK_DATA,
166 "Set the global user interface extra data (internal)",
167 ENGINE_CMD_FLAG_INTERNAL},
171 #ifndef OPENSSL_NO_RSA
172 /* Our internal RSA_METHOD that we provide pointers to */
173 static RSA_METHOD hwcrhk_rsa =
175 "nCipher RSA method",
191 #ifndef OPENSSL_NO_DH
192 /* Our internal DH_METHOD that we provide pointers to */
193 static DH_METHOD hwcrhk_dh =
206 static RAND_METHOD hwcrhk_rand =
208 /* "nCipher RAND method", */
217 /* Constants used when creating the ENGINE */
218 static const char *engine_hwcrhk_id = "chil";
219 static const char *engine_hwcrhk_name = "nCipher hardware engine support";
221 /* Internal stuff for HWCryptoHook */
223 /* Some structures needed for proper use of thread locks */
224 /* hwcryptohook.h has some typedefs that turn struct HWCryptoHook_MutexValue
225 into HWCryptoHook_Mutex */
226 struct HWCryptoHook_MutexValue
231 /* hwcryptohook.h has some typedefs that turn
232 struct HWCryptoHook_PassphraseContextValue
233 into HWCryptoHook_PassphraseContext */
234 struct HWCryptoHook_PassphraseContextValue
236 UI_METHOD *ui_method;
240 /* hwcryptohook.h has some typedefs that turn
241 struct HWCryptoHook_CallerContextValue
242 into HWCryptoHook_CallerContext */
243 struct HWCryptoHook_CallerContextValue
245 pem_password_cb *password_callback; /* Deprecated! Only present for
246 backward compatibility! */
247 UI_METHOD *ui_method;
251 /* The MPI structure in HWCryptoHook is pretty compatible with OpenSSL
252 BIGNUM's, so lets define a couple of conversion macros */
253 #define BN2MPI(mp, bn) \
254 {mp.size = bn->top * sizeof(BN_ULONG); mp.buf = (unsigned char *)bn->d;}
255 #define MPI2BN(bn, mp) \
256 {mp.size = bn->dmax * sizeof(BN_ULONG); mp.buf = (unsigned char *)bn->d;}
258 static BIO *logstream = NULL;
259 static int disable_mutex_callbacks = 0;
261 /* One might wonder why these are needed, since one can pass down at least
262 a UI_METHOD and a pointer to callback data to the key-loading functions.
263 The thing is that the ModExp and RSAImmed functions can load keys as well,
264 if the data they get is in a special, nCipher-defined format (hint: if you
265 look at the private exponent of the RSA data as a string, you'll see this
266 string: "nCipher KM tool key id", followed by some bytes, followed a key
267 identity string, followed by more bytes. This happens when you use "embed"
268 keys instead of "hwcrhk" keys). Unfortunately, those functions do not take
269 any passphrase or caller context, and our functions can't really take any
270 callback data either. Still, the "insert_card" and "get_passphrase"
271 callbacks may be called down the line, and will need to know what user
272 interface callbacks to call, and having callback data from the application
273 may be a nice thing as well, so we need to keep track of that globally. */
274 static HWCryptoHook_CallerContext password_context = { NULL, NULL, NULL };
276 /* Stuff to pass to the HWCryptoHook library */
277 static HWCryptoHook_InitInfo hwcrhk_globals = {
278 HWCryptoHook_InitFlags_SimpleForkCheck, /* Flags */
279 &logstream, /* logstream */
280 sizeof(BN_ULONG), /* limbsize */
281 0, /* mslimb first: false for BNs */
282 -1, /* msbyte first: use native */
283 0, /* Max mutexes, 0 = no small limit */
284 0, /* Max simultaneous, 0 = default */
286 /* The next few are mutex stuff: we write wrapper functions
287 around the OS mutex functions. We initialise them to 0
288 here, and change that to actual function pointers in hwcrhk_init()
289 if dynamic locks are supported (that is, if the application
290 programmer has made sure of setting up callbacks bafore starting
291 this engine) *and* if disable_mutex_callbacks hasn't been set by
292 a call to ENGINE_ctrl(ENGINE_CTRL_CHIL_NO_LOCKING). */
293 sizeof(HWCryptoHook_Mutex),
299 /* The next few are condvar stuff: we write wrapper functions
300 round the OS functions. Currently not implemented and not
301 and absolute necessity even in threaded programs, therefore
302 0'ed. Will hopefully be implemented some day, since it
303 enhances the efficiency of HWCryptoHook. */
304 0, /* sizeof(HWCryptoHook_CondVar), */
305 0, /* hwcrhk_cv_init, */
306 0, /* hwcrhk_cv_wait, */
307 0, /* hwcrhk_cv_signal, */
308 0, /* hwcrhk_cv_broadcast, */
309 0, /* hwcrhk_cv_destroy, */
311 hwcrhk_get_pass, /* pass phrase */
312 hwcrhk_insert_card, /* insert a card */
313 hwcrhk_log_message /* Log message */
317 /* Now, to our own code */
319 /* This internal function is used by ENGINE_ncipher() and possibly by the
320 * "dynamic" ENGINE support too */
321 static int bind_helper(ENGINE *e)
323 #ifndef OPENSSL_NO_RSA
324 const RSA_METHOD *meth1;
326 #ifndef OPENSSL_NO_DH
327 const DH_METHOD *meth2;
329 if(!ENGINE_set_id(e, engine_hwcrhk_id) ||
330 !ENGINE_set_name(e, engine_hwcrhk_name) ||
331 #ifndef OPENSSL_NO_RSA
332 !ENGINE_set_RSA(e, &hwcrhk_rsa) ||
334 #ifndef OPENSSL_NO_DH
335 !ENGINE_set_DH(e, &hwcrhk_dh) ||
337 !ENGINE_set_RAND(e, &hwcrhk_rand) ||
338 !ENGINE_set_destroy_function(e, hwcrhk_destroy) ||
339 !ENGINE_set_init_function(e, hwcrhk_init) ||
340 !ENGINE_set_finish_function(e, hwcrhk_finish) ||
341 !ENGINE_set_ctrl_function(e, hwcrhk_ctrl) ||
342 !ENGINE_set_load_privkey_function(e, hwcrhk_load_privkey) ||
343 !ENGINE_set_load_pubkey_function(e, hwcrhk_load_pubkey) ||
344 !ENGINE_set_cmd_defns(e, hwcrhk_cmd_defns))
347 #ifndef OPENSSL_NO_RSA
348 /* We know that the "PKCS1_SSLeay()" functions hook properly
349 * to the cswift-specific mod_exp and mod_exp_crt so we use
350 * those functions. NB: We don't use ENGINE_openssl() or
351 * anything "more generic" because something like the RSAref
352 * code may not hook properly, and if you own one of these
353 * cards then you have the right to do RSA operations on it
355 meth1 = RSA_PKCS1_SSLeay();
356 hwcrhk_rsa.rsa_pub_enc = meth1->rsa_pub_enc;
357 hwcrhk_rsa.rsa_pub_dec = meth1->rsa_pub_dec;
358 hwcrhk_rsa.rsa_priv_enc = meth1->rsa_priv_enc;
359 hwcrhk_rsa.rsa_priv_dec = meth1->rsa_priv_dec;
362 #ifndef OPENSSL_NO_DH
363 /* Much the same for Diffie-Hellman */
364 meth2 = DH_OpenSSL();
365 hwcrhk_dh.generate_key = meth2->generate_key;
366 hwcrhk_dh.compute_key = meth2->compute_key;
369 /* Ensure the hwcrhk error handling is set up */
370 ERR_load_HWCRHK_strings();
374 static ENGINE *engine_ncipher(void)
376 ENGINE *ret = ENGINE_new();
379 if(!bind_helper(ret))
387 void ENGINE_load_chil(void)
389 /* Copied from eng_[openssl|dyn].c */
390 ENGINE *toadd = engine_ncipher();
397 /* This is a process-global DSO handle used for loading and unloading
398 * the HWCryptoHook library. NB: This is only set (or unset) during an
399 * init() or finish() call (reference counts permitting) and they're
400 * operating with global locks, so this should be thread-safe
402 static DSO *hwcrhk_dso = NULL;
403 static HWCryptoHook_ContextHandle hwcrhk_context = 0;
404 #ifndef OPENSSL_NO_RSA
405 static int hndidx_rsa = -1; /* Index for KM handle. Not really used yet. */
408 /* These are the function pointers that are (un)set when the library has
409 * successfully (un)loaded. */
410 static HWCryptoHook_Init_t *p_hwcrhk_Init = NULL;
411 static HWCryptoHook_Finish_t *p_hwcrhk_Finish = NULL;
412 static HWCryptoHook_ModExp_t *p_hwcrhk_ModExp = NULL;
413 #ifndef OPENSSL_NO_RSA
414 static HWCryptoHook_RSA_t *p_hwcrhk_RSA = NULL;
416 static HWCryptoHook_RandomBytes_t *p_hwcrhk_RandomBytes = NULL;
417 #ifndef OPENSSL_NO_RSA
418 static HWCryptoHook_RSALoadKey_t *p_hwcrhk_RSALoadKey = NULL;
419 static HWCryptoHook_RSAGetPublicKey_t *p_hwcrhk_RSAGetPublicKey = NULL;
420 static HWCryptoHook_RSAUnloadKey_t *p_hwcrhk_RSAUnloadKey = NULL;
422 static HWCryptoHook_ModExpCRT_t *p_hwcrhk_ModExpCRT = NULL;
424 /* Used in the DSO operations. */
425 static const char def_HWCRHK_LIBNAME[] = "nfhwcrhk";
426 static const char *HWCRHK_LIBNAME = def_HWCRHK_LIBNAME;
427 static const char *n_hwcrhk_Init = "HWCryptoHook_Init";
428 static const char *n_hwcrhk_Finish = "HWCryptoHook_Finish";
429 static const char *n_hwcrhk_ModExp = "HWCryptoHook_ModExp";
430 #ifndef OPENSSL_NO_RSA
431 static const char *n_hwcrhk_RSA = "HWCryptoHook_RSA";
433 static const char *n_hwcrhk_RandomBytes = "HWCryptoHook_RandomBytes";
434 #ifndef OPENSSL_NO_RSA
435 static const char *n_hwcrhk_RSALoadKey = "HWCryptoHook_RSALoadKey";
436 static const char *n_hwcrhk_RSAGetPublicKey = "HWCryptoHook_RSAGetPublicKey";
437 static const char *n_hwcrhk_RSAUnloadKey = "HWCryptoHook_RSAUnloadKey";
439 static const char *n_hwcrhk_ModExpCRT = "HWCryptoHook_ModExpCRT";
441 /* HWCryptoHook library functions and mechanics - these are used by the
442 * higher-level functions further down. NB: As and where there's no
443 * error checking, take a look lower down where these functions are
444 * called, the checking and error handling is probably down there. */
446 /* utility function to obtain a context */
447 static int get_context(HWCryptoHook_ContextHandle *hac,
448 HWCryptoHook_CallerContext *cac)
451 HWCryptoHook_ErrMsgBuf rmsg;
454 rmsg.size = sizeof(tempbuf);
456 *hac = p_hwcrhk_Init(&hwcrhk_globals, sizeof(hwcrhk_globals), &rmsg,
463 /* similarly to release one. */
464 static void release_context(HWCryptoHook_ContextHandle hac)
466 p_hwcrhk_Finish(hac);
469 /* Destructor (complements the "ENGINE_ncipher()" constructor) */
470 static int hwcrhk_destroy(ENGINE *e)
472 ERR_unload_HWCRHK_strings();
476 /* (de)initialisation functions. */
477 static int hwcrhk_init(ENGINE *e)
479 HWCryptoHook_Init_t *p1;
480 HWCryptoHook_Finish_t *p2;
481 HWCryptoHook_ModExp_t *p3;
482 #ifndef OPENSSL_NO_RSA
483 HWCryptoHook_RSA_t *p4;
484 HWCryptoHook_RSALoadKey_t *p5;
485 HWCryptoHook_RSAGetPublicKey_t *p6;
486 HWCryptoHook_RSAUnloadKey_t *p7;
488 HWCryptoHook_RandomBytes_t *p8;
489 HWCryptoHook_ModExpCRT_t *p9;
491 if(hwcrhk_dso != NULL)
493 HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_ALREADY_LOADED);
496 /* Attempt to load libnfhwcrhk.so/nfhwcrhk.dll/whatever. */
497 hwcrhk_dso = DSO_load(NULL, HWCRHK_LIBNAME, NULL, 0);
498 if(hwcrhk_dso == NULL)
500 HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_DSO_FAILURE);
503 if(!(p1 = (HWCryptoHook_Init_t *)
504 DSO_bind_func(hwcrhk_dso, n_hwcrhk_Init)) ||
505 !(p2 = (HWCryptoHook_Finish_t *)
506 DSO_bind_func(hwcrhk_dso, n_hwcrhk_Finish)) ||
507 !(p3 = (HWCryptoHook_ModExp_t *)
508 DSO_bind_func(hwcrhk_dso, n_hwcrhk_ModExp)) ||
509 #ifndef OPENSSL_NO_RSA
510 !(p4 = (HWCryptoHook_RSA_t *)
511 DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSA)) ||
512 !(p5 = (HWCryptoHook_RSALoadKey_t *)
513 DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSALoadKey)) ||
514 !(p6 = (HWCryptoHook_RSAGetPublicKey_t *)
515 DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSAGetPublicKey)) ||
516 !(p7 = (HWCryptoHook_RSAUnloadKey_t *)
517 DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSAUnloadKey)) ||
519 !(p8 = (HWCryptoHook_RandomBytes_t *)
520 DSO_bind_func(hwcrhk_dso, n_hwcrhk_RandomBytes)) ||
521 !(p9 = (HWCryptoHook_ModExpCRT_t *)
522 DSO_bind_func(hwcrhk_dso, n_hwcrhk_ModExpCRT)))
524 HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_DSO_FAILURE);
527 /* Copy the pointers */
529 p_hwcrhk_Finish = p2;
530 p_hwcrhk_ModExp = p3;
531 #ifndef OPENSSL_NO_RSA
533 p_hwcrhk_RSALoadKey = p5;
534 p_hwcrhk_RSAGetPublicKey = p6;
535 p_hwcrhk_RSAUnloadKey = p7;
537 p_hwcrhk_RandomBytes = p8;
538 p_hwcrhk_ModExpCRT = p9;
540 /* Check if the application decided to support dynamic locks,
541 and if it does, use them. */
542 if (disable_mutex_callbacks == 0 &&
543 CRYPTO_get_dynlock_create_callback() != NULL &&
544 CRYPTO_get_dynlock_lock_callback() != NULL &&
545 CRYPTO_get_dynlock_destroy_callback() != NULL)
547 hwcrhk_globals.mutex_init = hwcrhk_mutex_init;
548 hwcrhk_globals.mutex_acquire = hwcrhk_mutex_lock;
549 hwcrhk_globals.mutex_release = hwcrhk_mutex_unlock;
550 hwcrhk_globals.mutex_destroy = hwcrhk_mutex_destroy;
553 /* Try and get a context - if not, we may have a DSO but no
555 if(!get_context(&hwcrhk_context, &password_context))
557 HWCRHKerr(HWCRHK_F_HWCRHK_INIT,HWCRHK_R_UNIT_FAILURE);
560 /* Everything's fine. */
561 #ifndef OPENSSL_NO_RSA
562 if (hndidx_rsa == -1)
563 hndidx_rsa = RSA_get_ex_new_index(0,
564 "nFast HWCryptoHook RSA key handle",
565 NULL, NULL, hwcrhk_ex_free);
570 DSO_free(hwcrhk_dso);
572 p_hwcrhk_Init = NULL;
573 p_hwcrhk_Finish = NULL;
574 p_hwcrhk_ModExp = NULL;
575 #ifndef OPENSSL_NO_RSA
577 p_hwcrhk_RSALoadKey = NULL;
578 p_hwcrhk_RSAGetPublicKey = NULL;
579 p_hwcrhk_RSAUnloadKey = NULL;
581 p_hwcrhk_ModExpCRT = NULL;
582 p_hwcrhk_RandomBytes = NULL;
586 static int hwcrhk_finish(ENGINE *e)
589 if(hwcrhk_dso == NULL)
591 HWCRHKerr(HWCRHK_F_HWCRHK_FINISH,HWCRHK_R_NOT_LOADED);
595 release_context(hwcrhk_context);
596 if(!DSO_free(hwcrhk_dso))
598 HWCRHKerr(HWCRHK_F_HWCRHK_FINISH,HWCRHK_R_DSO_FAILURE);
606 p_hwcrhk_Init = NULL;
607 p_hwcrhk_Finish = NULL;
608 p_hwcrhk_ModExp = NULL;
609 #ifndef OPENSSL_NO_RSA
611 p_hwcrhk_RSALoadKey = NULL;
612 p_hwcrhk_RSAGetPublicKey = NULL;
613 p_hwcrhk_RSAUnloadKey = NULL;
615 p_hwcrhk_ModExpCRT = NULL;
616 p_hwcrhk_RandomBytes = NULL;
620 static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
626 case HWCRHK_CMD_SO_PATH:
629 HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,HWCRHK_R_ALREADY_LOADED);
634 HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,ERR_R_PASSED_NULL_PARAMETER);
637 HWCRHK_LIBNAME = (const char *)p;
639 case ENGINE_CTRL_SET_LOGSTREAM:
643 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
649 if (CRYPTO_add(&bio->references,1,CRYPTO_LOCK_BIO) > 1)
652 HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,HWCRHK_R_BIO_WAS_FREED);
654 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
656 case ENGINE_CTRL_SET_PASSWORD_CALLBACK:
657 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
658 password_context.password_callback = (pem_password_cb *)f;
659 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
661 case ENGINE_CTRL_SET_USER_INTERFACE:
662 case HWCRHK_CMD_SET_USER_INTERFACE:
663 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
664 password_context.ui_method = (UI_METHOD *)p;
665 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
667 case ENGINE_CTRL_SET_CALLBACK_DATA:
668 case HWCRHK_CMD_SET_CALLBACK_DATA:
669 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
670 password_context.callback_data = p;
671 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
673 /* this enables or disables the "SimpleForkCheck" flag used in the
674 * initialisation structure. */
675 case ENGINE_CTRL_CHIL_SET_FORKCHECK:
676 case HWCRHK_CMD_FORK_CHECK:
677 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
679 hwcrhk_globals.flags |=
680 HWCryptoHook_InitFlags_SimpleForkCheck;
682 hwcrhk_globals.flags &=
683 ~HWCryptoHook_InitFlags_SimpleForkCheck;
684 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
686 /* This will prevent the initialisation function from "installing"
687 * the mutex-handling callbacks, even if they are available from
688 * within the library (or were provided to the library from the
689 * calling application). This is to remove any baggage for
690 * applications not using multithreading. */
691 case ENGINE_CTRL_CHIL_NO_LOCKING:
692 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
693 disable_mutex_callbacks = 1;
694 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
696 case HWCRHK_CMD_THREAD_LOCKING:
697 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
698 disable_mutex_callbacks = ((i == 0) ? 0 : 1);
699 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
702 /* The command isn't understood by this engine */
704 HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,
705 HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
713 static EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
714 UI_METHOD *ui_method, void *callback_data)
716 #ifndef OPENSSL_NO_RSA
719 EVP_PKEY *res = NULL;
720 #ifndef OPENSSL_NO_RSA
721 HWCryptoHook_MPI e, n;
722 HWCryptoHook_RSAKeyHandle *hptr;
724 #if !defined(OPENSSL_NO_RSA)
726 HWCryptoHook_ErrMsgBuf rmsg;
728 HWCryptoHook_PassphraseContext ppctx;
730 #if !defined(OPENSSL_NO_RSA)
732 rmsg.size = sizeof(tempbuf);
737 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
738 HWCRHK_R_NOT_INITIALISED);
741 #ifndef OPENSSL_NO_RSA
742 hptr = OPENSSL_malloc(sizeof(HWCryptoHook_RSAKeyHandle));
745 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
746 ERR_R_MALLOC_FAILURE);
749 ppctx.ui_method = ui_method;
750 ppctx.callback_data = callback_data;
751 if (p_hwcrhk_RSALoadKey(hwcrhk_context, key_id, hptr,
754 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
755 HWCRHK_R_CHIL_ERROR);
756 ERR_add_error_data(1,rmsg.buf);
761 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
766 #ifndef OPENSSL_NO_RSA
767 rtmp = RSA_new_method(eng);
768 RSA_set_ex_data(rtmp, hndidx_rsa, (char *)hptr);
771 rtmp->flags |= RSA_FLAG_EXT_PKEY;
774 if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg)
775 != HWCRYPTOHOOK_ERROR_MPISIZE)
777 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,HWCRHK_R_CHIL_ERROR);
778 ERR_add_error_data(1,rmsg.buf);
782 bn_expand2(rtmp->e, e.size/sizeof(BN_ULONG));
783 bn_expand2(rtmp->n, n.size/sizeof(BN_ULONG));
787 if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg))
789 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
790 HWCRHK_R_CHIL_ERROR);
791 ERR_add_error_data(1,rmsg.buf);
794 rtmp->e->top = e.size / sizeof(BN_ULONG);
796 rtmp->n->top = n.size / sizeof(BN_ULONG);
799 res = EVP_PKEY_new();
800 EVP_PKEY_assign_RSA(res, rtmp);
804 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
805 HWCRHK_R_PRIVATE_KEY_ALGORITHMS_DISABLED);
811 #ifndef OPENSSL_NO_RSA
818 static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
819 UI_METHOD *ui_method, void *callback_data)
821 EVP_PKEY *res = NULL;
823 #ifndef OPENSSL_NO_RSA
824 res = hwcrhk_load_privkey(eng, key_id,
825 ui_method, callback_data);
831 #ifndef OPENSSL_NO_RSA
836 CRYPTO_w_lock(CRYPTO_LOCK_EVP_PKEY);
838 res->pkey.rsa = RSA_new();
839 res->pkey.rsa->n = rsa->n;
840 res->pkey.rsa->e = rsa->e;
843 CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY);
849 HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
850 HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
861 /* A little mod_exp */
862 static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
863 const BIGNUM *m, BN_CTX *ctx)
866 HWCryptoHook_ErrMsgBuf rmsg;
867 /* Since HWCryptoHook_MPI is pretty compatible with BIGNUM's,
868 we use them directly, plus a little macro magic. We only
869 thing we need to make sure of is that enough space is allocated. */
870 HWCryptoHook_MPI m_a, m_p, m_n, m_r;
873 to_return = 0; /* expect failure */
875 rmsg.size = sizeof(tempbuf);
879 HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_NOT_INITIALISED);
882 /* Prepare the params */
883 bn_expand2(r, m->top); /* Check for error !! */
889 /* Perform the operation */
890 ret = p_hwcrhk_ModExp(hwcrhk_context, m_a, m_p, m_n, &m_r, &rmsg);
892 /* Convert the response */
893 r->top = m_r.size / sizeof(BN_ULONG);
898 /* FIXME: When this error is returned, HWCryptoHook is
899 telling us that falling back to software computation
900 might be a good thing. */
901 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
903 HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_REQUEST_FALLBACK);
907 HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_REQUEST_FAILED);
909 ERR_add_error_data(1,rmsg.buf);
918 #ifndef OPENSSL_NO_RSA
919 static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa)
922 HWCryptoHook_ErrMsgBuf rmsg;
923 HWCryptoHook_RSAKeyHandle *hptr;
924 int to_return = 0, ret;
927 rmsg.size = sizeof(tempbuf);
931 HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP,HWCRHK_R_NOT_INITIALISED);
935 /* This provides support for nForce keys. Since that's opaque data
936 all we do is provide a handle to the proper key and let HWCryptoHook
937 take care of the rest. */
938 if ((hptr = (HWCryptoHook_RSAKeyHandle *) RSA_get_ex_data(rsa, hndidx_rsa))
941 HWCryptoHook_MPI m_a, m_r;
945 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
946 HWCRHK_R_MISSING_KEY_COMPONENTS);
950 /* Prepare the params */
951 bn_expand2(r, rsa->n->top); /* Check for error !! */
955 /* Perform the operation */
956 ret = p_hwcrhk_RSA(m_a, *hptr, &m_r, &rmsg);
958 /* Convert the response */
959 r->top = m_r.size / sizeof(BN_ULONG);
964 /* FIXME: When this error is returned, HWCryptoHook is
965 telling us that falling back to software computation
966 might be a good thing. */
967 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
969 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
970 HWCRHK_R_REQUEST_FALLBACK);
974 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
975 HWCRHK_R_REQUEST_FAILED);
977 ERR_add_error_data(1,rmsg.buf);
983 HWCryptoHook_MPI m_a, m_p, m_q, m_dmp1, m_dmq1, m_iqmp, m_r;
985 if(!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp)
987 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
988 HWCRHK_R_MISSING_KEY_COMPONENTS);
992 /* Prepare the params */
993 bn_expand2(r, rsa->n->top); /* Check for error !! */
997 BN2MPI(m_dmp1, rsa->dmp1);
998 BN2MPI(m_dmq1, rsa->dmq1);
999 BN2MPI(m_iqmp, rsa->iqmp);
1002 /* Perform the operation */
1003 ret = p_hwcrhk_ModExpCRT(hwcrhk_context, m_a, m_p, m_q,
1004 m_dmp1, m_dmq1, m_iqmp, &m_r, NULL);
1006 /* Convert the response */
1007 r->top = m_r.size / sizeof(BN_ULONG);
1012 /* FIXME: When this error is returned, HWCryptoHook is
1013 telling us that falling back to software computation
1014 might be a good thing. */
1015 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1017 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1018 HWCRHK_R_REQUEST_FALLBACK);
1022 HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1023 HWCRHK_R_REQUEST_FAILED);
1025 ERR_add_error_data(1,rmsg.buf);
1029 /* If we're here, we must be here with some semblance of success :-) */
1036 /* This function is aliased to mod_exp (with the mont stuff dropped). */
1037 static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
1038 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1040 return hwcrhk_mod_exp(r, a, p, m, ctx);
1043 /* This function is aliased to mod_exp (with the dh and mont dropped). */
1044 static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r,
1045 const BIGNUM *a, const BIGNUM *p,
1046 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1048 return hwcrhk_mod_exp(r, a, p, m, ctx);
1051 /* Random bytes are good */
1052 static int hwcrhk_rand_bytes(unsigned char *buf, int num)
1055 HWCryptoHook_ErrMsgBuf rmsg;
1056 int to_return = 0; /* assume failure */
1060 rmsg.size = sizeof(tempbuf);
1064 HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,HWCRHK_R_NOT_INITIALISED);
1068 ret = p_hwcrhk_RandomBytes(hwcrhk_context, buf, num, &rmsg);
1071 /* FIXME: When this error is returned, HWCryptoHook is
1072 telling us that falling back to software computation
1073 might be a good thing. */
1074 if(ret == HWCRYPTOHOOK_ERROR_FALLBACK)
1076 HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,
1077 HWCRHK_R_REQUEST_FALLBACK);
1081 HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES,
1082 HWCRHK_R_REQUEST_FAILED);
1084 ERR_add_error_data(1,rmsg.buf);
1092 static int hwcrhk_rand_status(void)
1097 /* This cleans up an RSA KM key, called when ex_data is freed */
1099 static void hwcrhk_ex_free(void *obj, void *item, CRYPTO_EX_DATA *ad,
1100 int ind,long argl, void *argp)
1103 HWCryptoHook_ErrMsgBuf rmsg;
1104 #ifndef OPENSSL_NO_RSA
1105 HWCryptoHook_RSAKeyHandle *hptr;
1107 #if !defined(OPENSSL_NO_RSA)
1112 rmsg.size = sizeof(tempbuf);
1114 #ifndef OPENSSL_NO_RSA
1115 hptr = (HWCryptoHook_RSAKeyHandle *) item;
1118 ret = p_hwcrhk_RSAUnloadKey(*hptr, NULL);
1124 /* Mutex calls: since the HWCryptoHook model closely follows the POSIX model
1125 * these just wrap the POSIX functions and add some logging.
1128 static int hwcrhk_mutex_init(HWCryptoHook_Mutex* mt,
1129 HWCryptoHook_CallerContext *cactx)
1131 mt->lockid = CRYPTO_get_new_dynlockid();
1132 if (mt->lockid == 0)
1133 return 1; /* failure */
1134 return 0; /* success */
1137 static int hwcrhk_mutex_lock(HWCryptoHook_Mutex *mt)
1139 CRYPTO_w_lock(mt->lockid);
1143 static void hwcrhk_mutex_unlock(HWCryptoHook_Mutex * mt)
1145 CRYPTO_w_unlock(mt->lockid);
1148 static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex *mt)
1150 CRYPTO_destroy_dynlockid(mt->lockid);
1153 static int hwcrhk_get_pass(const char *prompt_info,
1154 int *len_io, char *buf,
1155 HWCryptoHook_PassphraseContext *ppctx,
1156 HWCryptoHook_CallerContext *cactx)
1158 pem_password_cb *callback = NULL;
1159 void *callback_data = NULL;
1160 UI_METHOD *ui_method = NULL;
1164 if (cactx->ui_method)
1165 ui_method = cactx->ui_method;
1166 if (cactx->password_callback)
1167 callback = cactx->password_callback;
1168 if (cactx->callback_data)
1169 callback_data = cactx->callback_data;
1173 if (ppctx->ui_method)
1175 ui_method = ppctx->ui_method;
1178 if (ppctx->callback_data)
1179 callback_data = ppctx->callback_data;
1181 if (callback == NULL && ui_method == NULL)
1183 HWCRHKerr(HWCRHK_F_HWCRHK_GET_PASS,HWCRHK_R_NO_CALLBACK);
1189 UI *ui = UI_new_method(ui_method);
1193 char *prompt = UI_construct_prompt(ui,
1194 "pass phrase", prompt_info);
1196 ok = UI_add_input_string(ui,prompt,
1197 UI_INPUT_FLAG_DEFAULT_PWD,
1198 buf,0,(*len_io) - 1);
1199 UI_add_user_data(ui, callback_data);
1200 UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0);
1207 while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0));
1210 *len_io = strlen(buf);
1213 OPENSSL_free(prompt);
1218 *len_io = callback(buf, *len_io, 0, callback_data);
1225 static int hwcrhk_insert_card(const char *prompt_info,
1226 const char *wrong_info,
1227 HWCryptoHook_PassphraseContext *ppctx,
1228 HWCryptoHook_CallerContext *cactx)
1232 void *callback_data = NULL;
1233 UI_METHOD *ui_method = NULL;
1237 if (cactx->ui_method)
1238 ui_method = cactx->ui_method;
1239 if (cactx->callback_data)
1240 callback_data = cactx->callback_data;
1244 if (ppctx->ui_method)
1245 ui_method = ppctx->ui_method;
1246 if (ppctx->callback_data)
1247 callback_data = ppctx->callback_data;
1249 if (ui_method == NULL)
1251 HWCRHKerr(HWCRHK_F_HWCRHK_INSERT_CARD,
1252 HWCRHK_R_NO_CALLBACK);
1256 ui = UI_new_method(ui_method);
1264 BIO_snprintf(buf, sizeof(buf)-1,
1265 "Current card: \"%s\"\n", wrong_info);
1266 ok = UI_dup_info_string(ui, buf);
1267 if (ok >= 0 && prompt_info)
1269 BIO_snprintf(buf, sizeof(buf)-1,
1270 "Insert card \"%s\"", prompt_info);
1271 ok = UI_dup_input_boolean(ui, buf,
1272 "\n then hit <enter> or C<enter> to cancel\n",
1273 "\r\n", "Cc", UI_INPUT_FLAG_ECHO, &answer);
1275 UI_add_user_data(ui, callback_data);
1278 ok = UI_process(ui);
1281 if (ok == -2 || (ok >= 0 && answer == 'C'))
1291 static void hwcrhk_log_message(void *logstr, const char *message)
1293 BIO *lstream = NULL;
1295 CRYPTO_w_lock(CRYPTO_LOCK_BIO);
1297 lstream=*(BIO **)logstr;
1300 BIO_write(lstream, message, strlen(message));
1302 CRYPTO_w_unlock(CRYPTO_LOCK_BIO);
1305 /* This stuff is needed if this ENGINE is being compiled into a self-contained
1306 * shared-library. */
1307 #ifdef ENGINE_DYNAMIC_SUPPORT
1308 static int bind_fn(ENGINE *e, const char *id)
1310 if(id && (strcmp(id, engine_hwcrhk_id) != 0))
1316 IMPLEMENT_DYNAMIC_CHECK_FN()
1317 IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
1318 #endif /* ENGINE_DYNAMIC_SUPPORT */
1320 #endif /* !OPENSSL_NO_HW_NCIPHER */
1321 #endif /* !OPENSSL_NO_HW */