Add FIPS DSA Keygen tests

Adjust the existing tests to disable DSA keygen in FIPS mode.

Allow evp_test to load DSA 'KeyParams' that can then be used to
perform a DSA KeyGen.

Reviewed-by: Paul Dale <ppzgs1@gmail.com>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/24978)
This commit is contained in:
slontis 2024-07-24 17:24:33 +10:00 committed by Tomas Mraz
parent 49a35f0f92
commit f98e49b326
7 changed files with 156 additions and 48 deletions

View File

@ -347,7 +347,7 @@ static EVP_PKEY *dsa_paramgen(int L, int N)
|| !TEST_true(EVP_PKEY_CTX_set_dsa_paramgen_bits(paramgen_ctx, L))
|| !TEST_true(EVP_PKEY_CTX_set_dsa_paramgen_q_bits(paramgen_ctx, N))
|| !TEST_true(EVP_PKEY_paramgen(paramgen_ctx, &param_key)))
return NULL;
TEST_info("dsa_paramgen failed");
EVP_PKEY_CTX_free(paramgen_ctx);
return param_key;
}
@ -378,6 +378,10 @@ static int dsa_keygen_test(int id)
size_t priv_len = 0, pub_len = 0;
const struct dsa_paramgen_st *tst = &dsa_keygen_data[id];
if (!dsasign_allowed) {
TEST_info("DSA keygen test skipped: DSA signing is not allowed");
return 1;
}
if (!TEST_ptr(param_key = dsa_paramgen(tst->L, tst->N))
|| !TEST_ptr(keygen_ctx = EVP_PKEY_CTX_new_from_pkey(libctx, param_key,
NULL))
@ -421,23 +425,31 @@ static int dsa_paramgen_test(int id)
if (!TEST_ptr(paramgen_ctx = EVP_PKEY_CTX_new_from_name(libctx, "DSA", NULL))
|| !TEST_int_gt(EVP_PKEY_paramgen_init(paramgen_ctx), 0)
|| !TEST_true(EVP_PKEY_CTX_set_dsa_paramgen_bits(paramgen_ctx, tst->L))
|| !TEST_true(EVP_PKEY_CTX_set_dsa_paramgen_q_bits(paramgen_ctx, tst->N))
|| !TEST_true(EVP_PKEY_paramgen(paramgen_ctx, &param_key))
|| !TEST_true(pkey_get_bn_bytes(param_key, OSSL_PKEY_PARAM_FFC_P,
&p, &plen))
|| !TEST_true(pkey_get_bn_bytes(param_key, OSSL_PKEY_PARAM_FFC_Q,
&q, &qlen))
|| !TEST_true(pkey_get_octet_bytes(param_key, OSSL_PKEY_PARAM_FFC_SEED,
&seed, &seedlen))
|| !TEST_true(EVP_PKEY_get_int_param(param_key,
OSSL_PKEY_PARAM_FFC_PCOUNTER,
&counter)))
|| !TEST_true(EVP_PKEY_CTX_set_dsa_paramgen_q_bits(paramgen_ctx,
tst->N)))
goto err;
test_output_memory("p", p, plen);
test_output_memory("q", q, qlen);
test_output_memory("domainSeed", seed, seedlen);
test_printf_stderr("%s: %d\n", "counter", counter);
if (!dsasign_allowed) {
if (!TEST_false(EVP_PKEY_paramgen(paramgen_ctx, &param_key)))
goto err;
} else {
if (!TEST_true(EVP_PKEY_paramgen(paramgen_ctx, &param_key))
|| !TEST_true(pkey_get_bn_bytes(param_key, OSSL_PKEY_PARAM_FFC_P,
&p, &plen))
|| !TEST_true(pkey_get_bn_bytes(param_key, OSSL_PKEY_PARAM_FFC_Q,
&q, &qlen))
|| !TEST_true(pkey_get_octet_bytes(param_key,
OSSL_PKEY_PARAM_FFC_SEED,
&seed, &seedlen))
|| !TEST_true(EVP_PKEY_get_int_param(param_key,
OSSL_PKEY_PARAM_FFC_PCOUNTER,
&counter)))
goto err;
test_output_memory("p", p, plen);
test_output_memory("q", q, qlen);
test_output_memory("domainSeed", seed, seedlen);
test_printf_stderr("%s: %d\n", "counter", counter);
}
ret = 1;
err:
OPENSSL_free(p);
@ -597,10 +609,12 @@ static int dsa_siggen_test(int id)
size_t sig_len = 0, rlen = 0, slen = 0;
const struct dsa_siggen_st *tst = &dsa_siggen_data[id];
if (!TEST_ptr(pkey = dsa_keygen(tst->L, tst->N)))
goto err;
if (dsasign_allowed) {
if (!dsasign_allowed) {
if (!TEST_ptr_null(pkey = dsa_keygen(tst->L, tst->N)))
goto err;
} else {
if (!TEST_ptr(pkey = dsa_keygen(tst->L, tst->N)))
goto err;
if (!TEST_true(sig_gen(pkey, NULL, tst->digest_alg, tst->msg, tst->msg_len,
&sig, &sig_len))
|| !TEST_true(get_dsa_sig_rs_bytes(sig, sig_len, &r, &s, &rlen, &slen)))

View File

@ -247,7 +247,7 @@ static int dsa_keygen_test(void)
goto end;
if (!TEST_ptr(pg_ctx = EVP_PKEY_CTX_new_from_name(NULL, "DSA", NULL))
|| !TEST_int_gt(EVP_PKEY_paramgen_init(pg_ctx), 0)
|| !TEST_ptr_null(EVP_PKEY_CTX_gettable_params(pg_ctx))
|| !TEST_ptr(EVP_PKEY_CTX_gettable_params(pg_ctx))
|| !TEST_ptr(settables = EVP_PKEY_CTX_settable_params(pg_ctx))
|| !TEST_ptr(OSSL_PARAM_locate_const(settables,
OSSL_PKEY_PARAM_FFC_PBITS))

View File

@ -781,7 +781,9 @@ int setup_tests(void)
ADD_TEST(test_evp_cipher_api_safety);
#if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_DH)
ADD_ALL_TESTS(test_dsa_param_keygen, 3 * 3 * 3);
if (strcmp(prov_name, "fips") != 0
|| fips_provider_version_lt(libctx, 3, 4, 0))
ADD_ALL_TESTS(test_dsa_param_keygen, 3 * 3 * 3);
#endif
#ifndef OPENSSL_NO_DH
ADD_ALL_TESTS(test_dh_safeprime_param_keygen, 3 * 3 * 3);

View File

@ -153,6 +153,13 @@ static int pkey_check_fips_approved(EVP_PKEY_CTX *ctx, EVP_TEST *t)
* value of approved.
*/
int approved = 1;
const OSSL_PARAM *gettables = EVP_PKEY_CTX_gettable_params(ctx);
if (gettables == NULL
|| OSSL_PARAM_locate_const(gettables,
OSSL_ALG_PARAM_FIPS_APPROVED_INDICATOR)
== NULL)
return 1;
/* Older providers dont have a gettable */
if (EVP_PKEY_CTX_gettable_params(ctx) == NULL)
@ -3879,14 +3886,15 @@ static const EVP_TEST_METHOD keypair_test_method = {
**/
typedef struct keygen_test_data_st {
EVP_PKEY_CTX *genctx; /* Keygen context to use */
char *keyname; /* Key name to store key or NULL */
char *paramname;
char *alg;
STACK_OF(OPENSSL_STRING) *controls; /* Collection of controls */
} KEYGEN_TEST_DATA;
static int keygen_test_init(EVP_TEST *t, const char *alg)
{
KEYGEN_TEST_DATA *data;
EVP_PKEY_CTX *genctx;
int nid = OBJ_sn2nid(alg);
if (nid == NID_undef) {
@ -3899,24 +3907,17 @@ static int keygen_test_init(EVP_TEST *t, const char *alg)
t->skip = 1;
return 1;
}
if (!TEST_ptr(genctx = EVP_PKEY_CTX_new_from_name(libctx, alg, propquery)))
goto err;
if (EVP_PKEY_keygen_init(genctx) <= 0) {
t->err = "KEYGEN_INIT_ERROR";
goto err;
}
if (!TEST_ptr(data = OPENSSL_malloc(sizeof(*data))))
goto err;
data->genctx = genctx;
data->keyname = NULL;
data->alg = OPENSSL_strdup(alg);
data->paramname = NULL;
data->controls = sk_OPENSSL_STRING_new_null();
t->data = data;
t->err = NULL;
return 1;
err:
EVP_PKEY_CTX_free(genctx);
return 0;
}
@ -3924,7 +3925,9 @@ static void keygen_test_cleanup(EVP_TEST *t)
{
KEYGEN_TEST_DATA *keygen = t->data;
EVP_PKEY_CTX_free(keygen->genctx);
ctrlfree(keygen->controls);
OPENSSL_free(keygen->alg);
OPENSSL_free(keygen->paramname);
OPENSSL_free(keygen->keyname);
OPENSSL_free(t->data);
t->data = NULL;
@ -3937,21 +3940,57 @@ static int keygen_test_parse(EVP_TEST *t,
if (strcmp(keyword, "KeyName") == 0)
return TEST_ptr(keygen->keyname = OPENSSL_strdup(value));
if (strcmp(keyword, "KeyParam") == 0)
return TEST_ptr(keygen->paramname = OPENSSL_strdup(value));
if (strcmp(keyword, "Ctrl") == 0)
return pkey_test_ctrl(t, keygen->genctx, value);
return ctrladd(keygen->controls, value);
return 0;
}
static int keygen_test_run(EVP_TEST *t)
{
KEYGEN_TEST_DATA *keygen = t->data;
EVP_PKEY *pkey = NULL;
int rv = 1;
EVP_PKEY *pkey = NULL, *keyparams = NULL;
EVP_PKEY_CTX *genctx = NULL; /* Keygen context to use */
int rv = 1, i;
if (EVP_PKEY_keygen(keygen->genctx, &pkey) <= 0) {
if (keygen->paramname != NULL) {
rv = find_key(&keyparams, keygen->paramname, public_keys);
if (rv == 0 || keyparams == NULL) {
TEST_info("skipping, key '%s' is disabled", keygen->paramname);
t->skip = 1;
return 1;
}
if (!TEST_ptr(genctx = EVP_PKEY_CTX_new_from_pkey(libctx, keyparams,
propquery)))
goto err;
} else {
if (!TEST_ptr(genctx = EVP_PKEY_CTX_new_from_name(libctx, keygen->alg,
propquery)))
goto err;
}
if (EVP_PKEY_keygen_init(genctx) <= 0) {
t->err = "KEYGEN_INIT_ERROR";
goto err;
}
for (i = 0; i < sk_OPENSSL_STRING_num(keygen->controls); ++i) {
if (!pkey_test_ctrl(t, genctx,
sk_OPENSSL_STRING_value(keygen->controls, i))
|| t->err != NULL)
goto err;
}
if (EVP_PKEY_keygen(genctx, &pkey) <= 0) {
t->err = "KEYGEN_GENERATE_ERROR";
goto err;
}
if (!pkey_check_fips_approved(genctx, t)) {
rv = 0;
goto err;
}
if (!evp_pkey_is_provided(pkey)) {
TEST_info("Warning: legacy key generated %s", keygen->keyname);
@ -3979,8 +4018,8 @@ static int keygen_test_run(EVP_TEST *t)
}
t->err = NULL;
err:
EVP_PKEY_CTX_free(genctx);
return rv;
}
@ -4662,6 +4701,15 @@ start:
return 0;
}
klist = &public_keys;
} else if (strcmp(pp->key, "ParamKey") == 0) {
pkey = PEM_read_bio_Parameters_ex(t->s.key, NULL, libctx, NULL);
if (pkey == NULL && !key_unsupported()) {
EVP_PKEY_free(pkey);
TEST_info("Can't read params key %s", pp->value);
TEST_openssl_errors();
return 0;
}
klist = &public_keys;
} else if (strcmp(pp->key, "PrivateKeyRaw") == 0
|| strcmp(pp->key, "PublicKeyRaw") == 0) {
char *strnid = NULL, *keydata = NULL;

View File

@ -1,5 +1,5 @@
#! /usr/bin/env perl
# Copyright 2017-2023 The OpenSSL Project Authors. All Rights Reserved.
# Copyright 2017-2024 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the Apache License 2.0 (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
@ -160,22 +160,28 @@ unless ($no_fips) {
$ENV{OPENSSL_TEST_LIBCTX} = "1";
# DSA signing/keygen is not approved in FIPS 140-3
run(test(["fips_version_test", "-config", $provconf, "<3.4.0"]),
capture => 1, statusvar => \my $dsasignpass);
# Generate params
ok(run(app(['openssl', 'genpkey',
is(run(app(['openssl', 'genpkey',
@prov,
'-genparam',
'-algorithm', 'DSA',
'-pkeyopt', 'pbits:3072',
'-pkeyopt', 'qbits:256',
'-out', 'gendsatest3072params.pem'])),
$dsasignpass,
"Generating 3072-bit DSA params");
# Generate keypair
ok(run(app(['openssl', 'genpkey',
is(run(app(['openssl', 'genpkey',
@prov,
'-paramfile', 'gendsatest3072params.pem',
'-text',
'-out', 'gendsatest3072.pem'])),
$dsasignpass,
"Generating 3072-bit DSA keypair");
}

View File

@ -437,3 +437,43 @@ CtrlInit = sign-check:0
Key = DSA-2048-256
Input = "Hello"
Result = DIGESTSIGNINIT_ERROR
Title = Test DSA keygen
# Load DSA Params to use in the DSA keygen tests
ParamKey = DSA-2048-PARAMS
-----BEGIN DSA PARAMETERS-----
MIICKAKCAQEAgrJrFYjhhJ3NnIBSRNpVK5+gze+9fA4Ce0Yjbiz3KOU2TTtE1mbf
lGVsjuAEX2c/cBUWFEjg77EoGCFCpfbzSh6nd2DgCiFaw91ak3GuQ+yKs55SyeQV
ikUQaAILVm0SgIPhdCUtG5XdghJyNUTEHFowWXh3gaQDaRB6MqxbMj0a9LoRwYAw
Mo/9bug6Uh/ITEKjoBertznRW8SflHhATvc6eCL6NXi3qhkQIgYDdwxUGGz1SnfH
wUTYcvu2eogv+0WAnnxCJh51qv2gUynH4TLeL9g/jskcJfvYtejJ+k/G3Q6dsEn/
an8pdKdH0MaplOZNB6nJSa1H0VZfg9V9VQIdALq9dtHaBpeXSal0qhn0P/nmR9ID
I1Yn4K1l33cCggEAAulOaqN0hBs9DXQyljrKesD8zTLgIsabgyEauuyFfsZp5ezU
762cnqDde20DPTHu1hbVmw68hvKDAWNpVzMMsopFPPWt8JwnEHSMZxwv08RxBET9
HQXL4+YxA9hfAmtRkUK+QdZFRdXv4AjnxcLyNbIqT/uPm1c/+Dd7875rIzTcW3cc
IvhlS7VgfwIg0IUuGF2uXt/6P7zInftR+nan4/DbNWind5308I7l4jchRjUDRlsK
WbJpcH2m2K43Ue0MUKIki1dTlH07PiHUuY4wQ+jInWtnnRQlLGSw+LdrD7gwpFYY
w/lWdpSTr0aHbSvxD9vcrUzKljFY6iSQF32wcg==
-----END DSA PARAMETERS-----
# FIPS Key generation tests
# Test FIPS DSA keygen is not allowed
Availablein = fips
FIPSversion = >=3.4.0
KeyGen = DSA
KeyParam = DSA-2048-PARAMS
KeyName = tmp1dsa
Result = KEYGEN_GENERATE_ERROR
Title = Test DSA keygen FIPS indicator test
# Test DSA keygen is not approved
Availablein = fips
FIPSversion = >=3.4.0
KeyGen = DSA
KeyParam = DSA-2048-PARAMS
KeyName = tmp2dsa
Unapproved = 1
Ctrl = sign-check:0

View File

@ -126,11 +126,9 @@ int test_readstanza(STANZA *s)
if (s->numpairs == 0)
s->start = s->curr;
if (strcmp(key, "PrivateKey") == 0) {
if (!read_key(s))
return 0;
}
if (strcmp(key, "PublicKey") == 0) {
if (strcmp(key, "PrivateKey") == 0
|| strcmp(key, "PublicKey") == 0
|| strcmp(key, "ParamKey") == 0) {
if (!read_key(s))
return 0;
}