Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor RSA_METHOD and expand API #1790

Merged
merged 47 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
9cb198e
refactor engine API and memory around METHOD structs
smittals2 Aug 19, 2024
9c1b425
added check in RSA_free and removed old comment
smittals2 Aug 20, 2024
d9ce001
updated documentation
smittals2 Aug 20, 2024
534e93e
removed ECDSA_METHOD and first batch of EC_KEY_METHOD replacement
smittals2 Jul 25, 2024
76633ab
updated documentation for EC_KEY_METHOD api
smittals2 Aug 9, 2024
b458ac2
refactored EC_KEY_is_opaque and updated documentation
smittals2 Aug 9, 2024
e236789
refactored ECDSA_size as a result of removing ECDSA_METHOD. We don't …
smittals2 Aug 9, 2024
ca46765
changed param type from unsigned int to int to match OpenSSL
smittals2 Aug 9, 2024
0630da8
added function to set flags on EC_KEY_METHOD
smittals2 Aug 20, 2024
9b17db0
changed func sig
smittals2 Aug 20, 2024
0686e44
test for EC_KEY_METHOD
smittals2 Aug 20, 2024
43a7315
added static default eckey meth
smittals2 Aug 20, 2024
3429da0
cleaned up comments and code, changed static allocation
smittals2 Aug 20, 2024
f7fe3b4
added more assertions
smittals2 Aug 20, 2024
8a68735
Merge branch 'main' into eckeymethod
smittals2 Aug 20, 2024
9bda4bb
changed default init for EC_KEY_METHOD for deterministic FIPS hash
smittals2 Aug 22, 2024
2e2d6f3
fixed memory leak in test
smittals2 Aug 22, 2024
3ce0ec8
removed cast for string
smittals2 Aug 22, 2024
f885475
using ASSERT_STREQ for string literals instead of comapring pointers
smittals2 Aug 22, 2024
fca2567
updated patch file to account for sign_setup
smittals2 Aug 23, 2024
83236f9
Merge branch 'main' into eckeymethod
smittals2 Aug 26, 2024
89d7b75
removed unsused fields and updated documentation
smittals2 Aug 28, 2024
474a36f
Merge branch 'main' into eckeymethod
smittals2 Aug 28, 2024
46ccb04
added static asserts for params that should not be set
smittals2 Aug 28, 2024
404312c
removed unused params and updated documetnation
smittals2 Aug 28, 2024
63ca963
using OPENSSL_STATIC_ASSERT and removed IS_NULL macro
smittals2 Aug 28, 2024
6c1f2e7
commented out more unsused fields
smittals2 Aug 29, 2024
c687981
fixed set_method and removed old fields
smittals2 Aug 29, 2024
bccc420
rsa changes and expanded functionality
smittals2 Aug 20, 2024
e163a36
added more checks and changed static default rsa allocation
smittals2 Aug 20, 2024
f72c95e
added RSA_set_flags and RSAErr
smittals2 Aug 21, 2024
f629b73
changed func name
smittals2 Aug 21, 2024
a3607b2
added test for RSA
smittals2 Aug 21, 2024
cc74cba
moved default RSA_METHOD declaration and used macro to prevent FIPS i…
smittals2 Aug 22, 2024
6fc62a8
changed str checks
smittals2 Aug 22, 2024
afd0062
refactored ENGINE funcs and updated documentation
smittals2 Aug 22, 2024
d21e674
updated return values
smittals2 Aug 23, 2024
ed46cde
updated rsa_method test with checks for out_len
smittals2 Aug 23, 2024
bf49206
updated comments and changed openssh integration script
smittals2 Aug 24, 2024
30791a8
Merge branch 'main' into rsaMethod
smittals2 Aug 30, 2024
76e6454
updated patch file to enable mgmt interface with openvpn
smittals2 Aug 30, 2024
612c200
update documentation and added null checks
smittals2 Sep 3, 2024
c286ad7
removed additional space
smittals2 Sep 5, 2024
dd6cc75
updated documentation and added set_sign functionality
smittals2 Sep 5, 2024
685de40
added engine testing
smittals2 Sep 6, 2024
b87e274
updated documentation
smittals2 Sep 6, 2024
b9a609f
updated documentation for custom operations
smittals2 Sep 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 5 additions & 9 deletions crypto/ecdsa_extra/ecdsa_asn1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
35 changes: 22 additions & 13 deletions crypto/engine/engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@
#include <openssl/thread.h>

#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)); }
Expand All @@ -39,29 +40,37 @@ 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) {
smittals2 marked this conversation as resolved.
Show resolved Hide resolved
return engine->rsa_method;
if(engine) {
return engine->rsa_method;;
}
return NULL;
}

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) {
if(engine) {
return engine->eckey_method;
}
return NULL;
}

OPENSSL_DECLARE_ERROR_REASON(ENGINE, OPERATION_NOT_SUPPORTED)
Expand Down
102 changes: 97 additions & 5 deletions crypto/fipsmodule/ec/ec_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,20 @@ 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;
ret->references = 1;

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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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; }
Expand Down Expand Up @@ -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;
}
112 changes: 112 additions & 0 deletions crypto/fipsmodule/ec/ec_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
#include <openssl/crypto.h>
#include <openssl/ec.h>
#include <openssl/ec_key.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/nid.h>
Expand Down Expand Up @@ -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<EC_GROUP> 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<EVP_PKEY> ec_key(EVP_PKEY_new());
ASSERT_TRUE(ec_key.get());
EVP_PKEY_assign_EC_KEY(ec_key.get(), ec);
bssl::UniquePtr<EVP_PKEY_CTX> 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<uint8_t> 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<const char*>(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<const char*>(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));
}
Loading
Loading