xref: /netbsd-src/external/mpl/bind/dist/bin/tools/nsec3hash.c (revision 9fd8799cb5ceb66c69f2eb1a6d26a1d587ba1f1e)
1 /*	$NetBSD: nsec3hash.c,v 1.4 2020/05/24 19:46:19 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 #include <stdarg.h>
15 #include <stdbool.h>
16 #include <stdlib.h>
17 
18 #include <isc/base32.h>
19 #include <isc/buffer.h>
20 #include <isc/commandline.h>
21 #include <isc/file.h>
22 #include <isc/hex.h>
23 #include <isc/iterated_hash.h>
24 #include <isc/print.h>
25 #include <isc/result.h>
26 #include <isc/string.h>
27 #include <isc/types.h>
28 #include <isc/util.h>
29 
30 #include <dns/fixedname.h>
31 #include <dns/name.h>
32 #include <dns/nsec3.h>
33 #include <dns/types.h>
34 
35 const char *program = "nsec3hash";
36 
37 ISC_PLATFORM_NORETURN_PRE static void
38 fatal(const char *format, ...) ISC_PLATFORM_NORETURN_POST;
39 
40 static void
41 fatal(const char *format, ...) {
42 	va_list args;
43 
44 	fprintf(stderr, "%s: ", program);
45 	va_start(args, format);
46 	vfprintf(stderr, format, args);
47 	va_end(args);
48 	fprintf(stderr, "\n");
49 	exit(1);
50 }
51 
52 static void
53 check_result(isc_result_t result, const char *message) {
54 	if (result != ISC_R_SUCCESS) {
55 		fatal("%s: %s", message, isc_result_totext(result));
56 	}
57 }
58 
59 static void
60 usage(void) {
61 	fprintf(stderr, "Usage: %s salt algorithm iterations domain\n",
62 		program);
63 	fprintf(stderr, "       %s -r algorithm flags iterations salt domain\n",
64 		program);
65 	exit(1);
66 }
67 
68 typedef void
69 nsec3printer(unsigned algo, unsigned flags, unsigned iters, const char *saltstr,
70 	     const char *domain, const char *digest);
71 
72 static void
73 nsec3hash(nsec3printer *nsec3print, const char *algostr, const char *flagstr,
74 	  const char *iterstr, const char *saltstr, const char *domain) {
75 	dns_fixedname_t fixed;
76 	dns_name_t *name;
77 	isc_buffer_t buffer;
78 	isc_region_t region;
79 	isc_result_t result;
80 	unsigned char hash[NSEC3_MAX_HASH_LENGTH];
81 	unsigned char salt[DNS_NSEC3_SALTSIZE];
82 	unsigned char text[1024];
83 	unsigned int hash_alg;
84 	unsigned int flags;
85 	unsigned int length;
86 	unsigned int iterations;
87 	unsigned int salt_length;
88 	const char dash[] = "-";
89 
90 	if (strcmp(saltstr, "-") == 0) {
91 		salt_length = 0;
92 		salt[0] = 0;
93 	} else {
94 		isc_buffer_init(&buffer, salt, sizeof(salt));
95 		result = isc_hex_decodestring(saltstr, &buffer);
96 		check_result(result, "isc_hex_decodestring(salt)");
97 		salt_length = isc_buffer_usedlength(&buffer);
98 		if (salt_length > DNS_NSEC3_SALTSIZE) {
99 			fatal("salt too long");
100 		}
101 		if (salt_length == 0) {
102 			saltstr = dash;
103 		}
104 	}
105 	hash_alg = atoi(algostr);
106 	if (hash_alg > 255U) {
107 		fatal("hash algorithm too large");
108 	}
109 	flags = flagstr == NULL ? 0 : atoi(flagstr);
110 	if (flags > 255U) {
111 		fatal("flags too large");
112 	}
113 	iterations = atoi(iterstr);
114 	if (iterations > 0xffffU) {
115 		fatal("iterations to large");
116 	}
117 
118 	name = dns_fixedname_initname(&fixed);
119 	isc_buffer_constinit(&buffer, domain, strlen(domain));
120 	isc_buffer_add(&buffer, strlen(domain));
121 	result = dns_name_fromtext(name, &buffer, dns_rootname, 0, NULL);
122 	check_result(result, "dns_name_fromtext() failed");
123 
124 	dns_name_downcase(name, name, NULL);
125 	length = isc_iterated_hash(hash, hash_alg, iterations, salt,
126 				   salt_length, name->ndata, name->length);
127 	if (length == 0) {
128 		fatal("isc_iterated_hash failed");
129 	}
130 	region.base = hash;
131 	region.length = length;
132 	isc_buffer_init(&buffer, text, sizeof(text));
133 	isc_base32hexnp_totext(&region, 1, "", &buffer);
134 	isc_buffer_putuint8(&buffer, '\0');
135 
136 	nsec3print(hash_alg, flags, iterations, saltstr, domain, (char *)text);
137 }
138 
139 static void
140 nsec3hash_print(unsigned algo, unsigned flags, unsigned iters,
141 		const char *saltstr, const char *domain, const char *digest) {
142 	UNUSED(flags);
143 	UNUSED(domain);
144 
145 	fprintf(stdout, "%s (salt=%s, hash=%u, iterations=%u)\n", digest,
146 		saltstr, algo, iters);
147 }
148 
149 static void
150 nsec3hash_rdata_print(unsigned algo, unsigned flags, unsigned iters,
151 		      const char *saltstr, const char *domain,
152 		      const char *digest) {
153 	fprintf(stdout, "%s NSEC3 %u %u %u %s %s\n", domain, algo, flags, iters,
154 		saltstr, digest);
155 }
156 
157 int
158 main(int argc, char *argv[]) {
159 	bool rdata_format = false;
160 	int ch;
161 
162 	while ((ch = isc_commandline_parse(argc, argv, "-r")) != -1) {
163 		switch (ch) {
164 		case 'r':
165 			rdata_format = true;
166 			break;
167 		case '-':
168 			isc_commandline_index -= 1;
169 			goto skip;
170 		default:
171 			break;
172 		}
173 	}
174 
175 skip:
176 	argc -= isc_commandline_index;
177 	argv += isc_commandline_index;
178 
179 	if (rdata_format) {
180 		if (argc != 5) {
181 			usage();
182 		}
183 		nsec3hash(nsec3hash_rdata_print, argv[0], argv[1], argv[2],
184 			  argv[3], argv[4]);
185 	} else {
186 		if (argc != 4) {
187 			usage();
188 		}
189 		nsec3hash(nsec3hash_print, argv[1], NULL, argv[2], argv[0],
190 			  argv[3]);
191 	}
192 	return (0);
193 }
194