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 all 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
10 changes: 8 additions & 2 deletions crypto/engine/engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ int ENGINE_set_RSA(ENGINE *engine, const RSA_METHOD *method) {
}

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_EC(ENGINE *engine, const EC_KEY_METHOD *method) {
Expand All @@ -64,7 +67,10 @@ int ENGINE_set_EC(ENGINE *engine, const EC_KEY_METHOD *method) {
}

const EC_KEY_METHOD *ENGINE_get_EC(const ENGINE *engine) {
return engine->eckey_method;
if(engine) {
return engine->eckey_method;
}
return NULL;
}

OPENSSL_DECLARE_ERROR_REASON(ENGINE, OPERATION_NOT_SUPPORTED)
Expand Down
26 changes: 26 additions & 0 deletions crypto/fipsmodule/ec/ec_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2525,3 +2525,29 @@ TEST(ECTest, ECKEYMETHOD) {
EC_KEY_METHOD_set_flags(ec_method, ECDSA_FLAG_OPAQUE);
ASSERT_TRUE(EC_KEY_is_opaque(ec));
}

TEST(ECTest, ECEngine) {
ENGINE *engine = ENGINE_new();
ASSERT_TRUE(engine);
ASSERT_FALSE(ENGINE_get_EC(engine));

EC_KEY_METHOD *eng_funcs = EC_KEY_METHOD_new(NULL);
ASSERT_TRUE(eng_funcs);
EC_KEY_METHOD_set_sign(eng_funcs, NULL, NULL, ecdsa_sign_sig);

ASSERT_TRUE(ENGINE_set_EC(engine, eng_funcs));
ASSERT_TRUE(ENGINE_get_EC(engine));

EC_KEY *key = EC_KEY_new_method(engine);
ASSERT_TRUE(key);

// Call custom Engine implementation
ECDSA_do_sign(NULL, 0, key);
ASSERT_STREQ(static_cast<const char*>(EC_KEY_get_ex_data(key, 1))
, "ecdsa_sign_sig");

EC_KEY_free(key);
ENGINE_free(engine);
EC_KEY_METHOD_free(eng_funcs);
}

8 changes: 5 additions & 3 deletions crypto/fipsmodule/ec/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -763,14 +763,16 @@ struct ec_key_method_st {
// 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|.
// The default behavior for |sign| is implemented in |ECDSA_sign|. If custom
// functionality is provided, |sign| will be invoked within |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|.
// as of now. |k_inv| and |r| must be NULL parameters. The default behavior
// for |sign_sig| is implemented in |ECDSA_do_sign|. If custom functionality
// is provided, |sign_sig| will be invoked within |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);
Expand Down
69 changes: 65 additions & 4 deletions crypto/fipsmodule/rsa/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,71 @@ extern "C" {

typedef struct bn_blinding_st BN_BLINDING;

struct rsa_meth_st {
void *app_data;

int (*init)(RSA *rsa);
int (*finish)(RSA *rsa);

// size returns the size of the RSA modulus in bytes.
size_t (*size)(const RSA *rsa);

// Set via |RSA_meth_set_sign|. The default behavior for |sign| is
// implemented in |RSA_sign|. If custom functionality is provided, |sign|
// will be invoked within |RSA_sign|.
int (*sign)(int type, const uint8_t *m, unsigned int m_length,
smittals2 marked this conversation as resolved.
Show resolved Hide resolved
uint8_t *sigret, unsigned int *siglen, const RSA *rsa);

// Set via |RSA_meth_set_priv_enc|. |sign_raw| is equivalent to the
// |priv_enc| field of OpenSSL's |RSA_METHOD| struct. The default behavior
// for |sign_raw| is implemented in |RSA_sign_raw|. If custom
// functionality is provided, |sign_raw| will be invoked within
// |RSA_sign_raw|.
int (*sign_raw)(int max_out, const uint8_t *in, uint8_t *out, RSA *rsa,
int padding);

// Set via |RSA_meth_set_pub_dec|. |verify_raw| is equivalent to the
// |pub_dec| field of OpenSSL's |RSA_METHOD| struct. The default behavior
// for |verify_raw| is implemented in |RSA_verify_raw|. If custom
// functionality is provided, |verify_raw| will be invoked within
// |RSA_verify_raw|.
int (*verify_raw)(int max_out, const uint8_t *in, uint8_t *out, RSA *rsa,
int padding);

// Set via |RSA_meth_set_priv_dec|. |decrypt| is equivalent to the
// |priv_dec| field of OpenSSL's |RSA_METHOD| struct. The default behavior
// for |decrypt| is implemented in |RSA_decrypt|. If custom
// functionality is provided, |decrypt| will be invoked within
// |RSA_decrypt|.
int (*decrypt)(int max_out, const uint8_t *in, uint8_t *out, RSA *rsa,
int padding);

// Set via |RSA_meth_set_pub_enc|. |encrypt| is equivalent to the
// |pub_enc| field of OpenSSL's |RSA_METHOD| struct. The default behavior
// for |encrypt| is implemented in |RSA_encrypt|. If custom
// functionality is provided, |encrypt| will be invoked within
// |RSA_encrypt|.
int (*encrypt)(int max_out, const uint8_t *in, uint8_t *out, RSA *rsa,
int padding);

// private_transform takes a big-endian integer from |in|, calculates the
// d'th power of it, modulo the RSA modulus and writes the result as a
// big-endian integer to |out|. Both |in| and |out| are |len| bytes long and
// |len| is always equal to |RSA_size(rsa)|. If the result of the transform
// can be represented in fewer than |len| bytes, then |out| must be zero
// padded on the left.
//
// It returns one on success and zero otherwise.
//
// RSA decrypt and sign operations will call this, thus an ENGINE might wish
// to override it in order to avoid having to implement the padding
// functionality demanded by those, higher level, operations.
int (*private_transform)(RSA *rsa, uint8_t *out, const uint8_t *in,
size_t len);

int flags;
justsmth marked this conversation as resolved.
Show resolved Hide resolved
};

struct rsa_st {
const RSA_METHOD *meth;

Expand Down Expand Up @@ -128,10 +193,6 @@ struct rsa_st {

// Default implementations of RSA operations.

// RSA_default_method returns a zero initialized |RSA_METHOD| object. The
// wrapper functions will select the appropriate |rsa_default_*| implementation.
const RSA_METHOD *RSA_default_method(void);

size_t rsa_default_size(const RSA *rsa);
int rsa_default_sign_raw(RSA *rsa, size_t *out_len, uint8_t *out,
size_t max_out, const uint8_t *in, size_t in_len,
Expand Down
182 changes: 175 additions & 7 deletions crypto/fipsmodule/rsa/rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ RSA *RSA_new_method(const ENGINE *engine) {
}

if (rsa->meth == NULL) {
rsa->meth = (RSA_METHOD *) RSA_default_method();
rsa->meth = (RSA_METHOD *) RSA_get_default_method();
}

rsa->references = 1;
Expand Down Expand Up @@ -448,12 +448,159 @@ int RSA_set0_crt_params(RSA *rsa, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp) {
return 1;
}

RSA_METHOD *RSA_meth_new(const char *name, int flags) {
RSA_METHOD *meth = OPENSSL_zalloc(sizeof(*meth));

if (meth == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
return NULL;
}

if (flags == RSA_FLAG_OPAQUE) {
meth->flags = flags;
}
return meth;
}

int RSA_set_method(RSA *rsa, const RSA_METHOD *meth) {
if(rsa == NULL || meth == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}

rsa->meth = meth;
return 1;
}

const RSA_METHOD *RSA_get_method(const RSA *rsa) {
if(rsa == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}

return rsa->meth;
}

void RSA_meth_free(RSA_METHOD *meth)
{
if (meth != NULL) {
OPENSSL_free(meth);
}
}

int RSA_meth_set_init(RSA_METHOD *meth, int (*init) (RSA *rsa)) {
if(meth == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}

meth->init = init;
return 1;
}

int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa)) {
if(meth == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}

meth->finish = finish;
return 1;
}

int RSA_meth_set_priv_dec(RSA_METHOD *meth,
int (*priv_dec) (int max_out, const uint8_t *from,
uint8_t *to, RSA *rsa,
int padding)) {
if(meth == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}

meth->decrypt = priv_dec;
return 1;
}

int RSA_meth_set_priv_enc(RSA_METHOD *meth,
int (*priv_enc) (int max_out, const uint8_t *from,
uint8_t *to, RSA *rsa,
int padding)) {
if(meth == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}

meth->sign_raw = priv_enc;
return 1;
}

int RSA_meth_set_pub_dec(RSA_METHOD *meth,
int (*pub_dec) (int max_out, const uint8_t *from,
uint8_t *to, RSA *rsa,
int padding)) {
if(meth == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}

meth->verify_raw = pub_dec;
return 1;
}

int RSA_meth_set_pub_enc(RSA_METHOD *meth,
int (*pub_enc) (int max_out, const uint8_t *from,
uint8_t *to, RSA *rsa,
int padding)) {
if(meth == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}

meth->encrypt = pub_enc;
return 1;
}

int RSA_meth_set0_app_data(RSA_METHOD *meth, void *app_data) {
if(meth == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}

meth->app_data = app_data;
return 1;
}

int RSA_meth_set_sign(RSA_METHOD *meth, int (*sign) (int type,
const unsigned char *m, unsigned int m_length, unsigned char *sigret,
unsigned int *siglen, const RSA *rsa)) {
if(meth == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}

meth->sign = sign;
return 1;
}

static int rsa_sign_raw_no_self_test(RSA *rsa, size_t *out_len, uint8_t *out,
size_t max_out, const uint8_t *in,
size_t in_len, int padding) {
SET_DIT_AUTO_DISABLE;
if (rsa->meth->sign_raw) {
return rsa->meth->sign_raw(rsa, out_len, out, max_out, in, in_len, padding);
if (rsa->meth && rsa->meth->sign_raw) {
// In OpenSSL, the RSA_METHOD |sign_raw| or |priv_enc| operation does
// not directly take and initialize an |out_len| parameter. Instead, it
// returns the size of the encrypted data or a negative number for error.
// Our wrapping functions like |RSA_sign_raw| diverge from this paradigm
// and expect an |out_len| parameter. To remain compatible with this new
// paradigm and OpenSSL, we initialize |out_len| based on the return value
// here.
int ret = rsa->meth->sign_raw((int)max_out, in, out, rsa, padding);
if(ret < 0) {
*out_len = 0;
return 0;
}
*out_len = ret;
return 1;
}

return rsa_default_sign_raw(rsa, out_len, out, max_out, in, in_len, padding);
Expand All @@ -470,7 +617,8 @@ int RSA_sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,

unsigned RSA_size(const RSA *rsa) {
SET_DIT_AUTO_DISABLE;
size_t ret = rsa->meth->size ? rsa->meth->size(rsa) : rsa_default_size(rsa);
size_t ret = (rsa->meth && rsa->meth->size) ?
smittals2 marked this conversation as resolved.
Show resolved Hide resolved
rsa->meth->size(rsa) : rsa_default_size(rsa);
// RSA modulus sizes are bounded by |BIGNUM|, which must fit in |unsigned|.
//
// TODO(https://crbug.com/boringssl/516): Should we make this return |size_t|?
Expand Down Expand Up @@ -665,7 +813,7 @@ int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len,
int rsa_sign_no_self_test(int hash_nid, const uint8_t *digest,
size_t digest_len, uint8_t *out, unsigned *out_len,
RSA *rsa) {
if (rsa->meth->sign) {
if (rsa->meth && rsa->meth->sign) {
if (!rsa_check_digest_size(hash_nid, digest_len)) {
return 0;
}
Expand Down Expand Up @@ -862,7 +1010,7 @@ int RSA_verify_pss_mgf1(RSA *rsa, const uint8_t *digest, size_t digest_len,

int rsa_private_transform_no_self_test(RSA *rsa, uint8_t *out,
const uint8_t *in, size_t len) {
if (rsa->meth->private_transform) {
if (rsa->meth && rsa->meth->private_transform) {
return rsa->meth->private_transform(rsa, out, in, len);
}

Expand All @@ -878,12 +1026,32 @@ int rsa_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,

int RSA_flags(const RSA *rsa) {
SET_DIT_AUTO_DISABLE;
if (rsa == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}

return rsa->flags;
}

void RSA_set_flags(RSA *rsa, int flags) {
smittals2 marked this conversation as resolved.
Show resolved Hide resolved
SET_DIT_AUTO_DISABLE;
if (rsa == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_PASSED_NULL_PARAMETER);
return;
}

rsa->flags |= flags;
}

int RSA_test_flags(const RSA *rsa, int flags) {
SET_DIT_AUTO_DISABLE;
return rsa->flags & flags;
if (rsa) {
return rsa->flags & flags;
}

OPENSSL_PUT_ERROR(RSA, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}

int RSA_blinding_on(RSA *rsa, BN_CTX *ctx) {
Expand Down
Loading
Loading