From 28572b577c9a8fa41d85e1d2dce8afb2892464cd Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Mon, 19 Oct 2015 14:38:43 +0100 Subject: [PATCH] Support for EC_KEY_METHOD. Add EC_KEY_METHOD. This is part of the EC revision and will make EC behave more like other algorithms. Specifically: EC_KEY_METHOD is part of EC_KEY. It is part of ENGINE. Default or key specific implementations can be provided to redirect some or all operations. Reviewed-by: Richard Levitte --- crypto/ec/Makefile | 4 +- crypto/ec/ec_key.c | 12 +--- crypto/ec/ec_kmeth.c | 120 +++++++++++++++++++++++++++++++++++++ crypto/ec/ec_lcl.h | 11 ++++ crypto/engine/Makefile | 4 +- crypto/engine/eng_int.h | 1 + crypto/engine/tb_eckey.c | 124 +++++++++++++++++++++++++++++++++++++++ include/openssl/ec.h | 6 ++ include/openssl/engine.h | 9 +++ 9 files changed, 276 insertions(+), 15 deletions(-) create mode 100644 crypto/ec/ec_kmeth.c create mode 100644 crypto/engine/tb_eckey.c diff --git a/crypto/ec/Makefile b/crypto/ec/Makefile index 18e9610180..2ecac0fa74 100644 --- a/crypto/ec/Makefile +++ b/crypto/ec/Makefile @@ -21,13 +21,13 @@ LIBSRC= ec_lib.c ecp_smpl.c ecp_mont.c ecp_nist.c ec_cvt.c ec_mult.c\ ec_err.c ec_curve.c ec_check.c ec_print.c ec_asn1.c ec_key.c\ ec2_smpl.c ec2_mult.c ec_ameth.c ec_pmeth.c eck_prn.c \ ecp_nistp224.c ecp_nistp256.c ecp_nistp521.c ecp_nistputil.c \ - ecp_oct.c ec2_oct.c ec_oct.c + ecp_oct.c ec2_oct.c ec_oct.c ec_kmeth.c LIBOBJ= ec_lib.o ecp_smpl.o ecp_mont.o ecp_nist.o ec_cvt.o ec_mult.o\ ec_err.o ec_curve.o ec_check.o ec_print.o ec_asn1.o ec_key.o\ ec2_smpl.o ec2_mult.o ec_ameth.o ec_pmeth.o eck_prn.o \ ecp_nistp224.o ecp_nistp256.o ecp_nistp521.o ecp_nistputil.o \ - ecp_oct.o ec2_oct.o ec_oct.o $(EC_ASM) + ecp_oct.o ec2_oct.o ec_oct.o ec_kmeth.o $(EC_ASM) SRC= $(LIBSRC) diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c index d5706010ff..4a086be096 100644 --- a/crypto/ec/ec_key.c +++ b/crypto/ec/ec_key.c @@ -68,17 +68,7 @@ EC_KEY *EC_KEY_new(void) { - EC_KEY *ret = OPENSSL_zalloc(sizeof(*ret)); - - if (ret == NULL) { - ECerr(EC_F_EC_KEY_NEW, ERR_R_MALLOC_FAILURE); - return (NULL); - } - - ret->version = 1; - ret->conv_form = POINT_CONVERSION_UNCOMPRESSED; - ret->references = 1; - return (ret); + return EC_KEY_new_method(NULL); } EC_KEY *EC_KEY_new_by_curve_name(int nid) diff --git a/crypto/ec/ec_kmeth.c b/crypto/ec/ec_kmeth.c new file mode 100644 index 0000000000..f0e3fdeadf --- /dev/null +++ b/crypto/ec/ec_kmeth.c @@ -0,0 +1,120 @@ +/* crypto/ec/ec_kmeth.c */ +/* + * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2015 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#include +#include +#include +#include "ec_lcl.h" + + +static const EC_KEY_METHOD openssl_ec_key_method = { + "OpenSSL EC_KEY method", + 0 +}; + +const EC_KEY_METHOD *default_ec_key_meth = &openssl_ec_key_method; + +const EC_KEY_METHOD *EC_KEY_OpenSSL(void) +{ + return &openssl_ec_key_method; +} + +const EC_KEY_METHOD *EC_KEY_get_default_method(void) +{ + return default_ec_key_meth; +} + +void EC_KEY_set_default_method(const EC_KEY_METHOD *meth) +{ + if (meth == NULL) + default_ec_key_meth = &openssl_ec_key_method; + else + default_ec_key_meth = meth; +} + +EC_KEY *EC_KEY_new_method(ENGINE *engine) +{ + EC_KEY *ret = OPENSSL_zalloc(sizeof(*ret)); + + if (ret == NULL) { + ECerr(EC_F_EC_KEY_NEW_METHOD, ERR_R_MALLOC_FAILURE); + return (NULL); + } + ret->meth = EC_KEY_get_default_method(); +#ifndef OPENSSL_NO_ENGINE + if (engine) { + if (!ENGINE_init(engine)) { + ECerr(EC_F_EC_KEY_NEW_METHOD, ERR_R_ENGINE_LIB); + OPENSSL_free(ret); + return NULL; + } + ret->engine = engine; + } else + ret->engine = ENGINE_get_default_EC_KEY(); + if (ret->engine) { + ret->meth = ENGINE_get_EC_KEY(ret->engine); + if (!ret->meth) { + ECerr(EC_F_EC_KEY_NEW_METHOD, ERR_R_ENGINE_LIB); + ENGINE_finish(ret->engine); + OPENSSL_free(ret); + return NULL; + } + } +#endif + + ret->version = 1; + ret->conv_form = POINT_CONVERSION_UNCOMPRESSED; + ret->references = 1; + return (ret); +} diff --git a/crypto/ec/ec_lcl.h b/crypto/ec/ec_lcl.h index 3bf64c6497..77b294114e 100644 --- a/crypto/ec/ec_lcl.h +++ b/crypto/ec/ec_lcl.h @@ -257,6 +257,8 @@ struct ec_group_st { } /* EC_GROUP */ ; struct ec_key_st { + const EC_KEY_METHOD *meth; + ENGINE *engine; int version; EC_GROUP *group; EC_POINT *pub_key; @@ -552,3 +554,12 @@ int ec_precompute_mont_data(EC_GROUP *); */ const EC_METHOD *EC_GFp_nistz256_method(void); #endif + +/* EC_METHOD definitions */ + +struct ec_key_method_st { + const char *name; + int32_t flags; +} /* EC_KEY_METHOD */ ; + +#define EC_KEY_METHOD_DYNAMIC 1 diff --git a/crypto/engine/Makefile b/crypto/engine/Makefile index dae2926746..74ff4ff622 100644 --- a/crypto/engine/Makefile +++ b/crypto/engine/Makefile @@ -18,13 +18,13 @@ LIB=$(TOP)/libcrypto.a LIBSRC= eng_err.c eng_lib.c eng_list.c eng_init.c eng_ctrl.c \ eng_table.c eng_pkey.c eng_fat.c eng_all.c \ tb_rsa.c tb_dsa.c tb_ecdsa.c tb_dh.c tb_ecdh.c tb_rand.c tb_store.c \ - tb_cipher.c tb_digest.c tb_pkmeth.c tb_asnmth.c \ + tb_cipher.c tb_digest.c tb_pkmeth.c tb_asnmth.c tb_eckey.c \ eng_openssl.c eng_cnf.c eng_dyn.c eng_cryptodev.c \ eng_rdrand.c LIBOBJ= eng_err.o eng_lib.o eng_list.o eng_init.o eng_ctrl.o \ eng_table.o eng_pkey.o eng_fat.o eng_all.o \ tb_rsa.o tb_dsa.o tb_ecdsa.o tb_dh.o tb_ecdh.o tb_rand.o tb_store.o \ - tb_cipher.o tb_digest.o tb_pkmeth.o tb_asnmth.o \ + tb_cipher.o tb_digest.o tb_pkmeth.o tb_asnmth.o tb_eckey.o \ eng_openssl.o eng_cnf.o eng_dyn.o eng_cryptodev.o \ eng_rdrand.o diff --git a/crypto/engine/eng_int.h b/crypto/engine/eng_int.h index 42674e14fa..91160ded48 100644 --- a/crypto/engine/eng_int.h +++ b/crypto/engine/eng_int.h @@ -181,6 +181,7 @@ struct engine_st { const DH_METHOD *dh_meth; const ECDH_METHOD *ecdh_meth; const ECDSA_METHOD *ecdsa_meth; + const EC_KEY_METHOD *ec_key_meth; const RAND_METHOD *rand_meth; const STORE_METHOD *store_meth; /* Cipher handling is via this callback */ diff --git a/crypto/engine/tb_eckey.c b/crypto/engine/tb_eckey.c new file mode 100644 index 0000000000..a3a4a23f81 --- /dev/null +++ b/crypto/engine/tb_eckey.c @@ -0,0 +1,124 @@ +/* ==================================================================== + * Copyright (c) 2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include "eng_int.h" + +/* + * If this symbol is defined then ENGINE_get_default_EC_KEY(), the function that + * is used by EC_KEY to hook in implementation code and cache defaults (etc), + * will display brief debugging summaries to stderr with the 'nid'. + */ +/* #define ENGINE_EC_KEY_DEBUG */ + +static ENGINE_TABLE *dh_table = NULL; +static const int dummy_nid = 1; + +void ENGINE_unregister_EC_KEY(ENGINE *e) +{ + engine_table_unregister(&dh_table, e); +} + +static void engine_unregister_all_EC_KEY(void) +{ + engine_table_cleanup(&dh_table); +} + +int ENGINE_register_EC_KEY(ENGINE *e) +{ + if (e->ec_key_meth) + return engine_table_register(&dh_table, + engine_unregister_all_EC_KEY, e, &dummy_nid, + 1, 0); + return 1; +} + +void ENGINE_register_all_EC_KEY() +{ + ENGINE *e; + + for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) + ENGINE_register_EC_KEY(e); +} + +int ENGINE_set_default_EC_KEY(ENGINE *e) +{ + if (e->ec_key_meth) + return engine_table_register(&dh_table, + engine_unregister_all_EC_KEY, e, &dummy_nid, + 1, 1); + return 1; +} + +/* + * Exposed API function to get a functional reference from the implementation + * table (ie. try to get a functional reference from the tabled structural + * references). + */ +ENGINE *ENGINE_get_default_EC_KEY(void) +{ + return engine_table_select(&dh_table, dummy_nid); +} + +/* Obtains an EC_KEY implementation from an ENGINE functional reference */ +const EC_KEY_METHOD *ENGINE_get_EC_KEY(const ENGINE *e) +{ + return e->ec_key_meth; +} + +/* Sets an EC_KEY implementation in an ENGINE structure */ +int ENGINE_set_EC_KEY(ENGINE *e, const EC_KEY_METHOD *ec_key_meth) +{ + e->ec_key_meth = ec_key_meth; + return 1; +} diff --git a/include/openssl/ec.h b/include/openssl/ec.h index 6ea4e419c4..9869cb6c68 100644 --- a/include/openssl/ec.h +++ b/include/openssl/ec.h @@ -740,6 +740,7 @@ int ECPKParameters_print_fp(FILE *fp, const EC_GROUP *x, int off); /********************************************************************/ typedef struct ec_key_st EC_KEY; +typedef struct ec_key_method_st EC_KEY_METHOD; /* some values for the encoding_flag */ # define EC_PKEY_NO_PARAMETERS 0x001 @@ -983,6 +984,11 @@ int EC_KEY_print_fp(FILE *fp, const EC_KEY *key, int off); # endif +const EC_KEY_METHOD *EC_KEY_OpenSSL(void); +const EC_KEY_METHOD *EC_KEY_get_default_method(void); +void EC_KEY_set_default_method(const EC_KEY_METHOD *meth); +EC_KEY *EC_KEY_new_method(ENGINE *engine); + # define ECParameters_dup(x) ASN1_dup_of(EC_KEY,i2d_ECParameters,d2i_ECParameters,x) # ifndef __cplusplus diff --git a/include/openssl/engine.h b/include/openssl/engine.h index 1b11e3e2ff..865eef1599 100644 --- a/include/openssl/engine.h +++ b/include/openssl/engine.h @@ -115,6 +115,7 @@ extern "C" { # define ENGINE_METHOD_STORE (unsigned int)0x0100 # define ENGINE_METHOD_PKEY_METHS (unsigned int)0x0200 # define ENGINE_METHOD_PKEY_ASN1_METHS (unsigned int)0x0400 +# define ENGINE_METHOD_EC_KEY (unsigned int)0x0800 /* Obvious all-or-nothing cases. */ # define ENGINE_METHOD_ALL (unsigned int)0xFFFF # define ENGINE_METHOD_NONE (unsigned int)0x0000 @@ -447,6 +448,10 @@ int ENGINE_register_ECDSA(ENGINE *e); void ENGINE_unregister_ECDSA(ENGINE *e); void ENGINE_register_all_ECDSA(void); +int ENGINE_register_EC_KEY(ENGINE *e); +void ENGINE_unregister_EC_KEY(ENGINE *e); +void ENGINE_register_all_EC_KEY(void); + int ENGINE_register_DH(ENGINE *e); void ENGINE_unregister_DH(ENGINE *e); void ENGINE_register_all_DH(void); @@ -555,6 +560,7 @@ int ENGINE_set_RSA(ENGINE *e, const RSA_METHOD *rsa_meth); int ENGINE_set_DSA(ENGINE *e, const DSA_METHOD *dsa_meth); int ENGINE_set_ECDH(ENGINE *e, const ECDH_METHOD *ecdh_meth); int ENGINE_set_ECDSA(ENGINE *e, const ECDSA_METHOD *ecdsa_meth); +int ENGINE_set_EC_KEY(ENGINE *e, const EC_KEY_METHOD *ecdsa_meth); int ENGINE_set_DH(ENGINE *e, const DH_METHOD *dh_meth); int ENGINE_set_RAND(ENGINE *e, const RAND_METHOD *rand_meth); int ENGINE_set_STORE(ENGINE *e, const STORE_METHOD *store_meth); @@ -600,6 +606,7 @@ const RSA_METHOD *ENGINE_get_RSA(const ENGINE *e); const DSA_METHOD *ENGINE_get_DSA(const ENGINE *e); const ECDH_METHOD *ENGINE_get_ECDH(const ENGINE *e); const ECDSA_METHOD *ENGINE_get_ECDSA(const ENGINE *e); +const EC_KEY_METHOD *ENGINE_get_EC_KEY(const ENGINE *e); const DH_METHOD *ENGINE_get_DH(const ENGINE *e); const RAND_METHOD *ENGINE_get_RAND(const ENGINE *e); const STORE_METHOD *ENGINE_get_STORE(const ENGINE *e); @@ -679,6 +686,7 @@ ENGINE *ENGINE_get_default_RSA(void); ENGINE *ENGINE_get_default_DSA(void); ENGINE *ENGINE_get_default_ECDH(void); ENGINE *ENGINE_get_default_ECDSA(void); +ENGINE *ENGINE_get_default_EC_KEY(void); ENGINE *ENGINE_get_default_DH(void); ENGINE *ENGINE_get_default_RAND(void); /* @@ -702,6 +710,7 @@ int ENGINE_set_default_string(ENGINE *e, const char *def_list); int ENGINE_set_default_DSA(ENGINE *e); int ENGINE_set_default_ECDH(ENGINE *e); int ENGINE_set_default_ECDSA(ENGINE *e); +int ENGINE_set_default_EC_KEY(ENGINE *e); int ENGINE_set_default_DH(ENGINE *e); int ENGINE_set_default_RAND(ENGINE *e); int ENGINE_set_default_ciphers(ENGINE *e); -- 2.25.1