+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
- 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
struct trust_anchor* tp, struct ub_packed_rrset_key* rrset)
{
char* reason = NULL;
- if(tp->ds_rrset) {
- /* verify with ds, any will do to prime autotrust */
- enum sec_status sec = val_verify_DNSKEY_with_DS(
- env, ve, rrset, tp->ds_rrset, 0, &reason);
- verbose(VERB_ALGO, "autotrust: validate DNSKEY with DS: %s",
- sec_status_to_string(sec));
- if(sec == sec_status_secure) {
- return 1;
- }
- }
- if(tp->dnskey_rrset) {
- /* 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;
+ uint8_t sigalg[ALGO_NEEDS_MAX+1];
+ int downprot = 1;
+ enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset,
+ tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason);
+ /* sigalg is ignored, it returns algorithms signalled to exist, but
+ * in 5011 there are no other rrsets to check. if downprot is
+ * enabled, then it checks that the DNSKEY is signed with all
+ * algorithms available in the trust store. */
+ verbose(VERB_ALGO, "autotrust: validate DNSKEY with anchor: %s",
+ sec_status_to_string(sec));
+ return sec == sec_status_secure;
}
/** Find minimum expiration interval from signatures */
char* reason = NULL;
verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d",
(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,
&reason);
return (sec == sec_status_secure);
struct ub_packed_rrset_key* ta_ds,
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
- * equivalent to no DS rrset. */
+ /* as long as this is false, we can consider this anchor to be
+ * equivalent to no anchor. */
int has_useful_ta = 0, digest_algo = 0, alg;
struct algo_needs needs;
size_t i, num;
* And check it is the strongest digest */
if(!ds_digest_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;
- }
/* Once we see a single DS with a known digestID and
* algorithm, we cannot return INSECURE (with a
num = rrset_get_count(ta_dnskey);
for(i=0; i<num; i++) {
/* 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;
- }
/* we saw a useful TA */
has_useful_ta = true;
if(sec == sec_status_secure) {
if(!sigalg || algo_needs_set_secure(&needs,
(uint8_t)dnskey_get_algo(ta_dnskey, i))) {
- verbose(VERB_ALGO, "DS matched DNSKEY.");
+ verbose(VERB_ALGO, "anchor matched DNSKEY.");
return sec_status_secure;
}
} else if(sigalg && sec == sec_status_bogus) {
}
}
-
/* If no DSs were understandable, then this is OK. */
if(!has_useful_ta) {
verbose(VERB_ALGO, "No usable trust anchors were found -- "
}
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 ub_packed_rrset_key* ta_ds_rrset,
struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot,
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
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
* match the DNSKEY keys.
struct key_entry_key* kkey = NULL;
enum sec_status sec = sec_status_unchecked;
char* reason = NULL;
+ int downprot = 1;
if(!dnskey_rrset) {
log_nametypeclass(VERB_OPS, "failed to prime trust anchor -- "
}
/* attempt to verify with trust anchor DS and DNSKEY */
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) {
log_err("out of memory: verifying prime TA");
return NULL;