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