From b92524266ae13b1caddf058903438095ab8b791b Mon Sep 17 00:00:00 2001 From: Shubham Mittal <107728331+smittals2@users.noreply.github.com> Date: Fri, 30 Aug 2024 09:42:15 -0700 Subject: [PATCH] Replace ECDSA_METHOD with EC_KEY_METHOD and add the associated API (#1785) ### Description of changes: This is the second pull request in a series of three ([prev PR](https://github.com/aws/aws-lc/pull/1776)). This PR primarily focuses on refactoring and enhancing the EC_KEY_METHOD API. The key changes are as follows: 1. **Removal of ECDSA_METHOD**: ECDSA_METHOD support, including the associated ENGINE functions, has been fully removed and replaced by EC_KEY_METHOD. This aligns with the transition seen in OpenSSL 1.1.1 and was also driven by customer requirements. 2. **Hiding Struct definition**: The EC_KEY_METHOD struct definition is now internal. Unlike OpenSSL, where static allocation was possible, AWS-LC now supports only dynamic allocation of this struct. 3. **Expansion of EC_KEY_METHOD Functions**: Added various EC_KEY_METHOD_* functions to create, free, get/set, and manipulate the EC_KEY_METHOD struct. ### Testing: Tested with various fields initialized in EC_KEY_METHOD to ensure that custom functionality is correctly invoked. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license. --- crypto/ecdsa_extra/ecdsa_asn1.c | 14 +- crypto/engine/engine.c | 27 ++-- crypto/fipsmodule/ec/ec_key.c | 102 ++++++++++++++- crypto/fipsmodule/ec/ec_test.cc | 112 ++++++++++++++++ crypto/fipsmodule/ec/internal.h | 50 ++++++- crypto/fipsmodule/ecdsa/ecdsa.c | 15 ++- include/openssl/base.h | 2 +- include/openssl/ec_key.h | 122 ++++++++++++++---- include/openssl/engine.h | 8 +- .../openvpn_patch/aws-lc-openvpn2-6-x.patch | 28 ++-- 10 files changed, 404 insertions(+), 76 deletions(-) diff --git a/crypto/ecdsa_extra/ecdsa_asn1.c b/crypto/ecdsa_extra/ecdsa_asn1.c index 320d521661..503e8c7462 100644 --- a/crypto/ecdsa_extra/ecdsa_asn1.c +++ b/crypto/ecdsa_extra/ecdsa_asn1.c @@ -72,17 +72,13 @@ size_t ECDSA_size(const EC_KEY *key) { } size_t group_order_size; - if (key->ecdsa_meth && key->ecdsa_meth->group_order_size) { - group_order_size = key->ecdsa_meth->group_order_size(key); - } else { - const EC_GROUP *group = EC_KEY_get0_group(key); - if (group == NULL) { - return 0; - } - - group_order_size = BN_num_bytes(EC_GROUP_get0_order(group)); + const EC_GROUP *group = EC_KEY_get0_group(key); + if (group == NULL) { + return 0; } + group_order_size = BN_num_bytes(EC_GROUP_get0_order(group)); + return ECDSA_SIG_max_len(group_order_size); } diff --git a/crypto/engine/engine.c b/crypto/engine/engine.c index f610c360a7..95a1bbd988 100644 --- a/crypto/engine/engine.c +++ b/crypto/engine/engine.c @@ -24,11 +24,12 @@ #include #include "../internal.h" +#include "../crypto/fipsmodule/ec/internal.h" struct engine_st { RSA_METHOD *rsa_method; - ECDSA_METHOD *ecdsa_method; + EC_KEY_METHOD *eckey_method; }; ENGINE *ENGINE_new(void) { return OPENSSL_zalloc(sizeof(ENGINE)); } @@ -39,29 +40,31 @@ int ENGINE_free(ENGINE *engine) { } int ENGINE_set_RSA(ENGINE *engine, const RSA_METHOD *method) { - if(engine) { - engine->rsa_method = (RSA_METHOD *)method; - return 1; + if(!engine) { + OPENSSL_PUT_ERROR(ENGINE, ERR_R_PASSED_NULL_PARAMETER); + return 0; } - return 0; + engine->rsa_method = (RSA_METHOD *)method; + return 1; } const RSA_METHOD *ENGINE_get_RSA(const ENGINE *engine) { return engine->rsa_method; } -int ENGINE_set_ECDSA(ENGINE *engine, const ECDSA_METHOD *method) { - if(engine) { - engine->ecdsa_method = (ECDSA_METHOD *)method; - return 1; +int ENGINE_set_EC(ENGINE *engine, const EC_KEY_METHOD *method) { + if(!engine) { + OPENSSL_PUT_ERROR(ENGINE, ERR_R_PASSED_NULL_PARAMETER); + return 0; } - return 0; + engine->eckey_method = (EC_KEY_METHOD *)method; + return 1; } -const ECDSA_METHOD *ENGINE_get_ECDSA(const ENGINE *engine) { - return engine->ecdsa_method; +const EC_KEY_METHOD *ENGINE_get_EC(const ENGINE *engine) { + return engine->eckey_method; } OPENSSL_DECLARE_ERROR_REASON(ENGINE, OPERATION_NOT_SUPPORTED) diff --git a/crypto/fipsmodule/ec/ec_key.c b/crypto/fipsmodule/ec/ec_key.c index b305a4f389..730729ee3c 100644 --- a/crypto/fipsmodule/ec/ec_key.c +++ b/crypto/fipsmodule/ec/ec_key.c @@ -111,7 +111,12 @@ EC_KEY *EC_KEY_new_method(const ENGINE *engine) { } if (engine) { - ret->ecdsa_meth = ENGINE_get_ECDSA(engine); + // Cast away const + ret->eckey_method = (EC_KEY_METHOD *) ENGINE_get_EC(engine); + } + + if(ret->eckey_method == NULL) { + ret->eckey_method = EC_KEY_get_default_method(); } ret->conv_form = POINT_CONVERSION_UNCOMPRESSED; @@ -119,7 +124,7 @@ EC_KEY *EC_KEY_new_method(const ENGINE *engine) { CRYPTO_new_ex_data(&ret->ex_data); - if (ret->ecdsa_meth && ret->ecdsa_meth->init && !ret->ecdsa_meth->init(ret)) { + if (ret->eckey_method && ret->eckey_method->init && !ret->eckey_method->init(ret)) { CRYPTO_free_ex_data(g_ec_ex_data_class_bss_get(), ret, &ret->ex_data); OPENSSL_free(ret); return NULL; @@ -150,8 +155,8 @@ void EC_KEY_free(EC_KEY *r) { return; } - if (r->ecdsa_meth && r->ecdsa_meth->finish) { - r->ecdsa_meth->finish(r); + if (r->eckey_method && r->eckey_method->finish) { + r->eckey_method->finish(r); } CRYPTO_free_ex_data(g_ec_ex_data_class_bss_get(), r, &r->ex_data); @@ -195,7 +200,7 @@ int EC_KEY_up_ref(EC_KEY *r) { } int EC_KEY_is_opaque(const EC_KEY *key) { - return key->ecdsa_meth && (key->ecdsa_meth->flags & ECDSA_FLAG_OPAQUE); + return key->eckey_method && (key->eckey_method->flags & ECDSA_FLAG_OPAQUE); } const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key) { return key->group; } @@ -562,3 +567,90 @@ void *EC_KEY_get_ex_data(const EC_KEY *d, int idx) { } void EC_KEY_set_asn1_flag(EC_KEY *key, int flag) {} + +DEFINE_METHOD_FUNCTION(EC_KEY_METHOD, EC_KEY_OpenSSL) { + OPENSSL_memset(out, 0, sizeof(EC_KEY_METHOD)); +} + +const EC_KEY_METHOD *EC_KEY_get_default_method(void) { + return EC_KEY_OpenSSL(); +} + +EC_KEY_METHOD *EC_KEY_METHOD_new(const EC_KEY_METHOD *eckey_meth) { + EC_KEY_METHOD *ret; + + ret = OPENSSL_zalloc(sizeof(EC_KEY_METHOD)); + if(ret == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if(eckey_meth) { + *ret = *eckey_meth; + } + return ret; +} + +void EC_KEY_METHOD_free(EC_KEY_METHOD *eckey_meth) { + if(eckey_meth != NULL) { + OPENSSL_free(eckey_meth); + } +} + +int EC_KEY_set_method(EC_KEY *ec, const EC_KEY_METHOD *meth) { + if(ec == NULL || meth == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + ec->eckey_method = meth; + return 1; +} + +const EC_KEY_METHOD *EC_KEY_get_method(const EC_KEY *ec) { + if(ec == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + return ec->eckey_method; +} + +void EC_KEY_METHOD_set_init_awslc(EC_KEY_METHOD *meth, int (*init)(EC_KEY *key), + void (*finish)(EC_KEY *key)) { + if(meth == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return; + } + + meth->init = init; + meth->finish = finish; +} + +void EC_KEY_METHOD_set_sign_awslc(EC_KEY_METHOD *meth, + int (*sign)(int type, const uint8_t *digest, + int digest_len, uint8_t *sig, + unsigned int *siglen, const BIGNUM *k_inv, + const BIGNUM *r, EC_KEY *eckey), + ECDSA_SIG *(*sign_sig)(const uint8_t *digest, + int digest_len, + const BIGNUM *in_kinv, const BIGNUM *in_r, + EC_KEY *eckey)) { + + if(meth == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return; + } + + meth->sign = sign; + meth->sign_sig = sign_sig; +} + +int EC_KEY_METHOD_set_flags(EC_KEY_METHOD *meth, int flags) { + if(!meth || flags != ECDSA_FLAG_OPAQUE) { + return 0; + } + + meth->flags |= flags; + return 1; +} diff --git a/crypto/fipsmodule/ec/ec_test.cc b/crypto/fipsmodule/ec/ec_test.cc index 6b8d0a82db..ab86698f09 100644 --- a/crypto/fipsmodule/ec/ec_test.cc +++ b/crypto/fipsmodule/ec/ec_test.cc @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -2413,3 +2416,112 @@ TEST(ECTest, FelemBytes) { ASSERT_EQ(test_group.get()->field.N.width, expected_felem_words); } } + +static ECDSA_SIG * ecdsa_sign_sig(const unsigned char *dgst, int dgstlen, + const BIGNUM *in_kinv, const BIGNUM *in_r, + EC_KEY *ec) { + // To track whether custom implementation was called + EC_KEY_set_ex_data(ec, 1, (void*)"ecdsa_sign_sig"); + return nullptr; +} + +static int ecdsa_sign(int type, const unsigned char *dgst, int dgstlen, + unsigned char *sig, unsigned int *siglen, + const BIGNUM *kinv, const BIGNUM *r, EC_KEY *ec) { + + ECDSA_SIG *ret = ECDSA_do_sign(dgst, dgstlen, ec); + if (!ret) { + *siglen = 0; + return 0; + } + + CBB cbb; + CBB_init_fixed(&cbb, sig, ECDSA_size(ec)); + size_t len; + if (!ECDSA_SIG_marshal(&cbb, ret) || + !CBB_finish(&cbb, nullptr, &len)) { + ECDSA_SIG_free(ret); + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_ENCODE_ERROR); + *siglen = 0; + return 0; + } + + *siglen = (unsigned)len; + + // To track whether custom implementation was called + EC_KEY_set_ex_data(ec, 0, (void*)"ecdsa_sign"); + + ECDSA_SIG_free(ret); + return 1; +} + +static void openvpn_extkey_ec_finish(EC_KEY *ec) +{ + const EC_KEY_METHOD *ec_meth = EC_KEY_get_method(ec); + EC_KEY_METHOD_free((EC_KEY_METHOD *) ec_meth); +} + +TEST(ECTest, ECKEYMETHOD) { + EC_KEY *ec = EC_KEY_new(); + ASSERT_TRUE(ec); + + EC_KEY_METHOD *ec_method; + ec_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL()); + ASSERT_TRUE(ec_method); + // We zero initialize the default struct + ASSERT_FALSE(ec_method->finish && ec_method->sign); + + // Can only set these fields + EC_KEY_METHOD_set_init(ec_method, NULL, openvpn_extkey_ec_finish, + NULL, NULL, NULL, NULL); + ASSERT_TRUE(ec_method->finish); + // Checking Sign + EC_KEY_METHOD_set_sign(ec_method, ecdsa_sign, NULL, NULL); + ASSERT_TRUE(ec_method->sign); + + bssl::UniquePtr group(EC_GROUP_new_by_curve_name(NID_secp224r1)); + ASSERT_TRUE(group.get()); + ASSERT_TRUE(EC_KEY_set_group(ec, group.get())); + ASSERT_TRUE(EC_KEY_generate_key(ec)); + + // Should get freed with EC_KEY once assigned through + // |openvpn_extkey_ec_finish| + ASSERT_TRUE(EC_KEY_set_method(ec, ec_method)); + ASSERT_TRUE(EC_KEY_check_key(ec)); + + bssl::UniquePtr ec_key(EVP_PKEY_new()); + ASSERT_TRUE(ec_key.get()); + EVP_PKEY_assign_EC_KEY(ec_key.get(), ec); + bssl::UniquePtr ec_key_ctx(EVP_PKEY_CTX_new(ec_key.get(), NULL)); + ASSERT_TRUE(ec_key_ctx.get()); + + // Do a signature, should call custom openvpn_extkey_ec_finish + uint8_t digest[20]; + ASSERT_TRUE(RAND_bytes(digest, 20)); + CONSTTIME_DECLASSIFY(digest, 20); + std::vector signature(ECDSA_size(ec)); + size_t sig_len = ECDSA_size(ec); + ASSERT_TRUE(EVP_PKEY_sign_init(ec_key_ctx.get())); + ASSERT_TRUE(EVP_PKEY_sign(ec_key_ctx.get(), signature.data(), + &sig_len, digest, 20)); + signature.resize(sig_len); + + ASSERT_STREQ(static_cast(EC_KEY_get_ex_data(ec, 0)) + , "ecdsa_sign"); + // Verify the signature + EXPECT_TRUE(ECDSA_verify(0, digest, 20, signature.data(), signature.size(), + ec)); + + // Now test the sign_sig pointer + EC_KEY_METHOD_set_sign(ec_method, NULL, NULL, ecdsa_sign_sig); + ASSERT_TRUE(ec_method->sign_sig && !ec_method->sign); + + ECDSA_do_sign(digest, 20, ec); + ASSERT_STREQ(static_cast(EC_KEY_get_ex_data(ec, 1)), + "ecdsa_sign_sig"); + + // Flags + ASSERT_FALSE(EC_KEY_is_opaque(ec)); + EC_KEY_METHOD_set_flags(ec_method, ECDSA_FLAG_OPAQUE); + ASSERT_TRUE(EC_KEY_is_opaque(ec)); +} diff --git a/crypto/fipsmodule/ec/internal.h b/crypto/fipsmodule/ec/internal.h index e932b2a6ce..649911aad4 100644 --- a/crypto/fipsmodule/ec/internal.h +++ b/crypto/fipsmodule/ec/internal.h @@ -745,6 +745,54 @@ const EC_METHOD *EC_GFp_nistp521_method(void); // x86-64 optimized P256. See http://eprint.iacr.org/2013/816. const EC_METHOD *EC_GFp_nistz256_method(void); + +// EC_KEY_METHOD + +// ec_key_method_st is a structure of function pointers implementing EC_KEY +// operations. Currently, AWS-LC only allows consumers to use the |init|, +// |finish|, |sign|, |sign_sig|, and |flag| fields. This struct replaces the +// older variant |ECDSA_METHOD|. +// +// We do not support the |verify|, |verify_sig|, |compute_key|, or |keygen| +// fields at all. If this struct is made public in the future, to maintain +// OpenSSL compatability and match the struct size, they should be added in. +struct ec_key_method_st { + int (*init)(EC_KEY *key); + void (*finish)(EC_KEY *key); + + // AWS-LC doesn't support custom values for EC_KEY operations + // as of now. |k_inv| and |r| must be NULL parameters. + // The |type| parameter is ignored in OpenSSL, we pass in zero for it. + // |sign| is invoked in |ECDSA_sign|. + int (*sign)(int type, const uint8_t *digest, int digest_len, + uint8_t *sig, unsigned int *siglen, const BIGNUM *k_inv, + const BIGNUM *r, EC_KEY *eckey); + + // AWS-LC doesn't support custom values for EC_KEY operations + // as of now. |k_inv| and |r| must be NULL parameters. |sign_sig| is + // invoked in |ECDSA_do_sign|. + ECDSA_SIG *(*sign_sig)(const uint8_t *digest, int digest_len, + const BIGNUM *in_kinv, const BIGNUM *in_r, + EC_KEY *eckey); + + // Currently, |EC_KEY_METHOD| only supports |ECDSA_FLAG_OPAQUE|. It is + // not set by default. + int flags; + + // AWS-LC currently does not support these fields directly. However, they + // are left commented out here because the associated setter + // functions (macros) still include support for them in their signatures. + // Note: Compile-time checks (static asserts) are in place to ensure that + // these fields cannot be set by consumers, enforcing the requirement that + // NULL must be passed for these parameters. + // int (*sign_setup)(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **k_inv, + // BIGNUM **r); + // int (*copy)(EC_KEY *dest, const EC_KEY *src); + // int (*set_group)(EC_KEY *key, const EC_GROUP *group); + // int (*set_private)(EC_KEY *key, const BIGNUM *priv_key); + // int (*set_public)(EC_KEY *key, const EC_POINT *pub_key); +}; + // An EC_WRAPPED_SCALAR is an |EC_SCALAR| with a parallel |BIGNUM| // representation. It exists to support the |EC_KEY_get0_private_key| API. typedef struct { @@ -766,7 +814,7 @@ struct ec_key_st { CRYPTO_refcount_t references; - const ECDSA_METHOD *ecdsa_meth; + const EC_KEY_METHOD *eckey_method; CRYPTO_EX_DATA ex_data; } /* EC_KEY */; diff --git a/crypto/fipsmodule/ecdsa/ecdsa.c b/crypto/fipsmodule/ecdsa/ecdsa.c index 5a946ed94a..26a642e363 100644 --- a/crypto/fipsmodule/ecdsa/ecdsa.c +++ b/crypto/fipsmodule/ecdsa/ecdsa.c @@ -273,7 +273,7 @@ ECDSA_SIG *ecdsa_sign_with_nonce_for_known_answer_test(const uint8_t *digest, const EC_KEY *eckey, const uint8_t *nonce, size_t nonce_len) { - if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) { + if (eckey->eckey_method && eckey->eckey_method->sign) { OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED); return NULL; } @@ -309,9 +309,9 @@ ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len, const EC_KEY *eckey) { boringssl_ensure_ecc_self_test(); - if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) { - OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED); - return NULL; + if (eckey->eckey_method && eckey->eckey_method->sign_sig) { + return eckey->eckey_method->sign_sig(digest, (int)digest_len, NULL, NULL, + (EC_KEY *)eckey); } const EC_GROUP *group = EC_KEY_get0_group(eckey); @@ -376,9 +376,10 @@ ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len, // FIPS compliance. int ECDSA_sign(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig, unsigned int *sig_len, const EC_KEY *eckey) { - if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) { - return eckey->ecdsa_meth->sign(digest, digest_len, sig, sig_len, - (EC_KEY*) eckey /* cast away const */); + if (eckey->eckey_method && eckey->eckey_method->sign) { + return eckey->eckey_method->sign(type, digest, (int)digest_len, sig, sig_len, + NULL, NULL, + (EC_KEY*) eckey /* cast away const */); } int ret = 0; diff --git a/include/openssl/base.h b/include/openssl/base.h index b9f6444d4f..66a3c34444 100644 --- a/include/openssl/base.h +++ b/include/openssl/base.h @@ -325,7 +325,7 @@ typedef struct dsa_st DSA; typedef struct ec_group_st EC_GROUP; typedef struct ec_key_st EC_KEY; typedef struct ec_point_st EC_POINT; -typedef struct ecdsa_method_st ECDSA_METHOD; +typedef struct ec_key_method_st EC_KEY_METHOD; typedef struct ecdsa_sig_st ECDSA_SIG; typedef struct engine_st ENGINE; typedef struct env_md_ctx_st EVP_MD_CTX; diff --git a/include/openssl/ec_key.h b/include/openssl/ec_key.h index 10a5f9429a..3a826ba87a 100644 --- a/include/openssl/ec_key.h +++ b/include/openssl/ec_key.h @@ -279,34 +279,6 @@ OPENSSL_EXPORT int EC_KEY_set_ex_data(EC_KEY *r, int idx, void *arg); OPENSSL_EXPORT void *EC_KEY_get_ex_data(const EC_KEY *r, int idx); -// ECDSA method. - -// ECDSA_FLAG_OPAQUE specifies that this ECDSA_METHOD does not expose its key -// material. This may be set if, for instance, it is wrapping some other crypto -// API, like a platform key store. -#define ECDSA_FLAG_OPAQUE 1 - -// ecdsa_method_st is a structure of function pointers for implementing ECDSA. -// See engine.h. -struct ecdsa_method_st { - void *app_data; - - int (*init)(EC_KEY *key); - int (*finish)(EC_KEY *key); - - // group_order_size returns the number of bytes needed to represent the order - // of the group. This is used to calculate the maximum size of an ECDSA - // signature in |ECDSA_size|. - size_t (*group_order_size)(const EC_KEY *key); - - // sign matches the arguments and behaviour of |ECDSA_sign|. - int (*sign)(const uint8_t *digest, size_t digest_len, uint8_t *sig, - unsigned int *sig_len, EC_KEY *eckey); - - int flags; -}; - - // Deprecated functions. // d2i_ECPrivateKey parses a DER-encoded ECPrivateKey structure (RFC 5915) from @@ -356,6 +328,100 @@ OPENSSL_EXPORT EC_KEY *o2i_ECPublicKey(EC_KEY **out_key, const uint8_t **inp, OPENSSL_EXPORT int i2o_ECPublicKey(const EC_KEY *key, unsigned char **outp); +// EC_KEY_METHOD +// This struct replaces the old |ECDSA_METHOD| struct. + +// ECDSA_FLAG_OPAQUE specifies that this EC_KEY_METHOD does not expose its key +// material. This may be set if, for instance, it is wrapping some other crypto +// API, like a platform key store. Use |EC_KEY_METHOD_set_flag| to set +// this flag on an |EC_KEY_METHOD|. It is not set by default. +// This was supported in ECDSA_METHOD previously. +#define ECDSA_FLAG_OPAQUE 1 + +// EC_KEY_get_default_method returns a reference to the default +// |EC_KEY| implementation. All |EC_KEY| objects are initialized with the +// returned struct. This function currently calls |EC_KEY_OpenSSL| since AWS-LC +// does not support changing/setting the default method. +OPENSSL_EXPORT const EC_KEY_METHOD *EC_KEY_get_default_method(void); + +// EC_KEY_OpenSSL returns a reference to the default |EC_KEY| implementation. +// The returned |EC_KEY_METHOD| object is statically allocated. The application +// should not free this struct. +// +// This struct is also zero-initialized. This is different from OpenSSL which +// returns function pointers to the default implementations within the +// |EC_KEY_METHOD| struct. We do not do this to make it easier for the +// compiler/linker to drop unused functions. The wrapper functions for a given +// operation (e.g. |ECDSA_sign| corresponds to the |sign| field in +// |EC_KEY_METHOD|) will select the appropriate default implementation. +OPENSSL_EXPORT const EC_KEY_METHOD *EC_KEY_OpenSSL(void); + +// EC_KEY_METHOD_new returns a newly allocated |EC_KEY_METHOD| object. If the +// input parameter |eckey_meth| is non-NULL, the function pointers within the +// returned |EC_KEY_METHOD| object will be initialized to the values from +// |eckey_meth|. If |eckey_meth| is NULL, the returned object will be +// initialized using the value returned from |EC_KEY_get_default_method|. +OPENSSL_EXPORT EC_KEY_METHOD *EC_KEY_METHOD_new(const EC_KEY_METHOD *eckey_meth); + +// EC_KEY_METHOD_free frees the memory associated with |eckey_meth| +OPENSSL_EXPORT void EC_KEY_METHOD_free(EC_KEY_METHOD *eckey_meth); + +// EC_KEY_set_method sets |meth| on |ec|. We do not support setting the +// |copy|, |set_group|, |set_private|, |set_public|, and |sign_setup| +// fields in |ec| and these pointers should be set to NULL. We do not support +// the |verify|, |verify_sig|, or |keygen| fields yet. +// +// Returns zero on failure and one on success. +OPENSSL_EXPORT int EC_KEY_set_method(EC_KEY *ec, const EC_KEY_METHOD *meth); + +// EC_KEY_get_method returns the |EC_KEY_METHOD| object associated with |ec|. +OPENSSL_EXPORT const EC_KEY_METHOD *EC_KEY_get_method(const EC_KEY *ec); + +// EC_KEY_METHOD_set_sign_awslc sets the |sign| and |sign_sig| pointers on +// |meth|. +OPENSSL_EXPORT void EC_KEY_METHOD_set_sign_awslc(EC_KEY_METHOD *meth, + int (*sign)(int type, const uint8_t *digest, + int digest_len, uint8_t *sig, + unsigned int *siglen, + const BIGNUM *k_inv, + const BIGNUM *r, EC_KEY *eckey), + ECDSA_SIG *(*sign_sig)(const uint8_t *digest, + int digest_len, + const BIGNUM *in_kinv, + const BIGNUM *in_r, + EC_KEY *eckey)); + + +// EC_KEY_METHOD_set_sign sets function pointers on |meth|. AWS-LC currently +// supports setting |sign| and |sign_sig|. |sign_setup| must be set to NULL in +// order to compile with AWS-LC. +#define EC_KEY_METHOD_set_sign(meth, sign, sign_setup, sign_sig) \ + OPENSSL_STATIC_ASSERT((sign_setup) == NULL, \ + EC_KEY_METHOD_sign_setup_field_must_be_NULL); \ + EC_KEY_METHOD_set_sign_awslc(meth, sign, sign_sig); + +// EC_KEY_METHOD_set_init_awslc sets the |init| and |finish| pointers on |meth|. +OPENSSL_EXPORT void EC_KEY_METHOD_set_init_awslc(EC_KEY_METHOD *meth, + int (*init)(EC_KEY *key), + void (*finish)(EC_KEY *key)); + + +// EC_KEY_METHOD_set_init sets function pointers on |meth|. AWS-LC +// currently only supports setting the |init| and |finish| fields. |copy|, +// |set_group|, |set_private|, and |set_public| cannot be set yet and must +// be NULL. +#define EC_KEY_METHOD_set_init(meth, init, finish, copy, set_group, \ + set_private, set_public) \ + OPENSSL_STATIC_ASSERT((copy) == NULL && (set_group) == NULL && \ + (set_private) == NULL && (set_public) == NULL, \ + EC_KEY_METHOD_copy_set_group_set_private_and_set_public_fields_must_be_NULL);\ + EC_KEY_METHOD_set_init_awslc(meth, init, finish); + +// EC_KEY_METHOD_set_flags sets |flags| on |meth|. Currently, the only supported +// flag is |ECDSA_FLAG_OPAQUE|. Returns zero on failure and one on success. +OPENSSL_EXPORT int EC_KEY_METHOD_set_flags(EC_KEY_METHOD *meth, int flags); + + // General No-op Functions [Deprecated]. // EC_KEY_set_asn1_flag does nothing. AWS-LC only supports diff --git a/include/openssl/engine.h b/include/openssl/engine.h index 00c669d763..beaca578a3 100644 --- a/include/openssl/engine.h +++ b/include/openssl/engine.h @@ -54,15 +54,13 @@ OPENSSL_EXPORT int ENGINE_free(ENGINE *engine); // Set functions return one on success and zero for failure when // |engine| is NULL. -OPENSSL_EXPORT int ENGINE_set_RSA(ENGINE *engine, - const RSA_METHOD *method); +OPENSSL_EXPORT int ENGINE_set_RSA(ENGINE *engine, const RSA_METHOD *method); OPENSSL_EXPORT const RSA_METHOD *ENGINE_get_RSA(const ENGINE *engine); -OPENSSL_EXPORT int ENGINE_set_ECDSA(ENGINE *engine, - const ECDSA_METHOD *method); +OPENSSL_EXPORT int ENGINE_set_EC(ENGINE *engine, const EC_KEY_METHOD *method); -OPENSSL_EXPORT const ECDSA_METHOD *ENGINE_get_ECDSA(const ENGINE *engine); +OPENSSL_EXPORT const EC_KEY_METHOD *ENGINE_get_EC(const ENGINE *engine); // Deprecated functions. diff --git a/tests/ci/integration/openvpn_patch/aws-lc-openvpn2-6-x.patch b/tests/ci/integration/openvpn_patch/aws-lc-openvpn2-6-x.patch index 25e87f4832..aa15367e1b 100644 --- a/tests/ci/integration/openvpn_patch/aws-lc-openvpn2-6-x.patch +++ b/tests/ci/integration/openvpn_patch/aws-lc-openvpn2-6-x.patch @@ -1,8 +1,8 @@ diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c -index fbc95ff7..e174ed76 100644 +index fe1254f8..9ca3d36f 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c -@@ -1398,7 +1398,7 @@ memcmp_constant_time(const void *a, const void *b, size_t size) +@@ -1374,7 +1374,7 @@ memcmp_constant_time(const void *a, const void *b, size_t size) return CRYPTO_memcmp(a, b, size); } @@ -11,7 +11,7 @@ index fbc95ff7..e174ed76 100644 bool ssl_tls1_PRF(const uint8_t *seed, int seed_len, const uint8_t *secret, int secret_len, uint8_t *output, int output_len) -@@ -1478,7 +1478,12 @@ tls1_P_hash(const EVP_MD *md, const unsigned char *sec, +@@ -1454,7 +1454,12 @@ tls1_P_hash(const EVP_MD *md, const unsigned char *sec, int ret = false; chunk = EVP_MD_size(md); @@ -25,7 +25,7 @@ index fbc95ff7..e174ed76 100644 ctx = md_ctx_new(); ctx_tmp = md_ctx_new(); diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h -index c9fa7196..a48ef391 100644 +index f487b1bc..b299c4a1 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -75,7 +75,7 @@ X509_OBJECT_free(X509_OBJECT *obj) @@ -38,10 +38,22 @@ index c9fa7196..a48ef391 100644 #endif diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c -index 2595f878..cf99c3ec 100644 +index 23e76231..cab58ff4 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c -@@ -1658,8 +1658,10 @@ tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file, +@@ -1431,7 +1431,11 @@ tls_ctx_use_external_ec_key(struct tls_root_ctx *ctx, EVP_PKEY *pkey) + + /* Among init methods, we only need the finish method */ + EC_KEY_METHOD_set_init(ec_method, NULL, openvpn_extkey_ec_finish, NULL, NULL, NULL, NULL); ++#ifdef OPENSSL_IS_AWSLC ++ EC_KEY_METHOD_set_sign(ec_method, ecdsa_sign, NULL, ecdsa_sign_sig); ++#else + EC_KEY_METHOD_set_sign(ec_method, ecdsa_sign, ecdsa_sign_setup, ecdsa_sign_sig); ++#endif + + ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(pkey)); + if (!ec) +@@ -1658,8 +1662,10 @@ tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file, sk_X509_INFO_pop_free(info_stack, X509_INFO_free); } @@ -52,7 +64,7 @@ index 2595f878..cf99c3ec 100644 SSL_CTX_set_client_CA_list(ctx->ctx, cert_names); } -@@ -1672,7 +1674,6 @@ tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file, +@@ -1672,7 +1678,6 @@ tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file, if (tls_server) { @@ -60,7 +72,7 @@ index 2595f878..cf99c3ec 100644 if (cnum != added) { crypto_msg(M_FATAL, "Cannot load CA certificate file %s (only %d " -@@ -2234,7 +2235,7 @@ show_available_tls_ciphers_list(const char *cipher_list, +@@ -2234,7 +2239,7 @@ show_available_tls_ciphers_list(const char *cipher_list, crypto_msg(M_FATAL, "Cannot create SSL object"); }