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