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