From bd2d5542f307ae0e9e98a291f0d765a0be58b5fd Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Sat, 13 Feb 2021 14:52:39 +0100 Subject: [PATCH] Making a gost provider - Add the ciphers We add the ciphers for the provider as wrappers around the routines designed for ENGINEs. This is not the most elegant, but it does the job. When an algorithm has an OID, it's included in the OSSL_ALGORITHM name as an aliase. This is the way to avoid having to register the OIDs in OpenSSL proper. test/03-encrypt.t is modified to test the provider as well. --- CMakeLists.txt | 1 + gost_lcl.h | 5 + gost_prov.c | 5 + gost_prov_cipher.c | 352 +++++++++++++++++++++++++++++++++++++++++++++ test/03-encrypt.t | 350 ++++++++++++++++++++++++++------------------ 5 files changed, 570 insertions(+), 143 deletions(-) create mode 100644 gost_prov_cipher.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 499fc7e..05645c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -199,6 +199,7 @@ set(GOST_ENGINE_SOURCE_FILES set(GOST_PROV_SOURCE_FILES gost_prov.c + gost_prov_cipher.c ) set(TEST_ENVIRONMENT_COMMON diff --git a/gost_lcl.h b/gost_lcl.h index 4801e17..edfabcf 100644 --- a/gost_lcl.h +++ b/gost_lcl.h @@ -337,6 +337,7 @@ typedef struct gost_cipher_st GOST_cipher; EVP_CIPHER *GOST_init_cipher(GOST_cipher *c); void GOST_deinit_cipher(GOST_cipher *c); +/* ENGINE implementation data */ extern GOST_cipher Gost28147_89_cipher; extern GOST_cipher Gost28147_89_cbc_cipher; extern GOST_cipher Gost28147_89_cnt_cipher; @@ -355,6 +356,10 @@ extern GOST_cipher grasshopper_ctr_acpkm_omac_cipher; extern GOST_cipher magma_kexp15_cipher; extern GOST_cipher kuznyechik_kexp15_cipher; +/* Provider implementation data */ +extern const OSSL_ALGORITHM GOST_prov_ciphers[]; +void GOST_prov_deinit_ciphers(void); + struct gost_digest_st { struct gost_digest_st *template; int nid; diff --git a/gost_prov.c b/gost_prov.c index fe65c4d..04f4f3d 100644 --- a/gost_prov.c +++ b/gost_prov.c @@ -86,6 +86,10 @@ static const OSSL_ALGORITHM *gost_operation(void *vprovctx, int operation_id, const int *no_cache) { + switch (operation_id) { + case OSSL_OP_CIPHER: + return GOST_prov_ciphers; + } return NULL; } @@ -105,6 +109,7 @@ static const OSSL_ITEM *gost_get_reason_strings(void *provctx) /* The function that tears down this provider */ static void gost_teardown(void *vprovctx) { + GOST_prov_deinit_ciphers(); provider_ctx_free(vprovctx); } diff --git a/gost_prov_cipher.c b/gost_prov_cipher.c new file mode 100644 index 0000000..d64b0ff --- /dev/null +++ b/gost_prov_cipher.c @@ -0,0 +1,352 @@ +/********************************************************************** + * gost_prov_crypt.c - Initialize all ciphers * + * * + * Copyright (c) 2021 Richard Levitte * + * This file is distributed under the same license as OpenSSL * + * * + * OpenSSL provider interface to GOST cipher functions * + * Requires OpenSSL 3.0 for compilation * + **********************************************************************/ + +#include +#include +#include "gost_prov.h" +#include "gost_lcl.h" + +/* + * Forward declarations of all generic OSSL_DISPATCH functions, to make sure + * they are correctly defined further down. For the algorithm specific ones + * MAKE_FUNCTIONS() does it for us. + */ +static OSSL_FUNC_cipher_dupctx_fn cipher_dupctx; +static OSSL_FUNC_cipher_freectx_fn cipher_freectx; +static OSSL_FUNC_cipher_get_ctx_params_fn cipher_get_ctx_params; +static OSSL_FUNC_cipher_set_ctx_params_fn cipher_set_ctx_params; +static OSSL_FUNC_cipher_encrypt_init_fn cipher_encrypt_init; +static OSSL_FUNC_cipher_decrypt_init_fn cipher_decrypt_init; +static OSSL_FUNC_cipher_update_fn cipher_update; +static OSSL_FUNC_cipher_final_fn cipher_final; + +struct gost_prov_crypt_ctx_st { + /* Provider context */ + PROV_CTX *provctx; + /* OSSL_PARAM descriptors */ + const OSSL_PARAM *known_params; + /* GOST_cipher descriptor */ + GOST_cipher *descriptor; + + /* + * Since existing functionality is designed for ENGINEs, the functions + * in this file are accomodated and are simply wrappers that use a local + * EVP_CIPHER and EVP_CIPHER_CTX. + * Future development should take a more direct approach and have the + * appropriate cipher functions and cipher data directly in this context. + */ + + /* The EVP_CIPHER created from |descriptor| */ + EVP_CIPHER *cipher; + /* The context for the EVP_CIPHER functions */ + EVP_CIPHER_CTX *cctx; +}; +typedef struct gost_prov_crypt_ctx_st GOST_CTX; + +static void cipher_freectx(void *vgctx) +{ + GOST_CTX *gctx = vgctx; + + /* + * We don't free gctx->cipher here. + * That will be done by the provider teardown, via + * GOST_prov_deinit_ciphers() (defined at the bottom of this file). + */ + EVP_CIPHER_CTX_free(gctx->cctx); + OPENSSL_free(gctx); +} + +static GOST_CTX *cipher_newctx(void *provctx, GOST_cipher *descriptor, + const OSSL_PARAM *known_params) +{ + GOST_CTX *gctx = NULL; + + if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) { + gctx->provctx = provctx; + gctx->known_params = known_params; + gctx->descriptor = descriptor; + gctx->cipher = GOST_init_cipher(descriptor); + gctx->cctx = EVP_CIPHER_CTX_new(); + + if (gctx->cipher == NULL || gctx->cctx == NULL) { + cipher_freectx(gctx); + gctx = NULL; + } + } + return gctx; +} + +static void *cipher_dupctx(void *vsrc) +{ + GOST_CTX *src = vsrc; + GOST_CTX *dst = + cipher_newctx(src->provctx, src->descriptor, src->known_params); + + if (dst != NULL) + EVP_CIPHER_CTX_copy(dst->cctx, src->cctx); + return dst; +} + +static int cipher_get_params(EVP_CIPHER *c, OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + if (((p = OSSL_PARAM_locate(params, "blocksize")) != NULL + && !OSSL_PARAM_set_size_t(p, EVP_CIPHER_block_size(c))) + || ((p = OSSL_PARAM_locate(params, "ivlen")) != NULL + && !OSSL_PARAM_set_size_t(p, EVP_CIPHER_iv_length(c))) + || ((p = OSSL_PARAM_locate(params, "keylen")) != NULL + && !OSSL_PARAM_set_size_t(p, EVP_CIPHER_key_length(c))) + || ((p = OSSL_PARAM_locate(params, "mode")) != NULL + && !OSSL_PARAM_set_size_t(p, EVP_CIPHER_flags(c)))) + return 0; + return 1; +} + +static int cipher_get_ctx_params(void *vgctx, OSSL_PARAM params[]) +{ + GOST_CTX *gctx = vgctx; + OSSL_PARAM *p; + + if (!cipher_get_params(gctx->cipher, params)) + return 0; + if ((p = OSSL_PARAM_locate(params, "alg_id_param")) != NULL) { + ASN1_TYPE *algidparam = NULL; + unsigned char *der = NULL; + int derlen = 0; + int ret; + + ret = (algidparam = ASN1_TYPE_new()) != NULL + && EVP_CIPHER_param_to_asn1(gctx->cctx, algidparam) > 0 + && (derlen = i2d_ASN1_TYPE(algidparam, &der)) >= 0 + && OSSL_PARAM_set_octet_string(p, &der, (size_t)derlen); + + OPENSSL_free(der); + ASN1_TYPE_free(algidparam); + return ret; + } + if ((p = OSSL_PARAM_locate(params, "updated-iv")) != NULL) { + const void *iv = EVP_CIPHER_CTX_iv(gctx->cctx); + size_t ivlen = EVP_CIPHER_CTX_iv_length(gctx->cctx); + + if (!OSSL_PARAM_set_octet_ptr(p, iv, ivlen) + && !OSSL_PARAM_set_octet_string(p, iv, ivlen)) + return 0; + } + return 1; +} + +static int cipher_set_ctx_params(void *vgctx, const OSSL_PARAM params[]) +{ + GOST_CTX *gctx = vgctx; + const OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate_const(params, "alg_id_param")) != NULL) { + ASN1_TYPE *algidparam = NULL; + const unsigned char *der = NULL; + size_t derlen = 0; + int ret; + + ret = OSSL_PARAM_get_octet_string_ptr(p, (const void **)&der, &derlen) + && (algidparam = d2i_ASN1_TYPE(NULL, &der, (long)derlen)) != NULL + && EVP_CIPHER_asn1_to_param(gctx->cctx, algidparam) > 0; + + ASN1_TYPE_free(algidparam); + return ret; + } + if ((p = OSSL_PARAM_locate_const(params, "padding")) != NULL) { + unsigned int pad = 0; + + if (!OSSL_PARAM_get_uint(p, &pad) + || EVP_CIPHER_CTX_set_padding(gctx->cctx, pad) <= 0) + return 0; + } + if ((p = OSSL_PARAM_locate_const(params, "key-mesh")) != NULL) { + size_t key_mesh = 0; + + if (!OSSL_PARAM_get_size_t(p, &key_mesh) + || EVP_CIPHER_CTX_ctrl(gctx->cctx, EVP_CTRL_KEY_MESH, + key_mesh, NULL) <= 0) + return 0; + } + return 1; +} + +static int cipher_encrypt_init(void *vgctx, + const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + GOST_CTX *gctx = vgctx; + + if (!cipher_set_ctx_params(vgctx, params) + || keylen > EVP_CIPHER_key_length(gctx->cipher) + || ivlen > EVP_CIPHER_iv_length(gctx->cipher)) + return 0; + return EVP_CipherInit_ex(gctx->cctx, gctx->cipher, gctx->provctx->e, + key, iv, 1); +} + +static int cipher_decrypt_init(void *vgctx, + const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + GOST_CTX *gctx = vgctx; + + if (!cipher_set_ctx_params(vgctx, params) + || keylen > EVP_CIPHER_key_length(gctx->cipher) + || ivlen > EVP_CIPHER_iv_length(gctx->cipher)) + return 0; + return EVP_CipherInit_ex(gctx->cctx, gctx->cipher, gctx->provctx->e, + key, iv, 0) > 0; +} + +static int cipher_update(void *vgctx, + unsigned char *out, size_t *outl, size_t outsize, + const unsigned char *in, size_t inl) +{ + GOST_CTX *gctx = vgctx; + int int_outl = outl != NULL ? *outl : 0; + int res = EVP_CipherUpdate(gctx->cctx, out, &int_outl, in, (int)inl); + + if (res > 0 && outl != NULL) + *outl = (size_t)int_outl; + return res > 0; +} + +static int cipher_final(void *vgctx, + unsigned char *out, size_t *outl, size_t outsize) +{ + GOST_CTX *gctx = vgctx; + int int_outl = outl != NULL ? *outl : 0; + int res = EVP_CipherFinal(gctx->cctx, out, &int_outl); + + if (res > 0 && outl != NULL) + *outl = (size_t)int_outl; + return res > 0; +} + +static const OSSL_PARAM known_Gost28147_89_cipher_params[] = {}; +static const OSSL_PARAM known_Gost28147_89_cbc_cipher_params[] = {}; +static const OSSL_PARAM known_Gost28147_89_cnt_cipher_params[] = {}; +static const OSSL_PARAM known_Gost28147_89_cnt_12_cipher_params[] = {}; +static const OSSL_PARAM known_grasshopper_ecb_cipher_params[] = {}; +static const OSSL_PARAM known_grasshopper_cbc_cipher_params[] = {}; +static const OSSL_PARAM known_grasshopper_cfb_cipher_params[] = {}; +static const OSSL_PARAM known_grasshopper_ofb_cipher_params[] = {}; +static const OSSL_PARAM known_grasshopper_ctr_cipher_params[] = {}; +static const OSSL_PARAM known_magma_ctr_cipher_params[] = {}; +static const OSSL_PARAM known_magma_ctr_acpkm_cipher_params[] = {}; +static const OSSL_PARAM known_magma_ctr_acpkm_omac_cipher_params[] = {}; +static const OSSL_PARAM known_magma_cbc_cipher_params[] = {}; +static const OSSL_PARAM known_grasshopper_ctr_acpkm_cipher_params[] = {}; +static const OSSL_PARAM known_grasshopper_ctr_acpkm_omac_cipher_params[] = {}; +/* + * These are named like the EVP_CIPHER templates in gost_crypt.c, with the + * added suffix "_functions". Hopefully, that makes it easy to find the + * actual implementation. + */ +typedef void (*fptr_t)(void); +#define MAKE_FUNCTIONS(name) \ + static OSSL_FUNC_cipher_get_params_fn name##_get_params; \ + static int name##_get_params(OSSL_PARAM *params) \ + { \ + return cipher_get_params(GOST_init_cipher(&name), params); \ + } \ + static OSSL_FUNC_cipher_newctx_fn name##_newctx; \ + static void *name##_newctx(void *provctx) \ + { \ + return cipher_newctx(provctx, &name, known_##name##_params); \ + } \ + static const OSSL_DISPATCH name##_functions[] = { \ + { OSSL_FUNC_CIPHER_GET_PARAMS, (fptr_t)name##_get_params }, \ + { OSSL_FUNC_CIPHER_NEWCTX, (fptr_t)name##_newctx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (fptr_t)cipher_dupctx }, \ + { OSSL_FUNC_CIPHER_FREECTX, (fptr_t)cipher_freectx }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, (fptr_t)cipher_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, (fptr_t)cipher_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (fptr_t)cipher_encrypt_init }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (fptr_t)cipher_decrypt_init }, \ + { OSSL_FUNC_CIPHER_UPDATE, (fptr_t)cipher_update }, \ + { OSSL_FUNC_CIPHER_FINAL, (fptr_t)cipher_final }, \ + } + +MAKE_FUNCTIONS(Gost28147_89_cipher); +MAKE_FUNCTIONS(Gost28147_89_cnt_cipher); +MAKE_FUNCTIONS(Gost28147_89_cnt_12_cipher); +MAKE_FUNCTIONS(Gost28147_89_cbc_cipher); +MAKE_FUNCTIONS(grasshopper_ecb_cipher); +MAKE_FUNCTIONS(grasshopper_cbc_cipher); +MAKE_FUNCTIONS(grasshopper_cfb_cipher); +MAKE_FUNCTIONS(grasshopper_ofb_cipher); +MAKE_FUNCTIONS(grasshopper_ctr_cipher); +MAKE_FUNCTIONS(magma_cbc_cipher); +MAKE_FUNCTIONS(magma_ctr_cipher); +MAKE_FUNCTIONS(magma_ctr_acpkm_cipher); +MAKE_FUNCTIONS(magma_ctr_acpkm_omac_cipher); +MAKE_FUNCTIONS(grasshopper_ctr_acpkm_cipher); +MAKE_FUNCTIONS(grasshopper_ctr_acpkm_omac_cipher); + +/* The OSSL_ALGORITHM for the provider's operation query function */ +const OSSL_ALGORITHM GOST_prov_ciphers[] = { + { SN_id_Gost28147_89 ":gost89:GOST 28147-89:1.2.643.2.2.21", NULL, + Gost28147_89_cipher_functions }, + { SN_gost89_cnt, NULL, Gost28147_89_cnt_cipher_functions }, + { SN_gost89_cnt_12, NULL, Gost28147_89_cnt_12_cipher_functions }, + { SN_gost89_cbc, NULL, Gost28147_89_cbc_cipher_functions }, + { SN_grasshopper_ecb, NULL, grasshopper_ecb_cipher_functions }, + { SN_grasshopper_cbc, NULL, grasshopper_cbc_cipher_functions }, + { SN_grasshopper_cfb, NULL, grasshopper_cfb_cipher_functions }, + { SN_grasshopper_ofb, NULL, grasshopper_ofb_cipher_functions }, + { SN_grasshopper_ctr, NULL, grasshopper_ctr_cipher_functions }, + { SN_magma_cbc, NULL, magma_cbc_cipher_functions }, + { SN_magma_ctr, NULL, magma_ctr_cipher_functions }, + { SN_magma_ctr_acpkm ":1.2.643.7.1.1.5.1.1", NULL, + magma_ctr_acpkm_cipher_functions }, + { SN_magma_ctr_acpkm_omac ":1.2.643.7.1.1.5.1.2", NULL, + magma_ctr_acpkm_omac_cipher_functions }, + { SN_kuznyechik_ctr_acpkm ":1.2.643.7.1.1.5.2.1", NULL, + grasshopper_ctr_acpkm_cipher_functions }, + { SN_kuznyechik_ctr_acpkm_omac ":1.2.643.7.1.1.5.2.2", NULL, + grasshopper_ctr_acpkm_omac_cipher_functions }, +#if 0 /* Not yet implemented */ + { SN_magma_kexp15 ":1.2.643.7.1.1.7.1.1", NULL, + magma_kexp15_cipher_functions }, + { SN_kuznyechik_kexp15 ":1.2.643.7.1.1.7.2.1", NULL, + kuznyechik_kexp15_cipher_functions }, +#endif + { NULL , NULL, NULL } +}; + +void GOST_prov_deinit_ciphers(void) { + static GOST_cipher *list[] = { + &Gost28147_89_cipher, + &Gost28147_89_cnt_cipher, + &Gost28147_89_cnt_12_cipher, + &Gost28147_89_cbc_cipher, + &grasshopper_ecb_cipher, + &grasshopper_cbc_cipher, + &grasshopper_cfb_cipher, + &grasshopper_ofb_cipher, + &grasshopper_ctr_cipher, + &magma_cbc_cipher, + &magma_ctr_cipher, + &magma_ctr_acpkm_cipher, + &magma_ctr_acpkm_omac_cipher, + &grasshopper_ctr_acpkm_cipher, + &grasshopper_ctr_acpkm_omac_cipher, + }; + size_t i; +#define elems(l) (sizeof(l) / sizeof(l[0])) + + for (i = 0; i < elems(list); i++) + GOST_deinit_cipher(list[i]); +} diff --git a/test/03-encrypt.t b/test/03-encrypt.t index 5b25f30..91e8876 100644 --- a/test/03-encrypt.t +++ b/test/03-encrypt.t @@ -1,160 +1,224 @@ #!/usr/bin/perl use Test2::V0; -skip_all('TODO: add symmetric cipher support in provider') - unless $ARGV[0] eq 'engine'; -plan(48); use Cwd 'abs_path'; -# -# If this variable is set, engine would be loaded via configuration -# file. Otherwise - via command line -# -my $use_config = 1; - -# prepare data for - -my $key='0123456789abcdef' x 2; +my $engine_name = $ENV{ENGINE_NAME} || 'gost'; +my $provider_name = $ENV{PROVIDER_NAME} || 'gostprov'; +# Supported test types: # -# You can redefine engine to use using ENGINE_NAME environment variable -# -my $engine=$ENV{'ENGINE_NAME'}||"gost"; +# conf Only if there's a command line argument. +# For this test type, we rely entirely on the +# caller to define the environment variable +# OPENSSL_CONF appropriately. +# standalone-engine-conf Tests the engine through a generated config +# file. +# This is done when there are no command line +# arguments or when the environment variable +# ENGINE_NAME is defined. +# standalone-engine-args Tests the engine through openssl command args. +# This is done when there are no command line +# arguments or when the environment variable +# ENGINE_NAME is defined. +# standalone-provider-conf Tests the provider through a generated config +# file. +# This is done when there are no command line +# arguments or when the environment variable +# PROVIDER_NAME is defined. +# standalone-provider-args Tests the provider through openssl command args. +# This is done when there are no command line +# arguments or when the environment variable +# PROVIDER_NAME is defined. +my @test_types = ( $ARGV[0] ? 'conf' : (), + ( !$ARGV[0] || $ENV{ENGINE_NAME} + ? ( 'standalone-engine-conf', 'standalone-engine-args' ) + : () ), + ( !$ARGV[0] || $ENV{PROVIDER_NAME} + ? ( 'standalone-provider-conf', 'standalone-provider-args' ) + : () ) ); + +plan(48 * scalar @test_types); + +# prepare data for -# Reopen STDERR to eliminate extra output -open STDERR, ">>","tests.err"; - -our $count=0; +my $key='0123456789abcdef' x 2; -# -# parameters -paramset = oid of the parameters -# -cleartext - data to encrypt -# -ciphertext - expected ciphertext (hex-encoded) -# -key - key (hex-encoded) -# -iv - IV (hex-encoded) -# -my $F; -my $eng_param; - -open $F,">","test.cnf"; -if (defined($use_config) && $use_config) { - $eng_param = ""; - open $F,">","test.cnf"; - print $F < { + 'openssl-args' => "-engine $engine_name", + }, + 'standalone-provider-args' => { + 'openssl-args' => "-provider $provider_name -provider default", + }, + 'standalone-engine-conf' => { + 'openssl-conf' => < { + 'openssl-conf' => <", "test$count.clear"; - print $f $p{-cleartext}; - close $f; - - $ENV{'CRYPT_PARAMS'} = $p{-paramset} if exists $p{-paramset}; - my $ctext = `openssl enc ${eng_param} -e -$p{-alg} -K $p{-key} -iv $p{-iv} -in test$count.clear`; - is($?,0,"$p{-name} - encrypt successful"); - is(unpack("H*",$ctext),$p{-ciphertext},"$p{-name} - ciphertext expected"); - open $f, ">", "test$count.enc"; - print $f $ctext; - close $f; - my $otext = `openssl enc ${eng_param} -d -$p{-alg} -K $p{-key} -iv $p{-iv} -in test$count.enc`; - is($?,0,"$p{-name} - decrypt successful"); - is($otext,$p{-cleartext},"$p{-name} - decrypted correctly"); - unlink "test$count.enc"; - unlink "test$count.clear"; - delete $ENV{'CRYPT_PARAMS'}; + my %p = @_; + my $test_type = $p{-testtype}; + my $args = $p{-args}; + my $count = ++${$p{-count}}; + my $result_name = "$test_type$count"; + open my $f, ">", "$result_name.clear"; + print $f $p{-cleartext}; + close $f; + + $ENV{'CRYPT_PARAMS'} = $p{-paramset} if exists $p{-paramset}; + my $ccmd = "openssl enc${args} -e -$p{-alg} -K $p{-key} -iv $p{-iv} -in $result_name.clear"; + my $ctext = `$ccmd`; + unless (is($?,0,"$p{-name} - Trying to encrypt")) { + diag("Command was: $ccmd"); + } + is(unpack("H*",$ctext),$p{-ciphertext},"$p{-name} - Checking that it encrypted correctly"); + open $f, ">", "$result_name.enc"; + print $f $ctext; + close $f; + my $ocmd = "openssl enc${args} -d -$p{-alg} -K $p{-key} -iv $p{-iv} -in $result_name.enc"; + my $otext = `$ocmd`; + unless(is($?,0,"$p{-name} - Trying to decrypt")) { + diag("Command was: $ocmd"); + } + is($otext,$p{-cleartext},"$p{-name} - Checking that it decrypted correctly"); + unlink "$result_name.enc"; + unlink "$result_name.clear"; + delete $ENV{'CRYPT_PARAMS'}; } -$key = '0123456789ABCDEF' x 4; -my $iv = '0000000000000000'; -my $clear1 = "The quick brown fox jumps over the lazy dog\n"; - -crypt_test(-paramset=> "1.2.643.2.2.31.1", -key => $key, -iv => $iv, - -cleartext => $clear1, - -ciphertext => '07f4102c6185c4a09e676e269bfa4bc9c5df6575916b879bd13a893a2285ee6690107cdeef7a315d2eb54bfa', - -alg => 'gost89', - -name=> 'CFB short text, paramset A'); - -crypt_test(-paramset=> "1.2.643.2.2.31.2", -key => $key, -iv => $iv, - -cleartext => $clear1, - -ciphertext => '11465c1c9708033e784fbb5536f2719c38353cb488b01f195c20d4c027022e8300d98bb66c138afbe878c88b', - -alg => 'gost89', - -name=> 'CFB short text, paramset B'); - -crypt_test(-paramset=> "1.2.643.2.2.31.3", -key => $key, -iv => $iv, - -cleartext => $clear1, - -ciphertext => '2f213b390c9b6ceb18de479686d23f4f03c76644a0aab8894b50b71a3bbb3c027ec4c2d569ba0e6a873bd46e', - -alg => 'gost89', - -name=> 'CFB short text, paramset C'); - -crypt_test(-paramset=> "1.2.643.2.2.31.4", -key => $key, -iv => $iv, - -cleartext => $clear1, - -ciphertext => 'e835f59a7fdfd84764efe1e987660327f5d0de187afea72f9cd040983a5e5bbeb4fe1aa5ff85d623ebc4d435', - -alg => 'gost89', - -name=> 'CFB short text, paramset D'); - - -crypt_test(-paramset=> "1.2.643.2.2.31.1", -key => $key, -iv => $iv, - -cleartext => $clear1, - -ciphertext => 'bcb821452e459f10f92019171e7c3b27b87f24b174306667f67704812c07b70b5e7420f74a9d54feb4897df8', - -alg => 'gost89-cnt', - -name=> 'CNT short text'); - -crypt_test(-paramset=> "1.2.643.2.2.31.2", -key => $key, -iv => $iv, - -cleartext => $clear1, - -ciphertext => 'bcb821452e459f10f92019171e7c3b27b87f24b174306667f67704812c07b70b5e7420f74a9d54feb4897df8', - -alg => 'gost89-cnt', - -name=> 'CNT short text, paramset param doesnt affect cnt'); - - -crypt_test(-paramset=> "1.2.643.2.2.31.1", -key => $key, -iv => $iv, - -cleartext => $clear1, - -ciphertext => 'cf3f5f713b3d10abd0c6f7bafb6aaffe13dfc12ef5c844f84873aeaaf6eb443a9747c9311b86f97ba3cdb5c4', - -alg => 'gost89-cnt-12', - -name=> 'CNT-12 short text'); - -crypt_test(-paramset=> "1.2.643.2.2.31.2", -key => $key, -iv => $iv, - -cleartext => $clear1, - -ciphertext => 'cf3f5f713b3d10abd0c6f7bafb6aaffe13dfc12ef5c844f84873aeaaf6eb443a9747c9311b86f97ba3cdb5c4', - -alg => 'gost89-cnt-12', - -name=> 'CNT-12 short text, paramset param doesnt affect cnt'); - - -crypt_test(-paramset=> "1.2.643.2.2.31.1", -key => $key, -iv => $iv, - -cleartext => $clear1, - -ciphertext => '3a3293e75089376572da44966cd1759c29d2f1e5e1c3fa9674909a63026da3dc51a4266bff37fb74a3a07155c9ca8fcf', - -alg => 'gost89-cbc', - -name=> 'CBC short text, paramset A'); - - -crypt_test(-paramset=> "1.2.643.2.2.31.2", -key => $key, -iv => $iv, - -cleartext => $clear1, - -ciphertext => 'af2a2167b75852378af176ac9950e3c4bffc94d3d4355191707adbb16d6c8e3f3a07868c4702babef18393edfac60a6d', - -alg => 'gost89-cbc', - -name=> 'CBC short text, paramset B'); - -crypt_test(-paramset=> "1.2.643.2.2.31.3", -key => $key, -iv => $iv, - -cleartext => $clear1, - -ciphertext => '987c0fb3d84530467a1973791e0a25e33c5d14591976f8c1573bdb9d056eb7b353f66fef3ffe2e3524583b3997123c8a', - -alg => 'gost89-cbc', - -name=> 'CBC short text, paramset C'); - -crypt_test(-paramset=> "1.2.643.2.2.31.4", -key => $key, -iv => $iv, - -cleartext => $clear1, - -ciphertext => 'e076b09822d4786a2863125d16594d765d8acd0f360e52df42e9d52c8e6c0e6595b5f6bbecb04a22c8ae5f4f87c1523b', - -alg => 'gost89-cbc', - -name=> 'CBC short text, paramset D'); - -unlink "test.cnf"; +foreach my $test_type (@test_types) { + my $configuration = $configurations{$test_type}; + my $module_args = $configuration->{'openssl-args'} // ''; + my $module_conf = $configuration->{'openssl-conf'}; + # This is a trick to make a locally modifiable environment variable and + # retain it's current value as a default. + local $ENV{OPENSSL_CONF} = $ENV{OPENSSL_CONF}; + + note("Running tests for test type $test_type"); + + if ($module_args) { + $module_args = ' ' . $module_args; + } + if (defined $module_conf) { + my $confname = "$test_type.cnf"; + open my $F, '>', $confname; + print $F $module_conf; + close $F; + $ENV{OPENSSL_CONF} = abs_path($confname); + } + + # Reopen STDERR to eliminate extra output + #open STDERR, ">>","tests.err"; + + my $count=0; + + # + # parameters -paramset = oid of the parameters + # -cleartext - data to encrypt + # -ciphertext - expected ciphertext (hex-encoded) + # -key - key (hex-encoded) + # -iv - IV (hex-encoded) + # + $key = '0123456789ABCDEF' x 4; + my $iv = '0000000000000000'; + my $clear1 = "The quick brown fox jumps over the lazy dog\n"; + my @common_args = ( -count => \$count, + -args => $module_args, + -key => $key, + -iv => $iv, + -cleartext => $clear1 ); + + crypt_test(-paramset => "1.2.643.2.2.31.1", + -ciphertext => '07f4102c6185c4a09e676e269bfa4bc9c5df6575916b879bd13a893a2285ee6690107cdeef7a315d2eb54bfa', + -alg => 'gost89', + -name => 'CFB short text, paramset A', + @common_args); + + crypt_test(-paramset => "1.2.643.2.2.31.2", + -ciphertext => '11465c1c9708033e784fbb5536f2719c38353cb488b01f195c20d4c027022e8300d98bb66c138afbe878c88b', + -alg => 'gost89', + -name => 'CFB short text, paramset B', + @common_args); + + crypt_test(-paramset => "1.2.643.2.2.31.3", + -ciphertext => '2f213b390c9b6ceb18de479686d23f4f03c76644a0aab8894b50b71a3bbb3c027ec4c2d569ba0e6a873bd46e', + -alg => 'gost89', + -name => 'CFB short text, paramset C', + @common_args); + + crypt_test(-paramset => "1.2.643.2.2.31.4", + -ciphertext => 'e835f59a7fdfd84764efe1e987660327f5d0de187afea72f9cd040983a5e5bbeb4fe1aa5ff85d623ebc4d435', + -alg => 'gost89', + -name => 'CFB short text, paramset D', + @common_args); + + crypt_test(-paramset => "1.2.643.2.2.31.1", + -ciphertext => 'bcb821452e459f10f92019171e7c3b27b87f24b174306667f67704812c07b70b5e7420f74a9d54feb4897df8', + -alg => 'gost89-cnt', + -name => 'CNT short text', + @common_args); + + crypt_test(-paramset => "1.2.643.2.2.31.2", + -ciphertext => 'bcb821452e459f10f92019171e7c3b27b87f24b174306667f67704812c07b70b5e7420f74a9d54feb4897df8', + -alg => 'gost89-cnt', + -name => 'CNT short text, paramset param doesnt affect cnt', + @common_args); + + crypt_test(-paramset => "1.2.643.2.2.31.1", + -ciphertext => 'cf3f5f713b3d10abd0c6f7bafb6aaffe13dfc12ef5c844f84873aeaaf6eb443a9747c9311b86f97ba3cdb5c4', + -alg => 'gost89-cnt-12', + -name => 'CNT-12 short text', + @common_args); + + crypt_test(-paramset => "1.2.643.2.2.31.2", + -ciphertext => 'cf3f5f713b3d10abd0c6f7bafb6aaffe13dfc12ef5c844f84873aeaaf6eb443a9747c9311b86f97ba3cdb5c4', + -alg => 'gost89-cnt-12', + -name => 'CNT-12 short text, paramset param doesnt affect cnt', + @common_args); + + crypt_test(-paramset => "1.2.643.2.2.31.1", + -ciphertext => '3a3293e75089376572da44966cd1759c29d2f1e5e1c3fa9674909a63026da3dc51a4266bff37fb74a3a07155c9ca8fcf', + -alg => 'gost89-cbc', + -name => 'CBC short text, paramset A', + @common_args); + + crypt_test(-paramset => "1.2.643.2.2.31.2", + -ciphertext => 'af2a2167b75852378af176ac9950e3c4bffc94d3d4355191707adbb16d6c8e3f3a07868c4702babef18393edfac60a6d', + -alg => 'gost89-cbc', + -name => 'CBC short text, paramset B', + @common_args); + + crypt_test(-paramset => "1.2.643.2.2.31.3", + -ciphertext => '987c0fb3d84530467a1973791e0a25e33c5d14591976f8c1573bdb9d056eb7b353f66fef3ffe2e3524583b3997123c8a', + -alg => 'gost89-cbc', + -name => 'CBC short text, paramset C', + @common_args); + + crypt_test(-paramset => "1.2.643.2.2.31.4", + -ciphertext => 'e076b09822d4786a2863125d16594d765d8acd0f360e52df42e9d52c8e6c0e6595b5f6bbecb04a22c8ae5f4f87c1523b', + -alg => 'gost89-cbc', + -name => 'CBC short text, paramset D', + @common_args); + + if (defined $module_conf) { + unlink "$test_type.cnf"; + } +} -- 2.39.5