e_aep.c revision 296465
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__)
61# include <sys/types.h>
62# include <unistd.h>
63#else
64# include <process.h>
65typedef int pid_t;
66#endif
67
68#if defined(OPENSSL_SYS_NETWARE) && defined(NETWARE_CLIB)
69# define getpid GetThreadID
70extern int GetThreadID(void);
71#endif
72
73#include <openssl/crypto.h>
74#include <openssl/dso.h>
75#include <openssl/engine.h>
76#include <openssl/buffer.h>
77#ifndef OPENSSL_NO_RSA
78# include <openssl/rsa.h>
79#endif
80#ifndef OPENSSL_NO_DSA
81# include <openssl/dsa.h>
82#endif
83#ifndef OPENSSL_NO_DH
84# include <openssl/dh.h>
85#endif
86#include <openssl/bn.h>
87
88#ifndef OPENSSL_NO_HW
89# ifndef OPENSSL_NO_HW_AEP
90#  ifdef FLAT_INC
91#   include "aep.h"
92#  else
93#   include "vendor_defns/aep.h"
94#  endif
95
96#  define AEP_LIB_NAME "aep engine"
97#  define FAIL_TO_SW 0x10101010
98
99#  include "e_aep_err.c"
100
101static int aep_init(ENGINE *e);
102static int aep_finish(ENGINE *e);
103static int aep_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void));
104static int aep_destroy(ENGINE *e);
105
106static AEP_RV aep_get_connection(AEP_CONNECTION_HNDL_PTR hConnection);
107static AEP_RV aep_return_connection(AEP_CONNECTION_HNDL hConnection);
108static AEP_RV aep_close_connection(AEP_CONNECTION_HNDL hConnection);
109static AEP_RV aep_close_all_connections(int use_engine_lock, int *in_use);
110
111/* BIGNUM stuff */
112#  ifndef OPENSSL_NO_RSA
113static int aep_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
114                       const BIGNUM *m, BN_CTX *ctx);
115
116static AEP_RV aep_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
117                              const BIGNUM *q, const BIGNUM *dmp1,
118                              const BIGNUM *dmq1, const BIGNUM *iqmp,
119                              BN_CTX *ctx);
120#  endif
121
122/* RSA stuff */
123#  ifndef OPENSSL_NO_RSA
124static int aep_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa,
125                           BN_CTX *ctx);
126#  endif
127
128/* This function is aliased to mod_exp (with the mont stuff dropped). */
129#  ifndef OPENSSL_NO_RSA
130static int aep_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
131                            const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
132#  endif
133
134/* DSA stuff */
135#  ifndef OPENSSL_NO_DSA
136static int aep_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1,
137                           BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m,
138                           BN_CTX *ctx, BN_MONT_CTX *in_mont);
139
140static int aep_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a,
141                           const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
142                           BN_MONT_CTX *m_ctx);
143#  endif
144
145/* DH stuff */
146/* This function is aliased to mod_exp (with the DH and mont dropped). */
147#  ifndef OPENSSL_NO_DH
148static int aep_mod_exp_dh(const DH *dh, BIGNUM *r, const BIGNUM *a,
149                          const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
150                          BN_MONT_CTX *m_ctx);
151#  endif
152
153/* rand stuff   */
154#  ifdef AEPRAND
155static int aep_rand(unsigned char *buf, int num);
156static int aep_rand_status(void);
157#  endif
158
159/* Bignum conversion stuff */
160static AEP_RV GetBigNumSize(AEP_VOID_PTR ArbBigNum, AEP_U32 *BigNumSize);
161static AEP_RV MakeAEPBigNum(AEP_VOID_PTR ArbBigNum, AEP_U32 BigNumSize,
162                            unsigned char *AEP_BigNum);
163static AEP_RV ConvertAEPBigNum(void *ArbBigNum, AEP_U32 BigNumSize,
164                               unsigned char *AEP_BigNum);
165
166/* The definitions for control commands specific to this engine */
167#  define AEP_CMD_SO_PATH         ENGINE_CMD_BASE
168static const ENGINE_CMD_DEFN aep_cmd_defns[] = {
169    {AEP_CMD_SO_PATH,
170     "SO_PATH",
171     "Specifies the path to the 'aep' shared library",
172     ENGINE_CMD_FLAG_STRING},
173    {0, NULL, NULL, 0}
174};
175
176#  ifndef OPENSSL_NO_RSA
177/* Our internal RSA_METHOD that we provide pointers to */
178static RSA_METHOD aep_rsa = {
179    "Aep RSA method",
180    NULL,                       /* rsa_pub_encrypt */
181    NULL,                       /* rsa_pub_decrypt */
182    NULL,                       /* rsa_priv_encrypt */
183    NULL,                       /* rsa_priv_encrypt */
184    aep_rsa_mod_exp,            /* rsa_mod_exp */
185    aep_mod_exp_mont,           /* bn_mod_exp */
186    NULL,                       /* init */
187    NULL,                       /* finish */
188    0,                          /* flags */
189    NULL,                       /* app_data */
190    NULL,                       /* rsa_sign */
191    NULL,                       /* rsa_verify */
192    NULL                        /* rsa_keygen */
193};
194#  endif
195
196#  ifndef OPENSSL_NO_DSA
197/* Our internal DSA_METHOD that we provide pointers to */
198static DSA_METHOD aep_dsa = {
199    "Aep DSA method",
200    NULL,                       /* dsa_do_sign */
201    NULL,                       /* dsa_sign_setup */
202    NULL,                       /* dsa_do_verify */
203    aep_dsa_mod_exp,            /* dsa_mod_exp */
204    aep_mod_exp_dsa,            /* bn_mod_exp */
205    NULL,                       /* init */
206    NULL,                       /* finish */
207    0,                          /* flags */
208    NULL,                       /* app_data */
209    NULL,                       /* dsa_paramgen */
210    NULL                        /* dsa_keygen */
211};
212#  endif
213
214#  ifndef OPENSSL_NO_DH
215/* Our internal DH_METHOD that we provide pointers to */
216static DH_METHOD aep_dh = {
217    "Aep DH method",
218    NULL,
219    NULL,
220    aep_mod_exp_dh,
221    NULL,
222    NULL,
223    0,
224    NULL,
225    NULL
226};
227#  endif
228
229#  ifdef AEPRAND
230/* our internal RAND_method that we provide pointers to  */
231static RAND_METHOD aep_random = {
232    /*
233     * "AEP RAND method",
234     */
235    NULL,
236    aep_rand,
237    NULL,
238    NULL,
239    aep_rand,
240    aep_rand_status,
241};
242#  endif
243
244/*
245 * Define an array of structures to hold connections
246 */
247static AEP_CONNECTION_ENTRY aep_app_conn_table[MAX_PROCESS_CONNECTIONS];
248
249/*
250 * Used to determine if this is a new process
251 */
252static pid_t recorded_pid = 0;
253
254#  ifdef AEPRAND
255static AEP_U8 rand_block[RAND_BLK_SIZE];
256static AEP_U32 rand_block_bytes = 0;
257#  endif
258
259/* Constants used when creating the ENGINE */
260static const char *engine_aep_id = "aep";
261static const char *engine_aep_name = "Aep hardware engine support";
262
263static int max_key_len = 2176;
264
265/*
266 * This internal function is used by ENGINE_aep() and possibly by the
267 * "dynamic" ENGINE support too
268 */
269static int bind_aep(ENGINE *e)
270{
271#  ifndef OPENSSL_NO_RSA
272    const RSA_METHOD *meth1;
273#  endif
274#  ifndef OPENSSL_NO_DSA
275    const DSA_METHOD *meth2;
276#  endif
277#  ifndef OPENSSL_NO_DH
278    const DH_METHOD *meth3;
279#  endif
280
281    if (!ENGINE_set_id(e, engine_aep_id) ||
282        !ENGINE_set_name(e, engine_aep_name) ||
283#  ifndef OPENSSL_NO_RSA
284        !ENGINE_set_RSA(e, &aep_rsa) ||
285#  endif
286#  ifndef OPENSSL_NO_DSA
287        !ENGINE_set_DSA(e, &aep_dsa) ||
288#  endif
289#  ifndef OPENSSL_NO_DH
290        !ENGINE_set_DH(e, &aep_dh) ||
291#  endif
292#  ifdef AEPRAND
293        !ENGINE_set_RAND(e, &aep_random) ||
294#  endif
295        !ENGINE_set_init_function(e, aep_init) ||
296        !ENGINE_set_destroy_function(e, aep_destroy) ||
297        !ENGINE_set_finish_function(e, aep_finish) ||
298        !ENGINE_set_ctrl_function(e, aep_ctrl) ||
299        !ENGINE_set_cmd_defns(e, aep_cmd_defns))
300        return 0;
301
302#  ifndef OPENSSL_NO_RSA
303    /*
304     * We know that the "PKCS1_SSLeay()" functions hook properly to the
305     * aep-specific mod_exp and mod_exp_crt so we use those functions. NB: We
306     * don't use ENGINE_openssl() or anything "more generic" because
307     * something like the RSAref code may not hook properly, and if you own
308     * one of these cards then you have the right to do RSA operations on it
309     * anyway!
310     */
311    meth1 = RSA_PKCS1_SSLeay();
312    aep_rsa.rsa_pub_enc = meth1->rsa_pub_enc;
313    aep_rsa.rsa_pub_dec = meth1->rsa_pub_dec;
314    aep_rsa.rsa_priv_enc = meth1->rsa_priv_enc;
315    aep_rsa.rsa_priv_dec = meth1->rsa_priv_dec;
316#  endif
317
318#  ifndef OPENSSL_NO_DSA
319    /*
320     * Use the DSA_OpenSSL() method and just hook the mod_exp-ish bits.
321     */
322    meth2 = DSA_OpenSSL();
323    aep_dsa.dsa_do_sign = meth2->dsa_do_sign;
324    aep_dsa.dsa_sign_setup = meth2->dsa_sign_setup;
325    aep_dsa.dsa_do_verify = meth2->dsa_do_verify;
326
327    aep_dsa = *DSA_get_default_method();
328    aep_dsa.dsa_mod_exp = aep_dsa_mod_exp;
329    aep_dsa.bn_mod_exp = aep_mod_exp_dsa;
330#  endif
331
332#  ifndef OPENSSL_NO_DH
333    /* Much the same for Diffie-Hellman */
334    meth3 = DH_OpenSSL();
335    aep_dh.generate_key = meth3->generate_key;
336    aep_dh.compute_key = meth3->compute_key;
337    aep_dh.bn_mod_exp = meth3->bn_mod_exp;
338#  endif
339
340    /* Ensure the aep error handling is set up */
341    ERR_load_AEPHK_strings();
342
343    return 1;
344}
345
346#  ifndef OPENSSL_NO_DYNAMIC_ENGINE
347static int bind_helper(ENGINE *e, const char *id)
348{
349    if (id && (strcmp(id, engine_aep_id) != 0))
350        return 0;
351    if (!bind_aep(e))
352        return 0;
353    return 1;
354}
355
356IMPLEMENT_DYNAMIC_CHECK_FN()
357    IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
358#  else
359static ENGINE *engine_aep(void)
360{
361    ENGINE *ret = ENGINE_new();
362    if (!ret)
363        return NULL;
364    if (!bind_aep(ret)) {
365        ENGINE_free(ret);
366        return NULL;
367    }
368    return ret;
369}
370
371void ENGINE_load_aep(void)
372{
373    /* Copied from eng_[openssl|dyn].c */
374    ENGINE *toadd = engine_aep();
375    if (!toadd)
376        return;
377    ENGINE_add(toadd);
378    ENGINE_free(toadd);
379    ERR_clear_error();
380}
381#  endif
382
383/*
384 * This is a process-global DSO handle used for loading and unloading the Aep
385 * library. NB: This is only set (or unset) during an init() or finish() call
386 * (reference counts permitting) and they're operating with global locks, so
387 * this should be thread-safe implicitly.
388 */
389static DSO *aep_dso = NULL;
390
391/*
392 * These are the static string constants for the DSO file name and the
393 * function symbol names to bind to.
394 */
395static const char *AEP_LIBNAME = NULL;
396static const char *get_AEP_LIBNAME(void)
397{
398    if (AEP_LIBNAME)
399        return AEP_LIBNAME;
400    return "aep";
401}
402
403static void free_AEP_LIBNAME(void)
404{
405    if (AEP_LIBNAME)
406        OPENSSL_free((void *)AEP_LIBNAME);
407    AEP_LIBNAME = NULL;
408}
409
410static long set_AEP_LIBNAME(const char *name)
411{
412    free_AEP_LIBNAME();
413    return ((AEP_LIBNAME = BUF_strdup(name)) != NULL ? 1 : 0);
414}
415
416static const char *AEP_F1 = "AEP_ModExp";
417static const char *AEP_F2 = "AEP_ModExpCrt";
418#  ifdef AEPRAND
419static const char *AEP_F3 = "AEP_GenRandom";
420#  endif
421static const char *AEP_F4 = "AEP_Finalize";
422static const char *AEP_F5 = "AEP_Initialize";
423static const char *AEP_F6 = "AEP_OpenConnection";
424static const char *AEP_F7 = "AEP_SetBNCallBacks";
425static 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 */
431static t_AEP_OpenConnection *p_AEP_OpenConnection = NULL;
432static t_AEP_CloseConnection *p_AEP_CloseConnection = NULL;
433static t_AEP_ModExp *p_AEP_ModExp = NULL;
434static t_AEP_ModExpCrt *p_AEP_ModExpCrt = NULL;
435#  ifdef AEPRAND
436static t_AEP_GenRandom *p_AEP_GenRandom = NULL;
437#  endif
438static t_AEP_Initialize *p_AEP_Initialize = NULL;
439static t_AEP_Finalize *p_AEP_Finalize = NULL;
440static t_AEP_SetBNCallBacks *p_AEP_SetBNCallBacks = NULL;
441
442/* (de)initialisation functions. */
443static 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) */
523static int aep_destroy(ENGINE *e)
524{
525    free_AEP_LIBNAME();
526    ERR_unload_AEPHK_strings();
527    return 1;
528}
529
530static 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
578static 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
599static 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
652static 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
696static 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
763static int aep_rand_status(void)
764{
765    return 1;
766}
767#  endif
768
769#  ifndef OPENSSL_NO_RSA
770static 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
813static 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
836static 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). */
846static 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). */
855static 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
863static 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#  ifdef NETWARE_CLIB
876    curr_pid = GetThreadID();
877#  elif defined(_WIN32)
878    curr_pid = _getpid();
879#  else
880    curr_pid = getpid();
881#  endif
882
883    /*
884     * Check if this is the first time this is being called from the current
885     * process
886     */
887    if (recorded_pid != curr_pid) {
888        /*
889         * Remember our pid so we can check if we're in a new process
890         */
891        recorded_pid = curr_pid;
892
893        /*
894         * Call Finalize to make sure we have not inherited some data from a
895         * parent process
896         */
897        p_AEP_Finalize();
898
899        /*
900         * Initialise the AEP API
901         */
902        rv = p_AEP_Initialize(NULL);
903
904        if (rv != AEP_R_OK) {
905            AEPHKerr(AEPHK_F_AEP_GET_CONNECTION, AEPHK_R_INIT_FAILURE);
906            recorded_pid = 0;
907            goto end;
908        }
909
910        /*
911         * Set the AEP big num call back functions
912         */
913        rv = p_AEP_SetBNCallBacks(&GetBigNumSize, &MakeAEPBigNum,
914                                  &ConvertAEPBigNum);
915
916        if (rv != AEP_R_OK) {
917            AEPHKerr(AEPHK_F_AEP_GET_CONNECTION,
918                     AEPHK_R_SETBNCALLBACK_FAILURE);
919            recorded_pid = 0;
920            goto end;
921        }
922#  ifdef AEPRAND
923        /*
924         * Reset the rand byte count
925         */
926        rand_block_bytes = 0;
927#  endif
928
929        /*
930         * Init the structures
931         */
932        for (count = 0; count < MAX_PROCESS_CONNECTIONS; count++) {
933            aep_app_conn_table[count].conn_state = NotConnected;
934            aep_app_conn_table[count].conn_hndl = 0;
935        }
936
937        /*
938         * Open a connection
939         */
940        rv = p_AEP_OpenConnection(phConnection);
941
942        if (rv != AEP_R_OK) {
943            AEPHKerr(AEPHK_F_AEP_GET_CONNECTION, AEPHK_R_UNIT_FAILURE);
944            recorded_pid = 0;
945            goto end;
946        }
947
948        aep_app_conn_table[0].conn_state = InUse;
949        aep_app_conn_table[0].conn_hndl = *phConnection;
950        goto end;
951    }
952    /*
953     * Check the existing connections to see if we can find a free one
954     */
955    for (count = 0; count < MAX_PROCESS_CONNECTIONS; count++) {
956        if (aep_app_conn_table[count].conn_state == Connected) {
957            aep_app_conn_table[count].conn_state = InUse;
958            *phConnection = aep_app_conn_table[count].conn_hndl;
959            goto end;
960        }
961    }
962    /*
963     * If no connections available, we're going to have to try to open a new
964     * one
965     */
966    for (count = 0; count < MAX_PROCESS_CONNECTIONS; count++) {
967        if (aep_app_conn_table[count].conn_state == NotConnected) {
968            /*
969             * Open a connection
970             */
971            rv = p_AEP_OpenConnection(phConnection);
972
973            if (rv != AEP_R_OK) {
974                AEPHKerr(AEPHK_F_AEP_GET_CONNECTION, AEPHK_R_UNIT_FAILURE);
975                goto end;
976            }
977
978            aep_app_conn_table[count].conn_state = InUse;
979            aep_app_conn_table[count].conn_hndl = *phConnection;
980            goto end;
981        }
982    }
983    rv = AEP_R_GENERAL_ERROR;
984 end:
985    CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
986    return rv;
987}
988
989static AEP_RV aep_return_connection(AEP_CONNECTION_HNDL hConnection)
990{
991    int count;
992
993    CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
994
995    /*
996     * Find the connection item that matches this connection handle
997     */
998    for (count = 0; count < MAX_PROCESS_CONNECTIONS; count++) {
999        if (aep_app_conn_table[count].conn_hndl == hConnection) {
1000            aep_app_conn_table[count].conn_state = Connected;
1001            break;
1002        }
1003    }
1004
1005    CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
1006
1007    return AEP_R_OK;
1008}
1009
1010static AEP_RV aep_close_connection(AEP_CONNECTION_HNDL hConnection)
1011{
1012    int count;
1013    AEP_RV rv = AEP_R_OK;
1014
1015    CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
1016
1017    /*
1018     * Find the connection item that matches this connection handle
1019     */
1020    for (count = 0; count < MAX_PROCESS_CONNECTIONS; count++) {
1021        if (aep_app_conn_table[count].conn_hndl == hConnection) {
1022            rv = p_AEP_CloseConnection(aep_app_conn_table[count].conn_hndl);
1023            if (rv != AEP_R_OK)
1024                goto end;
1025            aep_app_conn_table[count].conn_state = NotConnected;
1026            aep_app_conn_table[count].conn_hndl = 0;
1027            break;
1028        }
1029    }
1030
1031 end:
1032    CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
1033    return rv;
1034}
1035
1036static AEP_RV aep_close_all_connections(int use_engine_lock, int *in_use)
1037{
1038    int count;
1039    AEP_RV rv = AEP_R_OK;
1040
1041    *in_use = 0;
1042    if (use_engine_lock)
1043        CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
1044    for (count = 0; count < MAX_PROCESS_CONNECTIONS; count++) {
1045        switch (aep_app_conn_table[count].conn_state) {
1046        case Connected:
1047            rv = p_AEP_CloseConnection(aep_app_conn_table[count].conn_hndl);
1048            if (rv != AEP_R_OK)
1049                goto end;
1050            aep_app_conn_table[count].conn_state = NotConnected;
1051            aep_app_conn_table[count].conn_hndl = 0;
1052            break;
1053        case InUse:
1054            (*in_use)++;
1055            break;
1056        case NotConnected:
1057            break;
1058        }
1059    }
1060 end:
1061    if (use_engine_lock)
1062        CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
1063    return rv;
1064}
1065
1066/*
1067 * BigNum call back functions, used to convert OpenSSL bignums into AEP
1068 * bignums. Note only 32bit Openssl build support
1069 */
1070
1071static AEP_RV GetBigNumSize(AEP_VOID_PTR ArbBigNum, AEP_U32 *BigNumSize)
1072{
1073    BIGNUM *bn;
1074
1075    /*
1076     * Cast the ArbBigNum pointer to our BIGNUM struct
1077     */
1078    bn = (BIGNUM *)ArbBigNum;
1079
1080#  ifdef SIXTY_FOUR_BIT_LONG
1081    *BigNumSize = bn->top << 3;
1082#  else
1083    /*
1084     * Size of the bignum in bytes is equal to the bn->top (no of 32 bit
1085     * words) multiplies by 4
1086     */
1087    *BigNumSize = bn->top << 2;
1088#  endif
1089
1090    return AEP_R_OK;
1091}
1092
1093static AEP_RV MakeAEPBigNum(AEP_VOID_PTR ArbBigNum, AEP_U32 BigNumSize,
1094                            unsigned char *AEP_BigNum)
1095{
1096    BIGNUM *bn;
1097
1098#  ifndef SIXTY_FOUR_BIT_LONG
1099    unsigned char *buf;
1100    int i;
1101#  endif
1102
1103    /*
1104     * Cast the ArbBigNum pointer to our BIGNUM struct
1105     */
1106    bn = (BIGNUM *)ArbBigNum;
1107
1108#  ifdef SIXTY_FOUR_BIT_LONG
1109    memcpy(AEP_BigNum, bn->d, BigNumSize);
1110#  else
1111    /*
1112     * Must copy data into a (monotone) least significant byte first format
1113     * performing endian conversion if necessary
1114     */
1115    for (i = 0; i < bn->top; i++) {
1116        buf = (unsigned char *)&bn->d[i];
1117
1118        *((AEP_U32 *)AEP_BigNum) = (AEP_U32)
1119            ((unsigned)buf[1] << 8 | buf[0]) |
1120            ((unsigned)buf[3] << 8 | buf[2]) << 16;
1121
1122        AEP_BigNum += 4;
1123    }
1124#  endif
1125
1126    return AEP_R_OK;
1127}
1128
1129/*
1130 * Turn an AEP Big Num back to a user big num
1131 */
1132static AEP_RV ConvertAEPBigNum(void *ArbBigNum, AEP_U32 BigNumSize,
1133                               unsigned char *AEP_BigNum)
1134{
1135    BIGNUM *bn;
1136#  ifndef SIXTY_FOUR_BIT_LONG
1137    int i;
1138#  endif
1139
1140    bn = (BIGNUM *)ArbBigNum;
1141
1142    /*
1143     * Expand the result bn so that it can hold our big num. Size is in bits
1144     */
1145    bn_expand(bn, (int)(BigNumSize << 3));
1146
1147#  ifdef SIXTY_FOUR_BIT_LONG
1148    bn->top = BigNumSize >> 3;
1149
1150    if ((BigNumSize & 7) != 0)
1151        bn->top++;
1152
1153    memset(bn->d, 0, bn->top << 3);
1154
1155    memcpy(bn->d, AEP_BigNum, BigNumSize);
1156#  else
1157    bn->top = BigNumSize >> 2;
1158
1159    for (i = 0; i < bn->top; i++) {
1160        bn->d[i] = (AEP_U32)
1161            ((unsigned)AEP_BigNum[3] << 8 | AEP_BigNum[2]) << 16 |
1162            ((unsigned)AEP_BigNum[1] << 8 | AEP_BigNum[0]);
1163        AEP_BigNum += 4;
1164    }
1165#  endif
1166
1167    return AEP_R_OK;
1168}
1169
1170# endif                         /* !OPENSSL_NO_HW_AEP */
1171#endif                          /* !OPENSSL_NO_HW */
1172