1160814Ssimon/* crypto/engine/e_chil.c -*- mode: C; c-file-style: "eay" -*- */
2296465Sdelphij/*
3296465Sdelphij * Written by Richard Levitte (richard@levitte.org), Geoff Thorpe
4296465Sdelphij * (geoff@geoffthorpe.net) and Dr Stephen N Henson (steve@openssl.org) for
5296465Sdelphij * the OpenSSL project 2000.
6160814Ssimon */
7160814Ssimon/* ====================================================================
8160814Ssimon * Copyright (c) 1999-2001 The OpenSSL Project.  All rights reserved.
9160814Ssimon *
10160814Ssimon * Redistribution and use in source and binary forms, with or without
11160814Ssimon * modification, are permitted provided that the following conditions
12160814Ssimon * are met:
13160814Ssimon *
14160814Ssimon * 1. Redistributions of source code must retain the above copyright
15296465Sdelphij *    notice, this list of conditions and the following disclaimer.
16160814Ssimon *
17160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright
18160814Ssimon *    notice, this list of conditions and the following disclaimer in
19160814Ssimon *    the documentation and/or other materials provided with the
20160814Ssimon *    distribution.
21160814Ssimon *
22160814Ssimon * 3. All advertising materials mentioning features or use of this
23160814Ssimon *    software must display the following acknowledgment:
24160814Ssimon *    "This product includes software developed by the OpenSSL Project
25160814Ssimon *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
26160814Ssimon *
27160814Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
28160814Ssimon *    endorse or promote products derived from this software without
29160814Ssimon *    prior written permission. For written permission, please contact
30160814Ssimon *    licensing@OpenSSL.org.
31160814Ssimon *
32160814Ssimon * 5. Products derived from this software may not be called "OpenSSL"
33160814Ssimon *    nor may "OpenSSL" appear in their names without prior written
34160814Ssimon *    permission of the OpenSSL Project.
35160814Ssimon *
36160814Ssimon * 6. Redistributions of any form whatsoever must retain the following
37160814Ssimon *    acknowledgment:
38160814Ssimon *    "This product includes software developed by the OpenSSL Project
39160814Ssimon *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
40160814Ssimon *
41160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
42160814Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43160814Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
44160814Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
45160814Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46160814Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47160814Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
48160814Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49160814Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
50160814Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51160814Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
52160814Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
53160814Ssimon * ====================================================================
54160814Ssimon *
55160814Ssimon * This product includes cryptographic software written by Eric Young
56160814Ssimon * (eay@cryptsoft.com).  This product includes software written by Tim
57160814Ssimon * Hudson (tjh@cryptsoft.com).
58160814Ssimon *
59160814Ssimon */
60160814Ssimon
61160814Ssimon#include <stdio.h>
62160814Ssimon#include <string.h>
63160814Ssimon#include <openssl/crypto.h>
64160814Ssimon#include <openssl/pem.h>
65160814Ssimon#include <openssl/dso.h>
66160814Ssimon#include <openssl/engine.h>
67160814Ssimon#include <openssl/ui.h>
68160814Ssimon#include <openssl/rand.h>
69160814Ssimon#ifndef OPENSSL_NO_RSA
70296465Sdelphij# include <openssl/rsa.h>
71160814Ssimon#endif
72160814Ssimon#ifndef OPENSSL_NO_DH
73296465Sdelphij# include <openssl/dh.h>
74160814Ssimon#endif
75160814Ssimon#include <openssl/bn.h>
76160814Ssimon
77160814Ssimon#ifndef OPENSSL_NO_HW
78296465Sdelphij# ifndef OPENSSL_NO_HW_CHIL
79160814Ssimon
80296465Sdelphij/*-
81296465Sdelphij * Attribution notice: nCipher have said several times that it's OK for
82160814Ssimon * us to implement a general interface to their boxes, and recently declared
83160814Ssimon * their HWCryptoHook to be public, and therefore available for us to use.
84160814Ssimon * Thanks, nCipher.
85160814Ssimon *
86160814Ssimon * The hwcryptohook.h included here is from May 2000.
87160814Ssimon * [Richard Levitte]
88160814Ssimon */
89296465Sdelphij#  ifdef FLAT_INC
90296465Sdelphij#   include "hwcryptohook.h"
91296465Sdelphij#  else
92296465Sdelphij#   include "vendor_defns/hwcryptohook.h"
93296465Sdelphij#  endif
94160814Ssimon
95296465Sdelphij#  define HWCRHK_LIB_NAME "CHIL engine"
96296465Sdelphij#  include "e_chil_err.c"
97160814Ssimon
98160814Ssimonstatic int hwcrhk_destroy(ENGINE *e);
99160814Ssimonstatic int hwcrhk_init(ENGINE *e);
100160814Ssimonstatic int hwcrhk_finish(ENGINE *e);
101296465Sdelphijstatic int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void));
102160814Ssimon
103160814Ssimon/* Functions to handle mutexes */
104296465Sdelphijstatic int hwcrhk_mutex_init(HWCryptoHook_Mutex *,
105296465Sdelphij                             HWCryptoHook_CallerContext *);
106296465Sdelphijstatic int hwcrhk_mutex_lock(HWCryptoHook_Mutex *);
107296465Sdelphijstatic void hwcrhk_mutex_unlock(HWCryptoHook_Mutex *);
108296465Sdelphijstatic void hwcrhk_mutex_destroy(HWCryptoHook_Mutex *);
109160814Ssimon
110160814Ssimon/* BIGNUM stuff */
111160814Ssimonstatic int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
112296465Sdelphij                          const BIGNUM *m, BN_CTX *ctx);
113160814Ssimon
114296465Sdelphij#  ifndef OPENSSL_NO_RSA
115160814Ssimon/* RSA stuff */
116296465Sdelphijstatic int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa,
117296465Sdelphij                              BN_CTX *ctx);
118160814Ssimon/* This function is aliased to mod_exp (with the mont stuff dropped). */
119160814Ssimonstatic int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
120296465Sdelphij                               const BIGNUM *m, BN_CTX *ctx,
121296465Sdelphij                               BN_MONT_CTX *m_ctx);
122215697Ssimonstatic int hwcrhk_rsa_finish(RSA *rsa);
123296465Sdelphij#  endif
124160814Ssimon
125296465Sdelphij#  ifndef OPENSSL_NO_DH
126160814Ssimon/* DH stuff */
127160814Ssimon/* This function is alised to mod_exp (with the DH and mont dropped). */
128160814Ssimonstatic int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r,
129296465Sdelphij                             const BIGNUM *a, const BIGNUM *p,
130296465Sdelphij                             const BIGNUM *m, BN_CTX *ctx,
131296465Sdelphij                             BN_MONT_CTX *m_ctx);
132296465Sdelphij#  endif
133160814Ssimon
134160814Ssimon/* RAND stuff */
135160814Ssimonstatic int hwcrhk_rand_bytes(unsigned char *buf, int num);
136160814Ssimonstatic int hwcrhk_rand_status(void);
137160814Ssimon
138160814Ssimon/* KM stuff */
139160814Ssimonstatic EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
140296465Sdelphij                                     UI_METHOD *ui_method,
141296465Sdelphij                                     void *callback_data);
142160814Ssimonstatic EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
143296465Sdelphij                                    UI_METHOD *ui_method,
144296465Sdelphij                                    void *callback_data);
145160814Ssimon
146160814Ssimon/* Interaction stuff */
147160814Ssimonstatic int hwcrhk_insert_card(const char *prompt_info,
148296465Sdelphij                              const char *wrong_info,
149296465Sdelphij                              HWCryptoHook_PassphraseContext * ppctx,
150296465Sdelphij                              HWCryptoHook_CallerContext * cactx);
151160814Ssimonstatic int hwcrhk_get_pass(const char *prompt_info,
152296465Sdelphij                           int *len_io, char *buf,
153296465Sdelphij                           HWCryptoHook_PassphraseContext * ppctx,
154296465Sdelphij                           HWCryptoHook_CallerContext * cactx);
155160814Ssimonstatic void hwcrhk_log_message(void *logstr, const char *message);
156160814Ssimon
157160814Ssimon/* The definitions for control commands specific to this engine */
158296465Sdelphij#  define HWCRHK_CMD_SO_PATH              ENGINE_CMD_BASE
159296465Sdelphij#  define HWCRHK_CMD_FORK_CHECK           (ENGINE_CMD_BASE + 1)
160296465Sdelphij#  define HWCRHK_CMD_THREAD_LOCKING       (ENGINE_CMD_BASE + 2)
161296465Sdelphij#  define HWCRHK_CMD_SET_USER_INTERFACE   (ENGINE_CMD_BASE + 3)
162296465Sdelphij#  define HWCRHK_CMD_SET_CALLBACK_DATA    (ENGINE_CMD_BASE + 4)
163160814Ssimonstatic const ENGINE_CMD_DEFN hwcrhk_cmd_defns[] = {
164296465Sdelphij    {HWCRHK_CMD_SO_PATH,
165296465Sdelphij     "SO_PATH",
166296465Sdelphij     "Specifies the path to the 'hwcrhk' shared library",
167296465Sdelphij     ENGINE_CMD_FLAG_STRING},
168296465Sdelphij    {HWCRHK_CMD_FORK_CHECK,
169296465Sdelphij     "FORK_CHECK",
170296465Sdelphij     "Turns fork() checking on (non-zero) or off (zero)",
171296465Sdelphij     ENGINE_CMD_FLAG_NUMERIC},
172296465Sdelphij    {HWCRHK_CMD_THREAD_LOCKING,
173296465Sdelphij     "THREAD_LOCKING",
174296465Sdelphij     "Turns thread-safe locking on (zero) or off (non-zero)",
175296465Sdelphij     ENGINE_CMD_FLAG_NUMERIC},
176296465Sdelphij    {HWCRHK_CMD_SET_USER_INTERFACE,
177296465Sdelphij     "SET_USER_INTERFACE",
178296465Sdelphij     "Set the global user interface (internal)",
179296465Sdelphij     ENGINE_CMD_FLAG_INTERNAL},
180296465Sdelphij    {HWCRHK_CMD_SET_CALLBACK_DATA,
181296465Sdelphij     "SET_CALLBACK_DATA",
182296465Sdelphij     "Set the global user interface extra data (internal)",
183296465Sdelphij     ENGINE_CMD_FLAG_INTERNAL},
184296465Sdelphij    {0, NULL, NULL, 0}
185296465Sdelphij};
186160814Ssimon
187296465Sdelphij#  ifndef OPENSSL_NO_RSA
188160814Ssimon/* Our internal RSA_METHOD that we provide pointers to */
189296465Sdelphijstatic RSA_METHOD hwcrhk_rsa = {
190296465Sdelphij    "CHIL RSA method",
191296465Sdelphij    NULL,
192296465Sdelphij    NULL,
193296465Sdelphij    NULL,
194296465Sdelphij    NULL,
195296465Sdelphij    hwcrhk_rsa_mod_exp,
196296465Sdelphij    hwcrhk_mod_exp_mont,
197296465Sdelphij    NULL,
198296465Sdelphij    hwcrhk_rsa_finish,
199296465Sdelphij    0,
200296465Sdelphij    NULL,
201296465Sdelphij    NULL,
202296465Sdelphij    NULL,
203296465Sdelphij    NULL
204296465Sdelphij};
205296465Sdelphij#  endif
206160814Ssimon
207296465Sdelphij#  ifndef OPENSSL_NO_DH
208160814Ssimon/* Our internal DH_METHOD that we provide pointers to */
209296465Sdelphijstatic DH_METHOD hwcrhk_dh = {
210296465Sdelphij    "CHIL DH method",
211296465Sdelphij    NULL,
212296465Sdelphij    NULL,
213296465Sdelphij    hwcrhk_mod_exp_dh,
214296465Sdelphij    NULL,
215296465Sdelphij    NULL,
216296465Sdelphij    0,
217296465Sdelphij    NULL,
218296465Sdelphij    NULL
219296465Sdelphij};
220296465Sdelphij#  endif
221160814Ssimon
222296465Sdelphijstatic RAND_METHOD hwcrhk_rand = {
223296465Sdelphij    /* "CHIL RAND method", */
224296465Sdelphij    NULL,
225296465Sdelphij    hwcrhk_rand_bytes,
226296465Sdelphij    NULL,
227296465Sdelphij    NULL,
228296465Sdelphij    hwcrhk_rand_bytes,
229296465Sdelphij    hwcrhk_rand_status,
230296465Sdelphij};
231160814Ssimon
232160814Ssimon/* Constants used when creating the ENGINE */
233160814Ssimonstatic const char *engine_hwcrhk_id = "chil";
234160814Ssimonstatic const char *engine_hwcrhk_name = "CHIL hardware engine support";
235160814Ssimon
236296465Sdelphij#  ifndef OPENSSL_NO_DYNAMIC_ENGINE
237160814Ssimon/* Compatibility hack, the dynamic library uses this form in the path */
238160814Ssimonstatic const char *engine_hwcrhk_id_alt = "ncipher";
239296465Sdelphij#  endif
240160814Ssimon
241160814Ssimon/* Internal stuff for HWCryptoHook */
242160814Ssimon
243160814Ssimon/* Some structures needed for proper use of thread locks */
244296465Sdelphij/*
245296465Sdelphij * hwcryptohook.h has some typedefs that turn struct HWCryptoHook_MutexValue
246296465Sdelphij * into HWCryptoHook_Mutex
247296465Sdelphij */
248296465Sdelphijstruct HWCryptoHook_MutexValue {
249296465Sdelphij    int lockid;
250296465Sdelphij};
251160814Ssimon
252296465Sdelphij/*
253296465Sdelphij * hwcryptohook.h has some typedefs that turn struct
254296465Sdelphij * HWCryptoHook_PassphraseContextValue into HWCryptoHook_PassphraseContext
255296465Sdelphij */
256296465Sdelphijstruct HWCryptoHook_PassphraseContextValue {
257296465Sdelphij    UI_METHOD *ui_method;
258296465Sdelphij    void *callback_data;
259296465Sdelphij};
260160814Ssimon
261296465Sdelphij/*
262296465Sdelphij * hwcryptohook.h has some typedefs that turn struct
263296465Sdelphij * HWCryptoHook_CallerContextValue into HWCryptoHook_CallerContext
264296465Sdelphij */
265296465Sdelphijstruct HWCryptoHook_CallerContextValue {
266296465Sdelphij    pem_password_cb *password_callback; /* Deprecated! Only present for
267296465Sdelphij                                         * backward compatibility! */
268296465Sdelphij    UI_METHOD *ui_method;
269296465Sdelphij    void *callback_data;
270296465Sdelphij};
271160814Ssimon
272296465Sdelphij/*
273296465Sdelphij * The MPI structure in HWCryptoHook is pretty compatible with OpenSSL
274296465Sdelphij * BIGNUM's, so lets define a couple of conversion macros
275296465Sdelphij */
276296465Sdelphij#  define BN2MPI(mp, bn) \
277160814Ssimon    {mp.size = bn->top * sizeof(BN_ULONG); mp.buf = (unsigned char *)bn->d;}
278296465Sdelphij#  define MPI2BN(bn, mp) \
279160814Ssimon    {mp.size = bn->dmax * sizeof(BN_ULONG); mp.buf = (unsigned char *)bn->d;}
280160814Ssimon
281160814Ssimonstatic BIO *logstream = NULL;
282160814Ssimonstatic int disable_mutex_callbacks = 0;
283160814Ssimon
284296465Sdelphij/*
285296465Sdelphij * One might wonder why these are needed, since one can pass down at least a
286296465Sdelphij * UI_METHOD and a pointer to callback data to the key-loading functions. The
287296465Sdelphij * thing is that the ModExp and RSAImmed functions can load keys as well, if
288296465Sdelphij * the data they get is in a special, nCipher-defined format (hint: if you
289296465Sdelphij * look at the private exponent of the RSA data as a string, you'll see this
290296465Sdelphij * string: "nCipher KM tool key id", followed by some bytes, followed a key
291296465Sdelphij * identity string, followed by more bytes.  This happens when you use
292296465Sdelphij * "embed" keys instead of "hwcrhk" keys).  Unfortunately, those functions do
293296465Sdelphij * not take any passphrase or caller context, and our functions can't really
294296465Sdelphij * take any callback data either.  Still, the "insert_card" and
295296465Sdelphij * "get_passphrase" callbacks may be called down the line, and will need to
296296465Sdelphij * know what user interface callbacks to call, and having callback data from
297296465Sdelphij * the application may be a nice thing as well, so we need to keep track of
298296465Sdelphij * that globally.
299296465Sdelphij */
300160814Ssimonstatic HWCryptoHook_CallerContext password_context = { NULL, NULL, NULL };
301160814Ssimon
302160814Ssimon/* Stuff to pass to the HWCryptoHook library */
303160814Ssimonstatic HWCryptoHook_InitInfo hwcrhk_globals = {
304296465Sdelphij    HWCryptoHook_InitFlags_SimpleForkCheck, /* Flags */
305296465Sdelphij    &logstream,                 /* logstream */
306296465Sdelphij    sizeof(BN_ULONG),           /* limbsize */
307296465Sdelphij    0,                          /* mslimb first: false for BNs */
308296465Sdelphij    -1,                         /* msbyte first: use native */
309296465Sdelphij    0,                          /* Max mutexes, 0 = no small limit */
310296465Sdelphij    0,                          /* Max simultaneous, 0 = default */
311160814Ssimon
312296465Sdelphij    /*
313296465Sdelphij     * The next few are mutex stuff: we write wrapper functions around the OS
314296465Sdelphij     * mutex functions.  We initialise them to 0 here, and change that to
315296465Sdelphij     * actual function pointers in hwcrhk_init() if dynamic locks are
316296465Sdelphij     * supported (that is, if the application programmer has made sure of
317296465Sdelphij     * setting up callbacks bafore starting this engine) *and* if
318296465Sdelphij     * disable_mutex_callbacks hasn't been set by a call to
319296465Sdelphij     * ENGINE_ctrl(ENGINE_CTRL_CHIL_NO_LOCKING).
320296465Sdelphij     */
321296465Sdelphij    sizeof(HWCryptoHook_Mutex),
322296465Sdelphij    0,
323296465Sdelphij    0,
324296465Sdelphij    0,
325296465Sdelphij    0,
326160814Ssimon
327296465Sdelphij    /*
328296465Sdelphij     * The next few are condvar stuff: we write wrapper functions round the
329296465Sdelphij     * OS functions.  Currently not implemented and not and absolute
330296465Sdelphij     * necessity even in threaded programs, therefore 0'ed.  Will hopefully
331296465Sdelphij     * be implemented some day, since it enhances the efficiency of
332296465Sdelphij     * HWCryptoHook.
333296465Sdelphij     */
334296465Sdelphij    0,                          /* sizeof(HWCryptoHook_CondVar), */
335296465Sdelphij    0,                          /* hwcrhk_cv_init, */
336296465Sdelphij    0,                          /* hwcrhk_cv_wait, */
337296465Sdelphij    0,                          /* hwcrhk_cv_signal, */
338296465Sdelphij    0,                          /* hwcrhk_cv_broadcast, */
339296465Sdelphij    0,                          /* hwcrhk_cv_destroy, */
340160814Ssimon
341296465Sdelphij    hwcrhk_get_pass,            /* pass phrase */
342296465Sdelphij    hwcrhk_insert_card,         /* insert a card */
343296465Sdelphij    hwcrhk_log_message          /* Log message */
344160814Ssimon};
345160814Ssimon
346160814Ssimon/* Now, to our own code */
347160814Ssimon
348296465Sdelphij/*
349296465Sdelphij * This internal function is used by ENGINE_chil() and possibly by the
350296465Sdelphij * "dynamic" ENGINE support too
351296465Sdelphij */
352160814Ssimonstatic int bind_helper(ENGINE *e)
353296465Sdelphij{
354296465Sdelphij#  ifndef OPENSSL_NO_RSA
355296465Sdelphij    const RSA_METHOD *meth1;
356296465Sdelphij#  endif
357296465Sdelphij#  ifndef OPENSSL_NO_DH
358296465Sdelphij    const DH_METHOD *meth2;
359296465Sdelphij#  endif
360296465Sdelphij    if (!ENGINE_set_id(e, engine_hwcrhk_id) ||
361296465Sdelphij        !ENGINE_set_name(e, engine_hwcrhk_name) ||
362296465Sdelphij#  ifndef OPENSSL_NO_RSA
363296465Sdelphij        !ENGINE_set_RSA(e, &hwcrhk_rsa) ||
364296465Sdelphij#  endif
365296465Sdelphij#  ifndef OPENSSL_NO_DH
366296465Sdelphij        !ENGINE_set_DH(e, &hwcrhk_dh) ||
367296465Sdelphij#  endif
368296465Sdelphij        !ENGINE_set_RAND(e, &hwcrhk_rand) ||
369296465Sdelphij        !ENGINE_set_destroy_function(e, hwcrhk_destroy) ||
370296465Sdelphij        !ENGINE_set_init_function(e, hwcrhk_init) ||
371296465Sdelphij        !ENGINE_set_finish_function(e, hwcrhk_finish) ||
372296465Sdelphij        !ENGINE_set_ctrl_function(e, hwcrhk_ctrl) ||
373296465Sdelphij        !ENGINE_set_load_privkey_function(e, hwcrhk_load_privkey) ||
374296465Sdelphij        !ENGINE_set_load_pubkey_function(e, hwcrhk_load_pubkey) ||
375296465Sdelphij        !ENGINE_set_cmd_defns(e, hwcrhk_cmd_defns))
376296465Sdelphij        return 0;
377160814Ssimon
378296465Sdelphij#  ifndef OPENSSL_NO_RSA
379296465Sdelphij    /*
380296465Sdelphij     * We know that the "PKCS1_SSLeay()" functions hook properly to the
381296465Sdelphij     * cswift-specific mod_exp and mod_exp_crt so we use those functions. NB:
382296465Sdelphij     * We don't use ENGINE_openssl() or anything "more generic" because
383296465Sdelphij     * something like the RSAref code may not hook properly, and if you own
384296465Sdelphij     * one of these cards then you have the right to do RSA operations on it
385296465Sdelphij     * anyway!
386296465Sdelphij     */
387296465Sdelphij    meth1 = RSA_PKCS1_SSLeay();
388296465Sdelphij    hwcrhk_rsa.rsa_pub_enc = meth1->rsa_pub_enc;
389296465Sdelphij    hwcrhk_rsa.rsa_pub_dec = meth1->rsa_pub_dec;
390296465Sdelphij    hwcrhk_rsa.rsa_priv_enc = meth1->rsa_priv_enc;
391296465Sdelphij    hwcrhk_rsa.rsa_priv_dec = meth1->rsa_priv_dec;
392296465Sdelphij#  endif
393160814Ssimon
394296465Sdelphij#  ifndef OPENSSL_NO_DH
395296465Sdelphij    /* Much the same for Diffie-Hellman */
396296465Sdelphij    meth2 = DH_OpenSSL();
397296465Sdelphij    hwcrhk_dh.generate_key = meth2->generate_key;
398296465Sdelphij    hwcrhk_dh.compute_key = meth2->compute_key;
399296465Sdelphij#  endif
400160814Ssimon
401296465Sdelphij    /* Ensure the hwcrhk error handling is set up */
402296465Sdelphij    ERR_load_HWCRHK_strings();
403296465Sdelphij    return 1;
404296465Sdelphij}
405160814Ssimon
406296465Sdelphij#  ifdef OPENSSL_NO_DYNAMIC_ENGINE
407160814Ssimonstatic ENGINE *engine_chil(void)
408296465Sdelphij{
409296465Sdelphij    ENGINE *ret = ENGINE_new();
410296465Sdelphij    if (!ret)
411296465Sdelphij        return NULL;
412296465Sdelphij    if (!bind_helper(ret)) {
413296465Sdelphij        ENGINE_free(ret);
414296465Sdelphij        return NULL;
415296465Sdelphij    }
416296465Sdelphij    return ret;
417296465Sdelphij}
418160814Ssimon
419160814Ssimonvoid ENGINE_load_chil(void)
420296465Sdelphij{
421296465Sdelphij    /* Copied from eng_[openssl|dyn].c */
422296465Sdelphij    ENGINE *toadd = engine_chil();
423296465Sdelphij    if (!toadd)
424296465Sdelphij        return;
425296465Sdelphij    ENGINE_add(toadd);
426296465Sdelphij    ENGINE_free(toadd);
427296465Sdelphij    ERR_clear_error();
428296465Sdelphij}
429296465Sdelphij#  endif
430160814Ssimon
431296465Sdelphij/*
432296465Sdelphij * This is a process-global DSO handle used for loading and unloading the
433296465Sdelphij * HWCryptoHook library. NB: This is only set (or unset) during an init() or
434296465Sdelphij * finish() call (reference counts permitting) and they're operating with
435296465Sdelphij * global locks, so this should be thread-safe implicitly.
436296465Sdelphij */
437160814Ssimonstatic DSO *hwcrhk_dso = NULL;
438160814Ssimonstatic HWCryptoHook_ContextHandle hwcrhk_context = 0;
439296465Sdelphij#  ifndef OPENSSL_NO_RSA
440296465Sdelphij/* Index for KM handle.  Not really used yet. */
441296465Sdelphijstatic int hndidx_rsa = -1;
442296465Sdelphij#  endif
443160814Ssimon
444296465Sdelphij/*
445296465Sdelphij * These are the function pointers that are (un)set when the library has
446296465Sdelphij * successfully (un)loaded.
447296465Sdelphij */
448160814Ssimonstatic HWCryptoHook_Init_t *p_hwcrhk_Init = NULL;
449160814Ssimonstatic HWCryptoHook_Finish_t *p_hwcrhk_Finish = NULL;
450160814Ssimonstatic HWCryptoHook_ModExp_t *p_hwcrhk_ModExp = NULL;
451296465Sdelphij#  ifndef OPENSSL_NO_RSA
452160814Ssimonstatic HWCryptoHook_RSA_t *p_hwcrhk_RSA = NULL;
453296465Sdelphij#  endif
454160814Ssimonstatic HWCryptoHook_RandomBytes_t *p_hwcrhk_RandomBytes = NULL;
455296465Sdelphij#  ifndef OPENSSL_NO_RSA
456160814Ssimonstatic HWCryptoHook_RSALoadKey_t *p_hwcrhk_RSALoadKey = NULL;
457160814Ssimonstatic HWCryptoHook_RSAGetPublicKey_t *p_hwcrhk_RSAGetPublicKey = NULL;
458160814Ssimonstatic HWCryptoHook_RSAUnloadKey_t *p_hwcrhk_RSAUnloadKey = NULL;
459296465Sdelphij#  endif
460160814Ssimonstatic HWCryptoHook_ModExpCRT_t *p_hwcrhk_ModExpCRT = NULL;
461160814Ssimon
462160814Ssimon/* Used in the DSO operations. */
463160814Ssimonstatic const char *HWCRHK_LIBNAME = NULL;
464160814Ssimonstatic void free_HWCRHK_LIBNAME(void)
465296465Sdelphij{
466296465Sdelphij    if (HWCRHK_LIBNAME)
467296465Sdelphij        OPENSSL_free((void *)HWCRHK_LIBNAME);
468296465Sdelphij    HWCRHK_LIBNAME = NULL;
469296465Sdelphij}
470296465Sdelphij
471160814Ssimonstatic const char *get_HWCRHK_LIBNAME(void)
472296465Sdelphij{
473296465Sdelphij    if (HWCRHK_LIBNAME)
474296465Sdelphij        return HWCRHK_LIBNAME;
475296465Sdelphij    return "nfhwcrhk";
476296465Sdelphij}
477296465Sdelphij
478160814Ssimonstatic long set_HWCRHK_LIBNAME(const char *name)
479296465Sdelphij{
480296465Sdelphij    free_HWCRHK_LIBNAME();
481296465Sdelphij    return (((HWCRHK_LIBNAME = BUF_strdup(name)) != NULL) ? 1 : 0);
482296465Sdelphij}
483296465Sdelphij
484160814Ssimonstatic const char *n_hwcrhk_Init = "HWCryptoHook_Init";
485160814Ssimonstatic const char *n_hwcrhk_Finish = "HWCryptoHook_Finish";
486160814Ssimonstatic const char *n_hwcrhk_ModExp = "HWCryptoHook_ModExp";
487296465Sdelphij#  ifndef OPENSSL_NO_RSA
488160814Ssimonstatic const char *n_hwcrhk_RSA = "HWCryptoHook_RSA";
489296465Sdelphij#  endif
490160814Ssimonstatic const char *n_hwcrhk_RandomBytes = "HWCryptoHook_RandomBytes";
491296465Sdelphij#  ifndef OPENSSL_NO_RSA
492160814Ssimonstatic const char *n_hwcrhk_RSALoadKey = "HWCryptoHook_RSALoadKey";
493160814Ssimonstatic const char *n_hwcrhk_RSAGetPublicKey = "HWCryptoHook_RSAGetPublicKey";
494160814Ssimonstatic const char *n_hwcrhk_RSAUnloadKey = "HWCryptoHook_RSAUnloadKey";
495296465Sdelphij#  endif
496160814Ssimonstatic const char *n_hwcrhk_ModExpCRT = "HWCryptoHook_ModExpCRT";
497160814Ssimon
498296465Sdelphij/*
499296465Sdelphij * HWCryptoHook library functions and mechanics - these are used by the
500296465Sdelphij * higher-level functions further down. NB: As and where there's no error
501296465Sdelphij * checking, take a look lower down where these functions are called, the
502296465Sdelphij * checking and error handling is probably down there.
503296465Sdelphij */
504160814Ssimon
505160814Ssimon/* utility function to obtain a context */
506296465Sdelphijstatic int get_context(HWCryptoHook_ContextHandle * hac,
507296465Sdelphij                       HWCryptoHook_CallerContext * cac)
508296465Sdelphij{
509296465Sdelphij    char tempbuf[1024];
510296465Sdelphij    HWCryptoHook_ErrMsgBuf rmsg;
511160814Ssimon
512296465Sdelphij    rmsg.buf = tempbuf;
513296465Sdelphij    rmsg.size = sizeof(tempbuf);
514160814Ssimon
515296465Sdelphij    *hac = p_hwcrhk_Init(&hwcrhk_globals, sizeof(hwcrhk_globals), &rmsg, cac);
516296465Sdelphij    if (!*hac)
517296465Sdelphij        return 0;
518296465Sdelphij    return 1;
519296465Sdelphij}
520296465Sdelphij
521160814Ssimon/* similarly to release one. */
522160814Ssimonstatic void release_context(HWCryptoHook_ContextHandle hac)
523296465Sdelphij{
524296465Sdelphij    p_hwcrhk_Finish(hac);
525296465Sdelphij}
526160814Ssimon
527160814Ssimon/* Destructor (complements the "ENGINE_chil()" constructor) */
528160814Ssimonstatic int hwcrhk_destroy(ENGINE *e)
529296465Sdelphij{
530296465Sdelphij    free_HWCRHK_LIBNAME();
531296465Sdelphij    ERR_unload_HWCRHK_strings();
532296465Sdelphij    return 1;
533296465Sdelphij}
534160814Ssimon
535160814Ssimon/* (de)initialisation functions. */
536160814Ssimonstatic int hwcrhk_init(ENGINE *e)
537296465Sdelphij{
538296465Sdelphij    HWCryptoHook_Init_t *p1;
539296465Sdelphij    HWCryptoHook_Finish_t *p2;
540296465Sdelphij    HWCryptoHook_ModExp_t *p3;
541296465Sdelphij#  ifndef OPENSSL_NO_RSA
542296465Sdelphij    HWCryptoHook_RSA_t *p4;
543296465Sdelphij    HWCryptoHook_RSALoadKey_t *p5;
544296465Sdelphij    HWCryptoHook_RSAGetPublicKey_t *p6;
545296465Sdelphij    HWCryptoHook_RSAUnloadKey_t *p7;
546296465Sdelphij#  endif
547296465Sdelphij    HWCryptoHook_RandomBytes_t *p8;
548296465Sdelphij    HWCryptoHook_ModExpCRT_t *p9;
549160814Ssimon
550296465Sdelphij    if (hwcrhk_dso != NULL) {
551296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_INIT, HWCRHK_R_ALREADY_LOADED);
552296465Sdelphij        goto err;
553296465Sdelphij    }
554296465Sdelphij    /* Attempt to load libnfhwcrhk.so/nfhwcrhk.dll/whatever. */
555296465Sdelphij    hwcrhk_dso = DSO_load(NULL, get_HWCRHK_LIBNAME(), NULL, 0);
556296465Sdelphij    if (hwcrhk_dso == NULL) {
557296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_INIT, HWCRHK_R_DSO_FAILURE);
558296465Sdelphij        goto err;
559296465Sdelphij    }
560296465Sdelphij    if (!(p1 = (HWCryptoHook_Init_t *)
561296465Sdelphij          DSO_bind_func(hwcrhk_dso, n_hwcrhk_Init)) ||
562296465Sdelphij        !(p2 = (HWCryptoHook_Finish_t *)
563296465Sdelphij          DSO_bind_func(hwcrhk_dso, n_hwcrhk_Finish)) ||
564296465Sdelphij        !(p3 = (HWCryptoHook_ModExp_t *)
565296465Sdelphij          DSO_bind_func(hwcrhk_dso, n_hwcrhk_ModExp)) ||
566296465Sdelphij#  ifndef OPENSSL_NO_RSA
567296465Sdelphij        !(p4 = (HWCryptoHook_RSA_t *)
568296465Sdelphij          DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSA)) ||
569296465Sdelphij        !(p5 = (HWCryptoHook_RSALoadKey_t *)
570296465Sdelphij          DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSALoadKey)) ||
571296465Sdelphij        !(p6 = (HWCryptoHook_RSAGetPublicKey_t *)
572296465Sdelphij          DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSAGetPublicKey)) ||
573296465Sdelphij        !(p7 = (HWCryptoHook_RSAUnloadKey_t *)
574296465Sdelphij          DSO_bind_func(hwcrhk_dso, n_hwcrhk_RSAUnloadKey)) ||
575296465Sdelphij#  endif
576296465Sdelphij        !(p8 = (HWCryptoHook_RandomBytes_t *)
577296465Sdelphij          DSO_bind_func(hwcrhk_dso, n_hwcrhk_RandomBytes)) ||
578296465Sdelphij        !(p9 = (HWCryptoHook_ModExpCRT_t *)
579296465Sdelphij          DSO_bind_func(hwcrhk_dso, n_hwcrhk_ModExpCRT))) {
580296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_INIT, HWCRHK_R_DSO_FAILURE);
581296465Sdelphij        goto err;
582296465Sdelphij    }
583296465Sdelphij    /* Copy the pointers */
584296465Sdelphij    p_hwcrhk_Init = p1;
585296465Sdelphij    p_hwcrhk_Finish = p2;
586296465Sdelphij    p_hwcrhk_ModExp = p3;
587296465Sdelphij#  ifndef OPENSSL_NO_RSA
588296465Sdelphij    p_hwcrhk_RSA = p4;
589296465Sdelphij    p_hwcrhk_RSALoadKey = p5;
590296465Sdelphij    p_hwcrhk_RSAGetPublicKey = p6;
591296465Sdelphij    p_hwcrhk_RSAUnloadKey = p7;
592296465Sdelphij#  endif
593296465Sdelphij    p_hwcrhk_RandomBytes = p8;
594296465Sdelphij    p_hwcrhk_ModExpCRT = p9;
595160814Ssimon
596296465Sdelphij    /*
597296465Sdelphij     * Check if the application decided to support dynamic locks, and if it
598296465Sdelphij     * does, use them.
599296465Sdelphij     */
600296465Sdelphij    if (disable_mutex_callbacks == 0) {
601296465Sdelphij        if (CRYPTO_get_dynlock_create_callback() != NULL &&
602296465Sdelphij            CRYPTO_get_dynlock_lock_callback() != NULL &&
603296465Sdelphij            CRYPTO_get_dynlock_destroy_callback() != NULL) {
604296465Sdelphij            hwcrhk_globals.mutex_init = hwcrhk_mutex_init;
605296465Sdelphij            hwcrhk_globals.mutex_acquire = hwcrhk_mutex_lock;
606296465Sdelphij            hwcrhk_globals.mutex_release = hwcrhk_mutex_unlock;
607296465Sdelphij            hwcrhk_globals.mutex_destroy = hwcrhk_mutex_destroy;
608296465Sdelphij        }
609296465Sdelphij    }
610160814Ssimon
611296465Sdelphij    /*
612296465Sdelphij     * Try and get a context - if not, we may have a DSO but no accelerator!
613296465Sdelphij     */
614296465Sdelphij    if (!get_context(&hwcrhk_context, &password_context)) {
615296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_INIT, HWCRHK_R_UNIT_FAILURE);
616296465Sdelphij        goto err;
617296465Sdelphij    }
618296465Sdelphij    /* Everything's fine. */
619296465Sdelphij#  ifndef OPENSSL_NO_RSA
620296465Sdelphij    if (hndidx_rsa == -1)
621296465Sdelphij        hndidx_rsa = RSA_get_ex_new_index(0,
622296465Sdelphij                                          "nFast HWCryptoHook RSA key handle",
623296465Sdelphij                                          NULL, NULL, NULL);
624296465Sdelphij#  endif
625296465Sdelphij    return 1;
626296465Sdelphij err:
627296465Sdelphij    if (hwcrhk_dso)
628296465Sdelphij        DSO_free(hwcrhk_dso);
629296465Sdelphij    hwcrhk_dso = NULL;
630296465Sdelphij    p_hwcrhk_Init = NULL;
631296465Sdelphij    p_hwcrhk_Finish = NULL;
632296465Sdelphij    p_hwcrhk_ModExp = NULL;
633296465Sdelphij#  ifndef OPENSSL_NO_RSA
634296465Sdelphij    p_hwcrhk_RSA = NULL;
635296465Sdelphij    p_hwcrhk_RSALoadKey = NULL;
636296465Sdelphij    p_hwcrhk_RSAGetPublicKey = NULL;
637296465Sdelphij    p_hwcrhk_RSAUnloadKey = NULL;
638296465Sdelphij#  endif
639296465Sdelphij    p_hwcrhk_ModExpCRT = NULL;
640296465Sdelphij    p_hwcrhk_RandomBytes = NULL;
641296465Sdelphij    return 0;
642296465Sdelphij}
643160814Ssimon
644160814Ssimonstatic int hwcrhk_finish(ENGINE *e)
645296465Sdelphij{
646296465Sdelphij    int to_return = 1;
647296465Sdelphij    free_HWCRHK_LIBNAME();
648296465Sdelphij    if (hwcrhk_dso == NULL) {
649296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_FINISH, HWCRHK_R_NOT_LOADED);
650296465Sdelphij        to_return = 0;
651296465Sdelphij        goto err;
652296465Sdelphij    }
653296465Sdelphij    release_context(hwcrhk_context);
654296465Sdelphij    if (!DSO_free(hwcrhk_dso)) {
655296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_FINISH, HWCRHK_R_DSO_FAILURE);
656296465Sdelphij        to_return = 0;
657296465Sdelphij        goto err;
658296465Sdelphij    }
659160814Ssimon err:
660296465Sdelphij    if (logstream)
661296465Sdelphij        BIO_free(logstream);
662296465Sdelphij    hwcrhk_dso = NULL;
663296465Sdelphij    p_hwcrhk_Init = NULL;
664296465Sdelphij    p_hwcrhk_Finish = NULL;
665296465Sdelphij    p_hwcrhk_ModExp = NULL;
666296465Sdelphij#  ifndef OPENSSL_NO_RSA
667296465Sdelphij    p_hwcrhk_RSA = NULL;
668296465Sdelphij    p_hwcrhk_RSALoadKey = NULL;
669296465Sdelphij    p_hwcrhk_RSAGetPublicKey = NULL;
670296465Sdelphij    p_hwcrhk_RSAUnloadKey = NULL;
671296465Sdelphij#  endif
672296465Sdelphij    p_hwcrhk_ModExpCRT = NULL;
673296465Sdelphij    p_hwcrhk_RandomBytes = NULL;
674296465Sdelphij    return to_return;
675296465Sdelphij}
676160814Ssimon
677296465Sdelphijstatic int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
678296465Sdelphij{
679296465Sdelphij    int to_return = 1;
680160814Ssimon
681296465Sdelphij    switch (cmd) {
682296465Sdelphij    case HWCRHK_CMD_SO_PATH:
683296465Sdelphij        if (hwcrhk_dso) {
684296465Sdelphij            HWCRHKerr(HWCRHK_F_HWCRHK_CTRL, HWCRHK_R_ALREADY_LOADED);
685296465Sdelphij            return 0;
686296465Sdelphij        }
687296465Sdelphij        if (p == NULL) {
688296465Sdelphij            HWCRHKerr(HWCRHK_F_HWCRHK_CTRL, ERR_R_PASSED_NULL_PARAMETER);
689296465Sdelphij            return 0;
690296465Sdelphij        }
691296465Sdelphij        return set_HWCRHK_LIBNAME((const char *)p);
692296465Sdelphij    case ENGINE_CTRL_SET_LOGSTREAM:
693296465Sdelphij        {
694296465Sdelphij            BIO *bio = (BIO *)p;
695160814Ssimon
696296465Sdelphij            CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
697296465Sdelphij            if (logstream) {
698296465Sdelphij                BIO_free(logstream);
699296465Sdelphij                logstream = NULL;
700296465Sdelphij            }
701296465Sdelphij            if (CRYPTO_add(&bio->references, 1, CRYPTO_LOCK_BIO) > 1)
702296465Sdelphij                logstream = bio;
703296465Sdelphij            else
704296465Sdelphij                HWCRHKerr(HWCRHK_F_HWCRHK_CTRL, HWCRHK_R_BIO_WAS_FREED);
705296465Sdelphij        }
706296465Sdelphij        CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
707296465Sdelphij        break;
708296465Sdelphij    case ENGINE_CTRL_SET_PASSWORD_CALLBACK:
709296465Sdelphij        CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
710296465Sdelphij        password_context.password_callback = (pem_password_cb *)f;
711296465Sdelphij        CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
712296465Sdelphij        break;
713296465Sdelphij    case ENGINE_CTRL_SET_USER_INTERFACE:
714296465Sdelphij    case HWCRHK_CMD_SET_USER_INTERFACE:
715296465Sdelphij        CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
716296465Sdelphij        password_context.ui_method = (UI_METHOD *)p;
717296465Sdelphij        CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
718296465Sdelphij        break;
719296465Sdelphij    case ENGINE_CTRL_SET_CALLBACK_DATA:
720296465Sdelphij    case HWCRHK_CMD_SET_CALLBACK_DATA:
721296465Sdelphij        CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
722296465Sdelphij        password_context.callback_data = p;
723296465Sdelphij        CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
724296465Sdelphij        break;
725296465Sdelphij        /*
726296465Sdelphij         * this enables or disables the "SimpleForkCheck" flag used in the
727296465Sdelphij         * initialisation structure.
728296465Sdelphij         */
729296465Sdelphij    case ENGINE_CTRL_CHIL_SET_FORKCHECK:
730296465Sdelphij    case HWCRHK_CMD_FORK_CHECK:
731296465Sdelphij        CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
732296465Sdelphij        if (i)
733296465Sdelphij            hwcrhk_globals.flags |= HWCryptoHook_InitFlags_SimpleForkCheck;
734296465Sdelphij        else
735296465Sdelphij            hwcrhk_globals.flags &= ~HWCryptoHook_InitFlags_SimpleForkCheck;
736296465Sdelphij        CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
737296465Sdelphij        break;
738296465Sdelphij        /*
739296465Sdelphij         * This will prevent the initialisation function from "installing"
740296465Sdelphij         * the mutex-handling callbacks, even if they are available from
741296465Sdelphij         * within the library (or were provided to the library from the
742296465Sdelphij         * calling application). This is to remove any baggage for
743296465Sdelphij         * applications not using multithreading.
744296465Sdelphij         */
745296465Sdelphij    case ENGINE_CTRL_CHIL_NO_LOCKING:
746296465Sdelphij        CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
747296465Sdelphij        disable_mutex_callbacks = 1;
748296465Sdelphij        CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
749296465Sdelphij        break;
750296465Sdelphij    case HWCRHK_CMD_THREAD_LOCKING:
751296465Sdelphij        CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
752296465Sdelphij        disable_mutex_callbacks = ((i == 0) ? 0 : 1);
753296465Sdelphij        CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
754296465Sdelphij        break;
755160814Ssimon
756296465Sdelphij        /* The command isn't understood by this engine */
757296465Sdelphij    default:
758296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_CTRL,
759296465Sdelphij                  HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
760296465Sdelphij        to_return = 0;
761296465Sdelphij        break;
762296465Sdelphij    }
763160814Ssimon
764296465Sdelphij    return to_return;
765296465Sdelphij}
766160814Ssimon
767160814Ssimonstatic EVP_PKEY *hwcrhk_load_privkey(ENGINE *eng, const char *key_id,
768296465Sdelphij                                     UI_METHOD *ui_method,
769296465Sdelphij                                     void *callback_data)
770296465Sdelphij{
771296465Sdelphij#  ifndef OPENSSL_NO_RSA
772296465Sdelphij    RSA *rtmp = NULL;
773296465Sdelphij#  endif
774296465Sdelphij    EVP_PKEY *res = NULL;
775296465Sdelphij#  ifndef OPENSSL_NO_RSA
776296465Sdelphij    HWCryptoHook_MPI e, n;
777296465Sdelphij    HWCryptoHook_RSAKeyHandle *hptr;
778296465Sdelphij#  endif
779296465Sdelphij#  if !defined(OPENSSL_NO_RSA)
780296465Sdelphij    char tempbuf[1024];
781296465Sdelphij    HWCryptoHook_ErrMsgBuf rmsg;
782296465Sdelphij    HWCryptoHook_PassphraseContext ppctx;
783296465Sdelphij#  endif
784160814Ssimon
785296465Sdelphij#  if !defined(OPENSSL_NO_RSA)
786296465Sdelphij    rmsg.buf = tempbuf;
787296465Sdelphij    rmsg.size = sizeof(tempbuf);
788296465Sdelphij#  endif
789160814Ssimon
790296465Sdelphij    if (!hwcrhk_context) {
791296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_NOT_INITIALISED);
792296465Sdelphij        goto err;
793296465Sdelphij    }
794296465Sdelphij#  ifndef OPENSSL_NO_RSA
795296465Sdelphij    hptr = OPENSSL_malloc(sizeof(HWCryptoHook_RSAKeyHandle));
796296465Sdelphij    if (!hptr) {
797296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, ERR_R_MALLOC_FAILURE);
798296465Sdelphij        goto err;
799296465Sdelphij    }
800296465Sdelphij    ppctx.ui_method = ui_method;
801296465Sdelphij    ppctx.callback_data = callback_data;
802296465Sdelphij    if (p_hwcrhk_RSALoadKey(hwcrhk_context, key_id, hptr, &rmsg, &ppctx)) {
803296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_CHIL_ERROR);
804296465Sdelphij        ERR_add_error_data(1, rmsg.buf);
805296465Sdelphij        goto err;
806296465Sdelphij    }
807296465Sdelphij    if (!*hptr) {
808296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_NO_KEY);
809296465Sdelphij        goto err;
810296465Sdelphij    }
811296465Sdelphij#  endif
812296465Sdelphij#  ifndef OPENSSL_NO_RSA
813296465Sdelphij    rtmp = RSA_new_method(eng);
814296465Sdelphij    RSA_set_ex_data(rtmp, hndidx_rsa, (char *)hptr);
815296465Sdelphij    rtmp->e = BN_new();
816296465Sdelphij    rtmp->n = BN_new();
817296465Sdelphij    rtmp->flags |= RSA_FLAG_EXT_PKEY;
818296465Sdelphij    MPI2BN(rtmp->e, e);
819296465Sdelphij    MPI2BN(rtmp->n, n);
820296465Sdelphij    if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg)
821296465Sdelphij        != HWCRYPTOHOOK_ERROR_MPISIZE) {
822296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_CHIL_ERROR);
823296465Sdelphij        ERR_add_error_data(1, rmsg.buf);
824296465Sdelphij        goto err;
825296465Sdelphij    }
826160814Ssimon
827296465Sdelphij    bn_expand2(rtmp->e, e.size / sizeof(BN_ULONG));
828296465Sdelphij    bn_expand2(rtmp->n, n.size / sizeof(BN_ULONG));
829296465Sdelphij    MPI2BN(rtmp->e, e);
830296465Sdelphij    MPI2BN(rtmp->n, n);
831160814Ssimon
832296465Sdelphij    if (p_hwcrhk_RSAGetPublicKey(*hptr, &n, &e, &rmsg)) {
833296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_CHIL_ERROR);
834296465Sdelphij        ERR_add_error_data(1, rmsg.buf);
835296465Sdelphij        goto err;
836296465Sdelphij    }
837296465Sdelphij    rtmp->e->top = e.size / sizeof(BN_ULONG);
838296465Sdelphij    bn_fix_top(rtmp->e);
839296465Sdelphij    rtmp->n->top = n.size / sizeof(BN_ULONG);
840296465Sdelphij    bn_fix_top(rtmp->n);
841160814Ssimon
842296465Sdelphij    res = EVP_PKEY_new();
843296465Sdelphij    EVP_PKEY_assign_RSA(res, rtmp);
844296465Sdelphij#  endif
845160814Ssimon
846296465Sdelphij    if (!res)
847296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY,
848296465Sdelphij                  HWCRHK_R_PRIVATE_KEY_ALGORITHMS_DISABLED);
849160814Ssimon
850296465Sdelphij    return res;
851160814Ssimon err:
852296465Sdelphij    if (res)
853296465Sdelphij        EVP_PKEY_free(res);
854296465Sdelphij#  ifndef OPENSSL_NO_RSA
855296465Sdelphij    if (rtmp)
856296465Sdelphij        RSA_free(rtmp);
857296465Sdelphij#  endif
858296465Sdelphij    return NULL;
859296465Sdelphij}
860160814Ssimon
861160814Ssimonstatic EVP_PKEY *hwcrhk_load_pubkey(ENGINE *eng, const char *key_id,
862296465Sdelphij                                    UI_METHOD *ui_method, void *callback_data)
863296465Sdelphij{
864296465Sdelphij    EVP_PKEY *res = NULL;
865160814Ssimon
866296465Sdelphij#  ifndef OPENSSL_NO_RSA
867296465Sdelphij    res = hwcrhk_load_privkey(eng, key_id, ui_method, callback_data);
868296465Sdelphij#  endif
869160814Ssimon
870296465Sdelphij    if (res)
871296465Sdelphij        switch (res->type) {
872296465Sdelphij#  ifndef OPENSSL_NO_RSA
873296465Sdelphij        case EVP_PKEY_RSA:
874296465Sdelphij            {
875296465Sdelphij                RSA *rsa = NULL;
876160814Ssimon
877296465Sdelphij                CRYPTO_w_lock(CRYPTO_LOCK_EVP_PKEY);
878296465Sdelphij                rsa = res->pkey.rsa;
879296465Sdelphij                res->pkey.rsa = RSA_new();
880296465Sdelphij                res->pkey.rsa->n = rsa->n;
881296465Sdelphij                res->pkey.rsa->e = rsa->e;
882296465Sdelphij                rsa->n = NULL;
883296465Sdelphij                rsa->e = NULL;
884296465Sdelphij                CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY);
885296465Sdelphij                RSA_free(rsa);
886296465Sdelphij            }
887296465Sdelphij            break;
888296465Sdelphij#  endif
889296465Sdelphij        default:
890296465Sdelphij            HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PUBKEY,
891296465Sdelphij                      HWCRHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
892296465Sdelphij            goto err;
893296465Sdelphij        }
894160814Ssimon
895296465Sdelphij    return res;
896160814Ssimon err:
897296465Sdelphij    if (res)
898296465Sdelphij        EVP_PKEY_free(res);
899296465Sdelphij    return NULL;
900296465Sdelphij}
901160814Ssimon
902160814Ssimon/* A little mod_exp */
903160814Ssimonstatic int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
904296465Sdelphij                          const BIGNUM *m, BN_CTX *ctx)
905296465Sdelphij{
906296465Sdelphij    char tempbuf[1024];
907296465Sdelphij    HWCryptoHook_ErrMsgBuf rmsg;
908296465Sdelphij    /*
909296465Sdelphij     * Since HWCryptoHook_MPI is pretty compatible with BIGNUM's, we use them
910296465Sdelphij     * directly, plus a little macro magic.  We only thing we need to make
911296465Sdelphij     * sure of is that enough space is allocated.
912296465Sdelphij     */
913296465Sdelphij    HWCryptoHook_MPI m_a, m_p, m_n, m_r;
914296465Sdelphij    int to_return, ret;
915160814Ssimon
916296465Sdelphij    to_return = 0;              /* expect failure */
917296465Sdelphij    rmsg.buf = tempbuf;
918296465Sdelphij    rmsg.size = sizeof(tempbuf);
919160814Ssimon
920296465Sdelphij    if (!hwcrhk_context) {
921296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP, HWCRHK_R_NOT_INITIALISED);
922296465Sdelphij        goto err;
923296465Sdelphij    }
924296465Sdelphij    /* Prepare the params */
925296465Sdelphij    bn_expand2(r, m->top);      /* Check for error !! */
926296465Sdelphij    BN2MPI(m_a, a);
927296465Sdelphij    BN2MPI(m_p, p);
928296465Sdelphij    BN2MPI(m_n, m);
929296465Sdelphij    MPI2BN(r, m_r);
930160814Ssimon
931296465Sdelphij    /* Perform the operation */
932296465Sdelphij    ret = p_hwcrhk_ModExp(hwcrhk_context, m_a, m_p, m_n, &m_r, &rmsg);
933160814Ssimon
934296465Sdelphij    /* Convert the response */
935296465Sdelphij    r->top = m_r.size / sizeof(BN_ULONG);
936296465Sdelphij    bn_fix_top(r);
937160814Ssimon
938296465Sdelphij    if (ret < 0) {
939296465Sdelphij        /*
940296465Sdelphij         * FIXME: When this error is returned, HWCryptoHook is telling us
941296465Sdelphij         * that falling back to software computation might be a good thing.
942296465Sdelphij         */
943296465Sdelphij        if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) {
944296465Sdelphij            HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP, HWCRHK_R_REQUEST_FALLBACK);
945296465Sdelphij        } else {
946296465Sdelphij            HWCRHKerr(HWCRHK_F_HWCRHK_MOD_EXP, HWCRHK_R_REQUEST_FAILED);
947296465Sdelphij        }
948296465Sdelphij        ERR_add_error_data(1, rmsg.buf);
949296465Sdelphij        goto err;
950296465Sdelphij    }
951160814Ssimon
952296465Sdelphij    to_return = 1;
953296465Sdelphij err:
954296465Sdelphij    return to_return;
955296465Sdelphij}
956160814Ssimon
957296465Sdelphij#  ifndef OPENSSL_NO_RSA
958296465Sdelphijstatic int hwcrhk_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa,
959296465Sdelphij                              BN_CTX *ctx)
960296465Sdelphij{
961296465Sdelphij    char tempbuf[1024];
962296465Sdelphij    HWCryptoHook_ErrMsgBuf rmsg;
963296465Sdelphij    HWCryptoHook_RSAKeyHandle *hptr;
964296465Sdelphij    int to_return = 0, ret;
965160814Ssimon
966296465Sdelphij    rmsg.buf = tempbuf;
967296465Sdelphij    rmsg.size = sizeof(tempbuf);
968160814Ssimon
969296465Sdelphij    if (!hwcrhk_context) {
970296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP, HWCRHK_R_NOT_INITIALISED);
971296465Sdelphij        goto err;
972296465Sdelphij    }
973160814Ssimon
974296465Sdelphij    /*
975296465Sdelphij     * This provides support for nForce keys.  Since that's opaque data all
976296465Sdelphij     * we do is provide a handle to the proper key and let HWCryptoHook take
977296465Sdelphij     * care of the rest.
978296465Sdelphij     */
979296465Sdelphij    if ((hptr =
980296465Sdelphij         (HWCryptoHook_RSAKeyHandle *) RSA_get_ex_data(rsa, hndidx_rsa))
981296465Sdelphij        != NULL) {
982296465Sdelphij        HWCryptoHook_MPI m_a, m_r;
983160814Ssimon
984296465Sdelphij        if (!rsa->n) {
985296465Sdelphij            HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
986296465Sdelphij                      HWCRHK_R_MISSING_KEY_COMPONENTS);
987296465Sdelphij            goto err;
988296465Sdelphij        }
989160814Ssimon
990296465Sdelphij        /* Prepare the params */
991296465Sdelphij        bn_expand2(r, rsa->n->top); /* Check for error !! */
992296465Sdelphij        BN2MPI(m_a, I);
993296465Sdelphij        MPI2BN(r, m_r);
994160814Ssimon
995296465Sdelphij        /* Perform the operation */
996296465Sdelphij        ret = p_hwcrhk_RSA(m_a, *hptr, &m_r, &rmsg);
997160814Ssimon
998296465Sdelphij        /* Convert the response */
999296465Sdelphij        r->top = m_r.size / sizeof(BN_ULONG);
1000296465Sdelphij        bn_fix_top(r);
1001160814Ssimon
1002296465Sdelphij        if (ret < 0) {
1003296465Sdelphij            /*
1004296465Sdelphij             * FIXME: When this error is returned, HWCryptoHook is telling us
1005296465Sdelphij             * that falling back to software computation might be a good
1006296465Sdelphij             * thing.
1007296465Sdelphij             */
1008296465Sdelphij            if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) {
1009296465Sdelphij                HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1010296465Sdelphij                          HWCRHK_R_REQUEST_FALLBACK);
1011296465Sdelphij            } else {
1012296465Sdelphij                HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1013296465Sdelphij                          HWCRHK_R_REQUEST_FAILED);
1014296465Sdelphij            }
1015296465Sdelphij            ERR_add_error_data(1, rmsg.buf);
1016296465Sdelphij            goto err;
1017296465Sdelphij        }
1018296465Sdelphij    } else {
1019296465Sdelphij        HWCryptoHook_MPI m_a, m_p, m_q, m_dmp1, m_dmq1, m_iqmp, m_r;
1020160814Ssimon
1021296465Sdelphij        if (!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp) {
1022296465Sdelphij            HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1023296465Sdelphij                      HWCRHK_R_MISSING_KEY_COMPONENTS);
1024296465Sdelphij            goto err;
1025296465Sdelphij        }
1026160814Ssimon
1027296465Sdelphij        /* Prepare the params */
1028296465Sdelphij        bn_expand2(r, rsa->n->top); /* Check for error !! */
1029296465Sdelphij        BN2MPI(m_a, I);
1030296465Sdelphij        BN2MPI(m_p, rsa->p);
1031296465Sdelphij        BN2MPI(m_q, rsa->q);
1032296465Sdelphij        BN2MPI(m_dmp1, rsa->dmp1);
1033296465Sdelphij        BN2MPI(m_dmq1, rsa->dmq1);
1034296465Sdelphij        BN2MPI(m_iqmp, rsa->iqmp);
1035296465Sdelphij        MPI2BN(r, m_r);
1036160814Ssimon
1037296465Sdelphij        /* Perform the operation */
1038296465Sdelphij        ret = p_hwcrhk_ModExpCRT(hwcrhk_context, m_a, m_p, m_q,
1039296465Sdelphij                                 m_dmp1, m_dmq1, m_iqmp, &m_r, &rmsg);
1040160814Ssimon
1041296465Sdelphij        /* Convert the response */
1042296465Sdelphij        r->top = m_r.size / sizeof(BN_ULONG);
1043296465Sdelphij        bn_fix_top(r);
1044160814Ssimon
1045296465Sdelphij        if (ret < 0) {
1046296465Sdelphij            /*
1047296465Sdelphij             * FIXME: When this error is returned, HWCryptoHook is telling us
1048296465Sdelphij             * that falling back to software computation might be a good
1049296465Sdelphij             * thing.
1050296465Sdelphij             */
1051296465Sdelphij            if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) {
1052296465Sdelphij                HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1053296465Sdelphij                          HWCRHK_R_REQUEST_FALLBACK);
1054296465Sdelphij            } else {
1055296465Sdelphij                HWCRHKerr(HWCRHK_F_HWCRHK_RSA_MOD_EXP,
1056296465Sdelphij                          HWCRHK_R_REQUEST_FAILED);
1057296465Sdelphij            }
1058296465Sdelphij            ERR_add_error_data(1, rmsg.buf);
1059296465Sdelphij            goto err;
1060296465Sdelphij        }
1061296465Sdelphij    }
1062296465Sdelphij    /*
1063296465Sdelphij     * If we're here, we must be here with some semblance of success :-)
1064296465Sdelphij     */
1065296465Sdelphij    to_return = 1;
1066296465Sdelphij err:
1067296465Sdelphij    return to_return;
1068296465Sdelphij}
1069296465Sdelphij#  endif
1070296465Sdelphij
1071296465Sdelphij#  ifndef OPENSSL_NO_RSA
1072160814Ssimon/* This function is aliased to mod_exp (with the mont stuff dropped). */
1073160814Ssimonstatic int hwcrhk_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
1074296465Sdelphij                               const BIGNUM *m, BN_CTX *ctx,
1075296465Sdelphij                               BN_MONT_CTX *m_ctx)
1076296465Sdelphij{
1077296465Sdelphij    return hwcrhk_mod_exp(r, a, p, m, ctx);
1078296465Sdelphij}
1079215697Ssimon
1080215697Ssimonstatic int hwcrhk_rsa_finish(RSA *rsa)
1081296465Sdelphij{
1082296465Sdelphij    HWCryptoHook_RSAKeyHandle *hptr;
1083215697Ssimon
1084296465Sdelphij    hptr = RSA_get_ex_data(rsa, hndidx_rsa);
1085296465Sdelphij    if (hptr) {
1086296465Sdelphij        p_hwcrhk_RSAUnloadKey(*hptr, NULL);
1087296465Sdelphij        OPENSSL_free(hptr);
1088296465Sdelphij        RSA_set_ex_data(rsa, hndidx_rsa, NULL);
1089296465Sdelphij    }
1090296465Sdelphij    return 1;
1091296465Sdelphij}
1092215697Ssimon
1093296465Sdelphij#  endif
1094160814Ssimon
1095296465Sdelphij#  ifndef OPENSSL_NO_DH
1096160814Ssimon/* This function is aliased to mod_exp (with the dh and mont dropped). */
1097160814Ssimonstatic int hwcrhk_mod_exp_dh(const DH *dh, BIGNUM *r,
1098296465Sdelphij                             const BIGNUM *a, const BIGNUM *p,
1099296465Sdelphij                             const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1100296465Sdelphij{
1101296465Sdelphij    return hwcrhk_mod_exp(r, a, p, m, ctx);
1102296465Sdelphij}
1103296465Sdelphij#  endif
1104160814Ssimon
1105160814Ssimon/* Random bytes are good */
1106160814Ssimonstatic int hwcrhk_rand_bytes(unsigned char *buf, int num)
1107296465Sdelphij{
1108296465Sdelphij    char tempbuf[1024];
1109296465Sdelphij    HWCryptoHook_ErrMsgBuf rmsg;
1110296465Sdelphij    int to_return = 0;          /* assume failure */
1111296465Sdelphij    int ret;
1112160814Ssimon
1113296465Sdelphij    rmsg.buf = tempbuf;
1114296465Sdelphij    rmsg.size = sizeof(tempbuf);
1115160814Ssimon
1116296465Sdelphij    if (!hwcrhk_context) {
1117296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES, HWCRHK_R_NOT_INITIALISED);
1118296465Sdelphij        goto err;
1119296465Sdelphij    }
1120160814Ssimon
1121296465Sdelphij    ret = p_hwcrhk_RandomBytes(hwcrhk_context, buf, num, &rmsg);
1122296465Sdelphij    if (ret < 0) {
1123296465Sdelphij        /*
1124296465Sdelphij         * FIXME: When this error is returned, HWCryptoHook is telling us
1125296465Sdelphij         * that falling back to software computation might be a good thing.
1126296465Sdelphij         */
1127296465Sdelphij        if (ret == HWCRYPTOHOOK_ERROR_FALLBACK) {
1128296465Sdelphij            HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES, HWCRHK_R_REQUEST_FALLBACK);
1129296465Sdelphij        } else {
1130296465Sdelphij            HWCRHKerr(HWCRHK_F_HWCRHK_RAND_BYTES, HWCRHK_R_REQUEST_FAILED);
1131296465Sdelphij        }
1132296465Sdelphij        ERR_add_error_data(1, rmsg.buf);
1133296465Sdelphij        goto err;
1134296465Sdelphij    }
1135296465Sdelphij    to_return = 1;
1136160814Ssimon err:
1137296465Sdelphij    return to_return;
1138296465Sdelphij}
1139160814Ssimon
1140160814Ssimonstatic int hwcrhk_rand_status(void)
1141296465Sdelphij{
1142296465Sdelphij    return 1;
1143296465Sdelphij}
1144160814Ssimon
1145296465Sdelphij/*
1146296465Sdelphij * Mutex calls: since the HWCryptoHook model closely follows the POSIX model
1147160814Ssimon * these just wrap the POSIX functions and add some logging.
1148160814Ssimon */
1149160814Ssimon
1150296465Sdelphijstatic int hwcrhk_mutex_init(HWCryptoHook_Mutex * mt,
1151296465Sdelphij                             HWCryptoHook_CallerContext * cactx)
1152296465Sdelphij{
1153296465Sdelphij    mt->lockid = CRYPTO_get_new_dynlockid();
1154296465Sdelphij    if (mt->lockid == 0)
1155296465Sdelphij        return 1;               /* failure */
1156296465Sdelphij    return 0;                   /* success */
1157296465Sdelphij}
1158160814Ssimon
1159296465Sdelphijstatic int hwcrhk_mutex_lock(HWCryptoHook_Mutex * mt)
1160296465Sdelphij{
1161296465Sdelphij    CRYPTO_w_lock(mt->lockid);
1162296465Sdelphij    return 0;
1163296465Sdelphij}
1164160814Ssimon
1165160814Ssimonstatic void hwcrhk_mutex_unlock(HWCryptoHook_Mutex * mt)
1166296465Sdelphij{
1167296465Sdelphij    CRYPTO_w_unlock(mt->lockid);
1168296465Sdelphij}
1169160814Ssimon
1170296465Sdelphijstatic void hwcrhk_mutex_destroy(HWCryptoHook_Mutex * mt)
1171296465Sdelphij{
1172296465Sdelphij    CRYPTO_destroy_dynlockid(mt->lockid);
1173296465Sdelphij}
1174160814Ssimon
1175160814Ssimonstatic int hwcrhk_get_pass(const char *prompt_info,
1176296465Sdelphij                           int *len_io, char *buf,
1177296465Sdelphij                           HWCryptoHook_PassphraseContext * ppctx,
1178296465Sdelphij                           HWCryptoHook_CallerContext * cactx)
1179296465Sdelphij{
1180296465Sdelphij    pem_password_cb *callback = NULL;
1181296465Sdelphij    void *callback_data = NULL;
1182296465Sdelphij    UI_METHOD *ui_method = NULL;
1183296465Sdelphij    /*
1184296465Sdelphij     * Despite what the documentation says prompt_info can be an empty
1185296465Sdelphij     * string.
1186296465Sdelphij     */
1187296465Sdelphij    if (prompt_info && !*prompt_info)
1188296465Sdelphij        prompt_info = NULL;
1189160814Ssimon
1190296465Sdelphij    if (cactx) {
1191296465Sdelphij        if (cactx->ui_method)
1192296465Sdelphij            ui_method = cactx->ui_method;
1193296465Sdelphij        if (cactx->password_callback)
1194296465Sdelphij            callback = cactx->password_callback;
1195296465Sdelphij        if (cactx->callback_data)
1196296465Sdelphij            callback_data = cactx->callback_data;
1197296465Sdelphij    }
1198296465Sdelphij    if (ppctx) {
1199296465Sdelphij        if (ppctx->ui_method) {
1200296465Sdelphij            ui_method = ppctx->ui_method;
1201296465Sdelphij            callback = NULL;
1202296465Sdelphij        }
1203296465Sdelphij        if (ppctx->callback_data)
1204296465Sdelphij            callback_data = ppctx->callback_data;
1205296465Sdelphij    }
1206296465Sdelphij    if (callback == NULL && ui_method == NULL) {
1207296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_GET_PASS, HWCRHK_R_NO_CALLBACK);
1208296465Sdelphij        return -1;
1209296465Sdelphij    }
1210160814Ssimon
1211296465Sdelphij    if (ui_method) {
1212296465Sdelphij        UI *ui = UI_new_method(ui_method);
1213296465Sdelphij        if (ui) {
1214296465Sdelphij            int ok;
1215296465Sdelphij            char *prompt = UI_construct_prompt(ui,
1216296465Sdelphij                                               "pass phrase", prompt_info);
1217160814Ssimon
1218296465Sdelphij            ok = UI_add_input_string(ui, prompt,
1219296465Sdelphij                                     UI_INPUT_FLAG_DEFAULT_PWD,
1220296465Sdelphij                                     buf, 0, (*len_io) - 1);
1221296465Sdelphij            UI_add_user_data(ui, callback_data);
1222296465Sdelphij            UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0);
1223160814Ssimon
1224296465Sdelphij            if (ok >= 0)
1225296465Sdelphij                do {
1226296465Sdelphij                    ok = UI_process(ui);
1227296465Sdelphij                }
1228296465Sdelphij                while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0));
1229160814Ssimon
1230296465Sdelphij            if (ok >= 0)
1231296465Sdelphij                *len_io = strlen(buf);
1232160814Ssimon
1233296465Sdelphij            UI_free(ui);
1234296465Sdelphij            OPENSSL_free(prompt);
1235296465Sdelphij        }
1236296465Sdelphij    } else {
1237296465Sdelphij        *len_io = callback(buf, *len_io, 0, callback_data);
1238296465Sdelphij    }
1239296465Sdelphij    if (!*len_io)
1240296465Sdelphij        return -1;
1241296465Sdelphij    return 0;
1242296465Sdelphij}
1243160814Ssimon
1244160814Ssimonstatic int hwcrhk_insert_card(const char *prompt_info,
1245296465Sdelphij                              const char *wrong_info,
1246296465Sdelphij                              HWCryptoHook_PassphraseContext * ppctx,
1247296465Sdelphij                              HWCryptoHook_CallerContext * cactx)
1248296465Sdelphij{
1249296465Sdelphij    int ok = -1;
1250296465Sdelphij    UI *ui;
1251296465Sdelphij    void *callback_data = NULL;
1252296465Sdelphij    UI_METHOD *ui_method = NULL;
1253160814Ssimon
1254296465Sdelphij    if (cactx) {
1255296465Sdelphij        if (cactx->ui_method)
1256296465Sdelphij            ui_method = cactx->ui_method;
1257296465Sdelphij        if (cactx->callback_data)
1258296465Sdelphij            callback_data = cactx->callback_data;
1259296465Sdelphij    }
1260296465Sdelphij    if (ppctx) {
1261296465Sdelphij        if (ppctx->ui_method)
1262296465Sdelphij            ui_method = ppctx->ui_method;
1263296465Sdelphij        if (ppctx->callback_data)
1264296465Sdelphij            callback_data = ppctx->callback_data;
1265296465Sdelphij    }
1266296465Sdelphij    if (ui_method == NULL) {
1267296465Sdelphij        HWCRHKerr(HWCRHK_F_HWCRHK_INSERT_CARD, HWCRHK_R_NO_CALLBACK);
1268296465Sdelphij        return -1;
1269296465Sdelphij    }
1270160814Ssimon
1271296465Sdelphij    ui = UI_new_method(ui_method);
1272160814Ssimon
1273296465Sdelphij    if (ui) {
1274296465Sdelphij        char answer;
1275296465Sdelphij        char buf[BUFSIZ];
1276296465Sdelphij        /*
1277296465Sdelphij         * Despite what the documentation says wrong_info can be an empty
1278296465Sdelphij         * string.
1279296465Sdelphij         */
1280296465Sdelphij        if (wrong_info && *wrong_info)
1281296465Sdelphij            BIO_snprintf(buf, sizeof(buf) - 1,
1282296465Sdelphij                         "Current card: \"%s\"\n", wrong_info);
1283296465Sdelphij        else
1284296465Sdelphij            buf[0] = 0;
1285296465Sdelphij        ok = UI_dup_info_string(ui, buf);
1286296465Sdelphij        if (ok >= 0 && prompt_info) {
1287296465Sdelphij            BIO_snprintf(buf, sizeof(buf) - 1,
1288296465Sdelphij                         "Insert card \"%s\"", prompt_info);
1289296465Sdelphij            ok = UI_dup_input_boolean(ui, buf,
1290296465Sdelphij                                      "\n then hit <enter> or C<enter> to cancel\n",
1291296465Sdelphij                                      "\r\n", "Cc", UI_INPUT_FLAG_ECHO,
1292296465Sdelphij                                      &answer);
1293296465Sdelphij        }
1294296465Sdelphij        UI_add_user_data(ui, callback_data);
1295160814Ssimon
1296296465Sdelphij        if (ok >= 0)
1297296465Sdelphij            ok = UI_process(ui);
1298296465Sdelphij        UI_free(ui);
1299160814Ssimon
1300296465Sdelphij        if (ok == -2 || (ok >= 0 && answer == 'C'))
1301296465Sdelphij            ok = 1;
1302296465Sdelphij        else if (ok < 0)
1303296465Sdelphij            ok = -1;
1304296465Sdelphij        else
1305296465Sdelphij            ok = 0;
1306296465Sdelphij    }
1307296465Sdelphij    return ok;
1308296465Sdelphij}
1309160814Ssimon
1310160814Ssimonstatic void hwcrhk_log_message(void *logstr, const char *message)
1311296465Sdelphij{
1312296465Sdelphij    BIO *lstream = NULL;
1313160814Ssimon
1314296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_BIO);
1315296465Sdelphij    if (logstr)
1316296465Sdelphij        lstream = *(BIO **)logstr;
1317296465Sdelphij    if (lstream) {
1318296465Sdelphij        BIO_printf(lstream, "%s\n", message);
1319296465Sdelphij    }
1320296465Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_BIO);
1321296465Sdelphij}
1322160814Ssimon
1323296465Sdelphij/*
1324296465Sdelphij * This stuff is needed if this ENGINE is being compiled into a
1325296465Sdelphij * self-contained shared-library.
1326296465Sdelphij */
1327296465Sdelphij#  ifndef OPENSSL_NO_DYNAMIC_ENGINE
1328160814Ssimonstatic int bind_fn(ENGINE *e, const char *id)
1329296465Sdelphij{
1330296465Sdelphij    if (id && (strcmp(id, engine_hwcrhk_id) != 0) &&
1331296465Sdelphij        (strcmp(id, engine_hwcrhk_id_alt) != 0))
1332296465Sdelphij        return 0;
1333296465Sdelphij    if (!bind_helper(e))
1334296465Sdelphij        return 0;
1335296465Sdelphij    return 1;
1336296465Sdelphij}
1337296465Sdelphij
1338160814SsimonIMPLEMENT_DYNAMIC_CHECK_FN()
1339296465Sdelphij    IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
1340296465Sdelphij#  endif                        /* OPENSSL_NO_DYNAMIC_ENGINE */
1341296465Sdelphij# endif                         /* !OPENSSL_NO_HW_CHIL */
1342296465Sdelphij#endif                          /* !OPENSSL_NO_HW */
1343