Skip to content

Commit

Permalink
Implement more EVP_PKEY_DH functionality (#1880)
Browse files Browse the repository at this point in the history
  • Loading branch information
justsmth authored Oct 14, 2024
1 parent a748793 commit cf969b5
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 4 deletions.
44 changes: 44 additions & 0 deletions crypto/evp_extra/evp_extra_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1792,6 +1792,50 @@ TEST(EVPExtraTest, DHKeygen) {
}
}

TEST(EVPExtraTest, DHParamgen) {
std::vector<std::pair<int, int>> test_data(
{{768, 3}, {512, DH_GENERATOR_2}, {256, DH_GENERATOR_5}});

for (std::pair<int, int> plgen : test_data) {
const int prime_len = plgen.first;
const int generator = plgen.second;
// Construct a EVP_PKEY_CTX
bssl::UniquePtr<EVP_PKEY_CTX> ctx(
EVP_PKEY_CTX_new_id(EVP_PKEY_DH, nullptr));
ASSERT_TRUE(ctx);
// Initialize for paramgen
ASSERT_TRUE(EVP_PKEY_paramgen_init(ctx.get()));
// Set the prime length
ASSERT_TRUE(EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx.get(), prime_len));
// Set the generator
ASSERT_TRUE(EVP_PKEY_CTX_set_dh_paramgen_generator(ctx.get(), generator));

EVP_PKEY *raw_pkey = NULL;
// Generate the parameters
ASSERT_TRUE(EVP_PKEY_paramgen(ctx.get(), &raw_pkey));
bssl::UniquePtr<EVP_PKEY> pkey(raw_pkey);
ASSERT_TRUE(raw_pkey);

const DH* dh = EVP_PKEY_get0_DH(pkey.get());
const BIGNUM* p = DH_get0_p(dh);
unsigned p_size = BN_num_bits(p);
ASSERT_EQ(p_size, (unsigned)prime_len);
}

// Test error conditions
const int prime_len = 255;
const int generator = 1;
// Construct a EVP_PKEY_CTX
bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DH, nullptr));
ASSERT_TRUE(ctx);
// Initialize for paramgen
ASSERT_TRUE(EVP_PKEY_paramgen_init(ctx.get()));
// Set the prime length
ASSERT_NE(EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx.get(), prime_len), 1);
// Set the generator
ASSERT_NE(EVP_PKEY_CTX_set_dh_paramgen_generator(ctx.get(), generator), 1);
}

// Test that |EVP_PKEY_keygen| works for Ed25519.
TEST(EVPExtraTest, Ed25519Keygen) {
bssl::UniquePtr<EVP_PKEY_CTX> pctx(
Expand Down
73 changes: 69 additions & 4 deletions crypto/evp_extra/p_dh.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,19 @@

typedef struct dh_pkey_ctx_st {
int pad;
/* Parameter gen parameters */
int prime_len;
int generator;
} DH_PKEY_CTX;

static int pkey_dh_init(EVP_PKEY_CTX *ctx) {
DH_PKEY_CTX *dctx = OPENSSL_zalloc(sizeof(DH_PKEY_CTX));
if (dctx == NULL) {
return 0;
}
// Default parameters
dctx->prime_len = 2048;
dctx->generator = DH_GENERATOR_2;

ctx->data = dctx;
return 1;
Expand Down Expand Up @@ -104,7 +110,7 @@ static int pkey_dh_derive(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len) {
return 1;
}

static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *_p2) {
DH_PKEY_CTX *dctx = ctx->data;
switch (type) {
case EVP_PKEY_CTRL_PEER_KEY:
Expand All @@ -116,21 +122,70 @@ static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
dctx->pad = p1;
return 1;

case EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN:
if(p1 < 256) {
return -2;
}
dctx->prime_len = p1;
return 1;

case EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR:
if(p1 < 2) {
return -2;
}
dctx->generator = p1;
return 1;

default:
OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
return 0;
}
}

static int pkey_dh_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
DH_PKEY_CTX *dctx = ctx->data;
DH *dh = DH_new();
if (dh == NULL) {
return 0;
}
int ret = DH_generate_parameters_ex(dh, dctx->prime_len, dctx->generator, NULL);
if (ret == 1) {
EVP_PKEY_assign_DH(pkey, dh);
} else {
ret = 0;
DH_free(dh);
}
return ret;
}


static int pkey_dh_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
const char *value) {
// We don't support:
// * dh_paramgen_prime_len
// * dh_rfc5114
// * dh_param
// * dh_paramgen_generator
// * dh_paramgen_subprime_len
// * dh_paramgen_type
if (strcmp(type, "dh_paramgen_prime_len") == 0) {
char* str_end = NULL;
long prime_len = strtol(value, &str_end, 10);
if(str_end == value || prime_len < 0 || prime_len > INT_MAX) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
return 0;
}
return EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, (int)prime_len);
}

if (strcmp(type, "dh_paramgen_generator") == 0) {
char* str_end = NULL;
long generator = strtol(value, &str_end, 10);
if(str_end == value || generator < 0 || generator > INT_MAX) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
return 0;
}
return EVP_PKEY_CTX_set_dh_paramgen_generator(ctx, (int)generator);
}


if (strcmp(type, "dh_pad") == 0) {
char* str_end = NULL;
Expand All @@ -139,7 +194,7 @@ static int pkey_dh_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
return 0;
}
return EVP_PKEY_CTX_set_dh_pad(ctx, pad);
return EVP_PKEY_CTX_set_dh_pad(ctx, (int)pad);
}
return -2;
}
Expand All @@ -152,6 +207,7 @@ const EVP_PKEY_METHOD dh_pkey_meth = {
.cleanup = pkey_dh_cleanup,
.keygen = pkey_dh_keygen,
.derive = pkey_dh_derive,
.paramgen = pkey_dh_paramgen,
.ctrl = pkey_dh_ctrl,
.ctrl_str = pkey_dh_ctrl_str
};
Expand All @@ -160,3 +216,12 @@ int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad) {
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_DERIVE,
EVP_PKEY_CTRL_DH_PAD, pad, NULL);
}

int EVP_PKEY_CTX_set_dh_paramgen_prime_len(EVP_PKEY_CTX *ctx, int pbits) {
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN,
EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN, pbits, NULL);
}
int EVP_PKEY_CTX_set_dh_paramgen_generator(EVP_PKEY_CTX *ctx, int gen) {
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN,
EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR, gen, NULL);
}
26 changes: 26 additions & 0 deletions crypto/fipsmodule/evp/evp_ctx_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "internal.h"

#include <gtest/gtest.h>
#include <openssl/dh.h>
#include <openssl/ec_key.h>
#include <openssl/err.h>
#include <openssl/evp.h>
Expand Down Expand Up @@ -239,6 +240,31 @@ TEST_F(EvpPkeyCtxCtrlStrTest, DhPad) {
// There is no function to retrieve the DH pad value.
}

TEST_F(EvpPkeyCtxCtrlStrTest, DhParamGen) {
// Create a EVP_PKEY_CTX with a newly generated DH
bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DH, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_paramgen_init(ctx.get()));

ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dh_paramgen_prime_len", "256"), 1);
ASSERT_NE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dh_paramgen_prime_len", "gg"), 1);
ASSERT_NE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dh_paramgen_prime_len", "255"), 1);

ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dh_paramgen_generator", "5"), 1);
ASSERT_NE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dh_paramgen_prime_len", "gg"), 1);
ASSERT_NE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dh_paramgen_prime_len", "1"), 1);

EVP_PKEY* raw = nullptr;
ASSERT_EQ(EVP_PKEY_paramgen(ctx.get(), &raw), 1);
bssl::UniquePtr<EVP_PKEY> pkey(raw);
ASSERT_TRUE(raw);

const DH* dh = EVP_PKEY_get0_DH(pkey.get());
const BIGNUM* p = DH_get0_p(dh);
unsigned p_size = BN_num_bits(p);
ASSERT_EQ(p_size, 256u);
}

static const char *hkdf_hexsalt = "000102030405060708090a0b0c";
static const char *hkdf_hexinfo = "f0f1f2f3f4f5f6f7f8f9";
static const char *hkdf_hexkey = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
Expand Down
2 changes: 2 additions & 0 deletions crypto/fipsmodule/evp/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ int EVP_RSA_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int optype, int cmd, int p1, void *
#define EVP_PKEY_CTRL_HKDF_SALT (EVP_PKEY_ALG_CTRL + 17)
#define EVP_PKEY_CTRL_HKDF_INFO (EVP_PKEY_ALG_CTRL + 18)
#define EVP_PKEY_CTRL_DH_PAD (EVP_PKEY_ALG_CTRL + 19)
#define EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN (EVP_PKEY_ALG_CTRL + 20)
#define EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR (EVP_PKEY_ALG_CTRL + 21)

// EVP_PKEY_CTX_KEYGEN_INFO_COUNT is the maximum array length for
// |EVP_PKEY_CTX->keygen_info|. The array length corresponds to the number of
Expand Down
12 changes: 12 additions & 0 deletions include/openssl/evp.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,18 @@ OPENSSL_EXPORT int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key);
OPENSSL_EXPORT DH *EVP_PKEY_get0_DH(const EVP_PKEY *pkey);
OPENSSL_EXPORT DH *EVP_PKEY_get1_DH(const EVP_PKEY *pkey);

// EVP_PKEY_CTX_set_dh_paramgen_prime_len sets the length of the DH prime
// parameter p for DH parameter generation. If this function is not called,
// the default length of 2048 is used. |pbits| must be greater than or equal
// to 256. Returns 1 on success, otherwise returns a non-positive value.
OPENSSL_EXPORT int EVP_PKEY_CTX_set_dh_paramgen_prime_len(EVP_PKEY_CTX *ctx, int pbits);

// EVP_PKEY_CTX_set_dh_paramgen_generator sets the DH generator for DH parameter
// generation. If this function is not called, the default value of 2 is used.
// |gen| must be greater than 1. Returns 1 on success, otherwise returns a
// non-positive value.
OPENSSL_EXPORT int EVP_PKEY_CTX_set_dh_paramgen_generator(EVP_PKEY_CTX *ctx, int gen);

#define EVP_PKEY_NONE NID_undef
#define EVP_PKEY_RSA NID_rsaEncryption
#define EVP_PKEY_RSA_PSS NID_rsassaPss
Expand Down

0 comments on commit cf969b5

Please sign in to comment.