]>
Commit | Line | Data |
---|---|---|
5f855569 RS |
1 | /* crypto/engine/hw_ibmca.c */ |
2 | /* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL | |
3 | * project 2000. | |
4 | */ | |
5 | /* ==================================================================== | |
6 | * Copyright (c) 1999 The OpenSSL Project. All rights reserved. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * | |
12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | |
14 | * | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in | |
17 | * the documentation and/or other materials provided with the | |
18 | * distribution. | |
19 | * | |
20 | * 3. All advertising materials mentioning features or use of this | |
21 | * software must display the following acknowledgment: | |
22 | * "This product includes software developed by the OpenSSL Project | |
23 | * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" | |
24 | * | |
25 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | |
26 | * endorse or promote products derived from this software without | |
27 | * prior written permission. For written permission, please contact | |
28 | * licensing@OpenSSL.org. | |
29 | * | |
30 | * 5. Products derived from this software may not be called "OpenSSL" | |
31 | * nor may "OpenSSL" appear in their names without prior written | |
32 | * permission of the OpenSSL Project. | |
33 | * | |
34 | * 6. Redistributions of any form whatsoever must retain the following | |
35 | * acknowledgment: | |
36 | * "This product includes software developed by the OpenSSL Project | |
37 | * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" | |
38 | * | |
39 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | |
40 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
42 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR | |
43 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
44 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
45 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
46 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
47 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
48 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
49 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
50 | * OF THE POSSIBILITY OF SUCH DAMAGE. | |
51 | * ==================================================================== | |
52 | * | |
53 | * This product includes cryptographic software written by Eric Young | |
54 | * (eay@cryptsoft.com). This product includes software written by Tim | |
55 | * Hudson (tjh@cryptsoft.com). | |
56 | * | |
57 | */ | |
58 | ||
59 | /* (C) COPYRIGHT International Business Machines Corp. 2001 */ | |
60 | ||
61 | #include <stdio.h> | |
62 | #include <openssl/crypto.h> | |
63 | #include <openssl/dso.h> | |
64 | #include <openssl/engine.h> | |
65 | ||
66 | #ifndef OPENSSL_NO_HW | |
67 | #ifndef OPENSSL_NO_HW_IBMCA | |
68 | ||
69 | #ifdef FLAT_INC | |
70 | #include "ica_openssl_api.h" | |
71 | #else | |
72 | #include "vendor_defns/ica_openssl_api.h" | |
73 | #endif | |
74 | ||
75 | #define IBMCA_LIB_NAME "ibmca engine" | |
76 | #include "hw_ibmca_err.c" | |
77 | ||
78 | static int ibmca_destroy(ENGINE *e); | |
79 | static int ibmca_init(ENGINE *e); | |
80 | static int ibmca_finish(ENGINE *e); | |
81 | static int ibmca_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)()); | |
82 | ||
83 | static const char *IBMCA_F1 = "icaOpenAdapter"; | |
84 | static const char *IBMCA_F2 = "icaCloseAdapter"; | |
85 | static const char *IBMCA_F3 = "icaRsaModExpo"; | |
86 | static const char *IBMCA_F4 = "icaRandomNumberGenerate"; | |
87 | static const char *IBMCA_F5 = "icaRsaCrt"; | |
88 | ||
89 | ICA_ADAPTER_HANDLE handle=0; | |
90 | ||
91 | /* BIGNUM stuff */ | |
92 | static int ibmca_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, | |
93 | const BIGNUM *m, BN_CTX *ctx); | |
94 | ||
95 | static int ibmca_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, | |
96 | const BIGNUM *q, const BIGNUM *dmp1, const BIGNUM *dmq1, | |
97 | const BIGNUM *iqmp, BN_CTX *ctx); | |
98 | ||
99 | #ifndef OPENSSL_NO_RSA | |
100 | /* RSA stuff */ | |
101 | static int ibmca_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa); | |
102 | #endif | |
103 | ||
104 | /* This function is aliased to mod_exp (with the mont stuff dropped). */ | |
105 | static int ibmca_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, | |
106 | const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); | |
107 | ||
108 | #ifndef OPENSSL_NO_DSA | |
109 | /* DSA stuff */ | |
110 | static int ibmca_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1, | |
111 | BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m, | |
112 | BN_CTX *ctx, BN_MONT_CTX *in_mont); | |
113 | static int ibmca_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a, | |
114 | const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, | |
115 | BN_MONT_CTX *m_ctx); | |
116 | #endif | |
117 | ||
118 | #ifndef OPENSSL_NO_DH | |
119 | /* DH stuff */ | |
120 | /* This function is alised to mod_exp (with the DH and mont dropped). */ | |
121 | static int ibmca_mod_exp_dh(const DH *dh, BIGNUM *r, | |
122 | const BIGNUM *a, const BIGNUM *p, | |
123 | const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); | |
124 | #endif | |
125 | ||
126 | /* RAND stuff */ | |
127 | static int ibmca_rand_bytes(unsigned char *buf, int num); | |
128 | static int ibmca_rand_status(void); | |
129 | ||
130 | ||
131 | /* WJH - check for more commands, like in nuron */ | |
132 | ||
133 | /* The definitions for control commands specific to this engine */ | |
134 | #define IBMCA_CMD_SO_PATH ENGINE_CMD_BASE | |
135 | static const ENGINE_CMD_DEFN ibmca_cmd_defns[] = { | |
136 | {IBMCA_CMD_SO_PATH, | |
137 | "SO_PATH", | |
138 | "Specifies the path to the 'atasi' shared library", | |
139 | ENGINE_CMD_FLAG_STRING}, | |
140 | {0, NULL, NULL, 0} | |
141 | }; | |
142 | ||
143 | #ifndef OPENSSL_NO_RSA | |
144 | /* Our internal RSA_METHOD that we provide pointers to */ | |
145 | static RSA_METHOD ibmca_rsa = | |
146 | { | |
147 | "Ibmca RSA method", | |
148 | NULL, | |
149 | NULL, | |
150 | NULL, | |
151 | NULL, | |
152 | ibmca_rsa_mod_exp, | |
153 | ibmca_mod_exp_mont, | |
154 | NULL, | |
155 | NULL, | |
156 | 0, | |
157 | NULL, | |
158 | NULL, | |
159 | NULL | |
160 | }; | |
161 | #endif | |
162 | ||
163 | #ifndef OPENSSL_NO_DSA | |
164 | /* Our internal DSA_METHOD that we provide pointers to */ | |
165 | static DSA_METHOD ibmca_dsa = | |
166 | { | |
167 | "Ibmca DSA method", | |
168 | NULL, /* dsa_do_sign */ | |
169 | NULL, /* dsa_sign_setup */ | |
170 | NULL, /* dsa_do_verify */ | |
171 | ibmca_dsa_mod_exp, /* dsa_mod_exp */ | |
172 | ibmca_mod_exp_dsa, /* bn_mod_exp */ | |
173 | NULL, /* init */ | |
174 | NULL, /* finish */ | |
175 | 0, /* flags */ | |
176 | NULL /* app_data */ | |
177 | }; | |
178 | #endif | |
179 | ||
180 | #ifndef OPENSSL_NO_DH | |
181 | /* Our internal DH_METHOD that we provide pointers to */ | |
182 | static DH_METHOD ibmca_dh = | |
183 | { | |
184 | "Ibmca DH method", | |
185 | NULL, | |
186 | NULL, | |
187 | ibmca_mod_exp_dh, | |
188 | NULL, | |
189 | NULL, | |
190 | 0, | |
191 | NULL | |
192 | }; | |
193 | #endif | |
194 | ||
195 | static RAND_METHOD ibmca_rand = | |
196 | { | |
197 | /* "IBMCA RAND method", */ | |
198 | NULL, | |
199 | ibmca_rand_bytes, | |
200 | NULL, | |
201 | NULL, | |
202 | ibmca_rand_bytes, | |
203 | ibmca_rand_status, | |
204 | }; | |
205 | ||
206 | /* Constants used when creating the ENGINE */ | |
207 | static const char *engine_ibmca_id = "ibmca"; | |
208 | static const char *engine_ibmca_name = "Ibmca hardware engine support"; | |
209 | ||
210 | /* This internal function is used by ENGINE_ibmca() and possibly by the | |
211 | * "dynamic" ENGINE support too */ | |
212 | static int bind_helper(ENGINE *e) | |
213 | { | |
214 | #ifndef OPENSSL_NO_RSA | |
215 | const RSA_METHOD *meth1; | |
216 | #endif | |
217 | #ifndef OPENSSL_NO_DSA | |
218 | const DSA_METHOD *meth2; | |
219 | #endif | |
220 | #ifndef OPENSSL_NO_DH | |
221 | const DH_METHOD *meth3; | |
222 | #endif | |
223 | if(!ENGINE_set_id(e, engine_ibmca_id) || | |
224 | !ENGINE_set_name(e, engine_ibmca_name) || | |
225 | #ifndef OPENSSL_NO_RSA | |
226 | !ENGINE_set_RSA(e, &ibmca_rsa) || | |
227 | #endif | |
228 | #ifndef OPENSSL_NO_DSA | |
229 | !ENGINE_set_DSA(e, &ibmca_dsa) || | |
230 | #endif | |
231 | #ifndef OPENSSL_NO_DH | |
232 | !ENGINE_set_DH(e, &ibmca_dh) || | |
233 | #endif | |
234 | !ENGINE_set_RAND(e, &ibmca_rand) || | |
235 | !ENGINE_set_destroy_function(e, ibmca_destroy) || | |
236 | !ENGINE_set_init_function(e, ibmca_init) || | |
237 | !ENGINE_set_finish_function(e, ibmca_finish) || | |
238 | !ENGINE_set_ctrl_function(e, ibmca_ctrl) || | |
239 | !ENGINE_set_cmd_defns(e, ibmca_cmd_defns)) | |
240 | return 0; | |
241 | ||
242 | #ifndef OPENSSL_NO_RSA | |
243 | /* We know that the "PKCS1_SSLeay()" functions hook properly | |
244 | * to the ibmca-specific mod_exp and mod_exp_crt so we use | |
245 | * those functions. NB: We don't use ENGINE_openssl() or | |
246 | * anything "more generic" because something like the RSAref | |
247 | * code may not hook properly, and if you own one of these | |
248 | * cards then you have the right to do RSA operations on it | |
249 | * anyway! */ | |
250 | meth1 = RSA_PKCS1_SSLeay(); | |
251 | ibmca_rsa.rsa_pub_enc = meth1->rsa_pub_enc; | |
252 | ibmca_rsa.rsa_pub_dec = meth1->rsa_pub_dec; | |
253 | ibmca_rsa.rsa_priv_enc = meth1->rsa_priv_enc; | |
254 | ibmca_rsa.rsa_priv_dec = meth1->rsa_priv_dec; | |
255 | #endif | |
256 | ||
257 | #ifndef OPENSSL_NO_DSA | |
258 | /* Use the DSA_OpenSSL() method and just hook the mod_exp-ish | |
259 | * bits. */ | |
260 | meth2 = DSA_OpenSSL(); | |
261 | ibmca_dsa.dsa_do_sign = meth2->dsa_do_sign; | |
262 | ibmca_dsa.dsa_sign_setup = meth2->dsa_sign_setup; | |
263 | ibmca_dsa.dsa_do_verify = meth2->dsa_do_verify; | |
264 | #endif | |
265 | ||
266 | #ifndef OPENSSL_NO_DH | |
267 | /* Much the same for Diffie-Hellman */ | |
268 | meth3 = DH_OpenSSL(); | |
269 | ibmca_dh.generate_key = meth3->generate_key; | |
270 | ibmca_dh.compute_key = meth3->compute_key; | |
271 | #endif | |
272 | ||
273 | /* Ensure the ibmca error handling is set up */ | |
274 | ERR_load_IBMCA_strings(); | |
275 | return 1; | |
276 | } | |
277 | ||
278 | static ENGINE *engine_ibmca(void) | |
279 | { | |
280 | ENGINE *ret = ENGINE_new(); | |
281 | if(!ret) | |
282 | return NULL; | |
283 | if(!bind_helper(ret)) | |
284 | { | |
285 | ENGINE_free(ret); | |
286 | return NULL; | |
287 | } | |
288 | return ret; | |
289 | } | |
290 | ||
291 | #ifdef ENGINE_DYNAMIC_SUPPORT | |
292 | static | |
293 | #endif | |
294 | void ENGINE_load_ibmca(void) | |
295 | { | |
296 | /* Copied from eng_[openssl|dyn].c */ | |
297 | ENGINE *toadd = engine_ibmca(); | |
298 | if(!toadd) return; | |
299 | ENGINE_add(toadd); | |
300 | ENGINE_free(toadd); | |
301 | ERR_clear_error(); | |
302 | } | |
303 | ||
304 | /* Destructor (complements the "ENGINE_ibmca()" constructor) */ | |
305 | static int ibmca_destroy(ENGINE *e) | |
306 | { | |
307 | /* Unload the ibmca error strings so any error state including our | |
308 | * functs or reasons won't lead to a segfault (they simply get displayed | |
309 | * without corresponding string data because none will be found). */ | |
310 | ERR_unload_IBMCA_strings(); | |
311 | return 1; | |
312 | } | |
313 | ||
314 | ||
315 | /* This is a process-global DSO handle used for loading and unloading | |
316 | * the Ibmca library. NB: This is only set (or unset) during an | |
317 | * init() or finish() call (reference counts permitting) and they're | |
318 | * operating with global locks, so this should be thread-safe | |
319 | * implicitly. */ | |
320 | ||
321 | static DSO *ibmca_dso = NULL; | |
322 | ||
323 | /* These are the function pointers that are (un)set when the library has | |
324 | * successfully (un)loaded. */ | |
325 | ||
326 | static unsigned int (ICA_CALL *p_icaOpenAdapter)(); | |
327 | static unsigned int (ICA_CALL *p_icaCloseAdapter)(); | |
328 | static unsigned int (ICA_CALL *p_icaRsaModExpo)(); | |
329 | static unsigned int (ICA_CALL *p_icaRandomNumberGenerate)(); | |
330 | static unsigned int (ICA_CALL *p_icaRsaCrt)(); | |
331 | ||
332 | /* utility function to obtain a context */ | |
333 | static int get_context(ICA_ADAPTER_HANDLE *p_handle) | |
334 | { | |
335 | unsigned int status=0; | |
336 | ||
337 | status = p_icaOpenAdapter(0, p_handle); | |
338 | if(status != 0) | |
339 | return 0; | |
340 | return 1; | |
341 | } | |
342 | ||
343 | /* similarly to release one. */ | |
344 | static void release_context(ICA_ADAPTER_HANDLE handle) | |
345 | { | |
346 | p_icaCloseAdapter(handle); | |
347 | } | |
348 | ||
349 | /* (de)initialisation functions. */ | |
350 | static int ibmca_init(ENGINE *e) | |
351 | { | |
352 | ||
353 | void (*p1)(); | |
354 | void (*p2)(); | |
355 | void (*p3)(); | |
356 | void (*p4)(); | |
357 | void (*p5)(); | |
358 | ||
359 | if(ibmca_dso != NULL) | |
360 | { | |
361 | IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_ALREADY_LOADED); | |
362 | goto err; | |
363 | } | |
364 | /* Attempt to load libatasi.so/atasi.dll/whatever. Needs to be | |
365 | * changed unfortunately because the Ibmca drivers don't have | |
366 | * standard library names that can be platform-translated well. */ | |
367 | /* TODO: Work out how to actually map to the names the Ibmca | |
368 | * drivers really use - for now a symbollic link needs to be | |
369 | * created on the host system from libatasi.so to atasi.so on | |
370 | * unix variants. */ | |
371 | ||
372 | /* WJH XXX check name translation */ | |
373 | ||
374 | ibmca_dso = DSO_load(NULL, IBMCA_LIBNAME, NULL, | |
375 | /* DSO_FLAG_NAME_TRANSLATION */ 0); | |
376 | if(ibmca_dso == NULL) | |
377 | { | |
378 | IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_DSO_FAILURE); | |
379 | goto err; | |
380 | } | |
381 | ||
382 | if(!(p1 = DSO_bind_func( | |
383 | ibmca_dso, IBMCA_F1)) || | |
384 | !(p2 = DSO_bind_func( | |
385 | ibmca_dso, IBMCA_F2)) || | |
386 | !(p3 = DSO_bind_func( | |
387 | ibmca_dso, IBMCA_F3)) || | |
388 | !(p4 = DSO_bind_func( | |
389 | ibmca_dso, IBMCA_F4)) || | |
390 | !(p5 = DSO_bind_func( | |
391 | ibmca_dso, IBMCA_F5))) | |
392 | { | |
393 | IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_DSO_FAILURE); | |
394 | goto err; | |
395 | } | |
396 | ||
397 | /* Copy the pointers */ | |
398 | ||
399 | p_icaOpenAdapter = (unsigned int (ICA_CALL *)())p1; | |
400 | p_icaCloseAdapter = (unsigned int (ICA_CALL *)())p2; | |
401 | p_icaRsaModExpo = (unsigned int (ICA_CALL *)())p3; | |
402 | p_icaRandomNumberGenerate = (unsigned int (ICA_CALL *)())p4; | |
403 | p_icaRsaCrt = (unsigned int (ICA_CALL *)())p5; | |
404 | ||
405 | if(!get_context(&handle)) | |
406 | { | |
407 | IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_UNIT_FAILURE); | |
408 | goto err; | |
409 | } | |
410 | ||
411 | return 1; | |
412 | err: | |
413 | if(ibmca_dso) | |
414 | DSO_free(ibmca_dso); | |
415 | ||
416 | p_icaOpenAdapter = NULL; | |
417 | p_icaCloseAdapter = NULL; | |
418 | p_icaRsaModExpo = NULL; | |
419 | p_icaRandomNumberGenerate = NULL; | |
420 | ||
421 | return 0; | |
422 | } | |
423 | ||
424 | static int ibmca_finish(ENGINE *e) | |
425 | { | |
426 | if(ibmca_dso == NULL) | |
427 | { | |
428 | IBMCAerr(IBMCA_F_IBMCA_FINISH,IBMCA_R_NOT_LOADED); | |
429 | return 0; | |
430 | } | |
431 | release_context(handle); | |
432 | if(!DSO_free(ibmca_dso)) | |
433 | { | |
434 | IBMCAerr(IBMCA_F_IBMCA_FINISH,IBMCA_R_DSO_FAILURE); | |
435 | return 0; | |
436 | } | |
437 | ibmca_dso = NULL; | |
438 | ||
439 | return 1; | |
440 | } | |
441 | ||
442 | static int ibmca_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)()) | |
443 | { | |
444 | int initialised = ((ibmca_dso == NULL) ? 0 : 1); | |
445 | switch(cmd) | |
446 | { | |
447 | case IBMCA_CMD_SO_PATH: | |
448 | if(p == NULL) | |
449 | { | |
450 | IBMCAerr(IBMCA_F_IBMCA_CTRL,ERR_R_PASSED_NULL_PARAMETER); | |
451 | return 0; | |
452 | } | |
453 | if(initialised) | |
454 | { | |
455 | IBMCAerr(IBMCA_F_IBMCA_CTRL,IBMCA_R_ALREADY_LOADED); | |
456 | return 0; | |
457 | } | |
458 | IBMCA_LIBNAME = (const char *)p; | |
459 | return 1; | |
460 | default: | |
461 | break; | |
462 | } | |
463 | IBMCAerr(IBMCA_F_IBMCA_CTRL,IBMCA_R_CTRL_COMMAND_NOT_IMPLEMENTED); | |
464 | return 0; | |
465 | } | |
466 | ||
467 | ||
468 | static int ibmca_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, | |
469 | const BIGNUM *m, BN_CTX *ctx) | |
470 | { | |
471 | /* I need somewhere to store temporary serialised values for | |
472 | * use with the Ibmca API calls. A neat cheat - I'll use | |
473 | * BIGNUMs from the BN_CTX but access their arrays directly as | |
474 | * byte arrays <grin>. This way I don't have to clean anything | |
475 | * up. */ | |
476 | ||
477 | BIGNUM *argument=NULL; | |
478 | BIGNUM *result=NULL; | |
479 | BIGNUM *key=NULL; | |
480 | int to_return; | |
481 | int inLen, outLen, tmpLen; | |
482 | ||
483 | ||
484 | ICA_KEY_RSA_MODEXPO *publKey=NULL; | |
485 | unsigned int rc; | |
486 | ||
487 | to_return = 0; /* expect failure */ | |
488 | ||
489 | if(!ibmca_dso) | |
490 | { | |
491 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_NOT_LOADED); | |
492 | goto err; | |
493 | } | |
494 | /* Prepare the params */ | |
495 | BN_CTX_start(ctx); | |
496 | argument = BN_CTX_get(ctx); | |
497 | result = BN_CTX_get(ctx); | |
498 | key = BN_CTX_get(ctx); | |
499 | ||
500 | if( !argument || !result || !key) | |
501 | { | |
502 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_BN_CTX_FULL); | |
503 | goto err; | |
504 | } | |
505 | ||
506 | ||
507 | if(!bn_wexpand(argument, m->top) || !bn_wexpand(result, m->top) || | |
508 | !bn_wexpand(key, sizeof(*publKey)/BN_BYTES)) | |
509 | ||
510 | { | |
511 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_BN_EXPAND_FAIL); | |
512 | goto err; | |
513 | } | |
514 | ||
515 | publKey = (ICA_KEY_RSA_MODEXPO *)key->d; | |
516 | ||
517 | if (publKey == NULL) | |
518 | { | |
519 | goto err; | |
520 | } | |
521 | memset(publKey, 0, sizeof(ICA_KEY_RSA_MODEXPO)); | |
522 | ||
523 | publKey->keyType = CORRECT_ENDIANNESS(ME_KEY_TYPE); | |
524 | publKey->keyLength = CORRECT_ENDIANNESS(sizeof(ICA_KEY_RSA_MODEXPO)); | |
525 | publKey->expOffset = (char *) publKey->keyRecord - (char *) publKey; | |
526 | ||
527 | /* A quirk of the card: the exponent length has to be the same | |
528 | as the modulus (key) length */ | |
529 | ||
530 | outLen = BN_num_bytes(m); | |
531 | ||
532 | /* check for modulus length SAB*/ | |
533 | if (outLen > 256 ) { | |
534 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_MEXP_LENGTH_TO_LARGE); | |
535 | goto err; | |
536 | } | |
537 | /* check for modulus length SAB*/ | |
538 | ||
539 | ||
540 | publKey->expLength = publKey->nLength = outLen; | |
541 | /* SAB Check for underflow condition | |
542 | the size of the exponent is less than the size of the parameter | |
543 | then we have a big problem and will underflow the keyRecord | |
544 | buffer. Bad stuff could happen then | |
545 | */ | |
546 | if (outLen < BN_num_bytes(p)){ | |
547 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_UNDERFLOW_KEYRECORD); | |
548 | goto err; | |
549 | } | |
550 | /* SAB End check for underflow */ | |
551 | ||
552 | ||
553 | BN_bn2bin(p, &publKey->keyRecord[publKey->expLength - | |
554 | BN_num_bytes(p)]); | |
555 | BN_bn2bin(m, &publKey->keyRecord[publKey->expLength]); | |
556 | ||
557 | ||
558 | ||
559 | publKey->modulusBitLength = CORRECT_ENDIANNESS(publKey->nLength * 8); | |
560 | publKey->nOffset = CORRECT_ENDIANNESS(publKey->expOffset + | |
561 | publKey->expLength); | |
562 | ||
563 | publKey->expOffset = CORRECT_ENDIANNESS((char *) publKey->keyRecord - | |
564 | (char *) publKey); | |
565 | ||
566 | tmpLen = outLen; | |
567 | publKey->expLength = publKey->nLength = CORRECT_ENDIANNESS(tmpLen); | |
568 | ||
569 | /* Prepare the argument */ | |
570 | ||
571 | memset(argument->d, 0, outLen); | |
572 | BN_bn2bin(a, (unsigned char *)argument->d + outLen - | |
573 | BN_num_bytes(a)); | |
574 | ||
575 | inLen = outLen; | |
576 | ||
577 | /* Perform the operation */ | |
578 | ||
579 | if( (rc = p_icaRsaModExpo(handle, inLen,(unsigned char *)argument->d, | |
580 | publKey, &outLen, (unsigned char *)result->d)) | |
581 | !=0 ) | |
582 | ||
583 | { | |
584 | printf("rc = %d\n", rc); | |
585 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_REQUEST_FAILED); | |
586 | goto err; | |
587 | } | |
588 | ||
589 | ||
590 | /* Convert the response */ | |
591 | BN_bin2bn((unsigned char *)result->d, outLen, r); | |
592 | to_return = 1; | |
593 | err: | |
594 | BN_CTX_end(ctx); | |
595 | return to_return; | |
596 | } | |
597 | ||
598 | #ifndef OPENSSL_NO_RSA | |
599 | static int ibmca_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa) | |
600 | { | |
601 | BN_CTX *ctx; | |
602 | int to_return = 0; | |
603 | ||
604 | if((ctx = BN_CTX_new()) == NULL) | |
605 | goto err; | |
606 | if(!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp) | |
607 | { | |
608 | if(!rsa->d || !rsa->n) | |
609 | { | |
610 | IBMCAerr(IBMCA_F_IBMCA_RSA_MOD_EXP, | |
611 | IBMCA_R_MISSING_KEY_COMPONENTS); | |
612 | goto err; | |
613 | } | |
614 | to_return = ibmca_mod_exp(r0, I, rsa->d, rsa->n, ctx); | |
615 | } | |
616 | else | |
617 | { | |
618 | to_return = ibmca_mod_exp_crt(r0, I, rsa->p, rsa->q, rsa->dmp1, | |
619 | rsa->dmq1, rsa->iqmp, ctx); | |
620 | } | |
621 | err: | |
622 | if(ctx) | |
623 | BN_CTX_free(ctx); | |
624 | return to_return; | |
625 | } | |
626 | #endif | |
627 | ||
628 | /* Ein kleines chinesisches "Restessen" */ | |
629 | static int ibmca_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, | |
630 | const BIGNUM *q, const BIGNUM *dmp1, | |
631 | const BIGNUM *dmq1, const BIGNUM *iqmp, BN_CTX *ctx) | |
632 | { | |
633 | ||
634 | BIGNUM *argument = NULL; | |
635 | BIGNUM *result = NULL; | |
636 | BIGNUM *key = NULL; | |
637 | ||
638 | int to_return = 0; /* expect failure */ | |
639 | ||
640 | char *pkey=NULL; | |
641 | ICA_KEY_RSA_CRT *privKey=NULL; | |
642 | int inLen, outLen; | |
643 | ||
644 | int rc; | |
645 | unsigned int offset, pSize, qSize; | |
646 | /* SAB New variables */ | |
647 | unsigned int keyRecordSize; | |
648 | unsigned int pbytes = BN_num_bytes(p); | |
649 | unsigned int qbytes = BN_num_bytes(q); | |
650 | unsigned int dmp1bytes = BN_num_bytes(dmp1); | |
651 | unsigned int dmq1bytes = BN_num_bytes(dmq1); | |
652 | unsigned int iqmpbytes = BN_num_bytes(iqmp); | |
653 | ||
654 | /* Prepare the params */ | |
655 | ||
656 | BN_CTX_start(ctx); | |
657 | argument = BN_CTX_get(ctx); | |
658 | result = BN_CTX_get(ctx); | |
659 | key = BN_CTX_get(ctx); | |
660 | ||
661 | if(!argument || !result || !key) | |
662 | { | |
663 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_BN_CTX_FULL); | |
664 | goto err; | |
665 | } | |
666 | ||
667 | if(!bn_wexpand(argument, p->top + q->top) || | |
668 | !bn_wexpand(result, p->top + q->top) || | |
669 | !bn_wexpand(key, sizeof(*privKey)/BN_BYTES )) | |
670 | { | |
671 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_BN_EXPAND_FAIL); | |
672 | goto err; | |
673 | } | |
674 | ||
675 | ||
676 | privKey = (ICA_KEY_RSA_CRT *)key->d; | |
677 | /* SAB Add check for total size in bytes of the parms does not exceed | |
678 | the buffer space we have | |
679 | do this first | |
680 | */ | |
681 | keyRecordSize = pbytes+qbytes+dmp1bytes+dmq1bytes+iqmpbytes; | |
682 | if ( keyRecordSize > sizeof(privKey->keyRecord )) { | |
683 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OPERANDS_TO_LARGE); | |
684 | goto err; | |
685 | } | |
686 | ||
687 | if ( (qbytes + dmq1bytes) > 256 ){ | |
688 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OPERANDS_TO_LARGE); | |
689 | goto err; | |
690 | } | |
691 | ||
692 | if ( pbytes + dmp1bytes > 256 ) { | |
693 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OPERANDS_TO_LARGE); | |
694 | goto err; | |
695 | } | |
696 | ||
697 | /* end SAB additions */ | |
698 | ||
699 | memset(privKey, 0, sizeof(ICA_KEY_RSA_CRT)); | |
700 | privKey->keyType = CORRECT_ENDIANNESS(CRT_KEY_TYPE); | |
701 | privKey->keyLength = CORRECT_ENDIANNESS(sizeof(ICA_KEY_RSA_CRT)); | |
702 | privKey->modulusBitLength = | |
703 | CORRECT_ENDIANNESS(BN_num_bytes(q) * 2 * 8); | |
704 | ||
705 | /* | |
706 | * p,dp & qInv are 1 QWORD Larger | |
707 | */ | |
708 | privKey->pLength = CORRECT_ENDIANNESS(BN_num_bytes(p)+8); | |
709 | privKey->qLength = CORRECT_ENDIANNESS(BN_num_bytes(q)); | |
710 | privKey->dpLength = CORRECT_ENDIANNESS(BN_num_bytes(dmp1)+8); | |
711 | privKey->dqLength = CORRECT_ENDIANNESS(BN_num_bytes(dmq1)); | |
712 | privKey->qInvLength = CORRECT_ENDIANNESS(BN_num_bytes(iqmp)+8); | |
713 | ||
714 | offset = (char *) privKey->keyRecord | |
715 | - (char *) privKey; | |
716 | ||
717 | qSize = BN_num_bytes(q); | |
718 | pSize = qSize + 8; /* 1 QWORD larger */ | |
719 | ||
720 | ||
721 | /* SAB probably aittle redundant, but we'll verify that each of the | |
722 | components which make up a key record sent ot the card does not exceed | |
723 | the space that is allocated for it. this handles the case where even if | |
724 | the total length does not exceed keyrecord zied, if the operands are funny sized | |
725 | they could cause potential side affects on either the card or the result */ | |
726 | ||
727 | if ( (pbytes > pSize) || (dmp1bytes > pSize) || | |
728 | (iqmpbytes > pSize) || ( qbytes >qSize) || | |
729 | (dmq1bytes > qSize) ) { | |
730 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_OPERANDS_TO_LARGE); | |
731 | goto err; | |
732 | ||
733 | } | |
734 | ||
735 | ||
736 | privKey->dpOffset = CORRECT_ENDIANNESS(offset); | |
737 | ||
738 | offset += pSize; | |
739 | privKey->dqOffset = CORRECT_ENDIANNESS(offset); | |
740 | ||
741 | offset += qSize; | |
742 | privKey->pOffset = CORRECT_ENDIANNESS(offset); | |
743 | ||
744 | offset += pSize; | |
745 | privKey->qOffset = CORRECT_ENDIANNESS(offset); | |
746 | ||
747 | offset += qSize; | |
748 | privKey->qInvOffset = CORRECT_ENDIANNESS(offset); | |
749 | ||
750 | pkey = (char *) privKey->keyRecord; | |
751 | ||
752 | ||
753 | /* SAB first check that we don;t under flow the buffer */ | |
754 | if ( pSize < pbytes ) { | |
755 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_UNDERFLOW_CONDITION); | |
756 | goto err; | |
757 | } | |
758 | ||
759 | /* pkey += pSize - BN_num_bytes(p); WROING this should be dmp1) */ | |
760 | pkey += pSize - BN_num_bytes(dmp1); | |
761 | BN_bn2bin(dmp1, pkey); | |
762 | pkey += BN_num_bytes(dmp1); /* move the pointer */ | |
763 | ||
764 | BN_bn2bin(dmq1, pkey); /* Copy over dmq1 */ | |
765 | ||
766 | pkey += qSize; /* move pointer */ | |
767 | pkey += pSize - BN_num_bytes(p); /* set up for zero padding of next field */ | |
768 | ||
769 | BN_bn2bin(p, pkey); | |
770 | pkey += BN_num_bytes(p); /* increment pointer by number of bytes moved */ | |
771 | ||
772 | BN_bn2bin(q, pkey); | |
773 | pkey += qSize ; /* move the pointer */ | |
774 | pkey += pSize - BN_num_bytes(iqmp); /* Adjust for padding */ | |
775 | BN_bn2bin(iqmp, pkey); | |
776 | ||
777 | /* Prepare the argument and response */ | |
778 | ||
779 | outLen = CORRECT_ENDIANNESS(privKey->qLength) * 2; /* Correct endianess is used | |
780 | because the fields were converted above */ | |
781 | ||
782 | if (outLen > 256) { | |
783 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OUTLEN_TO_LARGE); | |
784 | goto err; | |
785 | } | |
786 | ||
787 | /* SAB check for underflow here on the argeument */ | |
788 | if ( outLen < BN_num_bytes(a)) { | |
789 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_UNDERFLOW_CONDITION); | |
790 | goto err; | |
791 | } | |
792 | ||
793 | BN_bn2bin(a, (unsigned char *)argument->d + outLen - | |
794 | BN_num_bytes(a)); | |
795 | inLen = outLen; | |
796 | ||
797 | memset(result->d, 0, outLen); | |
798 | ||
799 | /* Perform the operation */ | |
800 | ||
801 | if ( (rc = p_icaRsaCrt(handle, inLen, (unsigned char *)argument->d, | |
802 | privKey, &outLen, (unsigned char *)result->d)) != 0) | |
803 | { | |
804 | printf("rc = %d\n", rc); | |
805 | IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_REQUEST_FAILED); | |
806 | goto err; | |
807 | } | |
808 | ||
809 | /* Convert the response */ | |
810 | ||
811 | BN_bin2bn((unsigned char *)result->d, outLen, r); | |
812 | to_return = 1; | |
813 | ||
814 | err: | |
815 | BN_CTX_end(ctx); | |
816 | return to_return; | |
817 | ||
818 | } | |
819 | ||
820 | #ifndef OPENSSL_NO_DSA | |
821 | /* This code was liberated and adapted from the commented-out code in | |
822 | * dsa_ossl.c. Because of the unoptimised form of the Ibmca acceleration | |
823 | * (it doesn't have a CRT form for RSA), this function means that an | |
824 | * Ibmca system running with a DSA server certificate can handshake | |
825 | * around 5 or 6 times faster/more than an equivalent system running with | |
826 | * RSA. Just check out the "signs" statistics from the RSA and DSA parts | |
827 | * of "openssl speed -engine ibmca dsa1024 rsa1024". */ | |
828 | static int ibmca_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1, | |
829 | BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m, | |
830 | BN_CTX *ctx, BN_MONT_CTX *in_mont) | |
831 | { | |
832 | BIGNUM t; | |
833 | int to_return = 0; | |
834 | ||
835 | BN_init(&t); | |
836 | /* let rr = a1 ^ p1 mod m */ | |
837 | if (!ibmca_mod_exp(rr,a1,p1,m,ctx)) goto end; | |
838 | /* let t = a2 ^ p2 mod m */ | |
839 | if (!ibmca_mod_exp(&t,a2,p2,m,ctx)) goto end; | |
840 | /* let rr = rr * t mod m */ | |
841 | if (!BN_mod_mul(rr,rr,&t,m,ctx)) goto end; | |
842 | to_return = 1; | |
843 | end: | |
844 | BN_free(&t); | |
845 | return to_return; | |
846 | } | |
847 | ||
848 | ||
849 | static int ibmca_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a, | |
850 | const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, | |
851 | BN_MONT_CTX *m_ctx) | |
852 | { | |
853 | return ibmca_mod_exp(r, a, p, m, ctx); | |
854 | } | |
855 | #endif | |
856 | ||
857 | /* This function is aliased to mod_exp (with the mont stuff dropped). */ | |
858 | static int ibmca_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, | |
859 | const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) | |
860 | { | |
861 | return ibmca_mod_exp(r, a, p, m, ctx); | |
862 | } | |
863 | ||
864 | #ifndef OPENSSL_NO_DH | |
865 | /* This function is aliased to mod_exp (with the dh and mont dropped). */ | |
866 | static int ibmca_mod_exp_dh(DH const *dh, BIGNUM *r, | |
867 | const BIGNUM *a, const BIGNUM *p, | |
868 | const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) | |
869 | { | |
870 | return ibmca_mod_exp(r, a, p, m, ctx); | |
871 | } | |
872 | #endif | |
873 | ||
874 | /* Random bytes are good */ | |
875 | static int ibmca_rand_bytes(unsigned char *buf, int num) | |
876 | { | |
877 | int to_return = 0; /* assume failure */ | |
878 | unsigned int ret; | |
879 | ||
880 | ||
881 | if(handle == 0) | |
882 | { | |
883 | IBMCAerr(IBMCA_F_IBMCA_RAND_BYTES,IBMCA_R_NOT_INITIALISED); | |
884 | goto err; | |
885 | } | |
886 | ||
887 | ret = p_icaRandomNumberGenerate(handle, num, buf); | |
888 | if (ret < 0) | |
889 | { | |
890 | IBMCAerr(IBMCA_F_IBMCA_RAND_BYTES,IBMCA_R_REQUEST_FAILED); | |
891 | goto err; | |
892 | } | |
893 | to_return = 1; | |
894 | err: | |
895 | return to_return; | |
896 | } | |
897 | ||
898 | static int ibmca_rand_status(void) | |
899 | { | |
900 | return 1; | |
901 | } | |
902 | ||
903 | /* This stuff is needed if this ENGINE is being compiled into a self-contained | |
904 | * shared-library. */ | |
905 | #ifdef ENGINE_DYNAMIC_SUPPORT | |
906 | static int bind_fn(ENGINE *e, const char *id) | |
907 | { | |
908 | if(id && (strcmp(id, engine_ibmca_id) != 0)) /* WJH XXX */ | |
909 | return 0; | |
910 | if(!bind_helper(e)) | |
911 | return 0; | |
912 | return 1; | |
913 | } | |
914 | IMPLEMENT_DYNAMIC_CHECK_FN() | |
915 | IMPLEMENT_DYNAMIC_BIND_FN(bind_fn) | |
916 | #endif /* ENGINE_DYNAMIC_SUPPORT */ | |
917 | ||
918 | ||
919 | #endif /* !OPENSSL_NO_HW_IBMCA */ | |
920 | #endif /* !OPENSSL_NO_HW */ |