{% if zone.ns.name == ns.name %}
zone "@zone.name@" {
type @zone.type@;
+{% if zone.type == "static-stub" %}
+ server-addresses { @zone.ns.ip@; };
+{% else %}
file "@zone.filepath@";
+{% endif %}
};
{% endif %}
{% endfor %}
+++ /dev/null
-// validating resolver
-
-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; };
- recursion yes;
- dnssec-validation yes;
-};
-
-controls {
- inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
-};
-
-include "../../_common/rndc.key";
-
-zone "." {
- type hint;
- file "../../_common/root.hint";
-};
-
-zone "f217.test" {
- type static-stub;
- server-addresses { 10.53.0.1; };
-};
-
-trust-anchors {
- f217.test. static-key 257 3 13 "@ZONE_DNSKEY@";
-};
file bounds its scope as the server accrues unrelated domains.
"""
-from dnssec_py.ans4 import rrsig_labels_signer_ans, sibling_ds_ans
+from dnssec_py.ans4 import noqname_mismatch, rrsig_labels_signer_ans, sibling_ds_ans
from isctest.asyncserver import AsyncDnsServer
server = AsyncDnsServer()
server.install_response_handler(sibling_ds_ans.SiblingDsInjectionHandler())
+ if noqname_mismatch.PEM_PATH.exists():
+ server.install_response_handlers(noqname_mismatch.RuntimeCheckHandler())
if rrsig_labels_signer_ans.PEM_PATH.exists():
server.install_response_handler(rrsig_labels_signer_ans.AttackerZoneHandler())
from pathlib import Path
import base64
-import json
from cryptography.hazmat.primitives import serialization
+from dns.rdtypes.dnskeybase import Flag
import dns.dnssec
import dns.flags
import dns.message
import dns.name
+import dns.rcode
import dns.rdata
import dns.rdataclass
-import dns.rcode
import dns.rdatatype
import dns.rrset
-from isctest.asyncserver import (
- AsyncDnsServer,
- DnsResponseSend,
- QueryContext,
- ResponseHandler,
-)
+from isctest.asyncserver import DnsResponseSend, DomainHandler, QueryContext
TTL = 300
ZONE = "f217.test."
+PEM_PATH = Path(f"{ZONE}.pem")
CHILD = f"evil.{ZONE}"
ATTACK = f"www.{CHILD}"
NSEC_OWNER = f"00000000.{CHILD}"
def load_key() -> Key:
- path = Path(__file__).resolve().parent / "keys.json"
- with path.open(encoding="utf-8") as keys_file:
- raw_key = json.load(keys_file)[ZONE]
-
private_key = serialization.load_pem_private_key(
- raw_key["private_pem"].encode("ascii"),
- password=None,
+ PEM_PATH.read_bytes(), password=None
)
- dnskey = dns.rdata.from_text(
- dns.rdataclass.IN, dns.rdatatype.DNSKEY, raw_key["dnskey"]
+
+ dnskey = dns.dnssec.make_dnskey(
+ private_key.public_key(),
+ dns.dnssec.Algorithm.ECDSAP256SHA256,
+ flags=Flag.ZONE | Flag.SEP,
)
+
return Key(name(ZONE), private_key, dnskey)
-def rrset(
- owner: str, rdtype: dns.rdatatype.RdataType, *rdatas: str
-) -> dns.rrset.RRset:
+def rrset(owner: str, rdtype: dns.rdatatype.RdataType, *rdatas: str) -> dns.rrset.RRset:
return dns.rrset.from_text(owner, TTL, dns.rdataclass.IN, rdtype, *rdatas)
response.authority.append(nsec3)
-class RuntimeCheckHandler(ResponseHandler):
- def __init__(self, key: Key) -> None:
- self.key = key
+class RuntimeCheckHandler(DomainHandler):
+ """Serve attacker.rrsig-labels-signer. with crafted wildcard RRSIG."""
+
+ domains = [ZONE]
+
+ def __init__(self) -> None:
+ super().__init__()
+ self.key = load_key()
self.zone = name(ZONE)
self.child = name(CHILD)
self.attack = name(ATTACK)
add_signed(qctx.response.authority, soa_rrset(ZONE), self.key)
yield DnsResponseSend(qctx.response, authoritative=True)
-
-
-def main() -> None:
- server = AsyncDnsServer(default_aa=True)
- server.install_response_handlers(RuntimeCheckHandler(load_key()))
- server.run()
-
-
-if __name__ == "__main__":
- main()
import pytest
-DNSSEC_PY_MARK = pytest.mark.extra_artifacts(
- [
- "ans*/*.db",
- "ans*/*.run",
- "ans*/*.pem",
- "ns*/dsset-*",
- "ns*/trusted.conf",
- "ns*/zones/*.db",
- "ns*/zones/*.db.signed",
- ]
-)
+import isctest
+
+DNSSEC_PY_MARK = [
+ isctest.mark.with_ecdsa_deterministic,
+ pytest.mark.extra_artifacts(
+ [
+ "ans*/*.db",
+ "ans*/*.run",
+ "ans*/*.pem",
+ "ns*/dsset-*",
+ "ns*/trusted.conf",
+ "ns*/zones/*.db",
+ "ns*/zones/*.db.signed",
+ ]
+ ),
+]
#
# SPDX-License-Identifier: MPL-2.0
-from pathlib import Path
-
-import json
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec
import dns.name
import dns.rdataclass
import dns.rdatatype
-import pytest
+
+from dnssec_py.common import DNSSEC_PY_MARK
+from isctest.template import NS4, NS9, Nameserver, zones
+from isctest.zone import PythonZoneKey, Zone
import isctest
ATTACK = f"www.{CHILD}"
NSEC_OWNER = f"00000000.{CHILD}"
FORGED_A = "192.0.2.217"
-AUTH = "10.53.0.1"
-RESOLVER = "10.53.0.2"
+AUTH = "10.53.0.4"
+RESOLVER = "10.53.0.9"
-pytestmark = pytest.mark.extra_artifacts(
- [
- "ans1/ans.run",
- "ans1/keys.json",
- ]
-)
+pytestmark = DNSSEC_PY_MARK
def _make_key():
def bootstrap():
- keys = {ZONE: _make_key()}
- Path("ans1/keys.json").write_text(json.dumps(keys, indent=2), encoding="ascii")
- zone_dnskey = "".join(keys[ZONE]["dnskey"].split()[3:])
- return {"ZONE_DNSKEY": zone_dnskey}
+ # for a static stub zones, NS name is the stub and NS IP is the target
+ ans = Nameserver(NS9.name, NS9.num, NS4.ip, NS4.ip6)
+
+ zone = Zone(ZONE, ans, signed=False, zone_type="static-stub")
+ zonekey = PythonZoneKey.generate(zone)
+ zonekey.write_private_key_pem(f"ans4/{ZONE}.pem")
+ zone.keys = [zonekey]
+
+ ta = zonekey.into_ta("static-key")
+
+ return {
+ "zones": zones([zone]),
+ "trust_anchors": [ta],
+ }
def _query(server, qname, qtype):