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