resolved: don't accept expired RRSIGs
This commit is contained in:
parent
2b442ac878
commit
2a32632159
|
@ -209,7 +209,44 @@ static void md_add_uint32(gcry_md_hd_t md, uint32_t v) {
|
||||||
gcry_md_write(md, &v, sizeof(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];
|
uint8_t wire_format_name[DNS_WIRE_FOMAT_HOSTNAME_MAX];
|
||||||
size_t exponent_size, modulus_size, hash_size;
|
size_t exponent_size, modulus_size, hash_size;
|
||||||
void *exponent, *modulus, *hash;
|
void *exponent, *modulus, *hash;
|
||||||
|
@ -221,6 +258,8 @@ int dnssec_verify_rrset(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord *rr
|
||||||
assert(key);
|
assert(key);
|
||||||
assert(rrsig);
|
assert(rrsig);
|
||||||
assert(dnskey);
|
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",
|
/* Verifies the the RRSet matching the specified "key" in "a",
|
||||||
* using the signature "rrsig" and the key "dnskey". It's
|
* 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)
|
if (a->n_rrs > VERIFY_RRS_MAX)
|
||||||
return -E2BIG;
|
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 */
|
/* Collect all relevant RRs in a single array, so that we can look at the RRset */
|
||||||
list = newa(DnsResourceRecord *, a->n_rrs);
|
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));
|
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;
|
bool found_rrsig = false, found_dnskey = false;
|
||||||
DnsResourceRecord *rrsig;
|
DnsResourceRecord *rrsig;
|
||||||
int r;
|
int r;
|
||||||
|
@ -456,12 +506,18 @@ int dnssec_verify_rrset_search(DnsAnswer *a, DnsResourceKey *key, DnsAnswer *val
|
||||||
|
|
||||||
found_dnskey = true;
|
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
|
/* Yay, we found a matching RRSIG with a matching
|
||||||
* DNSKEY, awesome. Now let's verify all entries of
|
* DNSKEY, awesome. Now let's verify all entries of
|
||||||
* the RRSet against the RRSIG and DNSKEY
|
* the RRSet against the RRSIG and DNSKEY
|
||||||
* combination. */
|
* combination. */
|
||||||
|
|
||||||
r = dnssec_verify_rrset(a, key, rrsig, dnskey);
|
r = dnssec_verify_rrset(a, key, rrsig, dnskey, realtime);
|
||||||
if (r < 0 && r != EOPNOTSUPP)
|
if (r < 0 && r != EOPNOTSUPP)
|
||||||
return r;
|
return r;
|
||||||
if (r == DNSSEC_VERIFIED)
|
if (r == DNSSEC_VERIFIED)
|
||||||
|
|
|
@ -30,6 +30,7 @@ enum {
|
||||||
DNSSEC_INVALID,
|
DNSSEC_INVALID,
|
||||||
DNSSEC_NO_SIGNATURE,
|
DNSSEC_NO_SIGNATURE,
|
||||||
DNSSEC_MISSING_KEY,
|
DNSSEC_MISSING_KEY,
|
||||||
|
DNSSEC_SIGNATURE_EXPIRED,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,8 +39,8 @@ enum {
|
||||||
int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey);
|
int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey);
|
||||||
int dnssec_key_match_rrsig(DnsResourceKey *key, DnsResourceRecord *rrsig);
|
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(DnsAnswer *answer, DnsResourceKey *key, DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, usec_t realtime);
|
||||||
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);
|
||||||
|
|
||||||
int dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds);
|
int dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds);
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,8 @@ static void test_dnssec_verify_rrset(void) {
|
||||||
assert_se(answer);
|
assert_se(answer);
|
||||||
assert_se(dns_answer_add(answer, a, 0) >= 0);
|
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) {
|
static void test_dnssec_verify_dns_key(void) {
|
||||||
|
|
Loading…
Reference in New Issue