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