Skip to content
12 changes: 6 additions & 6 deletions crypto/evp_extra/evp_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1682,7 +1682,7 @@ TEST(EVPTest, ED25519PH) {
pkey.get()));

ASSERT_TRUE(
EVP_PKEY_CTX_set_signature_context(pctx, context, sizeof(context)));
EVP_PKEY_CTX_set1_signature_context_string(pctx, context, sizeof(context)));
const uint8_t *sctx = NULL;
size_t sctx_len = 0;
ASSERT_TRUE(EVP_PKEY_CTX_get0_signature_context(pctx, &sctx, &sctx_len));
Expand All @@ -1700,7 +1700,7 @@ TEST(EVPTest, ED25519PH) {
ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx.get(), &pctx, EVP_sha512(), nullptr,
pubkey.get()));
ASSERT_TRUE(
EVP_PKEY_CTX_set_signature_context(pctx, context, sizeof(context)));
EVP_PKEY_CTX_set1_signature_context_string(pctx, context, sizeof(context)));
ASSERT_TRUE(EVP_DigestVerifyUpdate(md_ctx.get(), &message[0], 3));
ASSERT_TRUE(
EVP_DigestVerifyUpdate(md_ctx.get(), &message[3], sizeof(message) - 3));
Expand All @@ -1714,15 +1714,15 @@ TEST(EVPTest, ED25519PH) {
bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
ASSERT_TRUE(ctx.get());
ASSERT_TRUE(EVP_PKEY_sign_init(ctx.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set_signature_context(ctx.get(), context,
ASSERT_TRUE(EVP_PKEY_CTX_set1_signature_context_string(ctx.get(), context,
sizeof(context)));
ASSERT_TRUE(EVP_PKEY_sign(ctx.get(), working_signature, &working_signature_len, message_sha512, sizeof(message_sha512)));
ASSERT_EQ(working_signature_len, (size_t)ED25519_SIGNATURE_LEN);

ctx.reset(EVP_PKEY_CTX_new(pubkey.get(), nullptr));
ASSERT_TRUE(ctx.get());
ASSERT_TRUE(EVP_PKEY_verify_init(ctx.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set_signature_context(ctx.get(), context,
ASSERT_TRUE(EVP_PKEY_CTX_set1_signature_context_string(ctx.get(), context,
sizeof(context)));
ASSERT_TRUE(EVP_PKEY_verify(ctx.get(), working_signature,
working_signature_len, message_sha512,
Expand Down Expand Up @@ -1870,7 +1870,7 @@ TEST(EVPTest, Ed25519phTestVectors) {
ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pctx, EVP_sha512(), nullptr,
pkey.get()));
ASSERT_TRUE(
EVP_PKEY_CTX_set_signature_context(pctx, context.data(), context.size()));
EVP_PKEY_CTX_set1_signature_context_string(pctx, context.data(), context.size()));
ASSERT_TRUE(EVP_DigestSignUpdate(md_ctx.get(), message.data(), message.size()));
ASSERT_TRUE(EVP_DigestSignFinal(md_ctx.get(), signature,
&signature_len));
Expand All @@ -1880,7 +1880,7 @@ TEST(EVPTest, Ed25519phTestVectors) {
ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx.get(), &pctx, EVP_sha512(), nullptr,
pubkey.get()));
ASSERT_TRUE(
EVP_PKEY_CTX_set_signature_context(pctx, context.data(), context.size()));
EVP_PKEY_CTX_set1_signature_context_string(pctx, context.data(), context.size()));
ASSERT_TRUE(EVP_DigestVerifyUpdate(md_ctx.get(), message.data(), message.size()));
ASSERT_TRUE(EVP_DigestVerifyFinal(md_ctx.get(), signature,
signature_len));
Expand Down
250 changes: 154 additions & 96 deletions crypto/evp_extra/p_pqdsa_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2061,6 +2061,142 @@ TEST_P(PQDSAParameterTest, SIGOperations) {
md_ctx_verify.Reset();
}

TEST_P(PQDSAParameterTest, ContextString) {
Comment thread
justsmth marked this conversation as resolved.
// ---- 1. Setup: generate key pair ----
bssl::UniquePtr<EVP_PKEY> pkey(generate_key_pair(GetParam().nid));
ASSERT_TRUE(pkey);

std::vector<uint8_t> msg = {0x48, 0x65, 0x6c, 0x6c, 0x6f}; // "Hello"
uint8_t ctx_bytes[] = {0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74}; // "Context"

// ---- 2. Sign with context, verify with same context ----
bssl::ScopedEVP_MD_CTX md_ctx;
EVP_PKEY_CTX *pkey_ctx = nullptr;
ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pkey_ctx, nullptr, nullptr,
pkey.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set1_signature_context_string(pkey_ctx, ctx_bytes,
sizeof(ctx_bytes)));

// Verify the context can be read back correctly.
const uint8_t *read_ctx = nullptr;
size_t read_ctx_len = 0;
ASSERT_TRUE(EVP_PKEY_CTX_get0_signature_context(pkey_ctx, &read_ctx,
&read_ctx_len));
ASSERT_TRUE(read_ctx);
ASSERT_NE(read_ctx, ctx_bytes); // Must be an internal copy.
ASSERT_EQ(Bytes(ctx_bytes, sizeof(ctx_bytes)), Bytes(read_ctx, read_ctx_len));

size_t sig_len = 0;
ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), nullptr, &sig_len, msg.data(),
msg.size()));
std::vector<uint8_t> sig(sig_len);
ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), sig.data(), &sig_len, msg.data(),
msg.size()));

bssl::ScopedEVP_MD_CTX md_ctx_verify;
EVP_PKEY_CTX *verify_pkey_ctx = nullptr;
ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx_verify.get(), &verify_pkey_ctx,
nullptr, nullptr, pkey.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set1_signature_context_string(verify_pkey_ctx, ctx_bytes,
sizeof(ctx_bytes)));
ASSERT_TRUE(EVP_DigestVerify(md_ctx_verify.get(), sig.data(), sig_len,
msg.data(), msg.size()));

// ---- 3. Mismatched context string causes verification failure ----
md_ctx_verify.Reset();
verify_pkey_ctx = nullptr;
uint8_t wrong_ctx[] = {0x57, 0x72, 0x6f, 0x6e, 0x67}; // "Wrong"
ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx_verify.get(), &verify_pkey_ctx,
nullptr, nullptr, pkey.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set1_signature_context_string(verify_pkey_ctx, wrong_ctx,
sizeof(wrong_ctx)));
ASSERT_FALSE(EVP_DigestVerify(md_ctx_verify.get(), sig.data(), sig_len,
msg.data(), msg.size()));

// ---- 4. Verify with no context fails for signature made with context ----
md_ctx_verify.Reset();
ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx_verify.get(), nullptr, nullptr,
nullptr, pkey.get()));
ASSERT_FALSE(EVP_DigestVerify(md_ctx_verify.get(), sig.data(), sig_len,
msg.data(), msg.size()));

// ---- 5. Default (empty context) remains unchanged ----
md_ctx.Reset();
pkey_ctx = nullptr;
ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pkey_ctx, nullptr, nullptr,
pkey.get()));

// Verify default context is empty (NULL with length 0).
read_ctx = nullptr;
read_ctx_len = 1; // Non-zero to confirm it gets set to 0.
ASSERT_TRUE(EVP_PKEY_CTX_get0_signature_context(pkey_ctx, &read_ctx,
&read_ctx_len));
ASSERT_EQ(read_ctx, nullptr);
ASSERT_EQ(read_ctx_len, (size_t)0);
std::vector<uint8_t> sig_no_ctx(sig_len);
size_t sig_no_ctx_len = sig_len;
ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), sig_no_ctx.data(), &sig_no_ctx_len,
msg.data(), msg.size()));

md_ctx_verify.Reset();
ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx_verify.get(), nullptr, nullptr,
nullptr, pkey.get()));
ASSERT_TRUE(EVP_DigestVerify(md_ctx_verify.get(), sig_no_ctx.data(),
sig_no_ctx_len, msg.data(), msg.size()));

// ---- 6. Context string > 255 bytes is rejected ----
md_ctx.Reset();
pkey_ctx = nullptr;
ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pkey_ctx, nullptr, nullptr,
pkey.get()));
uint8_t long_ctx[256];
OPENSSL_memset(long_ctx, 0x41, sizeof(long_ctx));
ASSERT_FALSE(EVP_PKEY_CTX_set1_signature_context_string(pkey_ctx, long_ctx,
sizeof(long_ctx)));

// ---- 7. Max length context (255 bytes) round-trip sign + verify ----
md_ctx.Reset();
pkey_ctx = nullptr;
ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pkey_ctx, nullptr, nullptr,
pkey.get()));
uint8_t max_ctx[255];
OPENSSL_memset(max_ctx, 0x42, sizeof(max_ctx));
ASSERT_TRUE(EVP_PKEY_CTX_set1_signature_context_string(pkey_ctx, max_ctx,
sizeof(max_ctx)));
sig_len = 0;
ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), nullptr, &sig_len, msg.data(),
msg.size()));
std::vector<uint8_t> sig_max_ctx(sig_len);
ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), sig_max_ctx.data(), &sig_len,
msg.data(), msg.size()));

md_ctx_verify.Reset();
verify_pkey_ctx = nullptr;
ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx_verify.get(), &verify_pkey_ctx,
nullptr, nullptr, pkey.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set1_signature_context_string(verify_pkey_ctx,
max_ctx, sizeof(max_ctx)));
ASSERT_TRUE(EVP_DigestVerify(md_ctx_verify.get(), sig_max_ctx.data(),
sig_len, msg.data(), msg.size()));

// ---- 8. EVP_PKEY_CTX_dup preserves the context ----
md_ctx.Reset();
pkey_ctx = nullptr;
ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pkey_ctx, nullptr, nullptr,
pkey.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set1_signature_context_string(pkey_ctx, ctx_bytes,
sizeof(ctx_bytes)));
bssl::UniquePtr<EVP_PKEY_CTX> dup_ctx(EVP_PKEY_CTX_dup(pkey_ctx));
ASSERT_TRUE(dup_ctx);

read_ctx = nullptr;
read_ctx_len = 0;
ASSERT_TRUE(EVP_PKEY_CTX_get0_signature_context(dup_ctx.get(), &read_ctx,
&read_ctx_len));
ASSERT_TRUE(read_ctx);
ASSERT_EQ(Bytes(ctx_bytes, sizeof(ctx_bytes)), Bytes(read_ctx, read_ctx_len));
}
Comment thread
justsmth marked this conversation as resolved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also coverage for a couple more negative cases:

  // ---- 9. Context is rejected on the EVP_PKEY_sign/verify digest path ----
  // For ML-DSA, the pre-hashed |mu| input already encodes the context per
  // FIPS 204 section 5.3, so combining a configured context with the digest
  // path must fail rather than be silently ignored.
  bssl::UniquePtr<EVP_PKEY_CTX> raw_sign_ctx(
      EVP_PKEY_CTX_new(pkey.get(), nullptr));
  ASSERT_TRUE(raw_sign_ctx);
  ASSERT_TRUE(EVP_PKEY_sign_init(raw_sign_ctx.get()));
  ASSERT_TRUE(EVP_PKEY_CTX_set1_signature_context_string(
      raw_sign_ctx.get(), ctx_bytes, sizeof(ctx_bytes)));

  // |mu| is the 64-byte SHAKE256 output expected by the digest path; the
  // context guard fires before any cryptographic check, so the contents
  // don't need to be a valid mu for this test.
  uint8_t mu[64] = {0};
  size_t raw_sig_len = 0;
  // Query the signature size (|sig == NULL| short-circuits before the guard).
  ASSERT_TRUE(EVP_PKEY_sign(raw_sign_ctx.get(), nullptr, &raw_sig_len, mu,
                            sizeof(mu)));
  std::vector<uint8_t> raw_sig(raw_sig_len);
  ASSERT_FALSE(EVP_PKEY_sign(raw_sign_ctx.get(), raw_sig.data(), &raw_sig_len,
                             mu, sizeof(mu)));

  bssl::UniquePtr<EVP_PKEY_CTX> raw_verify_ctx(
      EVP_PKEY_CTX_new(pkey.get(), nullptr));
  ASSERT_TRUE(raw_verify_ctx);
  ASSERT_TRUE(EVP_PKEY_verify_init(raw_verify_ctx.get()));
  ASSERT_TRUE(EVP_PKEY_CTX_set1_signature_context_string(
      raw_verify_ctx.get(), ctx_bytes, sizeof(ctx_bytes)));
  std::vector<uint8_t> dummy_sig(raw_sig_len, 0);
  ASSERT_FALSE(EVP_PKEY_verify(raw_verify_ctx.get(), dummy_sig.data(),
                               dummy_sig.size(), mu, sizeof(mu)));

@jakemas jakemas May 5, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the suggested negative coverage in df71998. The ContextString test now exercises the digest-path guard on both EVP_PKEY_sign and EVP_PKEY_verify (section 9 of the test), so a configured context combined with the pre-hashed mu input fails loudly rather than being silently dropped.


TEST_P(PQDSAParameterTest, ParsePublicKey) {
// Test the example public key kPublicKey encodes correctly as kPublicKeySPKI
// Public key version of d2i_PrivateKey as part of the EVPExtraTest Gtest
Expand Down Expand Up @@ -2551,125 +2687,47 @@ INSTANTIATE_TEST_SUITE_P(
return params.param.name;
});

// ComputeMLDSAExternalMu formats |pk|, |ctx|, and |msg_ctx| to the ExternalMu
// format expected by |EVP_PKEY_verify|. For more information, see the docstring
// for |EVP_PKEY_verify|.
//
// It returns true on success and false on error.
static bool ComputeMLDSAExternalMu(const std::vector<uint8_t> &pk,
const std::vector<uint8_t> &msg_ctx,
const std::vector<uint8_t> &msg,
std::vector<uint8_t> &mu_out) {
// Ensure |msg_ctx| <= 255 to be representable by a uint8
// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf#algorithm.4
if (msg_ctx.size() > 255) {
return false;
}

// Compute tr = SHAKE256(pk)
// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf#algorithm.8
std::vector<uint8_t> tr(64);
bssl::ScopedEVP_MD_CTX md_ctx_pk;
if (!EVP_DigestInit_ex(md_ctx_pk.get(), EVP_shake256(), nullptr) ||
!EVP_DigestUpdate(md_ctx_pk.get(), pk.data(), pk.size()) ||
!EVP_DigestFinalXOF(md_ctx_pk.get(), tr.data(), tr.size())) {
return false;
}

// Compute mu = SHAKE256(tr || 0 || |msg_ctx| || msg_ctx || M)
// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf#subsection.5.3
mu_out.resize(64);
bssl::ScopedEVP_MD_CTX md_ctx_mu;
if (!EVP_DigestInit_ex(md_ctx_mu.get(), EVP_shake256(), nullptr) ||
!EVP_DigestUpdate(md_ctx_mu.get(), tr.data(), tr.size())) {
return false;
}

// Add 0 byte for "pure" mode, distinguished from "pre-hash" mode
// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf#subsection.5.4
uint8_t zero = 0;
if (!EVP_DigestUpdate(md_ctx_mu.get(), &zero, 1)) {
return false;
}

// Add |msg_ctx|, msg_ctx, and msg, in that order
uint8_t ctx_len = static_cast<uint8_t>(msg_ctx.size());
if (!EVP_DigestUpdate(md_ctx_mu.get(), &ctx_len, 1)) {
return false;
}
if (!msg_ctx.empty() &&
!EVP_DigestUpdate(md_ctx_mu.get(), msg_ctx.data(), msg_ctx.size())) {
return false;
}
if (!EVP_DigestUpdate(md_ctx_mu.get(), msg.data(), msg.size()) ||
!EVP_DigestFinalXOF(md_ctx_mu.get(), mu_out.data(), mu_out.size())) {
return false;
}

return true;
}

// VerifyMLDSAWithContext verifies that |sig| is a valid signature for |msg|
// with context |msg_ctx|. We need this wrapper because |EVP_DigestVerify| does
// not support verification with contexts.
// with context |msg_ctx| using the EVP_DigestVerify path with
// EVP_PKEY_CTX_set1_signature_context_string.
//
// It returns one on success and zero on error.
static int VerifyMLDSAWithContext(EVP_PKEY *pkey,
const std::vector<uint8_t> &pk,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NP: I don't think pk is used any more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropped the unused pk parameter from VerifyMLDSAWithContext (and updated all callers) in 848ed20.

const std::vector<uint8_t> &sig,
const std::vector<uint8_t> &msg,
const std::vector<uint8_t> &msg_ctx) {
// If there's a non-empty context string, do ExternalMu verification
if (!msg_ctx.empty()) {
std::vector<uint8_t> mu;
if (!ComputeMLDSAExternalMu(pk, msg_ctx, msg, mu)) {
return 0;
}
bssl::UniquePtr<EVP_PKEY_CTX> pkey_ctx(EVP_PKEY_CTX_new(pkey, nullptr));
if (!pkey_ctx || !EVP_PKEY_verify_init(pkey_ctx.get())) {
return 0;
}
return EVP_PKEY_verify(pkey_ctx.get(), sig.data(), sig.size(), mu.data(),
mu.size());
}

// Otherwise, do standard verification
bssl::ScopedEVP_MD_CTX md_ctx;
if (!EVP_DigestVerifyInit(md_ctx.get(), nullptr, nullptr, nullptr, pkey)) {
EVP_PKEY_CTX *pkey_ctx = nullptr;
if (!EVP_DigestVerifyInit(md_ctx.get(), &pkey_ctx, nullptr, nullptr, pkey)) {
return 0;
}
if (!msg_ctx.empty() &&
!EVP_PKEY_CTX_set1_signature_context_string(pkey_ctx, msg_ctx.data(),
msg_ctx.size())) {
return 0;
}
return EVP_DigestVerify(md_ctx.get(), sig.data(), sig.size(), msg.data(),
msg.size());
}

// SignMLDSAWithContext produces a signature |sig| for message |msg| with
// context |msg_ctx|. We need this wrapper because |EVP_DigestSign| does not
// support signing with contexts.
// context |msg_ctx| using the EVP_DigestSign path with
// EVP_PKEY_CTX_set1_signature_context_string.
//
// It returns one on success and zero on error.
static int SignMLDSAWithContext(EVP_PKEY *pkey, std::vector<uint8_t> &sig,
const std::vector<uint8_t> &pk,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NP: I don't think pk is used now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropped the unused pk parameter from SignMLDSAWithContext (and updated all callers) in 848ed20.

const std::vector<uint8_t> &msg,
const std::vector<uint8_t> &msg_ctx) {
// If there's a non-empty context string, do ExternalMu signing
if (!msg_ctx.empty()) {
std::vector<uint8_t> mu;
if (!ComputeMLDSAExternalMu(pk, msg_ctx, msg, mu)) {
return 0;
}
bssl::UniquePtr<EVP_PKEY_CTX> pkey_ctx(EVP_PKEY_CTX_new(pkey, nullptr));
if (!pkey_ctx || !EVP_PKEY_sign_init(pkey_ctx.get())) {
return 0;
}

size_t sig_len = sig.size();
return EVP_PKEY_sign(pkey_ctx.get(), sig.data(), &sig_len, mu.data(),
mu.size());
}

// Otherwise, do standard signing
bssl::ScopedEVP_MD_CTX md_ctx;
if (!EVP_DigestSignInit(md_ctx.get(), nullptr, nullptr, nullptr, pkey)) {
EVP_PKEY_CTX *pkey_ctx = nullptr;
if (!EVP_DigestSignInit(md_ctx.get(), &pkey_ctx, nullptr, nullptr, pkey)) {
return 0;
}
if (!msg_ctx.empty() &&
!EVP_PKEY_CTX_set1_signature_context_string(pkey_ctx, msg_ctx.data(),
msg_ctx.size())) {
return 0;
}
size_t sig_len = sig.size();
Expand Down
8 changes: 7 additions & 1 deletion crypto/fipsmodule/evp/evp.c
Original file line number Diff line number Diff line change
Expand Up @@ -659,14 +659,20 @@ int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) {
0, (void *)out_md);
}

int EVP_PKEY_CTX_set_signature_context(EVP_PKEY_CTX *ctx,
int EVP_PKEY_CTX_set1_signature_context_string(EVP_PKEY_CTX *ctx,
const uint8_t *context,
size_t context_len) {
EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS params = {context, context_len};
return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG,
EVP_PKEY_CTRL_SIGNING_CONTEXT, 0, &params);
}

int EVP_PKEY_CTX_set_signature_context(EVP_PKEY_CTX *ctx,
const uint8_t *context,
size_t context_len) {
return EVP_PKEY_CTX_set1_signature_context_string(ctx, context, context_len);
}
Comment on lines +684 to +688

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NP: Could one of the tests call EVP_PKEY_CTX_set_signature_context instead of EVP_PKEY_CTX_set1_signature_context_string just to ensure coverage for it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched the verify-side setup in the ContextString test to call EVP_PKEY_CTX_set_signature_context in 848ed20, so both setter names are covered in the round-trip.


int EVP_PKEY_CTX_get0_signature_context(EVP_PKEY_CTX *ctx,
const uint8_t **context,
size_t *context_len) {
Expand Down
10 changes: 8 additions & 2 deletions crypto/fipsmodule/evp/p_ed25519ph.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,16 @@ static int pkey_ed25519ph_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
}
case EVP_PKEY_CTRL_SIGNING_CONTEXT: {
EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS *params = p2;
if (!params || !dctx || params->context_len > sizeof(dctx->context)) {
if (!params || !dctx ||
params->context_len > sizeof(dctx->context) ||
(params->context_len > 0 && !params->context)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PARAMETERS);
return 0;
}
OPENSSL_memcpy(dctx->context, params->context, params->context_len);
OPENSSL_cleanse(dctx->context, sizeof(dctx->context));
if (params->context_len > 0) {
OPENSSL_memcpy(dctx->context, params->context, params->context_len);
}
dctx->context_len = params->context_len;
break;
}
Expand Down
Loading
Loading