diff options
-rw-r--r-- | src/resolve/resolved-dns-dnssec.c | 62 | ||||
-rw-r--r-- | src/resolve/resolved-dns-dnssec.h | 5 | ||||
-rw-r--r-- | src/resolve/test-dnssec.c | 3 |
3 files changed, 64 insertions, 6 deletions
diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index ad28d8adef..6b54fdf786 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -209,7 +209,44 @@ static void md_add_uint32(gcry_md_hd_t md, uint32_t v) { gcry_md_write(md, &v, sizeof(v)); } -int dnssec_verify_rrset(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord *rrsig, DnsResourceRecord *dnskey) { +static int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) { + usec_t expiration, inception, skew; + + assert(rrsig); + assert(rrsig->key->type == DNS_TYPE_RRSIG); + + if (realtime == USEC_INFINITY) + realtime = now(CLOCK_REALTIME); + + expiration = rrsig->rrsig.expiration * USEC_PER_SEC; + inception = rrsig->rrsig.inception * USEC_PER_SEC; + + if (inception > expiration) + return -EINVAL; + + /* Permit a certain amount of clock skew of 10% of the valid time range */ + skew = (expiration - inception) / 10; + + if (inception < skew) + inception = 0; + else + inception -= skew; + + if (expiration + skew < expiration) + expiration = USEC_INFINITY; + else + expiration += skew; + + return realtime < inception || realtime > expiration; +} + +int dnssec_verify_rrset( + DnsAnswer *a, + DnsResourceKey *key, + DnsResourceRecord *rrsig, + DnsResourceRecord *dnskey, + usec_t realtime) { + uint8_t wire_format_name[DNS_WIRE_FOMAT_HOSTNAME_MAX]; size_t exponent_size, modulus_size, hash_size; void *exponent, *modulus, *hash; @@ -221,6 +258,8 @@ int dnssec_verify_rrset(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord *rr assert(key); assert(rrsig); assert(dnskey); + assert(rrsig->key->type == DNS_TYPE_RRSIG); + assert(dnskey->key->type == DNS_TYPE_DNSKEY); /* Verifies the the RRSet matching the specified "key" in "a", * using the signature "rrsig" and the key "dnskey". It's @@ -232,6 +271,12 @@ int dnssec_verify_rrset(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord *rr if (a->n_rrs > VERIFY_RRS_MAX) return -E2BIG; + r = dnssec_rrsig_expired(rrsig, realtime); + if (r < 0) + return r; + if (r > 0) + return DNSSEC_SIGNATURE_EXPIRED; + /* Collect all relevant RRs in a single array, so that we can look at the RRset */ list = newa(DnsResourceRecord *, a->n_rrs); @@ -422,7 +467,12 @@ int dnssec_key_match_rrsig(DnsResourceKey *key, DnsResourceRecord *rrsig) { return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key)); } -int dnssec_verify_rrset_search(DnsAnswer *a, DnsResourceKey *key, DnsAnswer *validated_dnskeys) { +int dnssec_verify_rrset_search( + DnsAnswer *a, + DnsResourceKey *key, + DnsAnswer *validated_dnskeys, + usec_t realtime) { + bool found_rrsig = false, found_dnskey = false; DnsResourceRecord *rrsig; int r; @@ -456,12 +506,18 @@ int dnssec_verify_rrset_search(DnsAnswer *a, DnsResourceKey *key, DnsAnswer *val found_dnskey = true; + /* Take the time here, if it isn't set yet, so + * that we do all validations with the same + * time. */ + if (realtime == USEC_INFINITY) + realtime = now(CLOCK_REALTIME); + /* Yay, we found a matching RRSIG with a matching * DNSKEY, awesome. Now let's verify all entries of * the RRSet against the RRSIG and DNSKEY * combination. */ - r = dnssec_verify_rrset(a, key, rrsig, dnskey); + r = dnssec_verify_rrset(a, key, rrsig, dnskey, realtime); if (r < 0 && r != EOPNOTSUPP) return r; if (r == DNSSEC_VERIFIED) diff --git a/src/resolve/resolved-dns-dnssec.h b/src/resolve/resolved-dns-dnssec.h index 56f0aec437..8f812bc1fb 100644 --- a/src/resolve/resolved-dns-dnssec.h +++ b/src/resolve/resolved-dns-dnssec.h @@ -30,6 +30,7 @@ enum { DNSSEC_INVALID, DNSSEC_NO_SIGNATURE, DNSSEC_MISSING_KEY, + DNSSEC_SIGNATURE_EXPIRED, }; @@ -38,8 +39,8 @@ enum { int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey); int dnssec_key_match_rrsig(DnsResourceKey *key, DnsResourceRecord *rrsig); -int dnssec_verify_rrset(DnsAnswer *answer, DnsResourceKey *key, DnsResourceRecord *rrsig, DnsResourceRecord *dnskey); -int dnssec_verify_rrset_search(DnsAnswer *a, DnsResourceKey *key, DnsAnswer *validated_dnskeys); +int dnssec_verify_rrset(DnsAnswer *answer, DnsResourceKey *key, DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, usec_t realtime); +int dnssec_verify_rrset_search(DnsAnswer *a, DnsResourceKey *key, DnsAnswer *validated_dnskeys, usec_t realtime); int dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds); diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c index 8cab025426..be9a3c7332 100644 --- a/src/resolve/test-dnssec.c +++ b/src/resolve/test-dnssec.c @@ -106,7 +106,8 @@ static void test_dnssec_verify_rrset(void) { assert_se(answer); assert_se(dns_answer_add(answer, a, 0) >= 0); - assert_se(dnssec_verify_rrset(answer, a->key, rrsig, dnskey) == DNSSEC_VERIFIED); + /* Validate the RR as it if was 2015-12-2 today */ + assert_se(dnssec_verify_rrset(answer, a->key, rrsig, dnskey, 1449092754*USEC_PER_SEC) == DNSSEC_VERIFIED); } static void test_dnssec_verify_dns_key(void) { |