diff --git a/.github/workflows/test-nodejs.yaml b/.github/workflows/test-nodejs.yaml index 2b214e314..acc6ef0df 100644 --- a/.github/workflows/test-nodejs.yaml +++ b/.github/workflows/test-nodejs.yaml @@ -48,10 +48,19 @@ jobs: node-version: ${{ matrix.node-version }} - name: Check out code uses: actions/checkout@v2 + with: + submodules: true - name: Install Themis Core + env: + NODE_VERSION: ${{ matrix.node-version }} run: | + # Workaround for Node.js 8.x using OpenSSL 1.0.2 when Themis is built against OpenSSL 1.1 + # https://github.com/cossacklabs/themis/issues/657 + if [[ "$NODE_VERSION" = "8.x" ]]; then + export ENGINE=boringssl + fi make - sudo make install + sudo -E make install - name: Run test suite run: | echo Node.js: $(node --version) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8e6f4421..b2acb4bdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,7 @@ _Code:_ - Fixed cross-compilation on macOS by setting `ARCH` and `SDK` variables ([#849](https://github.com/cossacklabs/themis/pull/849)). - Updated embedded BoringSSL to the latest version ([#812](https://github.com/cossacklabs/themis/pull/812)). - Builds with OpenSSL 3.0 will result in a compilation error for the time being ([#872](https://github.com/cossacklabs/themis/pull/872)). + - Hardened EC/RSA key generation and Secure Message sign/verify code paths ([#875](https://github.com/cossacklabs/themis/pull/875)). - **Android** diff --git a/src/soter/openssl/soter_ecdsa_common.c b/src/soter/openssl/soter_ecdsa_common.c index 8ea2b3969..31061c70b 100644 --- a/src/soter/openssl/soter_ecdsa_common.c +++ b/src/soter/openssl/soter_ecdsa_common.c @@ -22,28 +22,59 @@ #include "soter/openssl/soter_engine.h" #include "soter/soter_ec_key.h" -soter_status_t soter_ec_gen_key(EVP_PKEY_CTX* pkey_ctx) +soter_status_t soter_ec_gen_key(EVP_PKEY** ppkey) { - EVP_PKEY* pkey; - EC_KEY* ec; - if (!pkey_ctx) { + soter_status_t res = SOTER_FAIL; + EVP_PKEY* param = NULL; + EVP_PKEY_CTX* param_ctx = NULL; + EVP_PKEY_CTX* pkey_ctx = NULL; + + if (!ppkey) { return SOTER_INVALID_PARAMETER; } - pkey = EVP_PKEY_CTX_get0_pkey(pkey_ctx); - if (!pkey) { - return SOTER_INVALID_PARAMETER; + + param_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + if (!param_ctx) { + res = SOTER_NO_MEMORY; + goto err; } - if (EVP_PKEY_EC != EVP_PKEY_id(pkey)) { - return SOTER_INVALID_PARAMETER; + + if (EVP_PKEY_paramgen_init(param_ctx) != 1) { + res = SOTER_FAIL; + goto err; } - ec = EVP_PKEY_get0(pkey); - if (NULL == ec) { - return SOTER_INVALID_PARAMETER; + if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(param_ctx, NID_X9_62_prime256v1) != 1) { + res = SOTER_FAIL; + goto err; } - if (1 == EC_KEY_generate_key(ec)) { - return SOTER_SUCCESS; + if (EVP_PKEY_paramgen(param_ctx, ¶m) != 1) { + res = SOTER_FAIL; + goto err; } - return SOTER_FAIL; + + pkey_ctx = EVP_PKEY_CTX_new(param, NULL); + if (!pkey_ctx) { + res = SOTER_NO_MEMORY; + goto err; + } + + if (EVP_PKEY_keygen_init(pkey_ctx) != 1) { + res = SOTER_FAIL; + goto err; + } + if (EVP_PKEY_keygen(pkey_ctx, ppkey) != 1) { + res = SOTER_FAIL; + goto err; + } + + res = SOTER_SUCCESS; + +err: + EVP_PKEY_CTX_free(param_ctx); + EVP_PKEY_CTX_free(pkey_ctx); + EVP_PKEY_free(param); + + return res; } soter_status_t soter_ec_import_key(EVP_PKEY* pkey, const void* key, const size_t key_length) @@ -71,9 +102,8 @@ soter_status_t soter_ec_import_key(EVP_PKEY* pkey, const void* key, const size_t return SOTER_INVALID_PARAMETER; } -soter_status_t soter_ec_export_key(soter_sign_ctx_t* ctx, void* key, size_t* key_length, bool isprivate) +soter_status_t soter_ec_export_key(EVP_PKEY* pkey, void* key, size_t* key_length, bool isprivate) { - EVP_PKEY* pkey = EVP_PKEY_CTX_get0_pkey(ctx->pkey_ctx); if (!pkey) { return SOTER_INVALID_PARAMETER; } diff --git a/src/soter/openssl/soter_ecdsa_common.h b/src/soter/openssl/soter_ecdsa_common.h index 77c4095e1..5dc8591e1 100644 --- a/src/soter/openssl/soter_ecdsa_common.h +++ b/src/soter/openssl/soter_ecdsa_common.h @@ -21,8 +21,8 @@ #include "soter/soter_ec_key.h" #include "soter/soter_error.h" -soter_status_t soter_ec_gen_key(EVP_PKEY_CTX* pkey_ctx); +soter_status_t soter_ec_gen_key(EVP_PKEY** ppkey); soter_status_t soter_ec_import_key(EVP_PKEY* pkey, const void* key, size_t key_length); -soter_status_t soter_ec_export_key(soter_sign_ctx_t* ctx, void* key, size_t* key_length, bool isprivate); +soter_status_t soter_ec_export_key(EVP_PKEY* pkey, void* key, size_t* key_length, bool isprivate); #endif /* SOTER_OPENSSL_ECDSA_COMMON_H */ diff --git a/src/soter/openssl/soter_engine.h b/src/soter/openssl/soter_engine.h index ecb961034..c2b308c8c 100644 --- a/src/soter/openssl/soter_engine.h +++ b/src/soter/openssl/soter_engine.h @@ -54,7 +54,7 @@ struct soter_asym_ka_type { }; struct soter_sign_ctx_type { - EVP_PKEY_CTX* pkey_ctx; + EVP_PKEY* pkey; EVP_MD_CTX* md_ctx; soter_sign_alg_t alg; }; diff --git a/src/soter/openssl/soter_rsa_common.c b/src/soter/openssl/soter_rsa_common.c index b92576315..9eb760ae4 100644 --- a/src/soter/openssl/soter_rsa_common.c +++ b/src/soter/openssl/soter_rsa_common.c @@ -24,51 +24,66 @@ #define SOTER_RSA_KEY_LENGTH 2048 #endif -soter_status_t soter_rsa_gen_key(EVP_PKEY_CTX* pkey_ctx) +soter_status_t soter_rsa_gen_key(EVP_PKEY** ppkey) { - /* it is copy-paste from /src/soter/openssl/soter_asym_cipher.c */ - BIGNUM* pub_exp; - EVP_PKEY* pkey = EVP_PKEY_CTX_get0_pkey(pkey_ctx); - if (!pkey) { + soter_status_t res = SOTER_FAIL; + BIGNUM* pub_exp = NULL; + EVP_PKEY_CTX* pkey_ctx = NULL; + + if (!ppkey) { return SOTER_INVALID_PARAMETER; } - if (EVP_PKEY_RSA != EVP_PKEY_id(pkey)) { - return SOTER_INVALID_PARAMETER; + pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + if (!pkey_ctx) { + res = SOTER_NO_MEMORY; + goto err; } - if (!EVP_PKEY_keygen_init(pkey_ctx)) { - return SOTER_INVALID_PARAMETER; + if (EVP_PKEY_keygen_init(pkey_ctx) != 1) { + res = SOTER_INVALID_PARAMETER; + goto err; } /* Although it seems that OpenSSL/LibreSSL use 0x10001 as default public exponent, we will set * it explicitly just in case */ pub_exp = BN_new(); if (!pub_exp) { - return SOTER_NO_MEMORY; + res = SOTER_NO_MEMORY; + goto err; } if (!BN_set_word(pub_exp, RSA_F4)) { - BN_free(pub_exp); - return SOTER_FAIL; + res = SOTER_FAIL; + goto err; } + /* Passing ownership over pub_exp to EVP_PKEY_CTX */ if (1 > EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, pub_exp)) { - BN_free(pub_exp); - return SOTER_FAIL; + res = SOTER_FAIL; + goto err; } + pub_exp = NULL; /* Override default key size for RSA key. Currently OpenSSL has default key size of 1024. * LibreSSL has 2048. We will put 2048 explicitly */ if (1 > EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_RSA_KEYGEN_BITS, SOTER_RSA_KEY_LENGTH, NULL)) { - return SOTER_FAIL; + res = SOTER_FAIL; + goto err; } - if (!EVP_PKEY_keygen(pkey_ctx, &pkey)) { - return SOTER_FAIL; + if (EVP_PKEY_keygen(pkey_ctx, ppkey) != 1) { + res = SOTER_FAIL; + goto err; } - return SOTER_SUCCESS; - /* end of copy-paste from /src/soter/openssl/soter_asym_cipher.c*/ + + res = SOTER_SUCCESS; + +err: + BN_free(pub_exp); + EVP_PKEY_CTX_free(pkey_ctx); + + return res; } soter_status_t soter_rsa_import_key(EVP_PKEY* pkey, const void* key, const size_t key_length) @@ -94,10 +109,8 @@ soter_status_t soter_rsa_import_key(EVP_PKEY* pkey, const void* key, const size_ return SOTER_INVALID_PARAMETER; } -soter_status_t soter_rsa_export_key(soter_sign_ctx_t* ctx, void* key, size_t* key_length, bool isprivate) +soter_status_t soter_rsa_export_key(EVP_PKEY* pkey, void* key, size_t* key_length, bool isprivate) { - EVP_PKEY* pkey = EVP_PKEY_CTX_get0_pkey(ctx->pkey_ctx); - if (!pkey) { return SOTER_INVALID_PARAMETER; } diff --git a/src/soter/openssl/soter_rsa_common.h b/src/soter/openssl/soter_rsa_common.h index 1776027b8..dbb24ad5a 100644 --- a/src/soter/openssl/soter_rsa_common.h +++ b/src/soter/openssl/soter_rsa_common.h @@ -21,8 +21,8 @@ #include "soter/soter_error.h" #include "soter/soter_rsa_key.h" -soter_status_t soter_rsa_gen_key(EVP_PKEY_CTX* pkey_ctx); +soter_status_t soter_rsa_gen_key(EVP_PKEY** ppkey); soter_status_t soter_rsa_import_key(EVP_PKEY* pkey, const void* key, size_t key_length); -soter_status_t soter_rsa_export_key(soter_sign_ctx_t* ctx, void* key, size_t* key_length, bool isprivate); +soter_status_t soter_rsa_export_key(EVP_PKEY* pkey, void* key, size_t* key_length, bool isprivate); #endif /* SOTER_OPENSSL_RSA_COMMON_H */ diff --git a/src/soter/openssl/soter_sign_ecdsa.c b/src/soter/openssl/soter_sign_ecdsa.c index d80459c3e..e47b5ea9f 100644 --- a/src/soter/openssl/soter_sign_ecdsa.c +++ b/src/soter/openssl/soter_sign_ecdsa.c @@ -31,49 +31,39 @@ soter_status_t soter_sign_init_ecdsa_none_pkcs8(soter_sign_ctx_t* ctx, const size_t public_key_length) { 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)) { - goto free_pkey; - } - - ctx->pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL); - if (!(ctx->pkey_ctx)) { - err = SOTER_NO_MEMORY; - goto free_pkey; - } - - if (!EVP_PKEY_paramgen_init(ctx->pkey_ctx)) { - goto free_pkey_ctx; - } - if (!EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx->pkey_ctx, NID_X9_62_prime256v1)) { - goto free_pkey_ctx; - } - if (!EVP_PKEY_paramgen(ctx->pkey_ctx, &pkey)) { - goto free_pkey_ctx; + /* soter_sign_ctx_t should be initialized only once */ + if (!ctx || ctx->pkey || ctx->md_ctx) { + return SOTER_INVALID_PARAMETER; } if ((!private_key) && (!public_key)) { - err = soter_ec_gen_key(ctx->pkey_ctx); + err = soter_ec_gen_key(&ctx->pkey); if (err != SOTER_SUCCESS) { - goto free_pkey_ctx; + goto free_pkey; } } else { + ctx->pkey = EVP_PKEY_new(); + if (!ctx->pkey) { + err = SOTER_NO_MEMORY; + goto free_pkey; + } + + if (!EVP_PKEY_set_type(ctx->pkey, EVP_PKEY_EC)) { + err = SOTER_FAIL; + goto free_pkey; + } + if (private_key != NULL) { - err = soter_ec_import_key(pkey, private_key, private_key_length); + err = soter_ec_import_key(ctx->pkey, private_key, private_key_length); if (err != SOTER_SUCCESS) { - goto free_pkey_ctx; + goto free_pkey; } } if (public_key != NULL) { - err = soter_ec_import_key(pkey, public_key, public_key_length); + err = soter_ec_import_key(ctx->pkey, public_key, public_key_length); if (err != SOTER_SUCCESS) { - goto free_pkey_ctx; + goto free_pkey; } } } @@ -81,24 +71,21 @@ soter_status_t soter_sign_init_ecdsa_none_pkcs8(soter_sign_ctx_t* ctx, ctx->md_ctx = EVP_MD_CTX_create(); if (!(ctx->md_ctx)) { err = SOTER_NO_MEMORY; - goto free_pkey_ctx; + goto free_pkey; } - if (EVP_DigestSignInit(ctx->md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1) { + if (EVP_DigestSignInit(ctx->md_ctx, NULL, EVP_sha256(), NULL, ctx->pkey) != 1) { 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); + EVP_PKEY_free(ctx->pkey); + ctx->pkey = NULL; return err; } @@ -107,13 +94,28 @@ soter_status_t soter_sign_export_key_ecdsa_none_pkcs8(soter_sign_ctx_t* ctx, size_t* key_length, bool isprivate) { - return soter_ec_export_key(ctx, key, key_length, isprivate); + if (!ctx || !ctx->pkey) { + return SOTER_INVALID_PARAMETER; + } + if (EVP_PKEY_base_id(ctx->pkey) != EVP_PKEY_EC) { + return SOTER_INVALID_PARAMETER; + } + return soter_ec_export_key(ctx->pkey, key, key_length, isprivate); } soter_status_t soter_sign_update_ecdsa_none_pkcs8(soter_sign_ctx_t* ctx, const void* data, const size_t data_length) { + if (!ctx || !ctx->pkey) { + return SOTER_INVALID_PARAMETER; + } + if (!data || data_length == 0) { + return SOTER_INVALID_PARAMETER; + } + if (EVP_PKEY_base_id(ctx->pkey) != EVP_PKEY_EC) { + return SOTER_INVALID_PARAMETER; + } if (EVP_DigestSignUpdate(ctx->md_ctx, data, data_length) != 1) { return SOTER_FAIL; } @@ -124,23 +126,31 @@ soter_status_t soter_sign_final_ecdsa_none_pkcs8(soter_sign_ctx_t* ctx, void* signature, size_t* signature_length) { - EVP_PKEY* pkey = EVP_PKEY_CTX_get0_pkey(ctx->pkey_ctx); - if (!pkey) { + int key_size = 0; + + if (!ctx || !ctx->pkey) { return SOTER_INVALID_PARAMETER; } - if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { + if (!signature_length) { return SOTER_INVALID_PARAMETER; - } /* TODO: need review */ - soter_status_t res = SOTER_SUCCESS; - if (!signature || (*signature_length) < (size_t)EVP_PKEY_size(pkey)) { - (*signature_length) = (size_t)EVP_PKEY_size(pkey); - res = SOTER_BUFFER_TOO_SMALL; - } else { - if (EVP_DigestSignFinal(ctx->md_ctx, signature, signature_length) != 1) { - res = SOTER_INVALID_SIGNATURE; - } } - return res; + if (EVP_PKEY_base_id(ctx->pkey) != EVP_PKEY_EC) { + return SOTER_INVALID_PARAMETER; + } + + key_size = EVP_PKEY_size(ctx->pkey); + if (key_size <= 0) { + return SOTER_FAIL; + } + if (!signature || (*signature_length) < (size_t)key_size) { + (*signature_length) = (size_t)key_size; + return SOTER_BUFFER_TOO_SMALL; + } + + if (EVP_DigestSignFinal(ctx->md_ctx, signature, signature_length) != 1) { + return SOTER_INVALID_SIGNATURE; + } + return SOTER_SUCCESS; } soter_status_t soter_sign_cleanup_ecdsa_none_pkcs8(soter_sign_ctx_t* ctx) @@ -148,13 +158,13 @@ soter_status_t soter_sign_cleanup_ecdsa_none_pkcs8(soter_sign_ctx_t* ctx) if (!ctx) { return SOTER_INVALID_PARAMETER; } + if (ctx->pkey) { + EVP_PKEY_free(ctx->pkey); + ctx->pkey = NULL; + } if (ctx->md_ctx) { EVP_MD_CTX_destroy(ctx->md_ctx); ctx->md_ctx = NULL; } - if (ctx->pkey_ctx) { - EVP_PKEY_CTX_free(ctx->pkey_ctx); - ctx->pkey_ctx = NULL; - } return SOTER_SUCCESS; } diff --git a/src/soter/openssl/soter_sign_rsa.c b/src/soter/openssl/soter_sign_rsa.c index c4e8b0ed7..a1bdb72c9 100644 --- a/src/soter/openssl/soter_sign_rsa.c +++ b/src/soter/openssl/soter_sign_rsa.c @@ -30,40 +30,40 @@ soter_status_t soter_sign_init_rsa_pss_pkcs8(soter_sign_ctx_t* ctx, const size_t public_key_length) { 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)) { - goto free_pkey; - } - - ctx->pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL); - if (!(ctx->pkey_ctx)) { - err = SOTER_NO_MEMORY; - goto free_pkey; + /* soter_sign_ctx_t should be initialized only once */ + if (!ctx || ctx->pkey || ctx->md_ctx) { + return SOTER_INVALID_PARAMETER; } if ((!private_key) && (!public_key)) { - err = soter_rsa_gen_key(ctx->pkey_ctx); + err = soter_rsa_gen_key(&ctx->pkey); if (err != SOTER_SUCCESS) { - goto free_pkey_ctx; + goto free_pkey; } } else { + ctx->pkey = EVP_PKEY_new(); + if (!ctx->pkey) { + err = SOTER_NO_MEMORY; + goto free_pkey; + } + + if (EVP_PKEY_set_type(ctx->pkey, EVP_PKEY_RSA) != 1) { + err = SOTER_FAIL; + goto free_pkey; + } + if (private_key != NULL) { - err = soter_rsa_import_key(pkey, private_key, private_key_length); + err = soter_rsa_import_key(ctx->pkey, private_key, private_key_length); if (err != SOTER_SUCCESS) { - goto free_pkey_ctx; + goto free_pkey; } } if (public_key != NULL) { - err = soter_rsa_import_key(pkey, public_key, public_key_length); + err = soter_rsa_import_key(ctx->pkey, public_key, public_key_length); if (err != SOTER_SUCCESS) { - goto free_pkey_ctx; + goto free_pkey; } } } @@ -71,31 +71,28 @@ soter_status_t soter_sign_init_rsa_pss_pkcs8(soter_sign_ctx_t* ctx, ctx->md_ctx = EVP_MD_CTX_create(); if (!(ctx->md_ctx)) { err = SOTER_NO_MEMORY; - goto free_pkey_ctx; + goto free_pkey; } /* md_pkey_ctx is owned by ctx->md_ctx */ - if (!EVP_DigestSignInit(ctx->md_ctx, &md_pkey_ctx, EVP_sha256(), NULL, pkey)) { + if (EVP_DigestSignInit(ctx->md_ctx, &md_pkey_ctx, EVP_sha256(), NULL, ctx->pkey) != 1) { goto free_md_ctx; } - if (!EVP_PKEY_CTX_set_rsa_padding(md_pkey_ctx, RSA_PKCS1_PSS_PADDING)) { + if (EVP_PKEY_CTX_set_rsa_padding(md_pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1) { goto free_md_ctx; } - if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(md_pkey_ctx, -2)) { + if (EVP_PKEY_CTX_set_rsa_pss_saltlen(md_pkey_ctx, -2) != 1) { 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); + EVP_PKEY_free(ctx->pkey); + ctx->pkey = NULL; return err; } @@ -104,14 +101,30 @@ soter_status_t soter_sign_export_key_rsa_pss_pkcs8(soter_sign_ctx_t* ctx, size_t* key_length, bool isprivate) { - return soter_rsa_export_key(ctx, key, key_length, isprivate); + if (!ctx) { + return SOTER_INVALID_PARAMETER; + } + if (EVP_PKEY_base_id(ctx->pkey) != EVP_PKEY_RSA) { + return SOTER_INVALID_PARAMETER; + } + return soter_rsa_export_key(ctx->pkey, key, key_length, isprivate); } soter_status_t soter_sign_update_rsa_pss_pkcs8(soter_sign_ctx_t* ctx, const void* data, const size_t data_length) { - if (!EVP_DigestSignUpdate(ctx->md_ctx, data, data_length)) { + if (!ctx || !ctx->pkey) { + return SOTER_INVALID_PARAMETER; + } + if (!data || data_length == 0) { + return SOTER_INVALID_PARAMETER; + } + if (EVP_PKEY_base_id(ctx->pkey) != EVP_PKEY_RSA) { + return SOTER_INVALID_PARAMETER; + } + + if (EVP_DigestSignUpdate(ctx->md_ctx, data, data_length) != 1) { return SOTER_FAIL; } return SOTER_SUCCESS; @@ -119,19 +132,28 @@ soter_status_t soter_sign_update_rsa_pss_pkcs8(soter_sign_ctx_t* ctx, soter_status_t soter_sign_final_rsa_pss_pkcs8(soter_sign_ctx_t* ctx, void* signature, size_t* signature_length) { - EVP_PKEY* pkey = EVP_PKEY_CTX_get0_pkey(ctx->pkey_ctx); - if (!pkey) { + int key_size = 0; + + if (!ctx || !ctx->pkey) { + return SOTER_INVALID_PARAMETER; + } + if (!signature_length) { return SOTER_INVALID_PARAMETER; } - int key_size = EVP_PKEY_size(pkey); - if (key_size < 0) { + if (EVP_PKEY_base_id(ctx->pkey) != EVP_PKEY_RSA) { + return SOTER_INVALID_PARAMETER; + } + + key_size = EVP_PKEY_size(ctx->pkey); + if (key_size <= 0) { return SOTER_FAIL; } - if ((*signature_length) < (size_t)key_size) { + if (!signature || (*signature_length) < (size_t)key_size) { (*signature_length) = (size_t)key_size; return SOTER_BUFFER_TOO_SMALL; } - if (!EVP_DigestSignFinal(ctx->md_ctx, signature, signature_length)) { + + if (EVP_DigestSignFinal(ctx->md_ctx, signature, signature_length) != 1) { return SOTER_FAIL; } return SOTER_SUCCESS; @@ -142,9 +164,9 @@ soter_status_t soter_sign_cleanup_rsa_pss_pkcs8(soter_sign_ctx_t* ctx) if (!ctx) { return SOTER_INVALID_PARAMETER; } - if (ctx->pkey_ctx) { - EVP_PKEY_CTX_free(ctx->pkey_ctx); - ctx->pkey_ctx = NULL; + if (ctx->pkey) { + EVP_PKEY_free(ctx->pkey); + ctx->pkey = NULL; } if (ctx->md_ctx) { EVP_MD_CTX_destroy(ctx->md_ctx); diff --git a/src/soter/openssl/soter_verify_ecdsa.c b/src/soter/openssl/soter_verify_ecdsa.c index e7f58af11..571d9af77 100644 --- a/src/soter/openssl/soter_verify_ecdsa.c +++ b/src/soter/openssl/soter_verify_ecdsa.c @@ -30,58 +30,53 @@ soter_status_t soter_verify_init_ecdsa_none_pkcs8(soter_sign_ctx_t* ctx, const size_t public_key_length) { soter_status_t err = SOTER_FAIL; - EVP_PKEY* pkey = NULL; - pkey = EVP_PKEY_new(); - if (!pkey) { - return SOTER_NO_MEMORY; + /* soter_sign_ctx_t should be initialized only once */ + if (!ctx || ctx->pkey || ctx->md_ctx) { + return SOTER_INVALID_PARAMETER; } - if (!EVP_PKEY_set_type(pkey, EVP_PKEY_EC)) { - goto free_pkey; + ctx->pkey = EVP_PKEY_new(); + if (!ctx->pkey) { + return SOTER_NO_MEMORY; } - ctx->pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL); - if (!(ctx->pkey_ctx)) { - err = SOTER_NO_MEMORY; + if (EVP_PKEY_set_type(ctx->pkey, EVP_PKEY_EC) != 1) { goto free_pkey; } /* TODO: Review needed */ if ((private_key) && (private_key_length)) { - err = soter_ec_import_key(pkey, private_key, private_key_length); + err = soter_ec_import_key(ctx->pkey, private_key, private_key_length); if (err != SOTER_SUCCESS) { - goto free_pkey_ctx; + goto free_pkey; } } if ((public_key) && (public_key_length)) { - err = soter_ec_import_key(pkey, public_key, public_key_length); + err = soter_ec_import_key(ctx->pkey, public_key, public_key_length); if (err != SOTER_SUCCESS) { - goto free_pkey_ctx; + goto free_pkey; } } ctx->md_ctx = EVP_MD_CTX_create(); if (!(ctx->md_ctx)) { err = SOTER_NO_MEMORY; - goto free_pkey_ctx; + goto free_pkey; } - if (!EVP_DigestVerifyInit(ctx->md_ctx, NULL, EVP_sha256(), NULL, pkey)) { + if (EVP_DigestVerifyInit(ctx->md_ctx, NULL, EVP_sha256(), NULL, ctx->pkey) != 1) { 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); + EVP_PKEY_free(ctx->pkey); + ctx->pkey = NULL; return err; } @@ -89,7 +84,17 @@ soter_status_t soter_verify_update_ecdsa_none_pkcs8(soter_sign_ctx_t* ctx, const void* data, const size_t data_length) { - if (!EVP_DigestVerifyUpdate(ctx->md_ctx, data, data_length)) { + if (!ctx || !ctx->pkey) { + return SOTER_INVALID_PARAMETER; + } + if (!data || data_length == 0) { + return SOTER_INVALID_PARAMETER; + } + if (EVP_PKEY_base_id(ctx->pkey) != EVP_PKEY_EC) { + return SOTER_INVALID_PARAMETER; + } + + if (EVP_DigestVerifyUpdate(ctx->md_ctx, data, data_length) != 1) { return SOTER_FAIL; } return SOTER_SUCCESS; @@ -100,23 +105,21 @@ soter_status_t soter_verify_final_ecdsa_none_pkcs8(soter_sign_ctx_t* ctx, const void* signature, const size_t signature_length) { - if (!ctx) { + if (!ctx || !ctx->pkey) { + return SOTER_INVALID_PARAMETER; + } + if (!signature || signature_length == 0) { return SOTER_INVALID_PARAMETER; } - EVP_PKEY* pkey = EVP_PKEY_CTX_get0_pkey(ctx->pkey_ctx); - if (!pkey) { + if (EVP_PKEY_base_id(ctx->pkey) != EVP_PKEY_EC) { return SOTER_INVALID_PARAMETER; } - int res = EVP_DigestVerifyFinal(ctx->md_ctx, (unsigned char*)signature, signature_length); - switch (res) { - case 0: - return SOTER_INVALID_SIGNATURE; - case 1: - return SOTER_SUCCESS; - default: + if (EVP_DigestVerifyFinal(ctx->md_ctx, (unsigned char*)signature, signature_length) != 1) { return SOTER_INVALID_SIGNATURE; } + + return SOTER_SUCCESS; } soter_status_t soter_verify_cleanup_ecdsa_none_pkcs8(soter_sign_ctx_t* ctx) @@ -124,13 +127,13 @@ soter_status_t soter_verify_cleanup_ecdsa_none_pkcs8(soter_sign_ctx_t* ctx) if (!ctx) { return SOTER_INVALID_PARAMETER; } + if (ctx->pkey) { + EVP_PKEY_free(ctx->pkey); + ctx->pkey = NULL; + } if (ctx->md_ctx) { EVP_MD_CTX_destroy(ctx->md_ctx); ctx->md_ctx = NULL; } - if (ctx->pkey_ctx) { - EVP_PKEY_CTX_free(ctx->pkey_ctx); - ctx->pkey_ctx = NULL; - } return SOTER_SUCCESS; } diff --git a/src/soter/openssl/soter_verify_rsa.c b/src/soter/openssl/soter_verify_rsa.c index cd5a70e8b..bef7049cc 100644 --- a/src/soter/openssl/soter_verify_rsa.c +++ b/src/soter/openssl/soter_verify_rsa.c @@ -30,65 +30,60 @@ soter_status_t soter_verify_init_rsa_pss_pkcs8(soter_sign_ctx_t* ctx, const size_t public_key_length) { 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; + /* soter_sign_ctx_t should be initialized only once */ + if (!ctx || ctx->pkey || ctx->md_ctx) { + return SOTER_INVALID_PARAMETER; } - if (!EVP_PKEY_set_type(pkey, EVP_PKEY_RSA)) { - goto free_pkey; + ctx->pkey = EVP_PKEY_new(); + if (!ctx->pkey) { + return SOTER_NO_MEMORY; } - ctx->pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL); - if (!(ctx->pkey_ctx)) { - err = SOTER_NO_MEMORY; + if (!EVP_PKEY_set_type(ctx->pkey, EVP_PKEY_RSA)) { goto free_pkey; } if (private_key && private_key_length != 0) { - err = soter_rsa_import_key(pkey, private_key, private_key_length); + err = soter_rsa_import_key(ctx->pkey, private_key, private_key_length); if (err != SOTER_SUCCESS) { - goto free_pkey_ctx; + goto free_pkey; } } if (public_key && public_key_length != 0) { - err = soter_rsa_import_key(pkey, public_key, public_key_length); + err = soter_rsa_import_key(ctx->pkey, public_key, public_key_length); if (err != SOTER_SUCCESS) { - goto free_pkey_ctx; + goto free_pkey; } } ctx->md_ctx = EVP_MD_CTX_create(); if (!(ctx->md_ctx)) { err = SOTER_NO_MEMORY; - goto free_pkey_ctx; + goto free_pkey; } /* md_pkey_ctx is owned by ctx->md_ctx */ - if (!EVP_DigestVerifyInit(ctx->md_ctx, &md_pkey_ctx, EVP_sha256(), NULL, pkey)) { + if (EVP_DigestVerifyInit(ctx->md_ctx, &md_pkey_ctx, EVP_sha256(), NULL, ctx->pkey) != 1) { goto free_md_ctx; } - if (!EVP_PKEY_CTX_set_rsa_padding(md_pkey_ctx, RSA_PKCS1_PSS_PADDING)) { + if (EVP_PKEY_CTX_set_rsa_padding(md_pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1) { goto free_md_ctx; } - if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(md_pkey_ctx, -2)) { + if (EVP_PKEY_CTX_set_rsa_pss_saltlen(md_pkey_ctx, -2) != 1) { 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); + EVP_PKEY_free(ctx->pkey); + ctx->pkey = NULL; return err; } @@ -96,7 +91,17 @@ soter_status_t soter_verify_update_rsa_pss_pkcs8(soter_sign_ctx_t* ctx, const void* data, const size_t data_length) { - if (!EVP_DigestVerifyUpdate(ctx->md_ctx, data, data_length)) { + if (!ctx || !ctx->pkey) { + return SOTER_INVALID_PARAMETER; + } + if (!data || data_length == 0) { + return SOTER_INVALID_PARAMETER; + } + if (EVP_PKEY_base_id(ctx->pkey) != EVP_PKEY_RSA) { + return SOTER_INVALID_PARAMETER; + } + + if (EVP_DigestVerifyUpdate(ctx->md_ctx, data, data_length) != 1) { return SOTER_FAIL; } return SOTER_SUCCESS; @@ -106,19 +111,23 @@ soter_status_t soter_verify_final_rsa_pss_pkcs8(soter_sign_ctx_t* ctx, const void* signature, const size_t signature_length) { - if (!ctx) { + if (!ctx || !ctx->pkey) { return SOTER_INVALID_PARAMETER; } - EVP_PKEY* pkey = EVP_PKEY_CTX_get0_pkey(ctx->pkey_ctx); - if (!pkey) { + if (!signature || signature_length == 0) { return SOTER_INVALID_PARAMETER; } - if (signature_length != (size_t)EVP_PKEY_size(pkey)) { + if (EVP_PKEY_base_id(ctx->pkey) != EVP_PKEY_RSA) { + return SOTER_INVALID_PARAMETER; + } + + if (signature_length != (size_t)EVP_PKEY_size(ctx->pkey)) { return SOTER_FAIL; } - if (!EVP_DigestVerifyFinal(ctx->md_ctx, (unsigned char*)signature, signature_length)) { + if (EVP_DigestVerifyFinal(ctx->md_ctx, (unsigned char*)signature, signature_length) != 1) { return SOTER_FAIL; } + return SOTER_SUCCESS; } @@ -127,9 +136,9 @@ soter_status_t soter_verify_cleanup_rsa_pss_pkcs8(soter_sign_ctx_t* ctx) if (!ctx) { return SOTER_INVALID_PARAMETER; } - if (ctx->pkey_ctx) { - EVP_PKEY_CTX_free(ctx->pkey_ctx); - ctx->pkey_ctx = NULL; + if (ctx->pkey) { + EVP_PKEY_free(ctx->pkey); + ctx->pkey = NULL; } if (ctx->md_ctx) { EVP_MD_CTX_destroy(ctx->md_ctx);