From 3048b2a5784e624fe021712b5dabf1d731f47c13 Mon Sep 17 00:00:00 2001 From: Colin Vidal Date: Tue, 2 Dec 2025 16:53:40 +0100 Subject: [PATCH 1/2] add RRSIG if required as soon as they are found When EDNS DO flag (`dig +dnssec`) flag is set, an rdataset is allocated to hold the RRSIG of an RR, if present in DB. However, this allocation is not done if the zone DB is not considered as secure (`dns_db_issecure() == false`). Changes this behaviour by allocating the rdataset anyway, so the RRSIG can be associated in the answer section of the response as soon it is found from the DB. --- lib/ns/query.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/ns/query.c b/lib/ns/query.c index f0a5a50251..22a3a9caa5 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -5843,9 +5843,7 @@ qctx_prepare_buffers(query_ctx_t *qctx, isc_buffer_t *buffer) { qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, buffer); qctx->rdataset = ns_client_newrdataset(qctx->client); - if ((WANTDNSSEC(qctx->client) || qctx->findcoveringnsec) && - (!qctx->is_zone || dns_db_issecure(qctx->db))) - { + if (WANTDNSSEC(qctx->client) || qctx->findcoveringnsec) { qctx->sigrdataset = ns_client_newrdataset(qctx->client); } From 6998fe42e354fc476618856a5bb7e96f0de6b204 Mon Sep 17 00:00:00 2001 From: Colin Vidal Date: Tue, 2 Dec 2025 19:00:55 +0100 Subject: [PATCH 2/2] test for RRSIG provided as soon as they are found Add a system test which checks that a server authoritative on zone which is not fully signed (here, it is missing the DNSKEY records as well as the RRSIG on the RR `b`) still return the RRSIG associated with an RR if provided in the zone. --- bin/tests/system/rrsig/ns1/named.conf.j2 | 45 ++++++++++ bin/tests/system/rrsig/ns1/test.db | 102 +++++++++++++++++++++++ bin/tests/system/rrsig/tests_rrsig.py | 36 ++++++++ 3 files changed, 183 insertions(+) create mode 100644 bin/tests/system/rrsig/ns1/named.conf.j2 create mode 100644 bin/tests/system/rrsig/ns1/test.db create mode 100644 bin/tests/system/rrsig/tests_rrsig.py diff --git a/bin/tests/system/rrsig/ns1/named.conf.j2 b/bin/tests/system/rrsig/ns1/named.conf.j2 new file mode 100644 index 0000000000..720353ab76 --- /dev/null +++ b/bin/tests/system/rrsig/ns1/named.conf.j2 @@ -0,0 +1,45 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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 https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +options { + notify-source 10.53.0.1; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.1; }; + listen-on-v6 { none; }; + allow-transfer { any; }; + recursion no; + notify explicit; + + /* + * We don't want the server to sign the zone here (which is the + * default), as we want to keep the zone partially signed. All which + * matters is that if +dnssec is set (EDNS flag DO) then RRSIG + * associated to the QTYPE, if present, is provided in the answer. + */ + dnssec-policy none; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm @DEFAULT_HMAC@; +}; + +controls { + inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; + +zone "test" { + file "test.db"; + type primary; +}; diff --git a/bin/tests/system/rrsig/ns1/test.db b/bin/tests/system/rrsig/ns1/test.db new file mode 100644 index 0000000000..91105f5882 --- /dev/null +++ b/bin/tests/system/rrsig/ns1/test.db @@ -0,0 +1,102 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; SPDX-License-Identifier: MPL-2.0 +; +; 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 https://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +; This zone file is signed but is not a valid signed zone. It is missing +; DNSKEYs and RR b.test is not signed + +; File (originally) written on Wed Dec 3 11:56:30 2025 +; dnssec-signzone version 9.20.9-dev +test. 300 IN SOA mname1. . ( + 2000042407 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + 300 RRSIG SOA 13 1 300 ( + 20260102095630 20251203095630 52821 test. + P7APqLQqBAd/nqcUcFUnSBpAwfSI/qM4tUvH + wdTtOlog9L0SxPhPFX2MQFqDQ8JO6mMlwU7c + Re/P/ATZ/OKt2Q== ) + 300 NS ns.test. + 300 RRSIG NS 13 1 300 ( + 20260102095630 20251203095630 52821 test. + hEFoqGYUAZtjH5pY0vGcPGBIsIC5lz1PETij + 8tGSE0VSopYDFOxiaoYh2gdP0DIuU+zkvObQ + K/fLQht0EvcpUg== ) + 300 MX 10 mx.test. + 300 RRSIG MX 13 1 300 ( + 20260102095630 20251203095630 52821 test. + ng2y6mPF6d+dhxK2gI4SMcGJFRW/TXSuGZIj + 6vkMLnnaGii2wuc1riJ8+71cGFfobYh49sff + a6kMDN+Yeoh2ZA== ) + 300 NSEC a.test. NS SOA MX RRSIG NSEC DNSKEY + 300 RRSIG NSEC 13 1 300 ( + 20260102095630 20251203095630 52821 test. + HaOwDq57XKfMRafsTXWikWCz6c9vj62iO/gA + m4xg87ynpkFQKtjHTvMPTQm7yfA+JPPdnH+W + Id8V5/eA43Wz5g== ) +; 300 DNSKEY 256 3 13 ( +; exU/MZuG3h7i6u4Ey7YajUmRjXnBEqMjwj9W +; GN8BJxuVzbiRiiylSaxxgMHUgvY0+xpCX/vQ +; lKQm7tRf/b9ItA== +; ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 52821 +; 300 DNSKEY 257 3 13 ( +; SwabCqxfxlzLRPN/oPu+8ShNd2J0QZA0NHNg +; 18TrNCPbc7z2nYS2KPxCOt+AEr7abBhI6w76 +; vpyST26I6x0u6g== +; ) ; KSK; alg = ECDSAP256SHA256 ; key id = 44462 + 300 RRSIG DNSKEY 13 1 300 ( + 20260102095630 20251203095630 44462 test. + Iab1tk+FrJOuSImGTbroLk3r3Cu7IQEoL/5N + tXCB/W87X0hLI9KgrrZgYWBvLQL388QtDSSO + MoAYKxn2c+wWXw== ) + 300 RRSIG DNSKEY 13 1 300 ( + 20260102095630 20251203095630 52821 test. + SXx+YXfM2A9Q94rKnaJ4NFGqJ5uKeuCdUpSM + owIshSrjqfQZNyYp0Obz6lb8HD9XxwASpHfx + VUOn7OHLZa0hiA== ) +a.test. 300 IN A 10.0.0.1 + 300 RRSIG A 13 2 300 ( + 20260102095630 20251203095630 52821 test. + 37i9bH5PCR42bCLS62ydRGHB6Q7OUKUUGoV5 + CR2tKtODSlHdByuAcPP8KOahyglgLxIx7191 + ZOiMzsyQdD8zDg== ) + 300 NSEC b.test. A RRSIG NSEC + 300 RRSIG NSEC 13 2 300 ( + 20260102095630 20251203095630 52821 test. + am4Q7ULEti/XiiYXQV6JkRh61sW23928y/JH + zBkHj/e5HIRWOwG8v4ivRhnZJjzzEJSIJmhv + hw7duxsVKKbITw== ) +b.test. 300 IN A 10.0.0.2 +; 300 RRSIG A 13 2 300 ( +; 20260102095630 20251203095630 52821 test. +; /bJJcHiTPW7csvPNOzEkedb04EWPdGcmHfrS +; LjCt3+JBKB8kxtPhv5VoqodNBRlnydCUV2AS +; 5aYRegtIcEuwog== ) + 300 NSEC ns.test. A RRSIG NSEC + 300 RRSIG NSEC 13 2 300 ( + 20260102095630 20251203095630 52821 test. + +Q2H9NBt/9KGKeuQLEVSt5sLP6KnkpI68gxa + F0B2vfN0npwWxPPqUktj0QcvXj4HQK0iW7aa + 2Ce8AlAp1y32xg== ) +ns.test. 300 IN A 10.53.0.1 + 300 RRSIG A 13 2 300 ( + 20260102095630 20251203095630 52821 test. + /g2PZ6LTkN7N+PvP5RKUgkXeVQimKiNyrAmX + PZz0x5OhgpLRrDuAAYX7JR/QqUZ61uAtLUO8 + RCED90fQOLWLPw== ) + 300 NSEC test. A RRSIG NSEC + 300 RRSIG NSEC 13 2 300 ( + 20260102095630 20251203095630 52821 test. + CaUsf4jGVbi8y7fH4l4EDYdhjz+tcP2M9bCl + hfh/tivKMutTm3qr1kB96liC+Tkw9m3waxZo + zZgr++cyTF2lkw== ) diff --git a/bin/tests/system/rrsig/tests_rrsig.py b/bin/tests/system/rrsig/tests_rrsig.py new file mode 100644 index 0000000000..c7b7ec1f69 --- /dev/null +++ b/bin/tests/system/rrsig/tests_rrsig.py @@ -0,0 +1,36 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# 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 https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import isctest + +import pytest +from dns import rdatatype + + +@pytest.mark.parametrize( + "name, dnssec, expect_rrsig", + [ + ("a.test", True, True), + ("a.test", False, False), + ("b.test", True, False), + ("b.test", False, False), + ], +) +def test_rrsig(name, dnssec, expect_rrsig): + msg = isctest.query.create(name, "A", dnssec=dnssec) + res = isctest.query.udp(msg, "10.53.0.1") + isctest.check.noerror(res) + if expect_rrsig: + assert len(res.answer) == 2 + assert res.answer[1].rdtype == rdatatype.RRSIG + else: + assert len(res.answer) == 1 + assert res.answer[0].rdtype == rdatatype.A