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