e_chil.c revision 296341
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    EVP_PKEY_assign_RSA(res, rtmp);
843#  endif
844
845    if (!res)
846        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
847                  HWCRHK_R_PRIVATE_KEY_ALGORITHMS_DISABLED);
848
849    return res;
850 err:
851#  ifndef OPENSSL_NO_RSA
852    if (rtmp)
853        RSA_free(rtmp);
854#  endif
855    return NULL;
856}
857
858static EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
859                                    UI_METHOD *ui_method, void *callback_data)
860{
861    EVP_PKEY *res = NULL;
862
863#  ifndef OPENSSL_NO_RSA
864    res = hwcrhk_load_privkey(eng, key_id, ui_method, callback_data);
865#  endif
866
867    if (res)
868        switch (res->type) {
869#  ifndef OPENSSL_NO_RSA
870        case EVP_PKEY_RSA:
871            {
872                RSA *rsa = NULL;
873
874                CRYPTO_w_lock(CRYPTO_LOCK_EVP_PKEY);
875                rsa = res->pkey.rsa;
876                res->pkey.rsa = RSA_new();
877                res->pkey.rsa->n = rsa->n;
878                res->pkey.rsa->e = rsa->e;
879                rsa->n = NULL;
880                rsa->e = NULL;
881                CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY);
882                RSA_free(rsa);
883            }
884            break;
885#  endif
886        default:
887            HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
888                      HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
889            goto err;
890        }
891
892    return res;
893 err:
894    if (res)
895        EVP_PKEY_free(res);
896    return NULL;
897}
898
899/* A little mod_exp */
900static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
901                          const BIGNUM *m, BN_CTX *ctx)
902{
903    char tempbuf[1024];
904    HWCryptoHook_ErrMsgBuf rmsg;
905    /*
906     * Since HWCryptoHook_MPI is pretty compatible with BIGNUM's, we use them
907     * directly, plus a little macro magic.  We only thing we need to make
908     * sure of is that enough space is allocated.
909     */
910    HWCryptoHook_MPI m_a, m_p, m_n, m_r;
911    int to_return, ret;
912
913    to_return = 0;              /* expect failure */
914    rmsg.buf = tempbuf;
915    rmsg.size = sizeof(tempbuf);
916
917    if (!hwcrhk_context) {
918        HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP, HWCRHK_R_NOT_INITIALISED);
919        goto err;
920    }
921    /* Prepare the params */
922    bn_expand2(r, m->top);      /* Check for error !! */
923    BN2MPI(m_a, a);
924    BN2MPI(m_p, p);
925    BN2MPI(m_n, m);
926    MPI2BN(r, m_r);
927
928    /* Perform the operation */
929    ret = p_hwcrhk_ModExp(hwcrhk_context, m_a, m_p, m_n, &m_r, &rmsg);
930
931    /* Convert the response */
932    r->top = m_r.size / sizeof(BN_ULONG);
933    bn_fix_top(r);
934
935    if (ret < 0) {
936        /*
937         * FIXME: When this error is returned, HWCryptoHook is telling us
938         * that falling back to software computation might be a good thing.
939         */
940        if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) {
941            HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP, HWCRHK_R_REQUEST_FALLBACK);
942        } else {
943            HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP, HWCRHK_R_REQUEST_FAILED);
944        }
945        ERR_add_error_data(1, rmsg.buf);
946        goto err;
947    }
948
949    to_return = 1;
950 err:
951    return to_return;
952}
953
954#  ifndef OPENSSL_NO_RSA
955static int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa,
956                              BN_CTX *ctx)
957{
958    char tempbuf[1024];
959    HWCryptoHook_ErrMsgBuf rmsg;
960    HWCryptoHook_RSAKeyHandle *hptr;
961    int to_return = 0, ret;
962
963    rmsg.buf = tempbuf;
964    rmsg.size = sizeof(tempbuf);
965
966    if (!hwcrhk_context) {
967        HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, HWCRHK_R_NOT_INITIALISED);
968        goto err;
969    }
970
971    /*
972     * This provides support for nForce keys.  Since that's opaque data all
973     * we do is provide a handle to the proper key and let HWCryptoHook take
974     * care of the rest.
975     */
976    if ((hptr =
977         (HWCryptoHook_RSAKeyHandle *) RSA_get_ex_data(rsa, hndidx_rsa))
978        != NULL) {
979        HWCryptoHook_MPI m_a, m_r;
980
981        if (!rsa->n) {
982            HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
983                      HWCRHK_R_MISSING_KEY_COMPONENTS);
984            goto err;
985        }
986
987        /* Prepare the params */
988        bn_expand2(r, rsa->n->top); /* Check for error !! */
989        BN2MPI(m_a, I);
990        MPI2BN(r, m_r);
991
992        /* Perform the operation */
993        ret = p_hwcrhk_RSA(m_a, *hptr, &m_r, &rmsg);
994
995        /* Convert the response */
996        r->top = m_r.size / sizeof(BN_ULONG);
997        bn_fix_top(r);
998
999        if (ret < 0) {
1000            /*
1001             * FIXME: When this error is returned, HWCryptoHook is telling us
1002             * that falling back to software computation might be a good
1003             * thing.
1004             */
1005            if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) {
1006                HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1007                          HWCRHK_R_REQUEST_FALLBACK);
1008            } else {
1009                HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1010                          HWCRHK_R_REQUEST_FAILED);
1011            }
1012            ERR_add_error_data(1, rmsg.buf);
1013            goto err;
1014        }
1015    } else {
1016        HWCryptoHook_MPI m_a, m_p, m_q, m_dmp1, m_dmq1, m_iqmp, m_r;
1017
1018        if (!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp) {
1019            HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1020                      HWCRHK_R_MISSING_KEY_COMPONENTS);
1021            goto err;
1022        }
1023
1024        /* Prepare the params */
1025        bn_expand2(r, rsa->n->top); /* Check for error !! */
1026        BN2MPI(m_a, I);
1027        BN2MPI(m_p, rsa->p);
1028        BN2MPI(m_q, rsa->q);
1029        BN2MPI(m_dmp1, rsa->dmp1);
1030        BN2MPI(m_dmq1, rsa->dmq1);
1031        BN2MPI(m_iqmp, rsa->iqmp);
1032        MPI2BN(r, m_r);
1033
1034        /* Perform the operation */
1035        ret = p_hwcrhk_ModExpCRT(hwcrhk_context, m_a, m_p, m_q,
1036                                 m_dmp1, m_dmq1, m_iqmp, &m_r, &rmsg);
1037
1038        /* Convert the response */
1039        r->top = m_r.size / sizeof(BN_ULONG);
1040        bn_fix_top(r);
1041
1042        if (ret < 0) {
1043            /*
1044             * FIXME: When this error is returned, HWCryptoHook is telling us
1045             * that falling back to software computation might be a good
1046             * thing.
1047             */
1048            if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) {
1049                HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1050                          HWCRHK_R_REQUEST_FALLBACK);
1051            } else {
1052                HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1053                          HWCRHK_R_REQUEST_FAILED);
1054            }
1055            ERR_add_error_data(1, rmsg.buf);
1056            goto err;
1057        }
1058    }
1059    /*
1060     * If we're here, we must be here with some semblance of success :-)
1061     */
1062    to_return = 1;
1063 err:
1064    return to_return;
1065}
1066#  endif
1067
1068#  ifndef OPENSSL_NO_RSA
1069/* This function is aliased to mod_exp (with the mont stuff dropped). */
1070static int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
1071                               const BIGNUM *m, BN_CTX *ctx,
1072                               BN_MONT_CTX *m_ctx)
1073{
1074    return hwcrhk_mod_exp(r, a, p, m, ctx);
1075}
1076
1077static int hwcrhk_rsa_finish(RSA *rsa)
1078{
1079    HWCryptoHook_RSAKeyHandle *hptr;
1080
1081    hptr = RSA_get_ex_data(rsa, hndidx_rsa);
1082    if (hptr) {
1083        p_hwcrhk_RSAUnloadKey(*hptr, NULL);
1084        OPENSSL_free(hptr);
1085        RSA_set_ex_data(rsa, hndidx_rsa, NULL);
1086    }
1087    return 1;
1088}
1089
1090#  endif
1091
1092#  ifndef OPENSSL_NO_DH
1093/* This function is aliased to mod_exp (with the dh and mont dropped). */
1094static int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r,
1095                             const BIGNUM *a, const BIGNUM *p,
1096                             const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1097{
1098    return hwcrhk_mod_exp(r, a, p, m, ctx);
1099}
1100#  endif
1101
1102/* Random bytes are good */
1103static int hwcrhk_rand_bytes(unsigned char *buf, int num)
1104{
1105    char tempbuf[1024];
1106    HWCryptoHook_ErrMsgBuf rmsg;
1107    int to_return = 0;          /* assume failure */
1108    int ret;
1109
1110    rmsg.buf = tempbuf;
1111    rmsg.size = sizeof(tempbuf);
1112
1113    if (!hwcrhk_context) {
1114        HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES, HWCRHK_R_NOT_INITIALISED);
1115        goto err;
1116    }
1117
1118    ret = p_hwcrhk_RandomBytes(hwcrhk_context, buf, num, &rmsg);
1119    if (ret < 0) {
1120        /*
1121         * FIXME: When this error is returned, HWCryptoHook is telling us
1122         * that falling back to software computation might be a good thing.
1123         */
1124        if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) {
1125            HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES, HWCRHK_R_REQUEST_FALLBACK);
1126        } else {
1127            HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES, HWCRHK_R_REQUEST_FAILED);
1128        }
1129        ERR_add_error_data(1, rmsg.buf);
1130        goto err;
1131    }
1132    to_return = 1;
1133 err:
1134    return to_return;
1135}
1136
1137static int hwcrhk_rand_status(void)
1138{
1139    return 1;
1140}
1141
1142/*
1143 * Mutex calls: since the HWCryptoHook model closely follows the POSIX model
1144 * these just wrap the POSIX functions and add some logging.
1145 */
1146
1147static int hwcrhk_mutex_init(HWCryptoHook_Mutex * mt,
1148                             HWCryptoHook_CallerContext * cactx)
1149{
1150    mt->lockid = CRYPTO_get_new_dynlockid();
1151    if (mt->lockid == 0)
1152        return 1;               /* failure */
1153    return 0;                   /* success */
1154}
1155
1156static int hwcrhk_mutex_lock(HWCryptoHook_Mutex * mt)
1157{
1158    CRYPTO_w_lock(mt->lockid);
1159    return 0;
1160}
1161
1162static void hwcrhk_mutex_unlock(HWCryptoHook_Mutex * mt)
1163{
1164    CRYPTO_w_unlock(mt->lockid);
1165}
1166
1167static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex * mt)
1168{
1169    CRYPTO_destroy_dynlockid(mt->lockid);
1170}
1171
1172static int hwcrhk_get_pass(const char *prompt_info,
1173                           int *len_io, char *buf,
1174                           HWCryptoHook_PassphraseContext * ppctx,
1175                           HWCryptoHook_CallerContext * cactx)
1176{
1177    pem_password_cb *callback = NULL;
1178    void *callback_data = NULL;
1179    UI_METHOD *ui_method = NULL;
1180    /*
1181     * Despite what the documentation says prompt_info can be an empty
1182     * string.
1183     */
1184    if (prompt_info && !*prompt_info)
1185        prompt_info = NULL;
1186
1187    if (cactx) {
1188        if (cactx->ui_method)
1189            ui_method = cactx->ui_method;
1190        if (cactx->password_callback)
1191            callback = cactx->password_callback;
1192        if (cactx->callback_data)
1193            callback_data = cactx->callback_data;
1194    }
1195    if (ppctx) {
1196        if (ppctx->ui_method) {
1197            ui_method = ppctx->ui_method;
1198            callback = NULL;
1199        }
1200        if (ppctx->callback_data)
1201            callback_data = ppctx->callback_data;
1202    }
1203    if (callback == NULL && ui_method == NULL) {
1204        HWCRHKerr(HWCRHK_F_HWCRHK_GET_PASS, HWCRHK_R_NO_CALLBACK);
1205        return -1;
1206    }
1207
1208    if (ui_method) {
1209        UI *ui = UI_new_method(ui_method);
1210        if (ui) {
1211            int ok;
1212            char *prompt = UI_construct_prompt(ui,
1213                                               "pass phrase", prompt_info);
1214
1215            ok = UI_add_input_string(ui, prompt,
1216                                     UI_INPUT_FLAG_DEFAULT_PWD,
1217                                     buf, 0, (*len_io) - 1);
1218            UI_add_user_data(ui, callback_data);
1219            UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0);
1220
1221            if (ok >= 0)
1222                do {
1223                    ok = UI_process(ui);
1224                }
1225                while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0));
1226
1227            if (ok >= 0)
1228                *len_io = strlen(buf);
1229
1230            UI_free(ui);
1231            OPENSSL_free(prompt);
1232        }
1233    } else {
1234        *len_io = callback(buf, *len_io, 0, callback_data);
1235    }
1236    if (!*len_io)
1237        return -1;
1238    return 0;
1239}
1240
1241static int hwcrhk_insert_card(const char *prompt_info,
1242                              const char *wrong_info,
1243                              HWCryptoHook_PassphraseContext * ppctx,
1244                              HWCryptoHook_CallerContext * cactx)
1245{
1246    int ok = -1;
1247    UI *ui;
1248    void *callback_data = NULL;
1249    UI_METHOD *ui_method = NULL;
1250
1251    if (cactx) {
1252        if (cactx->ui_method)
1253            ui_method = cactx->ui_method;
1254        if (cactx->callback_data)
1255            callback_data = cactx->callback_data;
1256    }
1257    if (ppctx) {
1258        if (ppctx->ui_method)
1259            ui_method = ppctx->ui_method;
1260        if (ppctx->callback_data)
1261            callback_data = ppctx->callback_data;
1262    }
1263    if (ui_method == NULL) {
1264        HWCRHKerr(HWCRHK_F_HWCRHK_INSERT_CARD, HWCRHK_R_NO_CALLBACK);
1265        return -1;
1266    }
1267
1268    ui = UI_new_method(ui_method);
1269
1270    if (ui) {
1271        char answer;
1272        char buf[BUFSIZ];
1273        /*
1274         * Despite what the documentation says wrong_info can be an empty
1275         * string.
1276         */
1277        if (wrong_info && *wrong_info)
1278            BIO_snprintf(buf, sizeof(buf) - 1,
1279                         "Current card: \"%s\"\n", wrong_info);
1280        else
1281            buf[0] = 0;
1282        ok = UI_dup_info_string(ui, buf);
1283        if (ok >= 0 && prompt_info) {
1284            BIO_snprintf(buf, sizeof(buf) - 1,
1285                         "Insert card \"%s\"", prompt_info);
1286            ok = UI_dup_input_boolean(ui, buf,
1287                                      "\n then hit <enter> or C<enter> to cancel\n",
1288                                      "\r\n", "Cc", UI_INPUT_FLAG_ECHO,
1289                                      &answer);
1290        }
1291        UI_add_user_data(ui, callback_data);
1292
1293        if (ok >= 0)
1294            ok = UI_process(ui);
1295        UI_free(ui);
1296
1297        if (ok == -2 || (ok >= 0 && answer == 'C'))
1298            ok = 1;
1299        else if (ok < 0)
1300            ok = -1;
1301        else
1302            ok = 0;
1303    }
1304    return ok;
1305}
1306
1307static void hwcrhk_log_message(void *logstr, const char *message)
1308{
1309    BIO *lstream = NULL;
1310
1311    CRYPTO_w_lock(CRYPTO_LOCK_BIO);
1312    if (logstr)
1313        lstream = *(BIO **)logstr;
1314    if (lstream) {
1315        BIO_printf(lstream, "%s\n", message);
1316    }
1317    CRYPTO_w_unlock(CRYPTO_LOCK_BIO);
1318}
1319
1320/*
1321 * This stuff is needed if this ENGINE is being compiled into a
1322 * self-contained shared-library.
1323 */
1324#  ifndef OPENSSL_NO_DYNAMIC_ENGINE
1325static int bind_fn(ENGINE *e, const char *id)
1326{
1327    if (id && (strcmp(id, engine_hwcrhk_id) != 0) &&
1328        (strcmp(id, engine_hwcrhk_id_alt) != 0))
1329        return 0;
1330    if (!bind_helper(e))
1331        return 0;
1332    return 1;
1333}
1334
1335IMPLEMENT_DYNAMIC_CHECK_FN()
1336    IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
1337#  endif                        /* OPENSSL_NO_DYNAMIC_ENGINE */
1338# endif                         /* !OPENSSL_NO_HW_CHIL */
1339#endif                          /* !OPENSSL_NO_HW */
1340