Complete EVP_PKEY_ASN1_METHOD ENGINE support.
diff --git a/crypto/asn1/ameth_lib.c b/crypto/asn1/ameth_lib.c
index af08def..a96f1ab 100644
--- a/crypto/asn1/ameth_lib.c
+++ b/crypto/asn1/ameth_lib.c
@@ -59,7 +59,9 @@
 #include "cryptlib.h"
 #include <openssl/asn1t.h>
 #include <openssl/x509.h>
-#include <openssl/ec.h>
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif
 #include "asn1_locl.h"
 
 extern const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[];
@@ -132,7 +134,7 @@
 	return (const EVP_PKEY_ASN1_METHOD *)sk_value(app_methods, idx);
 	}
 
-const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(int type)
+static const EVP_PKEY_ASN1_METHOD *pkey_asn1_find(int type)
 	{
 	EVP_PKEY_ASN1_METHOD tmp, *t = &tmp, **ret;
 	tmp.pkey_id = type;
@@ -151,17 +153,72 @@
 			(int (*)(const void *, const void *))ameth_cmp);
 	if (!ret || !*ret)
 		return NULL;
-	if ((*ret)->pkey_flags & ASN1_PKEY_ALIAS)
-		return EVP_PKEY_asn1_find((*ret)->pkey_base_id);
 	return *ret;
 	}
 
-const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(const char *str, int len)
+/* Find an implementation of an ASN1 algorithm. If 'pe' is not NULL
+ * also search through engines and set *pe to a functional reference
+ * to the engine implementing 'type' or NULL if no engine implements 
+ * it.
+ */
+
+const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pe, int type)
+	{
+	const EVP_PKEY_ASN1_METHOD *t;
+	ENGINE *e;
+
+	for (;;)
+		{
+		t = pkey_asn1_find(type);
+		if (!t || !(t->pkey_flags & ASN1_PKEY_ALIAS))
+			break;
+		type = t->pkey_base_id;
+		}
+	if (pe)
+		{
+#ifndef OPENSSL_NO_ENGINE
+		/* type will contain the final unaliased type */
+		e = ENGINE_get_pkey_asn1_meth_engine(type);
+		if (e)
+			{
+			*pe = e;
+			return ENGINE_get_pkey_asn1_meth(e, type);
+			}
+#endif
+		*pe = NULL;
+		}
+	return t;
+	}
+
+const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **pe,
+					const char *str, int len)
 	{
 	int i;
 	const EVP_PKEY_ASN1_METHOD *ameth;
 	if (len == -1)
 		len = strlen(str);
+	if (pe)
+		{
+#ifndef OPENSSL_NO_ENGINE
+		ENGINE *e;
+		for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
+			{
+			ameth = ENGINE_get_pkey_asn1_meth_str(e, str, len);
+			if (ameth)
+				{
+				/* Convert structural into
+				 * functional reference
+				 */
+				if (!ENGINE_init(e))
+					ameth = NULL;
+				ENGINE_free(e);
+				*pe = e;
+				return ameth;
+				}
+			}
+#endif
+		*pe = NULL;
+		}
 	for (i = 0; i < EVP_PKEY_asn1_get_count(); i++)
 		{
 		ameth = EVP_PKEY_asn1_get0(i);
diff --git a/crypto/asn1/d2i_pr.c b/crypto/asn1/d2i_pr.c
index b4e47d4..b2791ea 100644
--- a/crypto/asn1/d2i_pr.c
+++ b/crypto/asn1/d2i_pr.c
@@ -61,6 +61,7 @@
 #include <openssl/bn.h>
 #include <openssl/evp.h>
 #include <openssl/objects.h>
+#include <openssl/engine.h>
 #include <openssl/asn1.h>
 #include "asn1_locl.h"
 
@@ -77,25 +78,27 @@
 			return(NULL);
 			}
 		}
-	else	ret= *a;
-
-	ret->save_type=type;
-	ret->type=EVP_PKEY_type(type);
-	ret->ameth = EVP_PKEY_asn1_find(type);
-	if (ret->ameth)
+	else
 		{
-		if (!ret->ameth->old_priv_decode ||
-			!ret->ameth->old_priv_decode(ret, pp, length))
+		ret= *a;
+		if (ret->engine)
 			{
-			ASN1err(ASN1_F_D2I_PRIVATEKEY,ERR_R_ASN1_LIB);
-			goto err;
+			ENGINE_finish(ret->engine);
+			ret->engine = NULL;
 			}
 		}
-	else
+
+	if (!EVP_PKEY_set_type(ret, type))
 		{
 		ASN1err(ASN1_F_D2I_PRIVATEKEY,ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE);
 		goto err;
-		/* break; */
+		}
+
+	if (!ret->ameth->old_priv_decode ||
+			!ret->ameth->old_priv_decode(ret, pp, length))
+		{
+		ASN1err(ASN1_F_D2I_PRIVATEKEY,ERR_R_ASN1_LIB);
+		goto err;
 		}
 	if (a != NULL) (*a)=ret;
 	return(ret);
diff --git a/crypto/asn1/x_pubkey.c b/crypto/asn1/x_pubkey.c
index 34f0af0..d42b6a2 100644
--- a/crypto/asn1/x_pubkey.c
+++ b/crypto/asn1/x_pubkey.c
@@ -90,19 +90,16 @@
 int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey)
 	{
 	X509_PUBKEY *pk=NULL;
-	const EVP_PKEY_ASN1_METHOD *meth;
 
 	if (x == NULL) return(0);
 
 	if ((pk=X509_PUBKEY_new()) == NULL) goto error;
 
-	meth = EVP_PKEY_asn1_find(pkey->type);
-
-	if (meth)
+	if (pkey->ameth)
 		{
-		if (meth->pub_encode)
+		if (pkey->ameth->pub_encode)
 			{
-			if (!meth->pub_encode(pk, pkey))
+			if (!pkey->ameth->pub_encode(pk, pkey))
 				{
 				X509err(X509_F_X509_PUBKEY_SET,
 					X509_R_PUBLIC_KEY_ENCODE_ERROR);
@@ -136,7 +133,6 @@
 EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key)
 	{
 	EVP_PKEY *ret=NULL;
-	const EVP_PKEY_ASN1_METHOD *meth;
 
 	if (key == NULL) goto error;
 
@@ -154,29 +150,24 @@
 		goto error;
 		}
 
-	meth = EVP_PKEY_asn1_find(OBJ_obj2nid(key->algor->algorithm));
-
-	if (meth)
+	if (!EVP_PKEY_set_type(ret, OBJ_obj2nid(key->algor->algorithm)))
 		{
-		if (meth->pub_decode)
-			{
-			if (!meth->pub_decode(ret, key))
-				{
-				X509err(X509_F_X509_PUBKEY_GET,
-						X509_R_PUBLIC_KEY_DECODE_ERROR);
-				goto error;
-				}
-			}
-		else
+		X509err(X509_F_X509_PUBKEY_GET,X509_R_UNSUPPORTED_ALGORITHM);
+		goto error;
+		}
+
+	if (ret->ameth->pub_decode)
+		{
+		if (!ret->ameth->pub_decode(ret, key))
 			{
 			X509err(X509_F_X509_PUBKEY_GET,
-				X509_R_METHOD_NOT_SUPPORTED);
+						X509_R_PUBLIC_KEY_DECODE_ERROR);
 			goto error;
 			}
 		}
 	else
 		{
-		X509err(X509_F_X509_PUBKEY_GET,X509_R_UNSUPPORTED_ALGORITHM);
+		X509err(X509_F_X509_PUBKEY_GET, X509_R_METHOD_NOT_SUPPORTED);
 		goto error;
 		}
 
diff --git a/crypto/engine/eng_fat.c b/crypto/engine/eng_fat.c
index 41d511a..db66e62 100644
--- a/crypto/engine/eng_fat.c
+++ b/crypto/engine/eng_fat.c
@@ -89,7 +89,11 @@
 #endif
 	if((flags & ENGINE_METHOD_RAND) && !ENGINE_set_default_RAND(e))
 		return 0;
-	if((flags & ENGINE_METHOD_PKEY_METHS) && !ENGINE_set_default_pkey_meths(e))
+	if((flags & ENGINE_METHOD_PKEY_METHS)
+				&& !ENGINE_set_default_pkey_meths(e))
+		return 0;
+	if((flags & ENGINE_METHOD_PKEY_ASN1_METHS)
+				&& !ENGINE_set_default_pkey_asn1_meths(e))
 		return 0;
 	return 1;
 	}
@@ -118,7 +122,12 @@
 	else if (!strncmp(alg, "DIGESTS", len))
 		*pflags |= ENGINE_METHOD_DIGESTS;
 	else if (!strncmp(alg, "PKEY", len))
+		*pflags |=
+			ENGINE_METHOD_PKEY_METHS|ENGINE_METHOD_PKEY_ASN1_METHS;
+	else if (!strncmp(alg, "PKEY_CRYPTO", len))
 		*pflags |= ENGINE_METHOD_PKEY_METHS;
+	else if (!strncmp(alg, "PKEY_ASN1", len))
+		*pflags |= ENGINE_METHOD_PKEY_ASN1_METHS;
 	else
 		return 0;
 	return 1;
diff --git a/crypto/engine/eng_int.h b/crypto/engine/eng_int.h
index 8630597..8bee596 100644
--- a/crypto/engine/eng_int.h
+++ b/crypto/engine/eng_int.h
@@ -146,6 +146,7 @@
 /* Free up dynamically allocated public key methods associated with ENGINE */
 
 void engine_pkey_meths_free(ENGINE *e);
+void engine_pkey_asn1_meths_free(ENGINE *e);
 
 /* This is a structure for storing implementations of various crypto
  * algorithms and functions. */
diff --git a/crypto/engine/eng_lib.c b/crypto/engine/eng_lib.c
index 6ee8a90..18a6664 100644
--- a/crypto/engine/eng_lib.c
+++ b/crypto/engine/eng_lib.c
@@ -127,6 +127,7 @@
 #endif
 	/* Free up any dynamically allocated public key methods */
 	engine_pkey_meths_free(e);
+	engine_pkey_asn1_meths_free(e);
 	/* Give the ENGINE a chance to do any structural cleanup corresponding
 	 * to allocation it did in its constructor (eg. unload error strings) */
 	if(e->destroy)
diff --git a/crypto/engine/engine.h b/crypto/engine/engine.h
index 803ebf3..9a2eb68 100644
--- a/crypto/engine/engine.h
+++ b/crypto/engine/engine.h
@@ -112,6 +112,7 @@
 #define ENGINE_METHOD_DIGESTS		(unsigned int)0x0080
 #define ENGINE_METHOD_STORE		(unsigned int)0x0100
 #define ENGINE_METHOD_PKEY_METHS	(unsigned int)0x0200
+#define ENGINE_METHOD_PKEY_ASN1_METHS	(unsigned int)0x0400
 /* Obvious all-or-nothing cases. */
 #define ENGINE_METHOD_ALL		(unsigned int)0xFFFF
 #define ENGINE_METHOD_NONE		(unsigned int)0x0000
@@ -510,6 +511,8 @@
 const EVP_MD *ENGINE_get_digest(ENGINE *e, int nid);
 const EVP_PKEY_METHOD *ENGINE_get_pkey_meth(ENGINE *e, int nid);
 const EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth(ENGINE *e, int nid);
+const EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth_str(ENGINE *e,
+					const char *str, int len);
 const ENGINE_CMD_DEFN *ENGINE_get_cmd_defns(const ENGINE *e);
 int ENGINE_get_flags(const ENGINE *e);
 
@@ -558,6 +561,7 @@
 ENGINE *ENGINE_get_cipher_engine(int nid);
 ENGINE *ENGINE_get_digest_engine(int nid);
 ENGINE *ENGINE_get_pkey_meth_engine(int nid);
+ENGINE *ENGINE_get_pkey_asn1_meth_engine(int nid);
 
 /* This sets a new default ENGINE structure for performing RSA
  * operations. If the result is non-zero (success) then the ENGINE
@@ -574,6 +578,7 @@
 int ENGINE_set_default_ciphers(ENGINE *e);
 int ENGINE_set_default_digests(ENGINE *e);
 int ENGINE_set_default_pkey_meths(ENGINE *e);
+int ENGINE_set_default_pkey_asn1_meths(ENGINE *e);
 
 /* The combination "set" - the flags are bitwise "OR"d from the
  * ENGINE_METHOD_*** defines above. As with the "ENGINE_register_complete()"
diff --git a/crypto/engine/tb_asnmth.c b/crypto/engine/tb_asnmth.c
index b2363a7..2476d05 100644
--- a/crypto/engine/tb_asnmth.c
+++ b/crypto/engine/tb_asnmth.c
@@ -53,10 +53,12 @@
  */
 
 #include "eng_int.h"
+#include "asn1_locl.h"
 
-/* If this symbol is defined then ENGINE_get_pkey_asn1_meth_engine(), the function
- * that is used by EVP to hook in pkey_asn1_meth code and cache defaults (etc), will
- * display brief debugging summaries to stderr with the 'nid'. */
+/* If this symbol is defined then ENGINE_get_pkey_asn1_meth_engine(), the
+ * function that is used by EVP to hook in pkey_asn1_meth code and cache
+ * defaults (etc), will display brief debugging summaries to stderr with the
+ * 'nid'. */
 /* #define ENGINE_PKEY_ASN1_METH_DEBUG */
 
 static ENGINE_TABLE *pkey_asn1_meth_table = NULL;
@@ -164,3 +166,30 @@
 			}
 		}
 	}
+
+/* Find a method based on a string. This does a linear search through
+ * all implemented algorithms. This is OK in practice because only
+ * a small number of algorithms are likely to be implemented in an engine
+ * and it is only used for non speed critical operations.
+ */
+
+const EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth_str(ENGINE *e,
+					const char *str, int len)
+	{
+	int i, nidcount;
+	const int *nids;
+	EVP_PKEY_ASN1_METHOD *ameth;
+	if (!e->pkey_asn1_meths)
+		return NULL;
+	if (len == -1)
+		len = strlen(str);
+	nidcount = e->pkey_asn1_meths(e, NULL, &nids, 0);
+	for (i = 0; i < nidcount; i++)
+		{
+		e->pkey_asn1_meths(e, &ameth, NULL, nids[i]);
+		if (((int)strlen(ameth->pem_str) == len) && 
+					!strncasecmp(ameth->pem_str, str, len))
+			return ameth;
+		}
+	return NULL;
+	}
diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h
index 833257a..32a1ebe 100644
--- a/crypto/evp/evp.h
+++ b/crypto/evp/evp.h
@@ -129,7 +129,7 @@
 	int save_type;
 	int references;
 	const EVP_PKEY_ASN1_METHOD *ameth;
-	const EVP_PKEY_METHOD *pmeth;
+	ENGINE *engine;
 	union	{
 		char *ptr;
 #ifndef OPENSSL_NO_RSA
@@ -770,6 +770,8 @@
 int		EVP_PKEY_base_id(const EVP_PKEY *pkey);
 int		EVP_PKEY_bits(EVP_PKEY *pkey);
 int		EVP_PKEY_size(EVP_PKEY *pkey);
+int 		EVP_PKEY_set_type(EVP_PKEY *pkey,int type);
+int		EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len);
 int 		EVP_PKEY_assign(EVP_PKEY *pkey,int type,void *key);
 void *		EVP_PKEY_get0(EVP_PKEY *pkey);
 
@@ -874,8 +876,9 @@
 
 int EVP_PKEY_asn1_get_count(void);
 const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_get0(int idx);
-const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(int type);
-const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(const char *str, int len);
+const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pe, int type);
+const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **pe,
+					const char *str, int len);
 int EVP_PKEY_asn1_add0(const EVP_PKEY_ASN1_METHOD *ameth);
 int EVP_PKEY_asn1_add_alias(int to, int from);
 int EVP_PKEY_asn1_get0_info(int *ppkey_id, int *pkey_base_id, int *ppkey_flags,
@@ -1142,6 +1145,7 @@
 #define EVP_F_PKCS5_PBE_KEYIVGEN			 117
 #define EVP_F_PKCS5_V2_PBE_KEYIVGEN			 118
 #define EVP_F_PKCS8_SET_BROKEN				 112
+#define EVP_F_PKEY_SET_TYPE				 158
 #define EVP_F_RC2_MAGIC_TO_METH				 109
 #define EVP_F_RC5_CTRL					 125
 
@@ -1193,6 +1197,7 @@
 #define EVP_R_PUBLIC_KEY_NOT_RSA			 106
 #define EVP_R_UNKNOWN_PBE_ALGORITHM			 121
 #define EVP_R_UNSUPORTED_NUMBER_OF_ROUNDS		 135
+#define EVP_R_UNSUPPORTED_ALGORITHM			 156
 #define EVP_R_UNSUPPORTED_CIPHER			 107
 #define EVP_R_UNSUPPORTED_KEYLENGTH			 123
 #define EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION	 124
diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c
index a2f253c..150bfd0 100644
--- a/crypto/evp/evp_err.c
+++ b/crypto/evp/evp_err.c
@@ -125,6 +125,7 @@
 {ERR_FUNC(EVP_F_PKCS5_PBE_KEYIVGEN),	"PKCS5_PBE_keyivgen"},
 {ERR_FUNC(EVP_F_PKCS5_V2_PBE_KEYIVGEN),	"PKCS5_v2_PBE_keyivgen"},
 {ERR_FUNC(EVP_F_PKCS8_SET_BROKEN),	"PKCS8_set_broken"},
+{ERR_FUNC(EVP_F_PKEY_SET_TYPE),	"PKEY_SET_TYPE"},
 {ERR_FUNC(EVP_F_RC2_MAGIC_TO_METH),	"RC2_MAGIC_TO_METH"},
 {ERR_FUNC(EVP_F_RC5_CTRL),	"RC5_CTRL"},
 {0,NULL}
@@ -179,6 +180,7 @@
 {ERR_REASON(EVP_R_PUBLIC_KEY_NOT_RSA)    ,"public key not rsa"},
 {ERR_REASON(EVP_R_UNKNOWN_PBE_ALGORITHM) ,"unknown pbe algorithm"},
 {ERR_REASON(EVP_R_UNSUPORTED_NUMBER_OF_ROUNDS),"unsuported number of rounds"},
+{ERR_REASON(EVP_R_UNSUPPORTED_ALGORITHM) ,"unsupported algorithm"},
 {ERR_REASON(EVP_R_UNSUPPORTED_CIPHER)    ,"unsupported cipher"},
 {ERR_REASON(EVP_R_UNSUPPORTED_KEYLENGTH) ,"unsupported keylength"},
 {ERR_REASON(EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION),"unsupported key derivation function"},
diff --git a/crypto/evp/evp_pkey.c b/crypto/evp/evp_pkey.c
index e81c4fe..19cdbf9 100644
--- a/crypto/evp/evp_pkey.c
+++ b/crypto/evp/evp_pkey.c
@@ -69,7 +69,6 @@
 {
 	EVP_PKEY *pkey = NULL;
 	ASN1_OBJECT *algoid;
-	const EVP_PKEY_ASN1_METHOD *meth;
 	char obj_tmp[80];
 
 	if (!PKCS8_pkey_get0(&algoid, NULL, NULL, NULL, p8))
@@ -80,33 +79,29 @@
 		return NULL;
 	}
 
-	meth = EVP_PKEY_asn1_find(OBJ_obj2nid(algoid));
-
-	if (meth)
-		{
-		if (meth->priv_decode)
-			{
-			if (!meth->priv_decode(pkey, p8))
-				{
-				EVPerr(EVP_F_EVP_PKCS82PKEY,
-					EVP_R_PRIVATE_KEY_DECODE_ERROR);
-				goto error;
-				}
-			}
-		else
-			{
-			EVPerr(EVP_F_EVP_PKCS82PKEY,
-					EVP_R_METHOD_NOT_SUPPORTED);
-			goto error;
-			}
-		}
-	else
+	if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(algoid)))
 		{
 		EVPerr(EVP_F_EVP_PKCS82PKEY, EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM);
 		i2t_ASN1_OBJECT(obj_tmp, 80, algoid);
 		ERR_add_error_data(2, "TYPE=", obj_tmp);
 		goto error;
 		}
+
+	if (pkey->ameth->priv_decode)
+		{
+		if (!pkey->ameth->priv_decode(pkey, p8))
+			{
+			EVPerr(EVP_F_EVP_PKCS82PKEY,
+					EVP_R_PRIVATE_KEY_DECODE_ERROR);
+			goto error;
+			}
+		}
+	else
+		{
+		EVPerr(EVP_F_EVP_PKCS82PKEY, EVP_R_METHOD_NOT_SUPPORTED);
+		goto error;
+		}
+
 	return pkey;
 
 	error:
@@ -124,7 +119,6 @@
 PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8_broken(EVP_PKEY *pkey, int broken)
 {
 	PKCS8_PRIV_KEY_INFO *p8;
-	const EVP_PKEY_ASN1_METHOD *meth;
 
 	if (!(p8 = PKCS8_PRIV_KEY_INFO_new())) {	
 		EVPerr(EVP_F_EVP_PKEY2PKCS8_BROKEN,ERR_R_MALLOC_FAILURE);
@@ -132,13 +126,11 @@
 	}
 	p8->broken = broken;
 
-	meth = EVP_PKEY_asn1_find(pkey->type);
-
-	if (meth)
+	if (pkey->ameth)
 		{
-		if (meth->priv_encode)
+		if (pkey->ameth->priv_encode)
 			{
-			if (!meth->priv_encode(p8, pkey))
+			if (!pkey->ameth->priv_encode(p8, pkey))
 				{
 				EVPerr(EVP_F_EVP_PKEY2PKCS8_BROKEN,
 					EVP_R_PRIVATE_KEY_ENCODE_ERROR);
diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c
index 752547d..939857f 100644
--- a/crypto/evp/p_lib.c
+++ b/crypto/evp/p_lib.c
@@ -74,6 +74,10 @@
 #include <openssl/dh.h>
 #endif
 
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif
+
 #include "asn1_locl.h"
 
 static void EVP_PKEY_free_it(EVP_PKEY *x);
@@ -177,26 +181,79 @@
 		return(NULL);
 		}
 	ret->type=EVP_PKEY_NONE;
+	ret->save_type=EVP_PKEY_NONE;
 	ret->references=1;
 	ret->ameth=NULL;
+	ret->engine=NULL;
 	ret->pkey.ptr=NULL;
 	ret->attributes=NULL;
 	ret->save_parameters=1;
 	return(ret);
 	}
 
-int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key)
+/* Setup a public key ASN1 method and ENGINE from a NID or a string.
+ * If pkey is NULL just return 1 or 0 if the algorithm exists.
+ */
+
+static int pkey_set_type(EVP_PKEY *pkey, int type, const char *str, int len)
 	{
 	const EVP_PKEY_ASN1_METHOD *ameth;
-	if (pkey == NULL) return(0);
-	if (pkey->pkey.ptr != NULL)
-		EVP_PKEY_free_it(pkey);
-	ameth = EVP_PKEY_asn1_find(type);
-	pkey->ameth = ameth;
-	pkey->type = ameth->pkey_id;
-	pkey->save_type=type;
+	ENGINE *e = NULL;
+	if (pkey)
+		{
+		if (pkey->pkey.ptr)
+			EVP_PKEY_free_it(pkey);
+		/* If key type matches and a method exists then this
+		 * lookup has succeeded once so just indicate success.
+		 */
+		if ((type == pkey->save_type) && pkey->ameth)
+			return 1;
+#ifndef OPENSSL_NO_ENGINE
+		/* If we have an ENGINE release it */
+		if (pkey->engine)
+			ENGINE_finish(pkey->engine);
+#endif
+		}
+	if (str)
+		ameth = EVP_PKEY_asn1_find_str(&e, str, len);
+	else
+		ameth = EVP_PKEY_asn1_find(&e, type);
+#ifndef OPENSSL_NO_ENGINE
+	if (!pkey && e)
+		ENGINE_finish(e);
+#endif
+	if (!ameth)
+		{
+		EVPerr(EVP_F_PKEY_SET_TYPE, EVP_R_UNSUPPORTED_ALGORITHM);
+		return 0;
+		}
+	if (pkey)
+		{
+		pkey->ameth = ameth;
+		pkey->engine = e;
+
+		pkey->type = pkey->ameth->pkey_id;
+		pkey->save_type=type;
+		}
+	return 1;
+	}
+
+int EVP_PKEY_set_type(EVP_PKEY *pkey, int type)
+	{
+	return pkey_set_type(pkey, type, NULL, -1);
+	}
+
+int EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len)
+	{
+	return pkey_set_type(pkey, EVP_PKEY_NONE, str, len);
+	}
+
+int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key)
+	{
+	if (!EVP_PKEY_set_type(pkey, type))
+		return 0;
 	pkey->pkey.ptr=key;
-	return(key != NULL);
+	return (key != NULL);
 	}
 
 void *EVP_PKEY_get0(EVP_PKEY *pkey)
@@ -290,11 +347,19 @@
 
 int EVP_PKEY_type(int type)
 	{
+	int ret;
 	const EVP_PKEY_ASN1_METHOD *ameth;
-	ameth = EVP_PKEY_asn1_find(type);
+	ENGINE *e;
+	ameth = EVP_PKEY_asn1_find(&e, type);
 	if (ameth)
-		return ameth->pkey_id;
-	return NID_undef;
+		ret = ameth->pkey_id;
+	else
+		ret = NID_undef;
+#ifndef OPENSSL_NO_ENGINE
+	if (e)
+		ENGINE_finish(e);
+#endif
+	return ret;
 	}
 
 int EVP_PKEY_id(const EVP_PKEY *pkey)
@@ -335,14 +400,21 @@
 	{
 	if (x->ameth && x->ameth->pkey_free)
 		x->ameth->pkey_free(x);
+#ifndef OPENSSL_NO_ENGINE
+	if (x->engine)
+		{
+		ENGINE_finish(x->engine);
+		x->engine = NULL;
+		}
+#endif
 	}
 
 static int unsup_alg(BIO *out, const EVP_PKEY *pkey, int indent,
 				const char *kstr)
 	{
 	BIO_indent(out, indent, 128);
-	BIO_printf(out, "%s %s, algorithm, unsupported\n",
-						OBJ_nid2ln(pkey->type), kstr);
+	BIO_printf(out, "%s algorithm \"%s\" unsupported\n",
+						kstr, OBJ_nid2ln(pkey->type));
 	return 1;
 	}
 
diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c
index 8108d44..49a8ee9 100644
--- a/crypto/evp/pmeth_lib.c
+++ b/crypto/evp/pmeth_lib.c
@@ -140,7 +140,10 @@
 		pmeth = EVP_PKEY_meth_find(id);
 
 	if (pmeth == NULL)
+		{
+		EVPerr(EVP_F_INT_CTX_NEW,EVP_R_UNSUPPORTED_ALGORITHM);
 		return NULL;
+		}
 
 	ret = OPENSSL_malloc(sizeof(EVP_PKEY_CTX));
 	if (!ret)
diff --git a/crypto/pem/pem_lib.c b/crypto/pem/pem_lib.c
index 9631ee2..89e41b7 100644
--- a/crypto/pem/pem_lib.c
+++ b/crypto/pem/pem_lib.c
@@ -70,6 +70,9 @@
 #ifndef OPENSSL_NO_DES
 #include <openssl/des.h>
 #endif
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif
 
 const char *PEM_version="PEM" OPENSSL_VERSION_PTEXT;
 
@@ -197,7 +200,11 @@
 		slen = pem_check_suffix(nm, "PRIVATE KEY"); 
 		if (slen > 0)
 			{
-			ameth = EVP_PKEY_asn1_find_str(nm, slen);
+			/* NB: ENGINE implementations wont contain
+			 * a deprecated old private key decode function
+			 * so don't look for them.
+			 */
+			ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen);
 			if (ameth && ameth->old_priv_decode)
 				return 1;
 			}
@@ -211,9 +218,21 @@
 		slen = pem_check_suffix(nm, "PARAMETERS"); 
 		if (slen > 0)
 			{
-			ameth = EVP_PKEY_asn1_find_str(nm, slen);
-			if (ameth && ameth->param_decode)
-				return 1;
+			ENGINE *e;
+			ameth = EVP_PKEY_asn1_find_str(&e, nm, slen);
+			if (ameth)
+				{
+				int r;
+				if (ameth->param_decode)
+					r = 1;
+				else
+					r = 0;
+#ifndef OPENSSL_NO_ENGINE
+				if (e)
+					ENGINE_finish(e);
+#endif
+				return r;
+				}
 			}
 		return 0;
 		}
diff --git a/crypto/pem/pem_pkey.c b/crypto/pem/pem_pkey.c
index acd2dc2..6cca60c 100644
--- a/crypto/pem/pem_pkey.c
+++ b/crypto/pem/pem_pkey.c
@@ -65,6 +65,9 @@
 #include <openssl/x509.h>
 #include <openssl/pkcs12.h>
 #include <openssl/pem.h>
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif
 #include "asn1_locl.h"
 
 int pem_check_suffix(const char *pem_str, const char *suffix);
@@ -119,7 +122,7 @@
 	} else if ((slen = pem_check_suffix(nm, "PRIVATE KEY")) > 0)
 		{
 		const EVP_PKEY_ASN1_METHOD *ameth;
-		ameth = EVP_PKEY_asn1_find_str(nm, slen);
+		ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen);
 		if (!ameth || !ameth->old_priv_decode)
 			goto p8err;
 		ret=d2i_PrivateKey(ameth->pkey_id,x,&p,len);
@@ -164,14 +167,12 @@
 
 	if ((slen = pem_check_suffix(nm, "PARAMETERS")) > 0)
 		{
-		const EVP_PKEY_ASN1_METHOD *ameth;
-		ameth = EVP_PKEY_asn1_find_str(nm, slen);
-		if (!ameth || !ameth->param_decode)
-			goto err;
 		ret = EVP_PKEY_new();
 		if (!ret)
 			goto err;
-		if (!ameth->param_decode(ret, &p, len))
+		if (!EVP_PKEY_set_type_str(ret, nm, slen)
+			|| !ret->ameth->param_decode
+			|| !ret->ameth->param_decode(ret, &p, len))
 			{
 			EVP_PKEY_free(ret);
 			ret = NULL;