mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-24 00:29:58 -05:00
- algorithm compromise protection using the algorithms signalled in
the DS record. Also, trust anchors, DLV, and RFC5011 receive this,
and thus, if you have multiple algorithms in your trust-anchor-file
then it will now behave different than before. Also, 5011 rollover
for algorithms needs to be double-signature until the old algorithm
is revoked.
git-svn-id: file:///svn/unbound/trunk@2358 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
f378068b32
commit
daab92e954
5 changed files with 52 additions and 31 deletions
|
|
@ -1,3 +1,12 @@
|
||||||
|
21 December 2010: Wouter
|
||||||
|
- algorithm compromise protection using the algorithms signalled in
|
||||||
|
the DS record. Also, trust anchors, DLV, and RFC5011 receive this,
|
||||||
|
and thus, if you have multiple algorithms in your trust-anchor-file
|
||||||
|
then it will now behave different than before. Also, 5011 rollover
|
||||||
|
for algorithms needs to be double-signature until the old algorithm
|
||||||
|
is revoked.
|
||||||
|
It is not an option, because I see no use to turn the security off.
|
||||||
|
|
||||||
17 December 2010: Wouter
|
17 December 2010: Wouter
|
||||||
- squelch 'tcp connect: bla' in logfile, (set verbosity 2 to see them).
|
- squelch 'tcp connect: bla' in logfile, (set verbosity 2 to see them).
|
||||||
- fix validation in this case: CNAME to nodata for co-hosted opt-in
|
- fix validation in this case: CNAME to nodata for co-hosted opt-in
|
||||||
|
|
|
||||||
|
|
@ -972,27 +972,17 @@ verify_dnskey(struct module_env* env, struct val_env* ve,
|
||||||
struct trust_anchor* tp, struct ub_packed_rrset_key* rrset)
|
struct trust_anchor* tp, struct ub_packed_rrset_key* rrset)
|
||||||
{
|
{
|
||||||
char* reason = NULL;
|
char* reason = NULL;
|
||||||
if(tp->ds_rrset) {
|
uint8_t sigalg[ALGO_NEEDS_MAX+1];
|
||||||
/* verify with ds, any will do to prime autotrust */
|
int downprot = 1;
|
||||||
enum sec_status sec = val_verify_DNSKEY_with_DS(
|
enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset,
|
||||||
env, ve, rrset, tp->ds_rrset, 0, &reason);
|
tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason);
|
||||||
verbose(VERB_ALGO, "autotrust: validate DNSKEY with DS: %s",
|
/* sigalg is ignored, it returns algorithms signalled to exist, but
|
||||||
sec_status_to_string(sec));
|
* in 5011 there are no other rrsets to check. if downprot is
|
||||||
if(sec == sec_status_secure) {
|
* enabled, then it checks that the DNSKEY is signed with all
|
||||||
return 1;
|
* algorithms available in the trust store. */
|
||||||
}
|
verbose(VERB_ALGO, "autotrust: validate DNSKEY with anchor: %s",
|
||||||
}
|
sec_status_to_string(sec));
|
||||||
if(tp->dnskey_rrset) {
|
return sec == sec_status_secure;
|
||||||
/* verify with keys */
|
|
||||||
enum sec_status sec = val_verify_rrset(env, ve, rrset,
|
|
||||||
tp->dnskey_rrset, 0, &reason);
|
|
||||||
verbose(VERB_ALGO, "autotrust: validate DNSKEY with keys: %s",
|
|
||||||
sec_status_to_string(sec));
|
|
||||||
if(sec == sec_status_secure) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Find minimum expiration interval from signatures */
|
/** Find minimum expiration interval from signatures */
|
||||||
|
|
@ -1024,6 +1014,8 @@ rr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve,
|
||||||
char* reason = NULL;
|
char* reason = NULL;
|
||||||
verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d",
|
verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d",
|
||||||
(int)i);
|
(int)i);
|
||||||
|
/* no algorithm downgrade protection necessary, if it is selfsigned
|
||||||
|
* revoked it can be removed. */
|
||||||
sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i,
|
sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i,
|
||||||
&reason);
|
&reason);
|
||||||
return (sec == sec_status_secure);
|
return (sec == sec_status_secure);
|
||||||
|
|
|
||||||
|
|
@ -551,8 +551,8 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
|
||||||
struct ub_packed_rrset_key* ta_ds,
|
struct ub_packed_rrset_key* ta_ds,
|
||||||
struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason)
|
struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason)
|
||||||
{
|
{
|
||||||
/* as long as this is false, we can consider this DS rrset to be
|
/* as long as this is false, we can consider this anchor to be
|
||||||
* equivalent to no DS rrset. */
|
* equivalent to no anchor. */
|
||||||
int has_useful_ta = 0, digest_algo = 0, alg;
|
int has_useful_ta = 0, digest_algo = 0, alg;
|
||||||
struct algo_needs needs;
|
struct algo_needs needs;
|
||||||
size_t i, num;
|
size_t i, num;
|
||||||
|
|
@ -591,9 +591,8 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
|
||||||
* And check it is the strongest digest */
|
* And check it is the strongest digest */
|
||||||
if(!ds_digest_algo_is_supported(ta_ds, i) ||
|
if(!ds_digest_algo_is_supported(ta_ds, i) ||
|
||||||
!ds_key_algo_is_supported(ta_ds, i) ||
|
!ds_key_algo_is_supported(ta_ds, i) ||
|
||||||
ds_get_digest_algo(ta_ds, i) != digest_algo) {
|
ds_get_digest_algo(ta_ds, i) != digest_algo)
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
/* Once we see a single DS with a known digestID and
|
/* Once we see a single DS with a known digestID and
|
||||||
* algorithm, we cannot return INSECURE (with a
|
* algorithm, we cannot return INSECURE (with a
|
||||||
|
|
@ -620,9 +619,8 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
|
||||||
num = rrset_get_count(ta_dnskey);
|
num = rrset_get_count(ta_dnskey);
|
||||||
for(i=0; i<num; i++) {
|
for(i=0; i<num; i++) {
|
||||||
/* Check to see if we can understand this DNSKEY */
|
/* Check to see if we can understand this DNSKEY */
|
||||||
if(!dnskey_algo_is_supported(ta_dnskey, i)) {
|
if(!dnskey_algo_is_supported(ta_dnskey, i))
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
/* we saw a useful TA */
|
/* we saw a useful TA */
|
||||||
has_useful_ta = true;
|
has_useful_ta = true;
|
||||||
|
|
@ -632,7 +630,7 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
|
||||||
if(sec == sec_status_secure) {
|
if(sec == sec_status_secure) {
|
||||||
if(!sigalg || algo_needs_set_secure(&needs,
|
if(!sigalg || algo_needs_set_secure(&needs,
|
||||||
(uint8_t)dnskey_get_algo(ta_dnskey, i))) {
|
(uint8_t)dnskey_get_algo(ta_dnskey, i))) {
|
||||||
verbose(VERB_ALGO, "DS matched DNSKEY.");
|
verbose(VERB_ALGO, "anchor matched DNSKEY.");
|
||||||
return sec_status_secure;
|
return sec_status_secure;
|
||||||
}
|
}
|
||||||
} else if(sigalg && sec == sec_status_bogus) {
|
} else if(sigalg && sec == sec_status_bogus) {
|
||||||
|
|
@ -642,7 +640,6 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* If no DSs were understandable, then this is OK. */
|
/* If no DSs were understandable, then this is OK. */
|
||||||
if(!has_useful_ta) {
|
if(!has_useful_ta) {
|
||||||
verbose(VERB_ALGO, "No usable trust anchors were found -- "
|
verbose(VERB_ALGO, "No usable trust anchors were found -- "
|
||||||
|
|
@ -659,7 +656,7 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct key_entry_key*
|
struct key_entry_key*
|
||||||
val_verify_new_DNSKEYs_with_ta(struct regional* region, struct module_env* env,
|
val_verify_new_DNSKEYs_with_ta(struct regional* region, struct module_env* env,
|
||||||
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
|
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
|
||||||
struct ub_packed_rrset_key* ta_ds_rrset,
|
struct ub_packed_rrset_key* ta_ds_rrset,
|
||||||
struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot,
|
struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot,
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,27 @@ enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env,
|
||||||
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
|
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
|
||||||
struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason);
|
struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify DNSKEYs with DS and DNSKEY rrset. Like val_verify_DNSKEY_with_DS
|
||||||
|
* but for a trust anchor.
|
||||||
|
* @param env: module environment (scratch buffer)
|
||||||
|
* @param ve: validator environment (verification settings)
|
||||||
|
* @param dnskey_rrset: DNSKEY rrset to verify
|
||||||
|
* @param ta_ds: DS rrset to verify with.
|
||||||
|
* @param ta_dnskey: DNSKEY rrset to verify with.
|
||||||
|
* @param sigalg: if nonNULL provide downgrade protection otherwise one
|
||||||
|
* algorithm is enough. The list of signalled algorithms is returned,
|
||||||
|
* must have enough space for ALGO_NEEDS_MAX+1.
|
||||||
|
* @param reason: reason of failure. Fixed string or alloced in scratch.
|
||||||
|
* @return: sec_status_secure if a DS matches.
|
||||||
|
* sec_status_insecure if end of trust (i.e., unknown algorithms).
|
||||||
|
* sec_status_bogus if it fails.
|
||||||
|
*/
|
||||||
|
enum sec_status val_verify_DNSKEY_with_TA(struct module_env* env,
|
||||||
|
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
|
||||||
|
struct ub_packed_rrset_key* ta_ds,
|
||||||
|
struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify new DNSKEYs with DS rrset. The DS contains hash values that should
|
* Verify new DNSKEYs with DS rrset. The DS contains hash values that should
|
||||||
* match the DNSKEY keys.
|
* match the DNSKEY keys.
|
||||||
|
|
|
||||||
|
|
@ -2241,6 +2241,7 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
|
||||||
struct key_entry_key* kkey = NULL;
|
struct key_entry_key* kkey = NULL;
|
||||||
enum sec_status sec = sec_status_unchecked;
|
enum sec_status sec = sec_status_unchecked;
|
||||||
char* reason = NULL;
|
char* reason = NULL;
|
||||||
|
int downprot = 1;
|
||||||
|
|
||||||
if(!dnskey_rrset) {
|
if(!dnskey_rrset) {
|
||||||
log_nametypeclass(VERB_OPS, "failed to prime trust anchor -- "
|
log_nametypeclass(VERB_OPS, "failed to prime trust anchor -- "
|
||||||
|
|
@ -2262,7 +2263,8 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
|
||||||
}
|
}
|
||||||
/* attempt to verify with trust anchor DS and DNSKEY */
|
/* attempt to verify with trust anchor DS and DNSKEY */
|
||||||
kkey = val_verify_new_DNSKEYs_with_ta(qstate->region, qstate->env, ve,
|
kkey = val_verify_new_DNSKEYs_with_ta(qstate->region, qstate->env, ve,
|
||||||
dnskey_rrset, ta->ds_rrset, ta->dnskey_rrset, 0, &reason);
|
dnskey_rrset, ta->ds_rrset, ta->dnskey_rrset, downprot,
|
||||||
|
&reason);
|
||||||
if(!kkey) {
|
if(!kkey) {
|
||||||
log_err("out of memory: verifying prime TA");
|
log_err("out of memory: verifying prime TA");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue