]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Test that DNSSEC validation is aborted on malformed DNSKEY
authorNicki Křížek <nicki@isc.org>
Thu, 11 Sep 2025 12:27:34 +0000 (14:27 +0200)
committerNicki Křížek <nicki@isc.org>
Mon, 5 Jan 2026 13:04:58 +0000 (14:04 +0100)
Create a signed zone file that contains malformed ZSKs with colliding
key tags. The ZSKs don't represent valid ECDSA keys and will cause a
crypto failure when attempting to use them. Sign the zone with KSK, with
the exception of one record which is "signed" with the invalid ZSKs.

Check that the resolver aborts the DNSSEC verification after
encountering the first crypto failure, indicating malformed DNSKEY.

bin/tests/system/dnssec-malformed-dnskey/ns2/example.db.in [new file with mode: 0644]
bin/tests/system/dnssec-malformed-dnskey/ns2/named.conf.j2 [new file with mode: 0644]
bin/tests/system/dnssec-malformed-dnskey/ns2/trusted.conf.j2 [new file with mode: 0644]
bin/tests/system/dnssec-malformed-dnskey/ns3/named.conf.j2 [new file with mode: 0644]
bin/tests/system/dnssec-malformed-dnskey/ns3/trusted.conf.j2 [new symlink]
bin/tests/system/dnssec-malformed-dnskey/tests_malformed_dnskey.py [new file with mode: 0644]

diff --git a/bin/tests/system/dnssec-malformed-dnskey/ns2/example.db.in b/bin/tests/system/dnssec-malformed-dnskey/ns2/example.db.in
new file mode 100644 (file)
index 0000000..b1705d0
--- /dev/null
@@ -0,0 +1,128 @@
+; 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.
+
+$TTL 300
+@              IN SOA  mname1. . (
+                               1       ; serial
+                               600     ; refresh
+                               600     ; retry
+                               1200    ; expire
+                               600     ; minimum
+                               )
+
+@              NS      @
+@              A 10.53.0.2
+
+; All of the following DNSKEYs are malformed and have the same key tag - 20071.
+; The keys use invalid parameters for the ECDSA curve.
+
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5Or0NNksES2iAAwmRfEEnH/hzk+8xF
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfjFg5Y9Ytl2+UR1JO/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sW2HoOfwFg5Y1ctl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5ZA8tl2+URx5O/UNNkogS2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rjJ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwghfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD47F1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URydO/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNkuMS2iAAwmRfEEnH/hzk2cv3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNi7iu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Yt0W+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeNcGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8vg
+@              DNSKEY  256 3 14 rdZ2xb7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNky4S2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+FGHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5PE0NNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EFvr4ulinFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbkf1BvDhMNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtjlWd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNkuUS2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sS9HoOfwFg5Y9Ytl2+URx5O/UNNksETVCAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNkroS2iAHwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtmpWd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNAksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGQ8qmCKB+KmHS3YPgZjMZtl1W7/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmIe3YPgZjMZthFWd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Nr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGt8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cL1eMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHGAK8U3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4uli7FbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URqhO/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD6VF1z4ulhFFbCNdLiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulgyFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtIR/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAHOcqmCKB+KmHS3QXgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGasqmCKB+KmHS3dTgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfeVg5Y9Ytl2+URx5O/UNNksES2iAAwmRfV0nH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwsteqUnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1WEvfvtHF/3sU3HoOfwFieY9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9YtSW+UR2xO/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1WvPfvtHF/3sU3HoOfwFg5Y5Etl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPg5jMZtl1V9/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HnqfyVg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD6WF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sTlHoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BfD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfFEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgcjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk78v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD3HF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzleMv3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulinFbCNxbiu07nD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeJIGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFhnY9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCOE7iu1BvD9cNCeMAGu8qmCKB+KmGE3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtGB/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzlDMv3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EFwn4uliYFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cLTeMAGu8sVCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1WMvfvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iBFwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1JHD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfSlg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNf7iu1BvD9cNCeMAGu8qmCKB+KmHS3YPgrDMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFcCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fftHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fGtHF/3sU3HoOfwFg5Y9Ytl2+UR0dO/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjM7tl1Wd/fvtHF/3sU3HoOfnlg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbh71BvD9cN1eMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfYknH/crk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/hHtHF/3sU3HoOfwFg5Y9Ytl288Rx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF8z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB9umHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAHGsqmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y3ctl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4vlhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/frtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtopWd/fvtHF/3sU3HoOfwFgMY9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+lWHS3RjgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD4uF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgfDMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/gNtHF/3sU3HoOfwFg5Y9Ytl292Rx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/qMU3HoOfwFg5Y9YtzW+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytv2+URx5O/UMlksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr8HEQoEdD5EF1z4ulhFFYCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/6MU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEm9/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbkT1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmReq0nH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtCh/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzlRMv3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8rXCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzkysv3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPg2TMZtl1Wd/fvtHF/3sTEHoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOftVg5Y9Ytl2+URx5O/UNNksES2iAAwm9fEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cN2eMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sUDHoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr5aEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+p2HS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF0D4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOf3Fg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD6lF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCD9+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4jVhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtopWd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmI03YPgZjMZtftWd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtFp/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNktgS2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFZyNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwnhfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/gKtHF/w8U3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFfXY9Ytl2+URx5O/UNNksETPCAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNkeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/vMU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCN5Liu1BvD9cNCeMAGu8qmCKB+KmGz3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD4fF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9YtvG+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoE3z5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwflfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtjNWd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8wh
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1j4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfxFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ2+L7XEQoEdD5EF1z4ulhFFbCNxbiu1BvEL8NCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qOCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8wP
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbjh1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjLmtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjM2tl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2h/jwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCN4LiT1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr9DEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cLWeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFhYY9Ytl2+URx5O/UNNksES2iAAwmRe8UnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qlCKB+KmHS3YPgZjMatl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1n4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmdfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cODeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRez0nH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNqeMAGu8qmCKB+KmGq3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhrFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjLztl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF534ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2h+/wmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3QngZjMZtl1Wd/fvtHF/3sU3HoOfwFg5ZFAtl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+@              DNSKEY  256 3 14 rdZ3Mr7XEQoEdD5EF1z4ulhFFbCNxbiu1BvD9cNCeMAGu8qmCKB+KmHS3YPgZjMZtl1Wd/fvtHF/3sU3HoOfwFg5Y9Ytl2+URx5O/UNNksES2iAAwmRfEEnH/hzk+8v3
+
+malformed-dnskey               A       10.53.0.2
+multiple-rrsigs                        A       10.53.0.2
diff --git a/bin/tests/system/dnssec-malformed-dnskey/ns2/named.conf.j2 b/bin/tests/system/dnssec-malformed-dnskey/ns2/named.conf.j2
new file mode 100644 (file)
index 0000000..6f05c6d
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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 {
+       query-source address 10.53.0.2;
+       notify-source 10.53.0.2;
+       transfer-source 10.53.0.2;
+       port @PORT@;
+       pid-file "named.pid";
+       listen-on { 10.53.0.2; };
+       listen-on-v6 { none; };
+       allow-transfer { any; };
+       recursion no;
+       dnssec-validation yes;
+
+       /* Keep the order of RRSIGs in the response static. */
+       rrset-order {
+               name "example." order none;
+       };
+};
+
+zone example. {
+       type primary;
+       file "example.db.signed.malformed";
+};
+
+include "trusted.conf";
diff --git a/bin/tests/system/dnssec-malformed-dnskey/ns2/trusted.conf.j2 b/bin/tests/system/dnssec-malformed-dnskey/ns2/trusted.conf.j2
new file mode 100644 (file)
index 0000000..89adc17
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+
+trust-anchors {
+       example. static-key 257 3 14 "@ksk_public_key@";
+};
diff --git a/bin/tests/system/dnssec-malformed-dnskey/ns3/named.conf.j2 b/bin/tests/system/dnssec-malformed-dnskey/ns3/named.conf.j2
new file mode 100644 (file)
index 0000000..bdd1053
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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 {
+       query-source address 10.53.0.3;
+       notify-source 10.53.0.3;
+       transfer-source 10.53.0.3;
+       port @PORT@;
+       pid-file "named.pid";
+       listen-on { 10.53.0.3; };
+       listen-on-v6 { none; };
+       allow-transfer { any; };
+       dnssec-validation yes;
+
+       /* This is the default, but the test relies on it. */
+       max-validation-failures-per-fetch 1;
+};
+
+zone "example." {
+       type static-stub;
+       server-addresses { 10.53.0.2; };
+};
+
+include "trusted.conf";
diff --git a/bin/tests/system/dnssec-malformed-dnskey/ns3/trusted.conf.j2 b/bin/tests/system/dnssec-malformed-dnskey/ns3/trusted.conf.j2
new file mode 120000 (symlink)
index 0000000..e14af83
--- /dev/null
@@ -0,0 +1 @@
+../ns2/trusted.conf.j2
\ No newline at end of file
diff --git a/bin/tests/system/dnssec-malformed-dnskey/tests_malformed_dnskey.py b/bin/tests/system/dnssec-malformed-dnskey/tests_malformed_dnskey.py
new file mode 100644 (file)
index 0000000..8b871de
--- /dev/null
@@ -0,0 +1,182 @@
+# 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 base64
+from re import compile as Re
+
+import pytest
+
+pytest.importorskip("cryptography")
+pytest.importorskip(
+    "dns", minversion="2.7.0"
+)  # dns.dnssec.sign_zone(deterministic=...) needed
+
+from cryptography.hazmat.primitives.asymmetric import ec
+
+import dns
+import dns.dnssec
+import dns.zone
+from dns.rdtypes.dnskeybase import Flag
+
+import isctest
+
+
+def generate_key():
+    algorithm = dns.dnssec.Algorithm.ECDSAP384SHA384
+    ksk_private_key = ec.generate_private_key(ec.SECP384R1())
+    try:
+        ksk_dnskey = dns.dnssec.make_dnskey(
+            public_key=ksk_private_key.public_key(),
+            algorithm=algorithm,
+            flags=Flag.ZONE | Flag.SEP,
+        )
+    except ImportError as exc:
+        # if the cryptography package is too old, the make_dnskey() function
+        # will raise ImportError at runtime
+        pytest.skip(f"{exc}")
+    return ksk_private_key, ksk_dnskey
+
+
+MALFORMED_ZSK_KEY_TAG = 20071
+
+
+def create_malformed_rr(rr, n=0):
+    malformed_rr = dns.rdtypes.ANY.RRSIG.RRSIG(
+        rdclass=rr.rdclass,
+        rdtype=rr.rdtype,
+        type_covered=rr.type_covered,
+        algorithm=rr.algorithm,
+        labels=rr.labels,
+        original_ttl=rr.original_ttl - n,  # edit TTL so multiple RRSIGs can be added
+        expiration=rr.expiration,
+        inception=rr.inception,
+        key_tag=MALFORMED_ZSK_KEY_TAG,  # overwrite with the malformed ZSKs
+        signer=rr.signer,
+        signature=rr.signature,
+    )
+    return malformed_rr
+
+
+def bootstrap():
+    zone = dns.zone.from_file("ns2/example.db.in", origin="example.")
+    lifetime = 300
+
+    # geneate KSK, avoid key tag collision with ZSKs
+    while True:
+        ksk_private_key, ksk_dnskey = generate_key()
+        if dns.dnssec.key_id(ksk_dnskey) != MALFORMED_ZSK_KEY_TAG:
+            break
+    keys = [(ksk_private_key, ksk_dnskey)]
+
+    # sign the zone (including the malformed ZSKs) with KSK
+    with zone.writer() as txn:
+        dns.dnssec.sign_zone(
+            zone=zone,
+            txn=txn,
+            keys=keys,
+            lifetime=lifetime,
+            add_dnskey=True,
+            deterministic=False,  # for OpenSSL<3.2.0 compat
+        )
+
+    # force use of the malformed ZSKs for dnssec verification
+    # malformed-dnskey.example. has only one invalid RRSIG and is only signed
+    # with malformed ZSKs
+    malformed_rrset = zone.get_rdataset("malformed-dnskey", "RRSIG", "A")
+    rr = malformed_rrset.pop()
+    malformed_rrset.add(create_malformed_rr(rr))
+
+    # multiple-rrsigs.example. contains a lot of RRSIGS with the same invalid
+    # signature using malformed RRSIG, and one valid RRSIG
+    multiple_rrset = zone.get_rdataset("multiple-rrsigs", "RRSIG", "A")
+    rr = multiple_rrset.pop()
+    for i in range(99):
+        multiple_rrset.add(create_malformed_rr(rr, i))
+    multiple_rrset.add(rr)
+
+    zone.to_file("ns2/example.db.signed.malformed")
+
+    return {
+        "ksk_public_key": base64.b64encode(ksk_dnskey.key).decode(),
+    }
+
+
+def test_malformed_ecdsa(ns3):
+    log_validation_failed = Re(r"malformed-dnskey\.example/A\): validation failed")
+    log_openssl_failure = Re("EVP_PKEY_fromdata.*failed")
+    log_openssl_version = Re("linked to OpenSSL version: OpenSSL ([0-9]+)")
+
+    msg = isctest.query.create("malformed-dnskey.example", "A")
+
+    openssl_vers = ns3.log.grep(log_openssl_version)
+    if openssl_vers and int(openssl_vers[0].group(1)) >= 3:
+        # extra check for OpenSSL 3.0.0+
+        with ns3.watch_log_from_here() as watcher:
+            res = isctest.query.tcp(msg, "10.53.0.3")
+
+            # check the OpenSSL-specific log message appears just once
+            matches = watcher.wait_for_all(
+                [
+                    log_openssl_failure,
+                    log_validation_failed,
+                ]
+            )
+            assert len([m for m in matches if m.re == log_openssl_failure]) == 1
+    else:
+        res = isctest.query.tcp(msg, "10.53.0.3")
+
+    isctest.check.servfail(res)
+
+
+def test_multiple_rrsigs(ns3):
+    log_validation_failed = Re(r"multiple-rrsigs\.example/A\): validation failed")
+    log_openssl_failure = Re("EVP_PKEY_fromdata.*failed")
+    log_openssl_version = Re("linked to OpenSSL version: OpenSSL ([0-9]+)")
+
+    msg = isctest.query.create("multiple-rrsigs.example", "A")
+
+    # Check the order of returned RRSIGs from auth. Due to rrset-order none;
+    # this should remain constant for the remainder of the test.
+    # Ensure the first two RRSIGs are malformed, otherwise skip the test.
+    res = isctest.query.tcp(msg, "10.53.0.2")
+    rrsigs = res.get_rrset(
+        res.answer,
+        dns.name.from_text("multiple-rrsigs.example."),
+        dns.rdataclass.IN,
+        dns.rdatatype.RRSIG,
+        dns.rdatatype.A,
+    )
+    assert len(rrsigs) > 2
+    if (
+        rrsigs[0].key_tag != MALFORMED_ZSK_KEY_TAG
+        or rrsigs[1].key_tag != MALFORMED_ZSK_KEY_TAG
+    ):
+        pytest.skip("valid RRSIG listed first in response, re-run test")
+
+    openssl_vers = ns3.log.grep(log_openssl_version)
+    if openssl_vers and int(openssl_vers[0].group(1)) >= 3:
+        # extra check for OpenSSL 3.0.0+
+        with ns3.watch_log_from_here() as watcher:
+            res = isctest.query.tcp(msg, "10.53.0.3")
+
+            # check the OpenSSL-specific log message appears exactly twice:
+            # one failure is allowed by setting max-validation-failures-per-fetch 1;
+            matches = watcher.wait_for_all(
+                [
+                    log_openssl_failure,
+                    log_validation_failed,
+                ]
+            )
+            assert len([m for m in matches if m.re == log_openssl_failure]) == 2
+    else:
+        res = isctest.query.tcp(msg, "10.53.0.3")
+
+    isctest.check.servfail(res)