2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-28 04:58:04 +00:00
bind/lib/dns/tests/tsig_test.c

615 lines
16 KiB
C
Raw Normal View History

/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
2018-11-14 20:29:40 +08:00
#if HAVE_CMOCKA
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
2017-07-08 00:47:59 +10:00
2018-11-14 20:29:40 +08:00
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
2018-11-14 20:29:40 +08:00
#define UNIT_TESTING
#include <cmocka.h>
#include <isc/util.h>
#include <isc/mem.h>
2017-07-08 00:47:59 +10:00
#include <isc/print.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/tsig.h>
#include "../tsig_p.h"
#include "dnstest.h"
#define CHECK(r) \
do { \
result = (r); \
if (result != ISC_R_SUCCESS) { \
goto cleanup; \
} \
} while (0)
#define TEST_ORIGIN "test"
2018-11-14 20:29:40 +08:00
static int
_setup(void **state) {
isc_result_t result;
UNUSED(state);
result = dns_test_begin(NULL, false);
assert_int_equal(result, ISC_R_SUCCESS);
return (0);
}
static int
_teardown(void **state) {
UNUSED(state);
dns_test_end();
return (0);
}
static int debug = 0;
static isc_result_t
add_mac(dst_context_t *tsigctx, isc_buffer_t *buf) {
dns_rdata_any_tsig_t tsig;
dns_rdata_t rdata = DNS_RDATA_INIT;
isc_buffer_t databuf;
isc_region_t r;
isc_result_t result;
unsigned char tsigbuf[1024];
isc_buffer_usedregion(buf, &r);
dns_rdata_fromregion(&rdata, dns_rdataclass_any,
dns_rdatatype_tsig, &r);
isc_buffer_init(&databuf, tsigbuf, sizeof(tsigbuf));
CHECK(dns_rdata_tostruct(&rdata, &tsig, NULL));
isc_buffer_putuint16(&databuf, tsig.siglen);
isc_buffer_putmem(&databuf, tsig.signature, tsig.siglen);
isc_buffer_usedregion(&databuf, &r);
result = dst_context_adddata(tsigctx, &r);
dns_rdata_freestruct(&tsig);
cleanup:
return (result);
}
static isc_result_t
add_tsig(dst_context_t *tsigctx, dns_tsigkey_t *key, isc_buffer_t *target) {
dns_compress_t cctx;
dns_rdata_any_tsig_t tsig;
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdatalist_t rdatalist;
dns_rdataset_t rdataset;
isc_buffer_t *dynbuf = NULL;
isc_buffer_t databuf;
isc_buffer_t sigbuf;
isc_region_t r;
isc_result_t result = ISC_R_SUCCESS;
isc_stdtime_t now;
unsigned char tsigbuf[1024];
unsigned int count;
unsigned int sigsize = 0;
bool invalidate_ctx = false;
memset(&tsig, 0, sizeof(tsig));
CHECK(dns_compress_init(&cctx, -1, dt_mctx));
invalidate_ctx = true;
tsig.common.rdclass = dns_rdataclass_any;
tsig.common.rdtype = dns_rdatatype_tsig;
ISC_LINK_INIT(&tsig.common, link);
dns_name_init(&tsig.algorithm, NULL);
dns_name_clone(key->algorithm, &tsig.algorithm);
isc_stdtime_get(&now);
tsig.timesigned = now;
tsig.fudge = DNS_TSIG_FUDGE;
tsig.originalid = 50;
tsig.error = dns_rcode_noerror;
tsig.otherlen = 0;
tsig.other = NULL;
isc_buffer_init(&databuf, tsigbuf, sizeof(tsigbuf));
isc_buffer_putuint48(&databuf, tsig.timesigned);
isc_buffer_putuint16(&databuf, tsig.fudge);
isc_buffer_usedregion(&databuf, &r);
CHECK(dst_context_adddata(tsigctx, &r));
CHECK(dst_key_sigsize(key->key, &sigsize));
tsig.signature = isc_mem_get(dt_mctx, sigsize);
isc_buffer_init(&sigbuf, tsig.signature, sigsize);
CHECK(dst_context_sign(tsigctx, &sigbuf));
tsig.siglen = isc_buffer_usedlength(&sigbuf);
2018-11-14 20:29:40 +08:00
assert_int_equal(sigsize, tsig.siglen);
CHECK(isc_buffer_allocate(dt_mctx, &dynbuf, 512));
CHECK(dns_rdata_fromstruct(&rdata, dns_rdataclass_any,
dns_rdatatype_tsig, &tsig, dynbuf));
dns_rdatalist_init(&rdatalist);
rdatalist.rdclass = dns_rdataclass_any;
rdatalist.type = dns_rdatatype_tsig;
ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
dns_rdataset_init(&rdataset);
CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
CHECK(dns_rdataset_towire(&rdataset, &key->name, &cctx,
target, 0, &count));
/*
* Fixup additional record count.
*/
((unsigned char*)target->base)[11]++;
2018-11-14 20:29:40 +08:00
if (((unsigned char*)target->base)[11] == 0) {
((unsigned char*)target->base)[10]++;
2018-11-14 20:29:40 +08:00
}
cleanup:
2018-11-14 20:29:40 +08:00
if (tsig.signature != NULL) {
isc_mem_put(dt_mctx, tsig.signature, sigsize);
2018-11-14 20:29:40 +08:00
}
if (dynbuf != NULL) {
isc_buffer_free(&dynbuf);
2018-11-14 20:29:40 +08:00
}
if (invalidate_ctx) {
dns_compress_invalidate(&cctx);
2018-11-14 20:29:40 +08:00
}
return (result);
}
static void
printmessage(dns_message_t *msg) {
isc_buffer_t b;
char *buf = NULL;
int len = 1024;
isc_result_t result = ISC_R_SUCCESS;
2018-11-14 20:29:40 +08:00
if (!debug) {
return;
2018-11-14 20:29:40 +08:00
}
do {
buf = isc_mem_get(dt_mctx, len);
isc_buffer_init(&b, buf, len);
result = dns_message_totext(msg, &dns_master_style_debug,
0, &b);
if (result == ISC_R_NOSPACE) {
isc_mem_put(dt_mctx, buf, len);
len *= 2;
2018-11-14 20:29:40 +08:00
} else if (result == ISC_R_SUCCESS) {
printf("%.*s\n", (int) isc_buffer_usedlength(&b), buf);
2018-11-14 20:29:40 +08:00
}
} while (result == ISC_R_NOSPACE);
2018-11-14 20:29:40 +08:00
if (buf != NULL) {
isc_mem_put(dt_mctx, buf, len);
2018-11-14 20:29:40 +08:00
}
}
static void
render(isc_buffer_t *buf, unsigned flags, dns_tsigkey_t *key,
isc_buffer_t **tsigin, isc_buffer_t **tsigout,
dst_context_t *tsigctx)
{
dns_message_t *msg = NULL;
dns_compress_t cctx;
isc_result_t result;
result = dns_message_create(dt_mctx, DNS_MESSAGE_INTENTRENDER, &msg);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_non_null(msg);
msg->id = 50;
msg->rcode = dns_rcode_noerror;
msg->flags = flags;
/*
* XXXMPA: this hack needs to be replaced with use of
* dns_message_reply() at some point.
*/
2018-11-14 20:29:40 +08:00
if ((flags & DNS_MESSAGEFLAG_QR) != 0) {
msg->verified_sig = 1;
2018-11-14 20:29:40 +08:00
}
2018-11-14 20:29:40 +08:00
if (tsigin == tsigout) {
msg->tcp_continuation = 1;
2018-11-14 20:29:40 +08:00
}
if (tsigctx == NULL) {
result = dns_message_settsigkey(msg, key);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_message_setquerytsig(msg, *tsigin);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
}
result = dns_compress_init(&cctx, -1, dt_mctx);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_message_renderbegin(msg, &cctx, buf);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_message_renderend(msg);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
if (tsigctx != NULL) {
isc_region_t r;
isc_buffer_usedregion(buf, &r);
result = dst_context_adddata(tsigctx, &r);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
} else {
2018-11-14 20:29:40 +08:00
if (tsigin == tsigout && *tsigin != NULL) {
isc_buffer_free(tsigin);
2018-11-14 20:29:40 +08:00
}
result = dns_message_getquerytsig(msg, dt_mctx, tsigout);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
}
dns_compress_invalidate(&cctx);
dns_message_destroy(&msg);
}
/*
2018-11-14 20:29:40 +08:00
* Test tsig tcp-continuation validation:
* Check that a simulated three message TCP sequence where the first
* and last messages contain TSIGs but the intermediate message doesn't
* correctly verifies.
*/
2018-11-14 20:29:40 +08:00
static void
tsig_tcp_test(void **state) {
const dns_name_t *tsigowner = NULL;
dns_fixedname_t fkeyname;
dns_message_t *msg = NULL;
dns_name_t *keyname;
dns_tsig_keyring_t *ring = NULL;
dns_tsigkey_t *key = NULL;
isc_buffer_t *buf = NULL;
isc_buffer_t *querytsig = NULL;
isc_buffer_t *tsigin = NULL;
isc_buffer_t *tsigout = NULL;
isc_result_t result;
unsigned char secret[16] = { 0 };
dst_context_t *tsigctx = NULL;
dst_context_t *outctx = NULL;
2018-11-14 20:29:40 +08:00
UNUSED(state);
/* isc_log_setdebuglevel(lctx, 99); */
keyname = dns_fixedname_initname(&fkeyname);
result = dns_name_fromstring(keyname, "test", 0, NULL);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_tsigkeyring_create(dt_mctx, &ring);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_tsigkey_create(keyname, dns_tsig_hmacsha256_name,
secret, sizeof(secret), false,
NULL, 0, 0, dt_mctx, ring, &key);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_non_null(key);
/*
* Create request.
*/
result = isc_buffer_allocate(dt_mctx, &buf, 65535);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
render(buf, 0, key, &tsigout, &querytsig, NULL);
isc_buffer_free(&buf);
/*
* Create response message 1.
*/
result = isc_buffer_allocate(dt_mctx, &buf, 65535);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
render(buf, DNS_MESSAGEFLAG_QR, key, &querytsig, &tsigout, NULL);
/*
* Process response message 1.
*/
result = dns_message_create(dt_mctx, DNS_MESSAGE_INTENTPARSE, &msg);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_non_null(msg);
result = dns_message_settsigkey(msg, key);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_message_parse(msg, buf, 0);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
printmessage(msg);
result = dns_message_setquerytsig(msg, querytsig);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_tsig_verify(buf, msg, NULL, NULL);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(msg->verified_sig, 1);
assert_int_equal(msg->tsigstatus, dns_rcode_noerror);
/*
* Check that we have a TSIG in the first message.
*/
2018-11-14 20:29:40 +08:00
assert_non_null(dns_message_gettsig(msg, &tsigowner));
result = dns_message_getquerytsig(msg, dt_mctx, &tsigin);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
tsigctx = msg->tsigctx;
msg->tsigctx = NULL;
isc_buffer_free(&buf);
dns_message_destroy(&msg);
result = dst_context_create(key->key, dt_mctx, DNS_LOGCATEGORY_DNSSEC,
false, 0, &outctx);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_non_null(outctx);
/*
* Start digesting.
*/
result = add_mac(outctx, tsigout);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
/*
* Create response message 2.
*/
result = isc_buffer_allocate(dt_mctx, &buf, 65535);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
render(buf, DNS_MESSAGEFLAG_QR, key, &tsigout, &tsigout, outctx);
/*
* Process response message 2.
*/
result = dns_message_create(dt_mctx, DNS_MESSAGE_INTENTPARSE, &msg);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_non_null(msg);
msg->tcp_continuation = 1;
msg->tsigctx = tsigctx;
tsigctx = NULL;
result = dns_message_settsigkey(msg, key);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_message_parse(msg, buf, 0);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
printmessage(msg);
result = dns_message_setquerytsig(msg, tsigin);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_tsig_verify(buf, msg, NULL, NULL);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(msg->verified_sig, 0);
assert_int_equal(msg->tsigstatus, dns_rcode_noerror);
/*
* Check that we don't have a TSIG in the second message.
*/
tsigowner = NULL;
2018-11-14 20:29:40 +08:00
assert_true(dns_message_gettsig(msg, &tsigowner) == NULL);
tsigctx = msg->tsigctx;
msg->tsigctx = NULL;
isc_buffer_free(&buf);
dns_message_destroy(&msg);
/*
* Create response message 3.
*/
result = isc_buffer_allocate(dt_mctx, &buf, 65535);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
render(buf, DNS_MESSAGEFLAG_QR, key, &tsigout, &tsigout, outctx);
result = add_tsig(outctx, key, buf);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
/*
* Process response message 3.
*/
result = dns_message_create(dt_mctx, DNS_MESSAGE_INTENTPARSE, &msg);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_non_null(msg);
msg->tcp_continuation = 1;
msg->tsigctx = tsigctx;
tsigctx = NULL;
result = dns_message_settsigkey(msg, key);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_message_parse(msg, buf, 0);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
printmessage(msg);
/*
* Check that we had a TSIG in the third message.
*/
2018-11-14 20:29:40 +08:00
assert_non_null(dns_message_gettsig(msg, &tsigowner));
result = dns_message_setquerytsig(msg, tsigin);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_tsig_verify(buf, msg, NULL, NULL);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(msg->verified_sig, 1);
assert_int_equal(msg->tsigstatus, dns_rcode_noerror);
2018-11-14 20:29:40 +08:00
if (tsigin != NULL) {
isc_buffer_free(&tsigin);
2018-11-14 20:29:40 +08:00
}
result = dns_message_getquerytsig(msg, dt_mctx, &tsigin);
2018-11-14 20:29:40 +08:00
assert_int_equal(result, ISC_R_SUCCESS);
isc_buffer_free(&buf);
dns_message_destroy(&msg);
2018-11-14 20:29:40 +08:00
if (outctx != NULL) {
dst_context_destroy(&outctx);
2018-11-14 20:29:40 +08:00
}
if (querytsig != NULL) {
isc_buffer_free(&querytsig);
2018-11-14 20:29:40 +08:00
}
if (tsigin != NULL) {
isc_buffer_free(&tsigin);
2018-11-14 20:29:40 +08:00
}
if (tsigout != NULL) {
isc_buffer_free(&tsigout);
2018-11-14 20:29:40 +08:00
}
dns_tsigkey_detach(&key);
2018-11-14 20:29:40 +08:00
if (ring != NULL) {
dns_tsigkeyring_detach(&ring);
2018-11-14 20:29:40 +08:00
}
}
2018-11-14 20:29:40 +08:00
/* Tests the dns__tsig_algvalid function */
static void
algvalid_test(void **state) {
UNUSED(state);
2018-11-14 20:29:40 +08:00
assert_true(dns__tsig_algvalid(DST_ALG_HMACMD5));
2018-11-14 20:29:40 +08:00
assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA1));
assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA224));
assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA256));
assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA384));
assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA512));
2018-11-14 20:29:40 +08:00
assert_false(dns__tsig_algvalid(DST_ALG_GSSAPI));
}
2018-11-14 20:29:40 +08:00
/* Tests the dns__tsig_algfromname function */
static void
algfromname_test(void **state) {
UNUSED(state);
assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACMD5_NAME),
DST_ALG_HMACMD5);
assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA1_NAME),
DST_ALG_HMACSHA1);
assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA224_NAME),
DST_ALG_HMACSHA224);
assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA256_NAME),
DST_ALG_HMACSHA256);
assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA384_NAME),
DST_ALG_HMACSHA384);
assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA512_NAME),
DST_ALG_HMACSHA512);
assert_int_equal(dns__tsig_algfromname(DNS_TSIG_GSSAPI_NAME),
DST_ALG_GSSAPI);
assert_int_equal(dns__tsig_algfromname(DNS_TSIG_GSSAPIMS_NAME),
DST_ALG_GSSAPI);
assert_int_equal(dns__tsig_algfromname(dns_rootname), 0);
}
2018-11-14 20:29:40 +08:00
/* Tests the dns__tsig_algnamefromname function */
/*
* Helper function to create a dns_name_t from a string and see if
* the dns__tsig_algnamefromname function can correctly match it against the
* static table of known algorithms.
*/
static void test_name(const char *name_string, const dns_name_t *expected) {
dns_name_t name;
dns_name_init(&name, NULL);
assert_int_equal(dns_name_fromstring(&name, name_string, 0, dt_mctx),
2018-11-14 20:29:40 +08:00
ISC_R_SUCCESS);
assert_int_equal(dns__tsig_algnamefromname(&name), expected);
dns_name_free(&name, dt_mctx);
}
2018-11-14 20:29:40 +08:00
static void
algnamefromname_test(void **state) {
UNUSED(state);
/* test the standard algorithms */
test_name("hmac-md5.sig-alg.reg.int", DNS_TSIG_HMACMD5_NAME);
test_name("hmac-sha1", DNS_TSIG_HMACSHA1_NAME);
test_name("hmac-sha224", DNS_TSIG_HMACSHA224_NAME);
test_name("hmac-sha256", DNS_TSIG_HMACSHA256_NAME);
test_name("hmac-sha384", DNS_TSIG_HMACSHA384_NAME);
test_name("hmac-sha512", DNS_TSIG_HMACSHA512_NAME);
test_name("gss-tsig", DNS_TSIG_GSSAPI_NAME);
test_name("gss.microsoft.com", DNS_TSIG_GSSAPIMS_NAME);
/* try another name that isn't a standard algorithm name */
2018-11-14 20:29:40 +08:00
assert_int_equal(dns__tsig_algnamefromname(dns_rootname), NULL);
}
2018-11-14 20:29:40 +08:00
/* Tests the dns__tsig_algallocated function */
static void
algallocated_test(void **state) {
UNUSED(state);
/* test the standard algorithms */
2018-11-14 20:29:40 +08:00
assert_false(dns__tsig_algallocated(DNS_TSIG_HMACMD5_NAME));
assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA1_NAME));
assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA224_NAME));
assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA256_NAME));
assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA384_NAME));
assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA512_NAME));
2018-11-14 20:29:40 +08:00
assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA512_NAME));
assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA512_NAME));
/* try another name that isn't a standard algorithm name */
2018-11-14 20:29:40 +08:00
assert_true(dns__tsig_algallocated(dns_rootname));
}
2018-11-14 20:29:40 +08:00
int
main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(tsig_tcp_test,
_setup, _teardown),
cmocka_unit_test(algvalid_test),
cmocka_unit_test(algfromname_test),
cmocka_unit_test_setup_teardown(algnamefromname_test,
_setup, _teardown),
cmocka_unit_test(algallocated_test),
};
return (cmocka_run_group_tests(tests, NULL, NULL));
}
2018-11-14 20:29:40 +08:00
#else /* HAVE_CMOCKA */
#include <stdio.h>
int
main(void) {
printf("1..0 # Skipped: cmocka not available\n");
return (0);
}
#endif