new: usr: "Add code paths to fully support PRIVATEDNS and PRIVATEOID keys"

Added support for PRIVATEDNS and PRIVATEOID key usage. Added PRIVATEOID
test algorithms using the assigned OIDs for RSASHA256 and RSASHA512.

Added code to support proposed DS digest types that encode the PRIVATEDNS
and PRIVATEOID identifiers at the start of the digest field of the DS record.
This code is disabled by default.

Closes #3240

Merge branch '3240-add-privatedns-and-privateoid-support' into 'main'

See merge request isc-projects/bind9!10341
This commit is contained in:
Mark Andrews 2025-06-19 01:01:12 +00:00
commit 119f511a45
52 changed files with 2014 additions and 358 deletions

View file

@ -482,7 +482,7 @@ match_key_dsset(keyinfo_t *ki, dns_rdataset_t *dsset, strictness_t strictness) {
}
result = dns_ds_buildrdata(name, &ki->rdata, ds.digest_type,
dsbuf, &newdsrdata);
dsbuf, sizeof(dsbuf), &newdsrdata);
if (result != ISC_R_SUCCESS) {
vbprintf(3,
"dns_ds_buildrdata("
@ -769,7 +769,7 @@ ds_from_cdnskey(isc_buffer_t *buf, dns_rdata_t *ds, dns_dsdigest_t dt,
return ISC_R_NOSPACE;
}
result = dns_ds_buildrdata(name, cdnskey, dt, r.base, ds);
result = dns_ds_buildrdata(name, cdnskey, dt, r.base, r.length, ds);
if (result == ISC_R_SUCCESS) {
isc_buffer_add(buf, DNS_DS_BUFFERSIZE);
}

View file

@ -270,7 +270,7 @@ emit(dns_dsdigest_t dt, bool showall, bool cds, dns_rdata_t *rdata) {
return;
}
result = dns_ds_buildrdata(name, rdata, dt, buf, &ds);
result = dns_ds_buildrdata(name, rdata, dt, buf, sizeof(buf), &ds);
if (result != ISC_R_SUCCESS) {
fatal("can't build record");
}

View file

@ -113,7 +113,7 @@ main(int argc, char **argv) {
dns_fixedname_t fname;
dns_name_t *name;
uint16_t flags = 0, kskflag = 0, revflag = 0;
dns_secalg_t alg;
dst_algorithm_t alg;
bool oldstyle = false;
isc_mem_t *mctx = NULL;
int ch;
@ -382,7 +382,7 @@ main(int argc, char **argv) {
r.base = algname;
r.length = strlen(algname);
ret = dns_secalg_fromtext(&alg, &r);
ret = dst_algorithm_fromtext(&alg, &r);
if (ret != ISC_R_SUCCESS) {
fatal("unknown algorithm %s", algname);
}

View file

@ -89,7 +89,7 @@ struct keygen_ctx {
bool wantzsk;
bool wantksk;
bool wantrev;
dns_secalg_t alg;
dst_algorithm_t alg;
/* timing data */
int prepub;
isc_stdtime_t now;
@ -245,7 +245,7 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
UNUSED(argc);
dns_secalg_format(ctx->alg, algstr, sizeof(algstr));
dst_algorithm_format(ctx->alg, algstr, sizeof(algstr));
if (ctx->predecessor == NULL) {
if (ctx->prepub == -1) {
@ -286,6 +286,8 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
case DST_ALG_NSEC3RSASHA1:
case DST_ALG_RSASHA256:
case DST_ALG_RSASHA512:
case DST_ALG_RSASHA256PRIVATEOID:
case DST_ALG_RSASHA512PRIVATEOID:
case DST_ALG_ECDSA256:
case DST_ALG_ECDSA384:
case DST_ALG_ED25519:
@ -309,6 +311,8 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
FALLTHROUGH;
case DST_ALG_RSASHA256:
case DST_ALG_RSASHA512:
case DST_ALG_RSASHA256PRIVATEOID:
case DST_ALG_RSASHA512PRIVATEOID:
ctx->size = 2048;
if (verbose > 0) {
fprintf(stderr,
@ -454,14 +458,16 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
}
switch (ctx->alg) {
case DNS_KEYALG_RSASHA1:
case DNS_KEYALG_NSEC3RSASHA1:
case DST_ALG_RSASHA1:
case DST_ALG_NSEC3RSASHA1:
if (isc_crypto_fips_mode()) {
fatal("SHA1 based keys not supported in FIPS mode");
}
FALLTHROUGH;
case DNS_KEYALG_RSASHA256:
case DNS_KEYALG_RSASHA512:
case DST_ALG_RSASHA256:
case DST_ALG_RSASHA512:
case DST_ALG_RSASHA256PRIVATEOID:
case DST_ALG_RSASHA512PRIVATEOID:
if (ctx->size != 0 &&
(ctx->size < min_rsa || ctx->size > MAX_RSA))
{
@ -480,6 +486,8 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
case DST_ALG_ED448:
ctx->size = 456;
break;
default:
fatal("not a dnskey algorithm %u\n", ctx->alg);
}
if ((ctx->options & DST_TYPE_KEY) == 0) {
@ -502,10 +510,10 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
}
switch (ctx->alg) {
case DNS_KEYALG_RSASHA1:
case DNS_KEYALG_NSEC3RSASHA1:
case DNS_KEYALG_RSASHA256:
case DNS_KEYALG_RSASHA512:
case DST_ALG_RSASHA1:
case DST_ALG_NSEC3RSASHA1:
case DST_ALG_RSASHA256:
case DST_ALG_RSASHA512:
show_progress = true;
break;
@ -515,6 +523,8 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
case DST_ALG_ED448:
show_progress = true;
break;
default:
break;
}
if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY &&
@ -1072,7 +1082,7 @@ main(int argc, char **argv) {
}
r.base = algname;
r.length = strlen(algname);
ret = dns_secalg_fromtext(&ctx.alg, &r);
ret = dst_algorithm_fromtext(&ctx.alg, &r);
if (ret != ISC_R_SUCCESS) {
fatal("unknown algorithm %s", algname);
}

View file

@ -64,7 +64,7 @@ struct ksr_ctx {
/* keygen */
bool ksk;
dns_ttl_t ttl;
dns_secalg_t alg;
dst_algorithm_t alg;
int size;
time_t lifetime;
time_t parentpropagation;
@ -341,7 +341,7 @@ create_key(ksr_ctx_t *ksr, dns_kasp_t *kasp, dns_kasp_key_t *kaspkey,
}
/* Check algorithm and size. */
dns_secalg_format(ksr->alg, algstr, sizeof(algstr));
dst_algorithm_format(ksr->alg, algstr, sizeof(algstr));
if (!dst_algorithm_supported(ksr->alg)) {
fatal("unsupported algorithm: %s", algstr);
}
@ -356,6 +356,8 @@ create_key(ksr_ctx_t *ksr, dns_kasp_t *kasp, dns_kasp_key_t *kaspkey,
FALLTHROUGH;
case DST_ALG_RSASHA256:
case DST_ALG_RSASHA512:
case DST_ALG_RSASHA256PRIVATEOID:
case DST_ALG_RSASHA512PRIVATEOID:
if (ksr->size != 0 &&
(ksr->size < min_rsa || ksr->size > MAX_RSA))
{
@ -851,7 +853,7 @@ get_keymaterial(ksr_ctx_t *ksr, dns_kasp_t *kasp, isc_stdtime_t inception,
dns_rdata_init(rdata2);
CHECK(dns_ds_buildrdata(name, rdata, alg->digest,
cdsbuf, &cds));
cdsbuf, sizeof(cdsbuf), &cds));
cds.type = dns_rdatatype_cds;
dns_rdata_toregion(&cds, &rcds);
isc_buffer_allocate(mctx, &newbuf2, rcds.length);

View file

@ -348,9 +348,12 @@ iszsk(dns_dnsseckey_t *key) {
*/
static dns_dnsseckey_t *
keythatsigned_unlocked(dns_rdata_rrsig_t *rrsig) {
dst_algorithm_t algorithm = dst_algorithm_fromdata(
rrsig->algorithm, rrsig->signature, rrsig->siglen);
ISC_LIST_FOREACH (keylist, key, link) {
if (rrsig->keyid == dst_key_id(key->key) &&
rrsig->algorithm == dst_key_alg(key->key) &&
algorithm == dst_key_alg(key->key) &&
dns_name_equal(&rrsig->signer, dst_key_name(key->key)))
{
return key;
@ -1070,7 +1073,7 @@ loadds(dns_name_t *name, uint32_t ttl, dns_rdataset_t *dsset) {
dns_rdata_t ds = DNS_RDATA_INIT;
dns_rdataset_current(&keyset, &key);
result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA256,
dsbuf, &ds);
dsbuf, sizeof(dsbuf), &ds);
check_result(result, "dns_ds_buildrdata");
dns_difftuple_create(mctx, DNS_DIFFOP_ADDRESIGN, name, ttl, &ds,
@ -3052,7 +3055,7 @@ writeset(const char *prefix, dns_rdatatype_t type) {
if (type != dns_rdatatype_dnskey) {
result = dns_ds_buildrdata(gorigin, &rdata,
DNS_DSDIGEST_SHA256, dsbuf,
&ds);
sizeof(dsbuf), &ds);
check_result(result, "dns_ds_buildrdata");
dns_difftuple_create(mctx, DNS_DIFFOP_ADDRESIGN, name,
0, &ds, &tuple);

View file

@ -120,9 +120,11 @@ void
sig_format(dns_rdata_rrsig_t *sig, char *cp, unsigned int size) {
char namestr[DNS_NAME_FORMATSIZE];
char algstr[DNS_NAME_FORMATSIZE];
dst_algorithm_t algorithm = dst_algorithm_fromdata(
sig->algorithm, sig->signature, sig->siglen);
dns_name_format(&sig->signer, namestr, sizeof(namestr));
dns_secalg_format(sig->algorithm, algstr, sizeof(algstr));
dst_algorithm_format(algorithm, algstr, sizeof(algstr));
snprintf(cp, size, "%s/%s/%d", namestr, algstr, sig->keyid);
}
@ -361,7 +363,10 @@ strtodsdigest(const char *str) {
r.length = strlen(str);
result = dns_dsdigest_fromtext(&alg, &r);
if (result != ISC_R_SUCCESS) {
fatal("unknown DS algorithm %s", str);
fatal("unknown DS digest %s", str);
}
if (!dst_ds_digest_supported(alg)) {
fatal("unsupported DS digest %s", str);
}
return alg;
}

View file

@ -424,7 +424,7 @@ list_dnssec_algorithms(isc_buffer_t *b) {
}
if (dst_algorithm_supported(i)) {
isc_buffer_putstr(b, " ");
(void)dns_secalg_totext(i, b);
dst_algorithm_totext(i, b);
}
}
}

View file

@ -154,11 +154,11 @@
#endif /* HAVE_LMDB */
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)-1)
#define SIZE_MAX ((size_t)(-1))
#endif /* ifndef SIZE_MAX */
#ifndef SIZE_AS_PERCENT
#define SIZE_AS_PERCENT ((size_t)-2)
#define SIZE_AS_PERCENT ((size_t)(-2))
#endif /* ifndef SIZE_AS_PERCENT */
/* RFC7828 defines timeout as 16-bit value specified in units of 100
@ -677,7 +677,7 @@ cleanup:
static isc_result_t
ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
unsigned char *digest, dns_rdata_ds_t *ds) {
unsigned char *digest, size_t digest_len, dns_rdata_ds_t *ds) {
isc_result_t result;
dns_rdata_dnskey_t keystruct;
dns_rdata_t rdata = DNS_RDATA_INIT;
@ -699,6 +699,7 @@ ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
STATIC_DS,
TRUSTED
} anchortype;
dst_algorithm_t algorithm;
REQUIRE(namestrp != NULL && *namestrp == NULL);
REQUIRE(ds != NULL);
@ -787,22 +788,24 @@ ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
keystruct.flags = (uint16_t)rdata1;
keystruct.protocol = (uint8_t)rdata2;
keystruct.algorithm = (uint8_t)rdata3;
if (!dst_algorithm_supported(keystruct.algorithm)) {
CHECK(DST_R_UNSUPPORTEDALG);
}
datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
CHECK(isc_base64_decodestring(datastr, &databuf));
isc_buffer_usedregion(&databuf, &r);
keystruct.datalen = r.length;
keystruct.data = r.base;
algorithm = dst_algorithm_fromdata(
keystruct.algorithm, keystruct.data, keystruct.datalen);
if (!dst_algorithm_supported(algorithm)) {
CHECK(DST_R_UNSUPPORTEDALG);
}
CHECK(dns_rdata_fromstruct(&rdata, keystruct.common.rdclass,
keystruct.common.rdtype, &keystruct,
&rrdatabuf));
CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
digest, ds));
digest, digest_len, ds));
break;
case INIT_DS:
@ -841,6 +844,20 @@ ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
CHECK(ISC_R_UNEXPECTEDEND);
}
break;
#if defined(DNS_DSDIGEST_SHA256PRIVATE)
case DNS_DSDIGEST_SHA256PRIVATE:
if (r.length < ISC_SHA256_DIGESTLENGTH) {
CHECK(ISC_R_UNEXPECTEDEND);
}
break;
#endif
#if defined(DNS_DSDIGEST_SHA384PRIVATE)
case DNS_DSDIGEST_SHA384PRIVATE:
if (r.length < ISC_SHA384_DIGESTLENGTH) {
CHECK(ISC_R_UNEXPECTEDEND);
}
break;
#endif
default:
cfg_obj_log(key, ISC_LOG_ERROR,
"key '%s': "
@ -851,10 +868,49 @@ ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
break;
}
if (r.length > digest_len) {
CHECK(ISC_R_NOSPACE);
}
ds->length = r.length;
ds->digest = digest;
memmove(ds->digest, r.base, r.length);
algorithm = ds->algorithm;
#if defined(DNS_DSDIGEST_SHA256PRIVATE) && defined(DNS_DSDIGEST_SHA384PRIVATE)
/*
* Extract the private algorithm from the start
* of the hash field.
*/
switch (ds->digest_type) {
/*
* Digest types that do not encode the private DNSSEC algorithm
* at the start of the digest field.
*/
case DNS_DSDIGEST_SHA1:
case DNS_DSDIGEST_SHA256:
case DNS_DSDIGEST_SHA384:
break;
/*
* Digest types that encode the private DNSSEC algorithm
* at the start of the digest field.
*/
case DNS_DSDIGEST_SHA256PRIVATE:
case DNS_DSDIGEST_SHA384PRIVATE:
algorithm = dst_algorithm_fromdata(
ds->algorithm, ds->digest, ds->length);
break;
/*
* Unknown digest types.
*/
default:
break;
}
#endif
if (!dst_algorithm_supported(algorithm)) {
CHECK(DST_R_UNSUPPORTEDALG);
}
break;
default:
@ -894,10 +950,11 @@ process_key(const cfg_obj_t *key, dns_keytable_t *secroots,
dns_rdata_ds_t ds;
isc_result_t result;
bool initializing = managed;
unsigned char digest[ISC_MAX_MD_SIZE];
unsigned char digest[DNS_DS_BUFFERSIZE];
isc_buffer_t b;
result = ta_fromconfig(key, &initializing, &namestr, digest, &ds);
result = ta_fromconfig(key, &initializing, &namestr, digest,
sizeof(digest), &ds);
switch (result) {
case ISC_R_SUCCESS:
@ -950,7 +1007,7 @@ process_key(const cfg_obj_t *key, dns_keytable_t *secroots,
* warning, but do not prevent further keys from being processed.
*/
if (!dns_resolver_algorithm_supported(view->resolver, keyname,
ds.algorithm))
ds.algorithm, NULL, 0))
{
cfg_obj_log(key, ISC_LOG_WARNING,
"ignoring %s for '%s': algorithm is disabled",
@ -1592,17 +1649,11 @@ disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
algorithms = cfg_tuple_get(disabled, "algorithms");
CFG_LIST_FOREACH (algorithms, element) {
isc_textregion_t r;
dns_secalg_t alg;
dst_algorithm_t alg;
r.base = UNCONST(cfg_obj_asstring(cfg_listelt_value(element)));
r.length = strlen(r.base);
result = dns_secalg_fromtext(&alg, &r);
if (result != ISC_R_SUCCESS) {
uint8_t ui;
result = isc_parse_uint8(&ui, r.base, 10);
alg = ui;
}
result = dst_algorithm_fromtext(&alg, &r);
if (result != ISC_R_SUCCESS) {
cfg_obj_log(cfg_listelt_value(element), ISC_LOG_ERROR,
"invalid algorithm");
@ -14358,7 +14409,7 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
/* variables for -key */
bool use_keyid = false;
dns_keytag_t keyid = 0;
uint8_t algorithm = 0;
dst_algorithm_t algorithm = 0;
/* variables for -status */
bool status = false;
char output[4096];
@ -14414,7 +14465,7 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
}
alg.base = ptr;
alg.length = strlen(alg.base);
result = dns_secalg_fromtext(
result = dst_algorithm_fromtext(
&algorithm, (isc_textregion_t *)&alg);
if (result != ISC_R_SUCCESS) {
msg = "Bad algorithm";

View file

@ -31,12 +31,13 @@ showprivate() {
$DIG $DIGOPTS +nodnssec +short @$2 -t ${4:-type65534} $1 | cut -f3 -d' ' \
| while read record; do
$PERL -e 'my $rdata = pack("H*", @ARGV[0]);
die "invalid record" unless length($rdata) == 5;
my ($alg, $key, $remove, $complete) = unpack("CnCC", $rdata);
die "invalid record" unless length($rdata) == 5 || length($rdata) == 7;
my ($dns, $key, $remove, $complete, $alg) = unpack("CnCCn", $rdata);
my $action = "signing";
$action = "removing" if $remove;
my $state = " (incomplete)";
$state = " (complete)" if $complete;
$alg = $dns if ! defined($alg);
print ("$action: alg: $alg, key: $key$state\n");' $record
done
}

View file

@ -211,10 +211,19 @@ private_type_record() {
_zone=$1
_algorithm=$2
_keyfile=$3
_secalg=$2
case $_secalg in
256) _secalg=254 ;; # RSASHA256OID
257) _secalg=254 ;; # RSASHA512OID
esac
_id=$(keyfile_to_key_id "$_keyfile")
printf "%s. 0 IN TYPE65534 %s 5 %02x%04x0000\n" "$_zone" "\\#" "$_algorithm" "$_id"
if test "$_algorithm" -lt 256; then
printf "%s. 0 IN TYPE65534 %s 5 %02x%04x0000\n" "$_zone" "\\#" "$_secalg" "$_id"
else
printf "%s. 0 IN TYPE65534 %s 7 %02x%04x0000%04x\n" "$_zone" "\\#" "$_secalg" "$_id" "$_algorithm"
fi
}
# nextpart*() - functions for reading files incrementally
@ -518,13 +527,16 @@ copy_setports() {
-e "s/@CONTROLPORT@/${CONTROLPORT}/g" \
-e "s/@DEFAULT_ALGORITHM@/${DEFAULT_ALGORITHM}/g" \
-e "s/@DEFAULT_ALGORITHM_NUMBER@/${DEFAULT_ALGORITHM_NUMBER}/g" \
-e "s/@DEFAULT_ALGORITHM_DST_NUMBER@/${DEFAULT_ALGORITHM_DST_NUMBER}/g" \
-e "s/@DEFAULT_BITS@/${DEFAULT_BITS}/g" \
-e "s/@ALTERNATIVE_ALGORITHM@/${ALTERNATIVE_ALGORITHM}/g" \
-e "s/@ALTERNATIVE_ALGORITHM_NUMBER@/${ALTERNATIVE_ALGORITHM_NUMBER}/g" \
-e "s/@ALTERNATIVE_ALGORITHM_DST_NUMBER@/${ALTERNATIVE_ALGORITHM_DST_NUMBER}/g" \
-e "s/@ALTERNATIVE_BITS@/${ALTERNATIVE_BITS}/g" \
-e "s/@DEFAULT_HMAC@/${DEFAULT_HMAC}/g" \
-e "s/@DISABLED_ALGORITHM@/${DISABLED_ALGORITHM}/g" \
-e "s/@DISABLED_ALGORITHM_NUMBER@/${DISABLED_ALGORITHM_NUMBER}/g" \
-e "s/@DISABLED_ALGORITHM_NUMBER@/${DISABLED_ALGORITHM_DST_NUMBER}/g" \
-e "s/@DISABLED_BITS@/${DISABLED_BITS}/g" \
$1 >$2
}

View file

@ -181,3 +181,21 @@ rsasha1-1024 NS ns.rsasha1-1024
ns.rsasha1-1024 A 10.53.0.3
dname-at-apex-nsec3 NS ns3
rsasha256oid NS ns.rsasha256oid
ns.rsasha256oid A 10.53.0.3
rsasha512oid NS ns.rsasha512oid
ns.rsasha512oid A 10.53.0.3
unknownoid NS ns.unknownoid
ns.unknownoid A 10.53.0.3
extradsoid NS ns.extradsoid
ns.extradsoid A 10.53.0.3
extradsunknownoid NS ns.extradsunknownoid
ns.extradsunknownoid A 10.53.0.3
extended-ds-unknown-oid NS ns.extended-ds-unknown-oid
ns.extended-ds-unknown-oid A 10.53.0.3

View file

@ -65,7 +65,9 @@ for subdomain in digest-alg-unsupported ds-unsupported secure badds \
ttlpatch split-dnssec split-smart expired expiring upper lower \
dnskey-unknown dnskey-unsupported dnskey-unsupported-2 \
dnskey-nsec3-unknown managed-future future revkey \
dname-at-apex-nsec3 occluded rsasha1 rsasha1-1024; do
dname-at-apex-nsec3 occluded rsasha1 rsasha1-1024 \
rsasha256oid rsasha512oid unknownoid extradsoid extradsunknownoid \
extended-ds-unknown-oid; do
cp "../ns3/dsset-$subdomain.example." .
done
@ -87,7 +89,7 @@ zonefiletmp=$(mktemp "$zonefile.XXXXXX") || exit 1
| awk '
tolower($1) == "bad-cname.example." && $4 == "RRSIG" && $5 == "CNAME" {
for (i = 1; i <= NF; i++ ) {
if (i <= 12) {
if (i <= 13) {
printf("%s ", $i);
continue;
}
@ -106,7 +108,7 @@ tolower($1) == "bad-cname.example." && $4 == "RRSIG" && $5 == "CNAME" {
tolower($1) == "bad-dname.example." && $4 == "RRSIG" && $5 == "DNAME" {
for (i = 1; i <= NF; i++ ) {
if (i <= 12) {
if (i <= 13) {
printf("%s ", $i);
continue;
}

View file

@ -0,0 +1,28 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
2009102722 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns
ns A 10.53.0.3
a A 10.0.0.1
b A 10.0.0.2
d A 10.0.0.4
z A 10.0.0.26
a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
x CNAME a

View file

@ -0,0 +1,28 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
2009102722 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns
ns A 10.53.0.3
a A 10.0.0.1
b A 10.0.0.2
d A 10.0.0.4
z A 10.0.0.26
a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
x CNAME a

View file

@ -0,0 +1,28 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
2009102722 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns
ns A 10.53.0.3
a A 10.0.0.1
b A 10.0.0.2
d A 10.0.0.4
z A 10.0.0.26
a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
x CNAME a

View file

@ -429,11 +429,41 @@ zone "rsasha1-1024.example" {
file "rsasha1-1024.example.db";
};
zone "rsasha256oid.example" {
type primary;
file "rsasha256oid.example.db.signed";
};
zone "rsasha512oid.example" {
type primary;
file "rsasha512oid.example.db.signed";
};
zone "unknownoid.example" {
type primary;
file "unknownoid.example.db.signed";
};
zone "target.peer-ns-spoof" {
type primary;
file "target.peer-ns-spoof.db.signed";
};
zone "extradsoid.example" {
type primary;
file "extradsoid.example.db.signed";
};
zone "extradsunknownoid.example" {
type primary;
file "extradsunknownoid.example.db.signed";
};
zone "extended-ds-unknown-oid.example" {
type primary;
file "extended-ds-unknown-oid.example.db.signed";
};
dnssec-policy "siginterval1" {
keys {
ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;

View file

@ -0,0 +1,28 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
2009102722 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns
ns A 10.53.0.3
a A 10.0.0.1
b A 10.0.0.2
d A 10.0.0.4
z A 10.0.0.26
a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
x CNAME a

View file

@ -0,0 +1,28 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
2009102722 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns
ns A 10.53.0.3
a A 10.0.0.1
b A 10.0.0.2
d A 10.0.0.4
z A 10.0.0.26
a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
x CNAME a

View file

@ -424,6 +424,146 @@ cat "$infile" "$keyname.key" >"$zonefile"
"$SIGNER" -P -o "$zone" "$zonefile" >/dev/null
#
# A RSASHA256OID zone.
#
zone=rsasha256oid.example.
infile=rsasha256oid.example.db.in
zonefile=rsasha256oid.example.db
keyname=$("$KEYGEN" -q -a RSASHA256OID "$zone")
cat "$infile" "$keyname.key" >"$zonefile"
"$SIGNER" -z -o "$zone" "$zonefile" >/dev/null
#
# A RSASHA512OID zone.
#
zone=rsasha512oid.example.
infile=rsasha512oid.example.db.in
zonefile=rsasha512oid.example.db
keyname=$("$KEYGEN" -q -a RSASHA512OID "$zone")
cat "$infile" "$keyname.key" >"$zonefile"
"$SIGNER" -z -o "$zone" "$zonefile" >/dev/null
#
# A UNKNOWNOID zone. Sign the zone using RSASHA512OID then
# update the OID in the DNSKEY and RRSIGS to the unknown OID
# 1.2.840.113549.1.1.14
#
zone=unknownoid.example
infile=unknownoid.example.db.in
zonefile=unknownoid.example.db
keyname=$("$KEYGEN" -q -a RSASHA512OID "$zone")
cat "$infile" "$keyname.key" >"$zonefile"
# Sign with known OID RSASHA512OID
"$SIGNER" -z -o "$zone" -f "${zonefile}.stage1" "$zonefile" >/dev/null
# Change OID from 1.2.840.113549.1.1.13 to 1.2.840.113549.1.1.14
sed 's/CwYJKoZIhvcN/CwYJKoZIhvcO/' <"${zonefile}.stage1" >"${zonefile}.stage2"
"$DSFROMKEY" -2A -f "${zonefile}.stage2" "$zone" >"dsset-${zone}."
# extract the updated DNSKEY's tag
tag=$(awk '{print $4}' "dsset-${zone}.")
# Update RRSIG tags
sed "s/\(2[0-9]* 2[0-9]*\) [1-9][0-9]* unknownoid.example./\1 ${tag} unknownoid.example./" <"${zonefile}.stage2" >"${zonefile}.signed"
#
# A PRIVATEOID zone with a extra DS record for a non-existent DNSKEY.
#
zone=extradsoid.example.
infile=extradsoid.example.db.in
zonefile=extradsoid.example.db
keyname=$("$KEYGEN" -q -a RSASHA512OID "$zone")
cat "$infile" "$keyname.key" >"$zonefile"
"$SIGNER" -z -o "$zone" "$zonefile" >/dev/null
# add a DS for a second key with the same algorithm
keyname=$("$KEYGEN" -q -a RSASHA512OID "$zone")
"$DSFROMKEY" -2A "$keyname.key" >>"dsset-$zone"
#
# A UNKNOWNOID with an extra DS zone. Sign the zone using RSASHA512OID
# then update the OID in the DNSKEY and RRSIGS to the unknown OID
# 1.2.840.113549.1.1.14. Add an additional DS which does not match
# the DNSKEY RRset with using this unknown OID.
#
zone=extradsunknownoid.example
infile=extradsunknownoid.example.db.in
zonefile=extradsunknownoid.example.db
keyname=$("$KEYGEN" -q -a RSASHA512OID "$zone")
cat "$infile" "$keyname.key" >"$zonefile"
# Sign with known OID RSASHA512OID
"$SIGNER" -z -o "$zone" -f "${zonefile}.stage1" "$zonefile" >/dev/null
# Change OID from 1.2.840.113549.1.1.13 to 1.2.840.113549.1.1.14
sed 's/CwYJKoZIhvcN/CwYJKoZIhvcO/' <"${zonefile}.stage1" >"${zonefile}.stage2"
"$DSFROMKEY" -2A -f "${zonefile}.stage2" "$zone" >"dsset-${zone}."
tag=$(awk '{print $4}' "dsset-${zone}.")
# Update RRSIG tags
sed "s/\(2[0-9]* 2[0-9]*\) [1-9][0-9]* extradsunknownoid.example./\1 ${tag} extradsunknownoid.example./" <"${zonefile}.stage2" >"${zonefile}.signed"
# add a DS for a second key with the same algorithm
keyname=$("$KEYGEN" -L 300 -q -a RSASHA512OID "$zone")
# Change OID from 1.2.840.113549.1.1.13 to 1.2.840.113549.1.1.14 and
# add the resulting DS to the dsset.
sed 's/CwYJKoZIhvcN/CwYJKoZIhvcO/' <"$keyname.key" | "$DSFROMKEY" -2A -f - "$zone" >>"dsset-${zone}."
#
# A UNKNOWNOID with an extra DS zone. Sign the zone using RSASHA512OID
# then update the OID in the DNSKEY and RRSIGS to the unknown OID
# 1.2.840.113549.1.1.14. Add an additional DS with an extended digest
# type that encoded the DNSKEY's private type identifier which does not
# match the DNSKEY RRset with using this unknown OID.
#
zone=extended-ds-unknown-oid.example
infile=extended-ds-unknown-oid.example.db.in
zonefile=extended-ds-unknown-oid.example.db
keyname=$("$KEYGEN" -q -a RSASHA512OID "$zone")
cat "$infile" "$keyname.key" >"$zonefile"
# Sign with known OID RSASHA512OID
"$SIGNER" -z -o "$zone" -f "${zonefile}.stage1" "$zonefile" >/dev/null
# Change OID from 1.2.840.113549.1.1.13 to 1.2.840.113549.1.1.14
sed 's/CwYJKoZIhvcN/CwYJKoZIhvcO/' <"${zonefile}.stage1" >"${zonefile}.stage2"
"$DSFROMKEY" -2A -f "${zonefile}.stage2" "$zone" >"dsset-${zone}."
tag=$(awk '{print $4}' "dsset-${zone}.")
# Update RRSIG tags
sed "s/\(2[0-9]* 2[0-9]*\) [1-9][0-9]* ${zone}./\1 ${tag} ${zone}./" <"${zonefile}.stage2" >"${zonefile}.signed"
if $FEATURETEST --extended-ds-digest; then
# add a DS for a second key with the same algorithm
keyname=$("$KEYGEN" -L 300 -q -a RSASHA512OID "$zone")
# Change OID from 1.2.840.113549.1.1.13 to 1.2.840.113549.1.1.14 and
# add the resulting DS using digest type SHA-256-PRIVATE to the dsset.
sed 's/CwYJKoZIhvcN/CwYJKoZIhvcO/' <"$keyname.key" | "$DSFROMKEY" -a SHA-256-PRIVATE -A -f - "$zone" >>"dsset-${zone}."
fi
#
# A zone with the DNSKEY set only signed by the KSK
#

View file

@ -0,0 +1,28 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
2009102722 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns
ns A 10.53.0.3
a A 10.0.0.1
b A 10.0.0.2
d A 10.0.0.4
z A 10.0.0.26
a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
x CNAME a

View file

@ -53,18 +53,20 @@ dnssec_loadkeys_on() {
# convert private-type records to readable form
showprivate() {
echo "-- $* --"
dig_with_opts +nodnssec +short "@$2" -t type65534 "$1" | cut -f3 -d' ' \
| while read -r record; do
# shellcheck disable=SC2016
$PERL -e 'my $rdata = pack("H*", @ARGV[0]);
die "invalid record" unless length($rdata) == 5;
my ($alg, $key, $remove, $complete) = unpack("CnCC", $rdata);
my $action = "signing";
$action = "removing" if $remove;
my $state = " (incomplete)";
$state = " (complete)" if $complete;
print ("$action: alg: $alg, key: $key$state\n");' "$record"
done
dig_with_opts +nodnssec +short "@$2" -t type65534 "$1" >dig.out.$1.test$n
cut -f3 -d' ' <dig.out.$1.$n | while read -r record; do
# shellcheck disable=SC2016
$PERL -e 'my $rdata = pack("H*", @ARGV[0]);
die "invalid record" unless length($rdata) == 5 || length($rdata) == 7;
my ($dns, $key, $remove, $complete, $alg) = unpack("CnCCn", $rdata);
die "invalid record" unless $dns != 0;
my $action = "signing";
$action = "removing" if $remove;
my $state = " (incomplete)";
$state = " (complete)" if $complete;
$alg = $dns if ! defined($alg);
print ("$action: alg: $alg, key: $key$state\n");' "$record"
done
}
# check that signing records are marked as complete
@ -958,6 +960,80 @@ n=$((n + 1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
echo_i "checking positive validation with private algorithm works ($n)"
ret=0
dig_with_opts +noauth a.rsasha256oid.example. \
@10.53.0.3 a >dig.out.ns3.test$n || ret=1
dig_with_opts +noauth a.rsasha256oid.example. \
@10.53.0.4 a >dig.out.ns4.test$n || ret=1
digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n >/dev/null || ret=1
n=$((n + 1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
if [ -x "${DELV}" ]; then
ret=0
echo_i "checking positive validation NSEC3 using dns_client ($n)"
delv_with_opts @10.53.0.4 a a.nsec3.example >delv.out$n || ret=1
grep "a.nsec3.example..*10.0.0.1" delv.out$n >/dev/null || ret=1
grep "a.nsec3.example..*RRSIG.A [0-9][0-9]* 3 300.*" delv.out$n >/dev/null || ret=1
n=$((n + 1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
fi
echo_i "checking positive validation with unknown private algorithm works ($n)"
ret=0
dig_with_opts +noauth a.unknownoid.example. \
@10.53.0.3 a >dig.out.ns3.test$n || ret=1
dig_with_opts +noauth a.unknownoid.example. \
@10.53.0.4 a >dig.out.ns4.test$n || ret=1
digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n >/dev/null && ret=1
n=$((n + 1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
echo_i "checking positive validation with extra ds for private algorithm ($n)"
ret=0
dig_with_opts +noauth a.extradsoid.example. \
@10.53.0.3 a >dig.out.ns3.test$n || ret=1
dig_with_opts +noauth a.extradsoid.example. \
@10.53.0.4 a >dig.out.ns4.test$n || ret=1
digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n >/dev/null || ret=1
n=$((n + 1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
echo_i "checking positive validation with extra ds for unknown private algorithm fails ($n)"
ret=0
dig_with_opts +noauth a.extradsunknownoid.example. \
@10.53.0.3 a >dig.out.ns3.test$n || ret=1
dig_with_opts +noauth a.extradsunknownoid.example. \
@10.53.0.4 a >dig.out.ns4.test$n || ret=1
grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
grep "status: SERVFAIL" dig.out.ns4.test$n >/dev/null || ret=1
grep 'No DNSKEY for extradsunknownoid.example/DS with PRIVATEOID algorithm, tag [1-9][0-9]*$' ns4/named.run >/dev/null || ret=1
n=$((n + 1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
if $FEATURETEST --extended-ds-digest; then
echo_i "checking positive validation with extra ds using extended digest type for unknown private algorithm succeeds ($n)"
ret=0
dig_with_opts +noauth a.extended-ds-unknown-oid.example. \
@10.53.0.3 a >dig.out.ns3.test$n || ret=1
dig_with_opts +noauth a.extended-ds-unknown-oid.example. \
@10.53.0.4 a >dig.out.ns4.test$n || ret=1
digcomp dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n >/dev/null && ret=1
n=$((n + 1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
fi
# Check the bogus domain
echo_i "checking failed validation ($n)"
@ -3479,7 +3555,7 @@ status=$((status + ret))
echo_i "check that 'dnssec-keygen -S' works for all supported algorithms ($n)"
ret=0
alg=1
until test $alg -eq 256; do
until test $alg -eq 258; do
zone="keygen-$alg."
case $alg in
2) # Diffie Helman
@ -3496,10 +3572,20 @@ until test $alg -eq 256; do
15 | 16)
key1=$($KEYGEN -a "$alg" "$zone" 2>"keygen-$alg.err" || true)
;;
256)
key1=$($KEYGEN -a "RSASHA256OID" "$zone" 2>"keygen-$alg.err" || true)
;;
257)
key1=$($KEYGEN -a "RSASHA512OID" "$zone" 2>"keygen-$alg.err" || true)
;;
*)
key1=$($KEYGEN -a "$alg" "$zone" 2>"keygen-$alg.err" || true)
;;
esac
if grep "unknown algorithm" "keygen-$alg.err" >/dev/null; then
alg=$((alg + 1))
continue
fi
if grep "unsupported algorithm" "keygen-$alg.err" >/dev/null; then
alg=$((alg + 1))
continue

View file

@ -84,6 +84,7 @@ pytestmark = pytest.mark.extra_artifacts(
"ns3/auto-nsec3.example.db",
"ns3/badds.example.db",
"ns3/bogus.example.db",
"ns3/digest-alg-unsupported.example.db",
"ns3/disabled.managed.db",
"ns3/disabled.trusted.db",
"ns3/dname-at-apex-nsec3.example.db",
@ -94,13 +95,20 @@ pytestmark = pytest.mark.extra_artifacts(
"ns3/dnskey-unsupported-2.example.db",
"ns3/dnskey-unsupported.example.db",
"ns3/dnskey-unsupported.example.db.tmp",
"ns3/ds-unsupported.example.db",
"ns3/dynamic.example.db",
"ns3/digest-alg-unsupported.example.db",
"ns3/enabled.managed.db",
"ns3/enabled.trusted.db",
"ns3/example.bk",
"ns3/expired.example.db",
"ns3/expiring.example.db",
"ns3/extended-ds-unknown-oid.example.db",
"ns3/extended-ds-unknown-oid.example.db.stage1",
"ns3/extended-ds-unknown-oid.example.db.stage2",
"ns3/extradsoid.example.db",
"ns3/extradsunknownoid.example.db",
"ns3/extradsunknownoid.example.db.stage1",
"ns3/extradsunknownoid.example.db.stage2",
"ns3/future.example.db",
"ns3/keyless.example.db",
"ns3/kskonly.example.db",
@ -123,7 +131,9 @@ pytestmark = pytest.mark.extra_artifacts(
"ns3/revoked.trusted.db",
"ns3/rfc2335.example.bk",
"ns3/rsasha256.example.db",
"ns3/rsasha256oid.example.db",
"ns3/rsasha512.example.db",
"ns3/rsasha512oid.example.db",
"ns3/secure.below-cname.example.db",
"ns3/secure.example.db",
"ns3/secure.managed.db",
@ -138,6 +148,9 @@ pytestmark = pytest.mark.extra_artifacts(
"ns3/trusted-future.key",
"ns3/ttlpatch.example.db",
"ns3/ttlpatch.example.db.patched",
"ns3/unknownoid.example.db",
"ns3/unknownoid.example.db.stage1",
"ns3/unknownoid.example.db.stage2",
"ns3/unsupported.managed.db",
"ns3/unsupported.managed.db.tmp",
"ns3/unsupported.trusted.db",
@ -146,7 +159,6 @@ pytestmark = pytest.mark.extra_artifacts(
"ns3/update-nsec3.example.db.signed",
"ns3/upper.example.db",
"ns3/upper.example.db.lower",
"ns3/ds-unsupported.example.db",
"ns4/broken.conf",
"ns4/managed.conf",
"ns4/managed-keys.bind",

View file

@ -30,6 +30,7 @@
#include <isc/net.h>
#include <isc/util.h>
#include <dns/ds.h>
#include <dns/edns.h>
#include <dns/lib.h>
@ -42,6 +43,7 @@ usage(void) {
fprintf(stderr, "\t--edns-version\n");
fprintf(stderr, "\t--enable-dnstap\n");
fprintf(stderr, "\t--enable-querytrace\n");
fprintf(stderr, "\t--extended-ds-digest\n");
fprintf(stderr, "\t--fips-provider\n");
fprintf(stderr, "\t--gethostname\n");
fprintf(stderr, "\t--gssapi\n");
@ -93,6 +95,14 @@ main(int argc, char **argv) {
#endif /* ifdef WANT_QUERYTRACE */
}
if (strcasecmp(argv[1], "--extended-ds-digest") == 0) {
#if defined(DNS_DSDIGEST_SHA256PRIVATE) && defined(DNS_DSDIGEST_SHA384PRIVATE)
return 0;
#else
return 1;
#endif
}
if (strcasecmp(argv[1], "--fips-provider") == 0) {
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
OSSL_PROVIDER *fips = OSSL_PROVIDER_load(NULL, "fips");

View file

@ -390,6 +390,14 @@ class Key:
return ksigning, zsigning
def get_dnsalg(self) -> int:
alg = int(self.get_metadata("Algorithm"))
if alg == isctest.vars.algorithms.RSASHA256OID.dst:
return isctest.vars.algorithms.RSASHA256OID.number
if alg == isctest.vars.algorithms.RSASHA512OID.dst:
return isctest.vars.algorithms.RSASHA512OID.number
return alg
def ttl(self) -> int:
with open(self.keyfile, "r", encoding="utf-8") as file:
for line in file:
@ -810,7 +818,7 @@ def _check_signatures(
offline_ksk=offline_ksk, zsk_missing=zsk_missing, smooth=smooth
)
alg = key.get_metadata("Algorithm")
alg = key.get_dnsalg()
rtype = dns.rdatatype.to_text(covers)
expect = rf"IN RRSIG {rtype} {alg} (\d) (\d+) (\d+) (\d+) {key.tag} {fqdn}"

View file

@ -30,17 +30,20 @@ ALG_VARS = {
"ALGORITHM_SET": "none",
"DEFAULT_ALGORITHM": "",
"DEFAULT_ALGORITHM_NUMBER": "",
"DEFAULT_ALGORITHM_DST_NUMBER": "",
"DEFAULT_BITS": "",
# Alternative algorithm for test cases that require more than one algorithm
# (for example algorithm rollover). Must be different from
# DEFAULT_ALGORITHM.
"ALTERNATIVE_ALGORITHM": "",
"ALTERNATIVE_ALGORITHM_NUMBER": "",
"ALTERNATIVE_ALGORITHM_DST_NUMBER": "",
"ALTERNATIVE_BITS": "",
# Algorithm that is used for tests against the "disable-algorithms"
# configuration option. Must be different from above algorithms.
"DISABLED_ALGORITHM": "",
"DISABLED_ALGORITHM_NUMBER": "",
"DISABLED_ALGORITHM_DST_NUMBER": "",
"DISABLED_BITS": "",
# Default HMAC algorithm. Must match the rndc configuration in
# bin/tests/system/_common (rndc.conf, rndc.key)
@ -54,6 +57,7 @@ STABLE_PERIOD = 3600 * 3
class Algorithm(NamedTuple):
name: str
number: int
dst: int
bits: int
@ -72,13 +76,15 @@ class AlgorithmSet(NamedTuple):
"disable-algorithms" configuration option."""
RSASHA1 = Algorithm("RSASHA1", 5, 2048)
RSASHA256 = Algorithm("RSASHA256", 8, 2048)
RSASHA512 = Algorithm("RSASHA512", 10, 2048)
ECDSAP256SHA256 = Algorithm("ECDSAP256SHA256", 13, 256)
ECDSAP384SHA384 = Algorithm("ECDSAP384SHA384", 14, 384)
ED25519 = Algorithm("ED25519", 15, 256)
ED448 = Algorithm("ED448", 16, 456)
RSASHA1 = Algorithm("RSASHA1", 5, 5, 2048)
RSASHA256 = Algorithm("RSASHA256", 8, 8, 2048)
RSASHA512 = Algorithm("RSASHA512", 10, 10, 2048)
ECDSAP256SHA256 = Algorithm("ECDSAP256SHA256", 13, 13, 256)
ECDSAP384SHA384 = Algorithm("ECDSAP384SHA384", 14, 14, 384)
ED25519 = Algorithm("ED25519", 15, 15, 256)
ED448 = Algorithm("ED448", 16, 16, 456)
RSASHA256OID = Algorithm("RSASHA256OID", 254, 256, 2048)
RSASHA512OID = Algorithm("RSASHA512OID", 254, 257, 2048)
ALL_ALGORITHMS = [
RSASHA1,
@ -88,6 +94,8 @@ ALL_ALGORITHMS = [
ECDSAP384SHA384,
ED25519,
ED448,
RSASHA256OID,
RSASHA512OID,
]
ALL_ALGORITHMS_BY_NUM = {alg.number: alg for alg in ALL_ALGORITHMS}
@ -149,6 +157,8 @@ CRYPTO_SUPPORTED_VARS = {
"ECDSAP384SHA384_SUPPORTED": "0",
"ED25519_SUPPORTED": "0",
"ED448_SUPPORTED": "0",
"RSASHA256OID_SUPPORTED": "0",
"RSASHA512OID_SUPPORTED": "0",
}
SUPPORTED_ALGORITHMS: List[Algorithm] = []
@ -250,6 +260,7 @@ def _algorithms_env(algs: AlgorithmSet, name: str) -> Dict[str, str]:
def set_alg_env(alg: Algorithm, prefix):
algs_env[f"{prefix}_ALGORITHM"] = alg.name
algs_env[f"{prefix}_ALGORITHM_NUMBER"] = str(alg.number)
algs_env[f"{prefix}_ALGORITHM_DST_NUMBER"] = str(alg.dst)
algs_env[f"{prefix}_BITS"] = str(alg.bits)
assert isinstance(algs.default, Algorithm)

View file

@ -105,7 +105,7 @@ def ksr(zone, policy, action, options="", raise_on_exception=True):
def check_keys(
keys,
lifetime,
alg=os.environ["DEFAULT_ALGORITHM_NUMBER"],
alg=os.environ["DEFAULT_ALGORITHM_DST_NUMBER"],
size=os.environ["DEFAULT_BITS"],
offset=0,
with_state=False,
@ -246,7 +246,7 @@ def check_rrsig_bundle(bundle_keys, bundle_lines, zone, rrtype, sigend, sigstart
count = 0
for key in bundle_keys:
found = False
alg = key.get_metadata("Algorithm")
alg = key.get_dnsalg()
expect = f"{zone}. 3600 IN RRSIG {rrtype} {alg} 2 3600 {sigend} {sigstart} {key.tag} {zone}."
# there must be a signature of this ksk
for line in bundle_lines:
@ -1125,9 +1125,9 @@ def test_ksr_twotone(servers):
ksks_altalg = []
for ksk in ksks:
alg = ksk.get_metadata("Algorithm")
if alg == os.environ.get("DEFAULT_ALGORITHM_NUMBER"):
if alg == os.environ.get("DEFAULT_ALGORITHM_DST_NUMBER"):
ksks_defalg.append(ksk)
elif alg == os.environ.get("ALTERNATIVE_ALGORITHM_NUMBER"):
elif alg == os.environ.get("ALTERNATIVE_ALGORITHM_DST_NUMBER"):
ksks_altalg.append(ksk)
assert len(ksks_defalg) == 1
@ -1135,7 +1135,7 @@ def test_ksr_twotone(servers):
check_keys(ksks_defalg, None)
alg = os.environ.get("ALTERNATIVE_ALGORITHM_NUMBER")
alg = os.environ.get("ALTERNATIVE_ALGORITHM_DST_NUMBER")
size = os.environ.get("ALTERNATIVE_BITS")
check_keys(ksks_altalg, None, alg, size)
@ -1154,9 +1154,9 @@ def test_ksr_twotone(servers):
zsks_altalg = []
for zsk in zsks:
alg = zsk.get_metadata("Algorithm")
if alg == os.environ.get("DEFAULT_ALGORITHM_NUMBER"):
if alg == os.environ.get("DEFAULT_ALGORITHM_DST_NUMBER"):
zsks_defalg.append(zsk)
elif alg == os.environ.get("ALTERNATIVE_ALGORITHM_NUMBER"):
elif alg == os.environ.get("ALTERNATIVE_ALGORITHM_DST_NUMBER"):
zsks_altalg.append(zsk)
assert len(zsks_defalg) == 4
@ -1165,7 +1165,7 @@ def test_ksr_twotone(servers):
lifetime = timedelta(days=31 * 3)
check_keys(zsks_defalg, lifetime)
alg = os.environ.get("ALTERNATIVE_ALGORITHM_NUMBER")
alg = os.environ.get("ALTERNATIVE_ALGORITHM_DST_NUMBER")
size = os.environ.get("ALTERNATIVE_BITS")
lifetime = timedelta(days=31 * 5)
check_keys(zsks_altalg, lifetime, alg, size)
@ -1216,7 +1216,7 @@ def test_ksr_twotone(servers):
lifetime = timedelta(days=31 * 3)
check_keys(zsks_defalg, lifetime, with_state=True)
alg = os.environ.get("ALTERNATIVE_ALGORITHM_NUMBER")
alg = os.environ.get("ALTERNATIVE_ALGORITHM_DST_NUMBER")
size = os.environ.get("ALTERNATIVE_BITS")
lifetime = timedelta(days=31 * 5)
check_keys(zsks_altalg, lifetime, alg, size, with_state=True)

View file

@ -224,7 +224,7 @@ dns_dnssec_sign(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
dns_name_clone(dns_fixedname_name(&fsigner), &sig.signer);
sig.covered = set->type;
sig.algorithm = dst_key_alg(key);
sig.algorithm = dst_algorithm_tosecalg(dst_key_alg(key));
sig.labels = dns_name_countlabels(name) - 1;
if (dns_name_iswildcard(name)) {
sig.labels--;
@ -762,7 +762,7 @@ dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
ISC_LINK_INIT(&sig.common, link);
sig.covered = 0;
sig.algorithm = dst_key_alg(key);
sig.algorithm = dst_algorithm_tosecalg(dst_key_alg(key));
sig.labels = 0; /* the root name */
sig.originalttl = 0;
@ -1469,7 +1469,7 @@ mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
dns_rdataset_clone(rrsigs, &sigs);
ISC_LIST_FOREACH (*keylist, key, link) {
uint16_t keyid, sigid;
dns_secalg_t keyalg, sigalg;
dst_algorithm_t keyalg, sigalg;
keyid = dst_key_id(key->key);
keyalg = dst_key_alg(key->key);
@ -1480,7 +1480,8 @@ mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
dns_rdataset_current(&sigs, &rdata);
result = dns_rdata_tostruct(&rdata, &sig, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
sigalg = sig.algorithm;
sigalg = dst_algorithm_fromdata(
sig.algorithm, sig.signature, sig.siglen);
sigid = sig.keyid;
if (keyid == sigid && keyalg == sigalg) {
key->is_active = true;
@ -1544,14 +1545,23 @@ dns_dnssec_keylistfromrdataset(const dns_name_t *origin, dns_kasp_t *kasp,
dns_rdataset_clone(keyset, &keys);
DNS_RDATASET_FOREACH (&keys) {
dns_rdata_t rdata = DNS_RDATA_INIT;
dst_algorithm_t algorithm;
dns_rdata_dnskey_t keystruct;
dns_rdataset_current(&keys, &rdata);
REQUIRE(rdata.type == dns_rdatatype_key ||
rdata.type == dns_rdatatype_dnskey);
REQUIRE(rdata.length > 3);
result = dns_rdata_tostruct(&rdata, &keystruct, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
algorithm = dst_algorithm_fromdata(
keystruct.algorithm, keystruct.data, keystruct.datalen);
/* Skip unsupported algorithms */
if (!dst_algorithm_supported(rdata.data[3])) {
if (!dst_algorithm_supported(algorithm)) {
goto skip;
}
@ -1831,7 +1841,8 @@ add_cds(dns_dnsseckey_t *key, dns_rdata_t *keyrdata, const char *keystr,
dns_rdata_t cdsrdata = DNS_RDATA_INIT;
dns_name_t *origin = dst_key_name(key->key);
r = dns_ds_buildrdata(origin, keyrdata, digesttype, dsbuf, &cdsrdata);
r = dns_ds_buildrdata(origin, keyrdata, digesttype, dsbuf,
sizeof(dsbuf), &cdsrdata);
if (r != ISC_R_SUCCESS) {
char algbuf[DNS_DSDIGEST_FORMATSIZE];
dns_dsdigest_format(digesttype, algbuf,
@ -1866,7 +1877,8 @@ delete_cds(dns_dnsseckey_t *key, dns_rdata_t *keyrdata, const char *keystr,
dns_rdata_t cdsrdata = DNS_RDATA_INIT;
dns_name_t *origin = dst_key_name(key->key);
r = dns_ds_buildrdata(origin, keyrdata, digesttype, dsbuf, &cdsrdata);
r = dns_ds_buildrdata(origin, keyrdata, digesttype, dsbuf,
sizeof(dsbuf), &cdsrdata);
if (r != ISC_R_SUCCESS) {
return r;
}
@ -2354,7 +2366,7 @@ dns_dnssec_matchdskey(dns_name_t *name, dns_rdata_t *dsrdata,
}
result = dns_ds_buildrdata(name, keyrdata, ds.digest_type, buf,
&newdsrdata);
sizeof(buf), &newdsrdata);
if (result != ISC_R_SUCCESS) {
continue;
}

View file

@ -23,6 +23,7 @@
#include <dns/ds.h>
#include <dns/fixedname.h>
#include <dns/keyvalues.h>
#include <dns/name.h>
#include <dns/rdata.h>
#include <dns/rdatastruct.h>
@ -32,11 +33,12 @@
isc_result_t
dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key,
dns_dsdigest_t digest_type, unsigned char *digest,
dns_rdata_ds_t *dsrdata) {
size_t len, dns_rdata_ds_t *dsrdata) {
isc_result_t result;
dns_fixedname_t fname;
dns_name_t *name;
unsigned int digestlen;
unsigned int digestlen = 0;
unsigned int privatelen = 0;
isc_region_t r;
isc_md_t *md;
const isc_md_type_t *md_type = NULL;
@ -44,6 +46,7 @@ dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key,
REQUIRE(key != NULL);
REQUIRE(key->type == dns_rdatatype_dnskey ||
key->type == dns_rdatatype_cdnskey);
REQUIRE(digest != NULL);
if (!dst_ds_digest_supported(digest_type)) {
return ISC_R_NOTIMPLEMENTED;
@ -55,10 +58,16 @@ dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key,
break;
case DNS_DSDIGEST_SHA384:
#ifdef DNS_DSDIGEST_SHA384PRIVATE
case DNS_DSDIGEST_SHA384PRIVATE:
#endif
md_type = ISC_MD_SHA384;
break;
case DNS_DSDIGEST_SHA256:
#ifdef DNS_DSDIGEST_SHA256PRIVATE
case DNS_DSDIGEST_SHA256PRIVATE:
#endif
md_type = ISC_MD_SHA256;
break;
@ -91,6 +100,64 @@ dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key,
goto end;
}
#if defined(DNS_DSDIGEST_SHA256PRIVATE) && defined(DNS_DSDIGEST_SHA384PRIVATE)
/*
* Insert PRIVATE algorithm identify at start of digest.
*/
switch (digest_type) {
case DNS_DSDIGEST_SHA1:
case DNS_DSDIGEST_SHA256:
case DNS_DSDIGEST_SHA384:
break;
case DNS_DSDIGEST_SHA256PRIVATE:
case DNS_DSDIGEST_SHA384PRIVATE:
switch (r.base[3]) {
case DNS_KEYALG_PRIVATEDNS: {
isc_region_t r2 = r;
INSIST(r2.length >= 5);
isc_region_consume(&r2, 4);
dns_name_fromregion(name, &r2);
dns_name_toregion(name, &r2);
privatelen = r2.length;
if (r2.length > len) {
result = ISC_R_NOSPACE;
goto end;
}
memmove(digest, r2.base, privatelen);
digest += privatelen;
len -= privatelen;
break;
}
case DNS_KEYALG_PRIVATEOID: {
isc_region_t r2 = r;
INSIST(r2.length >= 5);
isc_region_consume(&r2, 4);
privatelen = r2.base[0] + 1;
if (r2.base[0] > len) {
result = ISC_R_NOSPACE;
goto end;
}
INSIST(r2.length >= privatelen);
memmove(digest, r2.base, privatelen);
digest += privatelen;
len -= privatelen;
break;
}
default:
break;
}
break;
default:
break;
}
#endif
size_t mdsize = isc_md_get_size(md);
if (mdsize > len) {
result = ISC_R_NOSPACE;
goto end;
}
result = isc_md_final(md, digest, &digestlen);
if (result != ISC_R_SUCCESS) {
goto end;
@ -102,8 +169,8 @@ dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key,
dsrdata->algorithm = r.base[3];
dsrdata->key_tag = dst_region_computeid(&r);
dsrdata->digest_type = digest_type;
dsrdata->digest = digest;
dsrdata->length = digestlen;
dsrdata->digest = digest - privatelen;
dsrdata->length = digestlen + privatelen;
end:
isc_md_free(md);
@ -112,14 +179,14 @@ end:
isc_result_t
dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key,
dns_dsdigest_t digest_type, unsigned char *buffer,
dns_dsdigest_t digest_type, unsigned char *buffer, size_t len,
dns_rdata_t *rdata) {
isc_result_t result;
unsigned char digest[ISC_MAX_MD_SIZE];
dns_rdata_ds_t ds;
isc_buffer_t b;
result = dns_ds_fromkeyrdata(owner, key, digest_type, digest, &ds);
result = dns_ds_fromkeyrdata(owner, key, digest_type, digest, len, &ds);
if (result != ISC_R_SUCCESS) {
return result;
}

View file

@ -140,6 +140,14 @@ static const char *keystates[KEYSTATES_NVALUES] = {
static dst_func_t *dst_t_func[DST_MAX_ALGS] = { 0 };
/* length byte + 1.2.840.113549.1.1.11 BER encoded RFC 4055 */
static unsigned char oid_rsasha256[] = { 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b };
/* length byte + 1.2.840.113549.1.1.13 BER encoded RFC 4055 */
static unsigned char oid_rsasha512[] = { 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d };
void
gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
@ -215,6 +223,18 @@ dst__lib_initialize(void) {
#if HAVE_GSSAPI
dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI]);
#endif /* HAVE_GSSAPI */
/*
* RSASHA256 using assigned OID 1.2.840.113549.1.1.11 as
* a private OID example.
*/
dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA256PRIVATEOID],
DST_ALG_RSASHA256PRIVATEOID);
/*
* RSASHA512 using assigned OID 1.2.840.113549.1.1.13 as
* a private OID example.
*/
dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA512PRIVATEOID],
DST_ALG_RSASHA512PRIVATEOID);
}
void
@ -233,7 +253,13 @@ dst_algorithm_supported(unsigned int alg) {
bool
dst_ds_digest_supported(unsigned int digest_type) {
return digest_type == DNS_DSDIGEST_SHA1 ||
#if defined(DNS_DSDIGEST_SHA256PRIVATE)
digest_type == DNS_DSDIGEST_SHA256PRIVATE ||
#endif
digest_type == DNS_DSDIGEST_SHA256 ||
#if defined(DNS_DSDIGEST_SHA256PRIVATE)
digest_type == DNS_DSDIGEST_SHA384PRIVATE ||
#endif
digest_type == DNS_DSDIGEST_SHA384;
}
@ -645,7 +671,8 @@ dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
}
isc_buffer_putuint16(target, (uint16_t)(key->key_flags & 0xffff));
isc_buffer_putuint8(target, (uint8_t)key->key_proto);
isc_buffer_putuint8(target, (uint8_t)key->key_alg);
isc_buffer_putuint8(target,
(uint8_t)dst_algorithm_tosecalg(key->key_alg));
if ((key->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
if (isc_buffer_availablelength(target) < 2) {
@ -1304,6 +1331,12 @@ dst_key_sigsize(const dst_key_t *key, unsigned int *n) {
case DST_ALG_RSASHA512:
*n = (key->key_size + 7) / 8;
break;
case DST_ALG_RSASHA256PRIVATEOID:
*n = (key->key_size + 7) / 8 + sizeof(oid_rsasha256);
break;
case DST_ALG_RSASHA512PRIVATEOID:
*n = (key->key_size + 7) / 8 + sizeof(oid_rsasha512);
break;
case DST_ALG_ECDSA256:
*n = DNS_SIG_ECDSA256SIZE;
break;
@ -1357,10 +1390,10 @@ void
dst_key_format(const dst_key_t *key, char *cp, unsigned int size) {
char namestr[DNS_NAME_FORMATSIZE];
char algstr[DNS_NAME_FORMATSIZE];
dst_algorithm_t algorithm = dst_key_alg(key);
dns_name_format(dst_key_name(key), namestr, sizeof(namestr));
dns_secalg_format((dns_secalg_t)dst_key_alg(key), algstr,
sizeof(algstr));
dst_algorithm_format(algorithm, algstr, sizeof(algstr));
snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key));
}
@ -2107,6 +2140,8 @@ buildfilename(dns_name_t *name, dns_keytag_t id, unsigned int alg,
isc_result_t result;
REQUIRE(out != NULL);
REQUIRE(alg != 0 && alg != DST_ALG_PRIVATEOID &&
alg != DST_ALG_PRIVATEDNS);
if ((type & DST_TYPE_PRIVATE) != 0) {
suffix = ".private";
@ -2172,6 +2207,22 @@ frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
REQUIRE(mctx != NULL);
REQUIRE(keyp != NULL && *keyp == NULL);
if (alg == DNS_KEYALG_PRIVATEDNS) {
isc_buffer_t b = *source;
alg = dst_algorithm_fromprivatedns(&b);
if (alg == 0) {
return DST_R_UNSUPPORTEDALG;
}
}
if (alg == DNS_KEYALG_PRIVATEOID) {
isc_buffer_t b = *source;
alg = dst_algorithm_fromprivateoid(&b);
if (alg == 0) {
return DST_R_UNSUPPORTEDALG;
}
}
key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
if (isc_buffer_remaininglength(source) > 0) {
@ -2636,3 +2687,115 @@ dst_hmac_algorithm_totext(dst_algorithm_t alg) {
return "unknown";
}
}
dns_secalg_t
dst_algorithm_tosecalg(dst_algorithm_t dst_alg) {
static dns_secalg_t dns_alg[DST_MAX_ALGS] = {
[DST_ALG_RSASHA256PRIVATEOID] = DNS_KEYALG_PRIVATEOID,
[DST_ALG_RSASHA512PRIVATEOID] = DNS_KEYALG_PRIVATEOID,
};
if (dst_alg < 256) {
return dst_alg;
}
if (dst_alg < DST_MAX_ALGS) {
return dns_alg[dst_alg];
}
return 0;
}
#if TEST_PRIVATEDNS
/*
* These are examples of specifying an algorithm using
* PRIVATEDNS. When creating such an algorithm, use your
* organisation's domain name instead of "example.org"
* so the identifier will be globally unique.
*/
static unsigned char rsasha256dns_data[] = "\011rsasha256\007example\003org";
static dns_name_t const rsasha256dns = DNS_NAME_INITABSOLUTE(rsasha256dns_data);
static unsigned char rsasha512dns_data[] = "\011rsasha512\007example\003org";
static dns_name_t const rsasha512dns = DNS_NAME_INITABSOLUTE(rsasha512dns_data);
#endif
dst_algorithm_t
dst_algorithm_fromprivatedns(isc_buffer_t *buffer) {
dns_fixedname_t fixed;
dns_name_t *name = dns_fixedname_initname(&fixed);
isc_result_t result;
result = dns_name_fromwire(name, buffer, DNS_DECOMPRESS_DEFAULT, NULL);
if (result != ISC_R_SUCCESS) {
return 0;
}
/*
* Do name to dst_algorithm number mapping here.
*/
switch (name->length) {
#if TEST_PRIVATEDNS
case 23:
switch (name->ndata[7]) {
case '2':
if (dns_name_equal(name, &rsasha256dns)) {
return DST_ALG_RSASHA256PRIVATEDNS;
}
break;
case '5':
if (dns_name_equal(name, &rsasha512dns)) {
return DST_ALG_RSASHA512PRIVATEDNS;
}
break;
}
break;
#endif
default:
break;
}
return 0;
}
dst_algorithm_t
dst_algorithm_fromprivateoid(isc_buffer_t *buffer) {
isc_region_t r;
isc_buffer_remainingregion(buffer, &r);
/*
* Do OID to dst_algorithm number mapping here. There is a
* length byte followed by the OID of that length.
*/
if (r.length > 0 && ((unsigned int)r.base[0] + 1) <= r.length) {
if (r.base[0] + 1 == sizeof(oid_rsasha256) &&
memcmp(oid_rsasha256, r.base, sizeof(oid_rsasha256)) == 0)
{
return DST_ALG_RSASHA256PRIVATEOID;
}
if (r.base[0] + 1 == sizeof(oid_rsasha512) &&
memcmp(oid_rsasha512, r.base, sizeof(oid_rsasha512)) == 0)
{
return DST_ALG_RSASHA512PRIVATEOID;
}
}
return 0;
}
dst_algorithm_t
dst_algorithm_fromdata(dns_secalg_t algorithm, unsigned char *data,
unsigned int length) {
isc_buffer_t b;
switch (algorithm) {
case DNS_KEYALG_PRIVATEDNS:
isc_buffer_init(&b, data, length);
isc_buffer_add(&b, length);
return dst_algorithm_fromprivatedns(&b);
case DNS_KEYALG_PRIVATEOID:
isc_buffer_init(&b, data, length);
isc_buffer_add(&b, length);
return dst_algorithm_fromprivateoid(&b);
default:
return algorithm;
}
}

View file

@ -193,7 +193,7 @@ dst__hmacsha384_init(struct dst_func **funcp);
void
dst__hmacsha512_init(struct dst_func **funcp);
void
dst__opensslrsa_init(struct dst_func **funcp, unsigned char algorithm);
dst__opensslrsa_init(struct dst_func **funcp, unsigned short algorithm);
void
dst__opensslecdsa_init(struct dst_func **funcp);
void

View file

@ -332,6 +332,8 @@ check_data(const dst_private_t *priv, const unsigned int alg, bool old,
case DST_ALG_NSEC3RSASHA1:
case DST_ALG_RSASHA256:
case DST_ALG_RSASHA512:
case DST_ALG_RSASHA256PRIVATEOID:
case DST_ALG_RSASHA512PRIVATEOID:
return check_rsa(priv, external);
case DST_ALG_ECDSA256:
case DST_ALG_ECDSA384:
@ -694,6 +696,12 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
case DST_ALG_HMACSHA512:
fprintf(fp, "(HMAC_SHA512)\n");
break;
case DST_ALG_RSASHA256PRIVATEOID:
fprintf(fp, "(OID:RSASHA256)\n");
break;
case DST_ALG_RSASHA512PRIVATEOID:
fprintf(fp, "(OID:RSASHA512)\n");
break;
default:
fprintf(fp, "(?)\n");
break;

View file

@ -16,20 +16,32 @@
#include <dns/rdatastruct.h>
#include <dns/types.h>
#define DNS_DSDIGEST_SHA1 (1)
#define DNS_DSDIGEST_SHA256 (2)
#define DNS_DSDIGEST_GOST (3)
#define DNS_DSDIGEST_SHA384 (4)
#define DNS_DSDIGEST_SHA1 (1)
#define DNS_DSDIGEST_SHA256 (2)
#define DNS_DSDIGEST_GOST (3)
#define DNS_DSDIGEST_SHA384 (4)
#define DNS_DSDIGEST_GOST2012 (5)
#define DNS_DSDIGEST_SM3 (6)
#if TEST_PRIVATE_DSDIGEST
/*
* Possible future digest types that encode the PRIVATEDNS and
* PRIVATEOID identifiers before the cryptographic digest value.
*/
#define DNS_DSDIGEST_SHA256PRIVATE (7)
#define DNS_DSDIGEST_SHA384PRIVATE (8)
#define DNS_DSDIGEST_SM3PRIVATE (9)
#endif
/*
* Assuming SHA-384 digest type.
* Assuming SHA-384 digest type + maximal PRIVATEDNS name.
*/
#define DNS_DS_BUFFERSIZE (52)
#define DNS_DS_BUFFERSIZE (52 + 255)
isc_result_t
dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key,
dns_dsdigest_t digest_type, unsigned char *digest,
dns_rdata_ds_t *dsrdata);
size_t len, dns_rdata_ds_t *dsrdata);
/*%<
* Build a DS rdata structure from a key.
*
@ -41,7 +53,7 @@ dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key,
isc_result_t
dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key,
dns_dsdigest_t digest_type, unsigned char *buffer,
dns_dsdigest_t digest_type, unsigned char *buffer, size_t len,
dns_rdata_t *rdata);
/*%<
* Similar to dns_ds_fromkeyrdata(), but copies the DS into a

View file

@ -52,7 +52,7 @@ struct dns_kasp_key {
/* Configuration */
dns_keystore_t *keystore;
uint32_t lifetime;
uint8_t algorithm;
dst_algorithm_t algorithm;
int length;
uint8_t role;
uint16_t tag_min;

View file

@ -434,12 +434,18 @@ dns_resolver_disable_ds_digest(dns_resolver_t *resolver, const dns_name_t *name,
bool
dns_resolver_algorithm_supported(dns_resolver_t *resolver,
const dns_name_t *name, unsigned int alg);
const dns_name_t *name, unsigned int alg,
unsigned char *private, size_t len);
/*%<
* Check if the given algorithm is supported by this resolver.
* This checks whether the algorithm has been disabled via
* dns_resolver_disable_algorithm(), then checks the underlying
* crypto libraries if it was not specifically disabled.
*
* The algorithm is specified with the value 'alg' or, if
* 'alg' is PRIVATEOID or PRIVATEDNS, then the algorithm is
* encoded as a DNS name or OID in the first 'len' bytes of
* 'private'.
*/
bool

View file

@ -137,6 +137,7 @@ struct dns_validator {
dns_rdataset_t fdsset;
dns_rdataset_t frdataset;
dns_rdataset_t fsigrdataset;
dns_rdataset_t dsrdataset;
dns_fixedname_t fname;
dns_fixedname_t wild;
dns_fixedname_t closest;

View file

@ -2187,8 +2187,8 @@ dns_zone_getsignatures(dns_zone_t *zone);
*/
isc_result_t
dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, uint16_t keyid,
bool deleteit);
dns_zone_signwithkey(dns_zone_t *zone, dst_algorithm_t algorithm,
uint16_t keyid, bool deleteit);
/*%<
* Initiate/resume signing of the entire zone with the zone DNSKEY(s)
* that match the given algorithm and keyid.

View file

@ -110,8 +110,15 @@ typedef enum dst_algorithm {
DST_ALG_HMAC_LAST = DST_ALG_HMACSHA512,
DST_ALG_INDIRECT = 252,
DST_ALG_PRIVATE = 254,
DST_MAX_ALGS = 256,
DST_ALG_PRIVATEDNS = 253,
DST_ALG_PRIVATEOID = 254,
DST_ALG_RESERVED = 255,
/*
* Put PRIVATE DNS and PRIVATE OID identifiers here.
*/
DST_ALG_RSASHA256PRIVATEOID = 256, /* 1.2.840.113549.1.1.11 */
DST_ALG_RSASHA512PRIVATEOID = 257, /* 1.2.840.113549.1.1.13 */
DST_MAX_ALGS = 258,
} dst_algorithm_t;
/*% A buffer of this size is large enough to hold any key */
@ -206,6 +213,20 @@ dst_algorithm_supported(unsigned int alg);
* \li false
*/
dst_algorithm_t
dst_algorithm_fromprivateoid(isc_buffer_t *buffer);
/*
* Extract the dst algorithm identifier that matches
* the OID value found at the start of 'buffer'.
*/
dst_algorithm_t
dst_algorithm_fromprivatedns(isc_buffer_t *buf);
/*
* Extract the dst algorithm identifier that matches
* the DNS name found at the start of 'buffer'.
*/
bool
dst_ds_digest_supported(unsigned int digest_type);
/*%<
@ -1160,3 +1181,89 @@ dst_hmac_algorithm_totext(dst_algorithm_t alg);
* Return the name associtated with the HMAC algorithm 'alg'
* or return "unknown".
*/
isc_result_t
dst_algorithm_fromtext(dst_algorithm_t *algp, isc_textregion_t *source);
/*%<
* Convert the text 'source' refers to into a DST security algorithm value.
* The text may contain either a mnemonic algorithm name or a decimal algorithm
* number. This supports more algorithms than 'dns_secalg_fromtext' as it
* supports private algorithms used with PRIVATEDNS and PRIVATEOID.
*
* Requires:
*\li 'algp' is a valid pointer.
*
*\li 'source' is a valid text region.
*
* Returns:
*\li ISC_R_SUCCESS on success
*\li ISC_R_RANGE numeric type is out of range
*\li DNS_R_UNKNOWN mnemonic type is unknown
*/
isc_result_t
dst_algorithm_totext(dst_algorithm_t alg, isc_buffer_t *target);
/*%<
* Put a textual representation of DST security algorithm 'alg'
* into 'target'. This supports a superset of dns_secalg_totext.
*
* Requires:
*\li 'alg' is a valid dst_algorithm_t.
*
*\li 'target' is a valid text buffer.
*
* Ensures,
* if the result is success:
*\li The used space in 'target' is updated.
*
* Returns:
*\li ISC_R_SUCCESS on success
*\li ISC_R_NOSPACE target buffer is too small
*/
#define DST_ALGORITHM_FORMATSIZE 20
void
dst_algorithm_format(dst_algorithm_t dst_alg, char *data, unsigned int length);
/*%<
* Wrapper for dst_algorithm_totext(), writing text into 'cp'
*/
dns_secalg_t
dst_algorithm_tosecalg(dst_algorithm_t dst_alg);
/*%<
* Return the DNSSEC algorithm identifier that applies for the DST
* algorithm. For PRIVATEDNS and PRIVATEOID based algorithms, this
* is PRIVATEDNS and PRIVATEOID respectively.
*
* Zero is returned when there is no mapping.
*/
isc_result_t
dst_privatedns_fromtext(dst_algorithm_t *algp, isc_textregion_t *source);
isc_result_t
dns_privatedns_totext(dst_algorithm_t alg, isc_buffer_t *b);
void
dns_privatedns_format(dst_algorithm_t alg, char *buf, unsigned int size);
isc_result_t
dst_privateoid_fromtext(dst_algorithm_t *algp, isc_textregion_t *source);
isc_result_t
dns_privateoid_totext(dst_algorithm_t alg, isc_buffer_t *b);
void
dns_privateoid_format(dst_algorithm_t alg, char *buf, unsigned int size);
dst_algorithm_t
dst_algorithm_fromdata(dns_secalg_t algorithm, unsigned char *data,
unsigned int length);
/*%<
* If 'algorithm' is PRIVATEOID or PRIVATEDNS, extract the DNSSEC private
* algorithm encoded at the begining of data and return the DST algorithm
* number that corresponds to it; if the algorithm is unknown to DST,
* return 0.
*
* If 'algorithm' is any other value, return it directly.
*/

View file

@ -426,11 +426,13 @@ dns_kasp_key_size(dns_kasp_key_t *key) {
REQUIRE(key != NULL);
switch (key->algorithm) {
case DNS_KEYALG_RSASHA1:
case DNS_KEYALG_NSEC3RSASHA1:
case DNS_KEYALG_RSASHA256:
case DNS_KEYALG_RSASHA512:
min = (key->algorithm == DNS_KEYALG_RSASHA512) ? 1024 : 512;
case DST_ALG_RSASHA1:
case DST_ALG_NSEC3RSASHA1:
case DST_ALG_RSASHA256:
case DST_ALG_RSASHA512:
case DST_ALG_RSASHA256PRIVATEOID:
case DST_ALG_RSASHA512PRIVATEOID:
min = (key->algorithm == DST_ALG_RSASHA512) ? 1024 : 512;
if (key->length > -1) {
size = (unsigned int)key->length;
if (size < min) {
@ -443,16 +445,16 @@ dns_kasp_key_size(dns_kasp_key_t *key) {
size = 2048;
}
break;
case DNS_KEYALG_ECDSA256:
case DST_ALG_ECDSA256:
size = 256;
break;
case DNS_KEYALG_ECDSA384:
case DST_ALG_ECDSA384:
size = 384;
break;
case DNS_KEYALG_ED25519:
case DST_ALG_ED25519:
size = 256;
break;
case DNS_KEYALG_ED448:
case DST_ALG_ED448:
size = 456;
break;
default:

View file

@ -453,7 +453,7 @@ dns_keytable_deletekey(dns_keytable_t *keytable, const dns_name_t *keyname,
}
result = dns_ds_fromkeyrdata(keyname, &rdata, DNS_DSDIGEST_SHA256,
digest, &ds);
digest, sizeof(digest), &ds);
if (result != ISC_R_SUCCESS) {
goto finish;
}

View file

@ -50,6 +50,14 @@ typedef struct rsa_components {
const BIGNUM *e, *n, *d, *p, *q, *dmp1, *dmq1, *iqmp;
} rsa_components_t;
/* length byte + 1.2.840.113549.1.1.11 BER encoded RFC 4055 */
static unsigned char oid_rsasha256[] = { 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b };
/* length byte + 1.2.840.113549.1.1.13 BER encoded RFC 4055 */
static unsigned char oid_rsasha512[] = { 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d };
static isc_result_t
opensslrsa_components_get(const dst_key_t *key, rsa_components_t *c,
bool private) {
@ -154,6 +162,8 @@ opensslrsa_valid_key_alg(unsigned int key_alg) {
case DST_ALG_NSEC3RSASHA1:
case DST_ALG_RSASHA256:
case DST_ALG_RSASHA512:
case DST_ALG_RSASHA256PRIVATEOID:
case DST_ALG_RSASHA512PRIVATEOID:
return true;
default:
return false;
@ -181,12 +191,14 @@ opensslrsa_createctx(dst_key_t *key, dst_context_t *dctx) {
}
break;
case DST_ALG_RSASHA256:
case DST_ALG_RSASHA256PRIVATEOID:
/* From RFC 5702 */
if (dctx->key->key_size < 512 || dctx->key->key_size > 4096) {
return ISC_R_FAILURE;
}
break;
case DST_ALG_RSASHA512:
case DST_ALG_RSASHA512PRIVATEOID:
/* From RFC 5702 */
if (dctx->key->key_size < 1024 || dctx->key->key_size > 4096) {
return ISC_R_FAILURE;
@ -207,9 +219,11 @@ opensslrsa_createctx(dst_key_t *key, dst_context_t *dctx) {
type = isc__crypto_sha1; /* SHA1 + RSA */
break;
case DST_ALG_RSASHA256:
case DST_ALG_RSASHA256PRIVATEOID:
type = isc__crypto_sha256; /* SHA256 + RSA */
break;
case DST_ALG_RSASHA512:
case DST_ALG_RSASHA512PRIVATEOID:
type = isc__crypto_sha512;
break;
default:
@ -264,6 +278,7 @@ opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
unsigned int siglen = 0;
EVP_MD_CTX *evp_md_ctx = NULL;
EVP_PKEY *pkey = NULL;
unsigned int len = 0;
REQUIRE(dctx != NULL && dctx->key != NULL);
REQUIRE(opensslrsa_valid_key_alg(dctx->key->key_alg));
@ -272,17 +287,42 @@ opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
evp_md_ctx = dctx->ctxdata.evp_md_ctx;
pkey = key->keydata.pkeypair.priv;
/*
* Account to the space the OIDs and DNS names consume.
*/
switch (key->key_alg) {
case DST_ALG_RSASHA256PRIVATEOID:
len = sizeof(oid_rsasha256);
break;
case DST_ALG_RSASHA512PRIVATEOID:
len = sizeof(oid_rsasha512);
break;
}
isc_buffer_availableregion(sig, &r);
if (r.length < (unsigned int)EVP_PKEY_size(pkey)) {
if (r.length < (unsigned int)EVP_PKEY_size(pkey) + len) {
return ISC_R_NOSPACE;
}
/*
* Add OID and DNS names to start of signature.
*/
switch (key->key_alg) {
case DST_ALG_RSASHA256PRIVATEOID:
isc_buffer_putmem(sig, oid_rsasha256, sizeof(oid_rsasha256));
isc_region_consume(&r, sizeof(oid_rsasha256));
break;
case DST_ALG_RSASHA512PRIVATEOID:
isc_buffer_putmem(sig, oid_rsasha512, sizeof(oid_rsasha512));
isc_region_consume(&r, sizeof(oid_rsasha512));
break;
}
if (!EVP_SignFinal(evp_md_ctx, r.base, &siglen, pkey)) {
return dst__openssl_toresult3(dctx->category, "EVP_SignFinal",
ISC_R_FAILURE);
}
isc_buffer_add(sig, siglen);
return ISC_R_SUCCESS;
@ -317,6 +357,8 @@ opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
int status = 0;
EVP_MD_CTX *evp_md_ctx = NULL;
EVP_PKEY *pkey = NULL;
const unsigned char *base = sig->base;
unsigned int length = sig->length;
REQUIRE(dctx != NULL && dctx->key != NULL);
REQUIRE(opensslrsa_valid_key_alg(dctx->key->key_alg));
@ -330,7 +372,31 @@ opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
return DST_R_VERIFYFAILURE;
}
status = EVP_VerifyFinal(evp_md_ctx, sig->base, sig->length, pkey);
/*
* Check identifying OID in front of public key material.
*/
switch (key->key_alg) {
case DST_ALG_RSASHA256PRIVATEOID:
if (length < sizeof(oid_rsasha256) ||
memcmp(base, oid_rsasha256, sizeof(oid_rsasha256)) != 0)
{
return DST_R_VERIFYFAILURE;
}
base += sizeof(oid_rsasha256);
length -= sizeof(oid_rsasha256);
break;
case DST_ALG_RSASHA512PRIVATEOID:
if (length < sizeof(oid_rsasha512) ||
memcmp(base, oid_rsasha512, sizeof(oid_rsasha512)) != 0)
{
return DST_R_VERIFYFAILURE;
}
base += sizeof(oid_rsasha512);
length -= sizeof(oid_rsasha512);
break;
}
status = EVP_VerifyFinal(evp_md_ctx, base, length, pkey);
switch (status) {
case 1:
return ISC_R_SUCCESS;
@ -692,12 +758,14 @@ opensslrsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
}
break;
case DST_ALG_RSASHA256:
case DST_ALG_RSASHA256PRIVATEOID:
/* From RFC 5702 */
if (key->key_size < 512 || key->key_size > 4096) {
DST_RET(DST_R_INVALIDPARAM);
}
break;
case DST_ALG_RSASHA512:
case DST_ALG_RSASHA512PRIVATEOID:
/* From RFC 5702 */
if (key->key_size < 1024 || key->key_size > 4096) {
DST_RET(DST_R_INVALIDPARAM);
@ -740,6 +808,26 @@ opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data) {
isc_buffer_availableregion(data, &r);
/*
* Add identifying OID and DNS names to front of public key material.
*/
switch (key->key_alg) {
case DST_ALG_RSASHA256PRIVATEOID:
if (r.length < sizeof(oid_rsasha256)) {
DST_RET(ISC_R_NOSPACE);
}
isc_buffer_putmem(data, oid_rsasha256, sizeof(oid_rsasha256));
isc_region_consume(&r, sizeof(oid_rsasha256));
break;
case DST_ALG_RSASHA512PRIVATEOID:
if (r.length < sizeof(oid_rsasha512)) {
DST_RET(ISC_R_NOSPACE);
}
isc_buffer_putmem(data, oid_rsasha512, sizeof(oid_rsasha512));
isc_region_consume(&r, sizeof(oid_rsasha512));
break;
}
ret = opensslrsa_components_get(key, &c, false);
if (ret != ISC_R_SUCCESS) {
goto err;
@ -794,6 +882,31 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
if (r.length == 0) {
DST_RET(ISC_R_SUCCESS);
}
/*
* Check identifying OID in front of public key material.
*/
switch (key->key_alg) {
case DST_ALG_RSASHA256PRIVATEOID:
if (r.length < sizeof(oid_rsasha256) ||
memcmp(r.base, oid_rsasha256, sizeof(oid_rsasha256)) != 0)
{
DST_RET(DST_R_INVALIDPUBLICKEY);
}
isc_region_consume(&r, sizeof(oid_rsasha256));
isc_buffer_forward(data, sizeof(oid_rsasha256));
break;
case DST_ALG_RSASHA512PRIVATEOID:
if (r.length < sizeof(oid_rsasha512) ||
memcmp(r.base, oid_rsasha512, sizeof(oid_rsasha512)) != 0)
{
DST_RET(DST_R_INVALIDPUBLICKEY);
}
isc_region_consume(&r, sizeof(oid_rsasha512));
isc_buffer_forward(data, sizeof(oid_rsasha512));
break;
}
length = r.length;
if (r.length < 1) {
DST_RET(DST_R_INVALIDPUBLICKEY);
@ -1214,7 +1327,7 @@ static const unsigned char sha512_sig[] =
"\xf1";
static isc_result_t
check_algorithm(unsigned char algorithm) {
check_algorithm(unsigned short algorithm) {
rsa_components_t c = { .bnfree = true };
EVP_MD_CTX *evp_md_ctx = EVP_MD_CTX_create();
EVP_PKEY *pkey = NULL;
@ -1231,11 +1344,13 @@ check_algorithm(unsigned char algorithm) {
len = sizeof(sha1_sig) - 1;
break;
case DST_ALG_RSASHA256:
case DST_ALG_RSASHA256PRIVATEOID:
type = isc__crypto_sha256; /* SHA256 + RSA */
sig = sha256_sig;
len = sizeof(sha256_sig) - 1;
break;
case DST_ALG_RSASHA512:
case DST_ALG_RSASHA512PRIVATEOID:
type = isc__crypto_sha512;
sig = sha512_sig;
len = sizeof(sha512_sig) - 1;
@ -1272,7 +1387,7 @@ err:
}
void
dst__opensslrsa_init(dst_func_t **funcp, unsigned char algorithm) {
dst__opensslrsa_init(dst_func_t **funcp, unsigned short algorithm) {
REQUIRE(funcp != NULL);
if (*funcp == NULL) {

View file

@ -354,6 +354,7 @@ dns_private_totext(dns_rdata_t *private, isc_buffer_t *buf) {
isc_buffer_putstr(buf, " / creating NSEC chain");
}
} else if (private->length == 5) {
/* Old Form */
unsigned char alg = private->data[0];
dns_keytag_t keyid = (private->data[2] | private->data[1] << 8);
char keybuf[DNS_SECALG_FORMATSIZE + BUFSIZ],
@ -371,6 +372,33 @@ dns_private_totext(dns_rdata_t *private, isc_buffer_t *buf) {
isc_buffer_putstr(buf, "Signing with ");
}
dns_secalg_format(alg, algbuf, sizeof(algbuf));
snprintf(keybuf, sizeof(keybuf), "key %d/%s", keyid, algbuf);
isc_buffer_putstr(buf, keybuf);
} else if (private->length == 7) {
/* New Form - supports private types */
dns_keytag_t keyid = private->data[2] | (private->data[1] << 8);
char keybuf[DNS_SECALG_FORMATSIZE + BUFSIZ],
algbuf[DNS_SECALG_FORMATSIZE];
bool del = private->data[3];
bool complete = private->data[4];
dst_algorithm_t alg = private->data[6] |
(private->data[5] << 8);
if (dst_algorithm_tosecalg(alg) != private->data[0]) {
return ISC_R_NOTFOUND;
}
if (del && complete) {
isc_buffer_putstr(buf, "Done removing signatures for ");
} else if (del) {
isc_buffer_putstr(buf, "Removing signatures for ");
} else if (complete) {
isc_buffer_putstr(buf, "Done signing with ");
} else {
isc_buffer_putstr(buf, "Signing with ");
}
dns_secalg_format(alg, algbuf, sizeof(algbuf));
snprintf(keybuf, sizeof(keybuf), "key %d/%s", keyid, algbuf);
isc_buffer_putstr(buf, keybuf);

View file

@ -36,6 +36,8 @@
#include <dns/secalg.h>
#include <dns/secproto.h>
#include <dst/dst.h>
#define RETERR(x) \
do { \
isc_result_t _r = (x); \
@ -47,6 +49,10 @@
#define TOTEXTONLY 0x01
/* clang-format off */
#define SENTINEL { 0, NULL, 0 }
/* clang-format on */
#define RCODENAMES \
/* standard rcodes */ \
{ dns_rcode_noerror, "NOERROR", 0 }, \
@ -69,7 +75,7 @@
#define ERCODENAMES \
/* extended rcodes */ \
{ dns_rcode_badvers, "BADVERS", 0 }, \
{ dns_rcode_badcookie, "BADCOOKIE", 0 }, { 0, NULL, 0 }
{ dns_rcode_badcookie, "BADCOOKIE", 0 }, SENTINEL
#define TSIGRCODENAMES \
/* extended rcodes */ \
@ -79,7 +85,7 @@
{ dns_tsigerror_badmode, "BADMODE", 0 }, \
{ dns_tsigerror_badname, "BADNAME", 0 }, \
{ dns_tsigerror_badalg, "BADALG", 0 }, \
{ dns_tsigerror_badtrunc, "BADTRUNC", 0 }, { 0, NULL, 0 }
{ dns_tsigerror_badtrunc, "BADTRUNC", 0 }, SENTINEL
/* RFC4398 section 2.1 */
@ -87,7 +93,7 @@
{ 1, "PKIX", 0 }, { 2, "SPKI", 0 }, { 3, "PGP", 0 }, \
{ 4, "IPKIX", 0 }, { 5, "ISPKI", 0 }, { 6, "IPGP", 0 }, \
{ 7, "ACPKIX", 0 }, { 8, "IACPKIX", 0 }, { 253, "URI", 0 }, \
{ 254, "OID", 0 }, { 0, NULL, 0 }
{ 254, "OID", 0 }, SENTINEL
/* RFC2535 section 7, RFC3110 */
@ -109,26 +115,56 @@
{ DNS_KEYALG_ED448, "ED448", 0 }, \
{ DNS_KEYALG_INDIRECT, "INDIRECT", 0 }, \
{ DNS_KEYALG_PRIVATEDNS, "PRIVATEDNS", 0 }, \
{ DNS_KEYALG_PRIVATEOID, "PRIVATEOID", 0 }, { 0, NULL, 0 }
{ DNS_KEYALG_PRIVATEOID, "PRIVATEOID", 0 }, SENTINEL
/*
* PRIVATEDNS subtypes we support.
*/
#define PRIVATEDNSS /* currently empty */
/*
* PRIVATEOID subtypes we support.
*/
#define PRIVATEOIDS \
{ DST_ALG_RSASHA256PRIVATEOID, "RSASHA256OID", 0 }, \
{ DST_ALG_RSASHA512PRIVATEOID, "RSASHA512OID", 0 },
/* RFC2535 section 7.1 */
#define SECPROTONAMES \
{ 0, "NONE", 0 }, { 1, "TLS", 0 }, { 2, "EMAIL", 0 }, \
{ 3, "DNSSEC", 0 }, { 4, "IPSEC", 0 }, { 255, "ALL", 0 }, \
{ 0, NULL, 0 }
SENTINEL
#define HASHALGNAMES { 1, "SHA-1", 0 }, { 0, NULL, 0 }
#define HASHALGNAMES { 1, "SHA-1", 0 }, SENTINEL
/* RFC3658, RFC4509, RFC5933, RFC6605 */
/* RFC3658, RFC4509, RFC5933, RFC6605, RFC9558, RFC9563 */
#if defined(DNS_DSDIGEST_SHA256PRIVATE) && \
defined(DNS_DSDIGEST_SHA384PRIVATE) && \
defined(DNS_DSDIGEST_SM3PRIVATE)
#define DSDIGESTPRIVATENAMES \
{ DNS_DSDIGEST_SHA256PRIVATE, "SHA-256-PRIVATE", 0 }, \
{ DNS_DSDIGEST_SHA256PRIVATE, "SHA256PRIVATE", 0 }, \
{ DNS_DSDIGEST_SHA384PRIVATE, "SHA-384-PRIVATE", 0 }, \
{ DNS_DSDIGEST_SHA384PRIVATE, "SHA384PRIVATE", 0 }, \
{ DNS_DSDIGEST_SM3PRIVATE, "SM3-PRIVATE", 0 }, \
{ DNS_DSDIGEST_SM3PRIVATE, "SM3PRIVATE", 0 },
#else
#define DSDIGESTPRIVATENAMES
#endif
#define DSDIGESTNAMES \
{ DNS_DSDIGEST_SHA1, "SHA-1", 0 }, { DNS_DSDIGEST_SHA1, "SHA1", 0 }, \
{ DNS_DSDIGEST_SHA256, "SHA-256", 0 }, \
{ DNS_DSDIGEST_SHA256, "SHA256", 0 }, \
{ DNS_DSDIGEST_GOST, "GOST", 0 }, \
{ DNS_DSDIGEST_SM3, "SM3", 0 }, \
{ DNS_DSDIGEST_SHA384, "SHA-384", 0 }, \
{ DNS_DSDIGEST_SHA384, "SHA384", 0 }, { 0, NULL, 0 }
{ DNS_DSDIGEST_SHA384, "SHA384", 0 }, \
{ DNS_DSDIGEST_GOST2012, "GOST-2012", 0 }, \
{ DNS_DSDIGEST_GOST2012, "GOST2012", 0 }, \
DSDIGESTPRIVATENAMES SENTINEL
struct tbl {
unsigned int value;
@ -143,6 +179,9 @@ static struct tbl secalgs[] = { SECALGNAMES };
static struct tbl secprotos[] = { SECPROTONAMES };
static struct tbl hashalgs[] = { HASHALGNAMES };
static struct tbl dsdigests[] = { DSDIGESTNAMES };
static struct tbl privatednss[] = { PRIVATEDNSS SENTINEL };
static struct tbl privateoids[] = { PRIVATEOIDS SENTINEL };
static struct tbl dstalgorithms[] = { PRIVATEDNSS PRIVATEOIDS SECALGNAMES };
static struct keyflag {
const char *name;
@ -346,6 +385,64 @@ dns_secalg_format(dns_secalg_t alg, char *cp, unsigned int size) {
}
}
isc_result_t
dst_privatedns_fromtext(dst_algorithm_t *dstalgp, isc_textregion_t *source) {
unsigned int value;
RETERR(dns_mnemonic_fromtext(&value, source, privatednss, 0));
*dstalgp = value;
return ISC_R_SUCCESS;
}
isc_result_t
dns_privatedns_totext(dst_algorithm_t alg, isc_buffer_t *target) {
return dns_mnemonic_totext(alg, target, privatednss);
}
void
dns_privatedns_format(dst_algorithm_t alg, char *cp, unsigned int size) {
isc_buffer_t b;
isc_region_t r;
isc_result_t result;
REQUIRE(cp != NULL && size > 0);
isc_buffer_init(&b, cp, size - 1);
result = dns_privatedns_totext(alg, &b);
isc_buffer_usedregion(&b, &r);
r.base[r.length] = 0;
if (result != ISC_R_SUCCESS) {
r.base[0] = 0;
}
}
isc_result_t
dst_privateoid_fromtext(dst_algorithm_t *dstalgp, isc_textregion_t *source) {
unsigned int value;
RETERR(dns_mnemonic_fromtext(&value, source, privateoids, 0));
*dstalgp = value;
return ISC_R_SUCCESS;
}
isc_result_t
dns_privateoid_totext(dst_algorithm_t alg, isc_buffer_t *target) {
return dns_mnemonic_totext(alg, target, privateoids);
}
void
dns_privateoid_format(dst_algorithm_t alg, char *cp, unsigned int size) {
isc_buffer_t b;
isc_region_t r;
isc_result_t result;
REQUIRE(cp != NULL && size > 0);
isc_buffer_init(&b, cp, size - 1);
result = dns_privateoid_totext(alg, &b);
isc_buffer_usedregion(&b, &r);
r.base[r.length] = 0;
if (result != ISC_R_SUCCESS) {
r.base[0] = 0;
}
}
isc_result_t
dns_secproto_fromtext(dns_secproto_t *secprotop, isc_textregion_t *source) {
unsigned int value;
@ -572,3 +669,32 @@ dns_rdataclass_format(dns_rdataclass_t rdclass, char *array,
strlcpy(array, "<unknown>", size);
}
}
isc_result_t
dst_algorithm_fromtext(dst_algorithm_t *dstalgp, isc_textregion_t *source) {
unsigned int value;
RETERR(dns_mnemonic_fromtext(&value, source, dstalgorithms, 255));
*dstalgp = value;
return ISC_R_SUCCESS;
}
isc_result_t
dst_algorithm_totext(dst_algorithm_t alg, isc_buffer_t *target) {
return dns_mnemonic_totext(alg, target, dstalgorithms);
}
void
dst_algorithm_format(dst_algorithm_t alg, char *cp, unsigned int size) {
isc_buffer_t b;
isc_region_t r;
isc_result_t result;
REQUIRE(cp != NULL && size > 0);
isc_buffer_init(&b, cp, size - 1);
result = dst_algorithm_totext(alg, &b);
isc_buffer_usedregion(&b, &r);
r.base[r.length] = 0;
if (result != ISC_R_SUCCESS) {
r.base[0] = 0;
}
}

View file

@ -10593,7 +10593,7 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, const dns_name_t *name,
unsigned int alg) {
REQUIRE(VALID_RESOLVER(resolver));
if (alg > 255) {
if (alg >= DST_MAX_ALGS) {
return ISC_R_RANGE;
}
@ -10614,13 +10614,37 @@ dns_resolver_disable_ds_digest(dns_resolver_t *resolver, const dns_name_t *name,
bool
dns_resolver_algorithm_supported(dns_resolver_t *resolver,
const dns_name_t *name, unsigned int alg) {
const dns_name_t *name, unsigned int alg,
unsigned char *private, size_t len) {
REQUIRE(VALID_RESOLVER(resolver));
if ((alg == DST_ALG_DH) || (alg == DST_ALG_INDIRECT)) {
return false;
}
/*
* Look up the DST algorithm identifier for private-OID
* and private-DNS keys.
*/
if (alg == DST_ALG_PRIVATEDNS && private != NULL) {
isc_buffer_t b;
isc_buffer_init(&b, private, len);
isc_buffer_add(&b, len);
alg = dst_algorithm_fromprivatedns(&b);
if (alg == 0) {
return false;
}
}
if (alg == DST_ALG_PRIVATEOID && private != NULL) {
isc_buffer_t b;
isc_buffer_init(&b, private, len);
isc_buffer_add(&b, len);
alg = dst_algorithm_fromprivateoid(&b);
if (alg == 0) {
return false;
}
}
if (dns_nametree_covered(resolver->algorithms, name, NULL, alg)) {
return false;
}

View file

@ -146,7 +146,8 @@ static isc_result_t
validate_nx(dns_validator_t *val, bool resume);
static isc_result_t
proveunsecure(dns_validator_t *val, bool have_ds, bool resume);
proveunsecure(dns_validator_t *val, bool have_ds, bool have_dnskey,
bool resume);
static void
validator_logv(dns_validator_t *val, isc_logcategory_t category,
@ -397,6 +398,13 @@ fetch_callback_dnskey(void *arg) {
dns_rdataset_t *rdataset = &val->frdataset;
isc_result_t eresult = resp->result;
isc_result_t result;
bool trustchain;
/*
* Set 'trustchain' to true if we're walking a chain of
* trust; false if we're attempting to prove insecurity.
*/
trustchain = ((val->attributes & VALATTR_INSECURITY) == 0);
/* Free resources which are not of interest. */
if (resp->node != NULL) {
@ -418,34 +426,55 @@ fetch_callback_dnskey(void *arg) {
goto cleanup;
}
switch (eresult) {
case ISC_R_SUCCESS:
case DNS_R_NCACHENXRRSET:
/*
* We have an answer to our DNSKEY query. Either the DNSKEY
* RRset or a NODATA response.
*/
validator_log(val, ISC_LOG_DEBUG(3), "%s with trust %s",
eresult == ISC_R_SUCCESS ? "keyset"
: "NCACHENXRRSET",
dns_trust_totext(rdataset->trust));
/*
* Only extract the dst key if the keyset exists and is secure.
*/
if (eresult == ISC_R_SUCCESS &&
rdataset->trust >= dns_trust_secure)
{
result = validate_helper_run(val,
resume_answer_with_key);
} else {
result = validate_async_run(val, resume_answer);
if (trustchain) {
switch (eresult) {
case ISC_R_SUCCESS:
case DNS_R_NCACHENXRRSET:
/*
* We have an answer to our DNSKEY query. Either the
* DNSKEY RRset or a NODATA response.
*/
validator_log(val, ISC_LOG_DEBUG(3), "%s with trust %s",
eresult == ISC_R_SUCCESS
? "keyset"
: "NCACHENXRRSET",
dns_trust_totext(rdataset->trust));
/*
* Only extract the dst key if the keyset exists and is
* secure.
*/
if (eresult == ISC_R_SUCCESS &&
rdataset->trust >= dns_trust_secure)
{
result = validate_helper_run(
val, resume_answer_with_key);
} else {
result = validate_async_run(val, resume_answer);
}
break;
default:
validator_log(val, ISC_LOG_DEBUG(3),
"fetch_callback_dnskey: got %s",
isc_result_totext(eresult));
result = DNS_R_BROKENCHAIN;
break;
}
} else {
switch (eresult) {
case ISC_R_SUCCESS:
/*
* We have a DS (val->dsrdataset) and
* DNSKEY (val->fdataset).
*/
result = proveunsecure(val, false, true, true);
break;
default:
validator_log(val, ISC_LOG_DEBUG(3),
"fetch_callback_dnskey: got %s",
isc_result_totext(eresult));
result = DNS_R_BROKENCHAIN;
break;
}
break;
default:
validator_log(val, ISC_LOG_DEBUG(3),
"fetch_callback_dnskey: got %s",
isc_result_totext(eresult));
result = DNS_R_BROKENCHAIN;
}
cleanup:
@ -518,7 +547,7 @@ fetch_callback_ds(void *arg) {
validator_log(val, ISC_LOG_DEBUG(3),
"falling back to insecurity proof (%s)",
isc_result_totext(eresult));
result = proveunsecure(val, false, false);
result = proveunsecure(val, false, false, false);
break;
default:
validator_log(val, ISC_LOG_DEBUG(3),
@ -537,7 +566,7 @@ fetch_callback_ds(void *arg) {
* trust.
*/
result = proveunsecure(val, false, true);
result = proveunsecure(val, false, false, true);
break;
case ISC_R_SUCCESS:
/*
@ -546,7 +575,7 @@ fetch_callback_ds(void *arg) {
* so keep looking for the break in the chain
* of trust.
*/
result = proveunsecure(val, true, true);
result = proveunsecure(val, true, false, true);
break;
case DNS_R_NXRRSET:
case DNS_R_NCACHENXRRSET:
@ -567,13 +596,14 @@ fetch_callback_ds(void *arg) {
* Not a zone cut, so we have to keep looking for
* the break point in the chain of trust.
*/
result = proveunsecure(val, false, true);
result = proveunsecure(val, false, false, true);
break;
default:
validator_log(val, ISC_LOG_DEBUG(3),
"fetch_callback_ds: got %s",
isc_result_totext(eresult));
result = DNS_R_BROKENCHAIN;
break;
}
}
@ -673,7 +703,7 @@ validator_callback_ds(void *arg) {
{
result = markanswer(val, "validator_callback_ds");
} else if ((val->attributes & VALATTR_INSECURITY) != 0) {
result = proveunsecure(val, have_dsset, true);
result = proveunsecure(val, have_dsset, false, true);
} else {
result = validate_async_run(val, validate_dnskey);
}
@ -724,7 +754,7 @@ validator_callback_cname(void *arg) {
if (eresult == ISC_R_SUCCESS) {
validator_log(val, ISC_LOG_DEBUG(3), "cname with trust %s",
dns_trust_totext(val->frdataset.trust));
result = proveunsecure(val, false, true);
result = proveunsecure(val, false, false, true);
} else {
if (eresult != DNS_R_BROKENCHAIN) {
expire_rdatasets(val);
@ -832,6 +862,7 @@ validator_callback_nsec(void *arg) {
FALLTHROUGH;
default:
result = validate_nx(val, true);
break;
}
}
@ -1364,6 +1395,7 @@ selfsigned_dnskey(dns_validator_t *val) {
return ISC_R_QUOTA;
}
consume_validation_fail(val);
break;
}
} else if (rdataset->trust >= dns_trust_secure) {
/*
@ -1469,6 +1501,7 @@ again:
break;
}
consume_validation_fail(val);
break;
}
return result;
}
@ -1641,11 +1674,15 @@ validate_answer_process(void *arg) {
* At this point we could check that the signature algorithm
* was known and "sufficiently good".
*/
if (!dns_resolver_algorithm_supported(val->view->resolver, val->name,
val->siginfo->algorithm))
if (!dns_resolver_algorithm_supported(
val->view->resolver, val->name, val->siginfo->algorithm,
val->siginfo->signature, val->siginfo->siglen))
{
if (val->unsupported_algorithm == 0) {
val->unsupported_algorithm = val->siginfo->algorithm;
/*
* XXXMPA save PRIVATEOID/PRIVATEDNS identifier here
*/
}
goto next_key;
}
@ -1814,7 +1851,7 @@ validate_async_done(dns_validator_t *val, isc_result_t result) {
isc_result_t saved_result = result;
validator_log(val, ISC_LOG_DEBUG(3),
"falling back to insecurity proof");
result = proveunsecure(val, false, false);
result = proveunsecure(val, false, false, false);
if (result == DNS_R_NOTINSECURE) {
result = saved_result;
}
@ -1975,6 +2012,7 @@ validate_dnskey_dsset_done(dns_validator_t *val, isc_result_t result) {
validator_log(val, ISC_LOG_INFO,
"no valid signature found (DS)");
result = DNS_R_NOVALIDSIG;
break;
}
if (val->dsset == &val->fdsset) {
@ -1991,6 +2029,9 @@ validate_dnskey_dsset(dns_validator_t *val) {
dns_rdata_t keyrdata = DNS_RDATA_INIT;
isc_result_t result;
dns_rdata_ds_t ds;
dns_rdata_dnskey_t key;
unsigned char *data = 0;
unsigned int datalen = 0;
dns_rdata_reset(&dsrdata);
dns_rdataset_current(val->dsset, &dsrdata);
@ -2010,13 +2051,37 @@ validate_dnskey_dsset(dns_validator_t *val) {
return DNS_R_BADALG;
}
if (!dns_resolver_algorithm_supported(val->view->resolver, val->name,
ds.algorithm))
{
if (val->unsupported_algorithm == 0) {
val->unsupported_algorithm = ds.algorithm;
switch (ds.algorithm) {
case DNS_KEYALG_PRIVATEDNS:
case DNS_KEYALG_PRIVATEOID:
switch (ds.digest_type) {
#if defined(DNS_DSDIGEST_SHA256PRIVATE) && defined(DNS_DSDIGEST_SHA384PRIVATE)
case DNS_DSDIGEST_SHA256PRIVATE:
case DNS_DSDIGEST_SHA384PRIVATE:
data = ds.digest;
datalen = ds.length;
break;
#endif
default:
break;
}
break;
default:
break;
}
if (data != NULL || (ds.algorithm != DNS_KEYALG_PRIVATEDNS &&
ds.algorithm != DNS_KEYALG_PRIVATEOID))
{
if (!dns_resolver_algorithm_supported(val->view->resolver,
val->name, ds.algorithm,
data, datalen))
{
if (val->unsupported_algorithm == 0) {
val->unsupported_algorithm = ds.algorithm;
}
return DNS_R_BADALG;
}
return DNS_R_BADALG;
}
/*
@ -2029,6 +2094,28 @@ validate_dnskey_dsset(dns_validator_t *val) {
return DNS_R_NOKEYMATCH;
}
/*
* Figure out if the private algorithm is supported now that we have
* found a matching dnskey.
*/
dns_rdata_tostruct(&keyrdata, &key, NULL);
if (data == NULL && (ds.algorithm == DNS_KEYALG_PRIVATEDNS ||
ds.algorithm == DNS_KEYALG_PRIVATEOID))
{
if (!dns_resolver_algorithm_supported(val->view->resolver,
val->name, key.algorithm,
key.data, key.datalen))
{
if (val->unsupported_algorithm == 0) {
val->unsupported_algorithm = key.algorithm;
/*
* XXXMPA Save PRIVATEOID / PRIVATEDNS here.
*/
}
return DNS_R_BADALG;
}
}
/*
* ... and check that it signed the DNSKEY RRset.
*/
@ -2213,7 +2300,8 @@ validate_dnskey(void *arg) {
}
if (!dns_resolver_algorithm_supported(val->view->resolver,
val->name, ds.algorithm))
val->name, ds.algorithm,
NULL, 0))
{
continue;
}
@ -2894,7 +2982,31 @@ validate_nx(dns_validator_t *val, bool resume) {
return DNS_R_BROKENCHAIN;
}
return proveunsecure(val, false, false);
return proveunsecure(val, false, false, false);
}
/*
* Check if any of the DS records has a private DNSSEC algorithm.
*/
static bool
check_ds_private(dns_rdataset_t *rdataset) {
dns_rdata_ds_t ds;
isc_result_t result;
for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS;
result = dns_rdataset_next(rdataset))
{
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdataset_current(rdataset, &rdata);
result = dns_rdata_tostruct(&rdata, &ds, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (ds.algorithm == DNS_KEYALG_PRIVATEDNS ||
ds.algorithm == DNS_KEYALG_PRIVATEOID)
{
return true;
}
}
return false;
}
/*%
@ -2903,21 +3015,72 @@ validate_nx(dns_validator_t *val, bool resume) {
*/
static bool
check_ds_algs(dns_validator_t *val, dns_name_t *name,
dns_rdataset_t *rdataset) {
dns_rdataset_t *dsrdataset, dns_rdataset_t *dnskeyset) {
dns_rdata_ds_t ds;
dns_rdata_dnskey_t key;
bool seen_private = false;
uint16_t key_tag = 0;
uint8_t algorithm = 0;
DNS_RDATASET_FOREACH (rdataset) {
DNS_RDATASET_FOREACH (dsrdataset) {
isc_result_t result;
dns_rdata_t dsrdata = DNS_RDATA_INIT;
dns_rdataset_current(rdataset, &dsrdata);
dns_rdata_t keyrdata = DNS_RDATA_INIT;
unsigned char *data = NULL;
size_t datalen = 0;
dns_rdataset_current(dsrdataset, &dsrdata);
result = dns_rdata_tostruct(&dsrdata, &ds, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
/*
* Look for a matching DNSKEY to find the PRIVATE
* DNSSEC algorithm.
*/
if (ds.algorithm == DNS_KEYALG_PRIVATEOID ||
ds.algorithm == DNS_KEYALG_PRIVATEDNS)
{
switch (ds.digest_type) {
#if defined(DNS_DSDIGEST_SHA256PRIVATE) && defined(DNS_DSDIGEST_SHA384PRIVATE)
case DNS_DSDIGEST_SHA256PRIVATE:
case DNS_DSDIGEST_SHA384PRIVATE:
data = ds.digest;
datalen = ds.length;
break;
#endif
case DNS_DSDIGEST_SHA1:
case DNS_DSDIGEST_SHA256:
case DNS_DSDIGEST_SHA384:
if (dnskeyset == NULL) {
algorithm = ds.algorithm;
key_tag = ds.key_tag;
seen_private = true;
continue;
}
result = dns_dnssec_matchdskey(
name, &dsrdata, dnskeyset, &keyrdata);
if (result != ISC_R_SUCCESS) {
algorithm = ds.algorithm;
key_tag = ds.key_tag;
seen_private = true;
continue;
}
result = dns_rdata_tostruct(&keyrdata, &key,
NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
data = key.data;
datalen = key.datalen;
break;
default:
break;
}
}
if (dns_resolver_ds_digest_supported(val->view->resolver, name,
ds.digest_type) &&
dns_resolver_algorithm_supported(val->view->resolver, name,
ds.algorithm))
ds.algorithm, data,
datalen))
{
return true;
}
@ -2928,8 +3091,26 @@ check_ds_algs(dns_validator_t *val, dns_name_t *name,
* unsecure flow always runs after a validate/validatenx flow. So if an
* unsupported alg/digest was found while building the chain of trust,
* it would be raised already.
*
* If we have seen a private algorithm for which we couldn't find a
* DNSKEY nor extract it from the digest field we must assume the child
* zone is secure. With PRIVATEDNS and PRIVATEOID we can make that
* determination if we match a DNSKEY for every DS with these algorithms
* or extract the algorithm from the digest field. Since we don't know
* whether the private algorithm is unsupported or not, we are required
* to treat it as supported.
*/
return false;
if (seen_private) {
char namebuf[DNS_NAME_FORMATSIZE];
dns_name_format(name, namebuf, sizeof(namebuf));
validator_log(val, ISC_LOG_INFO,
"No DNSKEY for %s/DS with %s algorithm, tag %u",
namebuf,
algorithm == DNS_KEYALG_PRIVATEDNS ? "PRIVATEDNS"
: "PRIVATEOID",
key_tag);
}
return seen_private;
}
/*%
@ -2972,7 +3153,49 @@ seek_ds(dns_validator_t *val, isc_result_t *resp) {
* validated, continue walking down labels.
*/
if (val->frdataset.trust >= dns_trust_secure) {
if (!check_ds_algs(val, tname, &val->frdataset)) {
dns_rdataset_t *dssetp = &val->frdataset,
*keysetp = NULL;
if (check_ds_private(&val->frdataset)) {
if (dns_rdataset_isassociated(&val->dsrdataset))
{
dns_rdataset_disassociate(
&val->dsrdataset);
}
dns_rdataset_clone(&val->frdataset,
&val->dsrdataset);
dssetp = &val->dsrdataset;
dns_rdataset_disassociate(&val->frdataset);
result = view_find(val, tname,
dns_rdatatype_dnskey);
switch (result) {
case ISC_R_SUCCESS:
keysetp = &val->frdataset;
break;
case ISC_R_NOTFOUND:
/*
* We don't know anything about the
* DNSKEY. Find it.
*/
*resp = DNS_R_WAIT;
result = create_fetch(
val, tname,
dns_rdatatype_dnskey,
fetch_callback_dnskey,
"seek_ds");
if (result != ISC_R_SUCCESS) {
*resp = result;
}
return ISC_R_COMPLETE;
break;
default:
validator_log(val, ISC_LOG_DEBUG(3),
"no DNSKEY found (%s/DS)",
namebuf);
break;
}
}
if (!check_ds_algs(val, tname, dssetp, keysetp)) {
validator_log(
val, ISC_LOG_DEBUG(3),
"no supported algorithm/digest (%s/DS)",
@ -3161,13 +3384,16 @@ seek_ds(dns_validator_t *val, isc_result_t *resp) {
* \li DNS_R_BROKENCHAIN
*/
static isc_result_t
proveunsecure(dns_validator_t *val, bool have_ds, bool resume) {
proveunsecure(dns_validator_t *val, bool have_ds, bool have_dnskey,
bool resume) {
isc_result_t result;
char namebuf[DNS_NAME_FORMATSIZE];
dns_fixedname_t fixedsecroot;
dns_name_t *secroot = dns_fixedname_initname(&fixedsecroot);
unsigned int labels;
INSIST(!(have_ds && have_dnskey));
/*
* We're attempting to prove insecurity.
*/
@ -3207,17 +3433,65 @@ proveunsecure(dns_validator_t *val, bool have_ds, bool resume) {
* it has a supported algorithm combination. If not, this is
* an insecure delegation as far as this resolver is concerned.
*/
if (have_ds && val->frdataset.trust >= dns_trust_secure &&
!check_ds_algs(val, dns_fixedname_name(&val->fname),
&val->frdataset))
if (have_dnskey ||
(have_ds && val->frdataset.trust >= dns_trust_secure))
{
dns_name_format(dns_fixedname_name(&val->fname),
namebuf, sizeof(namebuf));
validator_log(val, ISC_LOG_DEBUG(3),
"no supported algorithm/digest (%s/DS)",
namebuf);
result = markanswer(val, "proveunsecure (2)");
goto out;
dns_rdataset_t *dssetp = NULL, *keysetp = NULL;
dns_name_t *fname = dns_fixedname_name(&val->fname);
if (have_dnskey) {
dssetp = &val->dsrdataset;
keysetp = &val->frdataset;
} else {
dssetp = &val->frdataset;
}
if (!have_dnskey && check_ds_private(&val->frdataset)) {
if (dns_rdataset_isassociated(&val->dsrdataset))
{
dns_rdataset_disassociate(
&val->dsrdataset);
}
dns_rdataset_clone(&val->frdataset,
&val->dsrdataset);
dssetp = &val->dsrdataset;
dns_rdataset_disassociate(&val->frdataset);
result = view_find(val, fname,
dns_rdatatype_dnskey);
switch (result) {
case ISC_R_SUCCESS:
keysetp = &val->frdataset;
break;
case ISC_R_NOTFOUND:
/*
* We don't know anything about the
* DNSKEY. Find it.
*/
result = create_fetch(
val, fname,
dns_rdatatype_dnskey,
fetch_callback_dnskey,
"seek_ds");
if (result == ISC_R_SUCCESS) {
result = DNS_R_WAIT;
}
goto out;
default:
validator_log(val, ISC_LOG_DEBUG(3),
"no DNSKEY found (%s/DS)",
namebuf);
break;
}
}
if (!check_ds_algs(val, fname, dssetp, keysetp)) {
dns_name_format(fname, namebuf,
sizeof(namebuf));
validator_log(
val, ISC_LOG_DEBUG(3),
"no supported algorithm/digest (%s/DS)",
namebuf);
result = markanswer(val, "proveunsecure (2)");
goto out;
}
}
val->labels++;
}
@ -3308,7 +3582,7 @@ validator_start(void *arg) {
validator_log(val, ISC_LOG_DEBUG(3),
"attempting insecurity proof");
result = proveunsecure(val, false, false);
result = proveunsecure(val, false, false, false);
if (result == DNS_R_NOTINSECURE) {
validator_log(val, ISC_LOG_INFO,
"got insecure response; "
@ -3421,6 +3695,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
dns_rdataset_init(&val->fdsset);
dns_rdataset_init(&val->frdataset);
dns_rdataset_init(&val->fsigrdataset);
dns_rdataset_init(&val->dsrdataset);
dns_fixedname_init(&val->wild);
dns_fixedname_init(&val->closest);
val->start = isc_stdtime_now();
@ -3496,6 +3771,9 @@ destroy_validator(dns_validator_t *val) {
dns_keytable_detach(&val->keytable);
}
disassociate_rdatasets(val);
if (dns_rdataset_isassociated(&val->dsrdataset)) {
dns_rdataset_disassociate(&val->dsrdataset);
}
mctx = val->view->mctx;
if (val->siginfo != NULL) {
isc_mem_put(mctx, val->siginfo, sizeof(*val->siginfo));

View file

@ -1648,9 +1648,9 @@ dns_view_istrusted(dns_view_t *view, const dns_name_t *keyname,
goto finish;
}
result = dns_ds_fromkeyrdata(keyname, &rdata,
DNS_DSDIGEST_SHA256,
digest, &ds);
result = dns_ds_fromkeyrdata(
keyname, &rdata, DNS_DSDIGEST_SHA256, digest,
sizeof(digest), &ds);
if (result != ISC_R_SUCCESS) {
goto finish;
}
@ -2311,7 +2311,7 @@ dns_view_addtrustedkey(dns_view_t *view, dns_rdatatype_t rdtype,
isc_result_t result;
dns_name_t *name = UNCONST(keyname);
char rdatabuf[DST_KEY_MAXSIZE];
unsigned char digest[ISC_MAX_MD_SIZE];
unsigned char digest[DNS_DS_BUFFERSIZE];
dns_rdata_ds_t ds;
dns_rdata_t rdata;
isc_buffer_t b;
@ -2334,7 +2334,7 @@ dns_view_addtrustedkey(dns_view_t *view, dns_rdatatype_t rdtype,
CHECK(dns_rdata_tostruct(&rdata, &ds, NULL));
} else {
CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
digest, &ds));
digest, sizeof(digest), &ds));
}
CHECK(dns_keytable_add(view->secroots_priv, false, false, name, &ds,

View file

@ -728,7 +728,7 @@ struct dns_signing {
unsigned int magic;
dns_db_t *db;
dns_dbiterator_t *dbiterator;
dns_secalg_t algorithm;
dst_algorithm_t algorithm;
uint16_t keyid;
bool deleteit;
bool done;
@ -972,7 +972,7 @@ zone_notify(dns_zone_t *zone, isc_time_t *now);
static void
dump_done(void *arg, isc_result_t result);
static isc_result_t
zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, uint16_t keyid,
zone_signwithkey(dns_zone_t *zone, dst_algorithm_t algorithm, uint16_t keyid,
bool deleteit);
static isc_result_t
delete_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node,
@ -3755,6 +3755,9 @@ cleanup:
}
}
#define OLD_SIGNING_RECORD_SIZE 5
#define SIGNING_RECORD_SIZE 7
static void
resume_signingwithkey(dns_zone_t *zone) {
dns_dbnode_t *node = NULL;
@ -3788,14 +3791,22 @@ resume_signingwithkey(dns_zone_t *zone) {
DNS_RDATASET_FOREACH (&rdataset) {
dns_rdata_t rdata = DNS_RDATA_INIT;
dst_algorithm_t alg;
dns_rdataset_current(&rdataset, &rdata);
if (rdata.length != 5 || rdata.data[0] == 0 ||
rdata.data[4] != 0)
/*
* Old or New Forms
*/
if ((rdata.length != OLD_SIGNING_RECORD_SIZE &&
rdata.length != SIGNING_RECORD_SIZE) ||
rdata.data[0] == 0 || rdata.data[4] != 0)
{
continue;
}
result = zone_signwithkey(zone, rdata.data[0],
alg = (rdata.length == OLD_SIGNING_RECORD_SIZE)
? rdata.data[0]
: ((rdata.data[5] << 8) | rdata.data[6]);
result = zone_signwithkey(zone, alg,
(rdata.data[1] << 8) | rdata.data[2],
rdata.data[3]);
if (result != ISC_R_SUCCESS) {
@ -4422,7 +4433,7 @@ trust_key(dns_zone_t *zone, dns_name_t *keyname, dns_rdata_dnskey_t *dnskey,
bool initial) {
isc_result_t result;
dns_rdata_t rdata = DNS_RDATA_INIT;
unsigned char data[4096], digest[ISC_MAX_MD_SIZE];
unsigned char data[4096], digest[DNS_DS_BUFFERSIZE];
isc_buffer_t buffer;
dns_keytable_t *sr = NULL;
dns_rdata_ds_t ds;
@ -4437,7 +4448,7 @@ trust_key(dns_zone_t *zone, dns_name_t *keyname, dns_rdata_dnskey_t *dnskey,
dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
dns_rdatatype_dnskey, dnskey, &buffer);
CHECK(dns_ds_fromkeyrdata(keyname, &rdata, DNS_DSDIGEST_SHA256, digest,
&ds));
sizeof(digest), &ds));
CHECK(dns_keytable_add(sr, true, initial, keyname, &ds, sfd_add,
zone->view));
@ -6806,6 +6817,10 @@ delsig_ok(dns_rdata_rrsig_t *rrsig_ptr, dst_key_t **keys, unsigned int nkeys,
isc_result_t ret;
bool have_ksk = false, have_zsk = false;
bool have_pksk = false, have_pzsk = false;
dst_algorithm_t algorithm;
algorithm = dst_algorithm_fromdata(
rrsig_ptr->algorithm, rrsig_ptr->signature, rrsig_ptr->siglen);
for (i = 0; i < nkeys; i++) {
bool ksk, zsk;
@ -6814,7 +6829,7 @@ delsig_ok(dns_rdata_rrsig_t *rrsig_ptr, dst_key_t **keys, unsigned int nkeys,
break;
}
if (rrsig_ptr->algorithm != dst_key_alg(keys[i])) {
if (algorithm != dst_key_alg(keys[i])) {
continue;
}
@ -6873,7 +6888,7 @@ delsig_ok(dns_rdata_rrsig_t *rrsig_ptr, dst_key_t **keys, unsigned int nkeys,
* if the associated public key is still in the DNSKEY RRset
*/
for (i = 0; i < nkeys; i++) {
if ((rrsig_ptr->algorithm == dst_key_alg(keys[i])) &&
if ((algorithm == dst_key_alg(keys[i])) &&
(rrsig_ptr->keyid == dst_key_id(keys[i])))
{
return false;
@ -6936,10 +6951,13 @@ del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
DNS_RDATASET_FOREACH (&rdataset) {
dns_rdata_t rdata = DNS_RDATA_INIT;
dst_algorithm_t algorithm;
dns_rdataset_current(&rdataset, &rdata);
result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
algorithm = dst_algorithm_fromdata(
rrsig.algorithm, rrsig.signature, rrsig.siglen);
if (!dns_rdatatype_iskeymaterial(type)) {
bool warn = false, deleted = false;
@ -6983,9 +7001,8 @@ del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
char algbuf[DNS_NAME_FORMATSIZE];
dns_name_format(&zone->origin, origin,
sizeof(origin));
dns_secalg_format(rrsig.algorithm,
algbuf,
sizeof(algbuf));
dst_algorithm_format(algorithm, algbuf,
sizeof(algbuf));
dns_zone_log(zone, ISC_LOG_WARNING,
"Key %s/%s/%d "
"missing or inactive "
@ -7005,7 +7022,7 @@ del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
*/
found = false;
for (i = 0; i < nkeys; i++) {
if (rrsig.algorithm == dst_key_alg(keys[i]) &&
if (algorithm == dst_key_alg(keys[i]) &&
rrsig.keyid == dst_key_id(keys[i]))
{
found = true;
@ -7618,13 +7635,16 @@ signed_with_good_key(dns_zone_t *zone, dns_db_t *db, dns_dbnode_t *node,
dns_rdataset_current(&rdataset, &rdata);
result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
INSIST(result == ISC_R_SUCCESS);
if (rrsig.algorithm == dst_key_alg(key) &&
dst_algorithm_t algorithm;
algorithm = dst_algorithm_fromdata(
rrsig.algorithm, rrsig.signature, rrsig.siglen);
if (algorithm == dst_key_alg(key) &&
rrsig.keyid == dst_key_id(key))
{
dns_rdataset_disassociate(&rdataset);
return true;
}
if (rrsig.algorithm == dst_key_alg(key)) {
if (algorithm == dst_key_alg(key)) {
count++;
}
}
@ -7958,18 +7978,25 @@ updatesignwithkey(dns_zone_t *zone, dns_signing_t *signing,
INSIST(!dns_rdataset_isassociated(&rdataset));
goto failure;
}
DNS_RDATASET_FOREACH (&rdataset) {
dns_rdata_t rdata = DNS_RDATA_INIT;
unsigned char alg = dst_algorithm_tosecalg(signing->algorithm);
dns_rdataset_current(&rdataset, &rdata);
/*
* If we don't match the algorithm or keyid skip the record.
*/
if (rdata.length != 5 || rdata.data[0] != signing->algorithm ||
if ((rdata.length != SIGNING_RECORD_SIZE &&
rdata.length != OLD_SIGNING_RECORD_SIZE) ||
rdata.data[0] == 0 || rdata.data[0] != alg ||
rdata.data[1] != ((signing->keyid >> 8) & 0xff) ||
rdata.data[2] != (signing->keyid & 0xff))
rdata.data[2] != (signing->keyid & 0xff) ||
(rdata.length == SIGNING_RECORD_SIZE &&
(rdata.data[5] != (signing->algorithm >> 8 & 0xff) ||
rdata.data[6] != (signing->algorithm & 0xff))))
{
have_rr = true;
dns_rdata_reset(&rdata);
continue;
}
/*
@ -7999,20 +8026,32 @@ updatesignwithkey(dns_zone_t *zone, dns_signing_t *signing,
* finished signing the zone with this key. If it is already
* there we don't need to add it a second time.
*/
unsigned char data[5] = {
signing->algorithm,
unsigned char data[SIGNING_RECORD_SIZE] = {
dst_algorithm_tosecalg(signing->algorithm),
(signing->keyid >> 8) & 0xff,
signing->keyid & 0xff,
0,
1,
(signing->algorithm >> 8) & 0xff,
signing->algorithm & 0xff,
};
dns_rdata_t rdata = (dns_rdata_t){
.length = sizeof(data),
.length = signing->algorithm < 256
? OLD_SIGNING_RECORD_SIZE
: sizeof(data),
.data = data,
.type = zone->privatetype,
.rdclass = dns_db_class(signing->db),
.link = ISC_LINK_INITIALIZER,
};
/*
* data[0] can't be 0 as that is used to signal that the
* record is being used to for NSEC/NSEC3 chains generation.
* Set it to 255 instead.
*/
if (data[0] == 0) {
data[0] = 255;
}
CHECK(update_one_rr(signing->db, version, diff, DNS_DIFFOP_ADD,
&zone->origin, rdataset.ttl, &rdata));
} else if (!have_rr) {
@ -9341,7 +9380,7 @@ failure:
*/
static isc_result_t
del_sig(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
dns_dbnode_t *node, unsigned int nkeys, dns_secalg_t algorithm,
dns_dbnode_t *node, unsigned int nkeys, dst_algorithm_t algorithm,
uint16_t keyid, bool *has_algp, dns_diff_t *diff) {
dns_rdata_rrsig_t rrsig;
dns_rdataset_t rdataset;
@ -9382,12 +9421,17 @@ del_sig(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
}
DNS_RDATASET_FOREACH (&rdataset) {
dns_rdata_t rdata = DNS_RDATA_INIT;
dst_algorithm_t sigalg;
dns_rdataset_current(&rdataset, &rdata);
CHECK(dns_rdata_tostruct(&rdata, &rrsig, NULL));
if (nkeys != 0 && (rrsig.algorithm != algorithm ||
rrsig.keyid != keyid))
sigalg = dst_algorithm_fromdata(
rrsig.algorithm, rrsig.signature, rrsig.siglen);
if (nkeys != 0 &&
(sigalg != algorithm || rrsig.keyid != keyid))
{
if (rrsig.algorithm == algorithm) {
if (sigalg == algorithm) {
has_alg = true;
}
continue;
@ -9752,7 +9796,7 @@ zone_sign(dns_zone_t *zone) {
* When adding look for the specific key.
*/
if (!signing->deleteit &&
(dst_key_alg(zone_keys[i]) != signing->algorithm ||
(ALG(zone_keys[i]) != signing->algorithm ||
dst_key_id(zone_keys[i]) != signing->keyid))
{
continue;
@ -10288,6 +10332,7 @@ revocable(dns_keyfetch_t *kfetch, dns_rdata_keydata_t *keydata) {
unsigned char key_buf[4096];
isc_buffer_t keyb;
bool answer = false;
dst_algorithm_t algorithm;
REQUIRE(kfetch != NULL && keydata != NULL);
REQUIRE(dns_rdataset_isassociated(&kfetch->dnskeysigset));
@ -10315,7 +10360,9 @@ revocable(dns_keyfetch_t *kfetch, dns_rdata_keydata_t *keydata) {
result = dns_rdata_tostruct(&sigrr, &sig, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (dst_key_alg(dstkey) == sig.algorithm &&
algorithm = dst_algorithm_fromdata(sig.algorithm, sig.signature,
sig.siglen);
if (dst_key_alg(dstkey) == algorithm &&
dst_key_rid(dstkey) == sig.keyid)
{
result = dns_dnssec_verify(keyname, &kfetch->dnskeyset,
@ -16440,7 +16487,8 @@ cds_inuse(dns_zone_t *zone, dns_rdata_t *rdata, dns_dnsseckeylist_t *keylist,
unsigned char cdsbuf[DNS_DS_BUFFERSIZE];
if (dst_key_id(k->key) != cds.key_tag ||
dst_key_alg(k->key) != cds.algorithm)
dst_algorithm_tosecalg(dst_key_alg(k->key)) !=
cds.algorithm)
{
continue;
}
@ -16453,7 +16501,8 @@ cds_inuse(dns_zone_t *zone, dns_rdata_t *rdata, dns_dnsseckeylist_t *keylist,
return result;
}
result = dns_ds_buildrdata(dns_zone_getorigin(zone), &dnskey,
cds.digest_type, cdsbuf, &cdsrdata);
cds.digest_type, cdsbuf,
sizeof(cdsbuf), &cdsrdata);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR,
"dns_ds_buildrdata(keytag=%d, algo=%d, "
@ -20093,8 +20142,8 @@ dns_zone_setnotifydelay(dns_zone_t *zone, uint32_t delay) {
}
isc_result_t
dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, uint16_t keyid,
bool deleteit) {
dns_zone_signwithkey(dns_zone_t *zone, dst_algorithm_t algorithm,
uint16_t keyid, bool deleteit) {
isc_result_t result;
REQUIRE(DNS_ZONE_VALID(zone));
@ -20178,7 +20227,7 @@ dns_zone_getprivatetype(dns_zone_t *zone) {
}
static isc_result_t
zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, uint16_t keyid,
zone_signwithkey(dns_zone_t *zone, dst_algorithm_t algorithm, uint16_t keyid,
bool deleteit) {
dns_signing_t *signing = NULL;
isc_result_t result = ISC_R_SUCCESS;
@ -20335,7 +20384,7 @@ add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype,
isc_region_t r;
isc_result_t result = ISC_R_SUCCESS;
uint16_t keyid;
unsigned char buf[5];
unsigned char data[SIGNING_RECORD_SIZE];
dns_name_t *name = dns_db_origin(db);
dns_difftuplelist_t add = ISC_LIST_INITIALIZER;
dns_difftuplelist_t del = ISC_LIST_INITIALIZER;
@ -20410,17 +20459,23 @@ add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype,
* or added.
*/
ISC_LIST_FOREACH (tuples, tuple, link) {
dst_algorithm_t algorithm;
dns_rdata_toregion(&tuple->rdata, &r);
keyid = dst_region_computeid(&r);
buf[0] = dnskey.algorithm;
buf[1] = (keyid & 0xff00) >> 8;
buf[2] = (keyid & 0xff);
buf[3] = (tuple->op == DNS_DIFFOP_ADD) ? 0 : 1;
buf[4] = 0;
rdata.data = buf;
rdata.length = sizeof(buf);
algorithm = dst_algorithm_fromdata(dnskey.algorithm,
dnskey.data, dnskey.datalen);
data[0] = dnskey.algorithm;
data[1] = (keyid & 0xff00) >> 8;
data[2] = (keyid & 0xff);
data[3] = (tuple->op == DNS_DIFFOP_ADD) ? 0 : 1;
data[4] = 0;
data[5] = (algorithm & 0xff00) >> 8;
data[6] = (algorithm & 0xff);
rdata.data = data;
rdata.length = algorithm < 256 ? OLD_SIGNING_RECORD_SIZE
: sizeof(data);
rdata.type = privatetype;
rdata.rdclass = tuple->rdata.rdclass;
@ -20440,7 +20495,7 @@ add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype,
* Remove any record which says this operation has already
* completed.
*/
buf[4] = 1;
data[4] = 1;
CHECK(rr_exists(db, ver, name, &rdata, &flag));
if (flag) {
dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, name,
@ -20609,7 +20664,9 @@ failure:
* are any signatures using that algorithm.
*/
static bool
signed_with_alg(dns_rdataset_t *rdataset, dns_secalg_t alg) {
signed_with_alg(dns_rdataset_t *rdataset, dst_algorithm_t alg) {
dst_algorithm_t sigalg;
REQUIRE(rdataset == NULL || rdataset->type == dns_rdatatype_rrsig);
if (rdataset == NULL || !dns_rdataset_isassociated(rdataset)) {
return false;
@ -20621,7 +20678,9 @@ signed_with_alg(dns_rdataset_t *rdataset, dns_secalg_t alg) {
dns_rdataset_current(rdataset, &rdata);
dns_rdata_tostruct(&rdata, &rrsig, NULL);
if (rrsig.algorithm == alg) {
sigalg = dst_algorithm_fromdata(rrsig.algorithm,
rrsig.signature, rrsig.siglen);
if (sigalg == alg) {
return true;
}
}
@ -20967,13 +21026,16 @@ checkds_done(void *arg) {
if (dst_key_id(key->key) != ds.key_tag) {
continue;
}
if (dst_key_alg(key->key) != ds.algorithm) {
if (dst_algorithm_tosecalg(dst_key_alg(key->key)) !=
ds.algorithm)
{
continue;
}
/* Derive DS from DNSKEY, see if the rdata is equal. */
make_dnskey(key->key, keybuf, sizeof(keybuf), &dnskey);
r = dns_ds_buildrdata(&zone->origin, &dnskey,
ds.digest_type, dsbuf, &dsrdata);
ds.digest_type, dsbuf,
sizeof(dsbuf), &dsrdata);
if (r != ISC_R_SUCCESS) {
continue;
}
@ -22804,7 +22866,7 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
isc_result_t result;
dns_dbnode_t *node = NULL;
dns_rdataset_t dnskey, cds, cdnskey;
unsigned char algorithms[256];
unsigned char algorithms[DST_MAX_ALGS];
unsigned int i;
bool empty = false;
@ -22879,21 +22941,49 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
}
CHECK(dns_rdata_tostruct(&crdata, &structcds, NULL));
if (algorithms[structcds.algorithm] == 0) {
algorithms[structcds.algorithm] = expected;
}
DNS_RDATASET_FOREACH (&dnskey) {
if (structcds.algorithm != DNS_KEYALG_PRIVATEDNS &&
structcds.algorithm != DNS_KEYALG_PRIVATEOID)
{
if (algorithms[structcds.algorithm] == 0) {
algorithms[structcds.algorithm] =
expected;
}
DNS_RDATASET_FOREACH (&dnskey) {
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_dnskey_t structdnskey;
dns_rdataset_current(&dnskey, &rdata);
dns_rdata_tostruct(&rdata,
&structdnskey, NULL);
if (structdnskey.algorithm ==
structcds.algorithm)
{
algorithms[structcds.algorithm] =
found;
}
}
} else {
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_dnskey_t structdnskey;
dst_algorithm_t dnskeyalg;
dns_rdataset_current(&dnskey, &rdata);
dns_rdata_tostruct(&rdata, &structdnskey, NULL);
if (structdnskey.algorithm ==
structcds.algorithm)
{
algorithms[structcds.algorithm] = found;
/* Convert CDS to DS */
crdata.type = dns_rdatatype_ds;
result = dns_dnssec_matchdskey(&zone->origin,
&crdata, &dnskey,
&rdata);
if (result != ISC_R_SUCCESS) {
result = DNS_R_BADCDS;
goto failure;
}
CHECK(dns_rdata_tostruct(&rdata, &structdnskey,
NULL));
dnskeyalg = dst_algorithm_fromdata(
structdnskey.algorithm,
structdnskey.data,
structdnskey.datalen);
algorithms[dnskeyalg] = found;
}
}
for (i = 0; i < sizeof(algorithms); i++) {
@ -22920,6 +23010,7 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
DNS_RDATASET_FOREACH (&cdnskey) {
dns_rdata_t crdata = DNS_RDATA_INIT;
dns_rdata_cdnskey_t structcdnskey;
dst_algorithm_t cdnskeyalg;
dns_rdataset_current(&cdnskey, &crdata);
/*
@ -22942,22 +23033,27 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
CHECK(dns_rdata_tostruct(&crdata, &structcdnskey,
NULL));
if (algorithms[structcdnskey.algorithm] == 0) {
algorithms[structcdnskey.algorithm] = expected;
cdnskeyalg = dst_algorithm_fromdata(
structcdnskey.algorithm, structcdnskey.data,
structcdnskey.datalen);
if (algorithms[cdnskeyalg] == 0) {
algorithms[cdnskeyalg] = expected;
}
DNS_RDATASET_FOREACH (&dnskey) {
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_dnskey_t structdnskey;
dst_algorithm_t dnskeyalg;
dns_rdataset_current(&dnskey, &rdata);
CHECK(dns_rdata_tostruct(&rdata, &structdnskey,
NULL));
dnskeyalg = dst_algorithm_fromdata(
structdnskey.algorithm,
structdnskey.data,
structdnskey.datalen);
if (structdnskey.algorithm ==
structcdnskey.algorithm)
{
algorithms[structcdnskey.algorithm] =
found;
if (dnskeyalg == cdnskeyalg) {
algorithms[cdnskeyalg] = found;
}
}
}
@ -23211,7 +23307,7 @@ dns_zone_issecure(dns_zone_t *zone) {
struct keydone {
bool all;
unsigned char data[5];
unsigned char data[SIGNING_RECORD_SIZE];
dns_zone_t *zone;
};
@ -23279,8 +23375,11 @@ keydone(void *arg) {
dns_rdataset_current(&rdataset, &rdata);
if (kd->all) {
if (rdata.length == 5 && rdata.data[0] != 0 &&
rdata.data[3] == 0 && rdata.data[4] == 1)
/* Old (5) and new (7) forms */
if ((rdata.length == OLD_SIGNING_RECORD_SIZE ||
rdata.length == SIGNING_RECORD_SIZE) &&
rdata.data[0] != 0 && rdata.data[3] == 0 &&
rdata.data[4] == 1)
{
found = true;
} else if (rdata.data[0] == 0 &&
@ -23289,8 +23388,14 @@ keydone(void *arg) {
found = true;
clear_pending = true;
}
} else if (rdata.length == 5 &&
memcmp(rdata.data, kd->data, 5) == 0)
} else if (rdata.length == OLD_SIGNING_RECORD_SIZE &&
memcmp(rdata.data, kd->data,
OLD_SIGNING_RECORD_SIZE) == 0)
{
found = true;
} else if (rdata.length == SIGNING_RECORD_SIZE &&
memcmp(rdata.data, kd->data, SIGNING_RECORD_SIZE) ==
0)
{
found = true;
}
@ -23367,7 +23472,7 @@ dns_zone_keydone(dns_zone_t *zone, const char *keystr) {
isc_textregion_t r;
const char *algstr = NULL;
dns_keytag_t keyid;
dns_secalg_t alg;
dst_algorithm_t alg;
size_t n;
n = sscanf(keystr, "%hu/", &keyid);
@ -23382,20 +23487,20 @@ dns_zone_keydone(dns_zone_t *zone, const char *keystr) {
CHECK(ISC_R_FAILURE);
}
n = sscanf(algstr, "%hhu", &alg);
n = sscanf(algstr, "%u", &alg);
if (n == 0U) {
r.base = UNCONST(algstr);
r.length = strlen(algstr);
CHECK(dns_secalg_fromtext(&alg, &r));
CHECK(dst_algorithm_fromtext(&alg, &r));
}
/* construct a private-type rdata */
isc_buffer_init(&b, kd->data, sizeof(kd->data));
isc_buffer_putuint8(&b, alg);
isc_buffer_putuint8(&b, (keyid & 0xff00) >> 8);
isc_buffer_putuint8(&b, (keyid & 0xff));
isc_buffer_putuint8(&b, dst_algorithm_tosecalg(alg));
isc_buffer_putuint16(&b, keyid);
isc_buffer_putuint8(&b, 0);
isc_buffer_putuint8(&b, 1);
isc_buffer_putuint16(&b, alg);
}
zone_iattach(zone, &kd->zone);

View file

@ -68,14 +68,14 @@ typedef struct vctx {
dns_rdataset_t nsecsigs;
dns_rdataset_t nsec3paramset;
dns_rdataset_t nsec3paramsigs;
unsigned char revoked_ksk[256];
unsigned char revoked_zsk[256];
unsigned char standby_ksk[256];
unsigned char standby_zsk[256];
unsigned char ksk_algorithms[256];
unsigned char zsk_algorithms[256];
unsigned char bad_algorithms[256];
unsigned char act_algorithms[256];
unsigned char revoked_ksk[DST_MAX_ALGS];
unsigned char revoked_zsk[DST_MAX_ALGS];
unsigned char standby_ksk[DST_MAX_ALGS];
unsigned char standby_zsk[DST_MAX_ALGS];
unsigned char ksk_algorithms[DST_MAX_ALGS];
unsigned char zsk_algorithms[DST_MAX_ALGS];
unsigned char bad_algorithms[DST_MAX_ALGS];
unsigned char act_algorithms[DST_MAX_ALGS];
isc_heap_t *expected_chains;
isc_heap_t *found_chains;
} vctx_t;
@ -173,12 +173,16 @@ goodsig(const vctx_t *vctx, dns_rdata_t *sigrdata, const dns_name_t *name,
dst_key_t **dstkeys, size_t nkeys, dns_rdataset_t *rdataset) {
dns_rdata_rrsig_t sig;
isc_result_t result;
dst_algorithm_t algorithm;
result = dns_rdata_tostruct(sigrdata, &sig, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
algorithm = dst_algorithm_fromdata(sig.algorithm, sig.signature,
sig.siglen);
for (size_t key = 0; key < nkeys; key++) {
if (sig.algorithm != dst_key_alg(dstkeys[key]) ||
if (algorithm != dst_key_alg(dstkeys[key]) ||
sig.keyid != dst_key_id(dstkeys[key]) ||
!dns_name_equal(&sig.signer, vctx->origin))
{
@ -792,7 +796,7 @@ verifynsec3s(const vctx_t *vctx, const dns_name_t *name,
static isc_result_t
verifyset(vctx_t *vctx, dns_rdataset_t *rdataset, const dns_name_t *name,
dns_dbnode_t *node, dst_key_t **dstkeys, size_t nkeys) {
unsigned char set_algorithms[256] = { 0 };
unsigned char set_algorithms[DST_MAX_ALGS] = { 0 };
char namebuf[DNS_NAME_FORMATSIZE];
char algbuf[DNS_SECALG_FORMATSIZE];
char typebuf[DNS_RDATATYPE_FORMATSIZE];
@ -835,6 +839,7 @@ verifyset(vctx_t *vctx, dns_rdataset_t *rdataset, const dns_name_t *name,
DNS_RDATASET_FOREACH (&sigrdataset) {
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_rrsig_t sig;
dst_algorithm_t algorithm;
dns_rdataset_current(&sigrdataset, &rdata);
result = dns_rdata_tostruct(&rdata, &sig, NULL);
@ -849,15 +854,17 @@ verifyset(vctx_t *vctx, dns_rdataset_t *rdataset, const dns_name_t *name,
namebuf, typebuf, sig.keyid);
continue;
}
if ((set_algorithms[sig.algorithm] != 0) ||
(vctx->act_algorithms[sig.algorithm] == 0))
algorithm = dst_algorithm_fromdata(sig.algorithm, sig.signature,
sig.siglen);
if ((set_algorithms[algorithm] != 0) ||
(vctx->act_algorithms[algorithm] == 0))
{
continue;
}
if (goodsig(vctx, &rdata, name, dstkeys, nkeys, rdataset)) {
dns_rdataset_settrust(rdataset, dns_trust_secure);
dns_rdataset_settrust(&sigrdataset, dns_trust_secure);
set_algorithms[sig.algorithm] = 1;
set_algorithms[algorithm] = 1;
}
}
result = ISC_R_SUCCESS;
@ -871,7 +878,7 @@ verifyset(vctx_t *vctx, dns_rdataset_t *rdataset, const dns_name_t *name,
if ((vctx->act_algorithms[i] != 0) &&
(set_algorithms[i] == 0))
{
dns_secalg_format(i, algbuf, sizeof(algbuf));
dst_algorithm_format(i, algbuf, sizeof(algbuf));
zoneverify_log_error(vctx,
"No correct %s signature "
"for %s %s",
@ -1425,10 +1432,13 @@ check_dnskey_sigs(vctx_t *vctx, const dns_rdata_dnskey_t *dnskey,
dst_key_t *key = NULL;
isc_result_t result;
dns_rdataset_t dsset;
dst_algorithm_t algorithm;
active_keys = (is_ksk ? vctx->ksk_algorithms : vctx->zsk_algorithms);
standby_keys = (is_ksk ? vctx->standby_ksk : vctx->standby_zsk);
goodkey = (is_ksk ? &vctx->goodksk : &vctx->goodzsk);
algorithm = dst_algorithm_fromdata(dnskey->algorithm, dnskey->data,
dnskey->datalen);
/*
* First, does this key sign the DNSKEY rrset?
@ -1440,19 +1450,19 @@ check_dnskey_sigs(vctx_t *vctx, const dns_rdata_dnskey_t *dnskey,
dns_dnssec_signs(keyrdata, vctx->origin, &vctx->soaset,
&vctx->soasigs, false, vctx->mctx))
{
if (active_keys[dnskey->algorithm] != DNS_KEYALG_MAX) {
active_keys[dnskey->algorithm]++;
if (active_keys[algorithm] != DNS_KEYALG_MAX) {
active_keys[algorithm]++;
}
} else {
if (standby_keys[dnskey->algorithm] != DNS_KEYALG_MAX) {
standby_keys[dnskey->algorithm]++;
if (standby_keys[algorithm] != DNS_KEYALG_MAX) {
standby_keys[algorithm]++;
}
}
return;
}
if (active_keys[dnskey->algorithm] != DNS_KEYALG_MAX) {
active_keys[dnskey->algorithm]++;
if (active_keys[algorithm] != DNS_KEYALG_MAX) {
active_keys[algorithm]++;
}
/*
@ -1503,14 +1513,15 @@ check_dnskey_sigs(vctx_t *vctx, const dns_rdata_dnskey_t *dnskey,
RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (ds.key_tag != dst_key_id(key) ||
ds.algorithm != dst_key_alg(key))
ds.algorithm !=
dst_algorithm_tosecalg(dst_key_alg(key)))
{
continue;
}
result = dns_ds_buildrdata(vctx->origin, keyrdata,
ds.digest_type, buf,
&newdsrdata);
sizeof(buf), &newdsrdata);
if (result != ISC_R_SUCCESS) {
continue;
}
@ -1558,6 +1569,7 @@ check_dnskey(vctx_t *vctx) {
if ((dnskey.flags & DNS_KEYOWNER_ZONE) != 0 &&
(dnskey.flags & DNS_KEYFLAG_REVOKE) != 0)
{
dst_algorithm_t algorithm;
if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 &&
!dns_dnssec_selfsigns(&rdata, vctx->origin,
&vctx->keyset, &vctx->keysigs,
@ -1586,16 +1598,17 @@ check_dnskey(vctx_t *vctx) {
buffer);
return ISC_R_FAILURE;
}
algorithm = dst_algorithm_fromdata(
dnskey.algorithm, dnskey.data, dnskey.datalen);
if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 &&
vctx->revoked_ksk[dnskey.algorithm] !=
DNS_KEYALG_MAX)
vctx->revoked_ksk[algorithm] != DNS_KEYALG_MAX)
{
vctx->revoked_ksk[dnskey.algorithm]++;
vctx->revoked_ksk[algorithm]++;
} else if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0 &&
vctx->revoked_zsk[dnskey.algorithm] !=
vctx->revoked_zsk[algorithm] !=
DNS_KEYALG_MAX)
{
vctx->revoked_zsk[dnskey.algorithm]++;
vctx->revoked_zsk[algorithm]++;
}
} else {
check_dnskey_sigs(vctx, &dnskey, &rdata, is_ksk);
@ -1627,7 +1640,7 @@ determine_active_algorithms(vctx_t *vctx, bool ignore_kskflag,
: 0;
}
if (vctx->act_algorithms[i] != 0) {
dns_secalg_format(i, algbuf, sizeof(algbuf));
dst_algorithm_format(i, algbuf, sizeof(algbuf));
report("- %s", algbuf);
}
}
@ -1646,7 +1659,7 @@ determine_active_algorithms(vctx_t *vctx, bool ignore_kskflag,
{
continue;
}
dns_secalg_format(i, algbuf, sizeof(algbuf));
dst_algorithm_format(i, algbuf, sizeof(algbuf));
zoneverify_log_error(vctx, "Missing %s for algorithm %s",
(vctx->ksk_algorithms[i] != 0) ? "ZSK"
: "self-"
@ -1889,7 +1902,7 @@ check_bad_algorithms(const vctx_t *vctx, void (*report)(const char *, ...)) {
report("The zone is not fully signed "
"for the following algorithms:");
}
dns_secalg_format(i, algbuf, sizeof(algbuf));
dst_algorithm_format(i, algbuf, sizeof(algbuf));
report(" %s", algbuf);
first = false;
}
@ -1916,7 +1929,7 @@ print_summary(const vctx_t *vctx, bool keyset_kskonly,
{
continue;
}
dns_secalg_format(i, algbuf, sizeof(algbuf));
dst_algorithm_format(i, algbuf, sizeof(algbuf));
report("Algorithm: %s: KSKs: "
"%u active, %u stand-by, %u revoked",
algbuf, vctx->ksk_algorithms[i], vctx->standby_ksk[i],

View file

@ -365,12 +365,12 @@ disabled_algorithms(const cfg_obj_t *disabled) {
CFG_LIST_FOREACH (obj, element) {
isc_textregion_t r;
dns_secalg_t alg;
dst_algorithm_t alg;
r.base = UNCONST(cfg_obj_asstring(cfg_listelt_value(element)));
r.length = strlen(r.base);
tresult = dns_secalg_fromtext(&alg, &r);
tresult = dst_algorithm_fromtext(&alg, &r);
if (tresult != ISC_R_SUCCESS) {
cfg_obj_log(cfg_listelt_value(element), ISC_LOG_ERROR,
"invalid algorithm '%s'", r.base);

View file

@ -31,6 +31,8 @@
#include <dns/secalg.h>
#include <dns/ttl.h>
#include <dst/dst.h>
#include <isccfg/cfg.h>
#include <isccfg/duration.h>
#include <isccfg/kaspconf.h>
@ -127,7 +129,7 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
INSIST(!offline_ksk);
key->role |= DNS_KASP_KEY_ROLE_KSK | DNS_KASP_KEY_ROLE_ZSK;
key->lifetime = 0; /* unlimited */
key->algorithm = DNS_KEYALG_ECDSA256;
key->algorithm = DST_ALG_ECDSA256;
key->length = -1;
result = dns_keystorelist_find(keystorelist,
DNS_KEYSTORE_KEYDIRECTORY,
@ -217,8 +219,8 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
obj = cfg_tuple_get(config, "algorithm");
alg.base = cfg_obj_asstring(obj);
alg.length = strlen(alg.base);
result = dns_secalg_fromtext(&key->algorithm,
(isc_textregion_t *)&alg);
result = dst_algorithm_fromtext(&key->algorithm,
(isc_textregion_t *)&alg);
if (result != ISC_R_SUCCESS) {
cfg_obj_log(obj, ISC_LOG_ERROR,
"dnssec-policy: bad algorithm %s",
@ -226,10 +228,9 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
result = DNS_R_BADALG;
goto cleanup;
}
if (check_algorithms && isc_crypto_fips_mode() &&
(key->algorithm == DNS_KEYALG_RSASHA1 ||
key->algorithm == DNS_KEYALG_NSEC3RSASHA1))
(key->algorithm == DST_ALG_RSASHA1 ||
key->algorithm == DST_ALG_NSEC3RSASHA1))
{
cfg_obj_log(obj, ISC_LOG_ERROR,
"dnssec-policy: algorithm %s not supported "
@ -255,14 +256,16 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
size = cfg_obj_asuint32(obj);
switch (key->algorithm) {
case DNS_KEYALG_RSASHA1:
case DNS_KEYALG_NSEC3RSASHA1:
case DNS_KEYALG_RSASHA256:
case DNS_KEYALG_RSASHA512:
case DST_ALG_RSASHA1:
case DST_ALG_NSEC3RSASHA1:
case DST_ALG_RSASHA256:
case DST_ALG_RSASHA512:
case DST_ALG_RSASHA256PRIVATEOID:
case DST_ALG_RSASHA512PRIVATEOID:
if (isc_crypto_fips_mode()) {
min = 2048;
} else {
min = DNS_KEYALG_RSASHA512 ? 1024 : 512;
min = DST_ALG_RSASHA512 ? 1024 : 512;
}
if (size < min || size > 4096) {
cfg_obj_log(obj, ISC_LOG_ERROR,
@ -274,10 +277,10 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
goto cleanup;
}
break;
case DNS_KEYALG_ECDSA256:
case DNS_KEYALG_ECDSA384:
case DNS_KEYALG_ED25519:
case DNS_KEYALG_ED448:
case DST_ALG_ECDSA256:
case DST_ALG_ECDSA384:
case DST_ALG_ED25519:
case DST_ALG_ED448:
cfg_obj_log(obj, ISC_LOG_WARNING,
"dnssec-policy: key algorithm %s "
"has predefined length; ignoring "
@ -356,8 +359,8 @@ cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp) {
}
/* NSEC3 cannot be used with certain key algorithms. */
if (keyalg == DNS_KEYALG_RSAMD5 || keyalg == DNS_KEYALG_DSA ||
keyalg == DNS_KEYALG_RSASHA1)
if (keyalg == DST_ALG_RSAMD5 || keyalg == DST_ALG_DSA ||
keyalg == DST_ALG_RSASHA1)
{
badalg = keyalg;
}
@ -624,8 +627,8 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
(void)confget(maps, "keys", &keys);
if (keys != NULL) {
char role[256] = { 0 };
bool warn[256][2] = { { false } };
char role[DST_MAX_ALGS] = { 0 };
bool warn[DST_MAX_ALGS][2] = { { false } };
CFG_LIST_FOREACH (keys, element) {
cfg_obj_t *kobj = cfg_listelt_value(element);

View file

@ -2375,6 +2375,7 @@ get_key(ns_client_t *client, dns_db_t *db, dns_rdata_rrsig_t *rrsig,
bool secure = false;
dns_clientinfomethods_t cm;
dns_clientinfo_t ci;
dst_algorithm_t sigalg, keyalg;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
@ -2403,6 +2404,9 @@ get_key(ns_client_t *client, dns_db_t *db, dns_rdata_rrsig_t *rrsig,
result = dns_rdataset_next(keyrdataset);
}
sigalg = dst_algorithm_fromdata(rrsig->algorithm, rrsig->signature,
rrsig->siglen);
for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(keyrdataset))
{
dns_rdata_t rdata = DNS_RDATA_INIT;
@ -2411,10 +2415,10 @@ get_key(ns_client_t *client, dns_db_t *db, dns_rdata_rrsig_t *rrsig,
dns_rdataset_current(keyrdataset, &rdata);
dns_rdata_tostruct(&rdata, &key, NULL); /* can't fail */
keyalg = dst_algorithm_fromdata(key.algorithm, key.data,
key.datalen);
if (rrsig->algorithm != key.algorithm ||
!dns_dnssec_iszonekey(&key))
{
if (sigalg != keyalg || !dns_dnssec_iszonekey(&key)) {
continue;
}
@ -2476,14 +2480,18 @@ validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
dns_rdataset_current(sigrdataset, &rdata);
result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (!dns_resolver_algorithm_supported(client->view->resolver,
name, rrsig.algorithm))
if (!dns_resolver_algorithm_supported(
client->view->resolver, name, rrsig.algorithm,
rrsig.signature, rrsig.siglen))
{
char txt[DNS_NAME_FORMATSIZE + 32];
isc_buffer_t buffer;
dst_algorithm_t alg;
alg = dst_algorithm_fromdata(
rrsig.algorithm, rrsig.signature, rrsig.siglen);
isc_buffer_init(&buffer, txt, sizeof(txt));
dns_secalg_totext(rrsig.algorithm, &buffer);
dst_algorithm_totext(alg, &buffer);
isc_buffer_putstr(&buffer, " ");
dns_name_totext(name, DNS_NAME_OMITFINALDOT, &buffer);
isc_buffer_putstr(&buffer, " (cached)");

View file

@ -130,7 +130,7 @@ create_keystruct(uint16_t flags, uint8_t proto, uint8_t alg, const char *keystr,
static void
create_dsstruct(dns_name_t *name, uint16_t flags, uint8_t proto, uint8_t alg,
const char *keystr, unsigned char *digest,
const char *keystr, unsigned char *digest, size_t digest_len,
dns_rdata_ds_t *dsstruct) {
isc_result_t result;
unsigned char rrdata[4096];
@ -156,7 +156,7 @@ create_dsstruct(dns_name_t *name, uint16_t flags, uint8_t proto, uint8_t alg,
* Build DS rdata struct.
*/
result = dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256, digest,
dsstruct);
digest_len, dsstruct);
assert_int_equal(result, ISC_R_SUCCESS);
dns_rdata_freestruct(&dnskey);
@ -165,7 +165,7 @@ create_dsstruct(dns_name_t *name, uint16_t flags, uint8_t proto, uint8_t alg,
/* Common setup: create a keytable and ntatable to test with a few keys */
static void
create_tables(void) {
unsigned char digest[ISC_MAX_MD_SIZE];
unsigned char digest[DNS_DS_BUFFERSIZE];
dns_rdata_ds_t ds;
dns_fixedname_t fn;
dns_name_t *keyname = dns_fixedname_name(&fn);
@ -179,14 +179,16 @@ create_tables(void) {
/* Add a normal key */
dns_test_namefromstring("example.com.", &fn);
create_dsstruct(keyname, 257, 3, 5, keystr1, digest, &ds);
create_dsstruct(keyname, 257, 3, 5, keystr1, digest, sizeof(digest),
&ds);
assert_int_equal(dns_keytable_add(keytable, false, false, keyname, &ds,
NULL, NULL),
ISC_R_SUCCESS);
/* Add an initializing managed key */
dns_test_namefromstring("managed.com.", &fn);
create_dsstruct(keyname, 257, 3, 5, keystr1, digest, &ds);
create_dsstruct(keyname, 257, 3, 5, keystr1, digest, sizeof(digest),
&ds);
assert_int_equal(dns_keytable_add(keytable, true, true, keyname, &ds,
NULL, NULL),
ISC_R_SUCCESS);
@ -220,7 +222,7 @@ destroy_tables(void) {
ISC_LOOP_TEST_IMPL(add) {
dns_keynode_t *keynode = NULL;
dns_keynode_t *null_keynode = NULL;
unsigned char digest[ISC_MAX_MD_SIZE];
unsigned char digest[DNS_DS_BUFFERSIZE];
dns_rdata_ds_t ds;
dns_fixedname_t fn;
dns_name_t *keyname = dns_fixedname_name(&fn);
@ -241,7 +243,8 @@ ISC_LOOP_TEST_IMPL(add) {
* report success.
*/
dns_test_namefromstring("example.com.", &fn);
create_dsstruct(keyname, 257, 3, 5, keystr1, digest, &ds);
create_dsstruct(keyname, 257, 3, 5, keystr1, digest, sizeof(digest),
&ds);
assert_int_equal(dns_keytable_add(keytable, false, false, keyname, &ds,
NULL, NULL),
ISC_R_SUCCESS);
@ -252,7 +255,8 @@ ISC_LOOP_TEST_IMPL(add) {
/* Add another key (different keydata) */
dns_keynode_detach(&keynode);
create_dsstruct(keyname, 257, 3, 5, keystr2, digest, &ds);
create_dsstruct(keyname, 257, 3, 5, keystr2, digest, sizeof(digest),
&ds);
assert_int_equal(dns_keytable_add(keytable, false, false, keyname, &ds,
NULL, NULL),
ISC_R_SUCCESS);
@ -280,7 +284,8 @@ ISC_LOOP_TEST_IMPL(add) {
* node, the node should *not* be marked as initializing.
*/
dns_test_namefromstring("managed.com.", &fn);
create_dsstruct(keyname, 257, 3, 5, keystr2, digest, &ds);
create_dsstruct(keyname, 257, 3, 5, keystr2, digest, sizeof(digest),
&ds);
assert_int_equal(dns_keytable_add(keytable, true, true, keyname, &ds,
NULL, NULL),
ISC_R_SUCCESS);
@ -310,7 +315,8 @@ ISC_LOOP_TEST_IMPL(add) {
* initializing key.
*/
dns_test_namefromstring("two.com.", &fn);
create_dsstruct(keyname, 257, 3, 5, keystr1, digest, &ds);
create_dsstruct(keyname, 257, 3, 5, keystr1, digest, sizeof(digest),
&ds);
assert_int_equal(dns_keytable_add(keytable, true, true, keyname, &ds,
NULL, NULL),
ISC_R_SUCCESS);
@ -326,7 +332,8 @@ ISC_LOOP_TEST_IMPL(add) {
* trust anchor for two.com and we haven't run dns_keynode_trust(),
* the initialization status should not change.
*/
create_dsstruct(keyname, 257, 3, 5, keystr2, digest, &ds);
create_dsstruct(keyname, 257, 3, 5, keystr2, digest, sizeof(digest),
&ds);
assert_int_equal(dns_keytable_add(keytable, true, false, keyname, &ds,
NULL, NULL),
ISC_R_SUCCESS);
@ -344,7 +351,8 @@ ISC_LOOP_TEST_IMPL(add) {
&null_keynode),
ISC_R_SUCCESS);
dns_test_namefromstring("null.example.", &fn);
create_dsstruct(keyname, 257, 3, 5, keystr2, digest, &ds);
create_dsstruct(keyname, 257, 3, 5, keystr2, digest, sizeof(digest),
&ds);
assert_int_equal(dns_keytable_add(keytable, false, false, keyname, &ds,
NULL, NULL),
ISC_R_SUCCESS);
@ -598,7 +606,7 @@ ISC_LOOP_TEST_IMPL(nta) {
bool issecure, covered;
dns_fixedname_t fn;
dns_name_t *keyname = dns_fixedname_name(&fn);
unsigned char digest[ISC_MAX_MD_SIZE];
unsigned char digest[DNS_DS_BUFFERSIZE];
dns_rdata_ds_t ds;
dns_view_t *myview = NULL;
isc_stdtime_t now = isc_stdtime_now();
@ -616,7 +624,8 @@ ISC_LOOP_TEST_IMPL(nta) {
assert_int_equal(result, ISC_R_SUCCESS);
dns_test_namefromstring("example.", &fn);
create_dsstruct(keyname, 257, 3, 5, keystr1, digest, &ds);
create_dsstruct(keyname, 257, 3, 5, keystr1, digest, sizeof(digest),
&ds);
result = dns_keytable_add(keytable, false, false, keyname, &ds, NULL,
NULL),
assert_int_equal(result, ISC_R_SUCCESS);