1/*
2 * Copyright (C) 2004, 2005, 2007-2009  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: t_dst.c,v 1.58 2009/09/01 00:22:25 jinmei Exp $ */
19
20#include <config.h>
21
22#include <sys/types.h>		/* Required for dirent.h */
23#include <sys/stat.h>
24
25#include <dirent.h>		/* XXX */
26#include <errno.h>
27#include <fcntl.h>
28#include <limits.h>
29#include <stdlib.h>
30
31#include <unistd.h>		/* XXX */
32
33#include <isc/buffer.h>
34#include <isc/dir.h>
35#include <isc/entropy.h>
36#include <isc/file.h>
37#include <isc/mem.h>
38#include <isc/region.h>
39#include <isc/string.h>
40#include <isc/util.h>
41
42#include <dns/fixedname.h>
43#include <dns/name.h>
44
45#include <dst/dst.h>
46#include <dst/result.h>
47
48#include <tests/t_api.h>
49
50#ifndef PATH_MAX
51#define PATH_MAX	256
52#endif
53
54/*
55 * Adapted from the original dst_test.c program.
56 * XXXDCL should use isc_dir_*.
57 */
58
59static void
60cleandir(char *path) {
61	DIR		*dirp;
62	struct dirent	*pe;
63	char		fullname[PATH_MAX + 1];
64
65	dirp = opendir(path);
66	if (dirp == NULL) {
67		t_info("opendir(%s) failed %d\n", path, errno);
68		return;
69	}
70
71	while ((pe = readdir(dirp)) != NULL) {
72		if (! strcmp(pe->d_name, "."))
73			continue;
74		if (! strcmp(pe->d_name, ".."))
75			continue;
76		strcpy(fullname, path);
77		strcat(fullname, "/");
78		strcat(fullname, pe->d_name);
79		if (remove(fullname))
80			t_info("remove(%s) failed %d\n", fullname, errno);
81
82	}
83	(void)closedir(dirp);
84	if (rmdir(path))
85		t_info("rmdir(%s) failed %d\n", path, errno);
86
87	return;
88}
89
90static void
91use(dst_key_t *key, isc_mem_t *mctx, isc_result_t exp_result, int *nfails) {
92
93	isc_result_t ret;
94	const char *data = "This is some data";
95	unsigned char sig[512];
96	isc_buffer_t databuf, sigbuf;
97	isc_region_t datareg, sigreg;
98	dst_context_t *ctx = NULL;
99
100	isc_buffer_init(&sigbuf, sig, sizeof(sig));
101	isc_buffer_init(&databuf, data, strlen(data));
102	isc_buffer_add(&databuf, strlen(data));
103	isc_buffer_usedregion(&databuf, &datareg);
104
105	ret = dst_context_create(key, mctx, &ctx);
106	if (ret != exp_result) {
107		t_info("dst_context_create(%d) returned (%s) expected (%s)\n",
108		       dst_key_alg(key), dst_result_totext(ret),
109		       dst_result_totext(exp_result));
110		++*nfails;
111		return;
112	}
113	if (exp_result != ISC_R_SUCCESS)
114		return;
115	ret = dst_context_adddata(ctx, &datareg);
116	if (ret != ISC_R_SUCCESS) {
117		t_info("dst_context_adddata(%d) returned (%s)\n",
118		       dst_key_alg(key), dst_result_totext(ret));
119		++*nfails;
120		dst_context_destroy(&ctx);
121		return;
122	}
123	ret = dst_context_sign(ctx, &sigbuf);
124	if (ret != ISC_R_SUCCESS) {
125		t_info("dst_context_sign(%d) returned (%s)\n",
126		       dst_key_alg(key), dst_result_totext(ret));
127		++*nfails;
128		dst_context_destroy(&ctx);
129		return;
130	}
131	dst_context_destroy(&ctx);
132
133	isc_buffer_remainingregion(&sigbuf, &sigreg);
134	ret = dst_context_create(key, mctx, &ctx);
135	if (ret != ISC_R_SUCCESS) {
136		t_info("dst_context_create(%d) returned (%s)\n",
137		       dst_key_alg(key), dst_result_totext(ret));
138		++*nfails;
139		return;
140	}
141	ret = dst_context_adddata(ctx, &datareg);
142	if (ret != ISC_R_SUCCESS) {
143		t_info("dst_context_adddata(%d) returned (%s)\n",
144		       dst_key_alg(key), dst_result_totext(ret));
145		++*nfails;
146		dst_context_destroy(&ctx);
147		return;
148	}
149	ret = dst_context_verify(ctx, &sigreg);
150	if (ret != exp_result) {
151		t_info("dst_context_verify(%d) returned (%s) expected (%s)\n",
152		       dst_key_alg(key), dst_result_totext(ret),
153		       dst_result_totext(exp_result));
154		++*nfails;
155		dst_context_destroy(&ctx);
156		return;
157	}
158	dst_context_destroy(&ctx);
159}
160
161static void
162dh(dns_name_t *name1, int id1, dns_name_t *name2, int id2, isc_mem_t *mctx,
163   isc_result_t exp_result, int *nfails, int *nprobs)
164{
165	dst_key_t	*key1 = NULL, *key2 = NULL;
166	isc_result_t	ret;
167	char		current[PATH_MAX + 1];
168	char		tmp[PATH_MAX + 1];
169	char		*p;
170	int		alg = DST_ALG_DH;
171	int		type = DST_TYPE_PUBLIC|DST_TYPE_PRIVATE|DST_TYPE_KEY;
172	unsigned char	array1[1024], array2[1024];
173	isc_buffer_t	b1, b2;
174	isc_region_t	r1, r2;
175
176	UNUSED(exp_result);
177
178	p = getcwd(current, PATH_MAX);;
179	if (p == NULL) {
180		t_info("getcwd failed %d\n", errno);
181		++*nprobs;
182		return;
183	}
184
185	ret = dst_key_fromfile(name1, id1, alg, type, current, mctx, &key1);
186	if (ret != ISC_R_SUCCESS) {
187		t_info("dst_key_fromfile(%d) returned: %s\n",
188		       alg, dst_result_totext(ret));
189		++*nfails;
190		return;
191	}
192
193	ret = dst_key_fromfile(name2, id2, alg, type, current, mctx, &key2);
194	if (ret != ISC_R_SUCCESS) {
195		t_info("dst_key_fromfile(%d) returned: %s\n",
196		       alg, dst_result_totext(ret));
197		++*nfails;
198		return;
199	}
200
201	ret = isc_file_mktemplate("/tmp/", tmp, sizeof(tmp));
202	if (ret != ISC_R_SUCCESS) {
203		t_info("isc_file_mktemplate failed %s\n",
204		       isc_result_totext(ret));
205		++*nprobs;
206		return;
207	}
208
209	ret = isc_dir_createunique(tmp);
210	if (ret != ISC_R_SUCCESS) {
211		t_info("isc_dir_createunique failed %s\n",
212		       isc_result_totext(ret));
213		++*nprobs;
214		return;
215	}
216
217	ret = dst_key_tofile(key1, type, tmp);
218	if (ret != 0) {
219		t_info("dst_key_tofile(%d) returned: %s\n",
220		       alg, dst_result_totext(ret));
221		++*nfails;
222		return;
223	}
224
225	ret = dst_key_tofile(key2, type, tmp);
226	if (ret != 0) {
227		t_info("dst_key_tofile(%d) returned: %s\n",
228		       alg, dst_result_totext(ret));
229		++*nfails;
230		return;
231	}
232
233	cleandir(tmp);
234
235	isc_buffer_init(&b1, array1, sizeof(array1));
236	ret = dst_key_computesecret(key1, key2, &b1);
237	if (ret != 0) {
238		t_info("dst_computesecret() returned: %s\n",
239		       dst_result_totext(ret));
240		++*nfails;
241		return;
242	}
243
244	isc_buffer_init(&b2, array2, sizeof(array2));
245	ret = dst_key_computesecret(key2, key1, &b2);
246	if (ret != 0) {
247		t_info("dst_computesecret() returned: %s\n",
248		       dst_result_totext(ret));
249		++*nfails;
250		return;
251	}
252
253	isc_buffer_usedregion(&b1, &r1);
254	isc_buffer_usedregion(&b2, &r2);
255	if (r1.length != r2.length || memcmp(r1.base, r2.base, r1.length) != 0)
256	{
257		t_info("computed secrets don't match\n");
258		++*nfails;
259		return;
260	}
261
262	dst_key_free(&key1);
263	dst_key_free(&key2);
264}
265
266static void
267io(dns_name_t *name, int id, int alg, int type, isc_mem_t *mctx,
268   isc_result_t exp_result, int *nfails, int *nprobs)
269{
270	dst_key_t	*key = NULL;
271	isc_result_t	ret;
272	char		current[PATH_MAX + 1];
273	char		tmp[PATH_MAX + 1];
274	char		*p;
275
276	p = getcwd(current, PATH_MAX);;
277	if (p == NULL) {
278		t_info("getcwd failed %d\n", errno);
279		++*nprobs;
280		return;
281	}
282
283	ret = dst_key_fromfile(name, id, alg, type, current, mctx, &key);
284	if (ret != ISC_R_SUCCESS) {
285		t_info("dst_key_fromfile(%d) returned: %s\n",
286		       alg, dst_result_totext(ret));
287		++*nfails;
288		return;
289	}
290
291	ret = isc_file_mktemplate("/tmp/", tmp, sizeof(tmp));
292	if (ret != ISC_R_SUCCESS) {
293		t_info("isc_file_mktemplate failed %s\n",
294		       isc_result_totext(ret));
295		++*nprobs;
296		return;
297	}
298
299	ret = isc_dir_createunique(tmp);
300	if (ret != ISC_R_SUCCESS) {
301		t_info("mkdir failed %d\n", errno);
302		++*nprobs;
303		return;
304	}
305
306	ret = dst_key_tofile(key, type, tmp);
307	if (ret != 0) {
308		t_info("dst_key_tofile(%d) returned: %s\n",
309		       alg, dst_result_totext(ret));
310		++*nfails;
311		return;
312	}
313
314	if (dst_key_alg(key) != DST_ALG_DH)
315		use(key, mctx, exp_result, nfails);
316
317	cleandir(tmp);
318
319	dst_key_free(&key);
320}
321
322static void
323generate(int alg, isc_mem_t *mctx, int size, int *nfails) {
324	isc_result_t ret;
325	dst_key_t *key = NULL;
326
327	ret = dst_key_generate(dns_rootname, alg, size, 0, 0, 0,
328			       dns_rdataclass_in, mctx, &key);
329	if (ret != ISC_R_SUCCESS) {
330		t_info("dst_key_generate(%d) returned: %s\n", alg,
331		       dst_result_totext(ret));
332		++*nfails;
333		return;
334	}
335
336	if (alg != DST_ALG_DH)
337		use(key, mctx, ISC_R_SUCCESS, nfails);
338	dst_key_free(&key);
339}
340
341#define	DBUFSIZ	25
342
343static const char *a1 =
344		"the dst module provides the capability to "
345		"generate, store and retrieve public and private keys, "
346		"sign and verify data using the RSA, DSA and MD5 algorithms, "
347		"and compute Diffie-Hellman shared secrets.";
348static void
349t1(void) {
350	isc_mem_t	*mctx;
351	isc_entropy_t	*ectx;
352	int		nfails;
353	int		nprobs;
354	int		result;
355	isc_result_t	isc_result;
356	dns_fixedname_t	fname;
357	dns_name_t	*name;
358	isc_buffer_t	b;
359
360	t_assert("dst", 1, T_REQUIRED, "%s", a1);
361
362	nfails = 0;
363	nprobs = 0;
364	mctx = NULL;
365	isc_result = isc_mem_create(0, 0, &mctx);
366	if (isc_result != ISC_R_SUCCESS) {
367		t_info("isc_mem_create failed %s\n",
368		       isc_result_totext(isc_result));
369		t_result(T_UNRESOLVED);
370		return;
371	}
372	ectx = NULL;
373	isc_result = isc_entropy_create(mctx, &ectx);
374	if (isc_result != ISC_R_SUCCESS) {
375		t_info("isc_entropy_create failed %s\n",
376		       isc_result_totext(isc_result));
377		t_result(T_UNRESOLVED);
378		return;
379	}
380	isc_result = isc_entropy_createfilesource(ectx, "randomfile");
381	if (isc_result != ISC_R_SUCCESS) {
382		t_info("isc_entropy_create failed %s\n",
383		       isc_result_totext(isc_result));
384		t_result(T_UNRESOLVED);
385		return;
386	}
387	isc_result = dst_lib_init(mctx, ectx, ISC_ENTROPY_BLOCKING);
388	if (isc_result != ISC_R_SUCCESS) {
389		t_info("dst_lib_init failed %s\n",
390		       isc_result_totext(isc_result));
391		t_result(T_UNRESOLVED);
392		return;
393	}
394
395	if (!dst_algorithm_supported(DST_ALG_RSAMD5)) {
396		dst_lib_destroy();
397		t_info("library built without crypto support\n");
398		t_result(T_UNTESTED);
399		return;
400	}
401
402	t_info("testing use of stored keys [1]\n");
403
404	dns_fixedname_init(&fname);
405	name = dns_fixedname_name(&fname);
406	isc_buffer_init(&b, "test.", 5);
407	isc_buffer_add(&b, 5);
408	isc_result = dns_name_fromtext(name, &b, NULL, 0, NULL);
409	if (isc_result != ISC_R_SUCCESS) {
410		t_info("dns_name_fromtext failed %s\n",
411		       isc_result_totext(isc_result));
412		t_result(T_UNRESOLVED);
413		return;
414	}
415	io(name, 23616, DST_ALG_DSA, DST_TYPE_PRIVATE|DST_TYPE_PUBLIC,
416			mctx, ISC_R_SUCCESS, &nfails, &nprobs);
417	t_info("testing use of stored keys [2]\n");
418	io(name, 54622, DST_ALG_RSAMD5, DST_TYPE_PRIVATE|DST_TYPE_PUBLIC,
419			mctx, ISC_R_SUCCESS, &nfails, &nprobs);
420
421	t_info("testing use of stored keys [3]\n");
422	io(name, 49667, DST_ALG_DSA, DST_TYPE_PRIVATE|DST_TYPE_PUBLIC,
423			mctx, DST_R_NULLKEY, &nfails, &nprobs);
424	t_info("testing use of stored keys [4]\n");
425	io(name, 2, DST_ALG_RSAMD5, DST_TYPE_PRIVATE|DST_TYPE_PUBLIC,
426			mctx, DST_R_NULLKEY, &nfails, &nprobs);
427
428	isc_buffer_init(&b, "dh.", 3);
429	isc_buffer_add(&b, 3);
430	isc_result = dns_name_fromtext(name, &b, NULL, 0, NULL);
431	if (isc_result != ISC_R_SUCCESS) {
432		t_info("dns_name_fromtext failed %s\n",
433		       isc_result_totext(isc_result));
434		t_result(T_UNRESOLVED);
435		return;
436	}
437
438	dh(name, 18602, name, 48957, mctx, ISC_R_SUCCESS, &nfails, &nprobs);
439
440	t_info("testing use of generated keys\n");
441	generate(DST_ALG_RSAMD5, mctx, 512, &nfails);
442	generate(DST_ALG_DSA, mctx, 512, &nfails);
443	generate(DST_ALG_DH, mctx, 512, &nfails);
444	/*
445	 * This one uses a constant.
446	 */
447	generate(DST_ALG_DH, mctx, 768, &nfails);
448	generate(DST_ALG_HMACMD5, mctx, 512, &nfails);
449
450	dst_lib_destroy();
451
452	isc_entropy_detach(&ectx);
453
454	isc_mem_destroy(&mctx);
455
456	result = T_UNRESOLVED;
457	if ((nfails == 0) && (nprobs == 0))
458		result = T_PASS;
459	else if (nfails)
460		result = T_FAIL;
461	t_result(result);
462
463}
464
465#define	T_SIGMAX	512
466
467#undef	NEWSIG	/* Define NEWSIG to generate the original signature file. */
468
469#ifdef	NEWSIG
470
471/*
472 * Write a sig in buf to file at path.
473 */
474static int
475sig_tofile(char *path, isc_buffer_t *buf) {
476	int		rval;
477	int		fd;
478	int		len;
479	int		nprobs;
480	int		cnt;
481	unsigned char	c;
482	unsigned char	val;
483
484	cnt = 0;
485	nprobs = 0;
486	len = buf->used - buf->current;
487
488	t_info("buf: current %d used %d len %d\n",
489	       buf->current, buf->used, len);
490
491	fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRWXU|S_IRWXO|S_IRWXG);
492	if (fd < 0) {
493		t_info("open %s failed %d\n", path, errno);
494		return(1);
495	}
496
497	while (len) {
498		c = (unsigned char) isc_buffer_getuint8(buf);
499		val = ((c >> 4 ) & 0x0f);
500		if ((0 <= val) && (val <= 9))
501			val = '0' + val;
502		else
503			val = 'A' + val - 10;
504		rval = write(fd, &val, 1);
505		if (rval != 1) {
506			++nprobs;
507			t_info("write failed %d %d\n", rval, errno);
508			break;
509		}
510		val = (c & 0x0f);
511		if ((0 <= val) && (val <= 9))
512			val = '0' + val;
513		else
514			val = 'A' + val - 10;
515		rval = write(fd, &val, 1);
516		if (rval != 1) {
517			++nprobs;
518			t_info("write failed %d %d\n", rval, errno);
519			break;
520		}
521		--len;
522		++cnt;
523		if ((cnt % 16) == 0) {
524			val = '\n';
525			rval = write(fd, &val, 1);
526			if (rval != 1) {
527				++nprobs;
528				t_info("write failed %d %d\n", rval, errno);
529				break;
530			}
531		}
532	}
533	val = '\n';
534	rval = write(fd, &val, 1);
535	if (rval != 1) {
536		++nprobs;
537		t_info("write failed %d %d\n", rval, errno);
538	}
539	(void) close(fd);
540	return(nprobs);
541}
542
543#endif	/* NEWSIG */
544
545/*
546 * Read sig in file at path to buf.
547 */
548static int
549sig_fromfile(char *path, isc_buffer_t *iscbuf) {
550	int		rval;
551	int		len;
552	int		fd;
553	unsigned char	val;
554	struct stat	sb;
555	char		*p;
556	char		*buf;
557
558	rval = stat(path, &sb);
559	if (rval != 0) {
560		t_info("stat %s failed, errno == %d\n", path, errno);
561		return(1);
562	}
563
564	buf = (char *) malloc((sb.st_size + 1) * sizeof(unsigned char));
565	if (buf == NULL) {
566		t_info("malloc failed, errno == %d\n", errno);
567		return(1);
568	}
569
570	fd = open(path, O_RDONLY);
571	if (fd < 0) {
572		t_info("open failed, errno == %d\n", errno);
573		(void) free(buf);
574		return(1);
575	}
576
577	len = sb.st_size;
578	p = buf;
579	while (len) {
580		rval = read(fd, p, len);
581		if (rval > 0) {
582			len -= rval;
583			p += rval;
584		}
585		else {
586			t_info("read failed %d, errno == %d\n", rval, errno);
587			(void) free(buf);
588			(void) close(fd);
589			return(1);
590		}
591	}
592	close(fd);
593
594	p = buf;
595	len = sb.st_size;
596	while(len) {
597		if (*p == '\n') {
598			++p;
599			--len;
600			continue;
601		}
602		if (('0' <= *p) && (*p <= '9'))
603			val = *p - '0';
604		else
605			val = *p - 'A' + 10;
606		++p;
607		val <<= 4;
608		--len;
609		if (('0' <= *p) && (*p <= '9'))
610			val |= (*p - '0');
611		else
612			val |= (*p - 'A' + 10);
613		++p;
614		--len;
615		isc_buffer_putuint8(iscbuf, val);
616	}
617	(void) free(buf);
618	return(0);
619}
620
621static void
622t2_sigchk(char *datapath, char *sigpath, char *keyname,
623		int id, int alg, int type,
624		isc_mem_t *mctx, char *expected_result,
625		int *nfails, int *nprobs)
626{
627	int		rval;
628	int		len;
629	int		fd;
630	int		exp_res;
631	dst_key_t	*key = NULL;
632	unsigned char	sig[T_SIGMAX];
633	unsigned char	*p;
634	unsigned char	*data;
635	struct stat	sb;
636	isc_result_t	isc_result;
637	isc_buffer_t	databuf;
638	isc_buffer_t	sigbuf;
639	isc_region_t	datareg;
640	isc_region_t	sigreg;
641	dns_fixedname_t	fname;
642	dns_name_t	*name;
643	isc_buffer_t	b;
644	dst_context_t	*ctx = NULL;
645
646	/*
647	 * Read data from file in a form usable by dst_verify.
648	 */
649	rval = stat(datapath, &sb);
650	if (rval != 0) {
651		t_info("t2_sigchk: stat (%s) failed %d\n", datapath, errno);
652		++*nprobs;
653		return;
654	}
655
656	data = (unsigned char *) malloc(sb.st_size * sizeof(char));
657	if (data == NULL) {
658		t_info("t2_sigchk: malloc failed %d\n", errno);
659		++*nprobs;
660		return;
661	}
662
663	fd = open(datapath, O_RDONLY);
664	if (fd < 0) {
665		t_info("t2_sigchk: open failed %d\n", errno);
666		(void) free(data);
667		++*nprobs;
668		return;
669	}
670
671	p = data;
672	len = sb.st_size;
673	do {
674		rval = read(fd, p, len);
675		if (rval > 0) {
676			len -= rval;
677			p += rval;
678		}
679	} while (len);
680	(void) close(fd);
681
682	/*
683	 * Read key from file in a form usable by dst_verify.
684	 */
685	dns_fixedname_init(&fname);
686	name = dns_fixedname_name(&fname);
687	isc_buffer_init(&b, keyname, strlen(keyname));
688	isc_buffer_add(&b, strlen(keyname));
689	isc_result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
690	if (isc_result != ISC_R_SUCCESS) {
691		t_info("dns_name_fromtext failed %s\n",
692			isc_result_totext(isc_result));
693		(void) free(data);
694		++*nprobs;
695		return;
696	}
697	isc_result = dst_key_fromfile(name, id, alg, type, NULL, mctx, &key);
698	if (isc_result != ISC_R_SUCCESS) {
699		t_info("dst_key_fromfile failed %s\n",
700			isc_result_totext(isc_result));
701		(void) free(data);
702		++*nprobs;
703		return;
704	}
705
706	isc_buffer_init(&databuf, data, sb.st_size);
707	isc_buffer_add(&databuf, sb.st_size);
708	isc_buffer_usedregion(&databuf, &datareg);
709
710#ifdef	NEWSIG
711
712	/*
713	 * If we're generating a signature for the first time,
714	 * sign the data and save the signature to a file
715	 */
716
717	memset(sig, 0, sizeof(sig));
718	isc_buffer_init(&sigbuf, sig, sizeof(sig));
719
720	isc_result = dst_context_create(key, mctx, &ctx);
721	if (isc_result != ISC_R_SUCCESS) {
722		t_info("dst_context_create(%d) failed %s\n",
723		       dst_result_totext(isc_result));
724		(void) free(data);
725		dst_key_free(&key);
726		++*nprobs;
727		return;
728	}
729	isc_result = dst_context_adddata(ctx, &datareg);
730	if (isc_result != ISC_R_SUCCESS) {
731		t_info("dst_context_adddata(%d) failed %s\n",
732		       dst_result_totext(isc_result));
733		(void) free(data);
734		dst_key_free(&key);
735		dst_context_destroy(&ctx);
736		++*nprobs;
737		return;
738	}
739	isc_result = dst_context_sign(ctx, &sigbuf);
740	if (isc_result != ISC_R_SUCCESS) {
741		t_info("dst_sign(%d) failed %s\n",
742		       dst_result_totext(isc_result));
743		(void) free(data);
744		dst_key_free(&key);
745		dst_context_destroy(&ctx);
746		++*nprobs;
747		return;
748	}
749	dst_context_destroy(&ctx);
750
751	rval = sig_tofile(sigpath, &sigbuf);
752	if (rval != 0) {
753		t_info("sig_tofile failed\n");
754		++*nprobs;
755		(void) free(data);
756		dst_key_free(&key);
757		return;
758	}
759
760#endif	/* NEWSIG */
761
762	memset(sig, 0, sizeof(sig));
763	isc_buffer_init(&sigbuf, sig, sizeof(sig));
764
765	/*
766	 * Read precomputed signature from file in a form usable by dst_verify.
767	 */
768	rval = sig_fromfile(sigpath, &sigbuf);
769	if (rval != 0) {
770		t_info("sig_fromfile failed\n");
771		(void) free(data);
772		dst_key_free(&key);
773		++*nprobs;
774		return;
775	}
776
777	/*
778	 * Verify that the key signed the data.
779	 */
780	isc_buffer_remainingregion(&sigbuf, &sigreg);
781
782	exp_res = 0;
783	if (strstr(expected_result, "!"))
784		exp_res = 1;
785
786	isc_result = dst_context_create(key, mctx, &ctx);
787	if (isc_result != ISC_R_SUCCESS) {
788		t_info("dst_context_create returned %s\n",
789			isc_result_totext(isc_result));
790		++*nfails;
791	}
792	isc_result = dst_context_adddata(ctx, &datareg);
793	if (isc_result != ISC_R_SUCCESS) {
794		t_info("dst_context_adddata returned %s\n",
795			isc_result_totext(isc_result));
796		dst_context_destroy(&ctx);
797		++*nfails;
798	}
799	isc_result = dst_context_verify(ctx, &sigreg);
800	if (	((exp_res == 0) && (isc_result != ISC_R_SUCCESS))	||
801		((exp_res != 0) && (isc_result == ISC_R_SUCCESS)))	{
802
803		t_info("dst_context_verify returned %s, expected %s\n",
804			isc_result_totext(isc_result),
805			expected_result);
806		dst_context_destroy(&ctx);
807		++*nfails;
808	}
809
810	(void) free(data);
811	dst_context_destroy(&ctx);
812	dst_key_free(&key);
813	return;
814}
815
816/*
817 * The astute observer will note that t1() signs then verifies data
818 * during the test but that t2() verifies data that has been
819 * signed at some earlier time, possibly with an entire different
820 * version or implementation of the DSA and RSA algorithms
821 */
822static const char *a2 =
823		"the dst module provides the capability to "
824		"verify data signed with the RSA and DSA algorithms";
825
826/*
827 * av ==  datafile, sigpath, keyname, keyid, alg, exp_result.
828 */
829static int
830t2_vfy(char **av) {
831	char		*datapath;
832	char		*sigpath;
833	char		*keyname;
834	char		*key;
835	int		keyid;
836	char		*alg;
837	int		algid;
838	char		*exp_result;
839	int		nfails;
840	int		nprobs;
841	isc_mem_t	*mctx;
842	isc_entropy_t	*ectx;
843	isc_result_t	isc_result;
844	int		result;
845
846	datapath	= *av++;
847	sigpath		= *av++;
848	keyname		= *av++;
849	key		= *av++;
850	keyid		= atoi(key);
851	alg		= *av++;
852	exp_result	= *av++;
853	nfails		= 0;
854	nprobs		= 0;
855
856	if (! strcasecmp(alg, "DST_ALG_DSA"))
857		algid = DST_ALG_DSA;
858	else if (! strcasecmp(alg, "DST_ALG_RSAMD5"))
859		algid = DST_ALG_RSAMD5;
860	else {
861		t_info("Unknown algorithm %s\n", alg);
862		return(T_UNRESOLVED);
863	}
864
865	mctx = NULL;
866	isc_result = isc_mem_create(0, 0, &mctx);
867	if (isc_result != ISC_R_SUCCESS) {
868		t_info("isc_mem_create failed %s\n",
869		       isc_result_totext(isc_result));
870		return(T_UNRESOLVED);
871	}
872	ectx = NULL;
873	isc_result = isc_entropy_create(mctx, &ectx);
874	if (isc_result != ISC_R_SUCCESS) {
875		t_info("isc_entropy_create failed %s\n",
876		       isc_result_totext(isc_result));
877		return(T_UNRESOLVED);
878	}
879	isc_result = isc_entropy_createfilesource(ectx, "randomfile");
880	if (isc_result != ISC_R_SUCCESS) {
881		t_info("isc_entropy_create failed %s\n",
882		       isc_result_totext(isc_result));
883		return(T_UNRESOLVED);
884	}
885	isc_result = dst_lib_init(mctx, ectx, ISC_ENTROPY_BLOCKING);
886	if (isc_result != ISC_R_SUCCESS) {
887		t_info("dst_lib_init failed %s\n",
888		       isc_result_totext(isc_result));
889		return(T_UNRESOLVED);
890	}
891
892	if (!dst_algorithm_supported(DST_ALG_RSAMD5)) {
893		dst_lib_destroy();
894		t_info("library built without crypto support\n");
895		return (T_UNTESTED);
896	}
897
898	t_info("testing %s, %s, %s, %s, %s, %s\n",
899			datapath, sigpath, keyname, key, alg, exp_result);
900	t2_sigchk(datapath, sigpath, keyname, keyid,
901			algid, DST_TYPE_PRIVATE|DST_TYPE_PUBLIC,
902			mctx, exp_result,
903			&nfails, &nprobs);
904
905	dst_lib_destroy();
906
907	isc_entropy_detach(&ectx);
908
909	isc_mem_destroy(&mctx);
910
911	result = T_UNRESOLVED;
912	if (nfails)
913		result = T_FAIL;
914	else if ((nfails == 0) && (nprobs == 0))
915		result = T_PASS;
916
917	return(result);
918}
919
920static void
921t2(void) {
922	int	result;
923	t_assert("dst", 2, T_REQUIRED, "%s", a2);
924	result = t_eval("dst_2_data", t2_vfy, 6);
925	t_result(result);
926}
927
928testspec_t	T_testlist[] = {
929	{	t1,	"basic dst module verification"	},
930	{	t2,	"signature ineffability"	},
931	{	NULL,	NULL				}
932};
933
934