1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7  *
8  * See the COPYRIGHT file distributed with this work for additional
9  * information regarding copyright ownership.
10  */
11 
12 #include <config.h>
13 
14 #if HAVE_CMOCKA
15 
16 #include <stdarg.h>
17 #include <stddef.h>
18 #include <setjmp.h>
19 
20 #include <sched.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #define UNIT_TESTING
26 #include <cmocka.h>
27 
28 #include <isc/util.h>
29 #include <isc/print.h>
30 #include <isc/string.h>
31 
32 #include "dnstest.h"
33 
34 #ifdef HAVE_OPENSSL_GOST
35 #include "../dst_gost.h"
36 #include <openssl/err.h>
37 #include <openssl/objects.h>
38 #include <openssl/rsa.h>
39 #include <openssl/engine.h>
40 #include <openssl/bn.h>
41 #endif
42 
43 #ifdef HAVE_PKCS11_GOST
44 #include "../dst_gost.h"
45 #include <pk11/internal.h>
46 #define WANT_GOST_PARAMS
47 #include <pk11/constants.h>
48 #include <pkcs11/pkcs11.h>
49 #endif
50 
51 #if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
52 static int
_setup(void ** state)53 _setup(void **state) {
54 	isc_result_t result;
55 
56 	UNUSED(state);
57 
58 	result = dns_test_begin(NULL, false);
59 	assert_int_equal(result, ISC_R_SUCCESS);
60 
61 	return (0);
62 }
63 
64 static int
_teardown(void ** state)65 _teardown(void **state) {
66 	UNUSED(state);
67 
68 	dns_test_end();
69 
70 	return (0);
71 }
72 
73 /*
74  * Test data from Wikipedia GOST (hash function)
75  */
76 
77 unsigned char digest[ISC_GOST_DIGESTLENGTH];
78 unsigned char buffer[1024];
79 const char *s;
80 char str[2 * ISC_GOST_DIGESTLENGTH + 3];
81 int i = 0;
82 
83 /*
84  * Precondition: a hexadecimal number in *d, the length of that number in len,
85  *   and a pointer to a character array to put the output (*out).
86  * Postcondition: A String representation of the given hexadecimal number is
87  *   placed into the array *out
88  *
89  * 'out' MUST point to an array of at least len * 2 + 1
90  *
91  * Return values: ISC_R_SUCCESS if the operation is successful
92  */
93 static isc_result_t
tohexstr(unsigned char * d,unsigned int len,char * out,size_t out_size)94 tohexstr(unsigned char *d, unsigned int len, char *out, size_t out_size) {
95 	char c_ret[] = "AA";
96 	unsigned int j;
97 
98 	out[0] = '\0';
99 	strlcat(out, "0x", out_size);
100 	for (j = 0; j < len; j++) {
101 		snprintf(c_ret, sizeof(c_ret), "%02X", d[j]);
102 		strlcat(out, c_ret, out_size);
103 	}
104 	return (ISC_R_SUCCESS);
105 }
106 
107 
108 #define TEST_INPUT(x) (x), sizeof(x)-1
109 
110 typedef struct hash_testcase {
111 	const char *input;
112 	size_t input_len;
113 	const char *result;
114 	int repeats;
115 } hash_testcase_t;
116 
117 /* GOST R 34.11-94 examples from Wikipedia */
118 static void
isc_gost_md(void ** state)119 isc_gost_md(void **state) {
120 	isc_gost_t gost;
121 	isc_result_t result;
122 
123 	UNUSED(state);
124 
125 	/*
126 	 * These are the various test vectors.  All of these are passed
127 	 * through the hash function and the results are compared to the
128 	 * result specified here.
129 	 */
130 	hash_testcase_t testcases[] = {
131 		/* Test 1 */
132 		{
133 			TEST_INPUT(""),
134 			"0x981E5F3CA30C841487830F84FB433E1"
135 			"3AC1101569B9C13584AC483234CD656C0",
136 			1
137 		},
138 		/* Test 2 */
139 		{
140 			TEST_INPUT("a"),
141 			"0xE74C52DD282183BF37AF0079C9F7805"
142 			"5715A103F17E3133CEFF1AACF2F403011",
143 			1
144 		},
145 		/* Test 3 */
146 		{
147 			TEST_INPUT("abc"),
148 			"0xB285056DBF18D7392D7677369524DD1"
149 			"4747459ED8143997E163B2986F92FD42C",
150 			1
151 		},
152 		/* Test 4 */
153 		{
154 			TEST_INPUT("message digest"),
155 			"0xBC6041DD2AA401EBFA6E9886734174F"
156 			"EBDB4729AA972D60F549AC39B29721BA0",
157 			1
158 		},
159 		/* Test 5 */
160 		{
161 			TEST_INPUT("The quick brown fox jumps "
162 				   "over the lazy dog"),
163 			"0x9004294A361A508C586FE53D1F1B027"
164 			"46765E71B765472786E4770D565830A76",
165 			1
166 		},
167 
168 		/* Test 6 */
169 		{
170 			TEST_INPUT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
171 				   "fghijklmnopqrstuvwxyz0123456789"),
172 			"0x73B70A39497DE53A6E08C67B6D4DB85"
173 			"3540F03E9389299D9B0156EF7E85D0F61",
174 			1
175 		},
176 		/* Test 7 */
177 		{
178 			TEST_INPUT("1234567890123456789012345678901"
179 				   "2345678901234567890123456789012"
180 				   "345678901234567890"),
181 			"0x6BC7B38989B28CF93AE8842BF9D7529"
182 			"05910A7528A61E5BCE0782DE43E610C90",
183 			1
184 		},
185 		/* Test 8 */
186 		{
187 			TEST_INPUT("This is message, length=32 bytes"),
188 			"0x2CEFC2F7B7BDC514E18EA57FA74FF35"
189 			"7E7FA17D652C75F69CB1BE7893EDE48EB",
190 			1
191 		},
192 		/* Test 9 */
193 		{
194 			TEST_INPUT("Suppose the original message "
195 				   "has length = 50 bytes"),
196 			"0xC3730C5CBCCACF915AC292676F21E8B"
197 			"D4EF75331D9405E5F1A61DC3130A65011",
198 			1
199 		},
200 		/* Test 10 */
201 		{
202 			TEST_INPUT("U") /* times 128 */,
203 			"0x1C4AC7614691BBF427FA2316216BE8F"
204 			"10D92EDFD37CD1027514C1008F649C4E8",
205 			128
206 		},
207 		/* Test 11 */
208 		{
209 			TEST_INPUT("a") /* times 1000000 */,
210 			"0x8693287AA62F9478F7CB312EC0866B6"
211 			"C4E4A0F11160441E8F4FFCD2715DD554F",
212 			1000000
213 		},
214 		{ NULL, 0, NULL, 1 }
215 	};
216 
217 	hash_testcase_t *testcase = testcases;
218 
219 	while (testcase->input != NULL && testcase->result != NULL) {
220 		result = isc_gost_init(&gost);
221 		assert_int_equal(result, ISC_R_SUCCESS);
222 		for(i = 0; i < testcase->repeats; i++) {
223 			result = isc_gost_update(&gost,
224 					(const uint8_t *) testcase->input,
225 					testcase->input_len);
226 			assert_int_equal(result, ISC_R_SUCCESS);
227 		}
228 		result = isc_gost_final(&gost, digest);
229 		assert_int_equal(result, ISC_R_SUCCESS);
230 		tohexstr(digest, ISC_GOST_DIGESTLENGTH, str, sizeof(str));
231 		assert_string_equal(str, testcase->result);
232 
233 		testcase++;
234 	}
235 }
236 
237 /* GOST R 34.10-2001 private key */
238 static void
isc_gost_private(void ** state)239 isc_gost_private(void **state) {
240 	unsigned char privraw[31] = {
241 		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
242 		0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
243 		0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
244 		0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e
245 	};
246 #ifdef HAVE_OPENSSL_GOST
247 	unsigned char rbuf[32];
248 	unsigned char privasn1[70] = {
249 		0x30, 0x44, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06,
250 		0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30,
251 		0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02,
252 		0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02,
253 		0x02, 0x1e, 0x01, 0x04, 0x21, 0x02, 0x1f, 0x01,
254 		0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
255 		0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
256 		0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
257 		0x1a, 0x1b, 0x1c, 0x1d, 0x1e
258 	};
259 	unsigned char abuf[71];
260 	unsigned char gost_dummy_key[71] = {
261 		0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06,
262 		0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30,
263 		0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02,
264 		0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02,
265 		0x02, 0x1e, 0x01, 0x04, 0x22, 0x02, 0x20, 0x1b,
266 		0x3f, 0x94, 0xf7, 0x1a, 0x5f, 0x2f, 0xe7, 0xe5,
267 		0x74, 0x0b, 0x8c, 0xd4, 0xb7, 0x18, 0xdd, 0x65,
268 		0x68, 0x26, 0xd1, 0x54, 0xfb, 0x77, 0xba, 0x63,
269 		0x72, 0xd9, 0xf0, 0x63, 0x87, 0xe0, 0xd6
270 	};
271 	EVP_PKEY *pkey;
272 	EC_KEY *eckey;
273 	BIGNUM *privkey;
274 	const BIGNUM *privkey1;
275 	const unsigned char *p;
276 	int len;
277 	unsigned char *q;
278 
279 	UNUSED(state);
280 
281 	/* raw parse */
282 	privkey = BN_bin2bn(privraw, (int) sizeof(privraw), NULL);
283 	assert_non_null(privkey);
284 	p = gost_dummy_key;
285 	pkey = NULL;
286 	assert_non_null(d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
287 				       (long) sizeof(gost_dummy_key)));
288 	assert_non_null(pkey);
289 	assert_int_equal(EVP_PKEY_bits(pkey), 256);
290 	eckey = EVP_PKEY_get0(pkey);
291 	assert_non_null(eckey);
292 	assert_int_equal(EC_KEY_set_private_key(eckey, privkey), 1);
293 	BN_clear_free(privkey);
294 
295 	/* asn1 tofile */
296 	len = i2d_PrivateKey(pkey, NULL);
297 	assert_int_equal(len, 70);
298 	q = abuf;
299 	assert_int_equal(i2d_PrivateKey(pkey, &q), len);
300 	assert_int_equal(memcmp(abuf, privasn1, len), 0);
301 	EVP_PKEY_free(pkey);
302 
303 	/* asn1 parse */
304 	p = privasn1;
305 	pkey = NULL;
306 	assert_non_null(d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
307 				       (long) len));
308 	assert_non_null(pkey);
309 	eckey = EVP_PKEY_get0(pkey);
310 	assert_non_null(eckey);
311 	privkey1 = EC_KEY_get0_private_key(eckey);
312 	len = BN_num_bytes(privkey1);
313 	assert_int_equal(len, 31);
314 	assert_int_equal(BN_bn2bin(privkey1, rbuf), len);
315 	assert_memory_equal(rbuf, privraw, len);
316 #else
317 	CK_BBOOL truevalue = TRUE;
318 	CK_BBOOL falsevalue = FALSE;
319 	CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
320 	CK_KEY_TYPE keyType = CKK_GOSTR3410;
321 	CK_ATTRIBUTE keyTemplate[] =
322 	{
323 		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
324 		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
325 		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
326 		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
327 		{ CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
328 		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
329 		{ CKA_VALUE, privraw, sizeof(privraw) },
330 		{ CKA_GOSTR3410_PARAMS, pk11_gost_a_paramset,
331 		  (CK_ULONG) sizeof(pk11_gost_a_paramset) },
332 		{ CKA_GOSTR3411_PARAMS, pk11_gost_paramset,
333 		  (CK_ULONG) sizeof(pk11_gost_paramset) }
334 	};
335 	CK_MECHANISM mech = { CKM_GOSTR3410_WITH_GOSTR3411, NULL, 0 };
336 	CK_BYTE sig[64];
337 	CK_ULONG siglen;
338 	pk11_context_t pk11_ctx;
339 
340 	/* create the private key */
341 	memset(&pk11_ctx, 0, sizeof(pk11_ctx));
342 	assert_int_equal(pk11_get_session(&pk11_ctx, OP_GOST, true,
343 					  false, false, NULL,
344 					  pk11_get_best_token(OP_GOST)),
345 			 ISC_R_SUCCESS);
346 	pk11_ctx.object = CK_INVALID_HANDLE;
347 	pk11_ctx.ontoken = false;
348 	assert_int_equal(pkcs_C_CreateObject(pk11_ctx.session, keyTemplate,
349 					     (CK_ULONG) 9,
350 					     &pk11_ctx.object),
351 			 CKR_OK);
352 	assert_int_not_equal(pk11_ctx.object, CK_INVALID_HANDLE);
353 
354 	/* sign something */
355 	assert_int_equal(pkcs_C_SignInit(pk11_ctx.session, &mech,
356 					 pk11_ctx.object),
357 			 CKR_OK);
358 	siglen = 0;
359 	assert_int_equal(pkcs_C_Sign(pk11_ctx.session, sig, 64,
360 				     NULL, &siglen),
361 			 CKR_OK);
362 	assert_int_equal(siglen, 64);
363 	assert_int_equal(pkcs_C_Sign(pk11_ctx.session, sig, 64,
364 				     sig, &siglen),
365 			 CKR_OK);
366 	assert_int_equal(siglen, 64);
367 #endif
368 };
369 #endif
370 
371 int
main(void)372 main(void) {
373 #if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
374 	const struct CMUnitTest tests[] = {
375 		cmocka_unit_test_setup_teardown(isc_gost_md,
376 						_setup, _teardown),
377 		cmocka_unit_test_setup_teardown(isc_gost_private,
378 						_setup, _teardown),
379 	};
380 
381 	return (cmocka_run_group_tests(tests, dns_test_init, dns_test_final));
382 #else
383 	print_message("1..0 # Skip GOST is unavailable");
384 #endif
385 }
386 
387 #else /* HAVE_CMOCKA */
388 
389 #include <stdio.h>
390 
391 int
main(void)392 main(void) {
393 	printf("1..0 # Skipped: cmocka not available\n");
394 	return (0);
395 }
396 
397 #endif
398