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
78static int ibmca_destroy(ENGINE *e);
79static int ibmca_init(ENGINE *e);
80static int ibmca_finish(ENGINE *e);
81static int ibmca_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)());
82
83static const char *IBMCA_F1 = "icaOpenAdapter";
84static const char *IBMCA_F2 = "icaCloseAdapter";
85static const char *IBMCA_F3 = "icaRsaModExpo";
86static const char *IBMCA_F4 = "icaRandomNumberGenerate";
87static const char *IBMCA_F5 = "icaRsaCrt";
88
89ICA_ADAPTER_HANDLE handle=0;
90
91/* BIGNUM stuff */
92static int ibmca_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
93        const BIGNUM *m, BN_CTX *ctx);
94
95static 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 */
101static 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). */
105static 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 */
110static 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);
113static 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). */
121static 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 */
127static int ibmca_rand_bytes(unsigned char *buf, int num);
128static 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
135static 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 */
145static 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 */
165static 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 */
182static 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
195static 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 */
207static const char *engine_ibmca_id = "ibmca";
208static 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 */
212static 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
278static 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
292static
293#endif
294void 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) */
305static 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
321static DSO *ibmca_dso = NULL;
322
323/* These are the function pointers that are (un)set when the library has
324 * successfully (un)loaded. */
325
326static unsigned int    (ICA_CALL *p_icaOpenAdapter)();
327static unsigned int    (ICA_CALL *p_icaCloseAdapter)();
328static unsigned int    (ICA_CALL *p_icaRsaModExpo)();
329static unsigned int    (ICA_CALL *p_icaRandomNumberGenerate)();
330static unsigned int    (ICA_CALL *p_icaRsaCrt)();
331
332/* utility function to obtain a context */
333static 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. */
344static void release_context(ICA_ADAPTER_HANDLE handle)
345        {
346        p_icaCloseAdapter(handle);
347        }
348
349/* (de)initialisation functions. */
350static 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
424static 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
442static 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
468static 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*/
546if (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
599static 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"  */
629static 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
725they could cause potential side affects on either the card or the result */
726
727     if ( (pbytes > pSize) || (dmp1bytes > pSize) ||
728          (iqmpbytes > pSize) || ( qbytes >qSize) ||
729          (dmq1bytes > qSize) ) {
730		IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_OPERANDS_TO_LARGE);
731		goto err;
732
733	}
734
735
736        privKey->dpOffset = CORRECT_ENDIANNESS(offset);
737
738	offset += pSize;
739	privKey->dqOffset = CORRECT_ENDIANNESS(offset);
740
741	offset += qSize;
742	privKey->pOffset = CORRECT_ENDIANNESS(offset);
743
744	offset += pSize;
745	privKey->qOffset = CORRECT_ENDIANNESS(offset);
746
747	offset += qSize;
748	privKey->qInvOffset = CORRECT_ENDIANNESS(offset);
749
750        pkey = (char *) privKey->keyRecord;
751
752
753/* SAB first check that we don;t under flow the buffer */
754	if ( pSize < pbytes ) {
755		IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_UNDERFLOW_CONDITION);
756		goto err;
757	}
758
759        /* pkey += pSize - BN_num_bytes(p); WROING this should be dmp1) */
760        pkey += pSize - BN_num_bytes(dmp1);
761        BN_bn2bin(dmp1, pkey);
762        pkey += BN_num_bytes(dmp1);  /* move the pointer */
763
764        BN_bn2bin(dmq1, pkey);  /* Copy over dmq1 */
765
766        pkey += qSize;     /* move pointer */
767	pkey += pSize - BN_num_bytes(p);  /* set up for zero padding of next field */
768
769        BN_bn2bin(p, pkey);
770        pkey += BN_num_bytes(p);  /* increment pointer by number of bytes moved  */
771
772        BN_bn2bin(q, pkey);
773        pkey += qSize ;  /* move the pointer */
774	pkey +=  pSize - BN_num_bytes(iqmp); /* Adjust for padding */
775        BN_bn2bin(iqmp, pkey);
776
777        /* Prepare the argument and response */
778
779	outLen = CORRECT_ENDIANNESS(privKey->qLength) * 2;  /* Correct endianess is used
780						because the fields were converted above */
781
782        if (outLen > 256) {
783		IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OUTLEN_TO_LARGE);
784		goto err;
785	}
786
787	/* SAB check for underflow here on the argeument */
788	if ( outLen < BN_num_bytes(a)) {
789		IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_UNDERFLOW_CONDITION);
790		goto err;
791	}
792
793        BN_bn2bin(a, (unsigned char *)argument->d + outLen -
794                          BN_num_bytes(a));
795        inLen = outLen;
796
797        memset(result->d, 0, outLen);
798
799        /* Perform the operation */
800
801        if ( (rc = p_icaRsaCrt(handle, inLen, (unsigned char *)argument->d,
802                privKey, &outLen, (unsigned char *)result->d)) != 0)
803                {
804                printf("rc = %d\n", rc);
805                IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_REQUEST_FAILED);
806                goto err;
807                }
808
809        /* Convert the response */
810
811        BN_bin2bn((unsigned char *)result->d, outLen, r);
812        to_return = 1;
813
814 err:
815	BN_CTX_end(ctx);
816        return to_return;
817
818        }
819
820#ifndef OPENSSL_NO_DSA
821/* This code was liberated and adapted from the commented-out code in
822 * dsa_ossl.c. Because of the unoptimised form of the Ibmca acceleration
823 * (it doesn't have a CRT form for RSA), this function means that an
824 * Ibmca system running with a DSA server certificate can handshake
825 * around 5 or 6 times faster/more than an equivalent system running with
826 * RSA. Just check out the "signs" statistics from the RSA and DSA parts
827 * of "openssl speed -engine ibmca dsa1024 rsa1024". */
828static int ibmca_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1,
829        BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m,
830        BN_CTX *ctx, BN_MONT_CTX *in_mont)
831        {
832        BIGNUM t;
833        int to_return = 0;
834
835        BN_init(&t);
836        /* let rr = a1 ^ p1 mod m */
837        if (!ibmca_mod_exp(rr,a1,p1,m,ctx)) goto end;
838        /* let t = a2 ^ p2 mod m */
839        if (!ibmca_mod_exp(&t,a2,p2,m,ctx)) goto end;
840        /* let rr = rr * t mod m */
841        if (!BN_mod_mul(rr,rr,&t,m,ctx)) goto end;
842        to_return = 1;
843 end:
844        BN_free(&t);
845        return to_return;
846        }
847
848
849static int ibmca_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a,
850        const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
851        BN_MONT_CTX *m_ctx)
852        {
853        return ibmca_mod_exp(r, a, p, m, ctx);
854        }
855#endif
856
857/* This function is aliased to mod_exp (with the mont stuff dropped). */
858static int ibmca_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
859        const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
860        {
861        return ibmca_mod_exp(r, a, p, m, ctx);
862        }
863
864#ifndef OPENSSL_NO_DH
865/* This function is aliased to mod_exp (with the dh and mont dropped). */
866static int ibmca_mod_exp_dh(DH const *dh, BIGNUM *r,
867	const BIGNUM *a, const BIGNUM *p,
868	const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
869        {
870        return ibmca_mod_exp(r, a, p, m, ctx);
871        }
872#endif
873
874/* Random bytes are good */
875static int ibmca_rand_bytes(unsigned char *buf, int num)
876        {
877        int to_return = 0; /* assume failure */
878        unsigned int ret;
879
880
881        if(handle == 0)
882                {
883                IBMCAerr(IBMCA_F_IBMCA_RAND_BYTES,IBMCA_R_NOT_INITIALISED);
884                goto err;
885                }
886
887        ret = p_icaRandomNumberGenerate(handle, num, buf);
888        if (ret < 0)
889                {
890                IBMCAerr(IBMCA_F_IBMCA_RAND_BYTES,IBMCA_R_REQUEST_FAILED);
891                goto err;
892                }
893        to_return = 1;
894 err:
895        return to_return;
896        }
897
898static int ibmca_rand_status(void)
899        {
900        return 1;
901        }
902
903/* This stuff is needed if this ENGINE is being compiled into a self-contained
904 * shared-library. */
905#ifdef ENGINE_DYNAMIC_SUPPORT
906static int bind_fn(ENGINE *e, const char *id)
907	{
908	if(id && (strcmp(id, engine_ibmca_id) != 0))  /* WJH XXX */
909		return 0;
910	if(!bind_helper(e))
911		return 0;
912	return 1;
913	}
914IMPLEMENT_DYNAMIC_CHECK_FN()
915IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
916#endif /* ENGINE_DYNAMIC_SUPPORT */
917
918
919#endif /* !OPENSSL_NO_HW_IBMCA */
920#endif /* !OPENSSL_NO_HW */
921