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(®ion, 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