From 588c53d0441ee33b617582429434b47492f51744 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 14 Jan 2016 17:25:06 +0100 Subject: [PATCH] resolved: some RR types may appear only or not at all in a zone apex Add extra checks when validating with RRSIGs. This follows recommendations from: http://www.george-barwood.pwp.blueyonder.co.uk/DnsServer/NotesOnDNSSSEC.htm --- src/resolve/dns-type.c | 11 ++++++++++ src/resolve/dns-type.h | 1 + src/resolve/resolved-dns-dnssec.c | 36 +++++++++++++++++++++++++------ 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/resolve/dns-type.c b/src/resolve/dns-type.c index 47a37fa0a7..058d14009a 100644 --- a/src/resolve/dns-type.c +++ b/src/resolve/dns-type.c @@ -135,6 +135,17 @@ bool dns_type_may_wildcard(uint16_t type) { DNS_TYPE_DNAME); } +bool dns_type_apex_only(uint16_t type) { + + /* Returns true for all RR types that may only appear signed in a zone apex */ + + return IN_SET(type, + DNS_TYPE_SOA, + DNS_TYPE_NS, /* this one can appear elsewhere, too, but not signed */ + DNS_TYPE_DNSKEY, + DNS_TYPE_NSEC3PARAM); +} + bool dns_type_is_dnssec(uint16_t type) { return IN_SET(type, DNS_TYPE_DS, diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index 747bc854e1..78ff71b06e 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -132,6 +132,7 @@ bool dns_type_may_redirect(uint16_t type); bool dns_type_is_dnssec(uint16_t type); bool dns_type_is_obsolete(uint16_t type); bool dns_type_may_wildcard(uint16_t type); +bool dns_type_apex_only(uint16_t type); bool dns_class_is_pseudo(uint16_t class); bool dns_class_is_valid_rr(uint16_t class); diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index afff979b5a..4aade4829e 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -508,14 +508,14 @@ int dnssec_verify_rrset( DnssecResult *result) { uint8_t wire_format_name[DNS_WIRE_FOMAT_HOSTNAME_MAX]; - size_t hash_size; - void *hash; DnsResourceRecord **list, *rr; + const char *source, *name; gcry_md_hd_t md = NULL; int r, md_algorithm; size_t k, n = 0; + size_t hash_size; + void *hash; bool wildcard; - const char *source; assert(key); assert(rrsig); @@ -544,8 +544,32 @@ int dnssec_verify_rrset( return 0; } + name = DNS_RESOURCE_KEY_NAME(key); + + /* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */ + if (dns_type_apex_only(rrsig->rrsig.type_covered)) { + r = dns_name_equal(rrsig->rrsig.signer, name); + if (r < 0) + return r; + if (r == 0) { + *result = DNSSEC_INVALID; + return 0; + } + } + + /* OTOH DS RRs may not appear in the zone apex, but are valid everywhere else. */ + if (rrsig->rrsig.type_covered == DNS_TYPE_DS) { + r = dns_name_equal(rrsig->rrsig.signer, name); + if (r < 0) + return r; + if (r > 0) { + *result = DNSSEC_INVALID; + return 0; + } + } + /* Determine the "Source of Synthesis" and whether this is a wildcard RRSIG */ - r = dns_name_suffix(DNS_RESOURCE_KEY_NAME(key), rrsig->rrsig.labels, &source); + r = dns_name_suffix(name, rrsig->rrsig.labels, &source); if (r < 0) return r; if (r > 0 && !dns_type_may_wildcard(rrsig->rrsig.type_covered)) { @@ -556,11 +580,11 @@ int dnssec_verify_rrset( if (r == 1) { /* If we stripped a single label, then let's see if that maybe was "*". If so, we are not really * synthesized from a wildcard, we are the wildcard itself. Treat that like a normal name. */ - r = dns_name_startswith(DNS_RESOURCE_KEY_NAME(key), "*"); + r = dns_name_startswith(name, "*"); if (r < 0) return r; if (r > 0) - source = DNS_RESOURCE_KEY_NAME(key); + source = name; wildcard = r == 0; } else