Inline function declarations have to be prototypes.
[openssl.git] / engines / e_aep.c
1 /* ====================================================================
2  * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer. 
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * 3. All advertising materials mentioning features or use of this
17  *    software must display the following acknowledgment:
18  *    "This product includes software developed by the OpenSSL Project
19  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
20  *
21  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
22  *    endorse or promote products derived from this software without
23  *    prior written permission. For written permission, please contact
24  *    licensing@OpenSSL.org.
25  *
26  * 5. Products derived from this software may not be called "OpenSSL"
27  *    nor may "OpenSSL" appear in their names without prior written
28  *    permission of the OpenSSL Project.
29  *
30  * 6. Redistributions of any form whatsoever must retain the following
31  *    acknowledgment:
32  *    "This product includes software developed by the OpenSSL Project
33  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
36  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46  * OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This product includes cryptographic software written by Eric Young
50  * (eay@cryptsoft.com).  This product includes software written by Tim
51  * Hudson (tjh@cryptsoft.com).
52  *
53  */
54
55 #include <stdio.h>
56 #include <openssl/bn.h>
57 #include <string.h>
58
59 #include <openssl/e_os2.h>
60 #if !defined(OPENSSL_SYS_MSDOS) || defined(__DJGPP__)
61 #include <sys/types.h>
62 #include <unistd.h>
63 #else
64 #include <process.h>
65 typedef int pid_t;
66 #endif
67
68 #include <openssl/crypto.h>
69 #include <openssl/dso.h>
70 #include <openssl/engine.h>
71 #include <openssl/buffer.h>
72 #ifndef OPENSSL_NO_RSA
73 #include <openssl/rsa.h>
74 #endif
75 #ifndef OPENSSL_NO_DSA
76 #include <openssl/dsa.h>
77 #endif
78 #ifndef OPENSSL_NO_DH
79 #include <openssl/dh.h>
80 #endif
81 #include <openssl/bn.h>
82
83 #ifndef OPENSSL_NO_HW
84 #ifndef OPENSSL_NO_HW_AEP
85 #ifdef FLAT_INC
86 #include "aep.h"
87 #else
88 #include "vendor_defns/aep.h"
89 #endif
90
91 #define AEP_LIB_NAME "aep engine"
92 #define FAIL_TO_SW 0x10101010
93
94 #include "e_aep_err.c"
95
96 static int aep_init(ENGINE *e);
97 static int aep_finish(ENGINE *e);
98 static int aep_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void));
99 static int aep_destroy(ENGINE *e);
100
101 static AEP_RV aep_get_connection(AEP_CONNECTION_HNDL_PTR hConnection);
102 static AEP_RV aep_return_connection(AEP_CONNECTION_HNDL hConnection);
103 static AEP_RV aep_close_connection(AEP_CONNECTION_HNDL hConnection);
104 static AEP_RV aep_close_all_connections(int use_engine_lock, int *in_use);
105
106 /* BIGNUM stuff */
107 #ifndef OPENSSL_NO_RSA
108 static int aep_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
109         const BIGNUM *m, BN_CTX *ctx);
110
111 static AEP_RV aep_mod_exp_crt(BIGNUM *r,const  BIGNUM *a, const BIGNUM *p,
112         const BIGNUM *q, const BIGNUM *dmp1,const BIGNUM *dmq1,
113         const BIGNUM *iqmp, BN_CTX *ctx);
114 #endif
115
116 /* RSA stuff */
117 #ifndef OPENSSL_NO_RSA
118 static int aep_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx);
119 #endif
120
121 /* This function is aliased to mod_exp (with the mont stuff dropped). */
122 #ifndef OPENSSL_NO_RSA
123 static int aep_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
124         const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
125 #endif
126
127 /* DSA stuff */
128 #ifndef OPENSSL_NO_DSA
129 static int aep_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1,
130         BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m,
131         BN_CTX *ctx, BN_MONT_CTX *in_mont);
132
133 static int aep_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a,
134         const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
135         BN_MONT_CTX *m_ctx);
136 #endif
137
138 /* DH stuff */
139 /* This function is aliased to mod_exp (with the DH and mont dropped). */
140 #ifndef OPENSSL_NO_DH
141 static int aep_mod_exp_dh(const DH *dh, BIGNUM *r, const BIGNUM *a,
142         const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
143 #endif
144
145 /* rand stuff   */
146 #ifdef AEPRAND
147 static int aep_rand(unsigned char *buf, int num);
148 static int aep_rand_status(void);
149 #endif
150
151 /* Bignum conversion stuff */
152 static AEP_RV GetBigNumSize(AEP_VOID_PTR ArbBigNum, AEP_U32* BigNumSize);
153 static AEP_RV MakeAEPBigNum(AEP_VOID_PTR ArbBigNum, AEP_U32 BigNumSize,
154         unsigned char* AEP_BigNum);
155 static AEP_RV ConvertAEPBigNum(void* ArbBigNum, AEP_U32 BigNumSize,
156         unsigned char* AEP_BigNum);
157
158 /* The definitions for control commands specific to this engine */
159 #define AEP_CMD_SO_PATH         ENGINE_CMD_BASE
160 static const ENGINE_CMD_DEFN aep_cmd_defns[] =
161         {
162         { AEP_CMD_SO_PATH,
163           "SO_PATH",
164           "Specifies the path to the 'aep' shared library",
165           ENGINE_CMD_FLAG_STRING
166         },
167         {0, NULL, NULL, 0}
168         };
169
170 #ifndef OPENSSL_NO_RSA
171 /* Our internal RSA_METHOD that we provide pointers to */
172 static RSA_METHOD aep_rsa =
173         {
174         "Aep RSA method",
175         NULL,                /*rsa_pub_encrypt*/
176         NULL,                /*rsa_pub_decrypt*/
177         NULL,                /*rsa_priv_encrypt*/
178         NULL,                /*rsa_priv_encrypt*/
179         aep_rsa_mod_exp,     /*rsa_mod_exp*/
180         aep_mod_exp_mont,    /*bn_mod_exp*/
181         NULL,                /*init*/
182         NULL,                /*finish*/
183         0,                   /*flags*/
184         NULL,                /*app_data*/
185         NULL,                /*rsa_sign*/
186         NULL,                /*rsa_verify*/
187         NULL                 /*rsa_keygen*/
188         };
189 #endif
190
191 #ifndef OPENSSL_NO_DSA
192 /* Our internal DSA_METHOD that we provide pointers to */
193 static DSA_METHOD aep_dsa =
194         {
195         "Aep DSA method",
196         NULL,                /* dsa_do_sign */
197         NULL,                /* dsa_sign_setup */
198         NULL,                /* dsa_do_verify */
199         aep_dsa_mod_exp,     /* dsa_mod_exp */
200         aep_mod_exp_dsa,     /* bn_mod_exp */
201         NULL,                /* init */
202         NULL,                /* finish */
203         0,                   /* flags */
204         NULL,                /* app_data */
205         NULL,                /* dsa_paramgen */
206         NULL                 /* dsa_keygen */
207         };
208 #endif
209
210 #ifndef OPENSSL_NO_DH
211 /* Our internal DH_METHOD that we provide pointers to */
212 static DH_METHOD aep_dh =
213         {
214         "Aep DH method",
215         NULL,
216         NULL,
217         aep_mod_exp_dh,
218         NULL,
219         NULL,
220         0,
221         NULL,
222         NULL
223         };
224 #endif
225
226 #ifdef AEPRAND
227 /* our internal RAND_method that we provide pointers to  */
228 static RAND_METHOD aep_random =
229         {
230         /*"AEP RAND method", */
231         NULL,
232         aep_rand,
233         NULL,
234         NULL,
235         aep_rand,
236         aep_rand_status,
237         };
238 #endif
239
240 /*Define an array of structures to hold connections*/
241 static AEP_CONNECTION_ENTRY aep_app_conn_table[MAX_PROCESS_CONNECTIONS];
242
243 /*Used to determine if this is a new process*/
244 static pid_t    recorded_pid = 0;
245
246 #ifdef AEPRAND
247 static AEP_U8   rand_block[RAND_BLK_SIZE];
248 static AEP_U32  rand_block_bytes = 0;
249 #endif
250
251 /* Constants used when creating the ENGINE */
252 static const char *engine_aep_id = "aep";
253 static const char *engine_aep_name = "Aep hardware engine support";
254
255 static int max_key_len = 2176;
256
257
258 /* This internal function is used by ENGINE_aep() and possibly by the
259  * "dynamic" ENGINE support too */
260 static int bind_aep(ENGINE *e)
261         {
262 #ifndef OPENSSL_NO_RSA
263         const RSA_METHOD  *meth1;
264 #endif
265 #ifndef OPENSSL_NO_DSA
266         const DSA_METHOD  *meth2;
267 #endif
268 #ifndef OPENSSL_NO_DH
269         const DH_METHOD   *meth3;
270 #endif
271
272         if(!ENGINE_set_id(e, engine_aep_id) ||
273                 !ENGINE_set_name(e, engine_aep_name) ||
274 #ifndef OPENSSL_NO_RSA
275                 !ENGINE_set_RSA(e, &aep_rsa) ||
276 #endif
277 #ifndef OPENSSL_NO_DSA
278                 !ENGINE_set_DSA(e, &aep_dsa) ||
279 #endif
280 #ifndef OPENSSL_NO_DH
281                 !ENGINE_set_DH(e, &aep_dh) ||
282 #endif
283 #ifdef AEPRAND
284                 !ENGINE_set_RAND(e, &aep_random) ||
285 #endif
286                 !ENGINE_set_init_function(e, aep_init) ||
287                 !ENGINE_set_destroy_function(e, aep_destroy) ||
288                 !ENGINE_set_finish_function(e, aep_finish) ||
289                 !ENGINE_set_ctrl_function(e, aep_ctrl) ||
290                 !ENGINE_set_cmd_defns(e, aep_cmd_defns))
291                 return 0;
292
293 #ifndef OPENSSL_NO_RSA
294         /* We know that the "PKCS1_SSLeay()" functions hook properly
295          * to the aep-specific mod_exp and mod_exp_crt so we use
296          * those functions. NB: We don't use ENGINE_openssl() or
297          * anything "more generic" because something like the RSAref
298          * code may not hook properly, and if you own one of these
299          * cards then you have the right to do RSA operations on it
300          * anyway! */
301         meth1 = RSA_PKCS1_SSLeay();
302         aep_rsa.rsa_pub_enc = meth1->rsa_pub_enc;
303         aep_rsa.rsa_pub_dec = meth1->rsa_pub_dec;
304         aep_rsa.rsa_priv_enc = meth1->rsa_priv_enc;
305         aep_rsa.rsa_priv_dec = meth1->rsa_priv_dec;
306 #endif
307
308
309 #ifndef OPENSSL_NO_DSA
310         /* Use the DSA_OpenSSL() method and just hook the mod_exp-ish
311          * bits. */
312         meth2 = DSA_OpenSSL();
313         aep_dsa.dsa_do_sign    = meth2->dsa_do_sign;
314         aep_dsa.dsa_sign_setup = meth2->dsa_sign_setup;
315         aep_dsa.dsa_do_verify  = meth2->dsa_do_verify;
316
317         aep_dsa = *DSA_get_default_method(); 
318         aep_dsa.dsa_mod_exp = aep_dsa_mod_exp; 
319         aep_dsa.bn_mod_exp = aep_mod_exp_dsa;
320 #endif
321
322 #ifndef OPENSSL_NO_DH
323         /* Much the same for Diffie-Hellman */
324         meth3 = DH_OpenSSL();
325         aep_dh.generate_key = meth3->generate_key;
326         aep_dh.compute_key  = meth3->compute_key;
327         aep_dh.bn_mod_exp   = meth3->bn_mod_exp;
328 #endif
329
330         /* Ensure the aep error handling is set up */
331         ERR_load_AEPHK_strings();
332
333         return 1;
334 }
335
336 #ifndef OPENSSL_NO_DYNAMIC_ENGINE
337 static int bind_helper(ENGINE *e, const char *id)
338         {
339         if(id && (strcmp(id, engine_aep_id) != 0))
340                 return 0;
341         if(!bind_aep(e))
342                 return 0;
343         return 1;
344         }       
345 IMPLEMENT_DYNAMIC_CHECK_FN()
346 IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
347 #else
348 static ENGINE *engine_aep(void)
349         {
350         ENGINE *ret = ENGINE_new();
351         if(!ret)
352                 return NULL;
353         if(!bind_aep(ret))
354                 {
355                 ENGINE_free(ret);
356                 return NULL;
357                 }
358         return ret;
359         }
360
361 void ENGINE_load_aep(void)
362         {
363         /* Copied from eng_[openssl|dyn].c */
364         ENGINE *toadd = engine_aep();
365         if(!toadd) return;
366         ENGINE_add(toadd);
367         ENGINE_free(toadd);
368         ERR_clear_error();
369         }
370 #endif
371
372 /* This is a process-global DSO handle used for loading and unloading
373  * the Aep library. NB: This is only set (or unset) during an
374  * init() or finish() call (reference counts permitting) and they're
375  * operating with global locks, so this should be thread-safe
376  * implicitly. */
377 static DSO *aep_dso = NULL;
378
379 /* These are the static string constants for the DSO file name and the function
380  * symbol names to bind to. 
381 */
382 static const char *AEP_LIBNAME = NULL;
383 static const char *get_AEP_LIBNAME(void)
384         {
385         if(AEP_LIBNAME)
386                 return AEP_LIBNAME;
387         return "aep";
388         }
389 static void free_AEP_LIBNAME(void)
390         {
391         if(AEP_LIBNAME)
392                 OPENSSL_free((void*)AEP_LIBNAME);
393         AEP_LIBNAME = NULL;
394         }
395 static long set_AEP_LIBNAME(const char *name)
396         {
397         free_AEP_LIBNAME();
398         return ((AEP_LIBNAME = BUF_strdup(name)) != NULL ? 1 : 0);
399         }
400
401 static const char *AEP_F1    = "AEP_ModExp";
402 static const char *AEP_F2    = "AEP_ModExpCrt";
403 #ifdef AEPRAND
404 static const char *AEP_F3    = "AEP_GenRandom";
405 #endif
406 static const char *AEP_F4    = "AEP_Finalize";
407 static const char *AEP_F5    = "AEP_Initialize";
408 static const char *AEP_F6    = "AEP_OpenConnection";
409 static const char *AEP_F7    = "AEP_SetBNCallBacks";
410 static const char *AEP_F8    = "AEP_CloseConnection";
411
412 /* These are the function pointers that are (un)set when the library has
413  * successfully (un)loaded. */
414 static t_AEP_OpenConnection    *p_AEP_OpenConnection  = NULL;
415 static t_AEP_CloseConnection   *p_AEP_CloseConnection = NULL;
416 static t_AEP_ModExp            *p_AEP_ModExp          = NULL;
417 static t_AEP_ModExpCrt         *p_AEP_ModExpCrt       = NULL;
418 #ifdef AEPRAND
419 static t_AEP_GenRandom         *p_AEP_GenRandom       = NULL;
420 #endif
421 static t_AEP_Initialize        *p_AEP_Initialize      = NULL;
422 static t_AEP_Finalize          *p_AEP_Finalize        = NULL;
423 static t_AEP_SetBNCallBacks    *p_AEP_SetBNCallBacks  = NULL;
424
425 /* (de)initialisation functions. */
426 static int aep_init(ENGINE *e)
427         {
428         t_AEP_ModExp          *p1;
429         t_AEP_ModExpCrt       *p2;
430 #ifdef AEPRAND
431         t_AEP_GenRandom       *p3;
432 #endif
433         t_AEP_Finalize        *p4;
434         t_AEP_Initialize      *p5;
435         t_AEP_OpenConnection  *p6;
436         t_AEP_SetBNCallBacks  *p7;
437         t_AEP_CloseConnection *p8;
438
439         int to_return = 0;
440  
441         if(aep_dso != NULL)
442                 {
443                 AEPHKerr(AEPHK_F_AEP_INIT,AEPHK_R_ALREADY_LOADED);
444                 goto err;
445                 }
446         /* Attempt to load libaep.so. */
447
448         aep_dso = DSO_load(NULL, get_AEP_LIBNAME(), NULL, 0);
449   
450         if(aep_dso == NULL)
451                 {
452                 AEPHKerr(AEPHK_F_AEP_INIT,AEPHK_R_NOT_LOADED);
453                 goto err;
454                 }
455
456         if(     !(p1 = (t_AEP_ModExp *)     DSO_bind_func( aep_dso,AEP_F1))  ||
457                 !(p2 = (t_AEP_ModExpCrt*)   DSO_bind_func( aep_dso,AEP_F2))  ||
458 #ifdef AEPRAND
459                 !(p3 = (t_AEP_GenRandom*)   DSO_bind_func( aep_dso,AEP_F3))  ||
460 #endif
461                 !(p4 = (t_AEP_Finalize*)    DSO_bind_func( aep_dso,AEP_F4))  ||
462                 !(p5 = (t_AEP_Initialize*)  DSO_bind_func( aep_dso,AEP_F5))  ||
463                 !(p6 = (t_AEP_OpenConnection*) DSO_bind_func( aep_dso,AEP_F6))  ||
464                 !(p7 = (t_AEP_SetBNCallBacks*) DSO_bind_func( aep_dso,AEP_F7))  ||
465                 !(p8 = (t_AEP_CloseConnection*) DSO_bind_func( aep_dso,AEP_F8)))
466                 {
467                 AEPHKerr(AEPHK_F_AEP_INIT,AEPHK_R_NOT_LOADED);
468                 goto err;
469                 }
470
471         /* Copy the pointers */
472   
473         p_AEP_ModExp           = p1;
474         p_AEP_ModExpCrt        = p2;
475 #ifdef AEPRAND
476         p_AEP_GenRandom        = p3;
477 #endif
478         p_AEP_Finalize         = p4;
479         p_AEP_Initialize       = p5;
480         p_AEP_OpenConnection   = p6;
481         p_AEP_SetBNCallBacks   = p7;
482         p_AEP_CloseConnection  = p8;
483  
484         to_return = 1;
485  
486         return to_return;
487
488  err: 
489
490         if(aep_dso)
491                 DSO_free(aep_dso);
492         aep_dso = NULL;
493                 
494         p_AEP_OpenConnection    = NULL;
495         p_AEP_ModExp            = NULL;
496         p_AEP_ModExpCrt         = NULL;
497 #ifdef AEPRAND
498         p_AEP_GenRandom         = NULL;
499 #endif
500         p_AEP_Initialize        = NULL;
501         p_AEP_Finalize          = NULL;
502         p_AEP_SetBNCallBacks    = NULL;
503         p_AEP_CloseConnection   = NULL;
504
505         return to_return;
506         }
507
508 /* Destructor (complements the "ENGINE_aep()" constructor) */
509 static int aep_destroy(ENGINE *e)
510         {
511         free_AEP_LIBNAME();
512         ERR_unload_AEPHK_strings();
513         return 1;
514         }
515
516 static int aep_finish(ENGINE *e)
517         {
518         int to_return = 0, in_use;
519         AEP_RV rv;
520
521         if(aep_dso == NULL)
522                 {
523                 AEPHKerr(AEPHK_F_AEP_FINISH,AEPHK_R_NOT_LOADED);
524                 goto err;
525                 }
526
527         rv = aep_close_all_connections(0, &in_use);
528         if (rv != AEP_R_OK)
529                 {
530                 AEPHKerr(AEPHK_F_AEP_FINISH,AEPHK_R_CLOSE_HANDLES_FAILED);
531                 goto err;
532                 }
533         if (in_use)
534                 {
535                 AEPHKerr(AEPHK_F_AEP_FINISH,AEPHK_R_CONNECTIONS_IN_USE);
536                 goto err;
537                 }
538
539         rv = p_AEP_Finalize();
540         if (rv != AEP_R_OK)
541                 {
542                 AEPHKerr(AEPHK_F_AEP_FINISH,AEPHK_R_FINALIZE_FAILED);
543                 goto err;
544                 }
545
546         if(!DSO_free(aep_dso))
547                 {
548                 AEPHKerr(AEPHK_F_AEP_FINISH,AEPHK_R_UNIT_FAILURE);
549                 goto err;
550                 }
551
552         aep_dso = NULL;
553         p_AEP_CloseConnection   = NULL;
554         p_AEP_OpenConnection    = NULL;
555         p_AEP_ModExp            = NULL;
556         p_AEP_ModExpCrt         = NULL;
557 #ifdef AEPRAND
558         p_AEP_GenRandom         = NULL;
559 #endif
560         p_AEP_Initialize        = NULL;
561         p_AEP_Finalize          = NULL;
562         p_AEP_SetBNCallBacks    = NULL;
563
564         to_return = 1;
565  err:
566         return to_return;
567         }
568
569 static int aep_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void))
570         {
571         int initialised = ((aep_dso == NULL) ? 0 : 1);
572         switch(cmd)
573                 {
574         case AEP_CMD_SO_PATH:
575                 if(p == NULL)
576                         {
577                         AEPHKerr(AEPHK_F_AEP_CTRL,
578                                 ERR_R_PASSED_NULL_PARAMETER);
579                         return 0;
580                         }
581                 if(initialised)
582                         {
583                         AEPHKerr(AEPHK_F_AEP_CTRL,
584                                 AEPHK_R_ALREADY_LOADED);
585                         return 0;
586                         }
587                 return set_AEP_LIBNAME((const char*)p);
588         default:
589                 break;
590                 }
591         AEPHKerr(AEPHK_F_AEP_CTRL,AEPHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
592         return 0;
593         }
594
595 static int aep_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
596         const BIGNUM *m, BN_CTX *ctx)
597         {
598         int to_return = 0;
599         int     r_len = 0;
600         AEP_CONNECTION_HNDL hConnection;
601         AEP_RV rv;
602         
603         r_len = BN_num_bits(m);
604
605         /* Perform in software if modulus is too large for hardware. */
606
607         if (r_len > max_key_len){
608                 AEPHKerr(AEPHK_F_AEP_MOD_EXP, AEPHK_R_SIZE_TOO_LARGE_OR_TOO_SMALL);
609                 return BN_mod_exp(r, a, p, m, ctx);
610         } 
611
612         /*Grab a connection from the pool*/
613         rv = aep_get_connection(&hConnection);
614         if (rv != AEP_R_OK)
615                 {     
616                 AEPHKerr(AEPHK_F_AEP_MOD_EXP,AEPHK_R_GET_HANDLE_FAILED);
617                 return BN_mod_exp(r, a, p, m, ctx);
618                 }
619
620         /*To the card with the mod exp*/
621         rv = p_AEP_ModExp(hConnection,(void*)a, (void*)p,(void*)m, (void*)r,NULL);
622
623         if (rv !=  AEP_R_OK)
624                 {
625                 AEPHKerr(AEPHK_F_AEP_MOD_EXP,AEPHK_R_MOD_EXP_FAILED);
626                 rv = aep_close_connection(hConnection);
627                 return BN_mod_exp(r, a, p, m, ctx);
628                 }
629
630         /*Return the connection to the pool*/
631         rv = aep_return_connection(hConnection);
632         if (rv != AEP_R_OK)
633                 {
634                 AEPHKerr(AEPHK_F_AEP_MOD_EXP,AEPHK_R_RETURN_CONNECTION_FAILED); 
635                 goto err;
636                 }
637
638         to_return = 1;
639  err:
640         return to_return;
641         }
642         
643 #ifndef OPENSSL_NO_RSA
644 static AEP_RV aep_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
645         const BIGNUM *q, const BIGNUM *dmp1,
646         const BIGNUM *dmq1,const BIGNUM *iqmp, BN_CTX *ctx)
647         {
648         AEP_RV rv = AEP_R_OK;
649         AEP_CONNECTION_HNDL hConnection;
650
651         /*Grab a connection from the pool*/
652         rv = aep_get_connection(&hConnection);
653         if (rv != AEP_R_OK)
654                 {
655                 AEPHKerr(AEPHK_F_AEP_MOD_EXP_CRT,AEPHK_R_GET_HANDLE_FAILED);
656                 return FAIL_TO_SW;
657                 }
658
659         /*To the card with the mod exp*/
660         rv = p_AEP_ModExpCrt(hConnection,(void*)a, (void*)p, (void*)q, (void*)dmp1,(void*)dmq1,
661                 (void*)iqmp,(void*)r,NULL);
662         if (rv != AEP_R_OK)
663                 {
664                 AEPHKerr(AEPHK_F_AEP_MOD_EXP_CRT,AEPHK_R_MOD_EXP_CRT_FAILED);
665                 rv = aep_close_connection(hConnection);
666                 return FAIL_TO_SW;
667                 }
668
669         /*Return the connection to the pool*/
670         rv = aep_return_connection(hConnection);
671         if (rv != AEP_R_OK)
672                 {
673                 AEPHKerr(AEPHK_F_AEP_MOD_EXP_CRT,AEPHK_R_RETURN_CONNECTION_FAILED); 
674                 goto err;
675                 }
676  
677  err:
678         return rv;
679         }
680 #endif
681         
682
683 #ifdef AEPRAND
684 static int aep_rand(unsigned char *buf,int len )
685         {
686         AEP_RV rv = AEP_R_OK;
687         AEP_CONNECTION_HNDL hConnection;
688
689         CRYPTO_w_lock(CRYPTO_LOCK_RAND);
690
691         /*Can the request be serviced with what's already in the buffer?*/
692         if (len <= rand_block_bytes)
693                 {
694                 memcpy(buf, &rand_block[RAND_BLK_SIZE - rand_block_bytes], len);
695                 rand_block_bytes -= len;
696                 CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
697                 }
698         else
699                 /*If not the get another block of random bytes*/
700                 {
701                 CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
702
703                 rv = aep_get_connection(&hConnection);
704                 if (rv !=  AEP_R_OK)
705                         { 
706                         AEPHKerr(AEPHK_F_AEP_RAND,AEPHK_R_GET_HANDLE_FAILED);             
707                         goto err_nounlock;
708                         }
709
710                 if (len > RAND_BLK_SIZE)
711                         {
712                         rv = p_AEP_GenRandom(hConnection, len, 2, buf, NULL);
713                         if (rv !=  AEP_R_OK)
714                                 {  
715                                 AEPHKerr(AEPHK_F_AEP_RAND,AEPHK_R_GET_RANDOM_FAILED); 
716                                 goto err_nounlock;
717                                 }
718                         }
719                 else
720                         {
721                         CRYPTO_w_lock(CRYPTO_LOCK_RAND);
722
723                         rv = p_AEP_GenRandom(hConnection, RAND_BLK_SIZE, 2, &rand_block[0], NULL);
724                         if (rv !=  AEP_R_OK)
725                                 {       
726                                 AEPHKerr(AEPHK_F_AEP_RAND,AEPHK_R_GET_RANDOM_FAILED); 
727               
728                                 goto err;
729                                 }
730
731                         rand_block_bytes = RAND_BLK_SIZE;
732
733                         memcpy(buf, &rand_block[RAND_BLK_SIZE - rand_block_bytes], len);
734                         rand_block_bytes -= len;
735
736                         CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
737                         }
738
739                 rv = aep_return_connection(hConnection);
740                 if (rv != AEP_R_OK)
741                         {
742                         AEPHKerr(AEPHK_F_AEP_RAND,AEPHK_R_RETURN_CONNECTION_FAILED); 
743           
744                         goto err_nounlock;
745                         }
746                 }
747   
748         return 1;
749  err:
750         CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
751  err_nounlock:
752         return 0;
753         }
754         
755 static int aep_rand_status(void)
756 {
757         return 1;
758 }
759 #endif
760
761 #ifndef OPENSSL_NO_RSA
762 static int aep_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
763         {
764         int to_return = 0;
765         AEP_RV rv = AEP_R_OK;
766
767         if (!aep_dso)
768                 {
769                 AEPHKerr(AEPHK_F_AEP_RSA_MOD_EXP,AEPHK_R_NOT_LOADED);
770                 goto err;
771                 }
772
773         /*See if we have all the necessary bits for a crt*/
774         if (rsa->q && rsa->dmp1 && rsa->dmq1 && rsa->iqmp)
775                 {
776                 rv =  aep_mod_exp_crt(r0,I,rsa->p,rsa->q, rsa->dmp1,rsa->dmq1,rsa->iqmp,ctx);
777
778                 if (rv == FAIL_TO_SW){
779                         const RSA_METHOD *meth = RSA_PKCS1_SSLeay();
780                         to_return = (*meth->rsa_mod_exp)(r0, I, rsa, ctx);
781                         goto err;
782                 }
783                 else if (rv != AEP_R_OK)
784                         goto err;
785                 }
786         else
787                 {
788                 if (!rsa->d || !rsa->n)
789                         {
790                         AEPHKerr(AEPHK_F_AEP_RSA_MOD_EXP,AEPHK_R_MISSING_KEY_COMPONENTS);
791                         goto err;
792                         }
793  
794                 rv = aep_mod_exp(r0,I,rsa->d,rsa->n,ctx);
795                 if  (rv != AEP_R_OK)
796                         goto err;
797         
798                 }
799
800         to_return = 1;
801
802  err:
803         return to_return;
804 }
805 #endif
806
807 #ifndef OPENSSL_NO_DSA
808 static int aep_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1,
809         BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m,
810         BN_CTX *ctx, BN_MONT_CTX *in_mont)
811         {
812         BIGNUM t;
813         int to_return = 0;
814         BN_init(&t);
815
816         /* let rr = a1 ^ p1 mod m */
817         if (!aep_mod_exp(rr,a1,p1,m,ctx)) goto end;
818         /* let t = a2 ^ p2 mod m */
819         if (!aep_mod_exp(&t,a2,p2,m,ctx)) goto end;
820         /* let rr = rr * t mod m */
821         if (!BN_mod_mul(rr,rr,&t,m,ctx)) goto end;
822         to_return = 1;
823  end: 
824         BN_free(&t);
825         return to_return;
826         }
827
828 static int aep_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a,
829         const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
830         BN_MONT_CTX *m_ctx)
831         {  
832         return aep_mod_exp(r, a, p, m, ctx); 
833         }
834 #endif
835
836 #ifndef OPENSSL_NO_RSA
837 /* This function is aliased to mod_exp (with the mont stuff dropped). */
838 static int aep_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
839         const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
840         {
841         return aep_mod_exp(r, a, p, m, ctx);
842         }
843 #endif
844
845 #ifndef OPENSSL_NO_DH
846 /* This function is aliased to mod_exp (with the dh and mont dropped). */
847 static int aep_mod_exp_dh(const DH *dh, BIGNUM *r, const BIGNUM *a,
848         const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
849         BN_MONT_CTX *m_ctx)
850         {
851         return aep_mod_exp(r, a, p, m, ctx);
852         }
853 #endif
854
855 static AEP_RV aep_get_connection(AEP_CONNECTION_HNDL_PTR phConnection)
856         {
857         int count;
858         AEP_RV rv = AEP_R_OK;
859
860         /*Get the current process id*/
861         pid_t curr_pid;
862
863         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
864
865 #ifndef NETWARE_CLIB
866         curr_pid = getpid();
867 #else
868         curr_pid = GetThreadID();
869 #endif
870
871         /*Check if this is the first time this is being called from the current
872           process*/
873         if (recorded_pid != curr_pid)
874                 {
875                 /*Remember our pid so we can check if we're in a new process*/
876                 recorded_pid = curr_pid;
877
878                 /*Call Finalize to make sure we have not inherited some data
879                   from a parent process*/
880                 p_AEP_Finalize();
881      
882                 /*Initialise the AEP API*/
883                 rv = p_AEP_Initialize(NULL);
884
885                 if (rv != AEP_R_OK)
886                         {
887                         AEPHKerr(AEPHK_F_AEP_GET_CONNECTION,AEPHK_R_INIT_FAILURE);
888                         recorded_pid = 0;
889                         goto end;
890                         }
891
892                 /*Set the AEP big num call back functions*/
893                 rv = p_AEP_SetBNCallBacks(&GetBigNumSize, &MakeAEPBigNum,
894                         &ConvertAEPBigNum);
895
896                 if (rv != AEP_R_OK)
897                         {
898                         AEPHKerr(AEPHK_F_AEP_GET_CONNECTION,AEPHK_R_SETBNCALLBACK_FAILURE);
899                         recorded_pid = 0;
900                         goto end;
901                         }
902
903 #ifdef AEPRAND
904                 /*Reset the rand byte count*/
905                 rand_block_bytes = 0;
906 #endif
907
908                 /*Init the structures*/
909                 for (count = 0;count < MAX_PROCESS_CONNECTIONS;count ++)
910                         {
911                         aep_app_conn_table[count].conn_state = NotConnected;
912                         aep_app_conn_table[count].conn_hndl  = 0;
913                         }
914
915                 /*Open a connection*/
916                 rv = p_AEP_OpenConnection(phConnection);
917
918                 if (rv != AEP_R_OK)
919                         {
920                         AEPHKerr(AEPHK_F_AEP_GET_CONNECTION,AEPHK_R_UNIT_FAILURE);
921                         recorded_pid = 0;
922                         goto end;
923                         }
924
925                 aep_app_conn_table[0].conn_state = InUse;
926                 aep_app_conn_table[0].conn_hndl = *phConnection;
927                 goto end;
928                 }
929         /*Check the existing connections to see if we can find a free one*/
930         for (count = 0;count < MAX_PROCESS_CONNECTIONS;count ++)
931                 {
932                 if (aep_app_conn_table[count].conn_state == Connected)
933                         {
934                         aep_app_conn_table[count].conn_state = InUse;
935                         *phConnection = aep_app_conn_table[count].conn_hndl;
936                         goto end;
937                         }
938                 }
939         /*If no connections available, we're going to have to try
940           to open a new one*/
941         for (count = 0;count < MAX_PROCESS_CONNECTIONS;count ++)
942                 {
943                 if (aep_app_conn_table[count].conn_state == NotConnected)
944                         {
945                         /*Open a connection*/
946                         rv = p_AEP_OpenConnection(phConnection);
947
948                         if (rv != AEP_R_OK)
949                                 {             
950                                 AEPHKerr(AEPHK_F_AEP_GET_CONNECTION,AEPHK_R_UNIT_FAILURE);
951                                 goto end;
952                                 }
953
954                         aep_app_conn_table[count].conn_state = InUse;
955                         aep_app_conn_table[count].conn_hndl = *phConnection;
956                         goto end;
957                         }
958                 }
959         rv = AEP_R_GENERAL_ERROR;
960  end:
961         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
962         return rv;
963         }
964
965
966 static AEP_RV aep_return_connection(AEP_CONNECTION_HNDL hConnection)
967         {
968         int count;
969
970         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
971
972         /*Find the connection item that matches this connection handle*/
973         for(count = 0;count < MAX_PROCESS_CONNECTIONS;count ++)
974                 {
975                 if (aep_app_conn_table[count].conn_hndl == hConnection)
976                         {
977                         aep_app_conn_table[count].conn_state = Connected;
978                         break;
979                         }
980                 }
981
982         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
983
984         return AEP_R_OK;
985         }
986
987 static AEP_RV aep_close_connection(AEP_CONNECTION_HNDL hConnection)
988         {
989         int count;
990         AEP_RV rv = AEP_R_OK;
991
992         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
993
994         /*Find the connection item that matches this connection handle*/
995         for(count = 0;count < MAX_PROCESS_CONNECTIONS;count ++)
996                 {
997                 if (aep_app_conn_table[count].conn_hndl == hConnection)
998                         {
999                         rv = p_AEP_CloseConnection(aep_app_conn_table[count].conn_hndl);
1000                         if (rv != AEP_R_OK)
1001                                 goto end;
1002                         aep_app_conn_table[count].conn_state = NotConnected;
1003                         aep_app_conn_table[count].conn_hndl  = 0;
1004                         break;
1005                         }
1006                 }
1007
1008  end:
1009         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
1010         return rv;
1011         }
1012
1013 static AEP_RV aep_close_all_connections(int use_engine_lock, int *in_use)
1014         {
1015         int count;
1016         AEP_RV rv = AEP_R_OK;
1017
1018         *in_use = 0;
1019         if (use_engine_lock) CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
1020         for (count = 0;count < MAX_PROCESS_CONNECTIONS;count ++)
1021                 {
1022                 switch (aep_app_conn_table[count].conn_state)
1023                         {
1024                 case Connected:
1025                         rv = p_AEP_CloseConnection(aep_app_conn_table[count].conn_hndl);
1026                         if (rv != AEP_R_OK)
1027                                 goto end;
1028                         aep_app_conn_table[count].conn_state = NotConnected;
1029                         aep_app_conn_table[count].conn_hndl  = 0;
1030                         break;
1031                 case InUse:
1032                         (*in_use)++;
1033                         break;
1034                 case NotConnected:
1035                         break;
1036                         }
1037                 }
1038  end:
1039         if (use_engine_lock) CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
1040         return rv;
1041         }
1042
1043 /*BigNum call back functions, used to convert OpenSSL bignums into AEP bignums.
1044   Note only 32bit Openssl build support*/
1045
1046 static AEP_RV GetBigNumSize(AEP_VOID_PTR ArbBigNum, AEP_U32* BigNumSize)
1047         {
1048         BIGNUM* bn;
1049
1050         /*Cast the ArbBigNum pointer to our BIGNUM struct*/
1051         bn = (BIGNUM*) ArbBigNum;
1052
1053 #ifdef SIXTY_FOUR_BIT_LONG
1054         *BigNumSize = bn->top << 3;
1055 #else
1056         /*Size of the bignum in bytes is equal to the bn->top (no of 32 bit
1057           words) multiplies by 4*/
1058         *BigNumSize = bn->top << 2;
1059 #endif
1060
1061         return AEP_R_OK;
1062         }
1063
1064 static AEP_RV MakeAEPBigNum(AEP_VOID_PTR ArbBigNum, AEP_U32 BigNumSize,
1065         unsigned char* AEP_BigNum)
1066         {
1067         BIGNUM* bn;
1068
1069 #ifndef SIXTY_FOUR_BIT_LONG
1070         unsigned char* buf;
1071         int i;
1072 #endif
1073
1074         /*Cast the ArbBigNum pointer to our BIGNUM struct*/
1075         bn = (BIGNUM*) ArbBigNum;
1076
1077 #ifdef SIXTY_FOUR_BIT_LONG
1078         memcpy(AEP_BigNum, bn->d, BigNumSize);
1079 #else
1080         /*Must copy data into a (monotone) least significant byte first format
1081           performing endian conversion if necessary*/
1082         for(i=0;i<bn->top;i++)
1083                 {
1084                 buf = (unsigned char*)&bn->d[i];
1085
1086                 *((AEP_U32*)AEP_BigNum) = (AEP_U32)
1087                         ((unsigned) buf[1] << 8 | buf[0]) |
1088                         ((unsigned) buf[3] << 8 | buf[2])  << 16;
1089
1090                 AEP_BigNum += 4;
1091                 }
1092 #endif
1093
1094         return AEP_R_OK;
1095         }
1096
1097 /*Turn an AEP Big Num back to a user big num*/
1098 static AEP_RV ConvertAEPBigNum(void* ArbBigNum, AEP_U32 BigNumSize,
1099         unsigned char* AEP_BigNum)
1100         {
1101         BIGNUM* bn;
1102 #ifndef SIXTY_FOUR_BIT_LONG
1103         int i;
1104 #endif
1105
1106         bn = (BIGNUM*)ArbBigNum;
1107
1108         /*Expand the result bn so that it can hold our big num.
1109           Size is in bits*/
1110         bn_expand(bn, (int)(BigNumSize << 3));
1111
1112 #ifdef SIXTY_FOUR_BIT_LONG
1113         bn->top = BigNumSize >> 3;
1114         
1115         if((BigNumSize & 7) != 0)
1116                 bn->top++;
1117
1118         memset(bn->d, 0, bn->top << 3); 
1119
1120         memcpy(bn->d, AEP_BigNum, BigNumSize);
1121 #else
1122         bn->top = BigNumSize >> 2;
1123  
1124         for(i=0;i<bn->top;i++)
1125                 {
1126                 bn->d[i] = (AEP_U32)
1127                         ((unsigned) AEP_BigNum[3] << 8 | AEP_BigNum[2]) << 16 |
1128                         ((unsigned) AEP_BigNum[1] << 8 | AEP_BigNum[0]);
1129                 AEP_BigNum += 4;
1130                 }
1131 #endif
1132
1133         return AEP_R_OK;
1134 }       
1135         
1136 #endif /* !OPENSSL_NO_HW_AEP */
1137 #endif /* !OPENSSL_NO_HW */