]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Implement RFC 3645 Section 4.1.1 key expiry check in TKEY
authorOndřej Surý <ondrej@sury.org>
Tue, 17 Mar 2026 23:28:04 +0000 (00:28 +0100)
committerOndřej Surý <ondrej@sury.org>
Wed, 1 Apr 2026 05:04:39 +0000 (07:04 +0200)
Check for existing non-expired TSIG keys before accepting a new
GSS-API negotiation.  Per RFC 3645 Section 4.1.1:

- If a key exists and has not expired, reject with BADNAME
- If a key exists but has expired, delete it and start fresh

Previously, an expired GSS key would permanently block
re-negotiation for that name until the server was restarted.

Use BADKEY rather than BADNAME to avoid creating an oracle for
key name enumeration by unauthenticated attackers.

lib/dns/tkey.c

index f09edc2a9c4d25ae022c65cdbe075ce5786d8086..42deb423a2bc850e69d26d579f56822807047c4b 100644 (file)
@@ -178,15 +178,6 @@ process_gsstkey(dns_message_t *msg, dns_name_t *name, dns_rdata_tkey_t *tkeyin,
                return ISC_R_SUCCESS;
        }
 
-       /*
-        * XXXDCL need to check for key expiry per 4.1.1
-        * XXXDCL need a way to check fully established, perhaps w/key_flags
-        */
-       result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring);
-       if (result == ISC_R_SUCCESS) {
-               gss_ctx = dst_key_getgssctx(tsigkey->key);
-       }
-
        intoken = (isc_region_t){ tkeyin->key, tkeyin->keylen };
        result = dst_gssapi_acceptctx(tctx->gssapi_keytab, &intoken, &outtoken,
                                      &gss_ctx, principal, tctx->mctx);
@@ -430,10 +421,26 @@ dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx,
 
                result = dns_tsigkey_find(&tsigkey, keyname, NULL, ring);
                if (result == ISC_R_SUCCESS) {
-                       tkeyout.error = dns_tsigerror_badname;
-                       dns_tsigkey_detach(&tsigkey);
-                       break;
-               } else if (result == ISC_R_NOTFOUND) {
+                       /*
+                        * RFC 3645 Section 4.1.1: if the key exists
+                        * but has expired, delete it and allow
+                        * re-negotiation.  We use BADKEY rather than
+                        * BADNAME to avoid creating an oracle for key
+                        * name enumeration.
+                        */
+                       if (tsigkey->inception != tsigkey->expire &&
+                           tsigkey->expire <= isc_stdtime_now())
+                       {
+                               dns_tsigkey_delete(tsigkey);
+                               dns_tsigkey_detach(&tsigkey);
+                               result = ISC_R_NOTFOUND;
+                       } else {
+                               tkeyout.error = dns_tsigerror_badkey;
+                               dns_tsigkey_detach(&tsigkey);
+                               break;
+                       }
+               }
+               if (result == ISC_R_NOTFOUND || tsigkey == NULL) {
                        CHECK(process_gsstkey(msg, keyname, &tkeyin, tctx,
                                              &tkeyout, ring));
                        break;