add test
[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 void ENGINE_load_ibmca(void)\r
292         {\r
293         /* Copied from eng_[openssl|dyn].c */\r
294         ENGINE *toadd = engine_ibmca();\r
295         if(!toadd) return;\r
296         ENGINE_add(toadd);\r
297         ENGINE_free(toadd);\r
298         ERR_clear_error();\r
299         }\r
300 \r
301 /* Destructor (complements the "ENGINE_ibmca()" constructor) */\r
302 static int ibmca_destroy(ENGINE *e)\r
303         {\r
304         /* Unload the ibmca error strings so any error state including our\r
305          * functs or reasons won't lead to a segfault (they simply get displayed\r
306          * without corresponding string data because none will be found). */\r
307         ERR_unload_IBMCA_strings(); \r
308         return 1;\r
309         }\r
310 \r
311 \r
312 /* This is a process-global DSO handle used for loading and unloading\r
313  * the Ibmca library. NB: This is only set (or unset) during an\r
314  * init() or finish() call (reference counts permitting) and they're\r
315  * operating with global locks, so this should be thread-safe\r
316  * implicitly. */\r
317 \r
318 static DSO *ibmca_dso = NULL;\r
319 \r
320 /* These are the function pointers that are (un)set when the library has\r
321  * successfully (un)loaded. */\r
322 \r
323 static unsigned int    (ICA_CALL *p_icaOpenAdapter)();\r
324 static unsigned int    (ICA_CALL *p_icaCloseAdapter)();\r
325 static unsigned int    (ICA_CALL *p_icaRsaModExpo)();\r
326 static unsigned int    (ICA_CALL *p_icaRandomNumberGenerate)();\r
327 static unsigned int    (ICA_CALL *p_icaRsaCrt)();\r
328 \r
329 /* utility function to obtain a context */\r
330 static int get_context(ICA_ADAPTER_HANDLE *p_handle)\r
331         {\r
332         unsigned int status=0;\r
333 \r
334         status = p_icaOpenAdapter(0, p_handle);\r
335         if(status != 0)\r
336                 return 0;\r
337         return 1;\r
338         }\r
339 \r
340 /* similarly to release one. */\r
341 static void release_context(ICA_ADAPTER_HANDLE handle)\r
342         {\r
343         p_icaCloseAdapter(handle);\r
344         }\r
345 \r
346 /* (de)initialisation functions. */\r
347 static int ibmca_init(ENGINE *e)\r
348         {\r
349 \r
350         void          (*p1)();\r
351         void          (*p2)();\r
352         void          (*p3)();\r
353         void          (*p4)();\r
354         void          (*p5)();\r
355 \r
356         if(ibmca_dso != NULL)\r
357                 {\r
358                 IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_ALREADY_LOADED);\r
359                 goto err;\r
360                 }\r
361         /* Attempt to load libatasi.so/atasi.dll/whatever. Needs to be\r
362          * changed unfortunately because the Ibmca drivers don't have\r
363          * standard library names that can be platform-translated well. */\r
364         /* TODO: Work out how to actually map to the names the Ibmca\r
365          * drivers really use - for now a symbollic link needs to be\r
366          * created on the host system from libatasi.so to atasi.so on\r
367          * unix variants. */\r
368 \r
369         /* WJH XXX check name translation */\r
370 \r
371         ibmca_dso = DSO_load(NULL, IBMCA_LIBNAME, NULL,\r
372                              /* DSO_FLAG_NAME_TRANSLATION */ 0);\r
373         if(ibmca_dso == NULL)\r
374                 {\r
375                 IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_DSO_FAILURE);\r
376                 goto err;\r
377                 }\r
378 \r
379         if(!(p1 = DSO_bind_func(\r
380                 ibmca_dso, IBMCA_F1)) ||\r
381                 !(p2 = DSO_bind_func(\r
382                         ibmca_dso, IBMCA_F2)) ||\r
383                 !(p3 = DSO_bind_func(\r
384                         ibmca_dso, IBMCA_F3)) ||\r
385                 !(p4 = DSO_bind_func(\r
386                         ibmca_dso, IBMCA_F4)) ||\r
387                 !(p5 = DSO_bind_func(\r
388                         ibmca_dso, IBMCA_F5)))\r
389                 {\r
390                 IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_DSO_FAILURE);\r
391                 goto err;\r
392                 }\r
393 \r
394         /* Copy the pointers */\r
395 \r
396         p_icaOpenAdapter =           (unsigned int (ICA_CALL *)())p1;\r
397         p_icaCloseAdapter =          (unsigned int (ICA_CALL *)())p2;\r
398         p_icaRsaModExpo =            (unsigned int (ICA_CALL *)())p3;\r
399         p_icaRandomNumberGenerate =  (unsigned int (ICA_CALL *)())p4;\r
400         p_icaRsaCrt =                (unsigned int (ICA_CALL *)())p5;\r
401 \r
402         if(!get_context(&handle))\r
403                 {\r
404                 IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_UNIT_FAILURE);\r
405                 goto err;\r
406                 }\r
407 \r
408         return 1;\r
409  err:\r
410         if(ibmca_dso)\r
411                 DSO_free(ibmca_dso);\r
412 \r
413         p_icaOpenAdapter = NULL;\r
414         p_icaCloseAdapter = NULL;\r
415         p_icaRsaModExpo = NULL;\r
416         p_icaRandomNumberGenerate = NULL;\r
417 \r
418         return 0;\r
419         }\r
420 \r
421 static int ibmca_finish(ENGINE *e)\r
422         {\r
423         if(ibmca_dso == NULL)\r
424                 {\r
425                 IBMCAerr(IBMCA_F_IBMCA_FINISH,IBMCA_R_NOT_LOADED);\r
426                 return 0;\r
427                 }\r
428         release_context(handle);\r
429         if(!DSO_free(ibmca_dso))\r
430                 {\r
431                 IBMCAerr(IBMCA_F_IBMCA_FINISH,IBMCA_R_DSO_FAILURE);\r
432                 return 0;\r
433                 }\r
434         ibmca_dso = NULL;\r
435 \r
436         return 1;\r
437         }\r
438 \r
439 static int ibmca_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())\r
440         {\r
441         int initialised = ((ibmca_dso == NULL) ? 0 : 1);\r
442         switch(cmd)\r
443                 {\r
444         case IBMCA_CMD_SO_PATH:\r
445                 if(p == NULL)\r
446                         {\r
447                         IBMCAerr(IBMCA_F_IBMCA_CTRL,ERR_R_PASSED_NULL_PARAMETER);\r
448                         return 0;\r
449                         }\r
450                 if(initialised)\r
451                         {\r
452                         IBMCAerr(IBMCA_F_IBMCA_CTRL,IBMCA_R_ALREADY_LOADED);\r
453                         return 0;\r
454                         }\r
455                 IBMCA_LIBNAME = (const char *)p;\r
456                 return 1;\r
457         default:\r
458                 break;\r
459                 }\r
460         IBMCAerr(IBMCA_F_IBMCA_CTRL,IBMCA_R_CTRL_COMMAND_NOT_IMPLEMENTED);\r
461         return 0;\r
462         }\r
463 \r
464 \r
465 static int ibmca_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,\r
466         const BIGNUM *m, BN_CTX *ctx)\r
467         {\r
468         /* I need somewhere to store temporary serialised values for\r
469          * use with the Ibmca API calls. A neat cheat - I'll use\r
470          * BIGNUMs from the BN_CTX but access their arrays directly as\r
471          * byte arrays <grin>. This way I don't have to clean anything\r
472          * up. */\r
473 \r
474         BIGNUM *argument=NULL;\r
475         BIGNUM *result=NULL;\r
476         BIGNUM *key=NULL;\r
477         int to_return;\r
478         int inLen, outLen, tmpLen;\r
479 \r
480 \r
481         ICA_KEY_RSA_MODEXPO *publKey=NULL;\r
482         unsigned int rc;\r
483 \r
484         to_return = 0; /* expect failure */\r
485 \r
486         if(!ibmca_dso)\r
487                 {\r
488                 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_NOT_LOADED);\r
489                 goto err;\r
490                 }\r
491         /* Prepare the params */\r
492         BN_CTX_start(ctx);\r
493         argument = BN_CTX_get(ctx);\r
494         result = BN_CTX_get(ctx);\r
495         key = BN_CTX_get(ctx);\r
496 \r
497         if( !argument || !result || !key)\r
498                 {\r
499                 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_BN_CTX_FULL);\r
500                 goto err;\r
501                 }\r
502 \r
503 \r
504         if(!bn_wexpand(argument, m->top) || !bn_wexpand(result, m->top) ||\r
505                 !bn_wexpand(key, sizeof(*publKey)/BN_BYTES))\r
506 \r
507                 {\r
508                 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_BN_EXPAND_FAIL);\r
509                 goto err;\r
510                 }\r
511 \r
512         publKey = (ICA_KEY_RSA_MODEXPO *)key->d;\r
513 \r
514         if (publKey == NULL)\r
515                 {\r
516                 goto err;\r
517                 }\r
518         memset(publKey, 0, sizeof(ICA_KEY_RSA_MODEXPO));\r
519 \r
520         publKey->keyType   =  CORRECT_ENDIANNESS(ME_KEY_TYPE);\r
521         publKey->keyLength =  CORRECT_ENDIANNESS(sizeof(ICA_KEY_RSA_MODEXPO));\r
522         publKey->expOffset =  (char *) publKey->keyRecord - (char *) publKey;\r
523 \r
524         /* A quirk of the card: the exponent length has to be the same\r
525      as the modulus (key) length */\r
526 \r
527         outLen = BN_num_bytes(m);\r
528 \r
529 /* check for modulus length SAB*/\r
530         if (outLen > 256 ) {\r
531                 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_MEXP_LENGTH_TO_LARGE);\r
532                 goto err;\r
533         }\r
534 /* check for modulus length SAB*/\r
535 \r
536 \r
537         publKey->expLength = publKey->nLength = outLen;\r
538 /* SAB Check for underflow condition\r
539     the size of the exponent is less than the size of the parameter\r
540     then we have a big problem and will underflow the keyRecord\r
541    buffer.  Bad stuff could happen then\r
542 */\r
543 if (outLen < BN_num_bytes(p)){\r
544         IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_UNDERFLOW_KEYRECORD);\r
545         goto err;\r
546 }\r
547 /* SAB End check for underflow */\r
548 \r
549 \r
550         BN_bn2bin(p, &publKey->keyRecord[publKey->expLength -\r
551                 BN_num_bytes(p)]);\r
552         BN_bn2bin(m, &publKey->keyRecord[publKey->expLength]);\r
553 \r
554 \r
555 \r
556         publKey->modulusBitLength = CORRECT_ENDIANNESS(publKey->nLength * 8);\r
557         publKey->nOffset   = CORRECT_ENDIANNESS(publKey->expOffset + \r
558                                                 publKey->expLength);\r
559 \r
560         publKey->expOffset = CORRECT_ENDIANNESS((char *) publKey->keyRecord - \r
561                                                 (char *) publKey);\r
562 \r
563         tmpLen = outLen;\r
564         publKey->expLength = publKey->nLength = CORRECT_ENDIANNESS(tmpLen);\r
565 \r
566   /* Prepare the argument */\r
567 \r
568         memset(argument->d, 0, outLen);\r
569         BN_bn2bin(a, (unsigned char *)argument->d + outLen -\r
570                  BN_num_bytes(a));\r
571 \r
572         inLen = outLen;\r
573 \r
574   /* Perform the operation */\r
575 \r
576           if( (rc = p_icaRsaModExpo(handle, inLen,(unsigned char *)argument->d,\r
577                 publKey, &outLen, (unsigned char *)result->d))\r
578                 !=0 )\r
579 \r
580                 {\r
581                 printf("rc = %d\n", rc);\r
582                 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_REQUEST_FAILED);\r
583                 goto err;\r
584                 }\r
585 \r
586 \r
587         /* Convert the response */\r
588         BN_bin2bn((unsigned char *)result->d, outLen, r);\r
589         to_return = 1;\r
590  err:\r
591         BN_CTX_end(ctx);\r
592         return to_return;\r
593         }\r
594 \r
595 #ifndef OPENSSL_NO_RSA \r
596 static int ibmca_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa)\r
597         {\r
598         BN_CTX *ctx;\r
599         int to_return = 0;\r
600 \r
601         if((ctx = BN_CTX_new()) == NULL)\r
602                 goto err;\r
603         if(!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp)\r
604                 {\r
605                 if(!rsa->d || !rsa->n)\r
606                         {\r
607                         IBMCAerr(IBMCA_F_IBMCA_RSA_MOD_EXP,\r
608                                 IBMCA_R_MISSING_KEY_COMPONENTS);\r
609                         goto err;\r
610                         }\r
611                 to_return = ibmca_mod_exp(r0, I, rsa->d, rsa->n, ctx);\r
612                 }\r
613         else\r
614                 {\r
615                 to_return = ibmca_mod_exp_crt(r0, I, rsa->p, rsa->q, rsa->dmp1,\r
616                         rsa->dmq1, rsa->iqmp, ctx);\r
617                 }\r
618  err:\r
619         if(ctx)\r
620                 BN_CTX_free(ctx);\r
621         return to_return;\r
622         }\r
623 #endif\r
624 \r
625 /* Ein kleines chinesisches "Restessen"  */\r
626 static int ibmca_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,\r
627         const BIGNUM *q, const BIGNUM *dmp1,\r
628         const BIGNUM *dmq1, const BIGNUM *iqmp, BN_CTX *ctx)\r
629         {\r
630 \r
631         BIGNUM *argument = NULL;\r
632         BIGNUM *result = NULL;\r
633         BIGNUM *key = NULL;\r
634 \r
635         int to_return = 0; /* expect failure */\r
636 \r
637         char                *pkey=NULL;\r
638         ICA_KEY_RSA_CRT     *privKey=NULL;\r
639         int inLen, outLen;\r
640 \r
641         int rc;\r
642         unsigned int        offset, pSize, qSize;\r
643 /* SAB New variables */\r
644         unsigned int keyRecordSize;\r
645         unsigned int pbytes = BN_num_bytes(p);\r
646         unsigned int qbytes = BN_num_bytes(q);\r
647         unsigned int dmp1bytes = BN_num_bytes(dmp1);\r
648         unsigned int dmq1bytes = BN_num_bytes(dmq1);\r
649         unsigned int iqmpbytes = BN_num_bytes(iqmp);\r
650 \r
651         /* Prepare the params */\r
652 \r
653         BN_CTX_start(ctx);\r
654         argument = BN_CTX_get(ctx);\r
655         result = BN_CTX_get(ctx);\r
656         key = BN_CTX_get(ctx);\r
657 \r
658         if(!argument || !result || !key)\r
659                 {\r
660                 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_BN_CTX_FULL);\r
661                 goto err;\r
662                 }\r
663 \r
664         if(!bn_wexpand(argument, p->top + q->top) ||\r
665                 !bn_wexpand(result, p->top + q->top) ||\r
666                 !bn_wexpand(key, sizeof(*privKey)/BN_BYTES ))\r
667                 {\r
668                 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_BN_EXPAND_FAIL);\r
669                 goto err;\r
670                 }\r
671 \r
672 \r
673         privKey = (ICA_KEY_RSA_CRT *)key->d;\r
674 /* SAB Add check for total size in bytes of the parms does not exceed\r
675    the buffer space we have\r
676    do this first\r
677 */\r
678       keyRecordSize = pbytes+qbytes+dmp1bytes+dmq1bytes+iqmpbytes;\r
679      if (  keyRecordSize > sizeof(privKey->keyRecord )) {\r
680          IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OPERANDS_TO_LARGE);\r
681          goto err;\r
682      }\r
683 \r
684      if ( (qbytes + dmq1bytes)  > 256 ){\r
685          IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OPERANDS_TO_LARGE);\r
686          goto err;\r
687      }\r
688 \r
689      if ( pbytes + dmp1bytes > 256 ) {\r
690          IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OPERANDS_TO_LARGE);\r
691          goto err;\r
692      }\r
693 \r
694 /* end SAB additions */\r
695   \r
696         memset(privKey, 0, sizeof(ICA_KEY_RSA_CRT));\r
697         privKey->keyType =  CORRECT_ENDIANNESS(CRT_KEY_TYPE);\r
698         privKey->keyLength = CORRECT_ENDIANNESS(sizeof(ICA_KEY_RSA_CRT));\r
699         privKey->modulusBitLength = \r
700           CORRECT_ENDIANNESS(BN_num_bytes(q) * 2 * 8);\r
701 \r
702         /*\r
703          * p,dp & qInv are 1 QWORD Larger\r
704          */\r
705         privKey->pLength = CORRECT_ENDIANNESS(BN_num_bytes(p)+8);\r
706         privKey->qLength = CORRECT_ENDIANNESS(BN_num_bytes(q));\r
707         privKey->dpLength = CORRECT_ENDIANNESS(BN_num_bytes(dmp1)+8);\r
708         privKey->dqLength = CORRECT_ENDIANNESS(BN_num_bytes(dmq1));\r
709         privKey->qInvLength = CORRECT_ENDIANNESS(BN_num_bytes(iqmp)+8);\r
710 \r
711         offset = (char *) privKey->keyRecord\r
712                   - (char *) privKey;\r
713 \r
714         qSize = BN_num_bytes(q);\r
715         pSize = qSize + 8;   /*  1 QWORD larger */\r
716 \r
717 \r
718 /* SAB  probably aittle redundant, but we'll verify that each of the\r
719    components which make up a key record sent ot the card does not exceed\r
720    the space that is allocated for it.  this handles the case where even if\r
721    the total length does not exceed keyrecord zied, if the operands are funny sized\r
722 they could cause potential side affects on either the card or the result */\r
723 \r
724      if ( (pbytes > pSize) || (dmp1bytes > pSize) ||\r
725           (iqmpbytes > pSize) || ( qbytes >qSize) ||\r
726           (dmq1bytes > qSize) ) {\r
727                 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_OPERANDS_TO_LARGE);\r
728                 goto err;\r
729 \r
730         }\r
731      \r
732 \r
733         privKey->dpOffset = CORRECT_ENDIANNESS(offset);\r
734 \r
735         offset += pSize;\r
736         privKey->dqOffset = CORRECT_ENDIANNESS(offset);\r
737 \r
738         offset += qSize;\r
739         privKey->pOffset = CORRECT_ENDIANNESS(offset);\r
740 \r
741         offset += pSize;\r
742         privKey->qOffset = CORRECT_ENDIANNESS(offset);\r
743 \r
744         offset += qSize;\r
745         privKey->qInvOffset = CORRECT_ENDIANNESS(offset);\r
746 \r
747         pkey = (char *) privKey->keyRecord;\r
748 \r
749 \r
750 /* SAB first check that we don;t under flow the buffer */\r
751         if ( pSize < pbytes ) {\r
752                 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_UNDERFLOW_CONDITION);\r
753                 goto err;\r
754         }\r
755 \r
756         /* pkey += pSize - BN_num_bytes(p); WROING this should be dmp1) */\r
757         pkey += pSize - BN_num_bytes(dmp1);\r
758         BN_bn2bin(dmp1, pkey);   \r
759         pkey += BN_num_bytes(dmp1);  /* move the pointer */\r
760 \r
761         BN_bn2bin(dmq1, pkey);  /* Copy over dmq1 */\r
762 \r
763         pkey += qSize;     /* move pointer */\r
764         pkey += pSize - BN_num_bytes(p);  /* set up for zero padding of next field */\r
765 \r
766         BN_bn2bin(p, pkey);\r
767         pkey += BN_num_bytes(p);  /* increment pointer by number of bytes moved  */\r
768 \r
769         BN_bn2bin(q, pkey);\r
770         pkey += qSize ;  /* move the pointer */\r
771         pkey +=  pSize - BN_num_bytes(iqmp); /* Adjust for padding */\r
772         BN_bn2bin(iqmp, pkey);\r
773 \r
774         /* Prepare the argument and response */\r
775 \r
776         outLen = CORRECT_ENDIANNESS(privKey->qLength) * 2;  /* Correct endianess is used \r
777                                                 because the fields were converted above */\r
778 \r
779         if (outLen > 256) {\r
780                 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OUTLEN_TO_LARGE);\r
781                 goto err;\r
782         }\r
783 \r
784         /* SAB check for underflow here on the argeument */\r
785         if ( outLen < BN_num_bytes(a)) {\r
786                 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_UNDERFLOW_CONDITION);\r
787                 goto err;\r
788         }\r
789 \r
790         BN_bn2bin(a, (unsigned char *)argument->d + outLen -\r
791                           BN_num_bytes(a));\r
792         inLen = outLen;\r
793 \r
794         memset(result->d, 0, outLen);\r
795 \r
796         /* Perform the operation */\r
797 \r
798         if ( (rc = p_icaRsaCrt(handle, inLen, (unsigned char *)argument->d,\r
799                 privKey, &outLen, (unsigned char *)result->d)) != 0)\r
800                 {\r
801                 printf("rc = %d\n", rc);\r
802                 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_REQUEST_FAILED);\r
803                 goto err;\r
804                 }\r
805 \r
806         /* Convert the response */\r
807 \r
808         BN_bin2bn((unsigned char *)result->d, outLen, r);\r
809         to_return = 1;\r
810 \r
811  err:\r
812         BN_CTX_end(ctx);\r
813         return to_return;\r
814 \r
815         }\r
816 \r
817 #ifndef OPENSSL_NO_DSA\r
818 /* This code was liberated and adapted from the commented-out code in\r
819  * dsa_ossl.c. Because of the unoptimised form of the Ibmca acceleration\r
820  * (it doesn't have a CRT form for RSA), this function means that an\r
821  * Ibmca system running with a DSA server certificate can handshake\r
822  * around 5 or 6 times faster/more than an equivalent system running with\r
823  * RSA. Just check out the "signs" statistics from the RSA and DSA parts\r
824  * of "openssl speed -engine ibmca dsa1024 rsa1024". */\r
825 static int ibmca_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1,\r
826         BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m,\r
827         BN_CTX *ctx, BN_MONT_CTX *in_mont)\r
828         {\r
829         BIGNUM t;\r
830         int to_return = 0;\r
831 \r
832         BN_init(&t);\r
833         /* let rr = a1 ^ p1 mod m */\r
834         if (!ibmca_mod_exp(rr,a1,p1,m,ctx)) goto end;\r
835         /* let t = a2 ^ p2 mod m */\r
836         if (!ibmca_mod_exp(&t,a2,p2,m,ctx)) goto end;\r
837         /* let rr = rr * t mod m */\r
838         if (!BN_mod_mul(rr,rr,&t,m,ctx)) goto end;\r
839         to_return = 1;\r
840  end:\r
841         BN_free(&t);\r
842         return to_return;\r
843         }\r
844 \r
845 \r
846 static int ibmca_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a,\r
847         const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,\r
848         BN_MONT_CTX *m_ctx)\r
849         {\r
850         return ibmca_mod_exp(r, a, p, m, ctx);\r
851         }\r
852 #endif\r
853 \r
854 /* This function is aliased to mod_exp (with the mont stuff dropped). */\r
855 static int ibmca_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,\r
856         const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)\r
857         {\r
858         return ibmca_mod_exp(r, a, p, m, ctx);\r
859         }\r
860 \r
861 #ifndef OPENSSL_NO_DH \r
862 /* This function is aliased to mod_exp (with the dh and mont dropped). */\r
863 static int ibmca_mod_exp_dh(DH const *dh, BIGNUM *r, \r
864         const BIGNUM *a, const BIGNUM *p, \r
865         const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)\r
866         {\r
867         return ibmca_mod_exp(r, a, p, m, ctx);\r
868         }\r
869 #endif\r
870 \r
871 /* Random bytes are good */\r
872 static int ibmca_rand_bytes(unsigned char *buf, int num)\r
873         {\r
874         int to_return = 0; /* assume failure */\r
875         unsigned int ret;\r
876 \r
877 \r
878         if(handle == 0)\r
879                 {\r
880                 IBMCAerr(IBMCA_F_IBMCA_RAND_BYTES,IBMCA_R_NOT_INITIALISED);\r
881                 goto err;\r
882                 }\r
883 \r
884         ret = p_icaRandomNumberGenerate(handle, num, buf);\r
885         if (ret < 0)\r
886                 {\r
887                 IBMCAerr(IBMCA_F_IBMCA_RAND_BYTES,IBMCA_R_REQUEST_FAILED);\r
888                 goto err;\r
889                 }\r
890         to_return = 1;\r
891  err:\r
892         return to_return;\r
893         }\r
894 \r
895 static int ibmca_rand_status(void)\r
896         {\r
897         return 1;\r
898         }\r
899 \r
900 /* This stuff is needed if this ENGINE is being compiled into a self-contained\r
901  * shared-library. */\r
902 #ifdef ENGINE_DYNAMIC_SUPPORT\r
903 static int bind_fn(ENGINE *e, const char *id)\r
904         {\r
905         if(id && (strcmp(id, engine_ibmca_id) != 0))  /* WJH XXX */\r
906                 return 0;\r
907         if(!bind_helper(e))\r
908                 return 0;\r
909         return 1;\r
910         }\r
911 IMPLEMENT_DYNAMIC_CHECK_FN()\r
912 IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)\r
913 #endif /* ENGINE_DYNAMIC_SUPPORT */\r
914 \r
915 \r
916 #endif /* !OPENSSL_NO_HW_IBMCA */\r
917 #endif /* !OPENSSL_NO_HW */\r