summaryrefslogtreecommitdiffstats
path: root/lib/dns/tests/gost_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dns/tests/gost_test.c')
-rw-r--r--lib/dns/tests/gost_test.c379
1 files changed, 379 insertions, 0 deletions
diff --git a/lib/dns/tests/gost_test.c b/lib/dns/tests/gost_test.c
new file mode 100644
index 0000000..204c6cc
--- /dev/null
+++ b/lib/dns/tests/gost_test.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+
+/* ! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/util.h>
+#include <isc/print.h>
+#include <isc/string.h>
+
+#include "dnstest.h"
+
+#ifdef HAVE_OPENSSL_GOST
+#include "../dst_gost.h"
+#include <openssl/err.h>
+#include <openssl/objects.h>
+#include <openssl/rsa.h>
+#include <openssl/engine.h>
+#include <openssl/bn.h>
+#endif
+
+#ifdef HAVE_PKCS11_GOST
+#include "../dst_gost.h"
+#include <pk11/internal.h>
+#define WANT_GOST_PARAMS
+#include <pk11/constants.h>
+#include <pkcs11/pkcs11.h>
+#endif
+
+#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
+/*
+ * Test data from Wikipedia GOST (hash function)
+ */
+
+unsigned char digest[ISC_GOST_DIGESTLENGTH];
+unsigned char buffer[1024];
+const char *s;
+char str[2 * ISC_GOST_DIGESTLENGTH + 3];
+int i = 0;
+
+/*
+ * Precondition: a hexadecimal number in *d, the length of that number in len,
+ * and a pointer to a character array to put the output (*out).
+ * Postcondition: A String representation of the given hexadecimal number is
+ * placed into the array *out
+ *
+ * 'out' MUST point to an array of at least len * 2 + 1
+ *
+ * Return values: ISC_R_SUCCESS if the operation is sucessful
+ */
+static isc_result_t
+tohexstr(unsigned char *d, unsigned int len, char *out, size_t out_size) {
+ char c_ret[] = "AA";
+ unsigned int j;
+
+ out[0] = '\0';
+ strlcat(out, "0x", out_size);
+ for (j = 0; j < len; j++) {
+ snprintf(c_ret, sizeof(c_ret), "%02X", d[j]);
+ strlcat(out, c_ret, out_size);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+
+#define TEST_INPUT(x) (x), sizeof(x)-1
+
+typedef struct hash_testcase {
+ const char *input;
+ size_t input_len;
+ const char *result;
+ int repeats;
+} hash_testcase_t;
+
+ATF_TC(isc_gost_md);
+ATF_TC_HEAD(isc_gost_md, tc) {
+ atf_tc_set_md_var(tc, "descr",
+ "GOST R 34.11-94 examples from Wikipedia");
+}
+ATF_TC_BODY(isc_gost_md, tc) {
+ isc_gost_t gost;
+ isc_result_t result;
+
+ UNUSED(tc);
+
+ /*
+ * These are the various test vectors. All of these are passed
+ * through the hash function and the results are compared to the
+ * result specified here.
+ */
+ hash_testcase_t testcases[] = {
+ /* Test 1 */
+ {
+ TEST_INPUT(""),
+ "0x981E5F3CA30C841487830F84FB433E1"
+ "3AC1101569B9C13584AC483234CD656C0",
+ 1
+ },
+ /* Test 2 */
+ {
+ TEST_INPUT("a"),
+ "0xE74C52DD282183BF37AF0079C9F7805"
+ "5715A103F17E3133CEFF1AACF2F403011",
+ 1
+ },
+ /* Test 3 */
+ {
+ TEST_INPUT("abc"),
+ "0xB285056DBF18D7392D7677369524DD1"
+ "4747459ED8143997E163B2986F92FD42C",
+ 1
+ },
+ /* Test 4 */
+ {
+ TEST_INPUT("message digest"),
+ "0xBC6041DD2AA401EBFA6E9886734174F"
+ "EBDB4729AA972D60F549AC39B29721BA0",
+ 1
+ },
+ /* Test 5 */
+ {
+ TEST_INPUT("The quick brown fox jumps "
+ "over the lazy dog"),
+ "0x9004294A361A508C586FE53D1F1B027"
+ "46765E71B765472786E4770D565830A76",
+ 1
+ },
+
+ /* Test 6 */
+ {
+ TEST_INPUT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
+ "fghijklmnopqrstuvwxyz0123456789"),
+ "0x73B70A39497DE53A6E08C67B6D4DB85"
+ "3540F03E9389299D9B0156EF7E85D0F61",
+ 1
+ },
+ /* Test 7 */
+ {
+ TEST_INPUT("1234567890123456789012345678901"
+ "2345678901234567890123456789012"
+ "345678901234567890"),
+ "0x6BC7B38989B28CF93AE8842BF9D7529"
+ "05910A7528A61E5BCE0782DE43E610C90",
+ 1
+ },
+ /* Test 8 */
+ {
+ TEST_INPUT("This is message, length=32 bytes"),
+ "0x2CEFC2F7B7BDC514E18EA57FA74FF35"
+ "7E7FA17D652C75F69CB1BE7893EDE48EB",
+ 1
+ },
+ /* Test 9 */
+ {
+ TEST_INPUT("Suppose the original message "
+ "has length = 50 bytes"),
+ "0xC3730C5CBCCACF915AC292676F21E8B"
+ "D4EF75331D9405E5F1A61DC3130A65011",
+ 1
+ },
+ /* Test 10 */
+ {
+ TEST_INPUT("U") /* times 128 */,
+ "0x1C4AC7614691BBF427FA2316216BE8F"
+ "10D92EDFD37CD1027514C1008F649C4E8",
+ 128
+ },
+ /* Test 11 */
+ {
+ TEST_INPUT("a") /* times 1000000 */,
+ "0x8693287AA62F9478F7CB312EC0866B6"
+ "C4E4A0F11160441E8F4FFCD2715DD554F",
+ 1000000
+ },
+ { NULL, 0, NULL, 1 }
+ };
+
+ result = dns_test_begin(NULL, false);
+ ATF_REQUIRE(result == ISC_R_SUCCESS);
+
+ hash_testcase_t *testcase = testcases;
+
+ while (testcase->input != NULL && testcase->result != NULL) {
+ result = isc_gost_init(&gost);
+ ATF_REQUIRE(result == ISC_R_SUCCESS);
+ for(i = 0; i < testcase->repeats; i++) {
+ result = isc_gost_update(&gost,
+ (const uint8_t *) testcase->input,
+ testcase->input_len);
+ ATF_REQUIRE(result == ISC_R_SUCCESS);
+ }
+ result = isc_gost_final(&gost, digest);
+ ATF_REQUIRE(result == ISC_R_SUCCESS);
+ tohexstr(digest, ISC_GOST_DIGESTLENGTH, str, sizeof(str));
+ ATF_CHECK_STREQ(str, testcase->result);
+
+ testcase++;
+ }
+
+ dns_test_end();
+}
+
+ATF_TC(isc_gost_private);
+ATF_TC_HEAD(isc_gost_private, tc) {
+ atf_tc_set_md_var(tc, "descr", "GOST R 34.10-2001 private key");
+}
+ATF_TC_BODY(isc_gost_private, tc) {
+ isc_result_t result;
+ unsigned char privraw[31] = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e
+ };
+#ifdef HAVE_OPENSSL_GOST
+ unsigned char rbuf[32];
+ unsigned char privasn1[70] = {
+ 0x30, 0x44, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06,
+ 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30,
+ 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02,
+ 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02,
+ 0x02, 0x1e, 0x01, 0x04, 0x21, 0x02, 0x1f, 0x01,
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
+ 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ 0x1a, 0x1b, 0x1c, 0x1d, 0x1e
+ };
+ unsigned char abuf[71];
+ unsigned char gost_dummy_key[71] = {
+ 0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06,
+ 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30,
+ 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02,
+ 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02,
+ 0x02, 0x1e, 0x01, 0x04, 0x22, 0x02, 0x20, 0x1b,
+ 0x3f, 0x94, 0xf7, 0x1a, 0x5f, 0x2f, 0xe7, 0xe5,
+ 0x74, 0x0b, 0x8c, 0xd4, 0xb7, 0x18, 0xdd, 0x65,
+ 0x68, 0x26, 0xd1, 0x54, 0xfb, 0x77, 0xba, 0x63,
+ 0x72, 0xd9, 0xf0, 0x63, 0x87, 0xe0, 0xd6
+ };
+ EVP_PKEY *pkey;
+ EC_KEY *eckey;
+ BIGNUM *privkey;
+ const BIGNUM *privkey1;
+ const unsigned char *p;
+ int len;
+ unsigned char *q;
+
+ result = dns_test_begin(NULL, false);
+ ATF_REQUIRE(result == ISC_R_SUCCESS);
+
+ /* raw parse */
+ privkey = BN_bin2bn(privraw, (int) sizeof(privraw), NULL);
+ ATF_REQUIRE(privkey != NULL);
+ p = gost_dummy_key;
+ pkey = NULL;
+ ATF_REQUIRE(d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
+ (long) sizeof(gost_dummy_key)) != NULL);
+ ATF_REQUIRE(pkey != NULL);
+ ATF_REQUIRE(EVP_PKEY_bits(pkey) == 256);
+ eckey = EVP_PKEY_get0(pkey);
+ ATF_REQUIRE(eckey != NULL);
+ ATF_REQUIRE(EC_KEY_set_private_key(eckey, privkey) == 1);
+ BN_clear_free(privkey);
+
+ /* asn1 tofile */
+ len = i2d_PrivateKey(pkey, NULL);
+ ATF_REQUIRE(len == 70);
+ q = abuf;
+ ATF_REQUIRE(i2d_PrivateKey(pkey, &q) == len);
+ ATF_REQUIRE(memcmp(abuf, privasn1, len) == 0);
+ EVP_PKEY_free(pkey);
+
+ /* asn1 parse */
+ p = privasn1;
+ pkey = NULL;
+ ATF_REQUIRE(d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
+ (long) len) != NULL);
+ ATF_REQUIRE(pkey != NULL);
+ eckey = EVP_PKEY_get0(pkey);
+ ATF_REQUIRE(eckey != NULL);
+ privkey1 = EC_KEY_get0_private_key(eckey);
+ len = BN_num_bytes(privkey1);
+ ATF_REQUIRE(len == 31);
+ ATF_REQUIRE(BN_bn2bin(privkey1, rbuf) == len);
+ ATF_REQUIRE(memcmp(rbuf, privraw, len) == 0);
+
+ dns_test_end();
+#else
+ CK_BBOOL truevalue = TRUE;
+ CK_BBOOL falsevalue = FALSE;
+ CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
+ CK_KEY_TYPE keyType = CKK_GOSTR3410;
+ CK_ATTRIBUTE keyTemplate[] =
+ {
+ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
+ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
+ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
+ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
+ { CKA_VALUE, privraw, sizeof(privraw) },
+ { CKA_GOSTR3410_PARAMS, pk11_gost_a_paramset,
+ (CK_ULONG) sizeof(pk11_gost_a_paramset) },
+ { CKA_GOSTR3411_PARAMS, pk11_gost_paramset,
+ (CK_ULONG) sizeof(pk11_gost_paramset) }
+ };
+ CK_MECHANISM mech = { CKM_GOSTR3410_WITH_GOSTR3411, NULL, 0 };
+ CK_BYTE sig[64];
+ CK_ULONG siglen;
+ pk11_context_t pk11_ctx;
+
+ result = dns_test_begin(NULL, false);
+ ATF_REQUIRE(result == ISC_R_SUCCESS);
+
+ /* create the private key */
+ memset(&pk11_ctx, 0, sizeof(pk11_ctx));
+ ATF_REQUIRE(pk11_get_session(&pk11_ctx, OP_GOST, true,
+ false, false, NULL,
+ pk11_get_best_token(OP_GOST)) ==
+ ISC_R_SUCCESS);
+ pk11_ctx.object = CK_INVALID_HANDLE;
+ pk11_ctx.ontoken = false;
+ ATF_REQUIRE(pkcs_C_CreateObject(pk11_ctx.session, keyTemplate,
+ (CK_ULONG) 9, &pk11_ctx.object) ==
+ CKR_OK);
+ ATF_REQUIRE(pk11_ctx.object != CK_INVALID_HANDLE);
+
+ /* sign something */
+ ATF_REQUIRE(pkcs_C_SignInit(pk11_ctx.session, &mech,
+ pk11_ctx.object) == CKR_OK);
+ siglen = 0;
+ ATF_REQUIRE(pkcs_C_Sign(pk11_ctx.session, sig, 64,
+ NULL, &siglen) == CKR_OK);
+ ATF_REQUIRE(siglen == 64);
+ ATF_REQUIRE(pkcs_C_Sign(pk11_ctx.session, sig, 64,
+ sig, &siglen) == CKR_OK);
+ ATF_REQUIRE(siglen == 64);
+
+ dns_test_end();
+#endif
+};
+#else
+ATF_TC(untested);
+ATF_TC_HEAD(untested, tc) {
+ atf_tc_set_md_var(tc, "descr", "skipping gost test");
+}
+ATF_TC_BODY(untested, tc) {
+ UNUSED(tc);
+ atf_tc_skip("GOST not available");
+}
+#endif
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
+ ATF_TP_ADD_TC(tp, isc_gost_md);
+ ATF_TP_ADD_TC(tp, isc_gost_private);
+#else
+ ATF_TP_ADD_TC(tp, untested);
+#endif
+ return (atf_no_error());
+}
+