diff options
Diffstat (limited to '')
-rw-r--r-- | bin/tools/nsec3hash.c | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/bin/tools/nsec3hash.c b/bin/tools/nsec3hash.c new file mode 100644 index 0000000..a6a5ec3 --- /dev/null +++ b/bin/tools/nsec3hash.c @@ -0,0 +1,194 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdarg.h> +#include <stdbool.h> +#include <stdlib.h> + +#include <isc/attributes.h> +#include <isc/base32.h> +#include <isc/buffer.h> +#include <isc/commandline.h> +#include <isc/file.h> +#include <isc/hex.h> +#include <isc/iterated_hash.h> +#include <isc/print.h> +#include <isc/result.h> +#include <isc/string.h> +#include <isc/types.h> +#include <isc/util.h> + +#include <dns/fixedname.h> +#include <dns/name.h> +#include <dns/nsec3.h> +#include <dns/types.h> + +const char *program = "nsec3hash"; + +noreturn static void +fatal(const char *format, ...); + +static void +fatal(const char *format, ...) { + va_list args; + + fprintf(stderr, "%s: ", program); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + exit(1); +} + +static void +check_result(isc_result_t result, const char *message) { + if (result != ISC_R_SUCCESS) { + fatal("%s: %s", message, isc_result_totext(result)); + } +} + +static void +usage(void) { + fprintf(stderr, "Usage: %s salt algorithm iterations domain\n", + program); + fprintf(stderr, " %s -r algorithm flags iterations salt domain\n", + program); + exit(1); +} + +typedef void +nsec3printer(unsigned algo, unsigned flags, unsigned iters, const char *saltstr, + const char *domain, const char *digest); + +static void +nsec3hash(nsec3printer *nsec3print, const char *algostr, const char *flagstr, + const char *iterstr, const char *saltstr, const char *domain) { + dns_fixedname_t fixed; + dns_name_t *name; + isc_buffer_t buffer; + isc_region_t region; + isc_result_t result; + unsigned char hash[NSEC3_MAX_HASH_LENGTH]; + unsigned char salt[DNS_NSEC3_SALTSIZE]; + unsigned char text[1024]; + unsigned int hash_alg; + unsigned int flags; + unsigned int length; + unsigned int iterations; + unsigned int salt_length; + const char dash[] = "-"; + + if (strcmp(saltstr, "-") == 0) { + salt_length = 0; + salt[0] = 0; + } else { + isc_buffer_init(&buffer, salt, sizeof(salt)); + result = isc_hex_decodestring(saltstr, &buffer); + check_result(result, "isc_hex_decodestring(salt)"); + salt_length = isc_buffer_usedlength(&buffer); + if (salt_length > DNS_NSEC3_SALTSIZE) { + fatal("salt too long"); + } + if (salt_length == 0) { + saltstr = dash; + } + } + hash_alg = atoi(algostr); + if (hash_alg > 255U) { + fatal("hash algorithm too large"); + } + flags = flagstr == NULL ? 0 : atoi(flagstr); + if (flags > 255U) { + fatal("flags too large"); + } + iterations = atoi(iterstr); + if (iterations > 0xffffU) { + fatal("iterations to large"); + } + + name = dns_fixedname_initname(&fixed); + isc_buffer_constinit(&buffer, domain, strlen(domain)); + isc_buffer_add(&buffer, strlen(domain)); + result = dns_name_fromtext(name, &buffer, dns_rootname, 0, NULL); + check_result(result, "dns_name_fromtext() failed"); + + dns_name_downcase(name, name, NULL); + length = isc_iterated_hash(hash, hash_alg, iterations, salt, + salt_length, name->ndata, name->length); + if (length == 0) { + fatal("isc_iterated_hash failed"); + } + region.base = hash; + region.length = length; + isc_buffer_init(&buffer, text, sizeof(text)); + isc_base32hexnp_totext(®ion, 1, "", &buffer); + isc_buffer_putuint8(&buffer, '\0'); + + nsec3print(hash_alg, flags, iterations, saltstr, domain, (char *)text); +} + +static void +nsec3hash_print(unsigned algo, unsigned flags, unsigned iters, + const char *saltstr, const char *domain, const char *digest) { + UNUSED(flags); + UNUSED(domain); + + fprintf(stdout, "%s (salt=%s, hash=%u, iterations=%u)\n", digest, + saltstr, algo, iters); +} + +static void +nsec3hash_rdata_print(unsigned algo, unsigned flags, unsigned iters, + const char *saltstr, const char *domain, + const char *digest) { + fprintf(stdout, "%s NSEC3 %u %u %u %s %s\n", domain, algo, flags, iters, + saltstr, digest); +} + +int +main(int argc, char *argv[]) { + bool rdata_format = false; + int ch; + + while ((ch = isc_commandline_parse(argc, argv, "-r")) != -1) { + switch (ch) { + case 'r': + rdata_format = true; + break; + case '-': + isc_commandline_index -= 1; + goto skip; + default: + break; + } + } + +skip: + argc -= isc_commandline_index; + argv += isc_commandline_index; + + if (rdata_format) { + if (argc != 5) { + usage(); + } + nsec3hash(nsec3hash_rdata_print, argv[0], argv[1], argv[2], + argv[3], argv[4]); + } else { + if (argc != 4) { + usage(); + } + nsec3hash(nsec3hash_print, argv[1], NULL, argv[2], argv[0], + argv[3]); + } + return (0); +} |