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