]> www.wagner.pp.ru Git - openssl-gost/engine.git/commitdiff
Merge pull request #106 from vt-alt/test_sign
authorDmitry Belyavskiy <beldmit@users.noreply.github.com>
Mon, 28 Jan 2019 13:03:36 +0000 (16:03 +0300)
committerGitHub <noreply@github.com>
Mon, 28 Jan 2019 13:03:36 +0000 (16:03 +0300)
Sign/Verify and tests for all curves

CMakeLists.txt
README.gost
benchmark/sign.c
gost_ameth.c
gost_ec_sign.c
gost_pmeth.c
test_curves.c
test_sign.c [new file with mode: 0644]

index b4be930d3181ae1651d905940550372ebb821ca9..8209687f6d1c33afe833bd0f6414d8d70989c285 100644 (file)
@@ -123,15 +123,20 @@ set(GOST_ENGINE_SOURCE_FILES
         gost_omac_acpkm.c
         )
 
+add_executable(test_curves test_curves.c)
+target_link_libraries(test_curves gost_engine gost_core ${OPENSSL_CRYPTO_LIBRARY})
+add_test(NAME curves
+       COMMAND test_curves)
+
 add_executable(test_params test_params.c)
 target_link_libraries(test_params gost_engine gost_core ${OPENSSL_CRYPTO_LIBRARY})
 add_test(NAME parameters
        COMMAND test_params)
 
-add_executable(test_curves test_curves.c)
-target_link_libraries(test_curves gost_engine gost_core ${OPENSSL_CRYPTO_LIBRARY})
-add_test(NAME curves
-       COMMAND test_curves)
+add_executable(test_sign test_sign.c)
+target_link_libraries(test_sign gost_engine gost_core ${OPENSSL_CRYPTO_LIBRARY})
+add_test(NAME sign/verify
+       COMMAND test_sign)
 
 add_executable(test_context test_context.c)
 target_link_libraries(test_context gost_engine gost_core ${OPENSSL_CRYPTO_LIBRARY})
index db6b4b90d1994107763c878b18535b2589abdfae..3579665ba23fbfae128adb49beead98c7697eb18 100644 (file)
@@ -70,8 +70,8 @@ USAGE WITH COMMAND LINE openssl UTILITY
   Use -pkeyopt option to pass paramset to algorithm. The following paramsets
   are supported by 
        gost2001:     0,A,B,C,XA,XB
-       gost2012_256: 0,A,B,C,XA,XB
-       gost2012_512:   A,B
+       gost2012_256: 0,A,B,C,XA,XB,TCA,TCB,TCC,TCD
+       gost2012_512:   A,B,C
   You can also use numeric representation of OID as to destinate
   paramset.
 
index 2d1d7866480a16e0418ef31d70285d95260e03fc..765b9f05088b4908e87723ab6cf86b4ce8643eb6 100644 (file)
@@ -23,9 +23,14 @@ const char *tests[] = {
     "md_gost12_256", "gost2012_256", "A",
     "md_gost12_256", "gost2012_256", "B",
     "md_gost12_256", "gost2012_256", "C",
+    "md_gost12_256", "gost2012_256", "TCA",
+    "md_gost12_256", "gost2012_256", "TCB",
+    "md_gost12_256", "gost2012_256", "TCC",
+    "md_gost12_256", "gost2012_256", "TCD",
 
     "md_gost12_512", "gost2012_512", "A",
     "md_gost12_512", "gost2012_512", "B",
+    "md_gost12_512", "gost2012_512", "C",
 
     NULL,
 };
index df595207fadc43d5f7e5a53aa7ac7bb639383a34..6ae278655881c330797711047991da3d9d58dc7f 100644 (file)
@@ -67,11 +67,18 @@ static ASN1_STRING *encode_gost_algor_params(const EVP_PKEY *key)
     switch (EVP_PKEY_base_id(key)) {
     case NID_id_GostR3410_2012_256:
         pkey_param_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(key_ptr));
-        gkp->hash_params = OBJ_nid2obj(NID_id_GostR3411_2012_256);
+       switch (pkey_param_nid) {
+           case NID_id_GostR3410_2001_TestParamSet:
+           case NID_id_GostR3410_2001_CryptoPro_A_ParamSet:
+           case NID_id_GostR3410_2001_CryptoPro_B_ParamSet:
+           case NID_id_GostR3410_2001_CryptoPro_C_ParamSet:
+           case NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet:
+           case NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet:
+               gkp->hash_params = OBJ_nid2obj(NID_id_GostR3411_2012_256);
+       }
         break;
     case NID_id_GostR3410_2012_512:
         pkey_param_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(key_ptr));
-        gkp->hash_params = OBJ_nid2obj(NID_id_GostR3411_2012_512);
         break;
     case NID_id_GostR3410_2001:
         pkey_param_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(key_ptr));
index ba12783959e36ec31b1ea1c98da1678c78ed30df..3db118af1481d2680aa8f468176a7a4cc8d0935e 100644 (file)
@@ -146,7 +146,7 @@ int fill_GOST_EC_params(EC_KEY *eckey, int nid)
         GOSTerr(GOST_F_FILL_GOST_EC_PARAMS, ERR_R_INTERNAL_ERROR);
         goto end;
     }
-    EC_GROUP_set_curve_name(grp, params->nid);
+    EC_GROUP_set_curve_name(grp, nid);
     if (!EC_KEY_set_group(eckey, grp)) {
         GOSTerr(GOST_F_FILL_GOST_EC_PARAMS, ERR_R_INTERNAL_ERROR);
         goto end;
index b2e0a4956a545a79a3f0df031017c7c68d3cb724..41bda944cd6176db841973e263565959461de882 100644 (file)
@@ -208,6 +208,25 @@ static int pkey_gost_ec_ctrl_str_256(EVP_PKEY_CTX *ctx,
             default:
                 return 0;
             }
+       } else if ((strlen(value) == 3)
+           && (toupper((unsigned char)value[0]) == 'T')
+           && (toupper((unsigned char)value[1]) == 'C')) {
+            switch (toupper((unsigned char)value[2])) {
+            case 'A':
+                param_nid = NID_id_tc26_gost_3410_2012_256_paramSetA;
+                break;
+            case 'B':
+                param_nid = NID_id_tc26_gost_3410_2012_256_paramSetB;
+                break;
+            case 'C':
+                param_nid = NID_id_tc26_gost_3410_2012_256_paramSetC;
+                break;
+            case 'D':
+                param_nid = NID_id_tc26_gost_3410_2012_256_paramSetD;
+                break;
+            default:
+                return 0;
+            }
         } else {
             R3410_ec_params *p = R3410_2001_paramset;
             param_nid = OBJ_txt2nid(value);
@@ -252,6 +271,10 @@ static int pkey_gost_ec_ctrl_str_512(EVP_PKEY_CTX *ctx,
             param_nid = NID_id_tc26_gost_3410_2012_512_paramSetB;
             break;
 
+        case 'C':
+            param_nid = NID_id_tc26_gost_3410_2012_512_paramSetC;
+            break;
+
         default:
             return 0;
         }
@@ -320,6 +343,7 @@ static int pkey_gost2012_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
     switch (data->sign_param_nid) {
     case NID_id_tc26_gost_3410_2012_512_paramSetA:
     case NID_id_tc26_gost_3410_2012_512_paramSetB:
+    case NID_id_tc26_gost_3410_2012_512_paramSetC:
         result =
             (EVP_PKEY_assign(pkey, NID_id_GostR3410_2012_512, ec)) ? 1 : 0;
         break;
@@ -330,6 +354,10 @@ static int pkey_gost2012_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
     case NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet:
     case NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet:
     case NID_id_GostR3410_2001_TestParamSet:
+    case NID_id_tc26_gost_3410_2012_256_paramSetA:
+    case NID_id_tc26_gost_3410_2012_256_paramSetB:
+    case NID_id_tc26_gost_3410_2012_256_paramSetC:
+    case NID_id_tc26_gost_3410_2012_256_paramSetD:
         result =
             (EVP_PKEY_assign(pkey, NID_id_GostR3410_2012_256, ec)) ? 1 : 0;
         break;
index 1ee15b0fab706e665f53258a5ac1f4799b18d463..7c57c34ae9e496e32563cc520d72df9c29ba6268 100644 (file)
@@ -43,28 +43,19 @@ struct test_curve {
 static struct test_curve test_curves[] = {
 #if 2001
     { NID_id_GostR3410_2001_TestParamSet, },
+#endif
     { NID_id_GostR3410_2001_CryptoPro_A_ParamSet },
     { NID_id_GostR3410_2001_CryptoPro_B_ParamSet },
     { NID_id_GostR3410_2001_CryptoPro_C_ParamSet },
     { NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet },
     { NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet },
-#endif
-    {
-       NID_id_tc26_gost_3410_2012_512_paramSetA,
-       "id-tc26-gost-3410-2012-512-paramSetA",
-    },
-    {
-       NID_id_tc26_gost_3410_2012_512_paramSetB,
-       "id-tc26-gost-3410-2012-512-paramSetB",
-    },
-    {
-       NID_id_tc26_gost_3410_2012_512_paramSetC,
-       "id-tc26-gost-3410-2012-512-paramSetC",
-    },
-    {
-       NID_id_tc26_gost_3410_2012_256_paramSetA,
-       "id-tc26-gost-3410-2012-256-paramSetA",
-    },
+    { NID_id_tc26_gost_3410_2012_512_paramSetA, "id-tc26-gost-3410-2012-512-paramSetA", },
+    { NID_id_tc26_gost_3410_2012_512_paramSetB, "id-tc26-gost-3410-2012-512-paramSetB", },
+    { NID_id_tc26_gost_3410_2012_512_paramSetC, "id-tc26-gost-3410-2012-512-paramSetC", },
+    { NID_id_tc26_gost_3410_2012_256_paramSetA, "id-tc26-gost-3410-2012-256-paramSetA", },
+    { NID_id_tc26_gost_3410_2012_256_paramSetB, "id-tc26-gost-3410-2012-256-paramSetB", },
+    { NID_id_tc26_gost_3410_2012_256_paramSetC, "id-tc26-gost-3410-2012-256-paramSetC", },
+    { NID_id_tc26_gost_3410_2012_256_paramSetD, "id-tc26-gost-3410-2012-256-paramSetD", },
     0,
 };
 
diff --git a/test_sign.c b/test_sign.c
new file mode 100644 (file)
index 0000000..763b097
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Test GOST 34.10 Sign/Verify operation for every curve parameter
+ *
+ * Copyright (C) 2019 vt@altlinux.org. All Rights Reserved.
+ *
+ * Contents licensed under the terms of the OpenSSL license
+ * See https://www.openssl.org/source/license.html for details
+ */
+
+#include "e_gost_err.h"
+#include "gost_lcl.h"
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <openssl/asn1.h>
+#include <openssl/obj_mac.h>
+#include <openssl/ec.h>
+#include <openssl/bn.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define T(e) ({ if (!(e)) { \
+               ERR_print_errors_fp(stderr); \
+               OpenSSLDie(__FILE__, __LINE__, #e); \
+           } \
+        })
+#define TE(e) ({ if (!(e)) { \
+               ERR_print_errors_fp(stderr); \
+               fprintf(stderr, "Error at %s:%d %s\n", __FILE__, __LINE__, #e); \
+               return -1; \
+           } \
+        })
+
+#define cRED   "\033[1;31m"
+#define cDRED  "\033[0;31m"
+#define cGREEN "\033[1;32m"
+#define cDGREEN        "\033[0;32m"
+#define cBLUE  "\033[1;34m"
+#define cDBLUE "\033[0;34m"
+#define cNORM  "\033[m"
+#define TEST_ASSERT(e) {if ((test = (e))) \
+                printf(cRED "  Test FAILED\n" cNORM); \
+            else \
+                printf(cGREEN "  Test passed\n" cNORM);}
+
+struct test_sign {
+    const char *name;
+    unsigned int nid;
+    size_t bits;
+    const char *paramset;
+};
+
+#define D(x,y,z) { .name = #x, .nid = x, .bits = y, .paramset = z }
+static struct test_sign test_signs[] = {
+    D(NID_id_GostR3410_2001_CryptoPro_A_ParamSet, 256, "A"),
+    D(NID_id_GostR3410_2001_CryptoPro_B_ParamSet, 256, "B"),
+    D(NID_id_GostR3410_2001_CryptoPro_C_ParamSet, 256, "C"),
+    D(NID_id_tc26_gost_3410_2012_256_paramSetA, 256, "TCA"),
+    D(NID_id_tc26_gost_3410_2012_256_paramSetB, 256, "TCB"),
+    D(NID_id_tc26_gost_3410_2012_256_paramSetC, 256, "TCC"),
+    D(NID_id_tc26_gost_3410_2012_256_paramSetD, 256, "TCD"),
+    D(NID_id_tc26_gost_3410_2012_512_paramSetA,   512, "A"),
+    D(NID_id_tc26_gost_3410_2012_512_paramSetB,   512, "B"),
+    D(NID_id_tc26_gost_3410_2012_512_paramSetC,   512, "C"),
+    0
+};
+#undef D
+
+static void hexdump(const void *ptr, size_t len)
+{
+    const unsigned char *p = ptr;
+    size_t i, j;
+
+    for (i = 0; i < len; i += j) {
+       for (j = 0; j < 16 && i + j < len; j++)
+           printf("%s %02x", j? "" : "\n", p[i + j]);
+    }
+    printf("\n");
+}
+
+static void print_test_tf(int err, int val, const char *t, const char *f)
+{
+    if (err == 1)
+       printf(cGREEN "%s\n" cNORM, t);
+    else
+       printf(cRED "%s [%d]\n" cNORM, f, val);
+}
+
+static void print_test_result(int err)
+{
+    if (err == 1)
+       printf(cGREEN "success\n" cNORM);
+    else if (err == 0)
+       printf(cRED "failure\n" cNORM);
+    else
+       ERR_print_errors_fp(stderr);
+}
+
+static int test_sign(struct test_sign *t)
+{
+    int ret = 0, err;
+    size_t len = t->bits / 8;
+
+    printf(cBLUE "Test %s:\n" cNORM, t->name);
+
+    /* Signature type from size. */
+    int type = 0;
+    const char *algname = NULL;
+    switch (t->bits) {
+       case 256:
+           type = NID_id_GostR3410_2012_256;
+           algname = "gost2012_256";
+           break;
+       case 512:
+           type = NID_id_GostR3410_2012_512;
+           algname = "gost2012_512";
+    }
+
+    /* Keygen. */
+    EVP_PKEY *pkey;
+    T(pkey = EVP_PKEY_new());
+    TE(EVP_PKEY_set_type(pkey, type));
+    EVP_PKEY_CTX *ctx;
+    T(ctx = EVP_PKEY_CTX_new(pkey, NULL));
+    T(EVP_PKEY_keygen_init(ctx));
+    T(EVP_PKEY_CTX_ctrl(ctx, type, -1, EVP_PKEY_CTRL_GOST_PARAMSET, t->nid, NULL));
+    EVP_PKEY *priv_key = NULL;
+    err = EVP_PKEY_keygen(ctx, &priv_key);
+    printf("\tEVP_PKEY_keygen:\t");
+    print_test_result(err);
+    EVP_PKEY_CTX_free(ctx);
+    EVP_PKEY_free(pkey);
+    if (err != 1)
+       return -1;
+
+    /* Create another key using string interface. */
+    EVP_PKEY *key1;
+    T(key1 = EVP_PKEY_new());
+    T(EVP_PKEY_set_type_str(key1, algname, strlen(algname)));
+    EVP_PKEY_CTX *ctx1;
+    T(ctx1 = EVP_PKEY_CTX_new(key1, NULL));
+    T(EVP_PKEY_keygen_init(ctx1));
+    T(EVP_PKEY_CTX_ctrl_str(ctx1, "paramset", t->paramset));
+    EVP_PKEY *key2 = NULL;
+    err = EVP_PKEY_keygen(ctx1, &key2);
+    printf("\tEVP_PKEY_*_str:\t\t");
+    print_test_result(err);
+
+    /* Check if key type and curve_name match expected values. */
+    int id = EVP_PKEY_id(key2);
+    err = id == type;
+    printf("\tEVP_PKEY_id (%d):\t", type);
+    print_test_tf(err, id, "match", "mismatch");
+    ret |= !err;
+
+    const EC_KEY *ec = EVP_PKEY_get0(key2);
+    const EC_GROUP *group = EC_KEY_get0_group(ec);
+    int curve_name = EC_GROUP_get_curve_name(group);
+    err = curve_name == t->nid;
+    printf("\tcurve_name (%d):\t", t->nid);
+    print_test_tf(err, curve_name, "match", "mismatch");
+    ret |= !err;
+
+    /* Compare both keys.
+     * Parameters should match, public keys should mismatch.
+    */
+    err = EVP_PKEY_cmp_parameters(priv_key, key2);
+    printf("\tEVP_PKEY_cmp_parameters:");
+    print_test_tf(err, err, "success", "failure");
+    ret |= err != 1;
+
+    err = EVP_PKEY_cmp(priv_key, key2);
+    err = (err < 0) ? err : !err;
+    printf("\tEVP_PKEY_cmp:\t\t");
+    print_test_tf(err, err, "differ (good)", "equal (error)");
+    ret |= err != 1;
+    EVP_PKEY_CTX_free(ctx1);
+    EVP_PKEY_free(key1);
+
+    /*
+     * Prepare for sign testing.
+     */
+    size_t siglen = EVP_PKEY_size(priv_key);
+    unsigned char *sig;
+    T(sig = OPENSSL_malloc(siglen));
+    unsigned char *hash;
+    T(hash = OPENSSL_zalloc(len));
+    T(ctx = EVP_PKEY_CTX_new(priv_key, NULL));
+
+    /* Sign. */
+    T(EVP_PKEY_sign_init(ctx));
+    err = EVP_PKEY_sign(ctx, sig, &siglen, hash, len);
+    printf("\tEVP_PKEY_sign:\t\t");
+    print_test_result(err);
+    ret |= err != 1;
+
+    /* Non-determinism test.
+     * Check that different signatures for the same data
+     * are not equal. */
+    unsigned char *sig2;
+    T(sig2 = OPENSSL_malloc(siglen));
+    TE(EVP_PKEY_sign(ctx, sig2, &siglen, hash, len) == 1);
+    printf("\tNon-determinism:\t");
+    err = !!memcmp(sig, sig2, siglen);
+    print_test_result(err);
+    ret |= err != 1;
+    OPENSSL_free(sig2);
+
+    /* Verify. */
+    T(EVP_PKEY_verify_init(ctx));
+    hash[0]++; /* JFF */
+    err = EVP_PKEY_verify(ctx, sig, siglen, hash, len);
+    printf("\tEVP_PKEY_verify:\t");
+    print_test_result(err);
+    ret |= err != 1;
+
+    /* False positive Verify. */
+    T(EVP_PKEY_verify_init(ctx));
+    hash[0]++;
+    err = EVP_PKEY_verify(ctx, sig, siglen, hash, len);
+    err = (err < 0) ? err : !err;
+    printf("\tFalse positive test:\t");
+    print_test_result(err);
+    ret |= err != 1;
+
+    EVP_PKEY_CTX_free(ctx);
+    OPENSSL_free(sig);
+    OPENSSL_free(hash);
+
+    return ret;
+}
+
+int main(int argc, char **argv)
+{
+    int ret = 0;
+
+    setenv("OPENSSL_CONF", "../example.conf", 0);
+    OPENSSL_add_all_algorithms_conf();
+    ERR_load_crypto_strings();
+
+    struct test_sign *sp;
+    for (sp = test_signs; sp->name; sp++)
+       ret |= test_sign(sp);
+
+    if (ret)
+       printf(cDRED "= Some tests FAILED!\n" cNORM);
+    else
+       printf(cDGREEN "= All tests passed!\n" cNORM);
+    return ret;
+}