From 50701f1b92a5b97a96d28cac518d28648b1857fe Mon Sep 17 00:00:00 2001 From: Vitaly Chikunov Date: Wed, 23 Jan 2019 08:16:33 +0300 Subject: [PATCH] test_sign: Sign/Verify tests for all curves Currently, not all curves are tested, but only these that are fully implemented, to test all curves run `test_sign` with any argument. --- CMakeLists.txt | 13 ++- test_sign.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 259 insertions(+), 4 deletions(-) create mode 100644 test_sign.c diff --git a/CMakeLists.txt b/CMakeLists.txt index b4be930..8209687 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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}) diff --git a/test_sign.c b/test_sign.c new file mode 100644 index 0000000..763b097 --- /dev/null +++ b/test_sign.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} -- 2.39.2