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