]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: don't accept expired RRSIGs
authorLennart Poettering <lennart@poettering.net>
Wed, 2 Dec 2015 21:47:28 +0000 (22:47 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 2 Dec 2015 23:26:58 +0000 (00:26 +0100)
src/resolve/resolved-dns-dnssec.c
src/resolve/resolved-dns-dnssec.h
src/resolve/test-dnssec.c

index ad28d8adef6a2c180dcdf26ddbf989321ff71d51..6b54fdf78619d697c5f33807af1f8ccb286ed38e 100644 (file)
@@ -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)
index 56f0aec43765331aa24ad3e51fd7ed14a3150178..8f812bc1fbbc184c7fc8bac8138f19921e102dac 100644 (file)
@@ -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);
 
index 8cab025426332ffb3008a1f23c9be8c89bec0d5d..be9a3c73327dca91506ee0fb04cbc8172be0a88e 100644 (file)
@@ -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) {