Silence Clang warning about unit'd variable
[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     if (aep_dso == NULL) {
466         AEPHKerr(AEPHK_F_AEP_INIT, AEPHK_R_NOT_LOADED);
467         goto err;
468     }
469
470 #define BINDIT(t, name) (t *)DSO_bind_func(aep_dso, name)
471     if ((p1 = BINDIT(t_AEP_ModExp, AEP_F1)) == NULL
472         || (p2 = BINDIT(t_AEP_ModExpCrt, AEP_F2)) == NULL
473 #  ifdef AEPRAND
474         || (p3 = BINDIT(t_AEP_GenRandom, AEP_F3)) == NULL
475 #  endif
476         || (p4 = BINDIT(t_AEP_Finalize, AEP_F4)) == NULL
477         || (p5 = BINDIT(t_AEP_Initialize, AEP_F5)) == NULL
478         || (p6 = BINDIT(t_AEP_OpenConnection, AEP_F6)) == NULL
479         || (p7 = BINDIT(t_AEP_SetBNCallBacks, AEP_F7)) == NULL
480         || (p8 = BINDIT(t_AEP_CloseConnection, AEP_F8)) == NULL) {
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     DSO_free(aep_dso);
505     aep_dso = NULL;
506
507     p_AEP_OpenConnection = NULL;
508     p_AEP_ModExp = NULL;
509     p_AEP_ModExpCrt = NULL;
510 #  ifdef AEPRAND
511     p_AEP_GenRandom = NULL;
512 #  endif
513     p_AEP_Initialize = NULL;
514     p_AEP_Finalize = NULL;
515     p_AEP_SetBNCallBacks = NULL;
516     p_AEP_CloseConnection = NULL;
517
518     return to_return;
519 }
520
521 /* Destructor (complements the "ENGINE_aep()" constructor) */
522 static int aep_destroy(ENGINE *e)
523 {
524     free_AEP_LIBNAME();
525     ERR_unload_AEPHK_strings();
526     return 1;
527 }
528
529 static int aep_finish(ENGINE *e)
530 {
531     int to_return = 0, in_use;
532     AEP_RV rv;
533
534     if (aep_dso == NULL) {
535         AEPHKerr(AEPHK_F_AEP_FINISH, AEPHK_R_NOT_LOADED);
536         goto err;
537     }
538
539     rv = aep_close_all_connections(0, &in_use);
540     if (rv != AEP_R_OK) {
541         AEPHKerr(AEPHK_F_AEP_FINISH, AEPHK_R_CLOSE_HANDLES_FAILED);
542         goto err;
543     }
544     if (in_use) {
545         AEPHKerr(AEPHK_F_AEP_FINISH, AEPHK_R_CONNECTIONS_IN_USE);
546         goto err;
547     }
548
549     rv = p_AEP_Finalize();
550     if (rv != AEP_R_OK) {
551         AEPHKerr(AEPHK_F_AEP_FINISH, AEPHK_R_FINALIZE_FAILED);
552         goto err;
553     }
554
555     if (!DSO_free(aep_dso)) {
556         AEPHKerr(AEPHK_F_AEP_FINISH, AEPHK_R_UNIT_FAILURE);
557         goto err;
558     }
559
560     aep_dso = NULL;
561     p_AEP_CloseConnection = NULL;
562     p_AEP_OpenConnection = NULL;
563     p_AEP_ModExp = NULL;
564     p_AEP_ModExpCrt = NULL;
565 #  ifdef AEPRAND
566     p_AEP_GenRandom = NULL;
567 #  endif
568     p_AEP_Initialize = NULL;
569     p_AEP_Finalize = NULL;
570     p_AEP_SetBNCallBacks = NULL;
571
572     to_return = 1;
573  err:
574     return to_return;
575 }
576
577 static int aep_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
578 {
579     int initialised = ((aep_dso == NULL) ? 0 : 1);
580     switch (cmd) {
581     case AEP_CMD_SO_PATH:
582         if (p == NULL) {
583             AEPHKerr(AEPHK_F_AEP_CTRL, ERR_R_PASSED_NULL_PARAMETER);
584             return 0;
585         }
586         if (initialised) {
587             AEPHKerr(AEPHK_F_AEP_CTRL, AEPHK_R_ALREADY_LOADED);
588             return 0;
589         }
590         return set_AEP_LIBNAME((const char *)p);
591     default:
592         break;
593     }
594     AEPHKerr(AEPHK_F_AEP_CTRL, AEPHK_R_CTRL_COMMAND_NOT_IMPLEMENTED);
595     return 0;
596 }
597
598 static int aep_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
599                        const BIGNUM *m, BN_CTX *ctx)
600 {
601     int to_return = 0;
602     int r_len = 0;
603     AEP_CONNECTION_HNDL hConnection;
604     AEP_RV rv;
605
606     r_len = BN_num_bits(m);
607
608     /* Perform in software if modulus is too large for hardware. */
609
610     if (r_len > max_key_len) {
611         AEPHKerr(AEPHK_F_AEP_MOD_EXP, AEPHK_R_SIZE_TOO_LARGE_OR_TOO_SMALL);
612         return BN_mod_exp(r, a, p, m, ctx);
613     }
614
615     /*
616      * Grab a connection from the pool
617      */
618     rv = aep_get_connection(&hConnection);
619     if (rv != AEP_R_OK) {
620         AEPHKerr(AEPHK_F_AEP_MOD_EXP, AEPHK_R_GET_HANDLE_FAILED);
621         return BN_mod_exp(r, a, p, m, ctx);
622     }
623
624     /*
625      * To the card with the mod exp
626      */
627     rv = p_AEP_ModExp(hConnection, (void *)a, (void *)p, (void *)m, (void *)r,
628                       NULL);
629
630     if (rv != AEP_R_OK) {
631         AEPHKerr(AEPHK_F_AEP_MOD_EXP, AEPHK_R_MOD_EXP_FAILED);
632         rv = aep_close_connection(hConnection);
633         return BN_mod_exp(r, a, p, m, ctx);
634     }
635
636     /*
637      * Return the connection to the pool
638      */
639     rv = aep_return_connection(hConnection);
640     if (rv != AEP_R_OK) {
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,
654                               BN_CTX *ctx)
655 {
656     AEP_RV rv = AEP_R_OK;
657     AEP_CONNECTION_HNDL hConnection;
658
659     /*
660      * Grab a connection from the pool
661      */
662     rv = aep_get_connection(&hConnection);
663     if (rv != AEP_R_OK) {
664         AEPHKerr(AEPHK_F_AEP_MOD_EXP_CRT, AEPHK_R_GET_HANDLE_FAILED);
665         return FAIL_TO_SW;
666     }
667
668     /*
669      * To the card with the mod exp
670      */
671     rv = p_AEP_ModExpCrt(hConnection, (void *)a, (void *)p, (void *)q,
672                          (void *)dmp1, (void *)dmq1, (void *)iqmp, (void *)r,
673                          NULL);
674     if (rv != AEP_R_OK) {
675         AEPHKerr(AEPHK_F_AEP_MOD_EXP_CRT, AEPHK_R_MOD_EXP_CRT_FAILED);
676         rv = aep_close_connection(hConnection);
677         return FAIL_TO_SW;
678     }
679
680     /*
681      * Return the connection to the pool
682      */
683     rv = aep_return_connection(hConnection);
684     if (rv != AEP_R_OK) {
685         AEPHKerr(AEPHK_F_AEP_MOD_EXP_CRT, AEPHK_R_RETURN_CONNECTION_FAILED);
686         goto err;
687     }
688
689  err:
690     return rv;
691 }
692 #  endif
693
694 #  ifdef AEPRAND
695 static int aep_rand(unsigned char *buf, int len)
696 {
697     AEP_RV rv = AEP_R_OK;
698     AEP_CONNECTION_HNDL hConnection;
699
700     CRYPTO_w_lock(CRYPTO_LOCK_RAND);
701
702     /*
703      * Can the request be serviced with what's already in the buffer?
704      */
705     if (len <= rand_block_bytes) {
706         memcpy(buf, &rand_block[RAND_BLK_SIZE - rand_block_bytes], len);
707         rand_block_bytes -= len;
708         CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
709     } else
710         /*
711          * If not the get another block of random bytes
712          */
713     {
714         CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
715
716         rv = aep_get_connection(&hConnection);
717         if (rv != AEP_R_OK) {
718             AEPHKerr(AEPHK_F_AEP_RAND, AEPHK_R_GET_HANDLE_FAILED);
719             goto err_nounlock;
720         }
721
722         if (len > RAND_BLK_SIZE) {
723             rv = p_AEP_GenRandom(hConnection, len, 2, buf, NULL);
724             if (rv != AEP_R_OK) {
725                 AEPHKerr(AEPHK_F_AEP_RAND, AEPHK_R_GET_RANDOM_FAILED);
726                 goto err_nounlock;
727             }
728         } else {
729             CRYPTO_w_lock(CRYPTO_LOCK_RAND);
730
731             rv = p_AEP_GenRandom(hConnection, RAND_BLK_SIZE, 2,
732                                  &rand_block[0], NULL);
733             if (rv != AEP_R_OK) {
734                 AEPHKerr(AEPHK_F_AEP_RAND, AEPHK_R_GET_RANDOM_FAILED);
735
736                 goto err;
737             }
738
739             rand_block_bytes = RAND_BLK_SIZE;
740
741             memcpy(buf, &rand_block[RAND_BLK_SIZE - rand_block_bytes], len);
742             rand_block_bytes -= len;
743
744             CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
745         }
746
747         rv = aep_return_connection(hConnection);
748         if (rv != AEP_R_OK) {
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         AEPHKerr(AEPHK_F_AEP_RSA_MOD_EXP, AEPHK_R_NOT_LOADED);
776         goto err;
777     }
778
779     /*
780      * See if we have all the necessary bits for a crt
781      */
782     if (rsa->q && rsa->dmp1 && rsa->dmq1 && rsa->iqmp) {
783         rv = aep_mod_exp_crt(r0, I, rsa->p, rsa->q, rsa->dmp1, rsa->dmq1,
784                              rsa->iqmp, ctx);
785
786         if (rv == FAIL_TO_SW) {
787             const RSA_METHOD *meth = RSA_PKCS1_SSLeay();
788             to_return = (*meth->rsa_mod_exp) (r0, I, rsa, ctx);
789             goto err;
790         } else if (rv != AEP_R_OK)
791             goto err;
792     } else {
793         if (!rsa->d || !rsa->n) {
794             AEPHKerr(AEPHK_F_AEP_RSA_MOD_EXP, AEPHK_R_MISSING_KEY_COMPONENTS);
795             goto err;
796         }
797
798         rv = aep_mod_exp(r0, I, rsa->d, rsa->n, ctx);
799         if (rv != AEP_R_OK)
800             goto err;
801
802     }
803
804     to_return = 1;
805
806  err:
807     return to_return;
808 }
809 #  endif
810
811 #  ifndef OPENSSL_NO_DSA
812 static int aep_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1,
813                            BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m,
814                            BN_CTX *ctx, BN_MONT_CTX *in_mont)
815 {
816     BIGNUM t;
817     int to_return = 0;
818     BN_init(&t);
819
820     /* let rr = a1 ^ p1 mod m */
821     if (!aep_mod_exp(rr, a1, p1, m, ctx))
822         goto end;
823     /* let t = a2 ^ p2 mod m */
824     if (!aep_mod_exp(&t, a2, p2, m, ctx))
825         goto end;
826     /* let rr = rr * t mod m */
827     if (!BN_mod_mul(rr, rr, &t, m, ctx))
828         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     /*
868      * Get the current process id
869      */
870     pid_t curr_pid;
871
872     CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
873
874     curr_pid = getpid();
875
876     /*
877      * Check if this is the first time this is being called from the current
878      * process
879      */
880     if (recorded_pid != curr_pid) {
881         /*
882          * Remember our pid so we can check if we're in a new process
883          */
884         recorded_pid = curr_pid;
885
886         /*
887          * Call Finalize to make sure we have not inherited some data from a
888          * parent process
889          */
890         p_AEP_Finalize();
891
892         /*
893          * Initialise the AEP API
894          */
895         rv = p_AEP_Initialize(NULL);
896
897         if (rv != AEP_R_OK) {
898             AEPHKerr(AEPHK_F_AEP_GET_CONNECTION, AEPHK_R_INIT_FAILURE);
899             recorded_pid = 0;
900             goto end;
901         }
902
903         /*
904          * Set the AEP big num call back functions
905          */
906         rv = p_AEP_SetBNCallBacks(&GetBigNumSize, &MakeAEPBigNum,
907                                   &ConvertAEPBigNum);
908
909         if (rv != AEP_R_OK) {
910             AEPHKerr(AEPHK_F_AEP_GET_CONNECTION,
911                      AEPHK_R_SETBNCALLBACK_FAILURE);
912             recorded_pid = 0;
913             goto end;
914         }
915 #  ifdef AEPRAND
916         /*
917          * Reset the rand byte count
918          */
919         rand_block_bytes = 0;
920 #  endif
921
922         /*
923          * Init the structures
924          */
925         for (count = 0; count < MAX_PROCESS_CONNECTIONS; count++) {
926             aep_app_conn_table[count].conn_state = NotConnected;
927             aep_app_conn_table[count].conn_hndl = 0;
928         }
929
930         /*
931          * Open a connection
932          */
933         rv = p_AEP_OpenConnection(phConnection);
934
935         if (rv != AEP_R_OK) {
936             AEPHKerr(AEPHK_F_AEP_GET_CONNECTION, AEPHK_R_UNIT_FAILURE);
937             recorded_pid = 0;
938             goto end;
939         }
940
941         aep_app_conn_table[0].conn_state = InUse;
942         aep_app_conn_table[0].conn_hndl = *phConnection;
943         goto end;
944     }
945     /*
946      * Check the existing connections to see if we can find a free one
947      */
948     for (count = 0; count < MAX_PROCESS_CONNECTIONS; count++) {
949         if (aep_app_conn_table[count].conn_state == Connected) {
950             aep_app_conn_table[count].conn_state = InUse;
951             *phConnection = aep_app_conn_table[count].conn_hndl;
952             goto end;
953         }
954     }
955     /*
956      * If no connections available, we're going to have to try to open a new
957      * one
958      */
959     for (count = 0; count < MAX_PROCESS_CONNECTIONS; count++) {
960         if (aep_app_conn_table[count].conn_state == NotConnected) {
961             /*
962              * Open a connection
963              */
964             rv = p_AEP_OpenConnection(phConnection);
965
966             if (rv != AEP_R_OK) {
967                 AEPHKerr(AEPHK_F_AEP_GET_CONNECTION, AEPHK_R_UNIT_FAILURE);
968                 goto end;
969             }
970
971             aep_app_conn_table[count].conn_state = InUse;
972             aep_app_conn_table[count].conn_hndl = *phConnection;
973             goto end;
974         }
975     }
976     rv = AEP_R_GENERAL_ERROR;
977  end:
978     CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
979     return rv;
980 }
981
982 static AEP_RV aep_return_connection(AEP_CONNECTION_HNDL hConnection)
983 {
984     int count;
985
986     CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
987
988     /*
989      * Find the connection item that matches this connection handle
990      */
991     for (count = 0; count < MAX_PROCESS_CONNECTIONS; count++) {
992         if (aep_app_conn_table[count].conn_hndl == hConnection) {
993             aep_app_conn_table[count].conn_state = Connected;
994             break;
995         }
996     }
997
998     CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
999
1000     return AEP_R_OK;
1001 }
1002
1003 static AEP_RV aep_close_connection(AEP_CONNECTION_HNDL hConnection)
1004 {
1005     int count;
1006     AEP_RV rv = AEP_R_OK;
1007
1008     CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
1009
1010     /*
1011      * Find the connection item that matches this connection handle
1012      */
1013     for (count = 0; count < MAX_PROCESS_CONNECTIONS; count++) {
1014         if (aep_app_conn_table[count].conn_hndl == hConnection) {
1015             rv = p_AEP_CloseConnection(aep_app_conn_table[count].conn_hndl);
1016             if (rv != AEP_R_OK)
1017                 goto end;
1018             aep_app_conn_table[count].conn_state = NotConnected;
1019             aep_app_conn_table[count].conn_hndl = 0;
1020             break;
1021         }
1022     }
1023
1024  end:
1025     CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
1026     return rv;
1027 }
1028
1029 static AEP_RV aep_close_all_connections(int use_engine_lock, int *in_use)
1030 {
1031     int count;
1032     AEP_RV rv = AEP_R_OK;
1033
1034     *in_use = 0;
1035     if (use_engine_lock)
1036         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
1037     for (count = 0; count < MAX_PROCESS_CONNECTIONS; count++) {
1038         switch (aep_app_conn_table[count].conn_state) {
1039         case Connected:
1040             rv = p_AEP_CloseConnection(aep_app_conn_table[count].conn_hndl);
1041             if (rv != AEP_R_OK)
1042                 goto end;
1043             aep_app_conn_table[count].conn_state = NotConnected;
1044             aep_app_conn_table[count].conn_hndl = 0;
1045             break;
1046         case InUse:
1047             (*in_use)++;
1048             break;
1049         case NotConnected:
1050             break;
1051         }
1052     }
1053  end:
1054     if (use_engine_lock)
1055         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
1056     return rv;
1057 }
1058
1059 /*
1060  * BigNum call back functions, used to convert OpenSSL bignums into AEP
1061  * bignums. Note only 32bit Openssl build support
1062  */
1063
1064 static AEP_RV GetBigNumSize(AEP_VOID_PTR ArbBigNum, AEP_U32 *BigNumSize)
1065 {
1066     BIGNUM *bn;
1067
1068     /*
1069      * Cast the ArbBigNum pointer to our BIGNUM struct
1070      */
1071     bn = (BIGNUM *)ArbBigNum;
1072
1073     *BigNumSize = bn->top * BN_BYTES;
1074
1075     if (BN_BYTES > sizeof(AEP_U32) && (bn->d[bn->top - 1] >> BN_BITS4) == 0)
1076         *BigNumSize -= 4;
1077
1078     return AEP_R_OK;
1079 }
1080
1081 static AEP_RV MakeAEPBigNum(AEP_VOID_PTR ArbBigNum, AEP_U32 BigNumSize,
1082                             unsigned char *AEP_BigNum)
1083 {
1084     BIGNUM *bn;
1085     const union {
1086         long one;
1087         char little;
1088     } is_endian = {
1089         1
1090     };
1091     AEP_U32 i, j;
1092
1093     /*
1094      * Cast the ArbBigNum pointer to our BIGNUM struct
1095      */
1096     bn = (BIGNUM *)ArbBigNum;
1097
1098     /*
1099      * Must copy data into a (monotone) least significant byte first format
1100      * performing endian conversion if necessary
1101      */
1102     if (is_endian.little && sizeof(bn->d[0]) == BN_BYTES)
1103         memcpy(AEP_BigNum, bn->d, BigNumSize);
1104     else {
1105         BN_ULONG di;
1106
1107         for (i = 0; BigNumSize >= BN_BYTES; i++) {
1108             di = bn->d[i];
1109             for (j = 0; j < BN_BYTES; j++) {
1110                 AEP_BigNum[j] = (unsigned char)di;
1111                 di >>= 8;
1112             }
1113             AEP_BigNum += BN_BYTES;
1114             BigNumSize -= BN_BYTES;
1115         }
1116
1117         if (BigNumSize) {
1118             di = bn->d[i];
1119             for (j = 0; j < BigNumSize; j++) {
1120                 AEP_BigNum[j] = (unsigned char)di;
1121                 di >>= 8;
1122             }
1123         }
1124     }
1125
1126     return AEP_R_OK;
1127 }
1128
1129 /*
1130  * Turn an AEP Big Num back to a user big num
1131  */
1132 static AEP_RV ConvertAEPBigNum(void *ArbBigNum, AEP_U32 BigNumSize,
1133                                unsigned char *AEP_BigNum)
1134 {
1135     BIGNUM *bn;
1136     const union {
1137         long one;
1138         char little;
1139     } is_endian = {
1140         1
1141     };
1142     int i, j, top;
1143
1144     bn = (BIGNUM *)ArbBigNum;
1145
1146     /*
1147      * Expand the result bn so that it can hold our big num. Size is in bits
1148      */
1149     top = (BigNumSize + BN_BYTES - 1) / BN_BYTES;
1150     bn_expand(bn, top);
1151     bn->top = top;
1152     bn->d[top - 1] = 0;
1153
1154     if (is_endian.little && sizeof(bn->d[0]) == BN_BYTES)
1155         memcpy(bn->d, AEP_BigNum, BigNumSize);
1156     else {
1157         BN_ULONG di;
1158
1159         for (i = 0; BigNumSize >= BN_BYTES; i++) {
1160             for (di = 0, j = BN_BYTES; j != 0;) {
1161                 di <<= 8;
1162                 di |= AEP_BigNum[--j];
1163             }
1164             bn->d[i] = di;
1165             AEP_BigNum += BN_BYTES;
1166             BigNumSize -= BN_BYTES;
1167         }
1168
1169         if (BigNumSize) {
1170             for (di = 0, j = BigNumSize; j != 0;) {
1171                 di <<= 8;
1172                 di |= AEP_BigNum[--j];
1173             }
1174             bn->d[i] = di;
1175         }
1176     }
1177
1178     return AEP_R_OK;
1179 }
1180
1181 # endif                         /* !OPENSSL_NO_HW_AEP */
1182 #endif                          /* !OPENSSL_NO_HW */