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