From 01b8b3c7d2d8f835257ac1cb2512273aa27bfba8 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Mon, 5 Jun 2006 11:52:46 +0000 Subject: [PATCH] Complete EVP_PKEY_ASN1_METHOD ENGINE support. --- CHANGES | 4 +- apps/genpkey.c | 36 +++++++++++--- apps/req.c | 73 ++++++++++++++++++---------- crypto/asn1/ameth_lib.c | 67 +++++++++++++++++++++++-- crypto/asn1/d2i_pr.c | 27 +++++----- crypto/asn1/x_pubkey.c | 33 +++++-------- crypto/engine/eng_fat.c | 11 ++++- crypto/engine/eng_int.h | 1 + crypto/engine/eng_lib.c | 1 + crypto/engine/engine.h | 5 ++ crypto/engine/tb_asnmth.c | 35 +++++++++++-- crypto/evp/evp.h | 11 +++-- crypto/evp/evp_err.c | 2 + crypto/evp/evp_pkey.c | 38 ++++++--------- crypto/evp/p_lib.c | 100 ++++++++++++++++++++++++++++++++------ crypto/evp/pmeth_lib.c | 3 ++ crypto/pem/pem_lib.c | 27 ++++++++-- crypto/pem/pem_pkey.c | 13 ++--- 18 files changed, 359 insertions(+), 128 deletions(-) diff --git a/CHANGES b/CHANGES index 46d5cd8445..22165da32a 100644 --- 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 diff --git a/apps/genpkey.c b/apps/genpkey.c index 8468fb20b3..70e2e31971 100644 --- a/apps/genpkey.c +++ b/apps/genpkey.c @@ -61,6 +61,9 @@ #include #include #include +#ifndef OPENSSL_NO_ENGINE +#include +#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) diff --git a/apps/req.c b/apps/req.c index de1b182fc7..a0eca519af 100644 --- a/apps/req.c +++ b/apps/req.c @@ -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) { diff --git a/crypto/asn1/ameth_lib.c b/crypto/asn1/ameth_lib.c index af08defbe4..a96f1ab289 100644 --- a/crypto/asn1/ameth_lib.c +++ b/crypto/asn1/ameth_lib.c @@ -59,7 +59,9 @@ #include "cryptlib.h" #include #include -#include +#ifndef OPENSSL_NO_ENGINE +#include +#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); diff --git a/crypto/asn1/d2i_pr.c b/crypto/asn1/d2i_pr.c index b4e47d4819..b2791ea66e 100644 --- a/crypto/asn1/d2i_pr.c +++ b/crypto/asn1/d2i_pr.c @@ -61,6 +61,7 @@ #include #include #include +#include #include #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); diff --git a/crypto/asn1/x_pubkey.c b/crypto/asn1/x_pubkey.c index 34f0af0f59..d42b6a2c54 100644 --- a/crypto/asn1/x_pubkey.c +++ b/crypto/asn1/x_pubkey.c @@ -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; } diff --git a/crypto/engine/eng_fat.c b/crypto/engine/eng_fat.c index 41d511a033..db66e62350 100644 --- a/crypto/engine/eng_fat.c +++ b/crypto/engine/eng_fat.c @@ -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; diff --git a/crypto/engine/eng_int.h b/crypto/engine/eng_int.h index 8630597fe0..8bee5962c5 100644 --- a/crypto/engine/eng_int.h +++ b/crypto/engine/eng_int.h @@ -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. */ diff --git a/crypto/engine/eng_lib.c b/crypto/engine/eng_lib.c index 6ee8a90c15..18a6664645 100644 --- a/crypto/engine/eng_lib.c +++ b/crypto/engine/eng_lib.c @@ -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) diff --git a/crypto/engine/engine.h b/crypto/engine/engine.h index 803ebf31b2..9a2eb68646 100644 --- a/crypto/engine/engine.h +++ b/crypto/engine/engine.h @@ -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()" diff --git a/crypto/engine/tb_asnmth.c b/crypto/engine/tb_asnmth.c index b2363a7f00..2476d05912 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 @@ 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; + } diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h index 833257a937..32a1ebe9f6 100644 --- a/crypto/evp/evp.h +++ b/crypto/evp/evp.h @@ -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 diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c index a2f253cbd0..150bfd0db9 100644 --- a/crypto/evp/evp_err.c +++ b/crypto/evp/evp_err.c @@ -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"}, diff --git a/crypto/evp/evp_pkey.c b/crypto/evp/evp_pkey.c index e81c4fedb1..19cdbf9666 100644 --- a/crypto/evp/evp_pkey.c +++ b/crypto/evp/evp_pkey.c @@ -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); diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c index 752547d1e6..939857fdb0 100644 --- a/crypto/evp/p_lib.c +++ b/crypto/evp/p_lib.c @@ -74,6 +74,10 @@ #include #endif +#ifndef OPENSSL_NO_ENGINE +#include +#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; } diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index 8108d448cb..49a8ee99cb 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -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) diff --git a/crypto/pem/pem_lib.c b/crypto/pem/pem_lib.c index 9631ee2d5d..89e41b7f94 100644 --- a/crypto/pem/pem_lib.c +++ b/crypto/pem/pem_lib.c @@ -70,6 +70,9 @@ #ifndef OPENSSL_NO_DES #include #endif +#ifndef OPENSSL_NO_ENGINE +#include +#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; } diff --git a/crypto/pem/pem_pkey.c b/crypto/pem/pem_pkey.c index acd2dc2504..6cca60cb8d 100644 --- a/crypto/pem/pem_pkey.c +++ b/crypto/pem/pem_pkey.c @@ -65,6 +65,9 @@ #include #include #include +#ifndef OPENSSL_NO_ENGINE +#include +#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; -- 2.25.1