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