Commit 6d4fab1e authored by Joshua Tauberer's avatar Joshua Tauberer

whats_next: offer DNSSEC DS parameters rather than the full record and in...

whats_next: offer DNSSEC DS parameters rather than the full record and in validation allow for other digests than the one we suggest using

fixes #120 (hopefully), in which Gandi generates a SHA1 digest but we were only checking against a SHA256 digest

Also see http://discourse.mailinabox.email/t/how-to-set-ds-record-for-gandi-net/24/1 in which a user asks about the DS parameters that Gandi asks for.
parent 30178ef0
......@@ -93,7 +93,7 @@ def do_dns_update(env, force=False):
# Thus we only sign a zone if write_nsd_zone returned True
# indicating the zone changed, and thus it got a new serial number.
# write_nsd_zone is smart enough to check if a zone's signature
# is nearing experiation and if so it'll bump the serial number
# is nearing expiration and if so it'll bump the serial number
# and return True so we get a chance to re-sign it.
sign_zone(domain, zonefile, env)
......@@ -478,12 +478,17 @@ def sign_zone(domain, zonefile, env):
# zone being signed, so we can't use the .ds files generated when we created the keys.
# The DS record points to the KSK only. Write this next to the zone file so we can
# get it later to give to the user with instructions on what to do with it.
#
# We want to be able to validate DS records too, but multiple forms may be valid depending
# on the digest type. So we'll write all (both) valid records. Only one DS record should
# actually be deployed. Preferebly the first.
with open("/etc/nsd/zones/" + zonefile + ".ds", "w") as f:
for digest_type in ('2', '1'):
rr_ds = shell('check_output', ["/usr/bin/ldns-key2ds",
"-n", # output to stdout
"-2", # SHA256
"-" + digest_type, # 1=SHA1, 2=SHA256
dnssec_keys["KSK"] + ".key"
])
with open("/etc/nsd/zones/" + zonefile + ".ds", "w") as f:
f.write(rr_ds)
# Remove our temporary file.
......
......@@ -14,7 +14,7 @@ from dns_update import get_dns_zones
from web_update import get_web_domains, get_domain_ssl_files
from mailconfig import get_mail_domains, get_mail_aliases
from utils import shell, sort_domains
from utils import shell, sort_domains, load_env_vars_from_file
def run_checks(env):
run_system_checks(env)
......@@ -125,25 +125,47 @@ def check_dns_zone(domain, env, dns_zonefiles):
control panel to set the nameservers to %s."""
% (existing_ns, correct_ns) )
# See if the domain has a DS record set.
# See if the domain has a DS record set at the registrar. The DS record may have
# several forms. We have to be prepared to check for any valid record. We've
# pre-generated all of the valid digests --- read them in.
ds_correct = open('/etc/nsd/zones/' + dns_zonefiles[domain] + '.ds').read().strip().split("\n")
digests = { }
for rr_ds in ds_correct:
ds_keytag, ds_alg, ds_digalg, ds_digest = rr_ds.split("\t")[4].split(" ")
digests[ds_digalg] = ds_digest
# Some registrars may want the public key so they can compute the digest. The DS
# record that we suggest using is for the KSK (and that's how the DS records were generated).
dnssec_keys = load_env_vars_from_file(os.path.join(env['STORAGE_ROOT'], 'dns/dnssec/keys.conf'))
dnsssec_pubkey = open(os.path.join(env['STORAGE_ROOT'], 'dns/dnssec/' + dnssec_keys['KSK'] + '.key')).read().split("\t")[3].split(" ")[3]
# Query public DNS for the DS record at the registrar.
ds = query_dns(domain, "DS", nxdomain=None)
ds_correct = open('/etc/nsd/zones/' + dns_zonefiles[domain] + '.ds').read().strip()
ds_expected = re.sub(r"\S+\.\s+3600\s+IN\s+DS\s*", "", ds_correct)
if ds == ds_expected:
ds_looks_valid = ds and len(ds.split(" ")) == 4
if ds_looks_valid: ds = ds.split(" ")
if ds_looks_valid and ds[0] == ds_keytag and ds[1] == '7' and ds[3] == digests.get(ds[2]):
print_ok("DNS 'DS' record is set correctly at registrar.")
elif ds == None:
else:
if ds == None:
print_error("""This domain's DNS DS record is not set. The DS record is optional. The DS record activates DNSSEC.
To set a DS record, you must follow the instructions provided by your domain name registrar and provide to them this information:""")
print("")
print(" " + ds_correct)
print("")
else:
print_error("""This domain's DNS DS record is incorrect. The chain of trust is broken between the public DNS system
and this machine's DNS server. It may take several hours for public DNS to update after a change. If you did not recently
make a change, you must resolve this immediately by following the instructions provided by your domain name registrar and
provide to them this information:""")
print("")
print(" " + ds_correct)
print()
print("\tKey Tag: " + ds_keytag + ("" if not ds_looks_valid or ds[0] == ds_keytag else " (Got '%s')" % ds[0]))
print("\tKey Flags: KSK")
print("\tAlgorithm: 7 / RSASHA1-NSEC3-SHA1" + ("" if not ds_looks_valid or ds[1] == '7' else " (Got '%s')" % ds[1]))
print("\tDigest Type: 2 / SHA-256")
print("\tDigest: " + digests['2'])
if ds_looks_valid and ds[3] != digests.get(ds[2]):
print("\t(Got digest type %s and digest %s which do not match.)" % (ds[2], ds[3]))
print("\tPublic Key: " + dnsssec_pubkey)
print()
print("\tBulk/Record Format:")
print("\t" + ds_correct[0])
print("")
def check_mail_domain(domain, env):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment