1 /* $NetBSD: dns_message_checksig.c,v 1.3 2025/01/26 16:25:20 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 #include <inttypes.h> 17 #include <stdbool.h> 18 #include <stdlib.h> 19 #include <unistd.h> 20 21 #include <isc/buffer.h> 22 #include <isc/commandline.h> 23 #include <isc/file.h> 24 #include <isc/mem.h> 25 #include <isc/result.h> 26 #include <isc/string.h> 27 #include <isc/tid.h> 28 #include <isc/util.h> 29 30 #include <dns/fixedname.h> 31 #include <dns/message.h> 32 #include <dns/name.h> 33 #include <dns/rcode.h> 34 #include <dns/tsig.h> 35 #include <dns/view.h> 36 #include <dns/zone.h> 37 38 #include "fuzz.h" 39 40 bool debug = false; 41 42 static isc_mem_t *mctx = NULL; 43 44 /* 45 * Packet dumps of validily signed request ./IN/SOA 46 * requests. 47 * 48 * TSIG: 49 * 50 * 0x0000: 600b 0900 006a 1140 0000 0000 0000 0000 51 * 0x0010: 0000 0000 0000 0001 0000 0000 0000 0000 52 * 0x0020: 0000 0000 0000 0001 cc88 0035 006a 007d 53 * 0x0030: 1dfa 0000 0001 0000 0000 0001 0000 0600 54 * 0x0040: 0108 7473 6967 2d6b 6579 0000 fa00 ff00 55 * 0x0050: 0000 0000 3d0b 686d 6163 2d73 6861 3235 56 * 0x0060: 3600 0000 622a cce1 012c 0020 224d 5807 57 * 0x0070: 648d 1400 9d8e fc1c d049 55e9 cc90 2187 58 * 0x0080: 3b5f af5c 8899 dc27 c8df b34b 1dfa 0000 59 * 0x0090: 0000 60 * 61 * SIG(0): 62 * 63 * 0x0000: 6004 0e00 013f 1140 0000 0000 0000 0000 64 * 0x0010: 0000 0000 0000 0001 0000 0000 0000 0000 65 * 0x0020: 0000 0000 0000 0001 c0a7 0035 013f 0152 66 * 0x0030: 0000 0000 0001 0000 0000 0001 0000 0600 67 * 0x0040: 0100 0018 00ff 0000 0000 011b 0000 0800 68 * 0x0050: 0000 0000 622a ce0d 622a cbb5 da71 0773 69 * 0x0060: 6967 306b 6579 0068 988b 27bf 5c89 5270 70 * 0x0070: c5ba ea8b 2e10 0512 9b44 48d3 69de b7ec 71 * 0x0080: 7c67 15f3 6bc7 b0dc 277b e8f1 6979 4c89 72 * 0x0090: 149a 0203 30a1 c0b7 a711 ee8a 8d90 ebb9 73 * 0x00a0: 9e33 dd65 33d5 5d1d 90db cf9c bb6a b346 74 * 0x00b0: 568f a399 71d7 c877 616d 2fb7 0f86 963f 75 * 0x00c0: aa00 850d 180a 9f83 cd4b d115 c79f 64c9 76 * 0x00d0: ff05 e751 6810 28b3 2249 c4ba 2d8d 57ba 77 * 0x00e0: 9aad f1fc b34e c237 9465 04fd fe4d 19c9 78 * 0x00f0: 2368 ec8e 7097 eaea e067 2b9c 06eb c383 79 * 0x0100: e901 a11e 606b 4cce c12a 0e57 8c09 b7cb 80 * 0x0110: 23bb ec05 b68b 1852 9288 b665 fe89 cf62 81 * 0x0120: 0a41 5e5a acbe 6903 cbb7 e7b6 cab4 e4a2 82 * 0x0130: b98f 884f c09d 5b39 c695 c84c 9a92 f110 83 * 0x0140: ccc3 f2ee 313f a2a1 1cda 5aa2 faec d593 84 * 0x0150: 4514 724a 868f 94b9 0547 4dc9 7b73 c85e 85 * 0x0160: 544c 73d4 e892 f9 86 */ 87 88 #define HMACSHA256 "\x0bhmac-sha256" 89 90 static isc_stdtime_t fuzztime = 0x622acce1; 91 static isc_loopmgr_t *loopmgr = NULL; 92 static dns_view_t *view = NULL; 93 static dns_tsigkey_t *tsigkey = NULL; 94 static dns_tsigkeyring_t *ring = NULL; 95 static dns_tsigkeyring_t *emptyring = NULL; 96 static char *wd = NULL; 97 static char template[] = "/tmp/dns-message-checksig-XXXXXX"; 98 99 static char f1[] = "Ksig0key.+008+55921.key"; 100 static char c1[] = "sig0key. IN KEY 512 3 8 " 101 "AwEAAa22lgHi1vAbQvu5ETdTrm2H8rwga9tvyMa6LFiSDyevLvSv0Uo5 " 102 "uvfrXnxaLdtBMts6e1Ly2piSH9JRbOGMNibOK4EXWhWAn8MII4SWgQAs " 103 "bFwtiz4HyPn2wScrUQdo8DocKiQJBanesr7vDO8fdA6Rg1e0yAtSeNti " 104 "e8avx46/HJa6CFs3CoE0sf6oOFSxM954AgCBTXOGNBt1Nt3Bhfqt2qyA " 105 "TLFii5K1jLDTZDVkoiyDXL1M7wcTwKf9METgj1eQmH3GGlRM/OJ/j8xk " 106 "ZiFGbL3cipWdiH48031jiV2hlc92mKn8Ya0d9AN6c44piza/JSFydZXw " 107 "sY32nxzjDbs=\n"; 108 109 static char f2[] = "Ksig0key.+008+55921.private"; 110 static char c2[] = "Private-key-format: v1.3\n\ 111 Algorithm: 8 (RSASHA256)\n\ 112 Modulus: rbaWAeLW8BtC+7kRN1OubYfyvCBr22/IxrosWJIPJ68u9K/RSjm69+tefFot20Ey2zp7UvLamJIf0lFs4Yw2Js4rgRdaFYCfwwgjhJaBACxsXC2LPgfI+fbBJytRB2jwOhwqJAkFqd6yvu8M7x90DpGDV7TIC1J422J7xq/Hjr8clroIWzcKgTSx/qg4VLEz3ngCAIFNc4Y0G3U23cGF+q3arIBMsWKLkrWMsNNkNWSiLINcvUzvBxPAp/0wROCPV5CYfcYaVEz84n+PzGRmIUZsvdyKlZ2IfjzTfWOJXaGVz3aYqfxhrR30A3pzjimLNr8lIXJ1lfCxjfafHOMNuw==\n\ 113 PublicExponent: AQAB\n\ 114 PrivateExponent: GDfclFkR5ToFGH9rMTRMnP73Q5dzjLgkx4vyHcuzKtxcvAans4+hNj+NazckAy2E+mpzV2j95TJ4wZjSM2RvB5xLwBIc4Dg6oyAHL6Ikoae6gw64cHFOaYb808n8CyqWqfX+QWAz9sRSVZXnTuPViX3A+svR7ejVak9Bzr1NTDm0DFlrhaKVCYA++dKVZerfuNiXT/jQvrc4wMCa7WWsfLsFO8aTNkEhqUnmS9c5VYgr7MkCV4ENDBcISpQc9wElI0hl12QPaSj8iSdk9liYp+HTiOxOyp6BGGuecKAoQijMwrZy4qExdOxvowptll8+nZLtwGRn/un/xvIZY5OLAQ==\n\ 115 Prime1: ww3C6jwnrLQik/zxSgC0KuqgHq68cCjiRjwK2/euzs7NkMevFpXvV0cWO8x1/wKC1mszVLsUaKTvH6fzRsXfz5MPihzNzUYFwvobKVLserSxEwHNk+FKUU+q07Kf8WWnCqX5nX9QzVG1q4J8Q44N49I5S480jHLGYbyLZrEYMQE=\n\ 116 Prime2: 4/3Ozq/8vRgcO4bieFs4CbZR7C98HiTi65SiLBIKY09mDfCleZI0uurAYBluZJgHS5AC5cdyHFuJr3uKxvD+Mgdlru40U6cSCEdK7HAhyUGZUndWl28wyMEB6Kke1/owxVn0S4RKLPOgFI2668H6JObaqXf0wyY89RdVQP6VQrs=\n\ 117 Exponent1: Tbr9MyVX1j5PDVSev5P6OKQZvUB7PeM9ESo6VaCl3CqTxx+cic6ke86LcLcxSrewdkxwP1LydiVMWfwvOcP/RhRf+/Uwmp5OC35qNpSiQuAhNObiCw2b9T1fYU/s52FQKTEtgXNMOxZV5IxyguVoaaLMTG08TsAqiKZ/kyP99QE=\n\ 118 Exponent2: Q4qSNKrwLbixzHS2LL+hR0dK17RtiaSV0QKUVIf3qdoAusp6yxwkIOegnBeMm6JqLtl38kh2pq37iRAJWcxVEc8dMYiB2fJZpjgwmwDREYUsfcC611vqUN7UyO8pIwSMZDq045ZKPyzhVJV0NZmemEYHq0LNMO7oCheiewGwiDc=\n\ 119 Coefficient: T2u/J4NgyO+OqoLpXBIpTBzqrvDk8tb0feYgsp5d16hHvbXxNkMUR8cI07RdbI9HnEldtmhAnbQ6SvFiy2YYjpw/1Fz2WwdxRqLaDV7UlhrT+CqltvU9d/N/xThBNKDa23Wf5Vat+HRiLHSgzsY1PseVCWN+g4azuK2D8+DLeHE=\n\ 120 Created: 20220311073606\n\ 121 Publish: 20220311073606\n\ 122 Activate: 20220311073606\n"; 123 124 static char f3[] = "sig0key.db"; 125 static char c3[] = "sig0key. 0 IN SOA . . 0 0 0 0 0\n\ 126 sig0key. 0 IN NS .\n\ 127 sig0key. 0 IN KEY 512 3 8 AwEAAa22lgHi1vAbQvu5ETdTrm2H8rwga9tvyMa6LFiSDyevLvSv0Uo5 uvfrXnxaLdtBMts6e1Ly2piSH9JRbOGMNibOK4EXWhWAn8MII4SWgQAs bFwtiz4HyPn2wScrUQdo8DocKiQJBanesr7vDO8fdA6Rg1e0yAtSeNti e8avx46/HJa6CFs3CoE0sf6oOFSxM954AgCBTXOGNBt1Nt3Bhfqt2qyA TLFii5K1jLDTZDVkoiyDXL1M7wcTwKf9METgj1eQmH3GGlRM/OJ/j8xk ZiFGbL3cipWdiH48031jiV2hlc92mKn8Ya0d9AN6c44piza/JSFydZXw sY32nxzjDbs=\n"; 128 129 static bool destroy_dst = false; 130 131 int 132 LLVMFuzzerInitialize(int *argc ISC_ATTR_UNUSED, char ***argv ISC_ATTR_UNUSED) { 133 isc_result_t result; 134 dns_fixedname_t fixed; 135 dns_name_t *name = dns_fixedname_initname(&fixed); 136 unsigned char secret[16] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 137 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 138 0xff, 0xff, 0xff, 0xff }; 139 dns_zone_t *zone = NULL; 140 char pathbuf[PATH_MAX]; 141 FILE *fd; 142 143 wd = mkdtemp(template); 144 if (wd == NULL) { 145 fprintf(stderr, "mkdtemp failed\n"); 146 return 1; 147 } 148 149 snprintf(pathbuf, sizeof(pathbuf), "%s/%s", wd, f1); 150 fd = fopen(pathbuf, "w"); 151 if (fd == NULL) { 152 fprintf(stderr, "fopen(%s) failed\n", pathbuf); 153 return 1; 154 } 155 fputs(c1, fd); 156 fclose(fd); 157 158 snprintf(pathbuf, sizeof(pathbuf), "%s/%s", wd, f2); 159 fd = fopen(pathbuf, "w"); 160 if (fd == NULL) { 161 fprintf(stderr, "fopen(%s) failed\n", pathbuf); 162 return 1; 163 } 164 fputs(c2, fd); 165 fclose(fd); 166 167 snprintf(pathbuf, sizeof(pathbuf), "%s/%s", wd, f3); 168 fd = fopen(pathbuf, "w"); 169 if (fd == NULL) { 170 fprintf(stderr, "fopen(%s) failed\n", pathbuf); 171 return 1; 172 } 173 fputs(c3, fd); 174 fclose(fd); 175 176 isc_mem_create(&mctx); 177 178 result = dst_lib_init(mctx, NULL); 179 if (result != ISC_R_SUCCESS) { 180 fprintf(stderr, "dst_lib_init failed: %s\n", 181 isc_result_totext(result)); 182 return 1; 183 } 184 destroy_dst = true; 185 186 isc_loopmgr_create(mctx, 1, &loopmgr); 187 188 result = dns_view_create(mctx, loopmgr, NULL, dns_rdataclass_in, "view", 189 &view); 190 if (result != ISC_R_SUCCESS) { 191 fprintf(stderr, "dns_view_create failed: %s\n", 192 isc_result_totext(result)); 193 return 1; 194 } 195 196 dns_tsigkeyring_create(mctx, &ring); 197 dns_tsigkeyring_create(mctx, &emptyring); 198 199 result = dns_name_fromstring(name, "tsig-key", dns_rootname, 0, NULL); 200 if (result != ISC_R_SUCCESS) { 201 fprintf(stderr, "dns_name_fromstring failed: %s\n", 202 isc_result_totext(result)); 203 return 1; 204 } 205 206 result = dns_tsigkey_create(name, DST_ALG_HMACSHA256, secret, 207 sizeof(secret), mctx, &tsigkey); 208 if (result != ISC_R_SUCCESS) { 209 fprintf(stderr, "dns_tsigkey_create failed: %s\n", 210 isc_result_totext(result)); 211 return 1; 212 } 213 result = dns_tsigkeyring_add(ring, tsigkey); 214 if (result != ISC_R_SUCCESS) { 215 fprintf(stderr, "dns_tsigkeyring_add failed: %s\n", 216 isc_result_totext(result)); 217 return 1; 218 } 219 220 result = dns_name_fromstring(name, "sig0key", dns_rootname, 0, NULL); 221 if (result != ISC_R_SUCCESS) { 222 fprintf(stderr, "dns_name_fromstring failed: %s\n", 223 isc_result_totext(result)); 224 return 1; 225 } 226 227 dns_zone_create(&zone, mctx, 0); 228 229 result = dns_zone_setorigin(zone, name); 230 if (result != ISC_R_SUCCESS) { 231 fprintf(stderr, "dns_zone_setorigin failed: %s\n", 232 isc_result_totext(result)); 233 return 1; 234 } 235 236 dns_zone_setclass(zone, view->rdclass); 237 dns_zone_settype(zone, dns_zone_primary); 238 239 result = dns_zone_setkeydirectory(zone, wd); 240 if (result != ISC_R_SUCCESS) { 241 fprintf(stderr, "dns_zone_setkeydirectory failed: %s\n", 242 isc_result_totext(result)); 243 return 1; 244 } 245 246 result = dns_zone_setfile(zone, pathbuf, dns_masterformat_text, 247 &dns_master_style_default); 248 if (result != ISC_R_SUCCESS) { 249 fprintf(stderr, "dns_zone_setfile failed: %s\n", 250 isc_result_totext(result)); 251 return 1; 252 } 253 254 result = dns_zone_load(zone, false); 255 if (result != ISC_R_SUCCESS) { 256 fprintf(stderr, "dns_zone_load failed: %s\n", 257 isc_result_totext(result)); 258 return 1; 259 } 260 261 result = dns_view_addzone(view, zone); 262 if (result != ISC_R_SUCCESS) { 263 fprintf(stderr, "dns_view_addzone failed: %s\n", 264 isc_result_totext(result)); 265 return 1; 266 } 267 268 dns_zone_setview(zone, view); 269 dns_view_freeze(view); 270 271 dns_zone_detach(&zone); 272 273 return 0; 274 } 275 276 static isc_result_t 277 create_message(dns_message_t **messagep, const uint8_t *data, size_t size, 278 bool addasig, bool addtsig) { 279 isc_result_t result; 280 dns_message_t *message = NULL; 281 isc_buffer_t b; 282 static unsigned char buf[65535]; 283 284 isc_buffer_init(&b, buf, sizeof(buf)); 285 286 /* Message ID */ 287 isc_buffer_putuint16(&b, 0); 288 289 /* QR, Opcode, other flags = 0, rcode = 0 */ 290 isc_buffer_putuint16(&b, (*data & 0x1f) << 11); 291 /* Counts */ 292 isc_buffer_putuint16(&b, 1); 293 isc_buffer_putuint16(&b, 0); 294 isc_buffer_putuint16(&b, 0); 295 isc_buffer_putuint16(&b, addasig ? 1 : 0); 296 297 /* Question ./IN/SOA */ 298 isc_buffer_putuint8(&b, 0); 299 isc_buffer_putuint16(&b, 6); 300 isc_buffer_putuint16(&b, 1); 301 302 if (addasig) { 303 /* Signature */ 304 if (addtsig) { 305 const unsigned char keyname[] = "\x08tsig-key"; 306 isc_buffer_putmem(&b, keyname, sizeof(keyname)); 307 isc_buffer_putuint16(&b, dns_rdatatype_tsig); 308 isc_buffer_putuint16(&b, dns_rdataclass_any); 309 } else { 310 isc_buffer_putuint8(&b, 0); /* '.' */ 311 isc_buffer_putuint16(&b, dns_rdatatype_sig); 312 isc_buffer_putuint16(&b, dns_rdataclass_in); 313 } 314 isc_buffer_putuint32(&b, 0); /* ttl */ 315 data++; 316 size--; 317 if (size > isc_buffer_availablelength(&b) - 2) { 318 size = isc_buffer_availablelength(&b) - 2; 319 } 320 isc_buffer_putuint16(&b, size); 321 isc_buffer_putmem(&b, data, size); 322 } 323 324 dns_message_create(mctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE, &message); 325 326 result = dns_message_parse(message, &b, 0); 327 if (debug) { 328 fprintf(stderr, "dns_message_parse => %s\n", 329 isc_result_totext(result)); 330 } 331 if (result != ISC_R_SUCCESS) { 332 dns_message_detach(&message); 333 } else { 334 if (debug) { 335 char text[200000]; 336 isc_buffer_init(&b, text, sizeof(text)); 337 338 result = dns_message_totext( 339 message, &dns_master_style_debug, 0, &b); 340 if (result == ISC_R_SUCCESS) { 341 fprintf(stderr, "%.*s", (int)b.used, text); 342 } else { 343 fprintf(stderr, "dns_message_totext => %s\n", 344 isc_result_totext(result)); 345 } 346 } 347 *messagep = message; 348 } 349 return result; 350 } 351 352 int 353 LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 354 isc_result_t result; 355 dns_message_t *message = NULL; 356 unsigned char query_tsig[23 + 32 + 6] = { 0 }; 357 bool addasig = false; 358 bool addtime = false; 359 bool addtsig = false; 360 bool setquerytsig = false; 361 bool settsigkey = false; 362 bool subtime = false; 363 bool withring = false; 364 bool withview = false; 365 366 /* 367 * The first 2 octets affect setup. 368 * Octet 1 determines whether a signature is added and which type 369 * (addasig, addtsig), whether time should be adjusted (addtime, 370 * subtime), whether dns_message_setquerytsig and dns_message_settsigkey 371 * have been called, whether there is a keyring available with the 372 * TSIG key or a view is defined. 373 * 374 * The second octet defines if the message is a response and the 375 * opcode. 376 */ 377 if (size > 65535 || size < 2) { 378 return 0; 379 } 380 381 addasig = (*data & 0x80) != 0; 382 addtime = (*data & 0x40) != 0; 383 addtsig = (*data & 0x20) != 0; 384 setquerytsig = (*data & 0x10) != 0; 385 settsigkey = (*data & 0x08) != 0; 386 subtime = (*data & 0x04) != 0; 387 withring = (*data & 0x02) != 0; 388 withview = (*data & 0x01) != 0; 389 390 data++; 391 size--; 392 393 if (debug) { 394 fprintf(stderr, 395 "addasig=%u addtime=%u addtsig=%u setquerytsig=%u " 396 "settsigkey=%u subtime=%u withring=%u\nwithview=%u\n", 397 addasig, addtime, addtsig, setquerytsig, settsigkey, 398 subtime, withring, withview); 399 } 400 401 result = create_message(&message, data, size, addasig, addtsig); 402 if (result != ISC_R_SUCCESS) { 403 return 0; 404 } 405 406 /* 407 * Make time calculations consistent. 408 */ 409 message->fuzzing = 1; 410 message->fuzztime = fuzztime; 411 if (addtime) { 412 message->fuzztime += 1200; 413 } 414 if (subtime) { 415 message->fuzztime -= 1200; 416 } 417 418 if ((message->flags & DNS_MESSAGEFLAG_QR) != 0) { 419 if (setquerytsig) { 420 isc_buffer_t b; 421 unsigned char hmacname[] = HMACSHA256; 422 unsigned char hmacvalue[32] = { 423 0x22, 0x4d, 0x58, 0x07, 0x64, 0x8d, 0x14, 0x00, 424 0x9d, 0x8e, 0xfc, 0x1c, 0xd0, 0x49, 0x55, 0xe9, 425 0xcc, 0x90, 0x21, 0x87, 0x3b, 0x5f, 0xaf, 0x5c, 426 0x88, 0x99, 0xdc, 0x27, 0xc8, 0xdf, 0xb3, 0x4b 427 }; 428 429 /* 430 * Valid TSIG rdata for tsig-key over a plain 431 * DNS QUERY for ./SOA/IN with no flags set. 432 */ 433 isc_buffer_init(&b, query_tsig, sizeof(query_tsig)); 434 isc_buffer_putmem(&b, hmacname, sizeof(hmacname)); 435 isc_buffer_putuint16(&b, 0); /* time high */ 436 isc_buffer_putuint32(&b, 0x622abec0); /* time low */ 437 isc_buffer_putuint16(&b, 300); /* Fudge */ 438 isc_buffer_putuint16(&b, 32); /* Mac Length */ 439 /* Mac */ 440 isc_buffer_putmem(&b, hmacvalue, 32); 441 isc_buffer_putuint16(&b, 7674); /* Original Id */ 442 isc_buffer_putuint16(&b, 0); /* Error */ 443 isc_buffer_putuint16(&b, 0); /* Other len */ 444 445 dns_message_setquerytsig(message, &b); 446 } 447 } 448 449 if (settsigkey) { 450 result = dns_message_settsigkey(message, tsigkey); 451 if (debug) { 452 fprintf(stderr, "dns_message_settsigkey => %s\n", 453 isc_result_totext(result)); 454 } 455 } 456 457 dns_view_setkeyring(view, withring ? ring : emptyring); 458 459 result = dns_message_checksig(message, withview ? view : NULL); 460 if (debug) { 461 char textbuf[64]; 462 isc_buffer_t b; 463 464 fprintf(stderr, "dns_message_checksig => %s\n", 465 isc_result_totext(result)); 466 isc_buffer_init(&b, textbuf, sizeof(textbuf)); 467 dns_tsigrcode_totext(message->tsigstatus, &b); 468 fprintf(stderr, "tsigstatus=%.*s\n", (int)b.used, textbuf); 469 isc_buffer_init(&b, textbuf, sizeof(textbuf)); 470 dns_tsigrcode_totext(message->sig0status, &b); 471 fprintf(stderr, "sig0status=%.*s\n", (int)b.used, textbuf); 472 } 473 if (result != ISC_R_SUCCESS) { 474 goto cleanup; 475 } 476 477 cleanup: 478 if (message != NULL) { 479 dns_message_detach(&message); 480 } 481 482 return 0; 483 } 484