diff -urN openssl-engine-0.9.6c/Configure openssl-engine-0.9.6c-tw/Configure
--- openssl-engine-0.9.6c/Configure	Fri Dec 21 03:34:56 2001
+++ openssl-engine-0.9.6c-tw/Configure	Thu Apr 18 15:48:33 2002
@@ -337,6 +337,9 @@
 
 # The intel boxes :-), It would be worth seeing if bsdi-gcc can use the
 # bn86-elf.o file file since it is hand tweaked assembler.
+"linux-elf-tw",	"gcc:-DL_ENDIAN -DTERMIO -O3 -g -m486 -Wall::-D_REENTRANT:-ldl -lgpkcs11cc2000:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
+"debug-linux-elf-tw","gcc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG -DL_ENDIAN -DTERMIO -g -m486 -Wall::-D_REENTRANT:-lefence -ldl -lgpkcs11cc2000:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn",
+"debug-linux-elf-noefence-tw","gcc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG -DL_ENDIAN -DTERMIO -g -m486 -Wall::-D_REENTRANT:-ldl -lgpkcs11cc2000:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn",
 "linux-elf",	"gcc:-DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -m486 -Wall::-D_REENTRANT:-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
 "debug-linux-elf","gcc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG -DL_ENDIAN -DTERMIO -g -m486 -Wall::-D_REENTRANT:-lefence -ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn",
 "debug-linux-elf-noefence","gcc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG -DL_ENDIAN -DTERMIO -g -m486 -Wall::-D_REENTRANT:-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn",
diff -urN openssl-engine-0.9.6c/apps/CA-trustway.sh openssl-engine-0.9.6c-tw/apps/CA-trustway.sh
--- openssl-engine-0.9.6c/apps/CA-trustway.sh	Thu Jan  1 01:00:00 1970
+++ openssl-engine-0.9.6c-tw/apps/CA-trustway.sh	Thu Apr 18 15:48:33 2002
@@ -0,0 +1,164 @@
+#!/bin/sh
+#
+# CA - wrapper around ca to make it easier to use ... basically ca requires
+#      some setup stuff to be done before you can use it and this makes
+#      things easier between now and when Eric is convinced to fix it :-)
+#
+# CA -newca ... will setup the right stuff
+# CA -newreq ... will generate a certificate request 
+# CA -sign ... will sign the generated request and output 
+#
+# At the end of that grab newreq.pem and newcert.pem (one has the key 
+# and the other the certificate) and cat them together and that is what
+# you want/need ... I'll make even this a little cleaner later.
+#
+#
+# 12-Jan-96 tjh    Added more things ... including CA -signcert which
+#                  converts a certificate to a request and then signs it.
+# 10-Jan-96 eay    Fixed a few more bugs and added the SSLEAY_CONFIG
+#		   environment variable so this can be driven from
+#		   a script.
+# 25-Jul-96 eay    Cleaned up filenames some more.
+# 11-Jun-96 eay    Fixed a few filename missmatches.
+# 03-May-96 eay    Modified to use 'ssleay cmd' instead of 'cmd'.
+# 18-Apr-96 tjh    Original hacking
+#
+# Tim Hudson
+# tjh@cryptsoft.com
+#
+
+# default openssl.cnf file has setup as per the following
+# demoCA ... where everything is stored
+
+DAYS="-days 365"
+REQ="openssl req -engine trustway -config ../openssl.cnf"
+CA="openssl ca -engine trustway -config ../openssl.cnf"
+PKCS="openssl -engine trustway pkcs12"
+VERIFY="openssl -engine trustway verify"
+X509="openssl -engine trustway x509"
+
+CATOP=./demoCA
+CAKEY=./cakey.pem
+CACERT=./cacert.pem
+
+for i
+do
+case $i in
+-\?|-h|-help)
+    echo "usage: CA -newcert|-newreq|-newca|-sign|-verify|-pkcs12|-revoke|-gencrl" >&2
+    exit 0
+    ;;
+-newcert) 
+    # create a certificate
+    $REQ -new -x509 -keyout newkey.pem -out newreq.pem $DAYS
+    RET=$?
+    echo "Certificate (and private key) is in newreq.pem"
+    ;;
+-newreq) 
+    # create a certificate request
+    $REQ -new -keyout newkey.pem -out newreq.pem -nodes $DAYS
+    RET=$?
+    echo "Request (and private key) is in newreq.pem"
+    ;;
+-newca)     
+    # if explicitly asked for or it doesn't exist then setup the directory
+    # structure that Eric likes to manage things 
+    NEW="1"
+    if [ "$NEW" -o ! -f ${CATOP}/serial ]; then
+	# create the directory hierarchy
+	mkdir ${CATOP} 
+	mkdir ${CATOP}/certs 
+	mkdir ${CATOP}/crl 
+	mkdir ${CATOP}/newcerts
+	mkdir ${CATOP}/private
+	echo "01" > ${CATOP}/serial
+	touch ${CATOP}/index.txt
+    fi
+    if [ ! -f ${CATOP}/private/$CAKEY ]; then
+	echo "CA certificate filename (or enter to create)"
+	read FILE
+
+	# ask user for existing CA certificate
+	if [ "$FILE" ]; then
+	    cp $FILE ${CATOP}/private/$CAKEY
+	    RET=$?
+	else
+	    echo "Making CA certificate ..."
+	    $REQ -new -x509 -keyout ${CATOP}/private/$CAKEY \
+			   -out ${CATOP}/$CACERT $DAYS
+	    RET=$?
+	fi
+    fi
+    ;;
+-xsign)
+    $CA -policy policy_anything -infiles newreq.pem 
+    RET=$?
+    ;;
+-sign|-signreq) 
+    $CA -policy policy_anything -out newcert.pem -infiles newreq.pem
+    RET=$?
+    cat newcert.pem
+    echo "Signed certificate is in newcert.pem"
+    ;;
+-signcert) 
+    echo "Cert passphrase will be requested twice - bug?"
+    $X509 -x509toreq -in newreq.pem -signkey newkey.pem -out tmp.pem
+    $CA -policy policy_anything -out newcert.pem -infiles tmp.pem
+    cat newcert.pem
+    echo "Signed certificate is in newcert.pem"
+    ;;
+-verify) 
+    shift
+    if [ -z "$1" ]; then
+	    $VERIFY -CAfile $CATOP/$CACERT newcert.pem
+	    RET=$?
+    else
+	for j
+	do
+	    $VERIFY -CAfile $CATOP/$CACERT $j
+	    if [ $? != 0 ]; then
+		    RET=$?
+	    fi
+	done
+    fi
+    exit 0
+    ;;
+-pkcs12) 
+    shift
+    if [ -z "$1" ]; then
+       echo "manque no du certificat"
+    else
+       $PKCS -export -in newcert.pem -inkey newkey.pem -certfile demoCA/cacert.pem \
+		-name "MY CERTIFICATE$1" -out mycert$1.p12
+       RET=$?
+       echo "création de mycert$1.pem"
+    fi
+    exit 0
+    ;;
+-revoke) 
+    # revoke a certificate
+    shift
+    if [ -z "$1" ]; then
+       echo "manque no du certificat"
+    else
+	$CA -revoke demoCA/newcerts/0$1.pem
+	RET=$?
+	echo "the certificate has been revoked"
+    fi
+    exit 0
+    ;;
+-gencrl) 
+    # generate a CRL
+    $CA -gencrl -out ca_client.crl
+    RET=$?
+    echo "CRL is in ca_client.crl"
+    exit 0
+    ;;
+*)
+    echo "Unknown arg $i";
+    exit 1
+    ;;
+esac
+done
+exit $RET
+
diff -urN openssl-engine-0.9.6c/apps/Makefile.ssl openssl-engine-0.9.6c-tw/apps/Makefile.ssl
--- openssl-engine-0.9.6c/apps/Makefile.ssl	Fri Dec 21 03:35:11 2001
+++ openssl-engine-0.9.6c-tw/apps/Makefile.ssl	Thu Apr 18 15:48:33 2002
@@ -31,7 +31,7 @@
 
 PROGRAM= openssl
 
-SCRIPTS=CA.sh CA.pl der_chop
+SCRIPTS=CA.sh CA.pl der_chop CA-trustway.sh
 
 EXE= $(PROGRAM)$(EXE_EXT)
 
diff -urN openssl-engine-0.9.6c/crypto/asn1/d2i_r_pr.c openssl-engine-0.9.6c-tw/crypto/asn1/d2i_r_pr.c
--- openssl-engine-0.9.6c/crypto/asn1/d2i_r_pr.c	Sat Jan  8 22:06:18 2000
+++ openssl-engine-0.9.6c-tw/crypto/asn1/d2i_r_pr.c	Thu Apr 18 15:48:33 2002
@@ -63,6 +63,9 @@
 #include <openssl/rsa.h>
 #include <openssl/objects.h>
 #include <openssl/asn1_mac.h>
+#ifndef NO_HW_TRUSTWAY
+#include <openssl/engine.h>
+#endif
 
 static ASN1_METHOD method={
         (int (*)())  i2d_RSAPrivateKey,
@@ -80,6 +83,21 @@
 	int i=ASN1_R_PARSING;
 	ASN1_INTEGER *bs=NULL;
 	M_ASN1_D2I_vars(a,RSA *,RSA_new);
+#ifndef NO_HW_TRUSTWAY
+	if (ret->flags & RSA_FLAG_EXT_PKEY)
+	{
+	    RSA *rsa;
+	    rsa = ENGINE_get_RSA(ret->engine)->d2i_RSAPrivateKey(&ret, pp, length);
+	    if (rsa == NULL)
+	    {
+		if ((ret != NULL) && ((a == NULL) || (*a != ret)))
+		    RSA_free(ret);
+		return NULL;
+	    }
+	    else
+		return rsa;
+	}
+#endif
 
 	M_ASN1_D2I_Init();
 	M_ASN1_D2I_start_sequence();
diff -urN openssl-engine-0.9.6c/crypto/asn1/d2i_r_pu.c openssl-engine-0.9.6c-tw/crypto/asn1/d2i_r_pu.c
--- openssl-engine-0.9.6c/crypto/asn1/d2i_r_pu.c	Thu Apr  5 22:25:12 2001
+++ openssl-engine-0.9.6c-tw/crypto/asn1/d2i_r_pu.c	Thu Apr 18 15:48:33 2002
@@ -63,6 +63,9 @@
 #include <openssl/rsa.h>
 #include <openssl/objects.h>
 #include <openssl/asn1_mac.h>
+#ifndef NO_HW_TRUSTWAY
+#include <openssl/engine.h>
+#endif
 
 #ifndef NO_NEG_PUBKEY_BUG
 #define d2i_ASN1_INTEGER d2i_ASN1_UINTEGER
@@ -80,6 +83,15 @@
 	if ((ret->n=BN_bin2bn(bs->data,bs->length,ret->n)) == NULL) goto err_bn;
 	M_ASN1_D2I_get(bs,d2i_ASN1_INTEGER);
 	if ((ret->e=BN_bin2bn(bs->data,bs->length,ret->e)) == NULL) goto err_bn;
+#ifndef NO_HW_TRUSTWAY
+	if (ret->flags & RSA_FLAG_EXT_PKEY)
+	{
+	    if (!ENGINE_get_RSA(ret->engine)->d2i_RSAPublicKey(ret))
+		goto err;
+	    else
+		return ret;
+	}	
+#endif
 
 	M_ASN1_INTEGER_free(bs);
 	bs=NULL;
diff -urN openssl-engine-0.9.6c/crypto/asn1/i2d_r_pr.c openssl-engine-0.9.6c-tw/crypto/asn1/i2d_r_pr.c
--- openssl-engine-0.9.6c/crypto/asn1/i2d_r_pr.c	Thu Apr  5 22:25:14 2001
+++ openssl-engine-0.9.6c-tw/crypto/asn1/i2d_r_pr.c	Thu Apr 18 15:48:33 2002
@@ -63,6 +63,9 @@
 #include <openssl/rsa.h>
 #include <openssl/objects.h>
 #include <openssl/asn1_mac.h>
+#ifndef NO_HW_TRUSTWAY
+#include <openssl/engine.h>
+#endif
 
 int i2d_RSAPrivateKey(RSA *a, unsigned char **pp)
 	{
@@ -73,6 +76,10 @@
 	unsigned char *p;
 
 	if (a == NULL) return(0);
+#ifndef NO_HW_TRUSTWAY
+	if (a->flags & RSA_FLAG_EXT_PKEY)
+	    return ENGINE_get_RSA(a->engine)->i2d_RSAPrivateKey(a, pp);
+#endif
 
 	num[1]=a->n;
 	num[2]=a->e;
diff -urN openssl-engine-0.9.6c/crypto/engine/Makefile.ssl openssl-engine-0.9.6c-tw/crypto/engine/Makefile.ssl
--- openssl-engine-0.9.6c/crypto/engine/Makefile.ssl	Fri Dec 21 03:35:59 2001
+++ openssl-engine-0.9.6c-tw/crypto/engine/Makefile.ssl	Thu Apr 18 15:48:34 2002
@@ -24,10 +24,10 @@
 LIB=$(TOP)/libcrypto.a
 LIBSRC= engine_err.c engine_lib.c engine_list.c engine_openssl.c \
 	hw_atalla.c hw_cswift.c hw_ncipher.c hw_aep.c hw_sureware.c \
-	hw_ubsec.c hw_keyclient.c
+	hw_ubsec.c hw_keyclient.c hw_trustway.c
 LIBOBJ= engine_err.o engine_lib.o engine_list.o engine_openssl.o \
 	hw_atalla.o hw_cswift.o hw_ncipher.o hw_aep.o hw_sureware.o \
-	hw_ubsec.o hw_keyclient.o
+	hw_ubsec.o hw_keyclient.o hw_trustway.o
 
 SRC= $(LIBSRC)
 
@@ -301,3 +301,6 @@
 hw_ubsec.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
 hw_ubsec.o: ../../include/openssl/symhacks.h ../cryptlib.h engine_int.h
 hw_ubsec.o: vendor_defns/hw_ubsec.h
+hw_trustway.o: ../../include/openssl/rsa.h
+hw_trustway.o: engine.h
+hw_trustway.o: engine_int.h
diff -urN openssl-engine-0.9.6c/crypto/engine/engine.h openssl-engine-0.9.6c-tw/crypto/engine/engine.h
--- openssl-engine-0.9.6c/crypto/engine/engine.h	Fri Dec 21 03:35:59 2001
+++ openssl-engine-0.9.6c-tw/crypto/engine/engine.h	Thu Apr 18 15:48:34 2002
@@ -406,7 +406,22 @@
 #define ENGINE_F_UBSEC_RNG_BYTES			 172
 #define ENGINE_F_UBSEC_RSA_MOD_EXP			 168
 #define ENGINE_F_UBSEC_RSA_MOD_EXP_CRT			 169
-
+#define ENGINE_F_TRUSTWAY_RSA_GEN_KEY    		 300
+#define ENGINE_F_TRUSTWAY_RSA_GEN_KEY_WITH_MECHANISM	 301
+#define ENGINE_F_TRUSTWAY_RSA_PUB_ENC    		 302
+#define ENGINE_F_TRUSTWAY_RSA_PRIV_ENC    		 303
+#define ENGINE_F_TRUSTWAY_RSA_PUB_DEC    		 304
+#define ENGINE_F_TRUSTWAY_RSA_PRIV_DEC    		 305
+#define ENGINE_F_TRUSTWAY_RSA_SIGN      		 306
+#define ENGINE_F_TRUSTWAY_RSA_VERIFY      		 307
+#define ENGINE_F_TRUSTWAY_RSA_FINISH      		 308
+#define ENGINE_F_TRUSTWAY_RAND_ADD      		 309
+#define ENGINE_F_TRUSTWAY_RAND_BYTES      		 310
+#define ENGINE_F_TRUSTWAY_GLOBAL_CHECK     		 311
+#define ENGINE_F_TRUSTWAY_INIT           		 312
+#define ENGINE_F_TRUSTWAY_FINISH           		 313
+#define ENGINE_F_TRUSTWAY_FIND_KEY		     	 314
+#define ENGINE_F_TRUSTWAY_GETSESSION		     	 315
 /* Reason codes. */
 #define ENGINE_R_AEP_INIT_FAILURE			 132
 #define ENGINE_R_ALREADY_LOADED				 100
@@ -448,7 +463,40 @@
 #define ENGINE_R_SETBNCALLBACK_FAILURE			 136
 #define ENGINE_R_SIZE_TOO_LARGE_OR_TOO_SMALL		 122
 #define ENGINE_R_UNIT_FAILURE				 115
-
+#define ENGINE_R_UNKNOWN_PADDING_TYPE			 300
+#define ENGINE_R_ENCRYPTINIT     			 301
+#define ENGINE_R_ENCRYPT        			 302
+#define ENGINE_R_SIGNINIT        			 303
+#define ENGINE_R_SIGN           			 304
+#define ENGINE_R_DECRYPTINIT     			 305
+#define ENGINE_R_DECRYPT        			 306
+#define ENGINE_R_VERIFYRECOVERINIT     			 307
+#define ENGINE_R_VERIFYRECOVER        			 308
+#define ENGINE_R_DESTROYOBJECT        			 309
+#define ENGINE_R_INVALID_MESSAGE_LENGTH			 310
+#define ENGINE_R_UNKNOWN_ALGORITHM_TYPE			 311
+#define ENGINE_R_UNKNOWN_ASN1_OBJECT_ID			 312
+#define ENGINE_R_DIGEST_TOO_BIG 			 313
+#define ENGINE_R_MALLOC_FAILURE 			 314
+#define ENGINE_R_VERIFYINIT     			 315
+#define ENGINE_R_VERIFY         			 316
+#define ENGINE_R_GEN_KEY         			 317
+#define ENGINE_R_SEEDRANDOM         			 318
+#define ENGINE_R_GENERATERANDOM         		 319
+#define ENGINE_R_INITIALIZE             		 320
+#define ENGINE_R_GETINFO                		 321
+#define ENGINE_R_GETSLOTLIST                		 322
+#define ENGINE_R_OPENSESSION                		 323
+#define ENGINE_R_NO_MODULUS_OR_NO_EXPONENT		 324
+#define ENGINE_R_ATTRIBUT_SENSITIVE_OR_INVALID 		 325   
+#define ENGINE_R_GETATTRIBUTVALUE			 326
+#define ENGINE_R_NO_MODULUS				 327
+#define ENGINE_R_NO_EXPONENT		 		 328
+#define ENGINE_R_FINDOBJECTSINIT       			 329
+#define ENGINE_R_FINDOBJECTS				 330
+#define ENGINE_R_FINDOBJECTSFINAL			 331
+#define ENGINE_R_CREATEOBJECT                            332
+#define ENGINE_R_OBJECT_NOT_FOUND			 333
 #ifdef  __cplusplus
 }
 #endif
diff -urN openssl-engine-0.9.6c/crypto/engine/engine_err.c openssl-engine-0.9.6c-tw/crypto/engine/engine_err.c
--- openssl-engine-0.9.6c/crypto/engine/engine_err.c	Fri Dec 21 03:36:00 2001
+++ openssl-engine-0.9.6c-tw/crypto/engine/engine_err.c	Thu Apr 18 15:48:34 2002
@@ -177,6 +177,22 @@
 {ERR_PACK(0,ENGINE_F_UBSEC_RNG_BYTES,0),	"UBSEC_RNG_BYTES"},
 {ERR_PACK(0,ENGINE_F_UBSEC_RSA_MOD_EXP,0),	"UBSEC_RSA_MOD_EXP"},
 {ERR_PACK(0,ENGINE_F_UBSEC_RSA_MOD_EXP_CRT,0),	"UBSEC_RSA_MOD_EXP_CRT"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_RSA_GEN_KEY,0),	"TRUSTWAY_RSA_GEN_KEY"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_RSA_GEN_KEY_WITH_MECHANISM,0),	"TRUSTWAY_RSA_GEN_KEY_WITH_MECHANISM"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_RSA_PUB_ENC,0),	"TRUSTWAY_RSA_PUB_ENC"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_RSA_PRIV_ENC,0),	"TRUSTWAY_RSA_PRIV_ENC"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_RSA_PUB_DEC,0),	"TRUSTWAY_RSA_PUB_DEC"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_RSA_PRIV_DEC,0),	"TRUSTWAY_RSA_PRIV_DEC"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_RSA_SIGN,0),	"TRUSTWAY_RSA_SIGN"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_RSA_VERIFY,0),	"TRUSTWAY_RSA_VERIFY"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_RSA_FINISH,0),	"TRUSTWAY_RSA_FINISH"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_RAND_ADD,0),	"TRUSTWAY_RAND_ADD"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_RAND_BYTES,0),	"TRUSTWAY_RAND_BYTES"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_GLOBAL_CHECK,0),	"TRUSTWAY_GLOBAL_CHECK"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_INIT,0),	        "TRUSTWAY_INIT"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_FINISH,0),	"TRUSTWAY_FINISH"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_FIND_KEY,0),	"TRUSTWAY_FIND_KEY"},
+{ERR_PACK(0,ENGINE_F_TRUSTWAY_GETSESSION,0),	"TRUSTWAY_GETSESSION"},
 {0,NULL}
 	};
 
@@ -222,6 +238,39 @@
 {ENGINE_R_SETBNCALLBACK_FAILURE          ,"setbncallback failure"},
 {ENGINE_R_SIZE_TOO_LARGE_OR_TOO_SMALL    ,"size too large or too small"},
 {ENGINE_R_UNIT_FAILURE                   ,"unit failure"},
+{ENGINE_R_UNKNOWN_PADDING_TYPE           ,"unknown padding type"},
+{ENGINE_R_ENCRYPTINIT                    ,"C_EncryptInit failed"},
+{ENGINE_R_ENCRYPT                        ,"C_Encrypt failed"},
+{ENGINE_R_SIGNINIT                       ,"C_SignInit failed"},
+{ENGINE_R_SIGN                           ,"C_Sign failed"},
+{ENGINE_R_DECRYPT                        ,"C_Decrypt failed"},
+{ENGINE_R_DECRYPTINIT                    ,"C_DecryptInit failed"},
+{ENGINE_R_VERIFYRECOVERINIT              ,"C_VerifyRecoverInit failed"},
+{ENGINE_R_VERIFYRECOVER                  ,"C_VerifyRecover failed"},
+{ENGINE_R_DESTROYOBJECT                  ,"C_DestroyObject failed"},
+{ENGINE_R_INVALID_MESSAGE_LENGTH         ,"invalid message length"},
+{ENGINE_R_UNKNOWN_ALGORITHM_TYPE         ,"unknown algorithm type"},
+{ENGINE_R_UNKNOWN_ASN1_OBJECT_ID         ,"unknown asn1 onject id"},
+{ENGINE_R_DIGEST_TOO_BIG                 ,"digest too big"},
+{ENGINE_R_MALLOC_FAILURE                 ,"malloc failure"},
+{ENGINE_R_VERIFYINIT                     ,"C_VerifyRecover failed"},
+{ENGINE_R_VERIFY                         ,"C_Verify i"},
+{ENGINE_R_GEN_KEY                        ,"C_GenerateKeyPair failed"},
+{ENGINE_R_SEEDRANDOM                     ,"C_SeedRandom failed"},
+{ENGINE_R_GENERATERANDOM                 ,"C_GenerateRandom failed"},
+{ENGINE_R_INITIALIZE                     ,"C_Initialize failed"},
+{ENGINE_R_GETINFO                        ,"C_GetInfo faile"},
+{ENGINE_R_GETSLOTLIST                    ,"C_GetSlotList failed"},
+{ENGINE_R_OPENSESSION                    ,"C_OpenSession failed"},
+{ENGINE_R_NO_MODULUS_OR_NO_EXPONENT      ,"no modulus or no exponent"},
+{ENGINE_R_ATTRIBUT_SENSITIVE_OR_INVALID  ,"attrribute sensitive or invalid"},
+{ENGINE_R_GETATTRIBUTVALUE               ,"C_GetAttributeValue failed"},
+{ENGINE_R_NO_MODULUS                     ,"no modulus"},
+{ENGINE_R_NO_EXPONENT                    ,"no exponent"},
+{ENGINE_R_FINDOBJECTSINIT                ,"C_FindObjectsInit failed"},
+{ENGINE_R_FINDOBJECTS                    ,"C_FindObjects failed"},
+{ENGINE_R_FINDOBJECTSFINAL               ,"C_FindObjectsFinal failed"},
+{ENGINE_R_CREATEOBJECT                   ,"C_CreateObject failed"},
 {0,NULL}
 	};
 
diff -urN openssl-engine-0.9.6c/crypto/engine/engine_int.h openssl-engine-0.9.6c-tw/crypto/engine/engine_int.h
--- openssl-engine-0.9.6c/crypto/engine/engine_int.h	Fri Dec 21 03:36:00 2001
+++ openssl-engine-0.9.6c-tw/crypto/engine/engine_int.h	Thu Apr 18 15:48:34 2002
@@ -170,6 +170,10 @@
 /* Returns a structure of keyclient methods. */
 ENGINE *ENGINE_keyclient();
 #endif /* !NO_HW_KEYCLIENT */
+
+#ifndef NO_HW_TRUSTWAY
+ENGINE *ENGINE_trustway();
+#endif /* !NO_HW_TRUSTWAY */
 #endif /* !NO_HW */
 
 #ifdef  __cplusplus
diff -urN openssl-engine-0.9.6c/crypto/engine/engine_list.c openssl-engine-0.9.6c-tw/crypto/engine/engine_list.c
--- openssl-engine-0.9.6c/crypto/engine/engine_list.c	Fri Dec 21 03:36:02 2001
+++ openssl-engine-0.9.6c-tw/crypto/engine/engine_list.c	Thu Apr 18 15:48:34 2002
@@ -214,6 +214,10 @@
 	if(!engine_list_add(ENGINE_keyclient()))
 		return 0;
 #endif /* !NO_HW_KEYCLIENT */
+#ifndef NO_HW_TRUSTWAY
+	if(!engine_list_add(ENGINE_trustway()))
+		return 0;
+#endif /* !NO_HW_TRUSTWAY */
 #endif /* !NO_HW */
 	engine_list_flag = 1;
 	return 1;
diff -urN openssl-engine-0.9.6c/crypto/engine/hw_trustway.c openssl-engine-0.9.6c-tw/crypto/engine/hw_trustway.c
--- openssl-engine-0.9.6c/crypto/engine/hw_trustway.c	Thu Jan  1 01:00:00 1970
+++ openssl-engine-0.9.6c-tw/crypto/engine/hw_trustway.c	Thu May 16 17:37:06 2002
@@ -0,0 +1,1352 @@
+/*
+ * Bull Trustway PKCS#11 engine for the OpenSSL project 2002
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "engine_int.h"
+#include <openssl/engine.h>
+#include <openssl/dso.h>
+#include <openssl/err.h>
+#include <stdio.h>
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+
+#ifndef NO_HW
+#ifndef NO_HW_TRUSTWAY
+
+#if !defined CK_GENERIC && !defined CK_Win32
+#define CK_GENERIC
+#endif
+
+#include <cryptoki.h>
+
+/* ENGINE level stuff */
+static int trustway_init(void);
+static int trustway_finish(void);
+static CK_SESSION_HANDLE trustway_getsession(void);
+
+/* RSA stuff */
+static int trustway_RSA_public_encrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa,int padding);
+static int trustway_RSA_private_encrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa,int padding);
+static int trustway_RSA_public_decrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa,int padding);
+static int trustway_RSA_private_decrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa,int padding);
+static int trustway_RSA_init(RSA *rsa);
+static int trustway_RSA_finish(RSA *rsa);
+static int trustway_RSA_sign(int type, unsigned char *m, unsigned int m_len, unsigned char *sigret, unsigned int *siglen, RSA *rsa);
+static int trustway_RSA_verify(int dtype, unsigned char *m, unsigned int m_len, unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
+static int trustway_RSA_generate_key(RSA *rsa, int bits,unsigned long e_value,void (*callback)(int,int,void *),void *cb_arg);
+static int trustway_RSA_i2d_PrivateKey(RSA *rsa, unsigned char **pp);
+static int trustway_RSA_d2i_PublicKey(RSA *a);
+static RSA* trustway_RSA_d2i_PrivateKey(RSA **a, unsigned char **pp, long length);
+/* RAND stuff */
+static void trustway_rand_seed(const void *buf, int num);
+static void trustway_rand_add(const void *buf, int num, double add_entropy);
+static void trustway_rand_cleanup();
+static int trustway_rand_bytes(unsigned char *buf, int num);
+static int trustway_rand_status(void);
+
+static RSA_METHOD trustway_rsa =
+{
+    "Trustway PKCS#11 RSA",
+    trustway_RSA_public_encrypt,                     /* rsa_pub_encrypt */
+    trustway_RSA_public_decrypt,                     /* rsa_pub_decrypt */
+    trustway_RSA_private_encrypt,                    /* rsa_priv_encrypt */
+    trustway_RSA_private_decrypt,                    /* rsa_priv_decrypt */
+    NULL,                                            /* rsa_mod_exp */   
+    NULL,                                            /* bn_mod_exp */
+    trustway_RSA_init,                               /* init */
+    trustway_RSA_finish,                             /* finish */
+    RSA_FLAG_EXT_PKEY | RSA_FLAG_SIGN_VER,           /* flags */
+    NULL,                                            /* app_data */
+    trustway_RSA_sign,                               /* rsa_sign */
+    trustway_RSA_verify,                             /* rsa_verify */
+    trustway_RSA_generate_key,            /* new verb in Trustway engine */
+    trustway_RSA_i2d_PrivateKey,          /* new verb in Trustway engine */
+    trustway_RSA_d2i_PublicKey,           /* new verb in Trustway engine */
+    trustway_RSA_d2i_PrivateKey           /* new verb in Trustway engine */
+};
+
+extern const char *RAND_version;
+
+
+static RAND_METHOD trustway_rand =
+{
+    /* "PKCS11 RAND method", */
+    trustway_rand_seed,
+    trustway_rand_bytes,
+    trustway_rand_cleanup,
+    trustway_rand_add,
+    trustway_rand_bytes,
+    trustway_rand_status,
+};
+
+RSA_METHOD *TRUSTWAY_RSA(void)
+{
+    return(&trustway_rsa);
+}
+
+RAND_METHOD *TRUSTWAY_RAND(void)
+{
+    return(&trustway_rand);
+}
+
+static ENGINE trustway_engine =
+{
+    "trustway",
+    "Bull Trustway PKCS#11 hardware engine support",
+    &trustway_rsa,
+    NULL,                                             /* no dsa */
+    NULL,                                             /* no dh */
+    &trustway_rand,
+    NULL,                                             /* no mod_exp */
+    NULL,                                             /* no mod_exp_crt */
+    trustway_init,
+    trustway_finish,
+    NULL,                                             /* no ctrl() */
+    NULL,                                             /* no load_privkey() */
+    NULL,                                             /* no load_pubkey() */
+    RSA_METHOD_FLAG_NO_CHECK | RSA_FLAG_EXT_PKEY,     /* flags */
+    0, 0,                                             /* no references */
+    NULL, NULL                                        /* unlinked */
+};
+
+ENGINE *ENGINE_trustway()
+{
+    return &trustway_engine;
+}
+
+static DSO *trustway_dso = NULL;
+
+/* Used in the DSO operations. */
+static const char *TRUSTWAY_LIBNAME = "gpkcs11cc2000";
+
+/* Size of an SSL signature: MD5+SHA1 */
+#define SSL_SIG_LENGTH	36
+static CK_BBOOL true = TRUE;
+static CK_BBOOL false = FALSE;
+static CK_BBOOL IS_CC2000 = FALSE;
+static CK_SLOT_ID SLOTID = 0XFFFFFFFF;
+static CK_SESSION_HANDLE tw_hSession;
+static pid_t tw_pid;
+#define CC2000_LIBRARY_VERSION_MAJOR 2
+#define CC2000_LIBRARY_VERSION_MINOR 1
+#define CC2000_MANUFACTURER_ID     "Bull S.A. - TrustWay            "
+#define CC2000_LIBRARY_DESCRIPTION "Bull CC2000 PKCS#11 Library     "
+
+/* Where in the CRYPTO_EX_DATA stack we stick our per-key contexts */
+static int rsaPubKey = -1;
+static int rsaPrivKey = -1;
+static int deletePubKeyOnFree = -1;
+static int deletePrivKeyOnFree = -1;
+
+
+
+static CK_OBJECT_HANDLE trustway_RSA_FindKey(RSA* rsa, CK_OBJECT_CLASS oKey, CK_BBOOL fKeyCreate)
+{
+    CK_RV rv;
+    CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
+    int ret=0;
+    CK_ULONG Matches;
+    CK_KEY_TYPE kType = CKK_RSA;
+    CK_ULONG ulKeyAttributeCount = 4;  /* voir ci-dessous */
+    CK_ATTRIBUTE  aKeyTemplate[] =
+    {
+	{CKA_CLASS, &oKey, sizeof(CK_OBJECT_CLASS)},
+	{CKA_KEY_TYPE, &kType, sizeof(CK_KEY_TYPE)},
+	{CKA_MODULUS, (void *)NULL, 0},
+	{CKA_PUBLIC_EXPONENT, (void *)NULL, 0}
+    };
+    int  deletePubKey;
+
+    aKeyTemplate[2].ulValueLen = BN_num_bytes(rsa->n);
+    aKeyTemplate[2].pValue = (CK_VOID_PTR)OPENSSL_malloc((size_t)aKeyTemplate[2].ulValueLen);
+    ret = BN_bn2bin(rsa->n, aKeyTemplate[2].pValue);
+
+    aKeyTemplate[3].ulValueLen = BN_num_bytes(rsa->e);
+    aKeyTemplate[3].pValue = (CK_VOID_PTR)OPENSSL_malloc((size_t)aKeyTemplate[3].ulValueLen);
+    ret = BN_bn2bin(rsa->e, aKeyTemplate[3].pValue);
+
+    tw_hSession = trustway_getsession();
+    
+    rv = C_FindObjectsInit(tw_hSession, aKeyTemplate, ulKeyAttributeCount);
+    if (rv != CKR_OK)
+    {
+	char tmpbuf[20];
+	ENGINEerr(ENGINE_F_TRUSTWAY_FIND_KEY, ENGINE_R_FINDOBJECTSINIT);
+	sprintf(tmpbuf, "%lx", rv);
+	ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	goto err;
+    }
+    rv = C_FindObjects(tw_hSession, &hKey, 1, &Matches);
+    if (rv != CKR_OK)
+    {
+	char tmpbuf[20];
+	ENGINEerr(ENGINE_F_TRUSTWAY_FIND_KEY, ENGINE_R_FINDOBJECTS);
+	sprintf(tmpbuf, "%lx", rv);
+	ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	goto err;
+    }
+    rv = C_FindObjectsFinal(tw_hSession);
+    if (rv != CKR_OK)
+    {
+	char tmpbuf[20];
+	ENGINEerr(ENGINE_F_TRUSTWAY_FIND_KEY, ENGINE_R_FINDOBJECTSFINAL);
+	sprintf(tmpbuf, "%lx", rv);
+	ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	goto err;
+    }
+    /* Assume there should be no more than one match */
+    if (Matches == 0)
+    {
+	if (fKeyCreate && oKey == CKO_PUBLIC_KEY)
+	{
+	    rv = C_CreateObject(tw_hSession, aKeyTemplate, ulKeyAttributeCount, &hKey);
+	    if (rv != CKR_OK)
+	    {
+		char tmpbuf[20];
+		ENGINEerr(ENGINE_F_TRUSTWAY_FIND_KEY, ENGINE_R_CREATEOBJECT);
+		sprintf(tmpbuf, "%lx", rv);
+		ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+		goto err;
+	    }
+	    else
+	    {
+		deletePubKey = TRUE;
+		RSA_set_ex_data(rsa, deletePubKeyOnFree, (char *)deletePubKey);
+	    }
+	}
+	else
+	{
+	    ENGINEerr(ENGINE_F_TRUSTWAY_FIND_KEY, ENGINE_R_OBJECT_NOT_FOUND);
+	    goto err;
+	}
+    }
+    if (oKey == CKO_PUBLIC_KEY)
+	RSA_set_ex_data(rsa, rsaPubKey, (char *)hKey);
+    if (oKey == CKO_PRIVATE_KEY)
+	RSA_set_ex_data(rsa, rsaPrivKey, (char *)hKey);
+
+ err:
+    if (aKeyTemplate[2].pValue != NULL)
+    {
+	OPENSSL_free(aKeyTemplate[2].pValue);
+	aKeyTemplate[2].pValue = NULL;
+    }
+
+    if (aKeyTemplate[3].pValue != NULL)
+    {
+	OPENSSL_free(aKeyTemplate[3].pValue);
+	aKeyTemplate[3].pValue = NULL;
+    }
+
+    return hKey;
+
+}
+
+/*----------------------------------------------------------------*/
+/* trustway_RSA_public_encrypt */
+/* */
+/* This function implements RSA public encryption. 'from_len'
+   bytes taken from 'from' and encrypted and put into 'to'. 'to' needs
+   to be at least RSA_size(rsa) bytes long. The number of bytes
+   written into 'to' is returned. -1 is returned on an error. The
+   operation performed is to = from^rsa->e mod rsa->n. */
+/* for PKCS11, use C_EncryptInit + C_Encrypt */
+/*----------------------------------------------------------------*/
+static int trustway_RSA_public_encrypt(int flen,
+				       unsigned char *from,
+				       unsigned char *to,
+				       RSA *rsa,
+				       int padding)
+{
+    CK_ULONG bytesEncrypted=0;
+    CK_RV rv;
+    CK_MECHANISM Mechanism_rsa = {CKM_RSA_PKCS, NULL, 0};
+    CK_MECHANISM *pMechanism = &Mechanism_rsa;
+    CK_OBJECT_HANDLE hPublicKey = CK_INVALID_HANDLE;
+	
+    if (padding != RSA_PKCS1_PADDING)
+    {
+	ENGINEerr(ENGINE_F_TRUSTWAY_RSA_PUB_ENC, ENGINE_R_UNKNOWN_PADDING_TYPE);
+	return -1;
+    }
+
+    hPublicKey = (CK_OBJECT_HANDLE)RSA_get_ex_data(rsa, rsaPubKey);
+    if (hPublicKey == CK_INVALID_HANDLE)
+	hPublicKey = trustway_RSA_FindKey(rsa, CKO_PUBLIC_KEY, false);
+
+    tw_hSession = trustway_getsession();
+    
+    if (hPublicKey != CK_INVALID_HANDLE)
+    {
+	rv = C_EncryptInit(tw_hSession, pMechanism, hPublicKey);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_PUB_ENC, ENGINE_R_ENCRYPTINIT);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    return -1;
+	}
+	
+	rv = C_Encrypt(tw_hSession, from, flen, NULL_PTR, &bytesEncrypted);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_PUB_ENC, ENGINE_R_ENCRYPT);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    return -1;
+	}
+
+	rv = C_Encrypt(tw_hSession, from, flen, to, &bytesEncrypted);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_PUB_ENC, ENGINE_R_ENCRYPT);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    return -1;
+	}
+    }
+    
+    return bytesEncrypted;
+}
+
+
+
+/*----------------------------------------------------------------*/
+/* trustway_RSA_private_encrypt */
+/* This function implements RSA private encryption.
+   That corresponds to a signature and only the RSA_PKCS1_PADDING
+   is supported.
+   flen : bytes taken from 'from' and encrypted and put into 'to'.
+   to : needs to be at least bytes long.
+   ret : returns the number of bytes written into 'to' or -1 if an error.
+   for PKCS11 use C_SignInit + C_Sign */
+/*----------------------------------------------------------------*/
+static int trustway_RSA_private_encrypt(int flen,
+					unsigned char *from,
+					unsigned char *to,
+					RSA *rsa,
+					int padding)
+{
+    CK_ULONG ulSignatureLen=0;
+    CK_RV rv;
+    CK_MECHANISM Mechanism_rsa = {CKM_RSA_PKCS, NULL, 0};
+    CK_MECHANISM *pMechanism = &Mechanism_rsa;
+    CK_OBJECT_HANDLE hPrivateKey= CK_INVALID_HANDLE;
+	
+    if (padding != RSA_PKCS1_PADDING)
+    {
+	ENGINEerr(ENGINE_F_TRUSTWAY_RSA_PRIV_ENC, ENGINE_R_UNKNOWN_PADDING_TYPE);
+	return -1;
+    }
+    
+    tw_hSession = trustway_getsession();
+    
+    hPrivateKey = (CK_OBJECT_HANDLE)RSA_get_ex_data(rsa, rsaPrivKey);
+    if (hPrivateKey == CK_INVALID_HANDLE)
+	hPrivateKey = trustway_RSA_FindKey(rsa, CKO_PRIVATE_KEY, false);
+    
+    if (hPrivateKey != CK_INVALID_HANDLE)
+    {
+	rv = C_SignInit(tw_hSession, pMechanism, hPrivateKey);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_PRIV_ENC, ENGINE_R_SIGNINIT);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    return -1;
+	}
+	
+	rv = C_Sign(tw_hSession, from, flen, NULL_PTR, &ulSignatureLen);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_PRIV_ENC, ENGINE_R_SIGN);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    return -1;
+	}
+	
+	rv = C_Sign(tw_hSession, from, flen, to, &ulSignatureLen);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_PRIV_ENC, ENGINE_R_SIGN);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    return -1;
+	}
+    }
+    
+    return ulSignatureLen;
+}
+
+
+
+/*----------------------------------------------------------------*/
+/* trustway_RSA_private_decrypt */
+/* */
+/*This function implements RSA private decryption.
+
+  flen : bytes are taken from 'from' and decrypted.
+  The decrypted data is put into 'to'. 
+  ret : returns the number of bytes -1 if an error.
+  The operation performed is to = from^rsa->d mod rsa->n.*/
+/* for PKCS11 use C_DecryptInit + C_Decrypt */
+/*----------------------------------------------------------------*/
+static int trustway_RSA_private_decrypt(int flen,
+					unsigned char *from,
+					unsigned char *to,
+					RSA *rsa,
+					int padding)
+{
+    CK_ULONG bytesDecrypted = flen;
+    CK_RV rv;
+    CK_MECHANISM Mechanism_rsa = {CKM_RSA_PKCS, NULL, 0};
+    CK_MECHANISM *pMechanism = &Mechanism_rsa;
+    CK_OBJECT_HANDLE hPrivateKey;
+	
+    if (padding != RSA_PKCS1_PADDING)
+    {
+	ENGINEerr(ENGINE_F_TRUSTWAY_RSA_PRIV_DEC, ENGINE_R_UNKNOWN_PADDING_TYPE);
+	return -1;
+    }
+    
+    tw_hSession = trustway_getsession();
+    
+    hPrivateKey = (CK_OBJECT_HANDLE)RSA_get_ex_data(rsa, rsaPrivKey);
+    if (hPrivateKey == CK_INVALID_HANDLE)
+	hPrivateKey = trustway_RSA_FindKey(rsa, CKO_PRIVATE_KEY, false);
+
+    if (hPrivateKey != CK_INVALID_HANDLE)
+    {
+	rv = C_DecryptInit(tw_hSession, pMechanism, hPrivateKey);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_PRIV_DEC, ENGINE_R_DECRYPTINIT);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    return -1;
+	}
+	
+	rv = C_Decrypt(tw_hSession, from, flen, to, &bytesDecrypted);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_PRIV_DEC, ENGINE_R_DECRYPT);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    return -1;
+	}
+    }
+    return bytesDecrypted;
+}
+
+
+
+/*----------------------------------------------------------------*/
+/* trustway_RSA_public_decrypt */
+/* */
+/* This function implements RSA public decryption, the rsaKey
+   variable is the public key (but can be a private key).
+   This function should be processed as a pkcs11
+   verify-recover function
+   flen : bytes are taken from 'from' and decrypted.
+   to : The decrypted data.
+   ret : The number of bytes encrypted. -1 is returned to indicate an error.
+   The operation performed is to = from^rsa->e mod rsa->n.*/
+/* for PKCS11 use C_VerifyRecoverInit + C_VerifyRecover */
+/*'from' points to signature and 'flen' contains its length*/
+/*----------------------------------------------------------------*/
+static int trustway_RSA_public_decrypt(int flen,
+				       unsigned char *from,
+				       unsigned char *to,
+				       RSA *rsa,
+				       int padding)
+{
+    CK_ULONG bytesDecrypted = 0;
+    CK_RV rv;
+    CK_MECHANISM Mechanism_rsa = {CKM_RSA_PKCS, NULL, 0};
+    CK_MECHANISM *pMechanism = &Mechanism_rsa;
+    CK_OBJECT_HANDLE hPublicKey = CK_INVALID_HANDLE;
+	
+    if (padding != RSA_PKCS1_PADDING)
+    {
+	ENGINEerr(ENGINE_F_TRUSTWAY_RSA_PUB_DEC, ENGINE_R_UNKNOWN_PADDING_TYPE);
+	return -1;
+    }
+    
+    tw_hSession = trustway_getsession();
+    
+    hPublicKey = (CK_OBJECT_HANDLE)RSA_get_ex_data(rsa, rsaPubKey);
+    if (hPublicKey == CK_INVALID_HANDLE)
+	hPublicKey = trustway_RSA_FindKey(rsa, CKO_PUBLIC_KEY, false);
+
+    if (hPublicKey != CK_INVALID_HANDLE)
+    {	
+	rv = C_VerifyRecoverInit(tw_hSession, pMechanism, hPublicKey);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_PUB_DEC, ENGINE_R_VERIFYRECOVERINIT);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    return -1;
+	}
+	
+	rv = C_VerifyRecover(tw_hSession, from, flen, NULL_PTR, &bytesDecrypted);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_PUB_DEC, ENGINE_R_VERIFYRECOVER);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    return -1;
+	}
+	rv = C_VerifyRecover(tw_hSession, from, flen, to, &bytesDecrypted);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_PUB_DEC, ENGINE_R_VERIFYRECOVER);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    return -1;
+	}
+    }
+
+    return bytesDecrypted;
+}
+
+static int trustway_RSA_init(RSA *rsa)
+{
+    rsa->flags |= RSA_FLAG_EXT_PKEY | RSA_FLAG_SIGN_VER;
+
+    return 1;
+}
+
+
+
+static int trustway_RSA_finish(RSA *rsa)
+{
+    CK_RV rv;
+    CK_OBJECT_HANDLE hPublicKey = CK_INVALID_HANDLE;
+    CK_OBJECT_HANDLE hPrivateKey = CK_INVALID_HANDLE;
+    unsigned int deletePubKey;
+    unsigned int deletePrivKey;
+	
+    if (rsa->_method_mod_n != NULL)
+	BN_MONT_CTX_free(rsa->_method_mod_n);
+    if (rsa->_method_mod_p != NULL)
+	BN_MONT_CTX_free(rsa->_method_mod_p);
+    if (rsa->_method_mod_q != NULL)
+	BN_MONT_CTX_free(rsa->_method_mod_q);
+	
+    deletePrivKey = (unsigned int)RSA_get_ex_data(rsa, deletePrivKeyOnFree);
+    hPrivateKey = (CK_OBJECT_HANDLE)RSA_get_ex_data(rsa, rsaPrivKey);
+
+    tw_hSession = trustway_getsession();
+    
+    if ((deletePrivKey) && (hPrivateKey != CK_INVALID_HANDLE))
+    {
+	rv = C_DestroyObject(tw_hSession, hPrivateKey);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_FINISH, ENGINE_R_DESTROYOBJECT);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    return 0;
+	}
+	hPrivateKey = CK_INVALID_HANDLE;
+	RSA_set_ex_data(rsa, rsaPrivKey, (char *)hPrivateKey);
+	deletePrivKey = FALSE;
+	RSA_set_ex_data(rsa, deletePrivKeyOnFree, (char *)deletePrivKey);
+    }
+	
+    deletePubKey = (unsigned int)RSA_get_ex_data(rsa, deletePubKeyOnFree);
+    hPublicKey = (CK_OBJECT_HANDLE)RSA_get_ex_data(rsa, rsaPubKey);
+
+    if ((deletePubKey) && (hPublicKey != CK_INVALID_HANDLE))
+    {
+	rv = C_DestroyObject(tw_hSession, hPublicKey);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_FINISH, ENGINE_R_DESTROYOBJECT);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    return 0;
+	}
+	hPublicKey = CK_INVALID_HANDLE;
+	RSA_set_ex_data(rsa, rsaPubKey, (char *)hPublicKey);
+	deletePubKey = FALSE;
+	RSA_set_ex_data(rsa, deletePubKeyOnFree, (char *)deletePubKey);
+    }
+	
+    return 1;
+}
+
+
+
+static int trustway_RSA_sign(int type,
+			     unsigned char *m,
+			     unsigned int m_len,
+			     unsigned char *sigret,
+			     unsigned int *siglen,
+			     RSA *rsa)
+{
+    X509_SIG sig;
+    ASN1_TYPE parameter;
+    int i,j;
+    unsigned char *p,*s = NULL;
+    X509_ALGOR algor;
+    ASN1_OCTET_STRING digest;
+    CK_RV rv;
+    CK_MECHANISM Mechanism_rsa = {CKM_RSA_PKCS, NULL, 0};
+    CK_MECHANISM *pMechanism = &Mechanism_rsa;
+    CK_OBJECT_HANDLE hPrivateKey;
+    int ret = 0;
+
+    /* Encode the digest	*/
+    /* Special case: SSL signature, just check the length */
+    if(type == NID_md5_sha1)
+    {
+	if(m_len != SSL_SIG_LENGTH)
+	{
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_SIGN, ENGINE_R_INVALID_MESSAGE_LENGTH);
+	    return 0;
+	}
+	i = SSL_SIG_LENGTH;
+	s = m;
+    }
+    else
+    {
+	sig.algor= &algor;
+	sig.algor->algorithm=OBJ_nid2obj(type);
+	if (sig.algor->algorithm == NULL)
+	{
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_SIGN, ENGINE_R_UNKNOWN_ALGORITHM_TYPE);
+	    return 0;
+	}
+	if (sig.algor->algorithm->length == 0)
+	{
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_SIGN, ENGINE_R_UNKNOWN_ASN1_OBJECT_ID);
+	    return 0;
+	}
+	parameter.type=V_ASN1_NULL;
+	parameter.value.ptr=NULL;
+	sig.algor->parameter= &parameter;
+	
+	sig.digest= &digest;
+	sig.digest->data=m;
+	sig.digest->length=m_len;
+	
+	i=i2d_X509_SIG(&sig,NULL);
+    }
+    
+    j=RSA_size(rsa);
+    if ((i-RSA_PKCS1_PADDING) > j)
+    {
+	ENGINEerr(ENGINE_F_TRUSTWAY_RSA_SIGN, ENGINE_R_DIGEST_TOO_BIG);
+	return 0;
+    }
+    
+    if(type != NID_md5_sha1)
+    {
+	s=(unsigned char *)OPENSSL_malloc((unsigned int)j+1);
+	if (s == NULL)
+	{
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_SIGN, ENGINE_R_MALLOC_FAILURE);
+	    return 0;
+	}
+	p=s;
+	i2d_X509_SIG(&sig,&p);
+    }
+    
+    tw_hSession = trustway_getsession();
+    
+    hPrivateKey = (CK_OBJECT_HANDLE)RSA_get_ex_data(rsa, rsaPrivKey);
+    if (hPrivateKey == CK_INVALID_HANDLE)
+	hPrivateKey = trustway_RSA_FindKey(rsa, CKO_PRIVATE_KEY, false);
+
+    if (hPrivateKey != CK_INVALID_HANDLE)
+    {
+	rv = C_SignInit(tw_hSession, pMechanism, hPrivateKey);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_SIGN, ENGINE_R_SIGNINIT);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    goto err;
+	}
+
+	*siglen = j;
+	rv = C_Sign(tw_hSession, s, i, sigret, (CK_ULONG_PTR)siglen);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_SIGN, ENGINE_R_SIGN);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    goto err;
+	}
+	ret = 1;
+    }
+
+err:
+    if(type != NID_md5_sha1)
+    {
+	memset(s,0,(unsigned int)j+1);
+	OPENSSL_free(s);
+    }
+    
+    return ret;
+}
+
+static int trustway_RSA_verify(int type,
+			       unsigned char *m,
+			       unsigned int m_len,
+			       unsigned char *sigbuf,
+			       unsigned int siglen,
+			       RSA *rsa)
+{
+    X509_SIG sig;
+    ASN1_TYPE parameter;
+    int i,j;
+    unsigned char *p,*s = NULL;
+    X509_ALGOR algor;
+    ASN1_OCTET_STRING digest;
+    CK_RV rv;
+    CK_MECHANISM Mechanism_rsa = {CKM_RSA_PKCS, NULL, 0};
+    CK_MECHANISM *pMechanism = &Mechanism_rsa;
+    CK_OBJECT_HANDLE hPublicKey;
+    int ret = 0;
+
+    /* Encode the digest	*/
+    /* Special case: SSL signature, just check the length */
+    if(type == NID_md5_sha1)
+    {
+	if(m_len != SSL_SIG_LENGTH)
+	{
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_VERIFY, ENGINE_R_INVALID_MESSAGE_LENGTH);
+	    return 0;
+	}
+	i = SSL_SIG_LENGTH;
+	s = m;
+    }
+    else
+    {
+	sig.algor= &algor;
+	sig.algor->algorithm=OBJ_nid2obj(type);
+	if (sig.algor->algorithm == NULL)
+	{
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_VERIFY, ENGINE_R_UNKNOWN_ALGORITHM_TYPE);
+	    return 0;
+	}
+	if (sig.algor->algorithm->length == 0)
+	{
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_VERIFY, ENGINE_R_UNKNOWN_ASN1_OBJECT_ID);
+	    return 0;
+	}
+	parameter.type=V_ASN1_NULL;
+	parameter.value.ptr=NULL;
+	sig.algor->parameter= &parameter;
+	sig.digest= &digest;
+	sig.digest->data=m;
+	sig.digest->length=m_len;
+	i=i2d_X509_SIG(&sig,NULL);
+    }
+    
+    j=RSA_size(rsa);
+    if ((i-RSA_PKCS1_PADDING) > j)
+    {
+	ENGINEerr(ENGINE_F_TRUSTWAY_RSA_VERIFY, ENGINE_R_DIGEST_TOO_BIG);
+	return 0;
+    }
+    
+    if(type != NID_md5_sha1)
+    {
+	s=(unsigned char *)OPENSSL_malloc((unsigned int)j+1);
+	if (s == NULL)
+	{
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_VERIFY, ENGINE_R_MALLOC_FAILURE);
+	    return 0;
+	}
+	p=s;
+	i2d_X509_SIG(&sig,&p);
+    }
+    
+    tw_hSession = trustway_getsession();
+    
+    hPublicKey = (CK_OBJECT_HANDLE)RSA_get_ex_data(rsa, rsaPubKey);
+    if (hPublicKey == CK_INVALID_HANDLE)
+	hPublicKey = trustway_RSA_FindKey(rsa, CKO_PUBLIC_KEY, false);
+
+    if (hPublicKey != CK_INVALID_HANDLE)
+    {
+	rv = C_VerifyInit(tw_hSession, pMechanism, hPublicKey);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_VERIFY, ENGINE_R_VERIFYINIT);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    goto err;
+	}
+	rv = C_Verify(tw_hSession, s, i, sigbuf, (CK_ULONG)siglen);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_VERIFY, ENGINE_R_VERIFY);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    goto err;
+	}
+	ret = 1;
+    }
+
+err:
+    if(type != NID_md5_sha1)
+    {
+	memset(s,0,(unsigned int)siglen);
+	OPENSSL_free(s);
+    }
+
+    return ret;
+}
+
+static int trustway_RSA_generate_key_with_mechanism(RSA* rsa,
+						    CK_MECHANISM *pMechanism,
+						    int bits,
+						    unsigned long e_value,
+						    void (*callback)(int,int,void *),
+						    void *cb_arg, CK_BBOOL token)
+{
+    CK_ULONG i;
+    CK_OBJECT_HANDLE hPublicKey;
+    CK_OBJECT_HANDLE hPrivateKey;
+    CK_OBJECT_CLASS oPublicKey = CKO_PUBLIC_KEY;
+    CK_OBJECT_CLASS oPrivateKey = CKO_PRIVATE_KEY;
+    CK_KEY_TYPE kType = CKK_RSA;
+    CK_ULONG ulPublicKeyAttributeCount = 7; /* voir ci-dessous */
+    CK_ATTRIBUTE aPublicKeyTemplate[] =
+    {
+	{CKA_CLASS, &oPublicKey, sizeof(CK_OBJECT_CLASS)},
+	{CKA_TOKEN, (void *)NULL, 0},
+	{CKA_PRIVATE, &true, sizeof(true)},
+	{CKA_MODIFIABLE, &false, sizeof(false)},
+	{CKA_KEY_TYPE, &kType, sizeof(CK_KEY_TYPE)},
+	{CKA_MODULUS_BITS, (void *)&bits, sizeof(bits)},
+	{CKA_PUBLIC_EXPONENT, (void *)NULL, 0}
+    };
+    CK_ULONG	 ulPublicKeyAttributeResultCount = 2;
+    CK_ATTRIBUTE aPublicKeyResult[] =
+    {
+	{CKA_MODULUS, (void *)NULL, 0},
+	/* {CKA_MODULUS_BITS, (void *)NULL, 0}, */
+	{CKA_PUBLIC_EXPONENT, (void *)NULL, 0}
+    };
+    CK_ULONG	ulPrivateKeyAttributeCount = 11; /* voir ci-dessous */
+    CK_ATTRIBUTE	aPrivateKeyTemplate[] =
+    {
+	{CKA_CLASS, &oPrivateKey, sizeof(CK_OBJECT_CLASS)},
+	{CKA_TOKEN, (void *)NULL, 0},
+	{CKA_PRIVATE, &true, sizeof(CK_BBOOL)},
+	{CKA_MODIFIABLE, &false, sizeof(CK_BBOOL)},
+	{CKA_KEY_TYPE, &kType, sizeof(CK_KEY_TYPE)},
+	{CKA_SENSITIVE, &true, sizeof(CK_BBOOL)},
+	{CKA_DECRYPT, &true, sizeof(CK_BBOOL)},
+	{CKA_SIGN, &true, sizeof(CK_BBOOL)},
+	{CKA_SIGN_RECOVER, &true, sizeof(CK_BBOOL)},
+	{CKA_UNWRAP, &true, sizeof(CK_BBOOL)},
+	{CKA_EXTRACTABLE, &true, sizeof(CK_BBOOL)}
+    };
+    CK_RV rv;
+    CK_ATTRIBUTE *pModulus = NULL;
+    CK_ATTRIBUTE *pExponent = NULL;
+    BIGNUM	*bn_e=NULL;
+    int ret = 1;
+    
+
+    bn_e = BN_new();
+    if (bn_e == NULL)
+	goto err;
+    /* The problem is when building with 8, 16, or 32 BN_ULONG,
+     * unsigned long can	 be larger	 */
+    for (i=0; i<sizeof(unsigned long)*8; i++)
+    {
+	if (e_value & (1UL<<i))
+	    BN_set_bit(bn_e,i);
+    }
+    aPublicKeyTemplate[6].ulValueLen = BN_num_bytes(bn_e);
+    aPublicKeyTemplate[6].pValue = OPENSSL_malloc(aPublicKeyTemplate[6].ulValueLen);
+    i = BN_bn2bin(bn_e, aPublicKeyTemplate[6].pValue);
+    aPublicKeyTemplate[1].ulValueLen = sizeof(token);
+    aPublicKeyTemplate[1].pValue = &token;
+    aPrivateKeyTemplate[1].ulValueLen = sizeof(token);
+    aPrivateKeyTemplate[1].pValue = &token;
+
+    tw_hSession = trustway_getsession();
+    
+    rv = C_GenerateKeyPair(tw_hSession,
+			   pMechanism,
+			   aPublicKeyTemplate,
+			   ulPublicKeyAttributeCount,
+			   aPrivateKeyTemplate,
+			   ulPrivateKeyAttributeCount,
+			   &hPublicKey,
+			   &hPrivateKey);
+    if (rv != CKR_OK)
+    {
+	char tmpbuf[20];
+	ENGINEerr(ENGINE_F_TRUSTWAY_RSA_GEN_KEY_WITH_MECHANISM, ENGINE_R_GEN_KEY);
+	sprintf(tmpbuf, "%lx", rv);
+	ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	ret = 0;
+	goto err;
+    }
+
+    rv = C_GetAttributeValue(tw_hSession, hPublicKey, aPublicKeyResult, ulPublicKeyAttributeResultCount);
+
+    switch(rv) 
+    {
+      case CKR_OK:
+	for(i = 0; i < ulPublicKeyAttributeResultCount; i++) 
+	{ /* Al	locate required buffers */
+	    if (((CK_LONG) aPublicKeyResult[i].ulValueLen) == -1) 
+	    { /* can't get this attribute */
+		ENGINEerr(ENGINE_F_TRUSTWAY_RSA_GEN_KEY_WITH_MECHANISM, ENGINE_R_NO_MODULUS_OR_NO_EXPONENT);
+		goto err;
+	    }
+	    else 
+	    {
+		aPublicKeyResult[i].pValue = OPENSSL_malloc(aPublicKeyResult[i].ulValueLen);
+		if (!aPublicKeyResult[i].pValue)
+		{
+		    ENGINEerr(ENGINE_F_TRUSTWAY_RSA_GEN_KEY_WITH_MECHANISM, ENGINE_R_GEN_KEY);
+		    goto err;
+		}
+	    }
+	}
+	break;
+      case CKR_ATTRIBUTE_SENSITIVE:
+      case CKR_ATTRIBUTE_TYPE_INVALID:
+	ENGINEerr(ENGINE_F_TRUSTWAY_RSA_GEN_KEY_WITH_MECHANISM, ENGINE_R_ATTRIBUT_SENSITIVE_OR_INVALID);
+	goto err;
+      default:
+	ENGINEerr(ENGINE_F_TRUSTWAY_RSA_GEN_KEY_WITH_MECHANISM, ENGINE_R_GETATTRIBUTVALUE);
+	goto err;
+    }
+    /*	 Then get the values */
+    rv = C_GetAttributeValue(tw_hSession, hPublicKey, aPublicKeyResult,ulPublicKeyAttributeResultCount);
+    switch(rv) 
+    {
+      case CKR_OK:
+	break;
+      case CKR_ATTRIBUTE_SENSITIVE:
+      case CKR_ATTRIBUTE_TYPE_INVALID:
+	ENGINEerr(ENGINE_F_TRUSTWAY_RSA_GEN_KEY_WITH_MECHANISM, ENGINE_R_ATTRIBUT_SENSITIVE_OR_INVALID);
+	goto err;
+      default:
+	ENGINEerr(ENGINE_F_TRUSTWAY_RSA_GEN_KEY_WITH_MECHANISM, ENGINE_R_GETATTRIBUTVALUE);
+	goto err;
+    }
+
+    /* recherche du Modulus */ 
+    for(i = 0; i < ulPublicKeyAttributeResultCount; i++) 
+    {
+	if (aPublicKeyResult[i].type == CKA_MODULUS)
+	{
+	    if (((CK_LONG) aPublicKeyResult[i].ulValueLen) != -1) 
+	    {
+		pModulus = &(aPublicKeyResult[i]);
+	    }
+	    break;
+	}
+    }
+    if (pModulus == NULL)
+    {
+	ENGINEerr(ENGINE_F_TRUSTWAY_RSA_GEN_KEY_WITH_MECHANISM, ENGINE_R_NO_MODULUS);
+	goto err;
+    }
+    /* 	set n */ 
+    rsa->n = BN_bin2bn(pModulus->pValue, pModulus->ulValueLen, rsa->n);
+
+    /*	 search Exponent */
+    for(i = 0; i < ulPublicKeyAttributeResultCount; i++) 
+    {
+	if (aPublicKeyResult[i].type == CKA_PUBLIC_EXPONENT)
+	{
+	    if (((CK_LONG) aPublicKeyResult[i].ulValueLen) != -1) 
+	    {
+		pExponent = &(aPublicKeyResult[i]);
+	    }
+	    break;
+	}
+    }
+    if (pExponent == NULL)
+    {
+	ENGINEerr(ENGINE_F_TRUSTWAY_RSA_GEN_KEY_WITH_MECHANISM, ENGINE_R_NO_EXPONENT);
+	goto err;
+    }
+    /* 	set e */ 
+    rsa->e = bn_e;
+    bn_e = NULL;
+	
+    RSA_set_ex_data(rsa, rsaPubKey, (char *)hPublicKey);
+    RSA_set_ex_data(rsa, rsaPrivKey, (char *)hPrivateKey);
+
+ err:
+     
+    for(i = 0; i < ulPublicKeyAttributeResultCount; i++) 
+    {
+	if (aPublicKeyResult[i].pValue)
+	{ 
+	    OPENSSL_free(aPublicKeyResult[i].pValue);
+	    aPublicKeyResult[i].pValue = NULL;
+	}
+    }
+    if (aPublicKeyTemplate[6].pValue != NULL)
+    {
+	OPENSSL_free(aPublicKeyTemplate[6].pValue);
+	aPublicKeyTemplate[6].pValue = NULL;
+    }
+    if (bn_e != NULL)
+	BN_free(bn_e);
+
+    return ret;
+}
+
+
+
+/* ************************************************************ */
+/*								*/
+/*	function :	trustway_RSA_generate_key		*/
+/*								*/
+/* ************************************************************ */
+static int trustway_RSA_generate_key(RSA* rsa,
+				     int bits,
+				     unsigned long e_value,
+				     void (*callback)(int,int,void *),
+				     void *cb_arg)
+{
+    CK_MECHANISM Mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0};
+    CK_BBOOL token = TRUE;
+	
+    return trustway_RSA_generate_key_with_mechanism(rsa, &Mechanism, bits, e_value, callback, cb_arg, token);
+}
+
+RSA* trustway_RSA_generate_tmp_key(int bits,unsigned long e_value,void (*callback)(int,int,void *),void *cb_arg)
+{
+  RSA	*rsa;
+  CK_MECHANISM	Mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0};
+  CK_BBOOL      token = FALSE;
+  unsigned int deleteKey;
+
+  rsa=RSA_new();
+  if (rsa == NULL)
+      return NULL;
+  else
+  {
+      if (trustway_RSA_generate_key_with_mechanism(rsa, &Mechanism, bits, e_value, callback, cb_arg, token))
+      {
+	  deleteKey = TRUE;
+	  RSA_set_ex_data(rsa, deletePubKeyOnFree, (char *)deleteKey);
+	  RSA_set_ex_data(rsa, deletePrivKeyOnFree, (char *)deleteKey);
+	  return rsa;
+      }
+      else 
+	  return NULL;
+  }
+}
+
+static int trustway_RSA_i2d_PrivateKey(RSA *a, unsigned char **pp)
+{
+    return i2d_RSAPublicKey(a, pp); 
+}
+
+static int trustway_RSA_d2i_PublicKey(RSA *rsa)
+{
+    CK_OBJECT_HANDLE  hPublicKey = CK_INVALID_HANDLE;
+
+    hPublicKey = (CK_OBJECT_HANDLE)RSA_get_ex_data(rsa, rsaPubKey);
+    if (hPublicKey == CK_INVALID_HANDLE)
+	 hPublicKey = trustway_RSA_FindKey(rsa, CKO_PUBLIC_KEY, true);
+
+    if (hPublicKey == CK_INVALID_HANDLE)
+	return 0;
+    
+    return 1;
+}
+
+static RSA* trustway_RSA_d2i_PrivateKey(RSA **a, unsigned char **pp, long length)
+{
+    RSA *rsa;
+    CK_OBJECT_HANDLE  hPrivateKey = CK_INVALID_HANDLE;
+
+    rsa = d2i_RSAPublicKey(a, pp, length);
+    if (rsa == NULL)
+	return NULL;
+
+    hPrivateKey = (CK_OBJECT_HANDLE)RSA_get_ex_data(rsa, rsaPrivKey);
+    if (hPrivateKey == CK_INVALID_HANDLE)
+	hPrivateKey = trustway_RSA_FindKey(rsa, CKO_PRIVATE_KEY, false);
+
+    if (hPrivateKey == CK_INVALID_HANDLE)
+	return NULL;
+    
+    return rsa;
+}
+
+static void trustway_rand_cleanup()
+{
+    return;
+}
+
+
+
+static void trustway_rand_add(const void *buf,
+			      int num,
+			      double add)
+{
+    CK_RV rv;
+
+    tw_hSession = trustway_getsession();
+    
+    rv = C_SeedRandom(tw_hSession, (CK_BYTE_PTR)buf, num);
+    if (rv != CKR_OK)
+    {
+	char tmpbuf[20];
+	ENGINEerr(ENGINE_F_TRUSTWAY_RAND_ADD, ENGINE_R_SEEDRANDOM);
+	sprintf(tmpbuf, "%lx", rv);
+	ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+    }
+}
+
+
+
+static void trustway_rand_seed(const void *buf,
+			       int num)
+{
+    trustway_rand_add(buf, num, num);
+}
+
+
+
+static int trustway_rand_bytes(unsigned char *buf,
+			       int num)
+{
+    CK_RV rv;
+	
+    tw_hSession = trustway_getsession();
+    
+    rv = C_GenerateRandom(tw_hSession, buf, num);
+    if (rv != CKR_OK)
+    {
+	char tmpbuf[20];
+	ENGINEerr(ENGINE_F_TRUSTWAY_RAND_BYTES, ENGINE_R_GENERATERANDOM);
+	sprintf(tmpbuf, "%lx", rv);
+	ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	return 0;
+    }
+    return 1;
+}
+
+
+
+static int trustway_rand_status(void)
+{
+    return 1;
+}
+
+
+
+/* Setup default global context */
+static CK_RV trustway_global_check(void)
+{
+    CK_RV rv = CKR_OK;
+    CK_INFO Info;
+    CK_SLOT_ID_PTR pSlotList;
+    CK_ULONG ulSlotCount;
+	
+   rv = C_Initialize(NULL_PTR);
+    if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
+    {
+	char tmpbuf[20];
+	ENGINEerr(ENGINE_F_TRUSTWAY_GLOBAL_CHECK, ENGINE_R_INITIALIZE);
+	sprintf(tmpbuf, "%lx", rv);
+	ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	return rv;
+    }
+    /*	 check libraryDescription to detect CC2000 */
+    rv = C_GetInfo(&Info);
+    if (rv != CKR_OK) 
+    {
+	char tmpbuf[20];
+	ENGINEerr(ENGINE_F_TRUSTWAY_GLOBAL_CHECK, ENGINE_R_GETINFO);
+	sprintf(tmpbuf, "%lx", rv);
+	ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	C_Finalize(NULL_PTR);
+	return rv;
+    }
+    if (!strncmp(Info.libraryDescription, CC2000_LIBRARY_DESCRIPTION, 32))
+    {
+	/* CC2000 (hardware crypto) */
+	IS_CC2000 = TRUE;
+	SLOTID = 0xFFFFFFFF;
+    }
+    else
+    {
+	/* GPKCS11 (software crypto) */
+	IS_CC2000 = FALSE;
+	rv = C_GetSlotList(TRUE, NULL_PTR, &ulSlotCount);
+	if ((rv != CKR_OK) || (ulSlotCount == 0)) 
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_GLOBAL_CHECK, ENGINE_R_GETSLOTLIST);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	}
+	else
+	{
+	    pSlotList = (CK_SLOT_ID_PTR) OPENSSL_malloc(ulSlotCount * sizeof(CK_SLOT_ID));
+	    if ( pSlotList != NULL)
+	    {
+		rv = C_GetSlotList(TRUE, pSlotList, &ulSlotCount);
+		if (rv != CKR_OK) 
+		{
+		    char tmpbuf[20];
+		    ENGINEerr(ENGINE_F_TRUSTWAY_GLOBAL_CHECK, ENGINE_R_GETSLOTLIST);
+		    sprintf(tmpbuf, "%lx", rv);
+		    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+		    OPENSSL_free(pSlotList);
+		    return rv;
+		}
+		else
+		{
+		    SLOTID = pSlotList[0];
+		}
+		OPENSSL_free(pSlotList);
+	    }
+	}
+    }
+    return CKR_OK;
+}
+
+/* get pkcs11 session handle function */
+static CK_SESSION_HANDLE trustway_getsession(void)
+{
+    CK_RV rv = CKR_OK;
+    pid_t mypid = getpid();
+    
+    if((tw_hSession == CK_INVALID_HANDLE) ||
+       (tw_pid != mypid))
+    {
+	rv = C_OpenSession(SLOTID,
+			   CKF_SERIAL_SESSION | CKF_RW_SESSION,
+			   NULL_PTR,
+			   NULL_PTR,
+			   &tw_hSession);
+	if (rv != CKR_OK)
+	{
+	    char tmpbuf[20];
+	    ENGINEerr(ENGINE_F_TRUSTWAY_GETSESSION, ENGINE_R_OPENSESSION);
+	    sprintf(tmpbuf, "%lx", rv);
+	    ERR_add_error_data(2, "PKCS11 CK_RV=0X", tmpbuf);
+	    return rv;
+	}
+	tw_pid = mypid;
+    }
+    return tw_hSession;
+}
+
+/* free pkcs11 session handle function */
+void trustway_freesession(void)
+{
+    CK_RV rv = CKR_OK;
+    if(tw_hSession != CK_INVALID_HANDLE)
+	rv = C_CloseSession(tw_hSession);
+    return;
+}
+
+/* initialisation function */
+static int trustway_init(void)
+{
+    if(trustway_dso != NULL)
+    {
+	ENGINEerr(ENGINE_F_TRUSTWAY_INIT, ENGINE_R_ALREADY_LOADED);
+	goto err;
+    }
+
+    /* Attempt to load libgpkcs11_cc2000.so whatever. */
+    trustway_dso = DSO_load(NULL, TRUSTWAY_LIBNAME, NULL,
+			    DSO_FLAG_NAME_TRANSLATION);
+    if(trustway_dso == NULL)
+    {
+	ENGINEerr(ENGINE_F_TRUSTWAY_INIT, ENGINE_R_DSO_FAILURE);
+	goto err;
+    }
+    if(trustway_global_check() != CKR_OK)
+    {
+	ENGINEerr(ENGINE_F_TRUSTWAY_INIT, ENGINE_R_UNIT_FAILURE);
+	goto err;
+    }
+
+    /* Everything's fine. */
+    if (rsaPubKey == -1)
+	rsaPubKey = RSA_get_ex_new_index(0,
+					 NULL, NULL, NULL, NULL);
+    if (rsaPrivKey == -1)
+	rsaPrivKey = RSA_get_ex_new_index(0,
+					  NULL, NULL, NULL, NULL);
+    if (deletePubKeyOnFree == -1)
+	deletePubKeyOnFree = RSA_get_ex_new_index(0,
+						  NULL, NULL, NULL, NULL);
+    if (deletePrivKeyOnFree == -1)
+	deletePrivKeyOnFree = RSA_get_ex_new_index(0,
+						   NULL, NULL, NULL, NULL);
+
+    return 1;
+
+ err:
+    if(trustway_dso)
+	DSO_free(trustway_dso);
+    trustway_dso = NULL;
+    return 0;
+}
+
+
+
+/* termination function */
+static int trustway_finish()
+{
+    if(trustway_dso == NULL)
+    {
+	ENGINEerr(ENGINE_F_TRUSTWAY_FINISH, ENGINE_R_NOT_LOADED);
+	return 0;
+    }
+    if(!DSO_free(trustway_dso))
+    {
+	ENGINEerr(ENGINE_F_TRUSTWAY_FINISH, ENGINE_R_DSO_FAILURE);
+	return 0;
+    }
+    trustway_dso = NULL;
+    return 1;
+}
+
+#endif
+#endif
+
diff -urN openssl-engine-0.9.6c/crypto/rsa/rsa.h openssl-engine-0.9.6c-tw/crypto/rsa/rsa.h
--- openssl-engine-0.9.6c/crypto/rsa/rsa.h	Fri Dec 21 03:36:29 2001
+++ openssl-engine-0.9.6c-tw/crypto/rsa/rsa.h	Thu Apr 18 15:48:34 2002
@@ -105,7 +105,13 @@
              unsigned char *sigret, unsigned int *siglen, RSA *rsa);
 	int (*rsa_verify)(int dtype, unsigned char *m, unsigned int m_len,
              unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
-
+#ifndef NO_HW_TRUSTWAY
+	int (*rsa_generate_key)(RSA *rsa, int bits, unsigned long e_value, 
+	     void (*callback)(int,int,void *), void *cb_arg);
+	int (*i2d_RSAPrivateKey)(RSA *rsa, unsigned char **pp);
+	int (*d2i_RSAPublicKey)(RSA *a);
+	RSA* (*d2i_RSAPrivateKey)(RSA **a, unsigned char **pp, long length);
+#endif
 	} RSA_METHOD;
 
 struct rsa_st
diff -urN openssl-engine-0.9.6c/crypto/rsa/rsa_gen.c openssl-engine-0.9.6c-tw/crypto/rsa/rsa_gen.c
--- openssl-engine-0.9.6c/crypto/rsa/rsa_gen.c	Thu Apr  5 22:27:12 2001
+++ openssl-engine-0.9.6c-tw/crypto/rsa/rsa_gen.c	Thu Apr 18 15:48:34 2002
@@ -61,6 +61,9 @@
 #include "cryptlib.h"
 #include <openssl/bn.h>
 #include <openssl/rsa.h>
+#ifndef NO_HW_TRUSTWAY
+#include <openssl/engine.h>
+#endif
 
 RSA *RSA_generate_key(int bits, unsigned long e_value,
 	     void (*callback)(int,int,void *), void *cb_arg)
@@ -85,6 +88,19 @@
 	bitsq=bits-bitsp;
 	rsa=RSA_new();
 	if (rsa == NULL) goto err;
+#ifndef NO_HW_TRUSTWAY
+	if (rsa->flags & RSA_FLAG_EXT_PKEY)
+	{
+	    if (ENGINE_get_RSA(rsa->engine)->rsa_generate_key(rsa,
+							      bits,
+							      e_value,
+							      callback,
+							      cb_arg))
+		return rsa;
+	    else
+		goto err;
+	}
+#endif
 
 	/* set e */ 
 	rsa->e=BN_new();
