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 e827c39caf..4fad3a201a 100644 --- a/crypto/fipsmodule/evp/evp_ctx.c +++ b/crypto/fipsmodule/evp/evp_ctx.c @@ -643,13 +643,31 @@ int EVP_PKEY_decapsulate(EVP_PKEY_CTX *ctx, uint8_t *shared_secret, return ret; } -// 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/internal.h b/crypto/fipsmodule/evp/internal.h index 0a278a7959..9aa81882ea 100644 --- a/crypto/fipsmodule/evp/internal.h +++ b/crypto/fipsmodule/evp/internal.h @@ -188,6 +188,17 @@ struct evp_pkey_st { OPENSSL_EXPORT int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd, int p1, void *p2); +// 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 int EVP_PKEY_CTX_md(EVP_PKEY_CTX *ctx, int optype, int cmd, const char *md); + // EVP_RSA_PKEY_CTX_ctrl is a wrapper of |EVP_PKEY_CTX_ctrl|. // Before calling |EVP_PKEY_CTX_ctrl|, a check is added to make sure // the |ctx->pmeth->pkey_id| is either |EVP_PKEY_RSA| or |EVP_PKEY_RSA_PSS|. @@ -283,6 +294,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 64a96693fd..9e696c5167 100644 --- a/crypto/fipsmodule/evp/p_kem.c +++ b/crypto/fipsmodule/evp/p_kem.c @@ -318,6 +318,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..3f2cb12d80 100644 --- a/crypto/fipsmodule/evp/p_rsa.c +++ b/crypto/fipsmodule/evp/p_rsa.c @@ -703,6 +703,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 = NULL; } DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_rsa_pss_pkey_meth) { @@ -723,6 +724,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 = NULL; } int EVP_RSA_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int optype, int cmd, int p1, void *p2) { 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..f5c5f1b9c6 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1255,11 +1255,21 @@ 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 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);