]> www.wagner.pp.ru Git - openssl-gost/engine.git/commitdiff
Making a gost provider - Add the digests
authorRichard Levitte <richard@levitte.org>
Sat, 13 Feb 2021 13:56:17 +0000 (14:56 +0100)
committerDmitry Belyavskiy <beldmit@users.noreply.github.com>
Mon, 11 Oct 2021 16:34:09 +0000 (19:34 +0300)
We add the digests 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/01-digest.t is modified to test the provider as well.

CMakeLists.txt
gost_lcl.h
gost_prov.c
gost_prov_digest.c [new file with mode: 0644]
test/01-digest.t

index 05645c32c22e1ef54fcdb0bab039cb03eccc5ee4..c95e5ea49cf1593f7388ed8d1fd1337c22557ed8 100644 (file)
@@ -200,6 +200,7 @@ set(GOST_ENGINE_SOURCE_FILES
 set(GOST_PROV_SOURCE_FILES
         gost_prov.c
         gost_prov_cipher.c
+        gost_prov_digest.c
         )
 
 set(TEST_ENVIRONMENT_COMMON
index edfabcfd173d97479e086dfd2b4e065337d96607..0e544eee66e6b91941399fbb7493eddcf4b1997d 100644 (file)
@@ -381,6 +381,7 @@ typedef struct gost_digest_st GOST_digest;
 EVP_MD *GOST_init_digest(GOST_digest *d);
 void GOST_deinit_digest(GOST_digest *d);
 
+/* ENGINE implementation data */
 extern GOST_digest GostR3411_94_digest;
 extern GOST_digest Gost28147_89_MAC_digest;
 extern GOST_digest Gost28147_89_mac_12_digest;
@@ -390,5 +391,9 @@ extern GOST_digest magma_mac_digest;
 extern GOST_digest grasshopper_mac_digest;
 extern GOST_digest kuznyechik_ctracpkm_omac_digest;
 
+/* Provider implementation data */
+extern const OSSL_ALGORITHM GOST_prov_digests[];
+void GOST_prov_deinit_digests(void);
+
 #endif
 /* vim: set expandtab cinoptions=\:0,l1,t0,g0,(0 sw=4 : */
index 04f4f3de4f59b9c1adf7be0bdd1d12aaff64b400..ba7120b094a2328304d7fd6aa39e280c69337318 100644 (file)
@@ -89,6 +89,8 @@ static const OSSL_ALGORITHM *gost_operation(void *vprovctx,
     switch (operation_id) {
     case OSSL_OP_CIPHER:
         return GOST_prov_ciphers;
+    case OSSL_OP_DIGEST:
+        return GOST_prov_digests;
     }
     return NULL;
 }
@@ -110,6 +112,7 @@ static const OSSL_ITEM *gost_get_reason_strings(void *provctx)
 static void gost_teardown(void *vprovctx)
 {
     GOST_prov_deinit_ciphers();
+    GOST_prov_deinit_digests();
     provider_ctx_free(vprovctx);
 }
 
diff --git a/gost_prov_digest.c b/gost_prov_digest.c
new file mode 100644 (file)
index 0000000..9acd005
--- /dev/null
@@ -0,0 +1,200 @@
+/**********************************************************************
+ *             gost_prov_digest.c - Initialize all digests            *
+ *                                                                    *
+ *      Copyright (c) 2021 Richard Levitte <richard@levitte.org>      *
+ *     This file is distributed under the same license as OpenSSL     *
+ *                                                                    *
+ *         OpenSSL provider interface to GOST digest functions        *
+ *                Requires OpenSSL 3.0 for compilation                *
+ **********************************************************************/
+
+#include <openssl/core.h>
+#include <openssl/core_dispatch.h>
+#include "gost_prov.h"
+#include "gost_lcl.h"
+
+/*
+ * Forward declarations of all OSSL_DISPATCH functions, to make sure they
+ * are correctly defined further down.
+ */
+static OSSL_FUNC_digest_dupctx_fn digest_dupctx;
+static OSSL_FUNC_digest_freectx_fn digest_freectx;
+static OSSL_FUNC_digest_init_fn digest_init;
+static OSSL_FUNC_digest_update_fn digest_update;
+static OSSL_FUNC_digest_final_fn digest_final;
+
+
+struct gost_prov_crypt_ctx_st {
+    /* Provider context */
+    PROV_CTX *provctx;
+    /* OSSL_PARAM descriptors */
+    const OSSL_PARAM *known_params;
+    /* GOST_digest descriptor */
+    GOST_digest *descriptor;
+
+    /*
+     * Since existing functionality is designed for ENGINEs, the functions
+     * in this file are accomodated and are simply wrappers that use a local
+     * EVP_MD and EVP_MD_CTX.
+     * Future development should take a more direct approach and have the
+     * appropriate digest functions and digest data directly in this context.
+     */
+
+    /* The EVP_MD created from |descriptor| */
+    EVP_MD *digest;
+    /* The context for the EVP_MD functions */
+    EVP_MD_CTX *dctx;
+};
+typedef struct gost_prov_crypt_ctx_st GOST_CTX;
+
+static void digest_freectx(void *vgctx)
+{
+    GOST_CTX *gctx = vgctx;
+
+    /*
+     * We don't free gctx->digest here.
+     * That will be done by the provider teardown, via
+     * GOST_prov_deinit_digests() (defined at the bottom of this file).
+     */
+    EVP_MD_CTX_free(gctx->dctx);
+    OPENSSL_free(gctx);
+}
+
+static GOST_CTX *digest_newctx(void *provctx, GOST_digest *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->digest = GOST_init_digest(descriptor);
+        gctx->dctx = EVP_MD_CTX_new();
+
+        if (gctx->digest == NULL || gctx->dctx == NULL) {
+            digest_freectx(gctx);
+            gctx = NULL;
+        }
+    }
+    return gctx;
+}
+
+static void *digest_dupctx(void *vsrc)
+{
+    GOST_CTX *src = vsrc;
+    GOST_CTX *dst =
+        digest_newctx(src->provctx, src->descriptor, src->known_params);
+
+    if (dst != NULL)
+        EVP_MD_CTX_copy(dst->dctx, src->dctx);
+    return dst;
+}
+
+static int digest_get_params(EVP_MD *d, OSSL_PARAM params[])
+{
+    OSSL_PARAM *p;
+
+    if (((p = OSSL_PARAM_locate(params, "blocksize")) != NULL
+         && !OSSL_PARAM_set_size_t(p, EVP_MD_block_size(d)))
+        || ((p = OSSL_PARAM_locate(params, "size")) != NULL
+            && !OSSL_PARAM_set_size_t(p, EVP_MD_size(d)))
+        || ((p = OSSL_PARAM_locate(params, "xof")) != NULL
+            && !OSSL_PARAM_set_size_t(p, EVP_MD_flags(d) & EVP_MD_FLAG_XOF)))
+        return 0;
+    return 1;
+}
+
+static int digest_init(void *vgctx, const OSSL_PARAM unused_params[])
+{
+    GOST_CTX *gctx = vgctx;
+
+    return EVP_DigestInit_ex(gctx->dctx, gctx->digest, gctx->provctx->e) > 0;
+}
+
+static int digest_update(void *vgctx, const unsigned char *in, size_t inl)
+{
+    GOST_CTX *gctx = vgctx;
+
+    return EVP_DigestUpdate(gctx->dctx, in, (int)inl) > 0;
+}
+
+static int digest_final(void *vgctx,
+                        unsigned char *out, size_t *outl, size_t outsize)
+{
+    GOST_CTX *gctx = vgctx;
+    unsigned int int_outl = outl != NULL ? *outl : 0;
+    int res = EVP_DigestFinal(gctx->dctx, out, &int_outl);
+
+    if (res > 0 && outl != NULL)
+        *outl = (size_t)int_outl;
+    return res > 0;
+}
+
+static const OSSL_PARAM known_GostR3411_94_digest_params[] = {};
+static const OSSL_PARAM known_GostR3411_2012_256_digest_params[] = {};
+static const OSSL_PARAM known_GostR3411_2012_512_digest_params[] = {};
+
+/*
+ * These are named like the EVP_MD templates in gost_md.c etc, 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_digest_get_params_fn name##_get_params;            \
+    static int name##_get_params(OSSL_PARAM *params)                    \
+    {                                                                   \
+        return digest_get_params(GOST_init_digest(&name), params);      \
+    }                                                                   \
+    static OSSL_FUNC_digest_newctx_fn name##_newctx;                    \
+    static void *name##_newctx(void *provctx)                           \
+    {                                                                   \
+        return digest_newctx(provctx, &name, known_##name##_params);    \
+    }                                                                   \
+    static const OSSL_DISPATCH name##_functions[] = {                   \
+        { OSSL_FUNC_DIGEST_GET_PARAMS, (fptr_t)name##_get_params },     \
+        { OSSL_FUNC_DIGEST_NEWCTX, (fptr_t)name##_newctx },             \
+        { OSSL_FUNC_DIGEST_DUPCTX, (fptr_t)digest_dupctx },             \
+        { OSSL_FUNC_DIGEST_FREECTX, (fptr_t)digest_freectx },           \
+        { OSSL_FUNC_DIGEST_INIT, (fptr_t)digest_init },                 \
+        { OSSL_FUNC_DIGEST_UPDATE, (fptr_t)digest_update },             \
+        { OSSL_FUNC_DIGEST_FINAL, (fptr_t)digest_final },               \
+    }
+
+MAKE_FUNCTIONS(GostR3411_94_digest);
+MAKE_FUNCTIONS(GostR3411_2012_256_digest);
+MAKE_FUNCTIONS(GostR3411_2012_512_digest);
+
+/* The OSSL_ALGORITHM for the provider's operation query function */
+const OSSL_ALGORITHM GOST_prov_digests[] = {
+    /*
+     * Described in RFC 6986, first name from
+     * https://www.ietf.org/archive/id/draft-deremin-rfc4491-bis-06.txt
+     * (is there not an RFC namming these?)
+     */
+    { "id-tc26-gost3411-12-256:md_gost12_256:1.2.643.7.1.1.2.2", NULL,
+      GostR3411_2012_256_digest_functions,
+      "GOST R 34.11-2012 with 256 bit hash" },
+    { "id-tc26-gost3411-12-512:md_gost12_512:1.2.643.7.1.1.2.3", NULL,
+      GostR3411_2012_512_digest_functions,
+      "GOST R 34.11-2012 with 512 bit hash" },
+
+    /* Described in RFC 5831, first name from RFC 4357, section 10.4 */
+    { "id-GostR3411-94:md_gost94:1.2.643.2.2.9", NULL,
+      GostR3411_94_digest_functions, "GOST R 34.11-94" },
+    { NULL , NULL, NULL }
+};
+
+void GOST_prov_deinit_digests(void) {
+    static GOST_digest *list[] = {
+        &GostR3411_94_digest,
+        &GostR3411_2012_256_digest,
+        &GostR3411_2012_512_digest,
+    };
+    size_t i;
+#define elems(l) (sizeof(l) / sizeof(l[0]))
+
+    for (i = 0; i < elems(list); i++)
+        GOST_deinit_digest(list[i]);
+}
index 8d537b6e167f1c6a379a2edd10af4e24fec2ccb6..e116f7b4bf1d7a74f51adc2205ea61a6c17ce2e5 100644 (file)
 #!/usr/bin/perl 
 use Test2::V0;
-skip_all('TODO: add digest support in provider')
-    unless $ARGV[0] eq 'engine';
-plan(16);
-
-# Set engine name from environment to allow testing of different engines
-my $engine=$ENV{'ENGINE_NAME'}||"gost";
-# Reopen STDERR to eliminate extra output
-open STDERR, ">>","tests.err";
-
-# prepare data for 
-my $F;
-
-open $F,">","testm1.dat";
-print $F "012345678901234567890123456789012345678901234567890123456789012";
-close $F;
-is(`openssl dgst -engine ${engine} -md_gost12_256 testm1.dat`,
-"md_gost12_256(testm1.dat)= 9d151eefd8590b89daa6ba6cb74af9275dd051026bb149a452fd84e5e57b5500\n",
-"GOST R 34.11-2012 256bit example 1 from standard");
-
-is(`openssl dgst -engine ${engine} -md_gost12_512 testm1.dat`,
-"md_gost12_512(testm1.dat)= 1b54d01a4af5b9d5cc3d86d68d285462b19abc2475222f35c085122be4ba1ffa00ad30f8767b3a82384c6574f024c311e2a481332b08ef7f41797891c1646f48\n",
-"GOST R 34.11-2012 512bit example 1 from standard");
-
-unlink("testm1.dat");
-
-open $F,">","testm2.dat";
-print $F pack("H*","d1e520e2e5f2f0e82c20d1f2f0e8e1eee6e820e2edf3f6e82c20e2e5fef2fa20f120eceef0ff20f1f2f0e5ebe0ece820ede020f5f0e0e1f0fbff20efebfaeafb20c8e3eef0e5e2fb");
-close $F;
-is(`openssl dgst -engine ${engine} -md_gost12_256 testm2.dat`,
-"md_gost12_256(testm2.dat)= 9dd2fe4e90409e5da87f53976d7405b0c0cac628fc669a741d50063c557e8f50\n",
-"GOST R 34.11-2012 256bit example 2 from standard");
-
-is(`openssl dgst -engine ${engine} -md_gost12_512 testm2.dat`,
-"md_gost12_512(testm2.dat)= 1e88e62226bfca6f9994f1f2d51569e0daf8475a3b0fe61a5300eee46d961376035fe83549ada2b8620fcd7c496ce5b33f0cb9dddc2b6460143b03dabac9fb28\n",
-"GOST R 34.11-2012 512bit example 2 from standard");
-
-unlink("testm2.dat");
-
-
-open $F,">","testdata.dat";
-binmode $F;
-print $F "12345670" x 128;
-close $F;
-is(`openssl dgst -engine ${engine} -md_gost94 testdata.dat`,
-"md_gost94(testdata.dat)= f7fc6d16a6a5c12ac4f7d320e0fd0d8354908699125e09727a4ef929122b1cae\n",
-"GOST R 34.11-94 1K ascii");
-
-is(`openssl dgst -engine ${engine} -md_gost12_256 testdata.dat`,
-"md_gost12_256(testdata.dat)= 1906512b86a1283c68cec8419e57113efc562a1d0e95d8f4809542900c416fe4\n",
-"GOST R 34.11-2012 256bit 1K ascii");
-
-is(`openssl dgst -engine ${engine} -md_gost12_512 testdata.dat`,
-"md_gost12_512(testdata.dat)= 283587e434864d0d4bea97c0fb10e2dd421572fc859304bdf6a94673d652c59049212bad7802b4fcf5eecc1f8fab569d60f2c20dbd789a7fe4efbd79d8137ee7\n",
-"GOST R 34.11-2012 512bit 1K ascii");
-
-unlink("testdata.dat");
-
-open $F,">","testdata2.dat";
-binmode $F;
-print $F "\x00\x01\x02\x15\x84\x67\x45\x31" x 128;
-close $F;
-
-is(`openssl dgst -engine ${engine} -md_gost94 testdata2.dat`,
-"md_gost94(testdata2.dat)= 69f529aa82d9344ab0fa550cdf4a70ecfd92a38b5520b1906329763e09105196\n",
-"GOST R 34.11-94 1K binary");
-
-is(`openssl dgst -engine ${engine} -md_gost12_256 testdata2.dat`,
-"md_gost12_256(testdata2.dat)= 2eb1306be3e490f18ff0e2571a077b3831c815c46c7d4fdf9e0e26de4032b3f3\n",
-"GOST R 34.11-2012 256bit 1K binary");
-
-is(`openssl dgst -engine ${engine} -md_gost12_512 testdata2.dat`,
-"md_gost12_512(testdata2.dat)= 55656e5bcf795b499031a7833cd7dc18fe10d4a47e15be545c6ab3f304a4fe411c4c39de5b1fc6844880111441e0b92bf1ec2fb7840453fe39a2b70ced461968\n",
-"GOST R 34.11-2012 512bit 1K binary");
-
-unlink("testdata2.dat");
-
-open $F, ">","testdata3.dat";
-binmode $F;
-print $F substr("12345670" x 128,0,539);
-close $F;
-
-is(`openssl dgst -engine ${engine} -md_gost94 testdata3.dat`,
-"md_gost94(testdata3.dat)= bd5f1e4b539c7b00f0866afdbc8ed452503a18436061747a343f43efe888aac9\n",
-"GOST R 34.11-94 539 bytes");
-
-is(`openssl dgst -engine ${engine} -md_gost12_256 testdata3.dat`,
-"md_gost12_256(testdata3.dat)= c98a17f9fadff78d08521e4179a7b2e6275f3b1da88339a3cb961a3514e5332e\n",
-"GOST R 34.11-2012 256bit 539 bytes");
-
-is(`openssl dgst -engine ${engine} -md_gost12_512 testdata3.dat`,
-"md_gost12_512(testdata3.dat)= d5ad93fbc9ed7abc1cf28d00827a052b40bea74b04c4fd753102c1bcf9f9dad5142887f8a4cceaa0d64a0a8291592413d6adb956b99138a0023e127ff37bdf08\n",
-"GOST R 34.11-2012 512bit 539 bytes");
-
-unlink "testdata3.dat";
-open $F , ">","bigdata.dat";
-binmode $F;
-print $F  ("121345678" x 7 . "1234567\n") x 4096,"12345\n";
-close $F;
-
-is(`openssl dgst -engine ${engine} -md_gost94 bigdata.dat`,
-"md_gost94(bigdata.dat)= e5d3ac4ea3f67896c51ff919cedb9405ad771e39f0f2eab103624f9a758e506f\n",
-"GOST R 34.11-94 128K");
 
-is(`openssl dgst -engine ${engine} -md_gost12_256 bigdata.dat`,
-"md_gost12_256(bigdata.dat)= 50e935d725d9359e5991b6b7eba8b3539fca03584d26adf4c827c982ffd49367\n",
-"GOST R 34.11-2012 256bit 128K");
+my $engine_name = $ENV{ENGINE_NAME} || 'gost';
+my $provider_name = $ENV{PROVIDER_NAME} || 'gostprov';
 
-is(`openssl dgst -engine ${engine} -md_gost12_512 bigdata.dat`,
-"md_gost12_512(bigdata.dat)= 1d93645ebfbb477660f98b7d1598e37fbf3bfc8234ead26e2246e1b979e590ac46138158a692f9a0c9ac2550758b4d0d4c9fb8af5e595a16d3760c6516443f82\n",
-"GOST R 34.11-2012 512bit 128K");
+# Supported test types:
+#
+# 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' )
+                     : () ) );
 
-unlink "bigdata.dat";
+plan(16 * scalar @test_types);
+
+# prepare data for
+
+my %configurations = (
+    'standalone-engine-args' => {
+        'openssl-args'  => "-engine $engine_name",
+    },
+    'standalone-provider-args' => {
+        'openssl-args'  => "-provider $provider_name -provider default",
+    },
+    'standalone-engine-conf' => {
+        'openssl-conf'  => <<EOCFG,
+openssl_conf = openssl_def
+[openssl_def]
+engines = engines
+[engines]
+${engine_name}=${engine_name}_conf
+[${engine_name}_conf]
+default_algorithms = ALL
+EOCFG
+    },
+    'standalone-provider-conf' => {
+        'openssl-conf'  => <<EOCFG,
+openssl_conf = openssl_def
+[openssl_def]
+providers = providers
+[providers]
+${provider_name}=${provider_name}_conf
+[${provider_name}_conf]
+EOCFG
+    },
+);
+
+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 $F;
+    my $cmd;
+    my $name_re;
+
+    open $F,">","testm1.dat";
+    print $F "012345678901234567890123456789012345678901234567890123456789012";
+    close $F;
+    $cmd = "openssl dgst${module_args} -md_gost12_256 testm1.dat";
+    $name_re = qr/id-tc26-gost3411-12-256|md_gost12_256/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(testm1.dat)= 9d151eefd8590b89daa6ba6cb74af9275dd051026bb149a452fd84e5e57b5500\E\n$/ms,
+                 "GOST R 34.11-2012 256bit example 1 from standard")) {
+        diag("Command was: $cmd");
+    }
+
+    $cmd = "openssl dgst${module_args} -md_gost12_512 testm1.dat";
+    $name_re = qr/id-tc26-gost3411-12-512|md_gost12_512/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(testm1.dat)= 1b54d01a4af5b9d5cc3d86d68d285462b19abc2475222f35c085122be4ba1ffa00ad30f8767b3a82384c6574f024c311e2a481332b08ef7f41797891c1646f48\E\n$/ms,
+                 "GOST R 34.11-2012 512bit example 1 from standard")) {
+        diag("Command was: $cmd");
+    }
+
+    unlink("testm1.dat");
+
+
+    open $F,">","testm2.dat";
+    print $F pack("H*","d1e520e2e5f2f0e82c20d1f2f0e8e1eee6e820e2edf3f6e82c20e2e5fef2fa20f120eceef0ff20f1f2f0e5ebe0ece820ede020f5f0e0e1f0fbff20efebfaeafb20c8e3eef0e5e2fb");
+    close $F;
+    $cmd = "openssl dgst${module_args} -md_gost12_256 testm2.dat";
+    $name_re = qr/id-tc26-gost3411-12-256|md_gost12_256/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(testm2.dat)= 9dd2fe4e90409e5da87f53976d7405b0c0cac628fc669a741d50063c557e8f50\E\n$/ms,
+                 "GOST R 34.11-2012 256bit example 2 from standard")) {
+        diag("Command was: $cmd");
+    }
+
+    $cmd = "openssl dgst${module_args} -md_gost12_512 testm2.dat";
+    $name_re = qr/id-tc26-gost3411-12-512|md_gost12_512/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(testm2.dat)= 1e88e62226bfca6f9994f1f2d51569e0daf8475a3b0fe61a5300eee46d961376035fe83549ada2b8620fcd7c496ce5b33f0cb9dddc2b6460143b03dabac9fb28\E\n$/ms,
+                 "GOST R 34.11-2012 512bit example 2 from standard")) {
+        diag("Command was: $cmd");
+    }
+
+    unlink("testm2.dat");
+
+
+    open $F,">","testdata.dat";
+    binmode $F;
+    print $F "12345670" x 128;
+    close $F;
+    $cmd = "openssl dgst${module_args} -md_gost94 testdata.dat";
+    $name_re = qr/id-GostR3411-94|md_gost94/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(testdata.dat)= f7fc6d16a6a5c12ac4f7d320e0fd0d8354908699125e09727a4ef929122b1cae\E\n$/ms,
+                 "GOST R 34.11-94 1K ascii")) {
+        diag("Command was: $cmd");
+    }
+
+    $cmd = "openssl dgst${module_args} -md_gost12_256 testdata.dat";
+    $name_re = qr/id-tc26-gost3411-12-256|md_gost12_256/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(testdata.dat)= 1906512b86a1283c68cec8419e57113efc562a1d0e95d8f4809542900c416fe4\E\n$/ms,
+                 "GOST R 34.11-2012 256bit 1K ascii")) {
+        diag("Command was: $cmd");
+    }
+
+    $cmd = "openssl dgst${module_args} -md_gost12_512 testdata.dat";
+    $name_re = qr/id-tc26-gost3411-12-512|md_gost12_512/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(testdata.dat)= 283587e434864d0d4bea97c0fb10e2dd421572fc859304bdf6a94673d652c59049212bad7802b4fcf5eecc1f8fab569d60f2c20dbd789a7fe4efbd79d8137ee7\E\n$/ms,
+                 "GOST R 34.11-2012 512bit 1K ascii")) {
+        diag("Command was: $cmd");
+    }
+
+    unlink("testdata.dat");
+
+
+    open $F,">","testdata2.dat";
+    binmode $F;
+    print $F "\x00\x01\x02\x15\x84\x67\x45\x31" x 128;
+    close $F;
+
+    $cmd = "openssl dgst${module_args} -md_gost94 testdata2.dat";
+    $name_re = qr/id-GostR3411-94|md_gost94/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(testdata2.dat)= 69f529aa82d9344ab0fa550cdf4a70ecfd92a38b5520b1906329763e09105196\E\n$/ms,
+                 "GOST R 34.11-94 1K binary")) {
+        diag("Command was: $cmd");
+    }
+
+    $cmd = "openssl dgst${module_args} -md_gost12_256 testdata2.dat";
+    $name_re = qr/id-tc26-gost3411-12-256|md_gost12_256/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(testdata2.dat)= 2eb1306be3e490f18ff0e2571a077b3831c815c46c7d4fdf9e0e26de4032b3f3\E\n$/ms,
+                 "GOST R 34.11-2012 256bit 1K binary")) {
+        diag("Command was: $cmd");
+    }
+
+    $cmd = "openssl dgst${module_args} -md_gost12_512 testdata2.dat";
+    $name_re = qr/id-tc26-gost3411-12-512|md_gost12_512/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(testdata2.dat)= 55656e5bcf795b499031a7833cd7dc18fe10d4a47e15be545c6ab3f304a4fe411c4c39de5b1fc6844880111441e0b92bf1ec2fb7840453fe39a2b70ced461968\E\n$/ms,
+                 "GOST R 34.11-2012 512bit 1K binary")) {
+        diag("Command was: $cmd");
+    }
+
+    unlink("testdata2.dat");
+
+    open $F, ">","testdata3.dat";
+    binmode $F;
+    print $F substr("12345670" x 128,0,539);
+    close $F;
+
+    $cmd = "openssl dgst${module_args} -md_gost94 testdata3.dat";
+    $name_re = qr/id-GostR3411-94|md_gost94/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(testdata3.dat)= bd5f1e4b539c7b00f0866afdbc8ed452503a18436061747a343f43efe888aac9\E\n$/ms,
+                 "GOST R 34.11-94 539 bytes")) {
+        diag("Command was: $cmd");
+    }
+
+    $cmd = "openssl dgst${module_args} -md_gost12_256 testdata3.dat";
+    $name_re = qr/id-tc26-gost3411-12-256|md_gost12_256/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(testdata3.dat)= c98a17f9fadff78d08521e4179a7b2e6275f3b1da88339a3cb961a3514e5332e\E\n$/ms,
+                 "GOST R 34.11-2012 256bit 539 bytes")) {
+        diag("Command was: $cmd");
+    }
+
+    $cmd = "openssl dgst${module_args} -md_gost12_512 testdata3.dat";
+    $name_re = qr/id-tc26-gost3411-12-512|md_gost12_512/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(testdata3.dat)= d5ad93fbc9ed7abc1cf28d00827a052b40bea74b04c4fd753102c1bcf9f9dad5142887f8a4cceaa0d64a0a8291592413d6adb956b99138a0023e127ff37bdf08\E\n$/ms,
+                 "GOST R 34.11-2012 512bit 539 bytes")) {
+        diag("Command was: $cmd");
+    }
+
+    unlink "testdata3.dat";
+    open $F , ">","bigdata.dat";
+    binmode $F;
+    print $F  ("121345678" x 7 . "1234567\n") x 4096,"12345\n";
+    close $F;
+
+    $cmd = "openssl dgst${module_args} -md_gost94 bigdata.dat";
+    $name_re = qr/id-GostR3411-94|md_gost94/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(bigdata.dat)= e5d3ac4ea3f67896c51ff919cedb9405ad771e39f0f2eab103624f9a758e506f\E\n$/ms,
+                 "GOST R 34.11-94 128K")) {
+        diag("Command was: $cmd");
+    }
+
+    $cmd = "openssl dgst${module_args} -md_gost12_256 bigdata.dat";
+    $name_re = qr/id-tc26-gost3411-12-256|md_gost12_256/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(bigdata.dat)= 50e935d725d9359e5991b6b7eba8b3539fca03584d26adf4c827c982ffd49367\E\n$/ms,
+                 "GOST R 34.11-2012 256bit 128K")) {
+        diag("Command was: $cmd");
+    }
+
+    $cmd = "openssl dgst${module_args} -md_gost12_512 bigdata.dat";
+    $name_re = qr/id-tc26-gost3411-12-512|md_gost12_512/;
+    unless (like(`$cmd`,
+                 qr/^${name_re}\Q(bigdata.dat)= 1d93645ebfbb477660f98b7d1598e37fbf3bfc8234ead26e2246e1b979e590ac46138158a692f9a0c9ac2550758b4d0d4c9fb8af5e595a16d3760c6516443f82\E\n$/ms,
+                 "GOST R 34.11-2012 512bit 128K")) {
+        diag("Command was: $cmd");
+    }
+
+    unlink "bigdata.dat";
+}