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