From 9972546b217b5cde83852250d041d47a4e068bd3 Mon Sep 17 00:00:00 2001 From: Nickolay Olshevsky Date: Fri, 15 Nov 2024 18:18:50 +0200 Subject: [PATCH] (WIP) Use OpenSSL wrappers for RSA code. --- src/lib/crypto/rsa_ossl.cpp | 504 ++++++++++++++++-------------------- 1 file changed, 222 insertions(+), 282 deletions(-) diff --git a/src/lib/crypto/rsa_ossl.cpp b/src/lib/crypto/rsa_ossl.cpp index e3c7dbdd8..c8a3a08d8 100644 --- a/src/lib/crypto/rsa_ossl.cpp +++ b/src/lib/crypto/rsa_ossl.cpp @@ -44,232 +44,213 @@ namespace pgp { namespace rsa { -#ifndef CRYPTO_BACKEND_OPENSSL3 -static RSA * +#if !defined(CRYPTO_BACKEND_OPENSSL3) +static rnp::ossl::evp::PKey load_public_key(const Key &key) { - rnp::bn n(key.n); - rnp::bn e(key.e); + rnp::bn n(key.n); + rnp::bn e(key.e); + rnp::ossl::RSA rsa; - if (!n.get() || !e.get()) { + if (!n || !e || !rsa.get()) { /* LCOV_EXCL_START */ RNP_LOG("out of memory"); return NULL; /* LCOV_EXCL_END */ } - RSA *rsa = RSA_new(); - if (!rsa) { + /* OpenSSL set0 function transfers ownership of bignums */ + if (RSA_set0_key(rsa.get(), n.own(), e.own(), NULL) != 1) { /* LCOV_EXCL_START */ - RNP_LOG("Out of memory"); + RNP_LOG("Public key load error: %lu", ERR_peek_last_error()); return NULL; /* LCOV_EXCL_END */ } - /* OpenSSL set0 function transfers ownership of bignums */ - if (RSA_set0_key(rsa, n.own(), e.own(), NULL) != 1) { + + rnp::ossl::evp::PKey evpkey(EVP_PKEY_new()); + if (!evpkey || (EVP_PKEY_set1_RSA(evpkey.get(), rsa.get()) <= 0)) { /* LCOV_EXCL_START */ - RNP_LOG("Public key load error: %lu", ERR_peek_last_error()); - RSA_free(rsa); + RNP_LOG("Failed to set key: %lu", ERR_peek_last_error()); return NULL; /* LCOV_EXCL_END */ } - return rsa; + return evpkey; } -static RSA * +static rnp::ossl::evp::PKey load_secret_key(const Key &key) { - rnp::bn n(key.n); - rnp::bn e(key.e); - rnp::bn p(key.p); - rnp::bn q(key.q); - rnp::bn d(key.d); - - if (!n.get() || !p.get() || !q.get() || !e.get() || !d.get()) { + rnp::bn n(key.n); + rnp::bn e(key.e); + rnp::bn p(key.p); + rnp::bn q(key.q); + rnp::bn d(key.d); + rnp::ossl::RSA rsa; + + if (!n || !p || !q || !e || !d || !rsa.get()) { /* LCOV_EXCL_START */ RNP_LOG("out of memory"); return NULL; /* LCOV_EXCL_END */ } - RSA *rsa = RSA_new(); - if (!rsa) { - /* LCOV_EXCL_START */ - RNP_LOG("Out of memory"); - return NULL; - /* LCOV_EXCL_END */ - } /* OpenSSL set0 function transfers ownership of bignums */ - if (RSA_set0_key(rsa, n.own(), e.own(), d.own()) != 1) { + if (RSA_set0_key(rsa.get(), n.own(), e.own(), d.own()) != 1) { /* LCOV_EXCL_START */ RNP_LOG("Secret key load error: %lu", ERR_peek_last_error()); - RSA_free(rsa); return NULL; /* LCOV_EXCL_END */ } /* OpenSSL has p < q, as we do */ - if (RSA_set0_factors(rsa, p.own(), q.own()) != 1) { + if (RSA_set0_factors(rsa.get(), p.own(), q.own()) != 1) { /* LCOV_EXCL_START */ RNP_LOG("Factors load error: %lu", ERR_peek_last_error()); - RSA_free(rsa); return NULL; /* LCOV_EXCL_END */ } - return rsa; -} -static EVP_PKEY_CTX * -init_context(const Key &key, bool secret) -{ - EVP_PKEY *evpkey = EVP_PKEY_new(); - if (!evpkey) { + rnp::ossl::evp::PKey evpkey(EVP_PKEY_new()); + if (!evpkey || (EVP_PKEY_set1_RSA(evpkey.get(), rsa.get()) <= 0)) { /* LCOV_EXCL_START */ - RNP_LOG("allocation failed"); + RNP_LOG("Failed to set key: %lu", ERR_peek_last_error()); return NULL; /* LCOV_EXCL_END */ } - EVP_PKEY_CTX *ctx = NULL; - RSA * rsakey = secret ? load_secret_key(key) : load_public_key(key); - if (!rsakey) { - goto done; - } - if (EVP_PKEY_set1_RSA(evpkey, rsakey) <= 0) { - /* LCOV_EXCL_START */ - RNP_LOG("Failed to set key: %lu", ERR_peek_last_error()); - goto done; - /* LCOV_EXCL_END */ + return evpkey; +} + +static rnp::ossl::evp::Ctx +init_context(const Key &key, bool secret) +{ + rnp::ossl::evp::PKey evpkey(secret ? load_secret_key(key) : load_public_key(key)); + if (!evpkey) { + return NULL; // LCOV_EXCL_LINE } - ctx = EVP_PKEY_CTX_new(evpkey, NULL); + rnp::ossl::evp::Ctx ctx(evpkey); if (!ctx) { RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error()); // LCOV_EXCL_LINE } -done: - RSA_free(rsakey); - EVP_PKEY_free(evpkey); return ctx; } #else static OSSL_PARAM * bld_params(const Key &key, bool secret) { - OSSL_PARAM * params = NULL; - OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new(); - rnp::bn n(key.n); - rnp::bn e(key.e); - rnp::bn d; - rnp::bn p; - rnp::bn q; - rnp::bn u; - BN_CTX * bnctx = NULL; - - if (!n.get() || !e.get() || !bld) { + rnp::ossl::ParamBld bld; + rnp::bn n(key.n); + rnp::bn e(key.e); + + if (!n || !e || !bld) { /* LCOV_EXCL_START */ RNP_LOG("Out of memory"); - goto done; + return NULL; /* LCOV_EXCL_END */ } - if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, n.get()) || - !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, e.get())) { + if (!bld.push(OSSL_PKEY_PARAM_RSA_N, n) || !bld.push(OSSL_PKEY_PARAM_RSA_E, e)) { /* LCOV_EXCL_START */ RNP_LOG("Failed to push RSA params."); - OSSL_PARAM_BLD_free(bld); return NULL; /* LCOV_EXCL_END */ } - if (secret) { - d.set(key.d); - /* As we have u = p^-1 mod q, and qInv = q^-1 mod p, we need to replace one with - * another */ - p.set(key.q); - q.set(key.p); - u.set(key.u); - if (!d.get() || !p.get() || !q.get() || !u.get()) { - goto done; - } - /* We need to calculate exponents manually */ - bnctx = BN_CTX_new(); - if (!bnctx) { - /* LCOV_EXCL_START */ - RNP_LOG("Failed to allocate BN_CTX."); - goto done; - /* LCOV_EXCL_END */ - } - bignum_t *p1 = BN_CTX_get(bnctx); - bignum_t *q1 = BN_CTX_get(bnctx); - bignum_t *dp = BN_CTX_get(bnctx); - bignum_t *dq = BN_CTX_get(bnctx); - if (!BN_copy(p1, p.get()) || !BN_sub_word(p1, 1) || !BN_copy(q1, q.get()) || - !BN_sub_word(q1, 1) || !BN_mod(dp, d.get(), p1, bnctx) || - !BN_mod(dq, d.get(), q1, bnctx)) { - RNP_LOG("Failed to calculate dP or dQ."); // LCOV_EXCL_LINE - } - /* Push params */ - if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, d.get()) || - !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR1, p.get()) || - !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR2, q.get()) || - !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT1, dp) || - !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT2, dq) || - !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, u.get())) { - RNP_LOG("Failed to push RSA secret params."); // LCOV_EXCL_LINE - goto done; + + if (!secret) { + auto params = OSSL_PARAM_BLD_to_param(bld.get()); + if (!params) { + RNP_LOG("Failed to build RSA pub params: %s.", + ossl_latest_err()); // LCOV_EXCL_LINE } + return params; + } + + /* Add secret key fields */ + rnp::bn d(key.d); + /* As we have u = p^-1 mod q, and qInv = q^-1 mod p, we need to replace one with another */ + rnp::bn p(key.q); + rnp::bn q(key.p); + rnp::bn u(key.u); + + if (!d || !p || !q || !u) { + return NULL; } - params = OSSL_PARAM_BLD_to_param(bld); + /* We need to calculate exponents manually */ + rnp::ossl::BNCtx bnctx; + if (!bnctx.get()) { + /* LCOV_EXCL_START */ + RNP_LOG("Failed to allocate BN_CTX."); + return NULL; + /* LCOV_EXCL_END */ + } + auto p1 = bnctx.bn(); + auto q1 = bnctx.bn(); + auto dp = bnctx.bn(); + auto dq = bnctx.bn(); + if (!BN_copy(p1, p.get()) || !BN_sub_word(p1, 1) || !BN_copy(q1, q.get()) || + !BN_sub_word(q1, 1) || !BN_mod(dp, d.get(), p1, bnctx.get()) || + !BN_mod(dq, d.get(), q1, bnctx.get())) { + RNP_LOG("Failed to calculate dP or dQ."); // LCOV_EXCL_LINE + } + /* Push params */ + if (!bld.push(OSSL_PKEY_PARAM_RSA_D, d) || !bld.push(OSSL_PKEY_PARAM_RSA_FACTOR1, p) || + !bld.push(OSSL_PKEY_PARAM_RSA_FACTOR2, q) || + !bld.push(OSSL_PKEY_PARAM_RSA_EXPONENT1, dp) || + !bld.push(OSSL_PKEY_PARAM_RSA_EXPONENT2, dq) || + !bld.push(OSSL_PKEY_PARAM_RSA_COEFFICIENT1, u)) { + /* LCOV_EXCL_START */ + RNP_LOG("Failed to push RSA secret params."); + return NULL; + /* LCOV_EXCL_END */ + } + auto params = OSSL_PARAM_BLD_to_param(bld.get()); if (!params) { RNP_LOG("Failed to build RSA params: %s.", ossl_latest_err()); // LCOV_EXCL_LINE } -done: - BN_CTX_free(bnctx); - OSSL_PARAM_BLD_free(bld); return params; } -static EVP_PKEY * +static rnp::ossl::evp::PKey load_key(const Key &key, bool secret) { /* Build params */ - OSSL_PARAM *params = bld_params(key, secret); + rnp::ossl::Param params(bld_params(key, secret)); if (!params) { return NULL; } /* Create context for key creation */ - EVP_PKEY * res = NULL; - EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + rnp::ossl::evp::Ctx ctx(EVP_PKEY_RSA); if (!ctx) { /* LCOV_EXCL_START */ RNP_LOG("Context allocation failed: %s", ossl_latest_err()); - goto done; + return NULL; /* LCOV_EXCL_END */ } /* Create key */ - if (EVP_PKEY_fromdata_init(ctx) <= 0) { + if (EVP_PKEY_fromdata_init(ctx.get()) <= 0) { /* LCOV_EXCL_START */ RNP_LOG("Failed to initialize key creation: %s", ossl_latest_err()); - goto done; + return NULL; /* LCOV_EXCL_END */ } - if (EVP_PKEY_fromdata( - ctx, &res, secret ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params) <= 0) { + rnp::ossl::evp::PKey res; + if (EVP_PKEY_fromdata(ctx.get(), + res.ptr(), + secret ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, + params.get()) <= 0) { RNP_LOG("Failed to create RSA key: %s", ossl_latest_err()); // LCOV_EXCL_LINE } -done: - EVP_PKEY_CTX_free(ctx); - OSSL_PARAM_free(params); return res; } -static EVP_PKEY_CTX * +static rnp::ossl::evp::Ctx init_context(const Key &key, bool secret) { - EVP_PKEY *pkey = load_key(key, secret); + auto pkey = load_key(key, secret); if (!pkey) { return NULL; } - EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL); + rnp::ossl::evp::Ctx ctx(pkey); if (!ctx) { RNP_LOG("Context allocation failed: %s", ossl_latest_err()); // LCOV_EXCL_LINE } - EVP_PKEY_free(pkey); return ctx; } #endif @@ -277,41 +258,39 @@ init_context(const Key &key, bool secret) rnp_result_t Key::validate(rnp::RNG &rng, bool secret) const noexcept { -#ifdef CRYPTO_BACKEND_OPENSSL3 - EVP_PKEY_CTX *ctx = init_context(*this, secret); +#if defined(CRYPTO_BACKEND_OPENSSL3) + auto ctx = init_context(*this, secret); if (!ctx) { /* LCOV_EXCL_START */ RNP_LOG("Failed to init context: %s", ossl_latest_err()); return RNP_ERROR_GENERIC; /* LCOV_EXCL_END */ } - int res = secret ? EVP_PKEY_pairwise_check(ctx) : EVP_PKEY_public_check(ctx); + int res = secret ? EVP_PKEY_pairwise_check(ctx.get()) : EVP_PKEY_public_check(ctx.get()); if (res <= 0) { RNP_LOG("Key validation error: %s", ossl_latest_err()); // LCOV_EXCL_LINE } - EVP_PKEY_CTX_free(ctx); return res > 0 ? RNP_SUCCESS : RNP_ERROR_GENERIC; #else if (secret) { - EVP_PKEY_CTX *ctx = init_context(*this, secret); + rnp::ossl::evp::Ctx ctx(init_context(*this, secret)); if (!ctx) { /* LCOV_EXCL_START */ RNP_LOG("Failed to init context: %s", ossl_latest_err()); return RNP_ERROR_GENERIC; /* LCOV_EXCL_END */ } - int res = EVP_PKEY_check(ctx); + int res = EVP_PKEY_check(ctx.get()); if (res <= 0) { RNP_LOG("Key validation error: %s", ossl_latest_err()); // LCOV_EXCL_LINE } - EVP_PKEY_CTX_free(ctx); return res > 0 ? RNP_SUCCESS : RNP_ERROR_GENERIC; } /* OpenSSL 1.1.1 doesn't have RSA public key check function, so let's do some checks */ rnp::bn on(n); rnp::bn oe(e); - if (!on.get() || !oe.get()) { + if (!on || !oe) { /* LCOV_EXCL_START */ RNP_LOG("out of memory"); return RNP_ERROR_OUT_OF_MEMORY; @@ -326,9 +305,9 @@ Key::validate(rnp::RNG &rng, bool secret) const noexcept } static bool -setup_context(EVP_PKEY_CTX *ctx) +setup_context(rnp::ossl::evp::Ctx &ctx) { - if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) { + if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PADDING) <= 0) { RNP_LOG("Failed to set padding: %lu", ERR_peek_last_error()); return false; } @@ -339,22 +318,22 @@ static const uint8_t PKCS1_SHA1_ENCODING[15] = { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14}; static bool -setup_signature_hash(EVP_PKEY_CTX * ctx, - pgp_hash_alg_t hash_alg, - const uint8_t *&enc, - size_t & enc_size) +setup_signature_hash(rnp::ossl::evp::Ctx &ctx, + pgp_hash_alg_t hash_alg, + const uint8_t *& enc, + size_t & enc_size) { - const char *hash_name = rnp::Hash_OpenSSL::name(hash_alg); + auto hash_name = rnp::Hash_OpenSSL::name(hash_alg); if (!hash_name) { RNP_LOG("Unknown hash: %d", (int) hash_alg); return false; } - const EVP_MD *hash_tp = EVP_get_digestbyname(hash_name); + auto hash_tp = EVP_get_digestbyname(hash_name); if (!hash_tp) { RNP_LOG("Error creating hash object for '%s'", hash_name); return false; } - if (EVP_PKEY_CTX_set_signature_md(ctx, hash_tp) <= 0) { + if (EVP_PKEY_CTX_set_signature_md(ctx.get(), hash_tp) <= 0) { if ((hash_alg != PGP_HASH_SHA1)) { RNP_LOG("Failed to set digest %s: %s", hash_name, ossl_latest_err()); return false; @@ -374,28 +353,24 @@ Key::encrypt_pkcs1(rnp::RNG & rng, const uint8_t *in, size_t in_len) const noexcept { - rnp_result_t ret = RNP_ERROR_GENERIC; - EVP_PKEY_CTX *ctx = init_context(*this, false); + rnp::ossl::evp::Ctx ctx = init_context(*this, false); if (!ctx) { - return ret; + return RNP_ERROR_GENERIC; } - if (EVP_PKEY_encrypt_init(ctx) <= 0) { + if (EVP_PKEY_encrypt_init(ctx.get()) <= 0) { RNP_LOG("Failed to initialize encryption: %lu", ERR_peek_last_error()); - goto done; + return RNP_ERROR_GENERIC; } if (!setup_context(ctx)) { - goto done; + return RNP_ERROR_GENERIC; } out.m.len = PGP_MPINT_SIZE; - if (EVP_PKEY_encrypt(ctx, out.m.mpi, &out.m.len, in, in_len) <= 0) { + if (EVP_PKEY_encrypt(ctx.get(), out.m.mpi, &out.m.len, in, in_len) <= 0) { RNP_LOG("Encryption failed: %lu", ERR_peek_last_error()); out.m.len = 0; - goto done; + return RNP_ERROR_GENERIC; } - ret = RNP_SUCCESS; -done: - EVP_PKEY_CTX_free(ctx); - return ret; + return RNP_SUCCESS; } rnp_result_t @@ -404,51 +379,43 @@ Key::verify_pkcs1(const Signature &sig, const uint8_t * hash, size_t hash_len) const noexcept { - rnp_result_t ret = RNP_ERROR_SIGNATURE_INVALID; - EVP_PKEY_CTX *ctx = init_context(*this, false); + rnp::ossl::evp::Ctx ctx(init_context(*this, false)); if (!ctx) { - return ret; + return RNP_ERROR_SIGNATURE_INVALID; } - const uint8_t *hash_enc = NULL; - size_t hash_enc_size = 0; - uint8_t hash_enc_buf[PGP_MAX_HASH_SIZE + 32] = {0}; - assert(hash_len + hash_enc_size <= sizeof(hash_enc_buf)); - if (EVP_PKEY_verify_init(ctx) <= 0) { + if (EVP_PKEY_verify_init(ctx.get()) <= 0) { RNP_LOG("Failed to initialize verification: %lu", ERR_peek_last_error()); - goto done; + return RNP_ERROR_SIGNATURE_INVALID; } + + const uint8_t *hash_enc = NULL; + size_t hash_enc_size = 0; if (!setup_context(ctx) || !setup_signature_hash(ctx, hash_alg, hash_enc, hash_enc_size)) { - goto done; + return RNP_ERROR_SIGNATURE_INVALID; } /* Check whether we need to workaround on unsupported SHA1 for RSA signature verification */ + std::vector hash_buf(hash_enc, hash_enc + hash_enc_size); if (hash_enc_size) { - memcpy(hash_enc_buf, hash_enc, hash_enc_size); - memcpy(&hash_enc_buf[hash_enc_size], hash, hash_len); - hash = hash_enc_buf; - hash_len += hash_enc_size; + hash_buf.insert(hash_buf.end(), hash, hash + hash_len); + hash = hash_buf.data(); + hash_len = hash_buf.size(); } - int res; + int res = 0; if (sig.s.len < n.len) { /* OpenSSL doesn't like signatures smaller then N */ - pgp::mpi sn; - sn.len = n.len; - size_t diff = n.len - sig.s.len; - memset(sn.mpi, 0, diff); - memcpy(&sn.mpi[diff], sig.s.mpi, sig.s.len); - res = EVP_PKEY_verify(ctx, sn.mpi, sn.len, hash, hash_len); + std::vector sn(n.len - sig.s.len, 0); + sn.insert(sn.end(), sig.s.mpi, sig.s.mpi + sig.s.len); + res = EVP_PKEY_verify(ctx.get(), sn.data(), sn.size(), hash, hash_len); } else { - res = EVP_PKEY_verify(ctx, sig.s.mpi, sig.s.len, hash, hash_len); + res = EVP_PKEY_verify(ctx.get(), sig.s.mpi, sig.s.len, hash, hash_len); } - if (res > 0) { - ret = RNP_SUCCESS; - } else { + if (res <= 0) { RNP_LOG("RSA verification failure: %s", ossl_latest_err()); + return RNP_ERROR_SIGNATURE_INVALID; } -done: - EVP_PKEY_CTX_free(ctx); - return ret; + return RNP_SUCCESS; } rnp_result_t @@ -458,44 +425,39 @@ Key::sign_pkcs1(rnp::RNG & rng, const uint8_t *hash, size_t hash_len) const noexcept { - rnp_result_t ret = RNP_ERROR_GENERIC; if (!q.bytes()) { RNP_LOG("private key not set"); - return ret; + return RNP_ERROR_GENERIC; } - EVP_PKEY_CTX *ctx = init_context(*this, true); + rnp::ossl::evp::Ctx ctx(init_context(*this, true)); if (!ctx) { - return ret; + return RNP_ERROR_GENERIC; } - const uint8_t *hash_enc = NULL; - size_t hash_enc_size = 0; - uint8_t hash_enc_buf[PGP_MAX_HASH_SIZE + 32] = {0}; - assert(hash_len + hash_enc_size <= sizeof(hash_enc_buf)); - if (EVP_PKEY_sign_init(ctx) <= 0) { + + if (EVP_PKEY_sign_init(ctx.get()) <= 0) { RNP_LOG("Failed to initialize signing: %lu", ERR_peek_last_error()); - goto done; + return RNP_ERROR_GENERIC; } + const uint8_t *hash_enc = NULL; + size_t hash_enc_size = 0; if (!setup_context(ctx) || !setup_signature_hash(ctx, hash_alg, hash_enc, hash_enc_size)) { - goto done; + return RNP_ERROR_GENERIC; } /* Check whether we need to workaround on unsupported SHA1 for RSA signature verification */ + std::vector hash_buf(hash_enc, hash_enc + hash_enc_size); if (hash_enc_size) { - memcpy(hash_enc_buf, hash_enc, hash_enc_size); - memcpy(&hash_enc_buf[hash_enc_size], hash, hash_len); - hash = hash_enc_buf; - hash_len += hash_enc_size; + hash_buf.insert(hash_buf.end(), hash, hash + hash_len); + hash = hash_buf.data(); + hash_len = hash_buf.size(); } sig.s.len = PGP_MPINT_SIZE; - if (EVP_PKEY_sign(ctx, sig.s.mpi, &sig.s.len, hash, hash_len) <= 0) { - RNP_LOG("Encryption failed: %lu", ERR_peek_last_error()); + if (EVP_PKEY_sign(ctx.get(), sig.s.mpi, &sig.s.len, hash, hash_len) <= 0) { + RNP_LOG("Signing failed: %lu", ERR_peek_last_error()); sig.s.len = 0; - goto done; + return RNP_ERROR_GENERIC; } - ret = RNP_SUCCESS; -done: - EVP_PKEY_CTX_free(ctx); - return ret; + return RNP_SUCCESS; } rnp_result_t @@ -504,97 +466,84 @@ Key::decrypt_pkcs1(rnp::RNG & rng, size_t & out_len, const Encrypted &in) const noexcept { - rnp_result_t ret = RNP_ERROR_GENERIC; if (!q.bytes()) { RNP_LOG("private key not set"); - return ret; + return RNP_ERROR_GENERIC; } - EVP_PKEY_CTX *ctx = init_context(*this, true); + rnp::ossl::evp::Ctx ctx(init_context(*this, true)); if (!ctx) { - return ret; + return RNP_ERROR_GENERIC; } - if (EVP_PKEY_decrypt_init(ctx) <= 0) { + if (EVP_PKEY_decrypt_init(ctx.get()) <= 0) { RNP_LOG("Failed to initialize encryption: %lu", ERR_peek_last_error()); - goto done; + return RNP_ERROR_GENERIC; } if (!setup_context(ctx)) { - goto done; + return RNP_ERROR_GENERIC; } out_len = PGP_MPINT_SIZE; - if (EVP_PKEY_decrypt(ctx, out, &out_len, in.m.mpi, in.m.len) <= 0) { + if (EVP_PKEY_decrypt(ctx.get(), out, &out_len, in.m.mpi, in.m.len) <= 0) { RNP_LOG("Encryption failed: %lu", ERR_peek_last_error()); out_len = 0; - goto done; + return RNP_ERROR_GENERIC; } - ret = RNP_SUCCESS; -done: - EVP_PKEY_CTX_free(ctx); - return ret; + return RNP_SUCCESS; } static bool -calculate_pqu(const bignum_t *p, const bignum_t *q, const bignum_t *u, Key &key) +calculate_pqu(const rnp::bn &p, const rnp::bn &q, const rnp::bn &u, Key &key) { /* OpenSSL doesn't care whether p < q */ - if (BN_cmp(p, q) > 0) { + if (BN_cmp(p.get(), q.get()) > 0) { /* In this case we have u, as iqmp is inverse of q mod p, and we exchange them */ - bn2mpi(q, &key.p); - bn2mpi(p, &key.q); - bn2mpi(u, &key.u); - return true; + return q.mpi(key.p) && p.mpi(key.q) && u.mpi(key.u); } - BN_CTX *bnctx = BN_CTX_new(); - if (!bnctx) { + rnp::ossl::BNCtx bnctx; + if (!bnctx.get()) { return false; } /* we need to calculate u, since we need inverse of p mod q, while OpenSSL has inverse of q * mod p, and doesn't care of p < q */ - BN_CTX_start(bnctx); - bignum_t *nu = BN_CTX_get(bnctx); - bignum_t *nq = BN_CTX_get(bnctx); + auto nu = bnctx.bn(); + auto nq = bnctx.bn(); if (!nu || !nq) { - BN_CTX_free(bnctx); return false; } - BN_with_flags(nq, q, BN_FLG_CONSTTIME); + BN_with_flags(nq, q.get(), BN_FLG_CONSTTIME); /* calculate inverse of p mod q */ - if (!BN_mod_inverse(nu, p, nq, bnctx)) { + if (!BN_mod_inverse(nu, p.get(), nq, bnctx.get())) { /* LCOV_EXCL_START */ RNP_LOG("Failed to calculate u"); - BN_CTX_free(bnctx); return false; /* LCOV_EXCL_END */ } - bn2mpi(p, &key.p); - bn2mpi(q, &key.q); - bn2mpi(nu, &key.u); - BN_CTX_free(bnctx); - return true; + if (!p.mpi(key.p) || !q.mpi(key.q)) { + return false; + } + rnp::bn anu(nu); + bool res = anu.mpi(key.u); + /* internal BIGNUM is owned by the bnctx */ + anu.own(); + return res; } static bool -extract_key(EVP_PKEY *pkey, Key &key) +extract_key(rnp::ossl::evp::PKey &pkey, Key &key) { #if defined(CRYPTO_BACKEND_OPENSSL3) - rnp::bn n; - rnp::bn e; - rnp::bn d; - rnp::bn p; - rnp::bn q; - rnp::bn u; - - bool res = EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, n.ptr()) && - EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, e.ptr()) && - EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_D, d.ptr()) && - EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, p.ptr()) && - EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, q.ptr()) && - EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, u.ptr()) && - calculate_pqu(p.get(), q.get(), u.get(), key); - return res && n.mpi(key.n) && e.mpi(key.e) && d.mpi(key.d); + rnp::bn n(pkey.get_bn(OSSL_PKEY_PARAM_RSA_N)); + rnp::bn e(pkey.get_bn(OSSL_PKEY_PARAM_RSA_E)); + rnp::bn d(pkey.get_bn(OSSL_PKEY_PARAM_RSA_D)); + rnp::bn p(pkey.get_bn(OSSL_PKEY_PARAM_RSA_FACTOR1)); + rnp::bn q(pkey.get_bn(OSSL_PKEY_PARAM_RSA_FACTOR2)); + rnp::bn u(pkey.get_bn(OSSL_PKEY_PARAM_RSA_COEFFICIENT1)); + + return n && e && d && p && q && u && calculate_pqu(p, q, u, key) && n.mpi(key.n) && + e.mpi(key.e) && d.mpi(key.d); #else - const RSA *rsa = EVP_PKEY_get0_RSA(pkey); + const RSA *rsa = EVP_PKEY_get0_RSA(pkey.get()); if (!rsa) { RNP_LOG("Failed to retrieve RSA key: %lu", ERR_peek_last_error()); return false; @@ -604,22 +553,19 @@ extract_key(EVP_PKEY *pkey, Key &key) return false; } - const bignum_t *n = RSA_get0_n(rsa); - const bignum_t *e = RSA_get0_e(rsa); - const bignum_t *d = RSA_get0_d(rsa); - const bignum_t *p = RSA_get0_p(rsa); - const bignum_t *q = RSA_get0_q(rsa); - const bignum_t *u = RSA_get0_iqmp(rsa); + rnp::bn n(RSA_get0_n(rsa)); + rnp::bn e(RSA_get0_e(rsa)); + rnp::bn d(RSA_get0_d(rsa)); + rnp::bn p(RSA_get0_p(rsa)); + rnp::bn q(RSA_get0_q(rsa)); + rnp::bn u(RSA_get0_iqmp(rsa)); if (!n || !e || !d || !p || !q || !u) { return false; } if (!calculate_pqu(p, q, u, key)) { return false; } - bn2mpi(n, &key.n); - bn2mpi(e, &key.e); - bn2mpi(d, &key.d); - return true; + return n.mpi(key.n) && e.mpi(key.e) && d.mpi(key.d); #endif } @@ -630,34 +576,28 @@ Key::generate(rnp::RNG &rng, size_t numbits) noexcept return RNP_ERROR_BAD_PARAMETERS; } - rnp_result_t ret = RNP_ERROR_GENERIC; - EVP_PKEY * pkey = NULL; - EVP_PKEY_CTX *ctx = NULL; - - ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + rnp::ossl::evp::Ctx ctx(EVP_PKEY_RSA); if (!ctx) { RNP_LOG("Failed to create ctx: %lu", ERR_peek_last_error()); - return ret; + return RNP_ERROR_GENERIC; } - if (EVP_PKEY_keygen_init(ctx) <= 0) { + if (EVP_PKEY_keygen_init(ctx.get()) <= 0) { RNP_LOG("Failed to init keygen: %lu", ERR_peek_last_error()); - goto done; + return RNP_ERROR_GENERIC; } - if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, numbits) <= 0) { + if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), numbits) <= 0) { RNP_LOG("Failed to set rsa bits: %lu", ERR_peek_last_error()); - goto done; + return RNP_ERROR_GENERIC; } - if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { + rnp::ossl::evp::PKey pkey; + if (EVP_PKEY_keygen(ctx.get(), pkey.ptr()) <= 0) { RNP_LOG("RSA keygen failed: %lu", ERR_peek_last_error()); - goto done; + return RNP_ERROR_GENERIC; } - if (extract_key(pkey, *this)) { - ret = RNP_SUCCESS; + if (!extract_key(pkey, *this)) { + return RNP_ERROR_GENERIC; } -done: - EVP_PKEY_CTX_free(ctx); - EVP_PKEY_free(pkey); - return ret; + return RNP_SUCCESS; } } // namespace rsa