mirror of
https://github.com/openssl/openssl.git
synced 2024-12-21 06:09:35 +08:00
90409da6a5
Fixes #12405 Fixes #12377 Calling Init()/Update() and then Init()/Update() again gave a different result when using the same key and iv. Cipher modes that were using ctx->num were not resetting this value, this includes OFB, CFB & CTR. The fix is to reset this value during the ciphers einit() and dinit() methods. Most ciphers go thru a generic method so one line fixes most cases. Add test for calling EVP_EncryptInit()/EVP_EncryptUpdate() multiple times for all ciphers. Ciphers should return the same value for both updates. DES3-WRAP does not since it uses a random in the update. CCM modes currently also fail on the second update (This also happens in 1_1_1). Fix memory leak in AES_OCB cipher if EVP_EncryptInit is called multiple times. Fix AES_SIV cipher dup_ctx and init. Calling EVP_CIPHER_init multiple times resulted in a memory leak in the siv. Fixing this leak also showed that the dup ctx was not working for siv mode. Note: aes_siv_cleanup() can not be used by aes_siv_dupctx() as it clears data that is required for the decrypt (e.g the tag). Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org> (Merged from https://github.com/openssl/openssl/pull/12413)
340 lines
9.6 KiB
C
340 lines
9.6 KiB
C
/*
|
|
* Copyright 2020 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
|
|
* in the file LICENSE in the source distribution or at
|
|
* https://www.openssl.org/source/license.html
|
|
*/
|
|
|
|
/*
|
|
|
|
* These tests are setup to load null into the default library context.
|
|
* Any tests are expected to use the created 'libctx' to find algorithms.
|
|
* The framework runs the tests twice using the 'default' provider or
|
|
* 'fips' provider as inputs.
|
|
*/
|
|
|
|
/*
|
|
* DSA/DH low level APIs are deprecated for public use, but still ok for
|
|
* internal use.
|
|
*/
|
|
#include "internal/deprecated.h"
|
|
#include <openssl/evp.h>
|
|
#include <openssl/provider.h>
|
|
#include <openssl/dsa.h>
|
|
#include <openssl/safestack.h>
|
|
#include "testutil.h"
|
|
#include "internal/nelem.h"
|
|
#include "crypto/bn_dh.h" /* _bignum_ffdhe2048_p */
|
|
#include "../e_os.h" /* strcasecmp */
|
|
|
|
DEFINE_STACK_OF_CSTRING()
|
|
|
|
static OPENSSL_CTX *libctx = NULL;
|
|
static OSSL_PROVIDER *nullprov = NULL;
|
|
static OSSL_PROVIDER *libprov = NULL;
|
|
static STACK_OF(OPENSSL_CSTRING) *cipher_names = NULL;
|
|
|
|
typedef enum OPTION_choice {
|
|
OPT_ERR = -1,
|
|
OPT_EOF = 0,
|
|
OPT_CONFIG_FILE,
|
|
OPT_PROVIDER_NAME,
|
|
OPT_TEST_ENUM
|
|
} OPTION_CHOICE;
|
|
|
|
const OPTIONS *test_get_options(void)
|
|
{
|
|
static const OPTIONS test_options[] = {
|
|
OPT_TEST_OPTIONS_DEFAULT_USAGE,
|
|
{ "config", OPT_CONFIG_FILE, '<',
|
|
"The configuration file to use for the libctx" },
|
|
{ "provider", OPT_PROVIDER_NAME, 's',
|
|
"The provider to load (The default value is 'default'" },
|
|
{ NULL }
|
|
};
|
|
return test_options;
|
|
}
|
|
|
|
#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_DH)
|
|
static const char *getname(int id)
|
|
{
|
|
const char *name[] = {"p", "q", "g" };
|
|
|
|
if (id >= 0 && id < 3)
|
|
return name[id];
|
|
return "?";
|
|
}
|
|
#endif
|
|
|
|
#ifndef OPENSSL_NO_DSA
|
|
|
|
static int test_dsa_param_keygen(int tstid)
|
|
{
|
|
int ret = 0;
|
|
int expected;
|
|
EVP_PKEY_CTX *gen_ctx = NULL;
|
|
EVP_PKEY *pkey_parm = NULL;
|
|
EVP_PKEY *pkey = NULL;
|
|
DSA *dsa = NULL;
|
|
int pind, qind, gind;
|
|
BIGNUM *p = NULL, *q = NULL, *g = NULL;
|
|
|
|
/*
|
|
* Just grab some fixed dh p, q, g values for testing,
|
|
* these 'safe primes' should not be used normally for dsa *.
|
|
*/
|
|
static const BIGNUM *bn[] = {
|
|
&_bignum_dh2048_256_p, &_bignum_dh2048_256_q, &_bignum_dh2048_256_g
|
|
};
|
|
|
|
/*
|
|
* These tests are using bad values for p, q, g by reusing the values.
|
|
* A value of 0 uses p, 1 uses q and 2 uses g.
|
|
* There are 27 different combinations, with only the 1 valid combination.
|
|
*/
|
|
pind = tstid / 9;
|
|
qind = (tstid / 3) % 3;
|
|
gind = tstid % 3;
|
|
expected = (pind == 0 && qind == 1 && gind == 2);
|
|
|
|
TEST_note("Testing with (p, q, g) = (%s, %s, %s)\n", getname(pind),
|
|
getname(qind), getname(gind));
|
|
|
|
if (!TEST_ptr(pkey_parm = EVP_PKEY_new())
|
|
|| !TEST_ptr(dsa = DSA_new())
|
|
|| !TEST_ptr(p = BN_dup(bn[pind]))
|
|
|| !TEST_ptr(q = BN_dup(bn[qind]))
|
|
|| !TEST_ptr(g = BN_dup(bn[gind]))
|
|
|| !TEST_true(DSA_set0_pqg(dsa, p, q, g)))
|
|
goto err;
|
|
p = q = g = NULL;
|
|
|
|
if (!TEST_true(EVP_PKEY_assign_DSA(pkey_parm, dsa)))
|
|
goto err;
|
|
dsa = NULL;
|
|
|
|
if (!TEST_ptr(gen_ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey_parm, NULL))
|
|
|| !TEST_int_gt(EVP_PKEY_keygen_init(gen_ctx), 0)
|
|
|| !TEST_int_eq(EVP_PKEY_keygen(gen_ctx, &pkey), expected))
|
|
goto err;
|
|
ret = 1;
|
|
err:
|
|
EVP_PKEY_free(pkey);
|
|
EVP_PKEY_CTX_free(gen_ctx);
|
|
EVP_PKEY_free(pkey_parm);
|
|
DSA_free(dsa);
|
|
BN_free(g);
|
|
BN_free(q);
|
|
BN_free(p);
|
|
return ret;
|
|
}
|
|
#endif /* OPENSSL_NO_DSA */
|
|
|
|
#ifndef OPENSSL_NO_DH
|
|
static int do_dh_param_keygen(int tstid, const BIGNUM **bn)
|
|
{
|
|
int ret = 0;
|
|
int expected;
|
|
EVP_PKEY_CTX *gen_ctx = NULL;
|
|
EVP_PKEY *pkey_parm = NULL;
|
|
EVP_PKEY *pkey = NULL;
|
|
DH *dh = NULL;
|
|
int pind, qind, gind;
|
|
BIGNUM *p = NULL, *q = NULL, *g = NULL;
|
|
|
|
/*
|
|
* These tests are using bad values for p, q, g by reusing the values.
|
|
* A value of 0 uses p, 1 uses q and 2 uses g.
|
|
* There are 27 different combinations, with only the 1 valid combination.
|
|
*/
|
|
pind = tstid / 9;
|
|
qind = (tstid / 3) % 3;
|
|
gind = tstid % 3;
|
|
expected = (pind == 0 && qind == 1 && gind == 2);
|
|
|
|
TEST_note("Testing with (p, q, g) = (%s, %s, %s)", getname(pind),
|
|
getname(qind), getname(gind));
|
|
|
|
if (!TEST_ptr(pkey_parm = EVP_PKEY_new())
|
|
|| !TEST_ptr(dh = DH_new())
|
|
|| !TEST_ptr(p = BN_dup(bn[pind]))
|
|
|| !TEST_ptr(q = BN_dup(bn[qind]))
|
|
|| !TEST_ptr(g = BN_dup(bn[gind]))
|
|
|| !TEST_true(DH_set0_pqg(dh, p, q, g)))
|
|
goto err;
|
|
p = q = g = NULL;
|
|
|
|
if (!TEST_true(EVP_PKEY_assign_DH(pkey_parm, dh)))
|
|
goto err;
|
|
dh = NULL;
|
|
|
|
if (!TEST_ptr(gen_ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey_parm, NULL))
|
|
|| !TEST_int_gt(EVP_PKEY_keygen_init(gen_ctx), 0)
|
|
|| !TEST_int_eq(EVP_PKEY_keygen(gen_ctx, &pkey), expected))
|
|
goto err;
|
|
ret = 1;
|
|
err:
|
|
EVP_PKEY_free(pkey);
|
|
EVP_PKEY_CTX_free(gen_ctx);
|
|
EVP_PKEY_free(pkey_parm);
|
|
DH_free(dh);
|
|
BN_free(g);
|
|
BN_free(q);
|
|
BN_free(p);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Note that we get the fips186-4 path being run for most of these cases since
|
|
* the internal code will detect that the p, q, g does not match a safe prime
|
|
* group (Except for when tstid = 5, which sets the correct p, q, g)
|
|
*/
|
|
static int test_dh_safeprime_param_keygen(int tstid)
|
|
{
|
|
static const BIGNUM *bn[] = {
|
|
&_bignum_ffdhe2048_p, &_bignum_ffdhe2048_q, &_bignum_const_2
|
|
};
|
|
return do_dh_param_keygen(tstid, bn);
|
|
}
|
|
#endif /* OPENSSL_NO_DH */
|
|
|
|
static int test_cipher_reinit(int test_id)
|
|
{
|
|
int ret = 0, out1_len = 0, out2_len = 0, diff, ccm;
|
|
EVP_CIPHER *cipher = NULL;
|
|
EVP_CIPHER_CTX *ctx = NULL;
|
|
unsigned char out1[256];
|
|
unsigned char out2[256];
|
|
unsigned char in[16] = {
|
|
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
|
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
|
|
};
|
|
unsigned char key[64] = {
|
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
|
0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
|
0x02, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
|
0x03, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
|
};
|
|
unsigned char iv[16] = {
|
|
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
|
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
|
|
};
|
|
const char *name = sk_OPENSSL_CSTRING_value(cipher_names, test_id);
|
|
|
|
if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()))
|
|
goto err;
|
|
|
|
TEST_note("Fetching %s\n", name);
|
|
if (!TEST_ptr(cipher = EVP_CIPHER_fetch(libctx, name, NULL)))
|
|
goto err;
|
|
|
|
/* ccm fails on the second update - this matches OpenSSL 1_1_1 behaviour */
|
|
ccm = (EVP_CIPHER_mode(cipher) == EVP_CIPH_CCM_MODE);
|
|
|
|
/* DES3-WRAP uses random every update - so it will give a different value */
|
|
diff = EVP_CIPHER_is_a(cipher, "DES3-WRAP");
|
|
|
|
if (!TEST_true(EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv))
|
|
|| !TEST_true(EVP_EncryptUpdate(ctx, out1, &out1_len, in, sizeof(in)))
|
|
|| !TEST_true(EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
|
|
|| !TEST_int_eq(EVP_EncryptUpdate(ctx, out2, &out2_len, in, sizeof(in)),
|
|
ccm ? 0 : 1))
|
|
goto err;
|
|
|
|
if (ccm == 0) {
|
|
if (diff) {
|
|
if (!TEST_mem_ne(out1, out1_len, out2, out2_len))
|
|
goto err;
|
|
} else {
|
|
if (!TEST_mem_eq(out1, out1_len, out2, out2_len))
|
|
goto err;
|
|
}
|
|
}
|
|
ret = 1;
|
|
err:
|
|
EVP_CIPHER_free(cipher);
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
return ret;
|
|
}
|
|
|
|
static int name_cmp(const char * const *a, const char * const *b)
|
|
{
|
|
return strcasecmp(*a, *b);
|
|
}
|
|
|
|
static void collect_cipher_names(EVP_CIPHER *cipher, void *cipher_names_list)
|
|
{
|
|
STACK_OF(OPENSSL_CSTRING) *names = cipher_names_list;
|
|
|
|
sk_OPENSSL_CSTRING_push(names, EVP_CIPHER_name(cipher));
|
|
}
|
|
|
|
int setup_tests(void)
|
|
{
|
|
const char *prov_name = "default";
|
|
char *config_file = NULL;
|
|
OPTION_CHOICE o;
|
|
|
|
while ((o = opt_next()) != OPT_EOF) {
|
|
switch (o) {
|
|
case OPT_PROVIDER_NAME:
|
|
prov_name = opt_arg();
|
|
break;
|
|
case OPT_CONFIG_FILE:
|
|
config_file = opt_arg();
|
|
break;
|
|
case OPT_TEST_CASES:
|
|
break;
|
|
default:
|
|
case OPT_ERR:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
nullprov = OSSL_PROVIDER_load(NULL, "null");
|
|
if (!TEST_ptr(nullprov))
|
|
return 0;
|
|
|
|
libctx = OPENSSL_CTX_new();
|
|
|
|
if (!TEST_ptr(libctx))
|
|
return 0;
|
|
|
|
if (config_file != NULL) {
|
|
if (!TEST_true(OPENSSL_CTX_load_config(libctx, config_file)))
|
|
return 0;
|
|
}
|
|
|
|
libprov = OSSL_PROVIDER_load(libctx, prov_name);
|
|
if (!TEST_ptr(libprov))
|
|
return 0;
|
|
|
|
#ifndef OPENSSL_NO_DSA
|
|
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);
|
|
#endif
|
|
|
|
if (!TEST_ptr(cipher_names = sk_OPENSSL_CSTRING_new(name_cmp)))
|
|
return 0;
|
|
EVP_CIPHER_do_all_provided(libctx, collect_cipher_names, cipher_names);
|
|
|
|
ADD_ALL_TESTS(test_cipher_reinit, sk_OPENSSL_CSTRING_num(cipher_names));
|
|
return 1;
|
|
}
|
|
|
|
void cleanup_tests(void)
|
|
{
|
|
sk_OPENSSL_CSTRING_free(cipher_names);
|
|
OSSL_PROVIDER_unload(libprov);
|
|
OPENSSL_CTX_free(libctx);
|
|
OSSL_PROVIDER_unload(nullprov);
|
|
}
|