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