Complete EVP_PKEY_ASN1_METHOD ENGINE support.
authorDr. Stephen Henson <steve@openssl.org>
Mon, 5 Jun 2006 11:52:46 +0000 (11:52 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Mon, 5 Jun 2006 11:52:46 +0000 (11:52 +0000)
18 files changed:
CHANGES
apps/genpkey.c
apps/req.c
crypto/asn1/ameth_lib.c
crypto/asn1/d2i_pr.c
crypto/asn1/x_pubkey.c
crypto/engine/eng_fat.c
crypto/engine/eng_int.h
crypto/engine/eng_lib.c
crypto/engine/engine.h
crypto/engine/tb_asnmth.c
crypto/evp/evp.h
crypto/evp/evp_err.c
crypto/evp/evp_pkey.c
crypto/evp/p_lib.c
crypto/evp/pmeth_lib.c
crypto/pem/pem_lib.c
crypto/pem/pem_pkey.c

diff --git a/CHANGES b/CHANGES
index 46d5cd8445412e9b5b2f62f8be3a21181ec873f5..22165da32a97406c4c7675ebf3591ab4b33e8351 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,7 +4,9 @@
 
  Changes between 0.9.8b and 0.9.9  [xx XXX xxxx]
 
-  *) Initial engine support for EVP_PKEY_ASN1_METHOD.
+  *) Add engine support for EVP_PKEY_ASN1_METHOD. Add functions to process
+     an ENGINE asn1 method. Support ENGINE lookups in the ASN1 code.
+     [Steve Henson]
 
   *) Initial engine support for EVP_PKEY_METHOD. New functions to permit
      an engine to register a method. Add ENGINE lookups for methods and
index 8468fb20b33ade897f4166c69d2e45cafc086c6e..70e2e31971323b84586e476519e2e2fdb212feb9 100644 (file)
@@ -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 @@ int MAIN(int argc, char **argv)
        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 @@ int MAIN(int argc, char **argv)
 #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 @@ int MAIN(int argc, char **argv)
                }
 
        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 @@ static int init_gen_str(BIO *err, EVP_PKEY_CTX **pctx,
        {
        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 @@ static int init_gen_str(BIO *err, EVP_PKEY_CTX **pctx,
                }
 
        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)
index de1b182fc772ce8169cb25a4535b7f2ca5142916..a0eca519af1c272f5287419704f06a3daa0a3363 100644 (file)
@@ -145,8 +145,8 @@ static int genpkey_cb(EVP_PKEY_CTX *ctx);
 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, char **);
 
 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 @@ int MAIN(int argc, char **argv)
                        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 @@ bad:
                if (keyalg)
                        {
                        genctx = set_keygen_ctx(bio_err, keyalg, &newkey,
-                                                       &keyalgstr, e);
+                                                       &keyalgstr, gen_eng);
                        if (!genctx)
                                goto end;
                        }
@@ -655,7 +660,7 @@ bad:
                if (!genctx)
                        {
                        genctx = set_keygen_ctx(bio_err, NULL, &newkey,
-                                                       &keyalgstr, e);
+                                                       &keyalgstr, gen_eng);
                        if (!genctx)
                                goto end;
                        }
@@ -1080,18 +1085,18 @@ end:
                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 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)
        {
        EVP_PKEY_CTX *gctx = NULL;
        EVP_PKEY *param = NULL;
@@ -1593,14 +1598,18 @@ static EVP_PKEY_CTX *set_keygen_ctx(BIO *err, const char *gstr,
                {
                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 @@ static EVP_PKEY_CTX *set_keygen_ctx(BIO *err, const char *gstr,
                        }
 
                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 @@ static EVP_PKEY_CTX *set_keygen_ctx(BIO *err, const char *gstr,
        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)
                {
index af08defbe496d19e02ab428ef4e7fd886b44b3de..a96f1ab28916b2d21ee0fbb4ec571ee09ab07e16 100644 (file)
@@ -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 @@ const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_get0(int idx)
        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 @@ const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(int type)
                        (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);
index b4e47d48197f5080e9270d3cc5b8a702fdc196d5..b2791ea66e351be76d1c71abb9d403cdbf24c9de 100644 (file)
@@ -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 @@ EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **a, const unsigned char **pp,
                        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);
index 34f0af0f59b87373b59e26599fe8470a015bb376..d42b6a2c54cbac464edac9f8888b18d2520a38fb 100644 (file)
@@ -90,19 +90,16 @@ IMPLEMENT_ASN1_FUNCTIONS(X509_PUBKEY)
 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 @@ error:
 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 @@ EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key)
                goto error;
                }
 
-       meth = EVP_PKEY_asn1_find(OBJ_obj2nid(key->algor->algorithm));
+       if (!EVP_PKEY_set_type(ret, OBJ_obj2nid(key->algor->algorithm)))
+               {
+               X509err(X509_F_X509_PUBKEY_GET,X509_R_UNSUPPORTED_ALGORITHM);
+               goto error;
+               }
 
-       if (meth)
+       if (ret->ameth->pub_decode)
                {
-               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
+               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;
                }
 
index 41d511a033725b6c88819a63bf64045d5906847e..db66e623508f838ba585d4c909f18509710bb30c 100644 (file)
@@ -89,7 +89,11 @@ int ENGINE_set_default(ENGINE *e, unsigned int flags)
 #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 @@ static int int_def_cb(const char *alg, int len, void *arg)
        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;
index 8630597fe08f36c4ad362cb6274a2326327615c6..8bee5962c510f639fcf2c13adacc105c35326102 100644 (file)
@@ -146,6 +146,7 @@ void engine_set_all_null(ENGINE *e);
 /* 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. */
index 6ee8a90c158c98d5c4229449f3a5918935f1f887..18a66646458a9aa033abfdde32ce936229f75f57 100644 (file)
@@ -127,6 +127,7 @@ int engine_free_util(ENGINE *e, int locked)
 #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)
index 803ebf31b2b759e4292fbd51081c5c56438e0a59..9a2eb68646857cab39ce1c2d28b202897e295f0b 100644 (file)
@@ -112,6 +112,7 @@ extern "C" {
 #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_CIPHER *ENGINE_get_cipher(ENGINE *e, int nid);
 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_default_RAND(void);
 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_RAND(ENGINE *e);
 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()"
index b2363a7f00c81121c30da6086bc2924152132696..2476d059124ff8f5c254c2f7d8621c6d06414061 100644 (file)
  */
 
 #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 @@ void engine_pkey_asn1_meths_free(ENGINE *e)
                        }
                }
        }
+
+/* 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;
+       }
index 833257a937aa21fefcbd258c0ed3bc45700c363e..32a1ebe9f6b8f9fe409d9c2d613b55022bb2705c 100644 (file)
@@ -129,7 +129,7 @@ struct evp_pkey_st
        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_id(const EVP_PKEY *pkey);
 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 @@ void EVP_PBE_cleanup(void);
 
 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 @@ void ERR_load_EVP_strings(void);
 #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 @@ void ERR_load_EVP_strings(void);
 #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
index a2f253cbd00dbf06e5076e3f00be5df92dde516d..150bfd0db9440fd11dc18d8de513c99c96365181 100644 (file)
@@ -125,6 +125,7 @@ static ERR_STRING_DATA EVP_str_functs[]=
 {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 @@ static ERR_STRING_DATA EVP_str_reasons[]=
 {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"},
index e81c4fedb199954b540eb20b17be02699625b186..19cdbf966662f73f71a669773fc4eb2cb939ff3e 100644 (file)
@@ -69,7 +69,6 @@ EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8)
 {
        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 @@ EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8)
                return NULL;
        }
 
-       meth = EVP_PKEY_asn1_find(OBJ_obj2nid(algoid));
+       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 (meth)
+       if (pkey->ameth->priv_decode)
                {
-               if (meth->priv_decode)
-                       {
-                       if (!meth->priv_decode(pkey, p8))
-                               {
-                               EVPerr(EVP_F_EVP_PKCS82PKEY,
-                                       EVP_R_PRIVATE_KEY_DECODE_ERROR);
-                               goto error;
-                               }
-                       }
-               else
+               if (!pkey->ameth->priv_decode(pkey, p8))
                        {
                        EVPerr(EVP_F_EVP_PKCS82PKEY,
-                                       EVP_R_METHOD_NOT_SUPPORTED);
+                                       EVP_R_PRIVATE_KEY_DECODE_ERROR);
                        goto error;
                        }
                }
        else
                {
-               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);
+               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(EVP_PKEY *pkey)
 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 @@ PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8_broken(EVP_PKEY *pkey, int broken)
        }
        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);
index 752547d1e6cc00e41b50fe35052b6aab16584f63..939857fdb000b2b07694b1ddde47e3638a3d516d 100644 (file)
 #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 @@ EVP_PKEY *EVP_PKEY_new(void)
                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 @@ DH *EVP_PKEY_get1_DH(EVP_PKEY *pkey)
 
 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 @@ static void EVP_PKEY_free_it(EVP_PKEY *x)
        {
        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;
        }
 
index 8108d448cb1648025c8a84dac3a1df280f59475b..49a8ee99cb20cff4f8f63b5b702f3a9838d79b6d 100644 (file)
@@ -140,7 +140,10 @@ static EVP_PKEY_CTX *int_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id)
                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)
index 9631ee2d5dd34b6dfe781f70c045e7258b27edca..89e41b7f94f112a6a251ee4923f612e8f805057f 100644 (file)
@@ -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 @@ static int check_pem(const char *nm, const char *name)
                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 @@ static int check_pem(const char *nm, const char *name)
                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;
                }
index acd2dc250462475edc6f43ebfd2b2e723500dd6d..6cca60cb8d4d8d0ac3a9547033ccf7decb0b7f69 100644 (file)
@@ -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 @@ EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, vo
        } 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 @@ EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x)
 
        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;