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

Correct EVP_PKEY ownership #535

Merged
merged 8 commits into from
Sep 23, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
31 changes: 20 additions & 11 deletions src/soter/boringssl/soter_asym_cipher.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ soter_status_t soter_asym_cipher_init(soter_asym_cipher_t* asym_cipher,
const size_t key_length,
soter_asym_cipher_padding_t pad)
{
EVP_PKEY* pkey;
soter_status_t err = SOTER_FAIL;
EVP_PKEY* pkey = NULL;

if ((!asym_cipher) || (SOTER_ASYM_CIPHER_OAEP != pad)) {
return SOTER_INVALID_PARAMETER;
Expand All @@ -90,18 +91,29 @@ soter_status_t soter_asym_cipher_init(soter_asym_cipher_t* asym_cipher,

/* Only RSA supports asymmetric encryption */
if (!EVP_PKEY_set_type(pkey, EVP_PKEY_RSA)) {
EVP_PKEY_free(pkey);
return SOTER_FAIL;
goto free_pkey;
}

asym_cipher->pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL);
if (!(asym_cipher->pkey_ctx)) {
EVP_PKEY_free(pkey);
return SOTER_FAIL;
err = SOTER_NO_MEMORY;
goto free_pkey;
}

err = soter_asym_cipher_import_key(asym_cipher, key, key_length);
if (err != SOTER_SUCCESS) {
goto free_pkey_ctx;
}
SOTER_IF_FAIL(soter_asym_cipher_import_key(asym_cipher, key, key_length) == SOTER_SUCCESS,
(EVP_PKEY_free(pkey), EVP_PKEY_CTX_free(asym_cipher->pkey_ctx)));

EVP_PKEY_free(pkey);
return SOTER_SUCCESS;

free_pkey_ctx:
EVP_PKEY_CTX_free(asym_cipher->pkey_ctx);
asym_cipher->pkey_ctx = NULL;
free_pkey:
EVP_PKEY_free(pkey);
return err;
}

SOTER_PRIVATE_API
Expand All @@ -112,11 +124,8 @@ soter_status_t soter_asym_cipher_cleanup(soter_asym_cipher_t* asym_cipher)
}

if (asym_cipher->pkey_ctx) {
EVP_PKEY* pkey = EVP_PKEY_CTX_get0_pkey(asym_cipher->pkey_ctx);
if (pkey) {
EVP_PKEY_free(pkey);
}
EVP_PKEY_CTX_free(asym_cipher->pkey_ctx);
asym_cipher->pkey_ctx = NULL;
}

return SOTER_SUCCESS;
Expand Down
37 changes: 22 additions & 15 deletions src/soter/boringssl/soter_asym_ka.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ static int soter_alg_to_curve_nid(soter_asym_ka_alg_t alg)
SOTER_PRIVATE_API
soter_status_t soter_asym_ka_init(soter_asym_ka_t* asym_ka_ctx, soter_asym_ka_alg_t alg)
{
EVP_PKEY* pkey;
soter_status_t err = SOTER_FAIL;
EVP_PKEY* pkey = NULL;
EC_KEY* ec = NULL;
int nid = soter_alg_to_curve_nid(alg);

if ((!asym_ka_ctx) || (0 == nid)) {
ilammy marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -48,28 +50,36 @@ soter_status_t soter_asym_ka_init(soter_asym_ka_t* asym_ka_ctx, soter_asym_ka_al
}

if (!EVP_PKEY_set_type(pkey, EVP_PKEY_EC)) {
EVP_PKEY_free(pkey);
return SOTER_FAIL;
goto free_pkey;
}

asym_ka_ctx->pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL);
if (!(asym_ka_ctx->pkey_ctx)) {
EVP_PKEY_free(pkey);
return SOTER_FAIL;
err = SOTER_NO_MEMORY;
goto free_pkey;
}
EC_KEY* ec = EC_KEY_new_by_curve_name(nid);

ec = EC_KEY_new_by_curve_name(nid);
if (!ec) {
EVP_PKEY_CTX_free(asym_ka_ctx->pkey_ctx);
return SOTER_FAIL;
goto free_pkey_ctx;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's ok, but for future better to set err type SOTER_INVALID_PARAMETER in this case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that we should return SOTER_FAIL in this case. EC_KEY_new_by_curve_name() could fail if the nid argument is invalid, but we’re checking for that here (nid == 0):

int nid = soter_alg_to_curve_nid(alg);
if ((!asym_ka_ctx) || (0 == nid)) {
return SOTER_INVALID_PARAMETER;
}

That’s why the most likely reason for failure is some internal error in cryptographic backend. SOTER_INVALID_PARAMETER is used to indicate to the user that they broke some contract for expected function parameters and this error can be avoided by passing correct parameter values. It's used for ‘obvious’ errors like using NULL values where they are not expected, while SOTER_FAIL usually indicates deeper issues with arguments, or acts like a generic catch-all error code.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. I agree

}

if (1 != EVP_PKEY_set1_EC_KEY(pkey, ec)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know about your coding style guide, but it would be better to swap this parameters for better reading.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it can be rewrited with less code using EVP_PKEY_assign_EC_KEY(). I don't see any reason to use EVP_PKEY_set1_EC_KEY() in this plase.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the Yoda-style comparisons, they are not prescribed by the coding style and we don’t really like them that much (exactly for readability reasons). But it’s tedious to walk through all instances of such legacy code at once, so we incrementally modernize it during refactoring. Thank you for noting 👍 This code style, much readable it is not.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You’re absolutely right about EVP_PKEY_assign_EC_KEY(), It avoid unnecessary reference counting. I’ll update this part. Thank you.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I remember, this type of comparisons was used to avoid errors in C code like if (a = someFunc()). Using constant values (rvalue) as left operand of comparison you will see error on compilation because can't assign value if miss one "=" sign. It's less readable but saves from such errors

Copy link
Collaborator Author

@ilammy ilammy Sep 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another merit of this style is that it actually makes comparisons with long function calls more readable if they are made inline. Compare

if (EVP_PKEY_decrypt(asym_cipher->pkey_ctx, NULL, &output_length, (const unsigned char*)cipher_data, cipher_data_length) != -1) {
	// ...
}

with

if (-1 != EVP_PKEY_decrypt(asym_cipher->pkey_ctx, NULL, &output_length, (const unsigned char*)cipher_data, cipher_data_length)) {
	// ...
}

where it's really easy to miss whether it’s == or != and if it’s -1, or 0, or whatever.

Though, it’s less of an issue with our current code style that places a reasonable limit on the line length:

if (EVP_PKEY_decrypt(asym_cipher->pkey_ctx,
                     NULL,
                     &output_length,
                     (const unsigned char*)cipher_data,
                     cipher_data_length) != -1) {
    // ...
}

or even better:

err = EVP_PKEY_decrypt(asym_cipher->pkey_ctx,
                       NULL,
                       &output_length,
                       (const unsigned char*)cipher_data,
                       cipher_data_length);
if (err != -1) {
    // ...
}

As for accidentally using = instead of ==, I personally favor the -Wparentheses compiler warnings over an unnatural code style. So I’m all in for making the dog wag the tail, just without having a dedicated 8000-line-change that does only that.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for accidentally using = instead of ==, I personally favor the -Wparentheses compiler warnings over an unnatural code style.

how this flag will save from assigning in "if" statements which allowed by language syntax?

Copy link
Collaborator Author

@ilammy ilammy Sep 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Lagovas, a typical mistake looks like this:

pkey = EVP_PKEY_CTX_get0_pkey(pkey_ctx);
if (pkey = NULL) {
    return SOTER_INVALID_PARAMETER;
}

in which case the compiler will give a friendly warning:

src/soter/boringssl/soter_ecdsa_common.c:33:14: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
    if (pkey = NULL) {
        ~~~~~^~~~~~
src/soter/boringssl/soter_ecdsa_common.c:33:14: note: place parentheses around the assignment to silence this warning
    if (pkey = NULL) {
             ^
        (          )
src/soter/boringssl/soter_ecdsa_common.c:33:14: note: use '==' to turn this assignment into an equality comparison
    if (pkey = NULL) {
             ^
             ==
1 warning generated.

This has to be addressed, given that we treat warnings as errors in pull requests.

Obviously, if you do intent to make an assignment in conditional then you may explicitly code it like this (note the double parentheses):

if ((pkey = EVP_PKEY_CTX_get0_pkey(pkey_ctx))) {
    // pkey != NULL here
}

(It works for boolean function arguments as well.)

EVP_PKEY_CTX_free(asym_ka_ctx->pkey_ctx);
EC_KEY_free(ec);
return SOTER_FAIL;
goto free_ec_key;
}

EC_KEY_free(ec);
EVP_PKEY_free(pkey);
return SOTER_SUCCESS;

free_ec_key:
EC_KEY_free(ec);
free_pkey_ctx:
EVP_PKEY_CTX_free(asym_ka_ctx->pkey_ctx);
asym_ka_ctx->pkey_ctx = NULL;
free_pkey:
EVP_PKEY_free(pkey);
return err;
}

SOTER_PRIVATE_API
Expand All @@ -79,11 +89,8 @@ soter_status_t soter_asym_ka_cleanup(soter_asym_ka_t* asym_ka_ctx)
return SOTER_INVALID_PARAMETER;
}
if (asym_ka_ctx->pkey_ctx) {
EVP_PKEY* pkey = EVP_PKEY_CTX_get0_pkey(asym_ka_ctx->pkey_ctx);
if (pkey) {
EVP_PKEY_free(pkey);
}
EVP_PKEY_CTX_free(asym_ka_ctx->pkey_ctx);
asym_ka_ctx->pkey_ctx = NULL;
}
return SOTER_SUCCESS;
}
Expand Down
40 changes: 30 additions & 10 deletions src/soter/boringssl/soter_rsa_key_pair_gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,47 @@ soter_rsa_key_pair_gen_t* soter_rsa_key_pair_gen_create(const unsigned key_lengt

soter_status_t soter_rsa_key_pair_gen_init(soter_rsa_key_pair_gen_t* ctx, const unsigned key_length)
{
EVP_PKEY* pkey;
soter_status_t err = SOTER_FAIL;
EVP_PKEY* pkey = NULL;

pkey = EVP_PKEY_new();
SOTER_CHECK(pkey);
if (!pkey) {
return SOTER_NO_MEMORY;
}

/* Only RSA supports asymmetric encryption */
SOTER_IF_FAIL(EVP_PKEY_set_type(pkey, EVP_PKEY_RSA), EVP_PKEY_free(pkey));
if (EVP_PKEY_set_type(pkey, EVP_PKEY_RSA) != 1) {
goto free_pkey;
}

ctx->pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL);
SOTER_IF_FAIL(ctx->pkey_ctx, EVP_PKEY_free(pkey));
SOTER_IF_FAIL(soter_rsa_gen_key(ctx->pkey_ctx, key_length) == SOTER_SUCCESS,
EVP_PKEY_CTX_free(ctx->pkey_ctx));
if (!ctx->pkey_ctx) {
err = SOTER_NO_MEMORY;
goto free_pkey;
}

err = soter_rsa_gen_key(ctx->pkey_ctx, key_length);
if (err != SOTER_SUCCESS) {
goto free_pkey_ctx;
}

EVP_PKEY_free(pkey);
return SOTER_SUCCESS;

free_pkey_ctx:
EVP_PKEY_CTX_free(ctx->pkey_ctx);
ctx->pkey_ctx = NULL;
free_pkey:
EVP_PKEY_free(pkey);
return err;
}

soter_status_t soter_rsa_key_pair_gen_cleanup(soter_rsa_key_pair_gen_t* ctx)
{
SOTER_CHECK_PARAM(ctx);
if (ctx->pkey_ctx) {
EVP_PKEY* pkey = EVP_PKEY_CTX_get0_pkey(ctx->pkey_ctx);
if (pkey) {
EVP_PKEY_free(pkey);
}
EVP_PKEY_CTX_free(ctx->pkey_ctx);
ctx->pkey_ctx = NULL;
}
return SOTER_SUCCESS;
}
Expand Down
58 changes: 34 additions & 24 deletions src/soter/boringssl/soter_sign_ecdsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,52 +30,66 @@ soter_status_t soter_sign_init_ecdsa_none_pkcs8(soter_sign_ctx_t* ctx,
const void* public_key,
const size_t public_key_length)
{
/* pkey_ctx init */
EVP_PKEY* pkey;
soter_status_t err = SOTER_FAIL;
EVP_PKEY* pkey = NULL;

pkey = EVP_PKEY_new();
if (!pkey) {
return SOTER_NO_MEMORY;
}

if (!EVP_PKEY_set_type(pkey, EVP_PKEY_EC)) {
EVP_PKEY_free(pkey);
return SOTER_FAIL;
goto free_pkey;
}

ctx->pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this plase we get dereferencing a pointer. It would be good to check ctx before.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is not in SOTER_PRIVATE_API and i think that it would be good make that check. Same in soter_sign_final_ecdsa_none_pkcs8 (in this file)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functions that are not marked SOTER_API are considered to be private to Soter and they can make assumptions about arguments. Usually we check arguments for NULL in public functions and let the private ones assume that the arguments are more or less sane.

In this case soter_sign_init_ecdsa_none_pkcs8() is called by soter_sign_init() which does check that ctx is non-NULL beforehand. It’s also checked a couple of times more up the call stack, so we can be sure that it won’t be NULL in soter_sign_init_ecdsa_none_pkcs8().

SOTER_PRIVATE_API is kind of a hack that intentionally exposes private API for Themis. It’s not really pretty, but some code currently calls such functions and makes necessary precautions to ensure that they are safe to call. At some point we intend to get rid of SOTER_PRIVATE_API to avoid confusion over what’s public and what’s private.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your explanation. Now I have knowledge how this visibility works. This kind of bug is not connected with PR. But you have such functions in SOTER_API. Ex. is soter_rsa_key_pair_gen_init(). This is notice to be cerfull with this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mb it will be good to make some rule how to work with this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, with soter_rsa_key_pair_gen_init() is bad example (becouse it should be not in SOTER_API). But if we look at typtcal usage any public funtion it would be checked twice ore even more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, C does not really provide any amenities for null checks. Theoretically, we could use __attribute__((nonnull)) or something like that, but that’s not really portable and too much of a bother. Generally, the rules are that public functions (marked with SOTER_API or THEMIS_API) have to do paranoid thorough parameter checking while internal functions may expect the parameters to have reasonable values. And generally, it does not really hurt if internal functions have duplicated checks. Better safe than segfault.

if (!(ctx->pkey_ctx)) {
EVP_PKEY_free(pkey);
return SOTER_FAIL;
err = SOTER_NO_MEMORY;
goto free_pkey;
}

if ((!private_key) && (!public_key)) {
if (soter_ec_gen_key(ctx->pkey_ctx) != SOTER_SUCCESS) {
soter_sign_cleanup_ecdsa_none_pkcs8(ctx);
return SOTER_FAIL;
err = soter_ec_gen_key(ctx->pkey_ctx);
if (err != SOTER_SUCCESS) {
goto free_pkey_ctx;
}
} else {
if (private_key != NULL) {
if (soter_ec_import_key(pkey, private_key, private_key_length) != SOTER_SUCCESS) {
soter_sign_cleanup_ecdsa_none_pkcs8(ctx);
return SOTER_FAIL;
err = soter_ec_import_key(pkey, private_key, private_key_length);
if (err != SOTER_SUCCESS) {
goto free_pkey_ctx;
}
}
if (public_key != NULL) {
if (soter_ec_import_key(pkey, public_key, public_key_length) != SOTER_SUCCESS) {
soter_sign_cleanup_ecdsa_none_pkcs8(ctx);
return SOTER_FAIL;
err = soter_ec_import_key(pkey, public_key, public_key_length);
if (err != SOTER_SUCCESS) {
goto free_pkey_ctx;
}
}
}

/*md_ctx init*/
ctx->md_ctx = EVP_MD_CTX_create();
if (!(ctx->md_ctx)) {
soter_sign_cleanup_ecdsa_none_pkcs8(ctx);
return SOTER_NO_MEMORY;
err = SOTER_NO_MEMORY;
goto free_pkey_ctx;
}

if (EVP_DigestSignInit(ctx->md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1) {
soter_sign_cleanup_ecdsa_none_pkcs8(ctx);
return SOTER_FAIL;
goto free_md_ctx;
}

EVP_PKEY_free(pkey);
return SOTER_SUCCESS;

free_md_ctx:
EVP_MD_CTX_destroy(ctx->md_ctx);
ctx->md_ctx = NULL;
free_pkey_ctx:
EVP_PKEY_CTX_free(ctx->pkey_ctx);
ctx->pkey_ctx = NULL;
free_pkey:
EVP_PKEY_free(pkey);
return err;
}

soter_status_t soter_sign_export_key_ecdsa_none_pkcs8(soter_sign_ctx_t* ctx,
Expand Down Expand Up @@ -129,10 +143,6 @@ soter_status_t soter_sign_cleanup_ecdsa_none_pkcs8(soter_sign_ctx_t* ctx)
ctx->md_ctx = NULL;
}
if (ctx->pkey_ctx) {
EVP_PKEY* pkey = EVP_PKEY_CTX_get0_pkey(ctx->pkey_ctx);
if (pkey) {
EVP_PKEY_free(pkey);
}
EVP_PKEY_CTX_free(ctx->pkey_ctx);
ctx->pkey_ctx = NULL;
}
Expand Down
67 changes: 38 additions & 29 deletions src/soter/boringssl/soter_sign_rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,61 +29,74 @@ soter_status_t soter_sign_init_rsa_pss_pkcs8(soter_sign_ctx_t* ctx,
const void* public_key,
const size_t public_key_length)
{
/* pkey_ctx init */
EVP_PKEY* pkey;
soter_status_t err = SOTER_FAIL;
EVP_PKEY* pkey = NULL;
EVP_PKEY_CTX* md_pkey_ctx = NULL;

pkey = EVP_PKEY_new();
if (!pkey) {
return SOTER_NO_MEMORY;
}

if (!EVP_PKEY_set_type(pkey, EVP_PKEY_RSA)) {
EVP_PKEY_free(pkey);
return SOTER_FAIL;
goto free_pkey;
}

ctx->pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL);
ilammy marked this conversation as resolved.
Show resolved Hide resolved
if (!(ctx->pkey_ctx)) {
EVP_PKEY_free(pkey);
return SOTER_FAIL;
err = SOTER_NO_MEMORY;
goto free_pkey;
}

if ((!private_key) && (!public_key)) {
if (soter_rsa_gen_key(ctx->pkey_ctx, RSA_KEY_LENGTH_2048) != SOTER_SUCCESS) {
soter_sign_cleanup_rsa_pss_pkcs8(ctx);
return SOTER_FAIL;
err = soter_rsa_gen_key(ctx->pkey_ctx, RSA_KEY_LENGTH_2048);
if (err != SOTER_SUCCESS) {
goto free_pkey_ctx;
}
} else {
if (private_key != NULL) {
if (soter_rsa_import_key(pkey, private_key, private_key_length) != SOTER_SUCCESS) {
soter_sign_cleanup_rsa_pss_pkcs8(ctx);
return SOTER_FAIL;
err = soter_rsa_import_key(pkey, private_key, private_key_length);
if (err != SOTER_SUCCESS) {
goto free_pkey_ctx;
}
}
if (public_key != NULL) {
if (soter_rsa_import_key(pkey, public_key, public_key_length) != SOTER_SUCCESS) {
soter_sign_cleanup_rsa_pss_pkcs8(ctx);
return SOTER_FAIL;
err = soter_rsa_import_key(pkey, public_key, public_key_length);
if (err != SOTER_SUCCESS) {
goto free_pkey_ctx;
}
}
}

/*md_ctx init*/
ctx->md_ctx = EVP_MD_CTX_create();
if (!(ctx->md_ctx)) {
soter_sign_cleanup_rsa_pss_pkcs8(ctx);
return SOTER_NO_MEMORY;
err = SOTER_NO_MEMORY;
goto free_pkey_ctx;
}
EVP_PKEY_CTX* md_pkey_ctx = NULL;

/* md_pkey_ctx is owned by ctx->md_ctx */
if (!EVP_DigestSignInit(ctx->md_ctx, &md_pkey_ctx, EVP_sha256(), NULL, pkey)) {
soter_sign_cleanup_rsa_pss_pkcs8(ctx);
return SOTER_FAIL;
goto free_md_ctx;
}
if (!EVP_PKEY_CTX_set_rsa_padding(md_pkey_ctx, RSA_PKCS1_PSS_PADDING)) {
soter_sign_cleanup_rsa_pss_pkcs8(ctx);
return SOTER_FAIL;
goto free_md_ctx;
}
if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(md_pkey_ctx, -2)) {
soter_sign_cleanup_rsa_pss_pkcs8(ctx);
return SOTER_FAIL;
goto free_md_ctx;
}

EVP_PKEY_free(pkey);
return SOTER_SUCCESS;

free_md_ctx:
EVP_MD_CTX_destroy(ctx->md_ctx);
ctx->md_ctx = NULL;
free_pkey_ctx:
EVP_PKEY_CTX_free(ctx->pkey_ctx);
ctx->pkey_ctx = NULL;
free_pkey:
EVP_PKEY_free(pkey);
return err;
}

soter_status_t soter_sign_export_key_rsa_pss_pkcs8(soter_sign_ctx_t* ctx,
Expand Down Expand Up @@ -126,12 +139,8 @@ soter_status_t soter_sign_cleanup_rsa_pss_pkcs8(soter_sign_ctx_t* ctx)
return SOTER_INVALID_PARAMETER;
}
if (ctx->pkey_ctx) {
EVP_PKEY* pkey = EVP_PKEY_CTX_get0_pkey(ctx->pkey_ctx);
EVP_PKEY_CTX_free(ctx->pkey_ctx);
ctx->pkey_ctx = NULL;
if (pkey) {
EVP_PKEY_free(pkey);
}
}
if (ctx->md_ctx) {
EVP_MD_CTX_destroy(ctx->md_ctx);
Expand Down
Loading