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