4 * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2001 Internet Software Consortium.
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.
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.
20 /* Id: t_dst.c,v 1.58 2009/09/01 00:22:25 jinmei Exp */
24 #include <sys/types.h> /* Required for dirent.h */
27 #include <dirent.h> /* XXX */
33 #include <unistd.h> /* XXX */
35 #include <isc/buffer.h>
37 #include <isc/entropy.h>
40 #include <isc/region.h>
41 #include <isc/string.h>
44 #include <dns/fixedname.h>
48 #include <dst/result.h>
50 #include <tests/t_api.h>
57 * Adapted from the original dst_test.c program.
58 * XXXDCL should use isc_dir_*.
62 cleandir(char *path
) {
65 char fullname
[PATH_MAX
+ 1];
69 t_info("opendir(%s) failed %d\n", path
, errno
);
73 while ((pe
= readdir(dirp
)) != NULL
) {
74 if (! strcmp(pe
->d_name
, "."))
76 if (! strcmp(pe
->d_name
, ".."))
78 strcpy(fullname
, path
);
79 strcat(fullname
, "/");
80 strcat(fullname
, pe
->d_name
);
82 t_info("remove(%s) failed %d\n", fullname
, errno
);
87 t_info("rmdir(%s) failed %d\n", path
, errno
);
93 use(dst_key_t
*key
, isc_mem_t
*mctx
, isc_result_t exp_result
, int *nfails
) {
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
;
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
);
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
));
115 if (exp_result
!= ISC_R_SUCCESS
)
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
));
122 dst_context_destroy(&ctx
);
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
));
130 dst_context_destroy(&ctx
);
133 dst_context_destroy(&ctx
);
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
));
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
));
148 dst_context_destroy(&ctx
);
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
));
157 dst_context_destroy(&ctx
);
160 dst_context_destroy(&ctx
);
164 dh(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
)
167 dst_key_t
*key1
= NULL
, *key2
= NULL
;
169 char current
[PATH_MAX
+ 1];
170 char tmp
[PATH_MAX
+ 1];
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];
180 p
= getcwd(current
, PATH_MAX
);;
182 t_info("getcwd failed %d\n", errno
);
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
));
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
));
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
));
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
));
219 ret
= dst_key_tofile(key1
, type
, tmp
);
221 t_info("dst_key_tofile(%d) returned: %s\n",
222 alg
, dst_result_totext(ret
));
227 ret
= dst_key_tofile(key2
, type
, tmp
);
229 t_info("dst_key_tofile(%d) returned: %s\n",
230 alg
, dst_result_totext(ret
));
237 isc_buffer_init(&b1
, array1
, sizeof(array1
));
238 ret
= dst_key_computesecret(key1
, key2
, &b1
);
240 t_info("dst_computesecret() returned: %s\n",
241 dst_result_totext(ret
));
246 isc_buffer_init(&b2
, array2
, sizeof(array2
));
247 ret
= dst_key_computesecret(key2
, key1
, &b2
);
249 t_info("dst_computesecret() returned: %s\n",
250 dst_result_totext(ret
));
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)
259 t_info("computed secrets don't match\n");
269 io(dns_name_t
*name
, int id
, int alg
, int type
, isc_mem_t
*mctx
,
270 isc_result_t exp_result
, int *nfails
, int *nprobs
)
272 dst_key_t
*key
= NULL
;
274 char current
[PATH_MAX
+ 1];
275 char tmp
[PATH_MAX
+ 1];
278 p
= getcwd(current
, PATH_MAX
);;
280 t_info("getcwd failed %d\n", errno
);
285 ret
= dst_key_fromfile(name
, id
, alg
, type
, current
, mctx
, &key
);
286 if (ret
!= ISC_R_SUCCESS
) {
287 t_info("dst_key_fromfile(%d) returned: %s\n",
288 alg
, dst_result_totext(ret
));
293 ret
= isc_file_mktemplate("/tmp/", tmp
, sizeof(tmp
));
294 if (ret
!= ISC_R_SUCCESS
) {
295 t_info("isc_file_mktemplate failed %s\n",
296 isc_result_totext(ret
));
301 ret
= isc_dir_createunique(tmp
);
302 if (ret
!= ISC_R_SUCCESS
) {
303 t_info("mkdir failed %d\n", errno
);
308 ret
= dst_key_tofile(key
, type
, tmp
);
310 t_info("dst_key_tofile(%d) returned: %s\n",
311 alg
, dst_result_totext(ret
));
316 if (dst_key_alg(key
) != DST_ALG_DH
)
317 use(key
, mctx
, exp_result
, nfails
);
325 generate(int alg
, isc_mem_t
*mctx
, int size
, int *nfails
) {
327 dst_key_t
*key
= NULL
;
329 ret
= dst_key_generate(dns_rootname
, alg
, size
, 0, 0, 0,
330 dns_rdataclass_in
, mctx
, &key
);
331 if (ret
!= ISC_R_SUCCESS
) {
332 t_info("dst_key_generate(%d) returned: %s\n", alg
,
333 dst_result_totext(ret
));
338 if (alg
!= DST_ALG_DH
)
339 use(key
, mctx
, ISC_R_SUCCESS
, nfails
);
345 static const char *a1
=
346 "the dst module provides the capability to "
347 "generate, store and retrieve public and private keys, "
348 "sign and verify data using the RSA, DSA and MD5 algorithms, "
349 "and compute Diffie-Hellman shared secrets.";
357 isc_result_t isc_result
;
358 dns_fixedname_t fname
;
362 t_assert("dst", 1, T_REQUIRED
, "%s", a1
);
367 isc_result
= isc_mem_create(0, 0, &mctx
);
368 if (isc_result
!= ISC_R_SUCCESS
) {
369 t_info("isc_mem_create failed %s\n",
370 isc_result_totext(isc_result
));
371 t_result(T_UNRESOLVED
);
375 isc_result
= isc_entropy_create(mctx
, &ectx
);
376 if (isc_result
!= ISC_R_SUCCESS
) {
377 t_info("isc_entropy_create failed %s\n",
378 isc_result_totext(isc_result
));
379 t_result(T_UNRESOLVED
);
382 isc_result
= isc_entropy_createfilesource(ectx
, "randomfile");
383 if (isc_result
!= ISC_R_SUCCESS
) {
384 t_info("isc_entropy_create failed %s\n",
385 isc_result_totext(isc_result
));
386 t_result(T_UNRESOLVED
);
389 isc_result
= dst_lib_init(mctx
, ectx
, ISC_ENTROPY_BLOCKING
);
390 if (isc_result
!= ISC_R_SUCCESS
) {
391 t_info("dst_lib_init failed %s\n",
392 isc_result_totext(isc_result
));
393 t_result(T_UNRESOLVED
);
397 if (!dst_algorithm_supported(DST_ALG_RSAMD5
)) {
399 t_info("library built without crypto support\n");
400 t_result(T_UNTESTED
);
404 t_info("testing use of stored keys [1]\n");
406 dns_fixedname_init(&fname
);
407 name
= dns_fixedname_name(&fname
);
408 isc_buffer_init(&b
, "test.", 5);
409 isc_buffer_add(&b
, 5);
410 isc_result
= dns_name_fromtext(name
, &b
, NULL
, 0, NULL
);
411 if (isc_result
!= ISC_R_SUCCESS
) {
412 t_info("dns_name_fromtext failed %s\n",
413 isc_result_totext(isc_result
));
414 t_result(T_UNRESOLVED
);
417 io(name
, 23616, DST_ALG_DSA
, DST_TYPE_PRIVATE
|DST_TYPE_PUBLIC
,
418 mctx
, ISC_R_SUCCESS
, &nfails
, &nprobs
);
419 t_info("testing use of stored keys [2]\n");
420 io(name
, 54622, DST_ALG_RSAMD5
, DST_TYPE_PRIVATE
|DST_TYPE_PUBLIC
,
421 mctx
, ISC_R_SUCCESS
, &nfails
, &nprobs
);
423 t_info("testing use of stored keys [3]\n");
424 io(name
, 49667, DST_ALG_DSA
, DST_TYPE_PRIVATE
|DST_TYPE_PUBLIC
,
425 mctx
, DST_R_NULLKEY
, &nfails
, &nprobs
);
426 t_info("testing use of stored keys [4]\n");
427 io(name
, 2, DST_ALG_RSAMD5
, DST_TYPE_PRIVATE
|DST_TYPE_PUBLIC
,
428 mctx
, DST_R_NULLKEY
, &nfails
, &nprobs
);
430 isc_buffer_init(&b
, "dh.", 3);
431 isc_buffer_add(&b
, 3);
432 isc_result
= dns_name_fromtext(name
, &b
, NULL
, 0, NULL
);
433 if (isc_result
!= ISC_R_SUCCESS
) {
434 t_info("dns_name_fromtext failed %s\n",
435 isc_result_totext(isc_result
));
436 t_result(T_UNRESOLVED
);
440 dh(name
, 18602, name
, 48957, mctx
, ISC_R_SUCCESS
, &nfails
, &nprobs
);
442 t_info("testing use of generated keys\n");
443 generate(DST_ALG_RSAMD5
, mctx
, 512, &nfails
);
444 generate(DST_ALG_DSA
, mctx
, 512, &nfails
);
445 generate(DST_ALG_DH
, mctx
, 512, &nfails
);
447 * This one uses a constant.
449 generate(DST_ALG_DH
, mctx
, 768, &nfails
);
450 generate(DST_ALG_HMACMD5
, mctx
, 512, &nfails
);
454 isc_entropy_detach(&ectx
);
456 isc_mem_destroy(&mctx
);
458 result
= T_UNRESOLVED
;
459 if ((nfails
== 0) && (nprobs
== 0))
469 #undef NEWSIG /* Define NEWSIG to generate the original signature file. */
474 * Write a sig in buf to file at path.
477 sig_tofile(char *path
, isc_buffer_t
*buf
) {
488 len
= buf
->used
- buf
->current
;
490 t_info("buf: current %d used %d len %d\n",
491 buf
->current
, buf
->used
, len
);
493 fd
= open(path
, O_CREAT
|O_TRUNC
|O_WRONLY
, S_IRWXU
|S_IRWXO
|S_IRWXG
);
495 t_info("open %s failed %d\n", path
, errno
);
500 c
= (unsigned char) isc_buffer_getuint8(buf
);
501 val
= ((c
>> 4 ) & 0x0f);
502 if ((0 <= val
) && (val
<= 9))
505 val
= 'A' + val
- 10;
506 rval
= write(fd
, &val
, 1);
509 t_info("write failed %d %d\n", rval
, errno
);
513 if ((0 <= val
) && (val
<= 9))
516 val
= 'A' + val
- 10;
517 rval
= write(fd
, &val
, 1);
520 t_info("write failed %d %d\n", rval
, errno
);
525 if ((cnt
% 16) == 0) {
527 rval
= write(fd
, &val
, 1);
530 t_info("write failed %d %d\n", rval
, errno
);
536 rval
= write(fd
, &val
, 1);
539 t_info("write failed %d %d\n", rval
, errno
);
548 * Read sig in file at path to buf.
551 sig_fromfile(char *path
, isc_buffer_t
*iscbuf
) {
560 rval
= stat(path
, &sb
);
562 t_info("stat %s failed, errno == %d\n", path
, errno
);
566 buf
= (char *) malloc((sb
.st_size
+ 1) * sizeof(unsigned char));
568 t_info("malloc failed, errno == %d\n", errno
);
572 fd
= open(path
, O_RDONLY
);
574 t_info("open failed, errno == %d\n", errno
);
582 rval
= read(fd
, p
, len
);
588 t_info("read failed %d, errno == %d\n", rval
, errno
);
604 if (('0' <= *p
) && (*p
<= '9'))
611 if (('0' <= *p
) && (*p
<= '9'))
614 val
|= (*p
- 'A' + 10);
617 isc_buffer_putuint8(iscbuf
, val
);
624 t2_sigchk(char *datapath
, char *sigpath
, char *keyname
,
625 int id
, int alg
, int type
,
626 isc_mem_t
*mctx
, char *expected_result
,
627 int *nfails
, int *nprobs
)
633 dst_key_t
*key
= NULL
;
634 unsigned char sig
[T_SIGMAX
];
638 isc_result_t isc_result
;
639 isc_buffer_t databuf
;
641 isc_region_t datareg
;
643 dns_fixedname_t fname
;
646 dst_context_t
*ctx
= NULL
;
649 * Read data from file in a form usable by dst_verify.
651 rval
= stat(datapath
, &sb
);
653 t_info("t2_sigchk: stat (%s) failed %d\n", datapath
, errno
);
658 data
= (unsigned char *) malloc(sb
.st_size
* sizeof(char));
660 t_info("t2_sigchk: malloc failed %d\n", errno
);
665 fd
= open(datapath
, O_RDONLY
);
667 t_info("t2_sigchk: open failed %d\n", errno
);
676 rval
= read(fd
, p
, len
);
685 * Read key from file in a form usable by dst_verify.
687 dns_fixedname_init(&fname
);
688 name
= dns_fixedname_name(&fname
);
689 isc_buffer_init(&b
, keyname
, strlen(keyname
));
690 isc_buffer_add(&b
, strlen(keyname
));
691 isc_result
= dns_name_fromtext(name
, &b
, dns_rootname
, 0, NULL
);
692 if (isc_result
!= ISC_R_SUCCESS
) {
693 t_info("dns_name_fromtext failed %s\n",
694 isc_result_totext(isc_result
));
699 isc_result
= dst_key_fromfile(name
, id
, alg
, type
, NULL
, mctx
, &key
);
700 if (isc_result
!= ISC_R_SUCCESS
) {
701 t_info("dst_key_fromfile failed %s\n",
702 isc_result_totext(isc_result
));
708 isc_buffer_init(&databuf
, data
, sb
.st_size
);
709 isc_buffer_add(&databuf
, sb
.st_size
);
710 isc_buffer_usedregion(&databuf
, &datareg
);
715 * If we're generating a signature for the first time,
716 * sign the data and save the signature to a file
719 memset(sig
, 0, sizeof(sig
));
720 isc_buffer_init(&sigbuf
, sig
, sizeof(sig
));
722 isc_result
= dst_context_create(key
, mctx
, &ctx
);
723 if (isc_result
!= ISC_R_SUCCESS
) {
724 t_info("dst_context_create(%d) failed %s\n",
725 dst_result_totext(isc_result
));
731 isc_result
= dst_context_adddata(ctx
, &datareg
);
732 if (isc_result
!= ISC_R_SUCCESS
) {
733 t_info("dst_context_adddata(%d) failed %s\n",
734 dst_result_totext(isc_result
));
737 dst_context_destroy(&ctx
);
741 isc_result
= dst_context_sign(ctx
, &sigbuf
);
742 if (isc_result
!= ISC_R_SUCCESS
) {
743 t_info("dst_sign(%d) failed %s\n",
744 dst_result_totext(isc_result
));
747 dst_context_destroy(&ctx
);
751 dst_context_destroy(&ctx
);
753 rval
= sig_tofile(sigpath
, &sigbuf
);
755 t_info("sig_tofile failed\n");
764 memset(sig
, 0, sizeof(sig
));
765 isc_buffer_init(&sigbuf
, sig
, sizeof(sig
));
768 * Read precomputed signature from file in a form usable by dst_verify.
770 rval
= sig_fromfile(sigpath
, &sigbuf
);
772 t_info("sig_fromfile failed\n");
780 * Verify that the key signed the data.
782 isc_buffer_remainingregion(&sigbuf
, &sigreg
);
785 if (strstr(expected_result
, "!"))
788 isc_result
= dst_context_create(key
, mctx
, &ctx
);
789 if (isc_result
!= ISC_R_SUCCESS
) {
790 t_info("dst_context_create returned %s\n",
791 isc_result_totext(isc_result
));
794 isc_result
= dst_context_adddata(ctx
, &datareg
);
795 if (isc_result
!= ISC_R_SUCCESS
) {
796 t_info("dst_context_adddata returned %s\n",
797 isc_result_totext(isc_result
));
798 dst_context_destroy(&ctx
);
801 isc_result
= dst_context_verify(ctx
, &sigreg
);
802 if ( ((exp_res
== 0) && (isc_result
!= ISC_R_SUCCESS
)) ||
803 ((exp_res
!= 0) && (isc_result
== ISC_R_SUCCESS
))) {
805 t_info("dst_context_verify returned %s, expected %s\n",
806 isc_result_totext(isc_result
),
808 dst_context_destroy(&ctx
);
813 dst_context_destroy(&ctx
);
819 * The astute observer will note that t1() signs then verifies data
820 * during the test but that t2() verifies data that has been
821 * signed at some earlier time, possibly with an entire different
822 * version or implementation of the DSA and RSA algorithms
824 static const char *a2
=
825 "the dst module provides the capability to "
826 "verify data signed with the RSA and DSA algorithms";
829 * av == datafile, sigpath, keyname, keyid, alg, exp_result.
845 isc_result_t isc_result
;
858 if (! strcasecmp(alg
, "DST_ALG_DSA"))
860 else if (! strcasecmp(alg
, "DST_ALG_RSAMD5"))
861 algid
= DST_ALG_RSAMD5
;
863 t_info("Unknown algorithm %s\n", alg
);
864 return(T_UNRESOLVED
);
868 isc_result
= isc_mem_create(0, 0, &mctx
);
869 if (isc_result
!= ISC_R_SUCCESS
) {
870 t_info("isc_mem_create failed %s\n",
871 isc_result_totext(isc_result
));
872 return(T_UNRESOLVED
);
875 isc_result
= isc_entropy_create(mctx
, &ectx
);
876 if (isc_result
!= ISC_R_SUCCESS
) {
877 t_info("isc_entropy_create failed %s\n",
878 isc_result_totext(isc_result
));
879 return(T_UNRESOLVED
);
881 isc_result
= isc_entropy_createfilesource(ectx
, "randomfile");
882 if (isc_result
!= ISC_R_SUCCESS
) {
883 t_info("isc_entropy_create failed %s\n",
884 isc_result_totext(isc_result
));
885 return(T_UNRESOLVED
);
887 isc_result
= dst_lib_init(mctx
, ectx
, ISC_ENTROPY_BLOCKING
);
888 if (isc_result
!= ISC_R_SUCCESS
) {
889 t_info("dst_lib_init failed %s\n",
890 isc_result_totext(isc_result
));
891 return(T_UNRESOLVED
);
894 if (!dst_algorithm_supported(DST_ALG_RSAMD5
)) {
896 t_info("library built without crypto support\n");
900 t_info("testing %s, %s, %s, %s, %s, %s\n",
901 datapath
, sigpath
, keyname
, key
, alg
, exp_result
);
902 t2_sigchk(datapath
, sigpath
, keyname
, keyid
,
903 algid
, DST_TYPE_PRIVATE
|DST_TYPE_PUBLIC
,
909 isc_entropy_detach(&ectx
);
911 isc_mem_destroy(&mctx
);
913 result
= T_UNRESOLVED
;
916 else if ((nfails
== 0) && (nprobs
== 0))
925 t_assert("dst", 2, T_REQUIRED
, "%s", a2
);
926 result
= t_eval("dst_2_data", t2_vfy
, 6);
930 testspec_t T_testlist
[] = {
931 { t1
, "basic dst module verification" },
932 { t2
, "signature ineffability" },