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

EVP_PKEY_CTX_ctrl_str support for RSA key types #1847

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions crypto/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions crypto/crypto_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand Down
1 change: 1 addition & 0 deletions crypto/dilithium/p_dilithium3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */,
Expand Down
1 change: 1 addition & 0 deletions crypto/evp_extra/p_dh.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions crypto/evp_extra/p_x25519.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */,
Expand Down
29 changes: 24 additions & 5 deletions crypto/fipsmodule/evp/evp_ctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
179 changes: 179 additions & 0 deletions crypto/fipsmodule/evp/evp_ctx_test.cc
Original file line number Diff line number Diff line change
@@ -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 <gtest/gtest.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>

#include "../../internal.h"
#include "internal.h"

class EvpPkeyCtxCtrlStrTest : public ::testing::Test {
protected:
void SetUp() override {}

void TearDown() override {}
};

static bssl::UniquePtr<EVP_PKEY_CTX> gen_RSA() {
EVP_PKEY *raw = nullptr;
bssl::UniquePtr<EVP_PKEY_CTX> 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>(EVP_PKEY_CTX_new(raw, nullptr));
}

TEST_F(EvpPkeyCtxCtrlStrTest, RsaMissingValue) {
// Create a EVP_PKEY_CTX with a newly generated RSA key
bssl::UniquePtr<EVP_PKEY_CTX> 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<EVP_PKEY_CTX> 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<EVP_PKEY_CTX> 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<EVP_PKEY_CTX> 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<EVP_PKEY> 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<EVP_PKEY_CTX> 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<EVP_PKEY> pkey(raw);
ASSERT_TRUE(pkey);

bssl::UniquePtr<RSA> 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<EVP_PKEY_CTX> 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<EVP_PKEY_CTX> 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<EVP_PKEY_CTX> 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);
}
2 changes: 2 additions & 0 deletions crypto/fipsmodule/evp/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions crypto/fipsmodule/evp/p_ec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions crypto/fipsmodule/evp/p_ed25519.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions crypto/fipsmodule/evp/p_hkdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions crypto/fipsmodule/evp/p_hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions crypto/fipsmodule/evp/p_kem.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading
Loading