Complete EVP_PKEY_ASN1_METHOD ENGINE support.
diff --git a/apps/genpkey.c b/apps/genpkey.c
index 8468fb2..70e2e31 100644
--- a/apps/genpkey.c
+++ b/apps/genpkey.c
@@ -61,6 +61,9 @@
 #include <openssl/pem.h>
 #include <openssl/err.h>
 #include <openssl/evp.h>
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif
 
 static int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx,
 				const char *file, ENGINE *e);
@@ -85,7 +88,7 @@
 	EVP_PKEY_CTX *ctx = NULL;
 	char *pass = NULL;
 	int badarg = 0;
-	int ret = 1;
+	int ret = 1, rv;
 
 	int do_param = 0;
 
@@ -204,7 +207,7 @@
 #ifndef OPENSSL_NO_ENGINE
 		BIO_printf(bio_err, "-engine e       use engine e, possibly a hardware device.\n");
 #endif
-		return 1;
+		goto end;
 		}
 
 	if (!app_passwd(bio_err, passarg, NULL, &pass, NULL))
@@ -256,25 +259,36 @@
 		}
 
 	if (do_param)
-		PEM_write_bio_Parameters(out, pkey);
+		rv = PEM_write_bio_Parameters(out, pkey);
 	else if (outformat == FORMAT_PEM) 
-		PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0,
+		rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0,
 								NULL, pass);
 	else if (outformat == FORMAT_ASN1)
-		i2d_PrivateKey_bio(out, pkey);
+		rv = i2d_PrivateKey_bio(out, pkey);
 	else
 		{
 		BIO_printf(bio_err, "Bad format specified for key\n");
 		goto end;
 		}
 
+	if (rv <= 0)
+		{
+		BIO_puts(bio_err, "Error writing key\n");
+		ERR_print_errors(bio_err);
+		}
 
 	if (text)
 		{
 		if (do_param)
-			EVP_PKEY_print_params(out, pkey, 0, NULL);
+			rv = EVP_PKEY_print_params(out, pkey, 0, NULL);
 		else
-			EVP_PKEY_print_private(out, pkey, 0, NULL);
+			rv = EVP_PKEY_print_private(out, pkey, 0, NULL);
+
+		if (rv <= 0)
+			{
+			BIO_puts(bio_err, "Error printing key\n");
+			ERR_print_errors(bio_err);
+			}
 		}
 
 	ret = 0;
@@ -346,14 +360,16 @@
 	{
 	EVP_PKEY_CTX *ctx = NULL;
 	const EVP_PKEY_ASN1_METHOD *ameth;
+	ENGINE *tmpeng = NULL;
 	int pkey_id;
+
 	if (*pctx)
 		{
 		BIO_puts(err, "Algorithm already set!\n");
 		return 0;
 		}
+	ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1);
 
-	ameth = EVP_PKEY_asn1_find_str(algname, -1);
 	if (!ameth)
 		{
 		BIO_printf(bio_err, "Algorithm %s not found\n", algname);
@@ -361,6 +377,10 @@
 		}
 
 	EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
+#ifndef OPENSSL_NO_ENGINE
+	if (tmpeng)
+		ENGINE_finish(tmpeng);
+#endif
 	ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
 
 	if (!ctx)
diff --git a/apps/req.c b/apps/req.c
index de1b182..a0eca51 100644
--- a/apps/req.c
+++ b/apps/req.c
@@ -145,8 +145,8 @@
 static int req_check_len(int len,int n_min,int n_max);
 static int check_end(const char *str, const char *end);
 static EVP_PKEY_CTX *set_keygen_ctx(BIO *err, const char *gstr,
-					long *pkeylen, const char **palgnam,
-					ENGINE *e);
+					long *pkeylen, char **palgnam,
+					ENGINE *keygen_engine);
 #ifndef MONOLITH
 static char *default_config_file=NULL;
 #endif
@@ -157,19 +157,14 @@
 
 int MAIN(int argc, char **argv)
 	{
-	ENGINE *e = NULL;
-#ifndef OPENSSL_NO_DSA
-	DSA *dsa_params=NULL;
-#endif
-#ifndef OPENSSL_NO_ECDSA
-	EC_KEY *ec_params = NULL;
-#endif
+	ENGINE *e = NULL, *gen_eng = NULL;
 	unsigned long nmflag = 0, reqflag = 0;
 	int ex=1,x509=0,days=30;
 	X509 *x509ss=NULL;
 	X509_REQ *req=NULL;
 	EVP_PKEY_CTX *genctx = NULL;
-	const char *keyalg = NULL, *keyalgstr;
+	const char *keyalg = NULL;
+	char *keyalgstr = NULL;
 	STACK *pkeyopts = NULL;
 	EVP_PKEY *pkey=NULL;
 	int i=0,badops=0,newreq=0,verbose=0,pkey_type=EVP_PKEY_RSA;
@@ -235,6 +230,16 @@
 			if (--argc < 1) goto bad;
 			engine= *(++argv);
 			}
+		else if (strcmp(*argv,"-keygen_engine") == 0)
+			{
+			if (--argc < 1) goto bad;
+			gen_eng = ENGINE_by_id(*(++argv));
+			if (gen_eng == NULL)
+				{
+				BIO_printf(bio_err, "Can't find keygen engine %s\n", *argv);
+				goto end;
+				}
+			}
 #endif
 		else if (strcmp(*argv,"-key") == 0)
 			{
@@ -634,7 +639,7 @@
 		if (keyalg)
 			{
 			genctx = set_keygen_ctx(bio_err, keyalg, &newkey,
-							&keyalgstr, e);
+							&keyalgstr, gen_eng);
 			if (!genctx)
 				goto end;
 			}
@@ -655,7 +660,7 @@
 		if (!genctx)
 			{
 			genctx = set_keygen_ctx(bio_err, NULL, &newkey,
-							&keyalgstr, e);
+							&keyalgstr, gen_eng);
 			if (!genctx)
 				goto end;
 			}
@@ -1080,18 +1085,18 @@
 		EVP_PKEY_CTX_free(genctx);
 	if (pkeyopts)
 		sk_free(pkeyopts);
+#ifndef OPENSSL_NO_ENGINE
+	if (gen_eng)
+		ENGINE_free(gen_eng);
+#endif
+	if (keyalgstr)
+		OPENSSL_free(keyalgstr);
 	X509_REQ_free(req);
 	X509_free(x509ss);
 	ASN1_INTEGER_free(serial);
 	if(passargin && passin) OPENSSL_free(passin);
 	if(passargout && passout) OPENSSL_free(passout);
 	OBJ_cleanup();
-#ifndef OPENSSL_NO_DSA
-	if (dsa_params != NULL) DSA_free(dsa_params);
-#endif
-#ifndef OPENSSL_NO_ECDSA
-	if (ec_params != NULL) EC_KEY_free(ec_params);
-#endif
 	apps_shutdown();
 	OPENSSL_EXIT(ex);
 	}
@@ -1566,8 +1571,8 @@
 }
 
 static EVP_PKEY_CTX *set_keygen_ctx(BIO *err, const char *gstr,
-					long *pkeylen, const char **palgnam,
-					ENGINE *e)
+					long *pkeylen, char **palgnam,
+					ENGINE *keygen_engine)
 	{
 	EVP_PKEY_CTX *gctx = NULL;
 	EVP_PKEY *param = NULL;
@@ -1593,14 +1598,18 @@
 		{
 		const char *p = strchr(gstr, ':');
 		int len;
+		ENGINE *tmpeng;
 		const EVP_PKEY_ASN1_METHOD *ameth;
 
 		if (p)
 			len = p - gstr;
 		else
 			len = strlen(gstr);
+		/* The lookup of a the string will cover all engines so
+		 * keep a note of the implementation.
+		 */
 
-		ameth = EVP_PKEY_asn1_find_str(gstr, len);
+		ameth = EVP_PKEY_asn1_find_str(&tmpeng, gstr, len);
 
 		if (!ameth)
 			{
@@ -1609,7 +1618,11 @@
 			}
 
 		EVP_PKEY_asn1_get0_info(NULL, &pkey_type, NULL, NULL, NULL,
-						ameth);
+									ameth);
+#ifndef OPENSSL_NO_ENGINE
+		if (tmpeng)
+			ENGINE_finish(tmpeng);
+#endif
 		if (pkey_type == EVP_PKEY_RSA)
 			{
 			if (p)
@@ -1666,24 +1679,30 @@
 	if (palgnam)
 		{
 		const EVP_PKEY_ASN1_METHOD *ameth;
-		ameth = EVP_PKEY_asn1_find(pkey_type);
+		ENGINE *tmpeng;
+		const char *anam;
+		ameth = EVP_PKEY_asn1_find(&tmpeng, pkey_type);
 		if (!ameth)
 			{
 			BIO_puts(err, "Internal error: can't find key algorithm\n");
 			return NULL;
 			}
-		EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, palgnam,
-						ameth);
+		EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &anam, ameth);
+		*palgnam = BUF_strdup(anam);
+#ifndef OPENSSL_NO_ENGINE
+		if (tmpeng)
+			ENGINE_finish(tmpeng);
+#endif
 		}
 
 	if (param)
 		{
-		gctx = EVP_PKEY_CTX_new(param, e);
+		gctx = EVP_PKEY_CTX_new(param, keygen_engine);
 		*pkeylen = EVP_PKEY_bits(param);
 		EVP_PKEY_free(param);
 		}
 	else
-		gctx = EVP_PKEY_CTX_new_id(pkey_type, e);
+		gctx = EVP_PKEY_CTX_new_id(pkey_type, keygen_engine);
 
 	if (!gctx)
 		{