Home | History | Annotate | Line # | Download | only in nsec3
      1 # Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      2 #
      3 # SPDX-License-Identifier: MPL-2.0
      4 #
      5 # This Source Code Form is subject to the terms of the Mozilla Public
      6 # License, v. 2.0.  If a copy of the MPL was not distributed with this
      7 # file, you can obtain one at https://mozilla.org/MPL/2.0/.
      8 #
      9 # See the COPYRIGHT file distributed with this work for additional
     10 # information regarding copyright ownership.
     11 
     12 # pylint: disable=redefined-outer-name,unused-import
     13 
     14 import os
     15 import shutil
     16 
     17 from datetime import timedelta
     18 
     19 import dns.update
     20 import pytest
     21 
     22 pytest.importorskip("dns", minversion="2.0.0")
     23 import isctest
     24 import isctest.mark
     25 from isctest.vars.algorithms import RSASHA256
     26 from nsec3.common import (
     27     pytestmark,
     28     check_auth_nsec3,
     29     check_nsec3param,
     30 )
     31 
     32 DNSKEY_TTL = int(timedelta(hours=1).total_seconds())
     33 ZSK_LIFETIME = int(timedelta(days=90).total_seconds())
     34 
     35 # include the following zones when rendering named configs
     36 ZONES = {
     37     "retransfer.kasp",
     38 }
     39 
     40 
     41 def bootstrap():
     42     return {
     43         "zones": ZONES,
     44     }
     45 
     46 
     47 def perform_nsec3_tests(server, params):
     48     # Get test parameters.
     49     zone = params["zone"]
     50     fqdn = f"{zone}."
     51     policy = params["policy"]
     52     keydir = server.identifier
     53     minimum = params.get("soa-minimum", 3600)
     54     expected = isctest.kasp.policy_to_properties(
     55         ttl=DNSKEY_TTL, keys=params["key-properties"]
     56     )
     57 
     58     iterations = 0
     59     optout = 0
     60     saltlen = 0
     61 
     62     match = f"{fqdn} {minimum} IN NSEC3PARAM 1 0 {iterations}"
     63 
     64     # Test case.
     65     isctest.log.info(f"check nsec3 case zone {zone} policy {policy}")
     66 
     67     # First make sure the zone is properly signed.
     68     isctest.kasp.wait_keymgr_done(server, zone)
     69 
     70     keys = isctest.kasp.keydir_to_keylist(zone, keydir)
     71     ksks = [k for k in keys if k.is_ksk()]
     72     zsks = [k for k in keys if k.is_zsk()]
     73     isctest.kasp.check_keys(zone, keys, expected)
     74     isctest.kasp.check_dnssec_verify(server, zone)
     75     isctest.kasp.check_apex(server, zone, ksks, zsks)
     76 
     77     query = isctest.query.create(fqdn, dns.rdatatype.NSEC3PARAM)
     78     response = isctest.query.tcp(query, server.ip, server.ports.dns, timeout=3)
     79     assert response.rcode() == dns.rcode.NOERROR
     80 
     81     salt = check_nsec3param(response, match, saltlen)
     82 
     83     query = isctest.query.create(f"nosuchname.{fqdn}", dns.rdatatype.A)
     84     response = isctest.query.tcp(query, server.ip, server.ports.dns, timeout=3)
     85     assert response.rcode() == dns.rcode.NXDOMAIN
     86     check_auth_nsec3(response, iterations, optout, salt)
     87 
     88     return salt
     89 
     90 
     91 def test_nsec3_retransfer(servers, templates):
     92     ns2 = servers["ns2"]
     93     ns3 = servers["ns3"]
     94 
     95     params = {
     96         "zone": "retransfer.kasp",
     97         "policy": "nsec3rsa256",
     98         "key-properties": [
     99             f"ksk 0 {RSASHA256.number} 2048 goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden",
    100             f"zsk {ZSK_LIFETIME} {RSASHA256.number} 2048 goal:omnipresent dnskey:rumoured zrrsig:rumoured",
    101         ],
    102     }
    103 
    104     zone = params["zone"]
    105     salt = perform_nsec3_tests(ns3, params)
    106 
    107     # Stop primary.
    108     ns2.stop()
    109 
    110     # Update the zone.
    111     serial = 10
    112     templates.render(f"{ns2.identifier}/{zone}.db", {"serial": serial})
    113 
    114     with ns2.watch_log_from_here() as watcher:
    115         ns2.start(["--noclean", "--restart", "--port", os.environ["PORT"]])
    116         watcher.wait_for_line("all zones loaded")
    117 
    118     # Test NSEC3 and NSEC3PARAM is the same after retransfer.
    119     isctest.log.info(f"check zone {zone} after retransfer has salt {salt}")
    120     prevsalt = salt
    121 
    122     # Retransfer zone, NSEC3 should stay the same.
    123     with ns3.watch_log_from_here() as watcher:
    124         ns3.rndc(f"retransfer {zone}")
    125         # When sending notifies, the zone should be up to date.
    126         watcher.wait_for_line(f"zone {zone}/IN (signed): sending notify to 10.53.0.4")
    127 
    128     salt = perform_nsec3_tests(ns3, params)
    129     assert prevsalt == salt
    130