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