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