diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt index 8887df791e..0115800367 100644 --- a/crypto/CMakeLists.txt +++ b/crypto/CMakeLists.txt @@ -791,6 +791,7 @@ if(BUILD_TESTING) fipsmodule/ec/ec_test.cc fipsmodule/ec/p256-nistz_test.cc fipsmodule/ecdsa/ecdsa_test.cc + fipsmodule/evp/evp_ctx_test.cc fipsmodule/kdf/kdf_test.cc fipsmodule/md5/md5_test.cc fipsmodule/modes/gcm_test.cc diff --git a/crypto/crypto_test.cc b/crypto/crypto_test.cc index 9ceff77d4e..0f38923402 100644 --- a/crypto/crypto_test.cc +++ b/crypto/crypto_test.cc @@ -73,6 +73,33 @@ TEST(CryptoTest, Strndup) { EXPECT_STREQ("", str.get()); } +TEST(CryptoTest, OPENSSL_hexstr2buf) { + const char *test_cases[][2] = {{"a2", "\xa2"}, + {"a213", "\xa2\x13"}, + {"ffeedd", "\xff\xee\xdd"}, + {"10aab1c2", "\x10\xaa\xb1\xc2"}}; + + for (auto test_case : test_cases) { + const char *test_value = test_case[0]; + const char *expected_answer = test_case[1]; + size_t actual_answer_len = 0; + // The longest test case we have is currently 4 bytes long + size_t expected_answer_len = OPENSSL_strnlen(test_case[1], 5); + unsigned char *buf = OPENSSL_hexstr2buf(test_value, &actual_answer_len); + ASSERT_TRUE(buf != nullptr); + EXPECT_EQ(expected_answer_len, actual_answer_len); + EXPECT_EQ(0, OPENSSL_memcmp(buf, expected_answer, expected_answer_len)); + OPENSSL_free(buf); + } + + // Test failure modes + size_t actual_answer_len = 0; + EXPECT_FALSE(OPENSSL_hexstr2buf("a", &actual_answer_len)); + EXPECT_FALSE(OPENSSL_hexstr2buf(NULL, &actual_answer_len)); + EXPECT_FALSE(OPENSSL_hexstr2buf("ab", nullptr)); + EXPECT_FALSE(OPENSSL_hexstr2buf("ag", &actual_answer_len)); +} + #if defined(BORINGSSL_FIPS_COUNTERS) using CounterArray = size_t[fips_counter_max + 1]; diff --git a/crypto/dilithium/p_dilithium3.c b/crypto/dilithium/p_dilithium3.c index ad842ed1a4..1f174ee837 100644 --- a/crypto/dilithium/p_dilithium3.c +++ b/crypto/dilithium/p_dilithium3.c @@ -117,6 +117,7 @@ const EVP_PKEY_METHOD dilithium3_pkey_meth = { NULL /* derive */, NULL /* paramgen */, NULL /* ctrl */, + NULL /* ctrl_str */, NULL /* keygen deterministic */, NULL /* encapsulate deterministic */, NULL /* encapsulate */, diff --git a/crypto/evp_extra/p_dh.c b/crypto/evp_extra/p_dh.c index b1d799140f..a0e57d0ec6 100644 --- a/crypto/evp_extra/p_dh.c +++ b/crypto/evp_extra/p_dh.c @@ -129,6 +129,7 @@ const EVP_PKEY_METHOD dh_pkey_meth = { .keygen = pkey_dh_keygen, .derive = pkey_dh_derive, .ctrl = pkey_dh_ctrl, + .ctrl_str = NULL }; int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad) { diff --git a/crypto/evp_extra/p_x25519.c b/crypto/evp_extra/p_x25519.c index 84b514fb87..197e1f8297 100644 --- a/crypto/evp_extra/p_x25519.c +++ b/crypto/evp_extra/p_x25519.c @@ -106,6 +106,7 @@ const EVP_PKEY_METHOD x25519_pkey_meth = { pkey_x25519_derive, NULL /* paramgen */, pkey_x25519_ctrl, + NULL, /* ctrl_str */ NULL /* keygen deterministic */, NULL /* encapsulate deterministic */, NULL /* encapsulate */, diff --git a/crypto/fipsmodule/evp/evp_ctx.c b/crypto/fipsmodule/evp/evp_ctx.c index e659e317dc..be70c699fd 100644 --- a/crypto/fipsmodule/evp/evp_ctx.c +++ b/crypto/fipsmodule/evp/evp_ctx.c @@ -617,13 +617,32 @@ int EVP_PKEY_decapsulate(EVP_PKEY_CTX *ctx, ciphertext, ciphertext_len); } -// Deprecated keygen NO-OP functions -int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, - const char *value) { - // No-op - return 0; +int EVP_PKEY_CTX_md(EVP_PKEY_CTX *ctx, int optype, int cmd, const char *md) { + const EVP_MD *m; + + if (md == NULL || (m = EVP_get_digestbyname(md)) == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_TYPE); + return 0; + } + return EVP_PKEY_CTX_ctrl(ctx, -1, optype, cmd, 0, (void *)m); } +int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx, const char *name, + const char *value) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl_str) { + OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return -2; + } + if (strcmp(name, "digest") == 0) { + OPENSSL_BEGIN_ALLOW_DEPRECATED + return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, value); + OPENSSL_END_ALLOW_DEPRECATED + } + return ctx->pmeth->ctrl_str(ctx, name, value); +} + + +// Deprecated keygen NO-OP functions void EVP_PKEY_CTX_set_cb(EVP_PKEY_CTX *ctx, EVP_PKEY_gen_cb *cb) { // No-op } diff --git a/crypto/fipsmodule/evp/evp_ctx_test.cc b/crypto/fipsmodule/evp/evp_ctx_test.cc new file mode 100644 index 0000000000..1039734c6f --- /dev/null +++ b/crypto/fipsmodule/evp/evp_ctx_test.cc @@ -0,0 +1,179 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#include "internal.h" + +#include +#include +#include +#include + +#include "../../internal.h" +#include "internal.h" + +class EvpPkeyCtxCtrlStrTest : public ::testing::Test { + protected: + void SetUp() override {} + + void TearDown() override {} +}; + +static bssl::UniquePtr gen_RSA() { + EVP_PKEY *raw = nullptr; + bssl::UniquePtr keygen_ctx( + EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr)); + if (!EVP_PKEY_keygen_init(keygen_ctx.get()) || + !EVP_PKEY_CTX_set_rsa_keygen_bits(keygen_ctx.get(), 2048) || + !EVP_PKEY_keygen(keygen_ctx.get(), &raw)) { + return nullptr; + } + return bssl::UniquePtr(EVP_PKEY_CTX_new(raw, nullptr)); +} + +TEST_F(EvpPkeyCtxCtrlStrTest, RsaMissingValue) { + // Create a EVP_PKEY_CTX with a newly generated RSA key + bssl::UniquePtr ctx = gen_RSA(); + ASSERT_TRUE(ctx); + EXPECT_FALSE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", nullptr)); + unsigned long err = ERR_get_error(); + EXPECT_EQ(ERR_GET_LIB(err), ERR_LIB_EVP); + EXPECT_EQ(ERR_GET_REASON(err), RSA_R_VALUE_MISSING); +} + +TEST_F(EvpPkeyCtxCtrlStrTest, RsaPaddingModeValid) { + bssl::UniquePtr ctx = gen_RSA(); + ASSERT_TRUE(ctx); + + int padding = 0; + + // Padding for sign + ASSERT_TRUE(EVP_PKEY_sign_init(ctx.get())); + + EXPECT_TRUE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", "pkcs1")); + EXPECT_TRUE(EVP_PKEY_CTX_get_rsa_padding(ctx.get(), &padding)); + EXPECT_EQ(padding, RSA_PKCS1_PADDING); + + EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", "none"), 1); + EXPECT_TRUE(EVP_PKEY_CTX_get_rsa_padding(ctx.get(), &padding)); + EXPECT_EQ(padding, RSA_NO_PADDING); + + EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", "pss"), 1); + EXPECT_TRUE(EVP_PKEY_CTX_get_rsa_padding(ctx.get(), &padding)); + EXPECT_EQ(padding, RSA_PKCS1_PSS_PADDING); + + // Padding for encrypt + ASSERT_TRUE(EVP_PKEY_encrypt_init(ctx.get())); + + EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", "oaep"), 1); + EXPECT_TRUE(EVP_PKEY_CTX_get_rsa_padding(ctx.get(), &padding)); + EXPECT_EQ(padding, RSA_PKCS1_OAEP_PADDING); + + EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", "oeap"), 1); + EXPECT_TRUE(EVP_PKEY_CTX_get_rsa_padding(ctx.get(), &padding)); + EXPECT_EQ(padding, RSA_PKCS1_OAEP_PADDING); + + EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", "nonsense"), + -2); +} + +TEST_F(EvpPkeyCtxCtrlStrTest, RsaPssSaltlen) { + // Create a EVP_PKEY_CTX with a newly generated RSA key + bssl::UniquePtr ctx = gen_RSA(); + ASSERT_TRUE(ctx); + + ASSERT_TRUE(EVP_PKEY_sign_init(ctx.get())); + EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", "pss"), 1); + EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_pss_saltlen", "128"), 1); + + int saltlen = 0; + EXPECT_EQ(EVP_PKEY_CTX_get_rsa_pss_saltlen(ctx.get(), &saltlen), 1); + EXPECT_EQ(saltlen, 128); + + EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_pss_saltlen", "digest"), 1); + EXPECT_EQ(EVP_PKEY_CTX_get_rsa_pss_saltlen(ctx.get(), &saltlen), 1); + EXPECT_EQ(saltlen, -1); + + EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_pss_saltlen", "-3"), -2); +} + +TEST_F(EvpPkeyCtxCtrlStrTest, RsaKeygenBits) { + // Create a EVP_PKEY_CTX with a newly generated RSA key + EVP_PKEY *raw = nullptr; + bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr)); + ASSERT_TRUE(ctx); + ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get())); + ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_keygen_bits", "2048"), 1); + ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_keygen_bits", "-3"), -2); + ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw)); + bssl::UniquePtr pkey(raw); + ASSERT_TRUE(pkey); + + ASSERT_EQ(EVP_PKEY_bits(pkey.get()), 2048); +} + +TEST_F(EvpPkeyCtxCtrlStrTest, RsaKeygenPubexp) { + // Create a EVP_PKEY_CTX with a newly generated RSA key + EVP_PKEY *raw = nullptr; + bssl::UniquePtr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr)); + ASSERT_TRUE(ctx); + ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get())); + ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_keygen_pubexp", "729"), 1); + ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_keygen_pubexp", "gg"), -2); + ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw)); + bssl::UniquePtr pkey(raw); + ASSERT_TRUE(pkey); + + bssl::UniquePtr rsa_key(EVP_PKEY_get1_RSA(pkey.get())); + ASSERT_TRUE(rsa_key); + const BIGNUM *const_pe_bn = RSA_get0_e(rsa_key.get()); + ASSERT_TRUE(const_pe_bn != nullptr); + + const uint64_t expected_pe = 729; + uint64_t pe_u64; + ASSERT_TRUE(BN_get_u64(const_pe_bn, &pe_u64)); + EXPECT_EQ(pe_u64, expected_pe); +} + +TEST_F(EvpPkeyCtxCtrlStrTest, RsaMgf1Md) { + bssl::UniquePtr ctx = gen_RSA(); + ASSERT_TRUE(ctx); + + ASSERT_TRUE(EVP_PKEY_sign_init(ctx.get())); + ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PSS_PADDING)); + ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_mgf1_md", "sha256"), 1); + + const EVP_MD *out_md; + ASSERT_TRUE(EVP_PKEY_CTX_get_rsa_mgf1_md(ctx.get(), &out_md)); + ASSERT_STREQ(EVP_MD_name(out_md), "SHA256"); +} + +// rsa_oaep_md +TEST_F(EvpPkeyCtxCtrlStrTest, RsaOaepMd) { + bssl::UniquePtr ctx = gen_RSA(); + ASSERT_TRUE(ctx); + + ASSERT_TRUE(EVP_PKEY_encrypt_init(ctx.get())); + ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING)); + ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_oaep_md", "sha256"), 1); + + const EVP_MD *out_md; + ASSERT_TRUE(EVP_PKEY_CTX_get_rsa_oaep_md(ctx.get(), &out_md)); + ASSERT_STREQ(EVP_MD_name(out_md), "SHA256"); +} + +TEST_F(EvpPkeyCtxCtrlStrTest, RsaOaepLabel) { + bssl::UniquePtr ctx = gen_RSA(); + ASSERT_TRUE(ctx); + + ASSERT_TRUE(EVP_PKEY_encrypt_init(ctx.get())); + ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING)); + ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), EVP_sha256())); + ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_oaep_label", "aabb11"), 1); + ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_oaep_label", "gg"), -2); + + const char expected_label[4] = "\xaa\xbb\x11"; + const uint8_t *actual_label; + ASSERT_TRUE(EVP_PKEY_CTX_get0_rsa_oaep_label(ctx.get(), &actual_label)); + + ASSERT_TRUE(OPENSSL_memcmp(actual_label, expected_label, 3) == 0); +} diff --git a/crypto/fipsmodule/evp/internal.h b/crypto/fipsmodule/evp/internal.h index 0a278a7959..b6adb0c46a 100644 --- a/crypto/fipsmodule/evp/internal.h +++ b/crypto/fipsmodule/evp/internal.h @@ -283,6 +283,8 @@ struct evp_pkey_method_st { int (*ctrl)(EVP_PKEY_CTX *ctx, int type, int p1, void *p2); + int (*ctrl_str) (EVP_PKEY_CTX *ctx, const char *type, const char *value); + // Encapsulate, encapsulate_deterministic, keygen_deterministic, and // decapsulate are operations defined for a Key Encapsulation Mechanism (KEM). int (*keygen_deterministic)(EVP_PKEY_CTX *ctx, diff --git a/crypto/fipsmodule/evp/p_ec.c b/crypto/fipsmodule/evp/p_ec.c index d332c2afa3..d473f9bdeb 100644 --- a/crypto/fipsmodule/evp/p_ec.c +++ b/crypto/fipsmodule/evp/p_ec.c @@ -289,6 +289,7 @@ DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_ec_pkey_meth) { out->derive = pkey_ec_derive; out->paramgen = pkey_ec_paramgen; out->ctrl = pkey_ec_ctrl; + out->ctrl_str = NULL; } int EVP_PKEY_CTX_set_ec_paramgen_curve_nid(EVP_PKEY_CTX *ctx, int nid) { diff --git a/crypto/fipsmodule/evp/p_ed25519.c b/crypto/fipsmodule/evp/p_ed25519.c index 1550b351a7..e8b98b80ba 100644 --- a/crypto/fipsmodule/evp/p_ed25519.c +++ b/crypto/fipsmodule/evp/p_ed25519.c @@ -99,6 +99,7 @@ DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_ed25519_pkey_meth) { out->derive = NULL; out->paramgen = NULL; out->ctrl = NULL; + out->ctrl_str = NULL; out->keygen_deterministic = NULL; out->encapsulate_deterministic = NULL; out->encapsulate = NULL; diff --git a/crypto/fipsmodule/evp/p_hkdf.c b/crypto/fipsmodule/evp/p_hkdf.c index 2fbc31fa3c..04316a88bb 100644 --- a/crypto/fipsmodule/evp/p_hkdf.c +++ b/crypto/fipsmodule/evp/p_hkdf.c @@ -197,6 +197,7 @@ DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_hkdf_pkey_meth) { out->derive = pkey_hkdf_derive; out->paramgen = NULL; /* paramgen */ out->ctrl = pkey_hkdf_ctrl; + out->ctrl_str = NULL; } int EVP_PKEY_CTX_hkdf_mode(EVP_PKEY_CTX *ctx, int mode) { diff --git a/crypto/fipsmodule/evp/p_hmac.c b/crypto/fipsmodule/evp/p_hmac.c index d0e456c808..6a6d34e222 100644 --- a/crypto/fipsmodule/evp/p_hmac.c +++ b/crypto/fipsmodule/evp/p_hmac.c @@ -124,6 +124,7 @@ DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_hmac_pkey_meth) { out->derive = NULL; out->paramgen = NULL; out->ctrl = hmac_ctrl; + out->ctrl_str = NULL; } int used_for_hmac(EVP_MD_CTX *ctx) { diff --git a/crypto/fipsmodule/evp/p_kem.c b/crypto/fipsmodule/evp/p_kem.c index c5c310e122..c14f32027c 100644 --- a/crypto/fipsmodule/evp/p_kem.c +++ b/crypto/fipsmodule/evp/p_kem.c @@ -317,6 +317,7 @@ DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_kem_pkey_meth) { out->derive = pkey_hkdf_derive; out->paramgen = NULL; out->ctrl = NULL; + out->ctrl_str = NULL; out->keygen_deterministic = pkey_kem_keygen_deterministic; out->encapsulate_deterministic = pkey_kem_encapsulate_deterministic; out->encapsulate = pkey_kem_encapsulate; diff --git a/crypto/fipsmodule/evp/p_rsa.c b/crypto/fipsmodule/evp/p_rsa.c index 5ccb01d301..304134838b 100644 --- a/crypto/fipsmodule/evp/p_rsa.c +++ b/crypto/fipsmodule/evp/p_rsa.c @@ -685,6 +685,110 @@ static int pkey_rsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { return ret; } +static int pkey_rsa_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, + const char *value) { + if (value == NULL) { + OPENSSL_PUT_ERROR(EVP, RSA_R_VALUE_MISSING); + return 0; + } + if (strcmp(type, "rsa_padding_mode") == 0) { + // "sslv23" and "x931" are not supported + int pm; + + if (strcmp(value, "pkcs1") == 0) { + pm = RSA_PKCS1_PADDING; + } else if (strcmp(value, "none") == 0) { + pm = RSA_NO_PADDING; + // OpenSSL also supports the typo. + } else if (strcmp(value, "oeap") == 0) { + pm = RSA_PKCS1_OAEP_PADDING; + } else if (strcmp(value, "oaep") == 0) { + pm = RSA_PKCS1_OAEP_PADDING; + } else if (strcmp(value, "pss") == 0) { + pm = RSA_PKCS1_PSS_PADDING; + } else { + OPENSSL_PUT_ERROR(EVP, RSA_R_UNKNOWN_PADDING_TYPE); + return -2; + } + return EVP_PKEY_CTX_set_rsa_padding(ctx, pm); + } + + if (strcmp(type, "rsa_pss_saltlen") == 0) { + // "max" and "auto" are not supported + long saltlen; + + if (!strcmp(value, "digest")) { + saltlen = RSA_PSS_SALTLEN_DIGEST; + } else { + char* str_end; + saltlen = strtol(value, &str_end, 10); + if(str_end == value || saltlen < 0 || saltlen > INT_MAX) { + OPENSSL_PUT_ERROR(EVP, RSA_R_INTERNAL_ERROR); + return -2; + } + } + return EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, (int)saltlen); + } + + if (strcmp(type, "rsa_keygen_bits") == 0) { + char* str_end; + long nbits = strtol(value, &str_end, 10); + if (str_end == value || nbits <= 0 || nbits > INT_MAX) { + OPENSSL_PUT_ERROR(EVP, RSA_R_INTERNAL_ERROR); + return -2; + } + return EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, (int)nbits); + } + + if (strcmp(type, "rsa_keygen_pubexp") == 0) { + int ret; + + BIGNUM *pubexp = NULL; + if (!BN_asc2bn(&pubexp, value)) { + return -2; + } + ret = EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx, pubexp); + if (ret <= 0) { + BN_free(pubexp); + } + return ret; + } + + if (strcmp(type, "rsa_mgf1_md") == 0) { + OPENSSL_BEGIN_ALLOW_DEPRECATED + return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_MGF1_MD, value); + OPENSSL_END_ALLOW_DEPRECATED + } + + // rsa_pss_keygen_XXX options are not supported + + if (strcmp(type, "rsa_oaep_md") == 0) { + OPENSSL_BEGIN_ALLOW_DEPRECATED + return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_OAEP_MD, value); + OPENSSL_END_ALLOW_DEPRECATED + } + if (strcmp(type, "rsa_oaep_label") == 0) { + size_t lablen; + int ret; + uint8_t *lab; + + lab = OPENSSL_hexstr2buf(value, &lablen); + if (lab == NULL) { + return -2; + } + + ret = EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, lab, lablen); + if (ret <= 0) { + OPENSSL_free(lab); + } + return ret; + } + + return -2; +} + DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_rsa_pkey_meth) { out->pkey_id = EVP_PKEY_RSA; out->init = pkey_rsa_init; @@ -703,6 +807,7 @@ DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_rsa_pkey_meth) { out->derive = NULL; out->paramgen = NULL; out->ctrl = pkey_rsa_ctrl; + out->ctrl_str = pkey_rsa_ctrl_str; } DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_rsa_pss_pkey_meth) { @@ -723,6 +828,7 @@ DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_rsa_pss_pkey_meth) { out->derive = NULL; out->paramgen = NULL; out->ctrl = pkey_rsa_ctrl; + out->ctrl_str = pkey_rsa_ctrl_str; } int EVP_RSA_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int optype, int cmd, int p1, void *p2) { @@ -797,7 +903,7 @@ int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) { int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) { return EVP_RSA_PKEY_CTX_ctrl(ctx, - EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_OP_KEYGEN | EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, EVP_PKEY_CTRL_GET_RSA_MGF1_MD, 0, (void*) out_md); } diff --git a/crypto/mem.c b/crypto/mem.c index efe42dbee3..6bf94151b3 100644 --- a/crypto/mem.c +++ b/crypto/mem.c @@ -414,6 +414,36 @@ int OPENSSL_fromxdigit(uint8_t *out, int c) { return 0; } +uint8_t *OPENSSL_hexstr2buf(const char *str, size_t *len) { + if (str == NULL || len == NULL) { + return NULL; + } + + const size_t slen = OPENSSL_strnlen(str, INT16_MAX); + if (slen % 2 != 0) { + return NULL; + } + + const size_t buflen = slen / 2; + uint8_t *buf = OPENSSL_zalloc(buflen); + if (buf == NULL) { + return NULL; + } + + for (size_t i = 0; i < buflen; i++) { + uint8_t hi, lo; + if (!OPENSSL_fromxdigit(&hi, str[2 * i]) || + !OPENSSL_fromxdigit(&lo, str[2 * i + 1])) { + OPENSSL_free(buf); + return NULL; + } + buf[i] = (hi << 4) | lo; + } + + *len = buflen; + return buf; +} + int OPENSSL_isalnum(int c) { return OPENSSL_isalpha(c) || OPENSSL_isdigit(c); } int OPENSSL_tolower(int c) { diff --git a/include/openssl/evp.h b/include/openssl/evp.h index a770b26c0f..86526281f2 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1255,11 +1255,32 @@ OPENSSL_EXPORT OPENSSL_DEPRECATED int EVP_PKEY_CTX_set_dsa_paramgen_q_bits( EVP_PKEY_CTX *ctx, int qbits); -// EVP_PKEY_CTX No-ops [Deprecated]. +// EVP_PKEY_CTX_ctrl_str -// EVP_PKEY_CTX_ctrl_str is a no-op. +// EVP_PKEY_CTX_ctrl_str sets a parameter on |ctx| of type |type| to |value|. +// This function is deprecated and should not be used in new code. +// +// WARNING: This function is difficult to use correctly. New code should use +// the EVP_PKEY_CTX_set1_* or EVP_PKEY_CTX_set_* functions instead. +// +// |ctx| is the context to operate on. +// |type| is the parameter type as a string. +// |value| is the value to set. +// +// It returns 1 for success and 0 or a negative value for failure. OPENSSL_EXPORT OPENSSL_DEPRECATED int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, - const char *value); + const char *value); + +// EVP_PKEY_CTX_md sets the message digest type for a specific operation. +// This function is deprecated and should not be used in new code. +// +// |ctx| is the context to operate on. +// |optype| is the operation type (e.g., EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_OP_KEYGEN). +// |cmd| is the specific command (e.g., EVP_PKEY_CTRL_MD). +// |md| is the name of the message digest algorithm to use. +// +// It returns 1 for success and 0 or a negative value for failure. +OPENSSL_EXPORT OPENSSL_DEPRECATED int EVP_PKEY_CTX_md(EVP_PKEY_CTX *ctx, int optype, int cmd, const char *md); // EVP_PKEY_CTX keygen no-ops [Deprecated]. diff --git a/include/openssl/mem.h b/include/openssl/mem.h index 4092066bc6..d306758a99 100644 --- a/include/openssl/mem.h +++ b/include/openssl/mem.h @@ -145,6 +145,13 @@ OPENSSL_EXPORT int OPENSSL_isxdigit(int c); // zero is returned. OPENSSL_EXPORT int OPENSSL_fromxdigit(uint8_t *out, int c); +// OPENSSL_hexstr2buf allocates and returns a buffer containing the bytes +// represented by the hexadecimal string |str|. |str| must be a NULL terminated +// string of hex characters. The length of the buffer is stored in |*len|. +// |len| must not be NULL. The caller must free the returned +// buffer with |OPENSSL_free|. If |str| is malformed, NULL is returned. +OPENSSL_EXPORT uint8_t *OPENSSL_hexstr2buf(const char *str, size_t *len); + // OPENSSL_isalnum is a locale-independent, ASCII-only version of isalnum(3), It // only recognizes what |OPENSSL_isalpha| and |OPENSSL_isdigit| recognize. OPENSSL_EXPORT int OPENSSL_isalnum(int c);