From e914c5e194ab8f604b28d1de81dc514a23f3c3ac Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 28 Feb 2023 18:29:38 -0800 Subject: [PATCH] add basic test for TSIG key dump/restore functionality stop and restart the server in the 'tsiggss' test, in order to confirm that GSS negotiated TSIG keys are saved and restored when named loads. added logging to dns_tsigkey_createfromkey() to indicate whether a key has been statically configured, generated via GSS negotiation, or restored from a file. --- bin/dig/dighost.c | 8 ++--- bin/named/server.c | 3 +- bin/named/tsigconf.c | 4 +-- bin/nsupdate/nsupdate.c | 10 +++--- bin/tests/system/conf.sh.in | 2 -- bin/tests/system/tsiggss/tests.sh | 12 +++++++ fuzz/dns_message_checksig.c | 4 +-- lib/dns/include/dns/tsig.h | 28 ++++++++-------- lib/dns/tkey.c | 8 ++--- lib/dns/tsig.c | 55 +++++++++++++++++-------------- tests/dns/tsig_test.c | 4 +-- 11 files changed, 80 insertions(+), 58 deletions(-) diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 8c30438cc2..97b53f1b2f 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -884,8 +884,8 @@ setup_text_key(void) { } result = dns_tsigkey_create(&keyname, hmacname, secretstore, - (int)secretsize, false, NULL, 0, 0, mctx, - NULL, &tsigkey); + (int)secretsize, false, false, NULL, 0, 0, + mctx, NULL, &tsigkey); failure: if (result != ISC_R_SUCCESS) { printf(";; Couldn't create key %s: %s\n", keynametext, @@ -1186,8 +1186,8 @@ setup_file_key(void) { if (hmacname != NULL) { result = dns_tsigkey_createfromkey( - dst_key_name(dstkey), hmacname, dstkey, false, NULL, 0, - 0, mctx, NULL, &tsigkey); + dst_key_name(dstkey), hmacname, dstkey, false, 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)); diff --git a/bin/named/server.c b/bin/named/server.c index 8ca6872ded..f40a641e32 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -7548,7 +7548,8 @@ generate_session_key(const char *filename, const char *keynamestr, /* Store the key in tsigkey. */ isc_stdtime_get(&now); CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key, false, - NULL, now, now, mctx, NULL, &tsigkey)); + false, NULL, now, now, mctx, NULL, + &tsigkey)); /* Dump the key to the key file. */ fp = named_os_openfile(filename, S_IRUSR | S_IWUSR, first_time); diff --git a/bin/named/tsigconf.c b/bin/named/tsigconf.c index 6d596ab27f..d20ab72103 100644 --- a/bin/named/tsigconf.c +++ b/bin/named/tsigconf.c @@ -106,8 +106,8 @@ add_initial_keys(const cfg_obj_t *list, dns_tsig_keyring_t *ring, isc_stdtime_get(&now); ret = dns_tsigkey_create(&keyname, alg, secret, secretlen, - false, NULL, now, now, mctx, ring, - &tsigkey); + false, false, NULL, now, now, mctx, + ring, &tsigkey); isc_mem_put(mctx, secret, secretalloc); secret = NULL; if (ret != ISC_R_SUCCESS) { diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index 60a3874a6a..e93b8abc2b 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -542,7 +542,8 @@ setup_keystr(void) { debug("keycreate"); result = dns_tsigkey_create(mykeyname, hmacname, secret, secretlen, - false, NULL, 0, 0, gmctx, NULL, &tsigkey); + false, false, NULL, 0, 0, gmctx, NULL, + &tsigkey); if (result != ISC_R_SUCCESS) { fprintf(stderr, "could not create key from %s: %s\n", keystr, isc_result_totext(result)); @@ -676,8 +677,8 @@ setup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) { } if (hmacname != NULL) { result = dns_tsigkey_createfromkey( - dst_key_name(dstkey), hmacname, dstkey, false, NULL, 0, - 0, mctx, NULL, &tsigkey); + dst_key_name(dstkey), hmacname, dstkey, false, false, + NULL, 0, 0, mctx, NULL, &tsigkey); dst_key_free(&dstkey); if (result != ISC_R_SUCCESS) { fprintf(stderr, "could not create key from %s: %s\n", @@ -1710,7 +1711,8 @@ evaluate_key(char *cmdline) { dns_tsigkey_detach(&tsigkey); } result = dns_tsigkey_create(mykeyname, hmacname, secret, secretlen, - false, NULL, 0, 0, gmctx, NULL, &tsigkey); + false, false, NULL, 0, 0, gmctx, NULL, + &tsigkey); isc_mem_free(gmctx, secret); if (result != ISC_R_SUCCESS) { fprintf(stderr, "could not create key from %s %s: %s\n", diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in index 3969495821..ebf4d52522 100644 --- a/bin/tests/system/conf.sh.in +++ b/bin/tests/system/conf.sh.in @@ -56,8 +56,6 @@ export WIRETEST=$TOP_BUILDDIR/bin/tests/wire_test export BIGKEY=$TOP_BUILDDIR/bin/tests/system/rsabigexponent/bigkey export GENCHECK=$TOP_BUILDDIR/bin/tests/system/rndc/gencheck -export KEYCREATE=$TOP_BUILDDIR/bin/tests/system/tkey/keycreate -export KEYDELETE=$TOP_BUILDDIR/bin/tests/system/tkey/keydelete export MAKEJOURNAL=$TOP_BUILDDIR/bin/tests/system/makejournal export PIPEQUERIES=$TOP_BUILDDIR/bin/tests/system/pipelined/pipequeries diff --git a/bin/tests/system/tsiggss/tests.sh b/bin/tests/system/tsiggss/tests.sh index ee592bb470..32abb28f95 100644 --- a/bin/tests/system/tsiggss/tests.sh +++ b/bin/tests/system/tsiggss/tests.sh @@ -168,6 +168,18 @@ n=$((n+1)) if [ "$ret" -ne 0 ]; then echo_i "failed"; fi status=$((status+ret)) +echo_i "stop and start server to check key restoration ($n)" +ret=0 +gss_keys=$(grep 'tsig key.*generated' ns1/named.run | wc -l) +stop_server --use-rndc --port "${CONTROLPORT}" ns1 +start_server --noclean --restart --port "${PORT}" ns1 +restored_keys=$(grep 'tsig key.*restored from file' ns1/named.run | wc -l) +[ "$gss_keys" -ne 0 ] || ret=1 +[ "$restored_keys" -ne 0 ] || ret=1 +[ "$gss_keys" -eq "$restored_keys" ] || ret=1 +if [ "$ret" -ne 0 ]; then echo_i "failed"; fi +status=$((status+ret)) + [ $status -eq 0 ] && echo_i "tsiggss tests all OK" kill `cat authsock.pid` diff --git a/fuzz/dns_message_checksig.c b/fuzz/dns_message_checksig.c index b7407f3dd6..5c8f81aeb9 100644 --- a/fuzz/dns_message_checksig.c +++ b/fuzz/dns_message_checksig.c @@ -263,8 +263,8 @@ LLVMFuzzerInitialize(int *argc __attribute__((unused)), } result = dns_tsigkey_create(name, dns_tsig_hmacsha256_name, secret, - sizeof(secret), false, NULL, 0, 0, mctx, - ring, &tsigkey); + sizeof(secret), false, false, NULL, 0, 0, + mctx, ring, &tsigkey); if (result != ISC_R_SUCCESS) { fprintf(stderr, "dns_tsigkey_create failed: %s\n", isc_result_totext(result)); diff --git a/lib/dns/include/dns/tsig.h b/lib/dns/include/dns/tsig.h index 48292a1da4..bb72d01e17 100644 --- a/lib/dns/include/dns/tsig.h +++ b/lib/dns/include/dns/tsig.h @@ -72,15 +72,16 @@ struct dns_tsigkey { /* Unlocked */ unsigned int magic; /*%< Magic number. */ isc_mem_t *mctx; - dst_key_t *key; /*%< Key */ - dns_name_t name; /*%< Key name */ - const dns_name_t *algorithm; /*%< Algorithm name */ - dns_name_t *creator; /*%< name that created secret */ - bool generated; /*%< was this generated? */ - isc_stdtime_t inception; /*%< start of validity period */ - isc_stdtime_t expire; /*%< end of validity period */ - dns_tsig_keyring_t *ring; /*%< the enclosing keyring */ - isc_refcount_t refs; /*%< reference counter */ + dst_key_t *key; /*%< Key */ + dns_name_t name; /*%< Key name */ + const dns_name_t *algorithm; /*%< Algorithm name */ + dns_name_t *creator; /*%< name that created secret */ + bool generated : 1; /*%< key was auto-generated */ + bool restored : 1; /*%< key was restored at startup */ + isc_stdtime_t inception; /*%< start of validity period */ + isc_stdtime_t expire; /*%< end of validity period */ + dns_tsig_keyring_t *ring; /*%< the enclosing keyring */ + isc_refcount_t refs; /*%< reference counter */ ISC_LINK(dns_tsigkey_t) link; }; @@ -102,13 +103,14 @@ dns_tsigkey_identity(const dns_tsigkey_t *tsigkey); isc_result_t dns_tsigkey_create(const dns_name_t *name, const dns_name_t *algorithm, unsigned char *secret, int length, bool generated, - const dns_name_t *creator, isc_stdtime_t inception, - isc_stdtime_t expire, isc_mem_t *mctx, - dns_tsig_keyring_t *ring, dns_tsigkey_t **key); + bool restored, const dns_name_t *creator, + isc_stdtime_t inception, isc_stdtime_t expire, + isc_mem_t *mctx, dns_tsig_keyring_t *ring, + dns_tsigkey_t **key); isc_result_t dns_tsigkey_createfromkey(const dns_name_t *name, const dns_name_t *algorithm, - dst_key_t *dstkey, bool generated, + dst_key_t *dstkey, bool generated, bool restored, const dns_name_t *creator, isc_stdtime_t inception, isc_stdtime_t expire, isc_mem_t *mctx, dns_tsig_keyring_t *ring, dns_tsigkey_t **key); diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c index a452c45b11..45ac21c003 100644 --- a/lib/dns/tkey.c +++ b/lib/dns/tkey.c @@ -269,8 +269,8 @@ process_gsstkey(dns_message_t *msg, dns_name_t *name, dns_rdata_tkey_t *tkeyin, } #endif /* HAVE_GSSAPI */ RETERR(dns_tsigkey_createfromkey( - name, &tkeyin->algorithm, dstkey, true, principal, now, - expire, ring->mctx, ring, &tsigkey)); + name, &tkeyin->algorithm, dstkey, true, false, + principal, now, expire, ring->mctx, ring, &tsigkey)); dst_key_free(&dstkey); tkeyout->inception = now; tkeyout->expire = expire; @@ -861,8 +861,8 @@ dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, RETERR(dns_tsigkey_createfromkey( tkeyname, (win2k ? DNS_TSIG_GSSAPIMS_NAME : DNS_TSIG_GSSAPI_NAME), dstkey, - true, NULL, rtkey.inception, rtkey.expire, ring->mctx, ring, - outkey)); + true, false, NULL, rtkey.inception, rtkey.expire, ring->mctx, + ring, outkey)); dst_key_free(&dstkey); dns_rdata_freestruct(&rtkey); return (result); diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c index 54f3d2e5df..8eef675b82 100644 --- a/lib/dns/tsig.c +++ b/lib/dns/tsig.c @@ -150,7 +150,7 @@ tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) { strlcpy(namestr, "", sizeof(namestr)); } - if (key != NULL && key->generated && key->creator) { + if (key != NULL && key->generated && key->creator != NULL) { dns_name_format(key->creator, creatorstr, sizeof(creatorstr)); } else { strlcpy(creatorstr, "", sizeof(creatorstr)); @@ -239,11 +239,11 @@ keyring_add(dns_tsig_keyring_t *ring, const dns_name_t *name, isc_result_t dns_tsigkey_createfromkey(const dns_name_t *name, const dns_name_t *algorithm, - dst_key_t *dstkey, bool generated, + dst_key_t *dstkey, bool generated, bool restored, const dns_name_t *creator, isc_stdtime_t inception, isc_stdtime_t expire, isc_mem_t *mctx, dns_tsig_keyring_t *ring, dns_tsigkey_t **key) { - dns_tsigkey_t *tkey; + dns_tsigkey_t *tkey = NULL; isc_result_t ret; unsigned int refs = 0; unsigned int dstalg = 0; @@ -255,8 +255,16 @@ dns_tsigkey_createfromkey(const dns_name_t *name, const dns_name_t *algorithm, REQUIRE(key != NULL || ring != NULL); tkey = isc_mem_get(mctx, sizeof(dns_tsigkey_t)); + *tkey = (dns_tsigkey_t){ + .generated = generated, + .restored = restored, + .ring = ring, + .inception = inception, + .expire = expire, + .name = DNS_NAME_INITEMPTY, + .link = ISC_LINK_INITIALIZER, + }; - dns_name_init(&tkey->name, NULL); dns_name_dup(name, mctx, &tkey->name); (void)dns_name_downcase(&tkey->name, &tkey->name, NULL); @@ -273,7 +281,7 @@ dns_tsigkey_createfromkey(const dns_name_t *name, const dns_name_t *algorithm, goto cleanup_name; } } else { - dns_name_t *tmpname; + dns_name_t *tmpname = NULL; if (dstkey != NULL) { ret = DNS_R_BADALG; goto cleanup_name; @@ -289,15 +297,11 @@ dns_tsigkey_createfromkey(const dns_name_t *name, const dns_name_t *algorithm, tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t)); dns_name_init(tkey->creator, NULL); dns_name_dup(creator, mctx, tkey->creator); - } else { - tkey->creator = NULL; } - tkey->key = NULL; if (dstkey != NULL) { dst_key_attach(dstkey, &tkey->key); } - tkey->ring = ring; if (key != NULL) { refs = 1; @@ -307,13 +311,7 @@ dns_tsigkey_createfromkey(const dns_name_t *name, const dns_name_t *algorithm, } isc_refcount_init(&tkey->refs, refs); - - tkey->generated = generated; - tkey->inception = inception; - tkey->expire = expire; - tkey->mctx = NULL; isc_mem_attach(mctx, &tkey->mctx); - ISC_LINK_INIT(tkey, link); tkey->magic = TSIG_MAGIC; @@ -342,6 +340,14 @@ dns_tsigkey_createfromkey(const dns_name_t *name, const dns_name_t *algorithm, *key = tkey; } + if (tkey->restored) { + tsig_log(tkey, ISC_LOG_DEBUG(3), "restored from file"); + } else if (tkey->generated) { + tsig_log(tkey, ISC_LOG_DEBUG(3), "generated"); + } else { + tsig_log(tkey, ISC_LOG_DEBUG(3), "statically configured"); + } + return (ISC_R_SUCCESS); cleanup_refs: @@ -553,7 +559,7 @@ restore_key(dns_tsig_keyring_t *ring, isc_stdtime_t now, FILE *fp) { return (result); } - result = dns_tsigkey_createfromkey(name, algorithm, dstkey, true, + result = dns_tsigkey_createfromkey(name, algorithm, dstkey, true, true, creator, inception, expire, ring->mctx, ring, NULL); if (dstkey != NULL) { @@ -658,9 +664,10 @@ dns_tsigkey_identity(const dns_tsigkey_t *tsigkey) { isc_result_t dns_tsigkey_create(const dns_name_t *name, const dns_name_t *algorithm, unsigned char *secret, int length, bool generated, - const dns_name_t *creator, isc_stdtime_t inception, - isc_stdtime_t expire, isc_mem_t *mctx, - dns_tsig_keyring_t *ring, dns_tsigkey_t **key) { + bool restored, const dns_name_t *creator, + isc_stdtime_t inception, isc_stdtime_t expire, + isc_mem_t *mctx, dns_tsig_keyring_t *ring, + dns_tsigkey_t **key) { dst_key_t *dstkey = NULL; isc_result_t result; unsigned int dstalg = 0; @@ -690,8 +697,8 @@ dns_tsigkey_create(const dns_name_t *name, const dns_name_t *algorithm, } result = dns_tsigkey_createfromkey(name, algorithm, dstkey, generated, - creator, inception, expire, mctx, - ring, key); + restored, creator, inception, expire, + mctx, ring, key); if (dstkey != NULL) { dst_key_free(&dstkey); } @@ -1170,9 +1177,9 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, } if (ret != ISC_R_SUCCESS) { msg->tsigstatus = dns_tsigerror_badkey; - ret = dns_tsigkey_create(keyname, &tsig.algorithm, NULL, - 0, false, NULL, now, now, mctx, - NULL, &msg->tsigkey); + ret = dns_tsigkey_create( + keyname, &tsig.algorithm, NULL, 0, false, false, + NULL, now, now, mctx, NULL, &msg->tsigkey); if (ret != ISC_R_SUCCESS) { return (ret); } diff --git a/tests/dns/tsig_test.c b/tests/dns/tsig_test.c index d00266bf14..02b5926f0c 100644 --- a/tests/dns/tsig_test.c +++ b/tests/dns/tsig_test.c @@ -295,8 +295,8 @@ ISC_RUN_TEST_IMPL(tsig_tcp) { assert_int_equal(result, ISC_R_SUCCESS); result = dns_tsigkey_create(keyname, dns_tsig_hmacsha256_name, secret, - sizeof(secret), false, NULL, 0, 0, mctx, - ring, &key); + sizeof(secret), false, false, NULL, 0, 0, + mctx, ring, &key); assert_int_equal(result, ISC_R_SUCCESS); assert_non_null(key);