1 /* $NetBSD: tsig_test.c,v 1.3 2019/01/09 16:55:13 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 <config.h> 15 16 #if HAVE_CMOCKA 17 18 #include <stdarg.h> 19 #include <stddef.h> 20 #include <setjmp.h> 21 22 #include <stdlib.h> 23 #include <stdbool.h> 24 #include <unistd.h> 25 26 #define UNIT_TESTING 27 #include <cmocka.h> 28 29 #include <isc/util.h> 30 31 #include <isc/mem.h> 32 #include <isc/print.h> 33 34 #include <dns/rdatalist.h> 35 #include <dns/rdataset.h> 36 #include <dns/tsig.h> 37 38 #include "../tsig_p.h" 39 40 #include "dnstest.h" 41 42 #define TEST_ORIGIN "test" 43 44 static int 45 _setup(void **state) { 46 isc_result_t result; 47 48 UNUSED(state); 49 50 result = dns_test_begin(NULL, false); 51 assert_int_equal(result, ISC_R_SUCCESS); 52 53 return (0); 54 } 55 56 static int 57 _teardown(void **state) { 58 UNUSED(state); 59 60 dns_test_end(); 61 62 return (0); 63 } 64 65 static int debug = 0; 66 67 static isc_result_t 68 add_mac(dst_context_t *tsigctx, isc_buffer_t *buf) { 69 dns_rdata_any_tsig_t tsig; 70 dns_rdata_t rdata = DNS_RDATA_INIT; 71 isc_buffer_t databuf; 72 isc_region_t r; 73 isc_result_t result; 74 unsigned char tsigbuf[1024]; 75 76 isc_buffer_usedregion(buf, &r); 77 dns_rdata_fromregion(&rdata, dns_rdataclass_any, 78 dns_rdatatype_tsig, &r); 79 isc_buffer_init(&databuf, tsigbuf, sizeof(tsigbuf)); 80 CHECK(dns_rdata_tostruct(&rdata, &tsig, NULL)); 81 isc_buffer_putuint16(&databuf, tsig.siglen); 82 isc_buffer_putmem(&databuf, tsig.signature, tsig.siglen); 83 isc_buffer_usedregion(&databuf, &r); 84 result = dst_context_adddata(tsigctx, &r); 85 dns_rdata_freestruct(&tsig); 86 cleanup: 87 return (result); 88 } 89 90 static isc_result_t 91 add_tsig(dst_context_t *tsigctx, dns_tsigkey_t *key, isc_buffer_t *target) { 92 dns_compress_t cctx; 93 dns_rdata_any_tsig_t tsig; 94 dns_rdata_t rdata = DNS_RDATA_INIT; 95 dns_rdatalist_t rdatalist; 96 dns_rdataset_t rdataset; 97 isc_buffer_t *dynbuf = NULL; 98 isc_buffer_t databuf; 99 isc_buffer_t sigbuf; 100 isc_region_t r; 101 isc_result_t result = ISC_R_SUCCESS; 102 isc_stdtime_t now; 103 unsigned char tsigbuf[1024]; 104 unsigned int count; 105 unsigned int sigsize = 0; 106 bool invalidate_ctx = false; 107 108 memset(&tsig, 0, sizeof(tsig)); 109 110 CHECK(dns_compress_init(&cctx, -1, mctx)); 111 invalidate_ctx = true; 112 113 tsig.common.rdclass = dns_rdataclass_any; 114 tsig.common.rdtype = dns_rdatatype_tsig; 115 ISC_LINK_INIT(&tsig.common, link); 116 dns_name_init(&tsig.algorithm, NULL); 117 dns_name_clone(key->algorithm, &tsig.algorithm); 118 119 isc_stdtime_get(&now); 120 tsig.timesigned = now; 121 tsig.fudge = DNS_TSIG_FUDGE; 122 tsig.originalid = 50; 123 tsig.error = dns_rcode_noerror; 124 tsig.otherlen = 0; 125 tsig.other = NULL; 126 127 isc_buffer_init(&databuf, tsigbuf, sizeof(tsigbuf)); 128 isc_buffer_putuint48(&databuf, tsig.timesigned); 129 isc_buffer_putuint16(&databuf, tsig.fudge); 130 isc_buffer_usedregion(&databuf, &r); 131 CHECK(dst_context_adddata(tsigctx, &r)); 132 133 CHECK(dst_key_sigsize(key->key, &sigsize)); 134 tsig.signature = (unsigned char *) isc_mem_get(mctx, sigsize); 135 if (tsig.signature == NULL) { 136 CHECK(ISC_R_NOMEMORY); 137 } 138 isc_buffer_init(&sigbuf, tsig.signature, sigsize); 139 CHECK(dst_context_sign(tsigctx, &sigbuf)); 140 tsig.siglen = isc_buffer_usedlength(&sigbuf); 141 assert_int_equal(sigsize, tsig.siglen); 142 143 CHECK(isc_buffer_allocate(mctx, &dynbuf, 512)); 144 CHECK(dns_rdata_fromstruct(&rdata, dns_rdataclass_any, 145 dns_rdatatype_tsig, &tsig, dynbuf)); 146 dns_rdatalist_init(&rdatalist); 147 rdatalist.rdclass = dns_rdataclass_any; 148 rdatalist.type = dns_rdatatype_tsig; 149 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link); 150 dns_rdataset_init(&rdataset); 151 CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset)); 152 CHECK(dns_rdataset_towire(&rdataset, &key->name, &cctx, 153 target, 0, &count)); 154 155 /* 156 * Fixup additional record count. 157 */ 158 ((unsigned char*)target->base)[11]++; 159 if (((unsigned char*)target->base)[11] == 0) { 160 ((unsigned char*)target->base)[10]++; 161 } 162 cleanup: 163 if (tsig.signature != NULL) { 164 isc_mem_put(mctx, tsig.signature, sigsize); 165 } 166 if (dynbuf != NULL) { 167 isc_buffer_free(&dynbuf); 168 } 169 if (invalidate_ctx) { 170 dns_compress_invalidate(&cctx); 171 } 172 173 return (result); 174 } 175 176 static void 177 printmessage(dns_message_t *msg) { 178 isc_buffer_t b; 179 char *buf = NULL; 180 int len = 1024; 181 isc_result_t result = ISC_R_SUCCESS; 182 183 if (!debug) { 184 return; 185 } 186 187 do { 188 buf = isc_mem_get(mctx, len); 189 190 isc_buffer_init(&b, buf, len); 191 result = dns_message_totext(msg, &dns_master_style_debug, 192 0, &b); 193 if (result == ISC_R_NOSPACE) { 194 isc_mem_put(mctx, buf, len); 195 len *= 2; 196 } else if (result == ISC_R_SUCCESS) { 197 printf("%.*s\n", (int) isc_buffer_usedlength(&b), buf); 198 } 199 } while (result == ISC_R_NOSPACE); 200 201 if (buf != NULL) { 202 isc_mem_put(mctx, buf, len); 203 } 204 } 205 206 static void 207 render(isc_buffer_t *buf, unsigned flags, dns_tsigkey_t *key, 208 isc_buffer_t **tsigin, isc_buffer_t **tsigout, 209 dst_context_t *tsigctx) 210 { 211 dns_message_t *msg = NULL; 212 dns_compress_t cctx; 213 isc_result_t result; 214 215 result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &msg); 216 assert_int_equal(result, ISC_R_SUCCESS); 217 assert_non_null(msg); 218 219 msg->id = 50; 220 msg->rcode = dns_rcode_noerror; 221 msg->flags = flags; 222 223 /* 224 * XXXMPA: this hack needs to be replaced with use of 225 * dns_message_reply() at some point. 226 */ 227 if ((flags & DNS_MESSAGEFLAG_QR) != 0) { 228 msg->verified_sig = 1; 229 } 230 231 if (tsigin == tsigout) { 232 msg->tcp_continuation = 1; 233 } 234 235 if (tsigctx == NULL) { 236 result = dns_message_settsigkey(msg, key); 237 assert_int_equal(result, ISC_R_SUCCESS); 238 239 result = dns_message_setquerytsig(msg, *tsigin); 240 assert_int_equal(result, ISC_R_SUCCESS); 241 } 242 243 result = dns_compress_init(&cctx, -1, mctx); 244 assert_int_equal(result, ISC_R_SUCCESS); 245 246 result = dns_message_renderbegin(msg, &cctx, buf); 247 assert_int_equal(result, ISC_R_SUCCESS); 248 249 result = dns_message_renderend(msg); 250 assert_int_equal(result, ISC_R_SUCCESS); 251 252 if (tsigctx != NULL) { 253 isc_region_t r; 254 255 isc_buffer_usedregion(buf, &r); 256 result = dst_context_adddata(tsigctx, &r); 257 assert_int_equal(result, ISC_R_SUCCESS); 258 } else { 259 if (tsigin == tsigout && *tsigin != NULL) { 260 isc_buffer_free(tsigin); 261 } 262 263 result = dns_message_getquerytsig(msg, mctx, tsigout); 264 assert_int_equal(result, ISC_R_SUCCESS); 265 } 266 267 dns_compress_invalidate(&cctx); 268 dns_message_destroy(&msg); 269 } 270 271 /* 272 * Test tsig tcp-continuation validation: 273 * Check that a simulated three message TCP sequence where the first 274 * and last messages contain TSIGs but the intermediate message doesn't 275 * correctly verifies. 276 */ 277 static void 278 tsig_tcp_test(void **state) { 279 const dns_name_t *tsigowner = NULL; 280 dns_fixedname_t fkeyname; 281 dns_message_t *msg = NULL; 282 dns_name_t *keyname; 283 dns_tsig_keyring_t *ring = NULL; 284 dns_tsigkey_t *key = NULL; 285 isc_buffer_t *buf = NULL; 286 isc_buffer_t *querytsig = NULL; 287 isc_buffer_t *tsigin = NULL; 288 isc_buffer_t *tsigout = NULL; 289 isc_result_t result; 290 unsigned char secret[16] = { 0 }; 291 dst_context_t *tsigctx = NULL; 292 dst_context_t *outctx = NULL; 293 294 UNUSED(state); 295 296 /* isc_log_setdebuglevel(lctx, 99); */ 297 298 keyname = dns_fixedname_initname(&fkeyname); 299 result = dns_name_fromstring(keyname, "test", 0, NULL); 300 assert_int_equal(result, ISC_R_SUCCESS); 301 302 result = dns_tsigkeyring_create(mctx, &ring); 303 assert_int_equal(result, ISC_R_SUCCESS); 304 305 result = dns_tsigkey_create(keyname, dns_tsig_hmacsha256_name, 306 secret, sizeof(secret), false, 307 NULL, 0, 0, mctx, ring, &key); 308 assert_int_equal(result, ISC_R_SUCCESS); 309 assert_non_null(key); 310 311 /* 312 * Create request. 313 */ 314 result = isc_buffer_allocate(mctx, &buf, 65535); 315 assert_int_equal(result, ISC_R_SUCCESS); 316 render(buf, 0, key, &tsigout, &querytsig, NULL); 317 isc_buffer_free(&buf); 318 319 /* 320 * Create response message 1. 321 */ 322 result = isc_buffer_allocate(mctx, &buf, 65535); 323 assert_int_equal(result, ISC_R_SUCCESS); 324 render(buf, DNS_MESSAGEFLAG_QR, key, &querytsig, &tsigout, NULL); 325 326 /* 327 * Process response message 1. 328 */ 329 result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg); 330 assert_int_equal(result, ISC_R_SUCCESS); 331 assert_non_null(msg); 332 333 result = dns_message_settsigkey(msg, key); 334 assert_int_equal(result, ISC_R_SUCCESS); 335 336 result = dns_message_parse(msg, buf, 0); 337 assert_int_equal(result, ISC_R_SUCCESS); 338 339 printmessage(msg); 340 341 result = dns_message_setquerytsig(msg, querytsig); 342 assert_int_equal(result, ISC_R_SUCCESS); 343 344 result = dns_tsig_verify(buf, msg, NULL, NULL); 345 assert_int_equal(result, ISC_R_SUCCESS); 346 assert_int_equal(msg->verified_sig, 1); 347 assert_int_equal(msg->tsigstatus, dns_rcode_noerror); 348 349 /* 350 * Check that we have a TSIG in the first message. 351 */ 352 assert_non_null(dns_message_gettsig(msg, &tsigowner)); 353 354 result = dns_message_getquerytsig(msg, mctx, &tsigin); 355 assert_int_equal(result, ISC_R_SUCCESS); 356 357 tsigctx = msg->tsigctx; 358 msg->tsigctx = NULL; 359 isc_buffer_free(&buf); 360 dns_message_destroy(&msg); 361 362 result = dst_context_create(key->key, mctx, DNS_LOGCATEGORY_DNSSEC, 363 false, 0, &outctx); 364 assert_int_equal(result, ISC_R_SUCCESS); 365 assert_non_null(outctx); 366 367 /* 368 * Start digesting. 369 */ 370 result = add_mac(outctx, tsigout); 371 assert_int_equal(result, ISC_R_SUCCESS); 372 373 /* 374 * Create response message 2. 375 */ 376 result = isc_buffer_allocate(mctx, &buf, 65535); 377 assert_int_equal(result, ISC_R_SUCCESS); 378 379 assert_int_equal(result, ISC_R_SUCCESS); 380 render(buf, DNS_MESSAGEFLAG_QR, key, &tsigout, &tsigout, outctx); 381 382 /* 383 * Process response message 2. 384 */ 385 result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg); 386 assert_int_equal(result, ISC_R_SUCCESS); 387 assert_non_null(msg); 388 389 msg->tcp_continuation = 1; 390 msg->tsigctx = tsigctx; 391 tsigctx = NULL; 392 393 result = dns_message_settsigkey(msg, key); 394 assert_int_equal(result, ISC_R_SUCCESS); 395 396 result = dns_message_parse(msg, buf, 0); 397 assert_int_equal(result, ISC_R_SUCCESS); 398 399 printmessage(msg); 400 401 result = dns_message_setquerytsig(msg, tsigin); 402 assert_int_equal(result, ISC_R_SUCCESS); 403 404 result = dns_tsig_verify(buf, msg, NULL, NULL); 405 assert_int_equal(result, ISC_R_SUCCESS); 406 assert_int_equal(msg->verified_sig, 0); 407 assert_int_equal(msg->tsigstatus, dns_rcode_noerror); 408 409 /* 410 * Check that we don't have a TSIG in the second message. 411 */ 412 tsigowner = NULL; 413 assert_true(dns_message_gettsig(msg, &tsigowner) == NULL); 414 415 tsigctx = msg->tsigctx; 416 msg->tsigctx = NULL; 417 isc_buffer_free(&buf); 418 dns_message_destroy(&msg); 419 420 /* 421 * Create response message 3. 422 */ 423 result = isc_buffer_allocate(mctx, &buf, 65535); 424 assert_int_equal(result, ISC_R_SUCCESS); 425 render(buf, DNS_MESSAGEFLAG_QR, key, &tsigout, &tsigout, outctx); 426 427 result = add_tsig(outctx, key, buf); 428 assert_int_equal(result, ISC_R_SUCCESS); 429 430 /* 431 * Process response message 3. 432 */ 433 result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg); 434 assert_int_equal(result, ISC_R_SUCCESS); 435 assert_non_null(msg); 436 437 msg->tcp_continuation = 1; 438 msg->tsigctx = tsigctx; 439 tsigctx = NULL; 440 441 result = dns_message_settsigkey(msg, key); 442 assert_int_equal(result, ISC_R_SUCCESS); 443 444 result = dns_message_parse(msg, buf, 0); 445 assert_int_equal(result, ISC_R_SUCCESS); 446 447 printmessage(msg); 448 449 /* 450 * Check that we had a TSIG in the third message. 451 */ 452 assert_non_null(dns_message_gettsig(msg, &tsigowner)); 453 454 result = dns_message_setquerytsig(msg, tsigin); 455 assert_int_equal(result, ISC_R_SUCCESS); 456 457 result = dns_tsig_verify(buf, msg, NULL, NULL); 458 assert_int_equal(result, ISC_R_SUCCESS); 459 assert_int_equal(msg->verified_sig, 1); 460 assert_int_equal(msg->tsigstatus, dns_rcode_noerror); 461 462 if (tsigin != NULL) { 463 isc_buffer_free(&tsigin); 464 } 465 466 result = dns_message_getquerytsig(msg, mctx, &tsigin); 467 assert_int_equal(result, ISC_R_SUCCESS); 468 469 isc_buffer_free(&buf); 470 dns_message_destroy(&msg); 471 472 if (outctx != NULL) { 473 dst_context_destroy(&outctx); 474 } 475 if (querytsig != NULL) { 476 isc_buffer_free(&querytsig); 477 } 478 if (tsigin != NULL) { 479 isc_buffer_free(&tsigin); 480 } 481 if (tsigout != NULL) { 482 isc_buffer_free(&tsigout); 483 } 484 dns_tsigkey_detach(&key); 485 if (ring != NULL) { 486 dns_tsigkeyring_detach(&ring); 487 } 488 } 489 490 /* Tests the dns__tsig_algvalid function */ 491 static void 492 algvalid_test(void **state) { 493 UNUSED(state); 494 495 assert_true(dns__tsig_algvalid(DST_ALG_HMACMD5)); 496 497 assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA1)); 498 assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA224)); 499 assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA256)); 500 assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA384)); 501 assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA512)); 502 503 assert_false(dns__tsig_algvalid(DST_ALG_GSSAPI)); 504 } 505 506 /* Tests the dns__tsig_algfromname function */ 507 static void 508 algfromname_test(void **state) { 509 UNUSED(state); 510 511 assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACMD5_NAME), 512 DST_ALG_HMACMD5); 513 assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA1_NAME), 514 DST_ALG_HMACSHA1); 515 assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA224_NAME), 516 DST_ALG_HMACSHA224); 517 assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA256_NAME), 518 DST_ALG_HMACSHA256); 519 assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA384_NAME), 520 DST_ALG_HMACSHA384); 521 assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA512_NAME), 522 DST_ALG_HMACSHA512); 523 524 assert_int_equal(dns__tsig_algfromname(DNS_TSIG_GSSAPI_NAME), 525 DST_ALG_GSSAPI); 526 assert_int_equal(dns__tsig_algfromname(DNS_TSIG_GSSAPIMS_NAME), 527 DST_ALG_GSSAPI); 528 529 assert_int_equal(dns__tsig_algfromname(dns_rootname), 0); 530 } 531 532 /* Tests the dns__tsig_algnamefromname function */ 533 534 /* 535 * Helper function to create a dns_name_t from a string and see if 536 * the dns__tsig_algnamefromname function can correctly match it against the 537 * static table of known algorithms. 538 */ 539 static void test_name(const char *name_string, const dns_name_t *expected) { 540 dns_name_t name; 541 dns_name_init(&name, NULL); 542 assert_int_equal(dns_name_fromstring(&name, name_string, 0, mctx), 543 ISC_R_SUCCESS); 544 assert_int_equal(dns__tsig_algnamefromname(&name), expected); 545 dns_name_free(&name, mctx); 546 } 547 548 static void 549 algnamefromname_test(void **state) { 550 UNUSED(state); 551 552 /* test the standard algorithms */ 553 test_name("hmac-md5.sig-alg.reg.int", DNS_TSIG_HMACMD5_NAME); 554 test_name("hmac-sha1", DNS_TSIG_HMACSHA1_NAME); 555 test_name("hmac-sha224", DNS_TSIG_HMACSHA224_NAME); 556 test_name("hmac-sha256", DNS_TSIG_HMACSHA256_NAME); 557 test_name("hmac-sha384", DNS_TSIG_HMACSHA384_NAME); 558 test_name("hmac-sha512", DNS_TSIG_HMACSHA512_NAME); 559 560 test_name("gss-tsig", DNS_TSIG_GSSAPI_NAME); 561 test_name("gss.microsoft.com", DNS_TSIG_GSSAPIMS_NAME); 562 563 /* try another name that isn't a standard algorithm name */ 564 assert_int_equal(dns__tsig_algnamefromname(dns_rootname), NULL); 565 } 566 567 /* Tests the dns__tsig_algallocated function */ 568 static void 569 algallocated_test(void **state) { 570 571 UNUSED(state); 572 573 /* test the standard algorithms */ 574 assert_false(dns__tsig_algallocated(DNS_TSIG_HMACMD5_NAME)); 575 assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA1_NAME)); 576 assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA224_NAME)); 577 assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA256_NAME)); 578 assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA384_NAME)); 579 assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA512_NAME)); 580 581 assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA512_NAME)); 582 assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA512_NAME)); 583 584 /* try another name that isn't a standard algorithm name */ 585 assert_true(dns__tsig_algallocated(dns_rootname)); 586 } 587 588 int 589 main(void) { 590 const struct CMUnitTest tests[] = { 591 cmocka_unit_test_setup_teardown(tsig_tcp_test, 592 _setup, _teardown), 593 cmocka_unit_test(algvalid_test), 594 cmocka_unit_test(algfromname_test), 595 cmocka_unit_test_setup_teardown(algnamefromname_test, 596 _setup, _teardown), 597 cmocka_unit_test(algallocated_test), 598 }; 599 600 return (cmocka_run_group_tests(tests, NULL, NULL)); 601 } 602 603 #else /* HAVE_CMOCKA */ 604 605 #include <stdio.h> 606 607 int 608 main(void) { 609 printf("1..0 # Skipped: cmocka not available\n"); 610 return (0); 611 } 612 613 #endif 614