mirror of
https://github.com/systemd/systemd
synced 2024-10-14 12:04:49 +00:00
Merge pull request #2232 from poettering/dnssec8
Eigth DNSSEC patch set
This commit is contained in:
commit
7fdfc8634e
|
@ -408,13 +408,11 @@ static int resolve_record(sd_bus *bus, const char *name) {
|
|||
|
||||
r = dns_packet_read_rr(p, &rr, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse RR.");
|
||||
return log_error_errno(r, "Failed to parse RR: %m");
|
||||
|
||||
s = dns_resource_record_to_string(rr);
|
||||
if (!s) {
|
||||
log_error("Failed to format RR.");
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!s)
|
||||
return log_oom();
|
||||
|
||||
ifname[0] = 0;
|
||||
if (ifindex > 0 && !if_indextoname(ifindex, ifname))
|
||||
|
|
|
@ -272,6 +272,42 @@ static DnsCacheItem* dns_cache_get(DnsCache *c, DnsResourceRecord *rr) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static usec_t calculate_until(DnsResourceRecord *rr, usec_t timestamp, bool use_soa_minimum) {
|
||||
uint32_t ttl;
|
||||
usec_t u;
|
||||
|
||||
assert(rr);
|
||||
|
||||
ttl = rr->ttl;
|
||||
if (rr->key->type == DNS_TYPE_SOA && use_soa_minimum) {
|
||||
/* If this is a SOA RR, and it is requested, clamp to
|
||||
* the SOA's minimum field. This is used when we do
|
||||
* negative caching, to determine the TTL for the
|
||||
* negative caching entry. See RFC 2308, Section
|
||||
* 5. */
|
||||
|
||||
if (ttl > rr->soa.minimum)
|
||||
ttl = rr->soa.minimum;
|
||||
}
|
||||
|
||||
u = ttl * USEC_PER_SEC;
|
||||
if (u > CACHE_TTL_MAX_USEC)
|
||||
u = CACHE_TTL_MAX_USEC;
|
||||
|
||||
if (rr->expiry != USEC_INFINITY) {
|
||||
usec_t left;
|
||||
|
||||
/* Make use of the DNSSEC RRSIG expiry info, if we
|
||||
* have it */
|
||||
|
||||
left = LESS_BY(rr->expiry, now(CLOCK_REALTIME));
|
||||
if (u > left)
|
||||
u = left;
|
||||
}
|
||||
|
||||
return timestamp + u;
|
||||
}
|
||||
|
||||
static void dns_cache_item_update_positive(
|
||||
DnsCache *c,
|
||||
DnsCacheItem *i,
|
||||
|
@ -302,7 +338,7 @@ static void dns_cache_item_update_positive(
|
|||
dns_resource_key_unref(i->key);
|
||||
i->key = dns_resource_key_ref(rr->key);
|
||||
|
||||
i->until = timestamp + MIN(rr->ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC);
|
||||
i->until = calculate_until(rr, timestamp, false);
|
||||
i->authenticated = authenticated;
|
||||
i->shared_owner = shared_owner;
|
||||
|
||||
|
@ -383,7 +419,7 @@ static int dns_cache_put_positive(
|
|||
i->type = DNS_CACHE_POSITIVE;
|
||||
i->key = dns_resource_key_ref(rr->key);
|
||||
i->rr = dns_resource_record_ref(rr);
|
||||
i->until = timestamp + MIN(i->rr->ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC);
|
||||
i->until = calculate_until(rr, timestamp, false);
|
||||
i->authenticated = authenticated;
|
||||
i->shared_owner = shared_owner;
|
||||
i->owner_family = owner_family;
|
||||
|
@ -412,7 +448,7 @@ static int dns_cache_put_negative(
|
|||
int rcode,
|
||||
bool authenticated,
|
||||
usec_t timestamp,
|
||||
uint32_t soa_ttl,
|
||||
DnsResourceRecord *soa,
|
||||
int owner_family,
|
||||
const union in_addr_union *owner_address) {
|
||||
|
||||
|
@ -422,6 +458,7 @@ static int dns_cache_put_negative(
|
|||
|
||||
assert(c);
|
||||
assert(key);
|
||||
assert(soa);
|
||||
assert(owner_address);
|
||||
|
||||
/* Never cache pseudo RR keys. DNS_TYPE_ANY is particularly
|
||||
|
@ -432,7 +469,7 @@ static int dns_cache_put_negative(
|
|||
if (dns_type_is_pseudo(key->type))
|
||||
return 0;
|
||||
|
||||
if (soa_ttl <= 0) {
|
||||
if (soa->soa.minimum <= 0 || soa->ttl <= 0) {
|
||||
if (log_get_max_level() >= LOG_DEBUG) {
|
||||
r = dns_resource_key_to_string(key, &key_str);
|
||||
if (r < 0)
|
||||
|
@ -458,7 +495,7 @@ static int dns_cache_put_negative(
|
|||
return -ENOMEM;
|
||||
|
||||
i->type = rcode == DNS_RCODE_SUCCESS ? DNS_CACHE_NODATA : DNS_CACHE_NXDOMAIN;
|
||||
i->until = timestamp + MIN(soa_ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC);
|
||||
i->until = calculate_until(soa, timestamp, true);
|
||||
i->authenticated = authenticated;
|
||||
i->owner_family = owner_family;
|
||||
i->owner_address = *owner_address;
|
||||
|
@ -632,7 +669,7 @@ int dns_cache_put(
|
|||
rcode,
|
||||
authenticated,
|
||||
timestamp,
|
||||
MIN(soa->soa.minimum, soa->ttl),
|
||||
soa,
|
||||
owner_family, owner_address);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
|
|
@ -40,10 +40,9 @@
|
|||
* - multi-label zone compatibility
|
||||
* - cname/dname compatibility
|
||||
* - per-interface DNSSEC setting
|
||||
* - fix TTL for cache entries to match RRSIG TTL
|
||||
* - nxdomain on qname
|
||||
* - retry on failed validation?
|
||||
* - DSA support
|
||||
* - EC support?
|
||||
* - DSA support?
|
||||
*
|
||||
* */
|
||||
|
||||
|
@ -77,14 +76,6 @@ static void initialize_libgcrypt(void) {
|
|||
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
|
||||
}
|
||||
|
||||
static bool dnssec_algorithm_supported(int algorithm) {
|
||||
return IN_SET(algorithm,
|
||||
DNSSEC_ALGORITHM_RSASHA1,
|
||||
DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1,
|
||||
DNSSEC_ALGORITHM_RSASHA256,
|
||||
DNSSEC_ALGORITHM_RSASHA512);
|
||||
}
|
||||
|
||||
uint16_t dnssec_keytag(DnsResourceRecord *dnskey) {
|
||||
const uint8_t *p;
|
||||
uint32_t sum;
|
||||
|
@ -136,7 +127,7 @@ static int rr_compare(const void *a, const void *b) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dnssec_rsa_verify(
|
||||
static int dnssec_rsa_verify_raw(
|
||||
const char *hash_algorithm,
|
||||
const void *signature, size_t signature_size,
|
||||
const void *data, size_t data_size,
|
||||
|
@ -226,6 +217,196 @@ finish:
|
|||
return r;
|
||||
}
|
||||
|
||||
static int dnssec_rsa_verify(
|
||||
const char *hash_algorithm,
|
||||
const void *hash, size_t hash_size,
|
||||
DnsResourceRecord *rrsig,
|
||||
DnsResourceRecord *dnskey) {
|
||||
|
||||
size_t exponent_size, modulus_size;
|
||||
void *exponent, *modulus;
|
||||
|
||||
assert(hash_algorithm);
|
||||
assert(hash);
|
||||
assert(hash_size > 0);
|
||||
assert(rrsig);
|
||||
assert(dnskey);
|
||||
|
||||
if (*(uint8_t*) dnskey->dnskey.key == 0) {
|
||||
/* exponent is > 255 bytes long */
|
||||
|
||||
exponent = (uint8_t*) dnskey->dnskey.key + 3;
|
||||
exponent_size =
|
||||
((size_t) (((uint8_t*) dnskey->dnskey.key)[0]) << 8) |
|
||||
((size_t) ((uint8_t*) dnskey->dnskey.key)[1]);
|
||||
|
||||
if (exponent_size < 256)
|
||||
return -EINVAL;
|
||||
|
||||
if (3 + exponent_size >= dnskey->dnskey.key_size)
|
||||
return -EINVAL;
|
||||
|
||||
modulus = (uint8_t*) dnskey->dnskey.key + 3 + exponent_size;
|
||||
modulus_size = dnskey->dnskey.key_size - 3 - exponent_size;
|
||||
|
||||
} else {
|
||||
/* exponent is <= 255 bytes long */
|
||||
|
||||
exponent = (uint8_t*) dnskey->dnskey.key + 1;
|
||||
exponent_size = (size_t) ((uint8_t*) dnskey->dnskey.key)[0];
|
||||
|
||||
if (exponent_size <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (1 + exponent_size >= dnskey->dnskey.key_size)
|
||||
return -EINVAL;
|
||||
|
||||
modulus = (uint8_t*) dnskey->dnskey.key + 1 + exponent_size;
|
||||
modulus_size = dnskey->dnskey.key_size - 1 - exponent_size;
|
||||
}
|
||||
|
||||
return dnssec_rsa_verify_raw(
|
||||
hash_algorithm,
|
||||
rrsig->rrsig.signature, rrsig->rrsig.signature_size,
|
||||
hash, hash_size,
|
||||
exponent, exponent_size,
|
||||
modulus, modulus_size);
|
||||
}
|
||||
|
||||
static int dnssec_ecdsa_verify_raw(
|
||||
const char *hash_algorithm,
|
||||
const char *curve,
|
||||
const void *signature_r, size_t signature_r_size,
|
||||
const void *signature_s, size_t signature_s_size,
|
||||
const void *data, size_t data_size,
|
||||
const void *key, size_t key_size) {
|
||||
|
||||
gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
|
||||
gcry_mpi_t q = NULL, r = NULL, s = NULL;
|
||||
gcry_error_t ge;
|
||||
int k;
|
||||
|
||||
assert(hash_algorithm);
|
||||
|
||||
ge = gcry_mpi_scan(&r, GCRYMPI_FMT_USG, signature_r, signature_r_size, NULL);
|
||||
if (ge != 0) {
|
||||
k = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature_s, signature_s_size, NULL);
|
||||
if (ge != 0) {
|
||||
k = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ge = gcry_mpi_scan(&q, GCRYMPI_FMT_USG, key, key_size, NULL);
|
||||
if (ge != 0) {
|
||||
k = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ge = gcry_sexp_build(&signature_sexp,
|
||||
NULL,
|
||||
"(sig-val (ecdsa (r %m) (s %m)))",
|
||||
r,
|
||||
s);
|
||||
if (ge != 0) {
|
||||
k = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ge = gcry_sexp_build(&data_sexp,
|
||||
NULL,
|
||||
"(data (flags rfc6979) (hash %s %b))",
|
||||
hash_algorithm,
|
||||
(int) data_size,
|
||||
data);
|
||||
if (ge != 0) {
|
||||
k = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ge = gcry_sexp_build(&public_key_sexp,
|
||||
NULL,
|
||||
"(public-key (ecc (curve %s) (q %m)))",
|
||||
curve,
|
||||
q);
|
||||
if (ge != 0) {
|
||||
k = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
|
||||
if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
|
||||
k = 0;
|
||||
else if (ge != 0) {
|
||||
log_debug("ECDSA signature check failed: %s", gpg_strerror(ge));
|
||||
k = -EIO;
|
||||
} else
|
||||
k = 1;
|
||||
finish:
|
||||
if (r)
|
||||
gcry_mpi_release(r);
|
||||
if (s)
|
||||
gcry_mpi_release(s);
|
||||
if (q)
|
||||
gcry_mpi_release(q);
|
||||
|
||||
if (public_key_sexp)
|
||||
gcry_sexp_release(public_key_sexp);
|
||||
if (signature_sexp)
|
||||
gcry_sexp_release(signature_sexp);
|
||||
if (data_sexp)
|
||||
gcry_sexp_release(data_sexp);
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
static int dnssec_ecdsa_verify(
|
||||
const char *hash_algorithm,
|
||||
int algorithm,
|
||||
const void *hash, size_t hash_size,
|
||||
DnsResourceRecord *rrsig,
|
||||
DnsResourceRecord *dnskey) {
|
||||
|
||||
const char *curve;
|
||||
size_t key_size;
|
||||
uint8_t *q;
|
||||
|
||||
assert(hash);
|
||||
assert(hash_size);
|
||||
assert(rrsig);
|
||||
assert(dnskey);
|
||||
|
||||
if (algorithm == DNSSEC_ALGORITHM_ECDSAP256SHA256) {
|
||||
key_size = 32;
|
||||
curve = "NIST P-256";
|
||||
} else if (algorithm == DNSSEC_ALGORITHM_ECDSAP384SHA384) {
|
||||
key_size = 48;
|
||||
curve = "NIST P-384";
|
||||
} else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (dnskey->dnskey.key_size != key_size * 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (rrsig->rrsig.signature_size != key_size * 2)
|
||||
return -EINVAL;
|
||||
|
||||
q = alloca(key_size*2 + 1);
|
||||
q[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
|
||||
memcpy(q+1, dnskey->dnskey.key, key_size*2);
|
||||
|
||||
return dnssec_ecdsa_verify_raw(
|
||||
hash_algorithm,
|
||||
curve,
|
||||
rrsig->rrsig.signature, key_size,
|
||||
(uint8_t*) rrsig->rrsig.signature + key_size, key_size,
|
||||
hash, hash_size,
|
||||
q, key_size*2+1);
|
||||
}
|
||||
|
||||
static void md_add_uint8(gcry_md_hd_t md, uint8_t v) {
|
||||
gcry_md_write(md, &v, sizeof(v));
|
||||
}
|
||||
|
@ -275,6 +456,31 @@ static int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) {
|
|||
return realtime < inception || realtime > expiration;
|
||||
}
|
||||
|
||||
static int algorithm_to_gcrypt_md(uint8_t algorithm) {
|
||||
|
||||
/* Translates a DNSSEC signature algorithm into a gcrypt digest identifier */
|
||||
|
||||
switch (algorithm) {
|
||||
|
||||
case DNSSEC_ALGORITHM_RSASHA1:
|
||||
case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
|
||||
return GCRY_MD_SHA1;
|
||||
|
||||
case DNSSEC_ALGORITHM_RSASHA256:
|
||||
case DNSSEC_ALGORITHM_ECDSAP256SHA256:
|
||||
return GCRY_MD_SHA256;
|
||||
|
||||
case DNSSEC_ALGORITHM_ECDSAP384SHA384:
|
||||
return GCRY_MD_SHA384;
|
||||
|
||||
case DNSSEC_ALGORITHM_RSASHA512:
|
||||
return GCRY_MD_SHA512;
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
int dnssec_verify_rrset(
|
||||
DnsAnswer *a,
|
||||
DnsResourceKey *key,
|
||||
|
@ -284,12 +490,12 @@ int dnssec_verify_rrset(
|
|||
DnssecResult *result) {
|
||||
|
||||
uint8_t wire_format_name[DNS_WIRE_FOMAT_HOSTNAME_MAX];
|
||||
size_t exponent_size, modulus_size, hash_size;
|
||||
void *exponent, *modulus, *hash;
|
||||
size_t hash_size;
|
||||
void *hash;
|
||||
DnsResourceRecord **list, *rr;
|
||||
gcry_md_hd_t md = NULL;
|
||||
int r, md_algorithm;
|
||||
size_t k, n = 0;
|
||||
int r;
|
||||
|
||||
assert(key);
|
||||
assert(rrsig);
|
||||
|
@ -302,10 +508,13 @@ int dnssec_verify_rrset(
|
|||
* using the signature "rrsig" and the key "dnskey". It's
|
||||
* assumed the RRSIG and DNSKEY match. */
|
||||
|
||||
if (!dnssec_algorithm_supported(rrsig->rrsig.algorithm)) {
|
||||
md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm);
|
||||
if (md_algorithm == -EOPNOTSUPP) {
|
||||
*result = DNSSEC_UNSUPPORTED_ALGORITHM;
|
||||
return 0;
|
||||
}
|
||||
if (md_algorithm < 0)
|
||||
return md_algorithm;
|
||||
|
||||
if (a->n_rrs > VERIFY_RRS_MAX)
|
||||
return -E2BIG;
|
||||
|
@ -342,31 +551,13 @@ int dnssec_verify_rrset(
|
|||
/* Bring the RRs into canonical order */
|
||||
qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare);
|
||||
|
||||
/* OK, the RRs are now in canonical order. Let's calculate the digest */
|
||||
initialize_libgcrypt();
|
||||
|
||||
/* OK, the RRs are now in canonical order. Let's calculate the digest */
|
||||
switch (rrsig->rrsig.algorithm) {
|
||||
|
||||
case DNSSEC_ALGORITHM_RSASHA1:
|
||||
case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
|
||||
gcry_md_open(&md, GCRY_MD_SHA1, 0);
|
||||
hash_size = 20;
|
||||
break;
|
||||
|
||||
case DNSSEC_ALGORITHM_RSASHA256:
|
||||
gcry_md_open(&md, GCRY_MD_SHA256, 0);
|
||||
hash_size = 32;
|
||||
break;
|
||||
|
||||
case DNSSEC_ALGORITHM_RSASHA512:
|
||||
gcry_md_open(&md, GCRY_MD_SHA512, 0);
|
||||
hash_size = 64;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Unknown digest");
|
||||
}
|
||||
hash_size = gcry_md_get_algo_dlen(md_algorithm);
|
||||
assert(hash_size > 0);
|
||||
|
||||
gcry_md_open(&md, md_algorithm, 0);
|
||||
if (!md)
|
||||
return -EIO;
|
||||
|
||||
|
@ -417,53 +608,30 @@ int dnssec_verify_rrset(
|
|||
goto finish;
|
||||
}
|
||||
|
||||
if (*(uint8_t*) dnskey->dnskey.key == 0) {
|
||||
/* exponent is > 255 bytes long */
|
||||
switch (rrsig->rrsig.algorithm) {
|
||||
|
||||
exponent = (uint8_t*) dnskey->dnskey.key + 3;
|
||||
exponent_size =
|
||||
((size_t) (((uint8_t*) dnskey->dnskey.key)[0]) << 8) |
|
||||
((size_t) ((uint8_t*) dnskey->dnskey.key)[1]);
|
||||
case DNSSEC_ALGORITHM_RSASHA1:
|
||||
case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
|
||||
case DNSSEC_ALGORITHM_RSASHA256:
|
||||
case DNSSEC_ALGORITHM_RSASHA512:
|
||||
r = dnssec_rsa_verify(
|
||||
gcry_md_algo_name(md_algorithm),
|
||||
hash, hash_size,
|
||||
rrsig,
|
||||
dnskey);
|
||||
break;
|
||||
|
||||
if (exponent_size < 256) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (3 + exponent_size >= dnskey->dnskey.key_size) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
modulus = (uint8_t*) dnskey->dnskey.key + 3 + exponent_size;
|
||||
modulus_size = dnskey->dnskey.key_size - 3 - exponent_size;
|
||||
|
||||
} else {
|
||||
/* exponent is <= 255 bytes long */
|
||||
|
||||
exponent = (uint8_t*) dnskey->dnskey.key + 1;
|
||||
exponent_size = (size_t) ((uint8_t*) dnskey->dnskey.key)[0];
|
||||
|
||||
if (exponent_size <= 0) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (1 + exponent_size >= dnskey->dnskey.key_size) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
modulus = (uint8_t*) dnskey->dnskey.key + 1 + exponent_size;
|
||||
modulus_size = dnskey->dnskey.key_size - 1 - exponent_size;
|
||||
case DNSSEC_ALGORITHM_ECDSAP256SHA256:
|
||||
case DNSSEC_ALGORITHM_ECDSAP384SHA384:
|
||||
r = dnssec_ecdsa_verify(
|
||||
gcry_md_algo_name(md_algorithm),
|
||||
rrsig->rrsig.algorithm,
|
||||
hash, hash_size,
|
||||
rrsig,
|
||||
dnskey);
|
||||
break;
|
||||
}
|
||||
|
||||
r = dnssec_rsa_verify(
|
||||
gcry_md_algo_name(gcry_md_get_algo(md)),
|
||||
rrsig->rrsig.signature, rrsig->rrsig.signature_size,
|
||||
hash, hash_size,
|
||||
exponent, exponent_size,
|
||||
modulus, modulus_size);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
|
@ -533,6 +701,30 @@ int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig)
|
|||
return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key));
|
||||
}
|
||||
|
||||
static int dnssec_fix_rrset_ttl(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord *rrsig, usec_t realtime) {
|
||||
DnsResourceRecord *rr;
|
||||
int r;
|
||||
|
||||
assert(key);
|
||||
assert(rrsig);
|
||||
|
||||
DNS_ANSWER_FOREACH(rr, a) {
|
||||
r = dns_resource_key_equal(key, rr->key);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
/* Pick the TTL as the minimum of the RR's TTL, the
|
||||
* RR's original TTL according to the RRSIG and the
|
||||
* RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
|
||||
rr->ttl = MIN3(rr->ttl, rrsig->rrsig.original_ttl, rrsig->ttl);
|
||||
rr->expiry = rrsig->rrsig.expiration * USEC_PER_SEC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dnssec_verify_rrset_search(
|
||||
DnsAnswer *a,
|
||||
DnsResourceKey *key,
|
||||
|
@ -599,7 +791,11 @@ int dnssec_verify_rrset_search(
|
|||
|
||||
case DNSSEC_VALIDATED:
|
||||
/* Yay, the RR has been validated,
|
||||
* return immediately. */
|
||||
* return immediately, but fix up the expiry */
|
||||
r = dnssec_fix_rrset_ttl(a, key, rrsig, realtime);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*result = DNSSEC_VALIDATED;
|
||||
return 0;
|
||||
|
||||
|
@ -730,9 +926,9 @@ int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
|
|||
return (int) c;
|
||||
}
|
||||
|
||||
static int digest_to_gcrypt(uint8_t algorithm) {
|
||||
static int digest_to_gcrypt_md(uint8_t algorithm) {
|
||||
|
||||
/* Translates a DNSSEC digest algorithm into a gcrypt digest iedntifier */
|
||||
/* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
|
||||
|
||||
switch (algorithm) {
|
||||
|
||||
|
@ -742,6 +938,9 @@ static int digest_to_gcrypt(uint8_t algorithm) {
|
|||
case DNSSEC_DIGEST_SHA256:
|
||||
return GCRY_MD_SHA256;
|
||||
|
||||
case DNSSEC_DIGEST_SHA384:
|
||||
return GCRY_MD_SHA384;
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -751,9 +950,8 @@ int dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds) {
|
|||
char owner_name[DNSSEC_CANONICAL_HOSTNAME_MAX];
|
||||
gcry_md_hd_t md = NULL;
|
||||
size_t hash_size;
|
||||
int algorithm;
|
||||
int md_algorithm, r;
|
||||
void *result;
|
||||
int r;
|
||||
|
||||
assert(dnskey);
|
||||
assert(ds);
|
||||
|
@ -776,11 +974,11 @@ int dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds) {
|
|||
|
||||
initialize_libgcrypt();
|
||||
|
||||
algorithm = digest_to_gcrypt(ds->ds.digest_type);
|
||||
if (algorithm < 0)
|
||||
return algorithm;
|
||||
md_algorithm = digest_to_gcrypt_md(ds->ds.digest_type);
|
||||
if (md_algorithm < 0)
|
||||
return md_algorithm;
|
||||
|
||||
hash_size = gcry_md_get_algo_dlen(algorithm);
|
||||
hash_size = gcry_md_get_algo_dlen(md_algorithm);
|
||||
assert(hash_size > 0);
|
||||
|
||||
if (ds->ds.digest_size != hash_size)
|
||||
|
@ -790,7 +988,7 @@ int dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
gcry_md_open(&md, algorithm, 0);
|
||||
gcry_md_open(&md, md_algorithm, 0);
|
||||
if (!md)
|
||||
return -EIO;
|
||||
|
||||
|
@ -866,7 +1064,7 @@ int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
|
|||
if (nsec3->key->type != DNS_TYPE_NSEC3)
|
||||
return -EINVAL;
|
||||
|
||||
algorithm = digest_to_gcrypt(nsec3->nsec3.algorithm);
|
||||
algorithm = digest_to_gcrypt_md(nsec3->nsec3.algorithm);
|
||||
if (algorithm < 0)
|
||||
return algorithm;
|
||||
|
||||
|
|
|
@ -339,6 +339,7 @@ DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
|
|||
|
||||
rr->n_ref = 1;
|
||||
rr->key = dns_resource_key_ref(key);
|
||||
rr->expiry = USEC_INFINITY;
|
||||
|
||||
return rr;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ enum {
|
|||
DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1,
|
||||
DNSSEC_ALGORITHM_RSASHA256 = 8, /* RFC 5702 */
|
||||
DNSSEC_ALGORITHM_RSASHA512 = 10, /* RFC 5702 */
|
||||
DNSSEC_ALGORITHM_ECDSAP256SHA256 = 13, /* RFC 6605 */
|
||||
DNSSEC_ALGORITHM_ECDSAP384SHA384 = 14, /* RFC 6605 */
|
||||
DNSSEC_ALGORITHM_INDIRECT = 252,
|
||||
DNSSEC_ALGORITHM_PRIVATEDNS,
|
||||
DNSSEC_ALGORITHM_PRIVATEOID,
|
||||
|
@ -64,6 +66,7 @@ enum {
|
|||
enum {
|
||||
DNSSEC_DIGEST_SHA1 = 1,
|
||||
DNSSEC_DIGEST_SHA256 = 2,
|
||||
DNSSEC_DIGEST_SHA384 = 4,
|
||||
_DNSSEC_DIGEST_MAX_DEFINED
|
||||
};
|
||||
|
||||
|
@ -97,6 +100,7 @@ struct DnsResourceRecord {
|
|||
DnsResourceKey *key;
|
||||
char *to_string;
|
||||
uint32_t ttl;
|
||||
usec_t expiry; /* RRSIG signature expiry */
|
||||
bool unparseable:1;
|
||||
bool wire_format_canonical:1;
|
||||
void *wire_format;
|
||||
|
|
|
@ -48,14 +48,10 @@ static void dns_transaction_close_connection(DnsTransaction *t) {
|
|||
t->dns_udp_fd = safe_close(t->dns_udp_fd);
|
||||
}
|
||||
|
||||
static void dns_transaction_stop(DnsTransaction *t) {
|
||||
static void dns_transaction_stop_timeout(DnsTransaction *t) {
|
||||
assert(t);
|
||||
|
||||
t->timeout_event_source = sd_event_source_unref(t->timeout_event_source);
|
||||
t->stream = dns_stream_free(t->stream);
|
||||
|
||||
/* Note that we do not drop the UDP socket here, as we want to
|
||||
* reuse it to repeat the interaction. */
|
||||
}
|
||||
|
||||
DnsTransaction* dns_transaction_free(DnsTransaction *t) {
|
||||
|
@ -67,7 +63,7 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
|
|||
return NULL;
|
||||
|
||||
dns_transaction_close_connection(t);
|
||||
dns_transaction_stop(t);
|
||||
dns_transaction_stop_timeout(t);
|
||||
|
||||
dns_packet_unref(t->sent);
|
||||
dns_transaction_reset_answer(t);
|
||||
|
@ -264,7 +260,7 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
|
|||
t->state = state;
|
||||
|
||||
dns_transaction_close_connection(t);
|
||||
dns_transaction_stop(t);
|
||||
dns_transaction_stop_timeout(t);
|
||||
|
||||
/* Notify all queries that are interested, but make sure the
|
||||
* transaction isn't freed while we are still looking at it */
|
||||
|
@ -725,7 +721,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
|
|||
if (r > 0) {
|
||||
/* There are DNSSEC transactions pending now. Update the state accordingly. */
|
||||
t->state = DNS_TRANSACTION_VALIDATING;
|
||||
dns_transaction_stop(t);
|
||||
dns_transaction_close_connection(t);
|
||||
dns_transaction_stop_timeout(t);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -869,7 +866,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) {
|
|||
|
||||
assert(t);
|
||||
|
||||
dns_transaction_stop(t);
|
||||
dns_transaction_stop_timeout(t);
|
||||
|
||||
if (t->n_attempts >= TRANSACTION_ATTEMPTS_MAX(t->scope->protocol)) {
|
||||
dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);
|
||||
|
|
|
@ -98,8 +98,13 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
|
|||
((unsigned) (n[1] - '0') * 10) +
|
||||
((unsigned) (n[2] - '0'));
|
||||
|
||||
/* Don't allow CC characters or anything that doesn't fit in 8bit */
|
||||
if (k < ' ' || k > 255 || k == 127)
|
||||
/* Don't allow anything that doesn't
|
||||
* fit in 8bit. Note that we do allow
|
||||
* control characters, as some servers
|
||||
* (e.g. cloudflare) are happy to
|
||||
* generate labels with them
|
||||
* inside. */
|
||||
if (k > 255)
|
||||
return -EINVAL;
|
||||
|
||||
if (d)
|
||||
|
@ -245,7 +250,7 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
|
|||
*(q++) = *p;
|
||||
sz -= 1;
|
||||
|
||||
} else if ((uint8_t) *p >= (uint8_t) ' ' && *p != 127) {
|
||||
} else {
|
||||
|
||||
/* Everything else */
|
||||
|
||||
|
@ -259,8 +264,7 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
|
|||
|
||||
sz -= 4;
|
||||
|
||||
} else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
p++;
|
||||
l--;
|
||||
|
|
|
@ -168,7 +168,7 @@ static void test_dns_label_escape_one(const char *what, size_t l, const char *ex
|
|||
static void test_dns_label_escape(void) {
|
||||
test_dns_label_escape_one("", 0, NULL, -EINVAL);
|
||||
test_dns_label_escape_one("hallo", 5, "hallo", 5);
|
||||
test_dns_label_escape_one("hallo", 6, NULL, -EINVAL);
|
||||
test_dns_label_escape_one("hallo", 6, "hallo\\000", 9);
|
||||
test_dns_label_escape_one("hallo hallo.foobar,waldi", 24, "hallo\\032hallo\\.foobar\\044waldi", 31);
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ static void test_dns_name_normalize(void) {
|
|||
test_dns_name_normalize_one("f", "f", 0);
|
||||
test_dns_name_normalize_one("f.waldi", "f.waldi", 0);
|
||||
test_dns_name_normalize_one("f \\032.waldi", "f\\032\\032.waldi", 0);
|
||||
test_dns_name_normalize_one("\\000", NULL, -EINVAL);
|
||||
test_dns_name_normalize_one("\\000", "\\000", 0);
|
||||
test_dns_name_normalize_one("..", NULL, -EINVAL);
|
||||
test_dns_name_normalize_one(".foobar", NULL, -EINVAL);
|
||||
test_dns_name_normalize_one("foobar.", "foobar", 0);
|
||||
|
@ -216,7 +216,7 @@ static void test_dns_name_equal(void) {
|
|||
test_dns_name_equal_one("abc.def", "CBA.def", false);
|
||||
test_dns_name_equal_one("", "xxx", false);
|
||||
test_dns_name_equal_one("ab", "a", false);
|
||||
test_dns_name_equal_one("\\000", "xxxx", -EINVAL);
|
||||
test_dns_name_equal_one("\\000", "\\000", true);
|
||||
test_dns_name_equal_one(".", "", true);
|
||||
test_dns_name_equal_one(".", ".", true);
|
||||
test_dns_name_equal_one("..", "..", -EINVAL);
|
||||
|
|
Loading…
Reference in a new issue