diff --git a/CHANGES b/CHANGES index 9ddc566e84..ccb3131258 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +5982. [func] Extend dig to allow requests to be signed using SIG(0) + as well as providing a mechanism to specify the signing + time. [GL !5923] + +5981. [test] Add dns_message_checksig fuzzer to check messages + signed using TSIG or SIG(0). [GL !5923] + 5980. [func] The internal isc_entropy API provider has been changed from OpenSSL RAND_bytes() to uv_random() to use system provided entropy. [GL !6803] diff --git a/bin/dig/dig.c b/bin/dig/dig.c index fd3e2d4013..1fcb242558 100644 --- a/bin/dig/dig.c +++ b/bin/dig/dig.c @@ -1522,8 +1522,31 @@ plus_option(char *option, bool is_batchfile, bool *need_clone, } break; case 'f': /* fail */ - FULLCHECK("fail"); - lookup->servfail_stops = state; + switch (cmd[1]) { + case 'a': + FULLCHECK("fail"); + lookup->servfail_stops = state; + break; + case 'u': + FULLCHECK("fuzztime"); + lookup->fuzzing = state; + if (lookup->fuzzing) { + if (value == NULL) { + lookup->fuzztime = 0x622acce1; + break; + } + result = parse_uint(&num, value, 0xffffffff, + "fuzztime"); + if (result != ISC_R_SUCCESS) { + warn("Couldn't parse fuzztime"); + goto exit_or_usage; + } + lookup->fuzztime = num; + } + break; + default: + goto invalid_option; + } break; case 'h': switch (cmd[1]) { diff --git a/bin/dig/dig.rst b/bin/dig/dig.rst index 409dee4b28..c3b7e90b9d 100644 --- a/bin/dig/dig.rst +++ b/bin/dig/dig.rst @@ -132,12 +132,14 @@ Options .. option:: -k keyfile - This option tells :iscman:`named` to sign queries using TSIG using a key read from the given file. Key - files can be generated using :iscman:`tsig-keygen`. When using TSIG - authentication with :program:`dig`, the name server that is queried needs to - know the key and algorithm that is being used. In BIND, this is done - by providing appropriate ``key`` and ``server`` statements in - :iscman:`named.conf`. + This option tells :program:`dig` to sign queries using TSIG or + SIG(0) using a key read from the given file. Key files can be + generated using :iscman:`tsig-keygen`. When using TSIG authentication + with :program:`dig`, the name server that is queried needs to + know the key and algorithm that is being used. In BIND, this is + done by providing appropriate ``key`` and ``server`` statements + in :iscman:`named.conf` for TSIG and by looking up the KEY record + in zone data for SIG(0). .. option:: -m @@ -386,6 +388,14 @@ abbreviation is unambiguous; for example, :option:`+cd` is equivalent to to not try the next server, which is the reverse of normal stub resolver behavior. +.. option:: +fuzztime[=value], +nofuzztime + + This option allows the signing time to be specified when generating + signed messages. If a value is specified it is the seconds since + 00:00:00 January 1, 1970 UTC ignoring leap seconds. If no value + is specified 1646972129 (Fri 11 Mar 2022 04:15:29 UTC) is used. + The default is ``+nofuzztime`` and the current time is used. + .. option:: +header-only, +noheader-only This option sends a query with a DNS header without a question section. The diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 3c9e50fad5..519c7ef0b1 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -143,6 +143,7 @@ const dns_name_t *hmacname = NULL; unsigned int digestbits = 0; isc_buffer_t *namebuf = NULL; dns_tsigkey_t *tsigkey = NULL; +dst_key_t *sig0key = NULL; bool validated = true; bool debugging = false; bool debugtiming = false; @@ -794,6 +795,8 @@ clone_lookup(dig_lookup_t *lookold, bool servers) { looknew->done_as_is = lookold->done_as_is; looknew->dscp = lookold->dscp; looknew->rrcomments = lookold->rrcomments; + looknew->fuzzing = lookold->fuzzing; + looknew->fuzztime = lookold->fuzztime; if (lookold->ecs_addr != NULL) { size_t len = sizeof(isc_sockaddr_t); @@ -1141,6 +1144,10 @@ setup_file_key(void) { debug("setup_file_key()"); + if (sig0key != NULL) { + dst_key_free(&sig0key); + } + /* Try reading the key from a K* pair */ result = dst_key_fromnamedfile( keyfile, NULL, DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, &dstkey); @@ -1178,18 +1185,20 @@ setup_file_key(void) { case DST_ALG_HMACSHA512: hmacname = DNS_TSIG_HMACSHA512_NAME; break; - default: - printf(";; Couldn't create key %s: bad algorithm\n", - keynametext); - goto failure; } - result = dns_tsigkey_createfromkey(dst_key_name(dstkey), hmacname, - dstkey, false, NULL, 0, 0, mctx, - NULL, &tsigkey); - if (result != ISC_R_SUCCESS) { - printf(";; Couldn't create key %s: %s\n", keynametext, - isc_result_totext(result)); - goto failure; + + if (hmacname != NULL) { + result = dns_tsigkey_createfromkey( + dst_key_name(dstkey), hmacname, dstkey, false, NULL, 0, + 0, mctx, NULL, &tsigkey); + if (result != ISC_R_SUCCESS) { + printf(";; Couldn't create key %s: %s\n", keynametext, + isc_result_totext(result)); + goto failure; + } + } else { + dst_key_attach(dstkey, &sig0key); + dst_key_free(&dstkey); } failure: if (dstkey != NULL) { @@ -2425,6 +2434,15 @@ setup_lookup(dig_lookup_t *lookup) { debug("initializing keys"); result = dns_message_settsigkey(lookup->sendmsg, tsigkey); check_result(result, "dns_message_settsigkey"); + } else if (sig0key != NULL) { + debug("initializing keys"); + result = dns_message_setsig0key(lookup->sendmsg, sig0key); + check_result(result, "dns_message_setsig0key"); + } + + if (lookup->fuzzing) { + lookup->sendmsg->fuzzing = true; + lookup->sendmsg->fuzztime = lookup->fuzztime; } lookup->sendspace = isc_mem_get(mctx, COMMSIZE); @@ -4654,10 +4672,17 @@ destroy_libs(void) { clear_searchlist(); if (tsigkey != NULL) { - debug("freeing key %p", tsigkey); + debug("freeing TSIG key %p", tsigkey); dns_tsigkey_detach(&tsigkey); } + + if (sig0key != NULL) { + debug("freeing SIG(0) key %p", sig0key); + dst_key_free(&sig0key); + } + if (namebuf != NULL) { + debug("freeing key %p", tsigkey); isc_buffer_free(&namebuf); } diff --git a/bin/dig/dighost.h b/bin/dig/dighost.h index ecc20832a0..966e7a1a2c 100644 --- a/bin/dig/dighost.h +++ b/bin/dig/dighost.h @@ -108,10 +108,11 @@ struct dig_lookup { isc_refcount_t references; bool aaonly, adflag, badcookie, besteffort, cdflag, cleared, comments, dns64prefix, dnssec, doing_xfr, done_as_is, ednsneg, expandaaaa, - expire, header_only, identify, /*%< Append an "on server " - message */ - identify_previous_line, /*% Prepend a "Nameserver :" - message, with newline and tab */ + expire, fuzzing, header_only, identify, /*%< Append an "on + server " message + */ + identify_previous_line, /*% Prepend a "Nameserver :" + message, with newline and tab */ idnin, idnout, ignore, multiline, need_search, new_search, noclass, nocrypto, nottl, ns_search_only, /*%< dig +nssearch, host -C */ @@ -188,6 +189,7 @@ struct dig_lookup { char *tls_key_file; isc_tlsctx_cache_t *tls_ctx_cache; }; + isc_stdtime_t fuzztime; }; /*% The dig_query structure */ diff --git a/doc/man/dig.1in b/doc/man/dig.1in index 171d7fc602..0b0b87c1bb 100644 --- a/doc/man/dig.1in +++ b/doc/man/dig.1in @@ -153,12 +153,14 @@ Print a usage summary. .INDENT 0.0 .TP .B \-k keyfile -This option tells \fI\%named\fP to sign queries using TSIG using a key read from the given file. Key -files can be generated using \fI\%tsig\-keygen\fP\&. When using TSIG -authentication with \fBdig\fP, the name server that is queried needs to -know the key and algorithm that is being used. In BIND, this is done -by providing appropriate \fBkey\fP and \fBserver\fP statements in -\fI\%named.conf\fP\&. +This option tells \fBdig\fP to sign queries using TSIG or +SIG(0) using a key read from the given file. Key files can be +generated using \fI\%tsig\-keygen\fP\&. When using TSIG authentication +with \fBdig\fP, the name server that is queried needs to +know the key and algorithm that is being used. In BIND, this is +done by providing appropriate \fBkey\fP and \fBserver\fP statements +in \fI\%named.conf\fP for TSIG and by looking up the KEY record +in zone data for SIG(0). .UNINDENT .INDENT 0.0 .TP @@ -448,6 +450,15 @@ resolver behavior. .UNINDENT .INDENT 0.0 .TP +.B +fuzztime[=value], +nofuzztime +This option allows the signing time to be specified when generating +signed messages. If a value is specified it is the seconds since +00:00:00 January 1, 1970 UTC ignoring leap seconds. If no value +is specified 1646972129 (Fri 11 Mar 2022 04:15:29 UTC) is used. +The default is \fB+nofuzztime\fP and the current time is used. +.UNINDENT +.INDENT 0.0 +.TP .B +header\-only, +noheader\-only This option sends a query with a DNS header without a question section. The default is to add a question section. The query type and query name diff --git a/fuzz/.gitignore b/fuzz/.gitignore index 2f9818c6ec..7d03848c63 100644 --- a/fuzz/.gitignore +++ b/fuzz/.gitignore @@ -1,6 +1,7 @@ /*.dSYM/ /*.out/ /dns_master_load +/dns_message_checksig /dns_message_parse /dns_name_fromtext_target /dns_rdata_fromtext diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am index 021156da95..eb4a2f4ad6 100644 --- a/fuzz/Makefile.am +++ b/fuzz/Makefile.am @@ -23,6 +23,7 @@ libfuzzmain_la_SOURCES = \ check_PROGRAMS = \ dns_master_load \ + dns_message_checksig \ dns_message_parse \ dns_name_fromtext_target \ dns_rdata_fromtext \ @@ -32,6 +33,7 @@ check_PROGRAMS = \ EXTRA_DIST = \ dns_master_load.in \ + dns_message_checksig.in \ dns_message_parse.in \ dns_name_fromtext_target.in \ dns_rdata_fromtext.in \ diff --git a/fuzz/dns_message_checksig.c b/fuzz/dns_message_checksig.c new file mode 100644 index 0000000000..81a55d70e6 --- /dev/null +++ b/fuzz/dns_message_checksig.c @@ -0,0 +1,413 @@ +/* + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "fuzz.h" + +bool debug = false; + +static isc_mem_t *mctx = NULL; + +/* + * Packet dumps of validily signed request ./IN/SOA + * requests. + * + * TSIG: + * + * 0x0000: 600b 0900 006a 1140 0000 0000 0000 0000 + * 0x0010: 0000 0000 0000 0001 0000 0000 0000 0000 + * 0x0020: 0000 0000 0000 0001 cc88 0035 006a 007d + * 0x0030: 1dfa 0000 0001 0000 0000 0001 0000 0600 + * 0x0040: 0108 7473 6967 2d6b 6579 0000 fa00 ff00 + * 0x0050: 0000 0000 3d0b 686d 6163 2d73 6861 3235 + * 0x0060: 3600 0000 622a cce1 012c 0020 224d 5807 + * 0x0070: 648d 1400 9d8e fc1c d049 55e9 cc90 2187 + * 0x0080: 3b5f af5c 8899 dc27 c8df b34b 1dfa 0000 + * 0x0090: 0000 + * + * SIG(0): + * + * 0x0000: 6004 0e00 013f 1140 0000 0000 0000 0000 + * 0x0010: 0000 0000 0000 0001 0000 0000 0000 0000 + * 0x0020: 0000 0000 0000 0001 c0a7 0035 013f 0152 + * 0x0030: 0000 0000 0001 0000 0000 0001 0000 0600 + * 0x0040: 0100 0018 00ff 0000 0000 011b 0000 0800 + * 0x0050: 0000 0000 622a ce0d 622a cbb5 da71 0773 + * 0x0060: 6967 306b 6579 0068 988b 27bf 5c89 5270 + * 0x0070: c5ba ea8b 2e10 0512 9b44 48d3 69de b7ec + * 0x0080: 7c67 15f3 6bc7 b0dc 277b e8f1 6979 4c89 + * 0x0090: 149a 0203 30a1 c0b7 a711 ee8a 8d90 ebb9 + * 0x00a0: 9e33 dd65 33d5 5d1d 90db cf9c bb6a b346 + * 0x00b0: 568f a399 71d7 c877 616d 2fb7 0f86 963f + * 0x00c0: aa00 850d 180a 9f83 cd4b d115 c79f 64c9 + * 0x00d0: ff05 e751 6810 28b3 2249 c4ba 2d8d 57ba + * 0x00e0: 9aad f1fc b34e c237 9465 04fd fe4d 19c9 + * 0x00f0: 2368 ec8e 7097 eaea e067 2b9c 06eb c383 + * 0x0100: e901 a11e 606b 4cce c12a 0e57 8c09 b7cb + * 0x0110: 23bb ec05 b68b 1852 9288 b665 fe89 cf62 + * 0x0120: 0a41 5e5a acbe 6903 cbb7 e7b6 cab4 e4a2 + * 0x0130: b98f 884f c09d 5b39 c695 c84c 9a92 f110 + * 0x0140: ccc3 f2ee 313f a2a1 1cda 5aa2 faec d593 + * 0x0150: 4514 724a 868f 94b9 0547 4dc9 7b73 c85e + * 0x0160: 544c 73d4 e892 f9 + */ + +#define HMACSHA256 "\x0bhmac-sha256" + +static isc_stdtime_t fuzztime = 0x622acce1; +static dns_view_t *view = NULL; +static dns_tsigkey_t *tsigkey = NULL; +static dns_tsig_keyring_t *ring = NULL; +static dns_tsig_keyring_t *emptyring = NULL; + +static void +cleanup(void) { + if (view != NULL) { + dns_view_detach(&view); + } + if (tsigkey != NULL) { + dns_tsigkey_detach(&tsigkey); + } + if (ring != NULL) { + dns_tsigkeyring_detach(&ring); + } + if (emptyring != NULL) { + dns_tsigkeyring_detach(&emptyring); + } + if (mctx != NULL) { + isc_mem_detach(&mctx); + } +} + +int +LLVMFuzzerInitialize(int *argc __attribute__((unused)), + char ***argv __attribute__((unused))) { + isc_result_t result; + dns_fixedname_t fixed; + dns_name_t *name = dns_fixedname_initname(&fixed); + unsigned char secret[16] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff }; + dns_zone_t *zone = NULL; + + atexit(cleanup); + + isc_mem_create(&mctx); + + result = dst_lib_init(mctx, NULL); + if (result != ISC_R_SUCCESS) { + return (1); + } + + result = dns_view_create(mctx, dns_rdataclass_in, "view", &view); + if (result != ISC_R_SUCCESS) { + return (1); + } + + result = dns_tsigkeyring_create(mctx, &ring); + if (result != ISC_R_SUCCESS) { + return (1); + } + + result = dns_tsigkeyring_create(mctx, &emptyring); + if (result != ISC_R_SUCCESS) { + return (1); + } + + result = dns_name_fromstring(name, "tsig-key", 0, NULL); + if (result != ISC_R_SUCCESS) { + return (1); + } + + result = dns_tsigkey_create(name, dns_tsig_hmacsha256_name, secret, + sizeof(secret), false, NULL, 0, 0, mctx, + ring, &tsigkey); + if (result != ISC_R_SUCCESS) { + return (1); + } + + result = dns_name_fromstring(name, "sig0key", 0, NULL); + if (result != ISC_R_SUCCESS) { + return (1); + } + + result = dns_zone_create(&zone, mctx, 0); + if (result != ISC_R_SUCCESS) { + return (1); + } + + result = dns_zone_setorigin(zone, name); + if (result != ISC_R_SUCCESS) { + return (1); + } + + dns_zone_setclass(zone, view->rdclass); + dns_zone_settype(zone, dns_zone_primary); + + result = dns_zone_setkeydirectory(zone, "dns_message_checksig.data"); + if (result != ISC_R_SUCCESS) { + return (1); + } + + result = dns_zone_setfile(zone, "dns_message_checksig.data/sig0key.db", + dns_masterformat_text, + &dns_master_style_default); + if (result != ISC_R_SUCCESS) { + return (1); + } + + result = dns_zone_load(zone, false); + if (result != ISC_R_SUCCESS) { + return (1); + } + + result = dns_view_addzone(view, zone); + if (result != ISC_R_SUCCESS) { + return (1); + } + + dns_view_freeze(view); + + dns_zone_detach(&zone); + + return (0); +} + +static isc_result_t +create_message(dns_message_t **messagep, const uint8_t *data, size_t size, + bool addasig, bool addtsig) { + isc_result_t result; + dns_message_t *message = NULL; + isc_buffer_t b; + unsigned char buf[65535]; + + isc_buffer_init(&b, buf, sizeof(buf)); + + /* Message ID */ + isc_buffer_putuint16(&b, 0); + + /* QR, Opcode, other flags = 0, rcode = 0 */ + isc_buffer_putuint16(&b, (*data & 0x1f) << 11); + /* Counts */ + isc_buffer_putuint16(&b, 1); + isc_buffer_putuint16(&b, 0); + isc_buffer_putuint16(&b, 0); + isc_buffer_putuint16(&b, addasig ? 1 : 0); + + /* Question ./IN/SOA */ + isc_buffer_putuint8(&b, 0); + isc_buffer_putuint16(&b, 6); + isc_buffer_putuint16(&b, 1); + + if (addasig) { + /* Signature */ + if (addtsig) { + const unsigned char keyname[] = "\x08tsig-key"; + isc_buffer_putmem(&b, keyname, sizeof(keyname)); + isc_buffer_putuint16(&b, dns_rdatatype_tsig); + isc_buffer_putuint16(&b, dns_rdataclass_any); + } else { + isc_buffer_putuint8(&b, 0); /* '.' */ + isc_buffer_putuint16(&b, dns_rdatatype_sig); + isc_buffer_putuint16(&b, dns_rdataclass_in); + } + isc_buffer_putuint32(&b, 0); /* ttl */ + data++; + size--; + if (size > isc_buffer_availablelength(&b) - 2) { + size = isc_buffer_availablelength(&b) - 2; + } + isc_buffer_putuint16(&b, size); + isc_buffer_putmem(&b, data, size); + } + + dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &message); + + result = dns_message_parse(message, &b, 0); + if (debug) { + fprintf(stderr, "dns_message_parse => %s\n", + isc_result_totext(result)); + } + if (result != ISC_R_SUCCESS) { + dns_message_detach(&message); + } else { + if (debug) { + char text[200000]; + isc_buffer_init(&b, text, sizeof(text)); + + result = dns_message_totext( + message, &dns_master_style_debug, 0, &b); + if (result == ISC_R_SUCCESS) { + fprintf(stderr, "%.*s", (int)b.used, text); + } else { + fprintf(stderr, "dns_message_totext => %s\n", + isc_result_totext(result)); + } + } + *messagep = message; + } + return (result); +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + isc_result_t result; + dns_message_t *message = NULL; + unsigned char query_tsig[23 + 32 + 6] = { 0 }; + bool addasig = false; + bool addtime = false; + bool addtsig = false; + bool setquerytsig = false; + bool settsigkey = false; + bool subtime = false; + bool withring = false; + bool withview = false; + + /* + * The first 2 octets affect setup. + * Octet 1 determines whether a signature is added and which type + * (addasig, addtsig), whether time should be adjusted (addtime, + * subtime), whether dns_message_setquerytsig and dns_message_settsigkey + * have been called, whether there is a keyring available with the + * TSIG key or a view is defined. + * + * The second octet defines if the message is a response and the + * opcode. + */ + if (size > 65535 || size < 2) { + return (0); + } + + addasig = (*data & 0x80) != 0; + addtime = (*data & 0x40) != 0; + addtsig = (*data & 0x20) != 0; + setquerytsig = (*data & 0x10) != 0; + settsigkey = (*data & 0x08) != 0; + subtime = (*data & 0x04) != 0; + withring = (*data & 0x02) != 0; + withview = (*data & 0x01) != 0; + + data++; + size--; + + if (debug) { + fprintf(stderr, + "addasig=%u addtime=%u addtsig=%u setquerytsig=%u " + "settsigkey=%u subtime=%u withring=%u\nwithview=%u\n", + addasig, addtime, addtsig, setquerytsig, settsigkey, + subtime, withring, withview); + } + + result = create_message(&message, data, size, addasig, addtsig); + if (result != ISC_R_SUCCESS) { + return (0); + } + + /* + * Make time calculations consistent. + */ + message->fuzzing = 1; + message->fuzztime = fuzztime; + if (addtime) { + message->fuzztime += 1200; + } + if (subtime) { + message->fuzztime -= 1200; + } + + if ((message->flags & DNS_MESSAGEFLAG_QR) != 0) { + if (setquerytsig) { + isc_buffer_t b; + unsigned char hmacname[] = HMACSHA256; + unsigned char hmac[32] = { + 0x22, 0x4d, 0x58, 0x07, 0x64, 0x8d, 0x14, 0x00, + 0x9d, 0x8e, 0xfc, 0x1c, 0xd0, 0x49, 0x55, 0xe9, + 0xcc, 0x90, 0x21, 0x87, 0x3b, 0x5f, 0xaf, 0x5c, + 0x88, 0x99, 0xdc, 0x27, 0xc8, 0xdf, 0xb3, 0x4b + }; + + /* + * Valid TSIG rdata for tsig-key over a plain + * DNS QUERY for ./SOA/IN with no flags set. + */ + isc_buffer_init(&b, query_tsig, sizeof(query_tsig)); + isc_buffer_putmem(&b, hmacname, sizeof(hmacname)); + isc_buffer_putuint16(&b, 0); /* time high */ + isc_buffer_putuint32(&b, 0x622abec0); /* time low */ + isc_buffer_putuint16(&b, 300); /* Fudge */ + isc_buffer_putuint16(&b, 32); /* Mac Length */ + /* Mac */ + isc_buffer_putmem(&b, hmac, 32); + isc_buffer_putuint16(&b, 7674); /* Original Id */ + isc_buffer_putuint16(&b, 0); /* Error */ + isc_buffer_putuint16(&b, 0); /* Other len */ + + dns_message_setquerytsig(message, &b); + } + } + + if (settsigkey) { + result = dns_message_settsigkey(message, tsigkey); + if (debug) { + fprintf(stderr, "dns_message_settsigkey => %s\n", + isc_result_totext(result)); + } + } + + dns_view_setkeyring(view, withring ? ring : emptyring); + + result = dns_message_checksig(message, withview ? view : NULL); + if (debug) { + char textbuf[64]; + isc_buffer_t b; + + fprintf(stderr, "dns_message_checksig => %s\n", + isc_result_totext(result)); + isc_buffer_init(&b, textbuf, sizeof(textbuf)); + dns_tsigrcode_totext(message->tsigstatus, &b); + fprintf(stderr, "tsigstatus=%.*s\n", (int)b.used, textbuf); + isc_buffer_init(&b, textbuf, sizeof(textbuf)); + dns_tsigrcode_totext(message->sig0status, &b); + fprintf(stderr, "sig0status=%.*s\n", (int)b.used, textbuf); + } + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + +cleanup: + if (message != NULL) { + dns_message_detach(&message); + } + + return (0); +} diff --git a/fuzz/dns_message_checksig.data/Ksig0key.+008+55921.key b/fuzz/dns_message_checksig.data/Ksig0key.+008+55921.key new file mode 100644 index 0000000000..84575a001a --- /dev/null +++ b/fuzz/dns_message_checksig.data/Ksig0key.+008+55921.key @@ -0,0 +1 @@ +sig0key. IN KEY 512 3 8 AwEAAa22lgHi1vAbQvu5ETdTrm2H8rwga9tvyMa6LFiSDyevLvSv0Uo5 uvfrXnxaLdtBMts6e1Ly2piSH9JRbOGMNibOK4EXWhWAn8MII4SWgQAs bFwtiz4HyPn2wScrUQdo8DocKiQJBanesr7vDO8fdA6Rg1e0yAtSeNti e8avx46/HJa6CFs3CoE0sf6oOFSxM954AgCBTXOGNBt1Nt3Bhfqt2qyA TLFii5K1jLDTZDVkoiyDXL1M7wcTwKf9METgj1eQmH3GGlRM/OJ/j8xk ZiFGbL3cipWdiH48031jiV2hlc92mKn8Ya0d9AN6c44piza/JSFydZXw sY32nxzjDbs= diff --git a/fuzz/dns_message_checksig.data/Ksig0key.+008+55921.private b/fuzz/dns_message_checksig.data/Ksig0key.+008+55921.private new file mode 100644 index 0000000000..4acc2142a4 --- /dev/null +++ b/fuzz/dns_message_checksig.data/Ksig0key.+008+55921.private @@ -0,0 +1,13 @@ +Private-key-format: v1.3 +Algorithm: 8 (RSASHA256) +Modulus: rbaWAeLW8BtC+7kRN1OubYfyvCBr22/IxrosWJIPJ68u9K/RSjm69+tefFot20Ey2zp7UvLamJIf0lFs4Yw2Js4rgRdaFYCfwwgjhJaBACxsXC2LPgfI+fbBJytRB2jwOhwqJAkFqd6yvu8M7x90DpGDV7TIC1J422J7xq/Hjr8clroIWzcKgTSx/qg4VLEz3ngCAIFNc4Y0G3U23cGF+q3arIBMsWKLkrWMsNNkNWSiLINcvUzvBxPAp/0wROCPV5CYfcYaVEz84n+PzGRmIUZsvdyKlZ2IfjzTfWOJXaGVz3aYqfxhrR30A3pzjimLNr8lIXJ1lfCxjfafHOMNuw== +PublicExponent: AQAB +PrivateExponent: GDfclFkR5ToFGH9rMTRMnP73Q5dzjLgkx4vyHcuzKtxcvAans4+hNj+NazckAy2E+mpzV2j95TJ4wZjSM2RvB5xLwBIc4Dg6oyAHL6Ikoae6gw64cHFOaYb808n8CyqWqfX+QWAz9sRSVZXnTuPViX3A+svR7ejVak9Bzr1NTDm0DFlrhaKVCYA++dKVZerfuNiXT/jQvrc4wMCa7WWsfLsFO8aTNkEhqUnmS9c5VYgr7MkCV4ENDBcISpQc9wElI0hl12QPaSj8iSdk9liYp+HTiOxOyp6BGGuecKAoQijMwrZy4qExdOxvowptll8+nZLtwGRn/un/xvIZY5OLAQ== +Prime1: ww3C6jwnrLQik/zxSgC0KuqgHq68cCjiRjwK2/euzs7NkMevFpXvV0cWO8x1/wKC1mszVLsUaKTvH6fzRsXfz5MPihzNzUYFwvobKVLserSxEwHNk+FKUU+q07Kf8WWnCqX5nX9QzVG1q4J8Q44N49I5S480jHLGYbyLZrEYMQE= +Prime2: 4/3Ozq/8vRgcO4bieFs4CbZR7C98HiTi65SiLBIKY09mDfCleZI0uurAYBluZJgHS5AC5cdyHFuJr3uKxvD+Mgdlru40U6cSCEdK7HAhyUGZUndWl28wyMEB6Kke1/owxVn0S4RKLPOgFI2668H6JObaqXf0wyY89RdVQP6VQrs= +Exponent1: Tbr9MyVX1j5PDVSev5P6OKQZvUB7PeM9ESo6VaCl3CqTxx+cic6ke86LcLcxSrewdkxwP1LydiVMWfwvOcP/RhRf+/Uwmp5OC35qNpSiQuAhNObiCw2b9T1fYU/s52FQKTEtgXNMOxZV5IxyguVoaaLMTG08TsAqiKZ/kyP99QE= +Exponent2: Q4qSNKrwLbixzHS2LL+hR0dK17RtiaSV0QKUVIf3qdoAusp6yxwkIOegnBeMm6JqLtl38kh2pq37iRAJWcxVEc8dMYiB2fJZpjgwmwDREYUsfcC611vqUN7UyO8pIwSMZDq045ZKPyzhVJV0NZmemEYHq0LNMO7oCheiewGwiDc= +Coefficient: T2u/J4NgyO+OqoLpXBIpTBzqrvDk8tb0feYgsp5d16hHvbXxNkMUR8cI07RdbI9HnEldtmhAnbQ6SvFiy2YYjpw/1Fz2WwdxRqLaDV7UlhrT+CqltvU9d/N/xThBNKDa23Wf5Vat+HRiLHSgzsY1PseVCWN+g4azuK2D8+DLeHE= +Created: 20220311073606 +Publish: 20220311073606 +Activate: 20220311073606 diff --git a/fuzz/dns_message_checksig.data/sig0key.db b/fuzz/dns_message_checksig.data/sig0key.db new file mode 100644 index 0000000000..ecf15bf14a --- /dev/null +++ b/fuzz/dns_message_checksig.data/sig0key.db @@ -0,0 +1,14 @@ +; 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. + +sig0key. 0 IN SOA . . 0 0 0 0 0 +sig0key. 0 IN NS . +sig0key. 0 IN KEY 512 3 8 AwEAAa22lgHi1vAbQvu5ETdTrm2H8rwga9tvyMa6LFiSDyevLvSv0Uo5 uvfrXnxaLdtBMts6e1Ly2piSH9JRbOGMNibOK4EXWhWAn8MII4SWgQAs bFwtiz4HyPn2wScrUQdo8DocKiQJBanesr7vDO8fdA6Rg1e0yAtSeNti e8avx46/HJa6CFs3CoE0sf6oOFSxM954AgCBTXOGNBt1Nt3Bhfqt2qyA TLFii5K1jLDTZDVkoiyDXL1M7wcTwKf9METgj1eQmH3GGlRM/OJ/j8xk ZiFGbL3cipWdiH48031jiV2hlc92mKn8Ya0d9AN6c44piza/JSFydZXw sY32nxzjDbs= diff --git a/fuzz/dns_message_checksig.in/issue-3547 b/fuzz/dns_message_checksig.in/issue-3547 new file mode 100644 index 0000000000..238442775e Binary files /dev/null and b/fuzz/dns_message_checksig.in/issue-3547 differ diff --git a/fuzz/dns_message_checksig.in/sig0 b/fuzz/dns_message_checksig.in/sig0 new file mode 100644 index 0000000000..61fbeb3b65 Binary files /dev/null and b/fuzz/dns_message_checksig.in/sig0 differ diff --git a/fuzz/dns_message_checksig.in/tsig b/fuzz/dns_message_checksig.in/tsig new file mode 100644 index 0000000000..38d040b8cb Binary files /dev/null and b/fuzz/dns_message_checksig.in/tsig differ diff --git a/fuzz/dns_message_checksig.in/tsig-reply b/fuzz/dns_message_checksig.in/tsig-reply new file mode 100644 index 0000000000..f9fe2378a9 Binary files /dev/null and b/fuzz/dns_message_checksig.in/tsig-reply differ diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c index aac978d736..9ab1640a57 100644 --- a/lib/dns/dnssec.c +++ b/lib/dns/dnssec.c @@ -967,7 +967,11 @@ dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) { sig.labels = 0; /* the root name */ sig.originalttl = 0; - isc_stdtime_get(&now); + if (msg->fuzzing) { + now = msg->fuzztime; + } else { + isc_stdtime_get(&now); + } sig.timesigned = now - DNS_TSIG_FUDGE; sig.timeexpire = now + DNS_TSIG_FUDGE; @@ -1111,7 +1115,12 @@ dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg, goto failure; } - isc_stdtime_get(&now); + if (msg->fuzzing) { + now = msg->fuzztime; + } else { + isc_stdtime_get(&now); + } + if (isc_serial_lt((uint32_t)now, sig.timesigned)) { result = DNS_R_SIGFUTURE; msg->sig0status = dns_tsigerror_badtime; diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index 0e1a43e1fe..0c7cb4ee44 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -281,6 +281,7 @@ struct dns_message { unsigned int cc_bad : 1; unsigned int tkey : 1; unsigned int rdclass_set : 1; + unsigned int fuzzing : 1; unsigned int opt_reserved; unsigned int sig_reserved; @@ -323,6 +324,11 @@ struct dns_message { isc_region_t query; isc_region_t saved; + /* + * Time to be used when fuzzing. + */ + isc_stdtime_t fuzztime; + dns_rdatasetorderfunc_t order; dns_sortlist_arg_t order_arg; diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c index d1516ee243..d67e9d77c5 100644 --- a/lib/dns/tsig.c +++ b/lib/dns/tsig.c @@ -795,7 +795,12 @@ dns_tsig_sign(dns_message_t *msg) { dns_name_init(&tsig.algorithm, NULL); dns_name_clone(key->algorithm, &tsig.algorithm); - isc_stdtime_get(&now); + if (msg->fuzzing) { + now = msg->fuzztime; + } else { + isc_stdtime_get(&now); + } + tsig.timesigned = now + msg->timeadjust; tsig.fudge = DNS_TSIG_FUDGE; @@ -1143,7 +1148,11 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, /* * Get the current time. */ - isc_stdtime_get(&now); + if (msg->fuzzing) { + now = msg->fuzztime; + } else { + isc_stdtime_get(&now); + } /* * Find dns_tsigkey_t based on keyname. @@ -1636,7 +1645,11 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { /* * Is the time ok? */ - isc_stdtime_get(&now); + if (msg->fuzzing) { + now = msg->fuzztime; + } else { + isc_stdtime_get(&now); + } if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) { msg->tsigstatus = dns_tsigerror_badtime;