diff options
Diffstat (limited to 'sbin/unwind/libunbound/validator')
-rw-r--r-- | sbin/unwind/libunbound/validator/autotrust.c | 31 | ||||
-rw-r--r-- | sbin/unwind/libunbound/validator/val_anchor.c | 7 | ||||
-rw-r--r-- | sbin/unwind/libunbound/validator/val_nsec.c | 1 | ||||
-rw-r--r-- | sbin/unwind/libunbound/validator/val_secalgo.c | 247 | ||||
-rw-r--r-- | sbin/unwind/libunbound/validator/val_secalgo.h | 43 | ||||
-rw-r--r-- | sbin/unwind/libunbound/validator/val_sigcrypt.c | 98 | ||||
-rw-r--r-- | sbin/unwind/libunbound/validator/val_sigcrypt.h | 29 | ||||
-rw-r--r-- | sbin/unwind/libunbound/validator/val_utils.c | 39 | ||||
-rw-r--r-- | sbin/unwind/libunbound/validator/validator.c | 18 | ||||
-rw-r--r-- | sbin/unwind/libunbound/validator/validator.h | 6 |
10 files changed, 448 insertions, 71 deletions
diff --git a/sbin/unwind/libunbound/validator/autotrust.c b/sbin/unwind/libunbound/validator/autotrust.c index 7ce07e0d82d..9643a3ddb38 100644 --- a/sbin/unwind/libunbound/validator/autotrust.c +++ b/sbin/unwind/libunbound/validator/autotrust.c @@ -1077,6 +1077,17 @@ trustanchor_state2str(autr_state_type s) return " UNKNOWN "; } +/** ctime r for autotrust */ +static char* autr_ctime_r(time_t* t, char* s) +{ + ctime_r(t, s); +#ifdef USE_WINSOCK + if(strlen(s) > 10 && s[7]==' ' && s[8]=='0') + s[8]=' '; /* fix error in windows ctime */ +#endif + return s; +} + /** print ID to file */ static int print_id(FILE* out, char* fname, uint8_t* nm, size_t nmlen, uint16_t dclass) @@ -1123,13 +1134,13 @@ autr_write_contents(FILE* out, char* fn, struct trust_anchor* tp) } if(fprintf(out, ";;last_queried: %u ;;%s", (unsigned int)tp->autr->last_queried, - ctime_r(&(tp->autr->last_queried), tmi)) < 0 || + autr_ctime_r(&(tp->autr->last_queried), tmi)) < 0 || fprintf(out, ";;last_success: %u ;;%s", (unsigned int)tp->autr->last_success, - ctime_r(&(tp->autr->last_success), tmi)) < 0 || + autr_ctime_r(&(tp->autr->last_success), tmi)) < 0 || fprintf(out, ";;next_probe_time: %u ;;%s", (unsigned int)tp->autr->next_probe_time, - ctime_r(&(tp->autr->next_probe_time), tmi)) < 0 || + autr_ctime_r(&(tp->autr->next_probe_time), tmi)) < 0 || fprintf(out, ";;query_failed: %d\n", (int)tp->autr->query_failed)<0 || fprintf(out, ";;query_interval: %d\n", (int)tp->autr->query_interval) < 0 || @@ -1160,7 +1171,7 @@ autr_write_contents(FILE* out, char* fn, struct trust_anchor* tp) ";;lastchange=%u ;;%s", str, (int)ta->s, trustanchor_state2str(ta->s), (int)ta->pending_count, (unsigned int)ta->last_change, - ctime_r(&(ta->last_change), tmi)) < 0) { + autr_ctime_r(&(ta->last_change), tmi)) < 0) { log_err("could not write to %s: %s", fn, strerror(errno)); free(str); return 0; @@ -1579,6 +1590,7 @@ key_matches_a_ds(struct module_env* env, struct val_env* ve, for(ds_idx=0; ds_idx<num; ds_idx++) { if(!ds_digest_algo_is_supported(ds_rrset, ds_idx) || !ds_key_algo_is_supported(ds_rrset, ds_idx) || + !dnskey_size_is_supported(dnskey_rrset, key_idx) || ds_get_digest_algo(ds_rrset, ds_idx) != d) continue; if(ds_get_key_algo(ds_rrset, ds_idx) @@ -1633,7 +1645,8 @@ update_events(struct module_env* env, struct val_env* ve, } /* is a key of this type supported?. Note rr_list and * packed_rrset are in the same order. */ - if(!dnskey_algo_is_supported(dnskey_rrset, i)) { + if(!dnskey_algo_is_supported(dnskey_rrset, i) || + !dnskey_size_is_supported(dnskey_rrset, i)) { /* skip unknown algorithm key, it is useless to us */ log_nametypeclass(VERB_DETAIL, "trust point has " "unsupported algorithm at", @@ -2262,7 +2275,7 @@ autr_debug_print_ta(struct autr_ta* ta) return; } if(str[0]) str[strlen(str)-1]=0; /* remove newline */ - ctime_r(&ta->last_change, buf); + (void)autr_ctime_r(&ta->last_change, buf); if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ log_info("[%s] %s ;;state:%d ;;pending_count:%d%s%s last:%s", trustanchor_state2str(ta->s), str, ta->s, ta->pending_count, @@ -2289,13 +2302,13 @@ autr_debug_print_tp(struct trust_anchor* tp) log_packed_rrset(NO_VERBOSE, "DNSKEY:", tp->dnskey_rrset); } log_info("file %s", tp->autr->file); - ctime_r(&tp->autr->last_queried, buf); + (void)autr_ctime_r(&tp->autr->last_queried, buf); if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ log_info("last_queried: %u %s", (unsigned)tp->autr->last_queried, buf); - ctime_r(&tp->autr->last_success, buf); + (void)autr_ctime_r(&tp->autr->last_success, buf); if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ log_info("last_success: %u %s", (unsigned)tp->autr->last_success, buf); - ctime_r(&tp->autr->next_probe_time, buf); + (void)autr_ctime_r(&tp->autr->next_probe_time, buf); if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ log_info("next_probe_time: %u %s", (unsigned)tp->autr->next_probe_time, buf); diff --git a/sbin/unwind/libunbound/validator/val_anchor.c b/sbin/unwind/libunbound/validator/val_anchor.c index 9b6574c5d24..b1a54e1f019 100644 --- a/sbin/unwind/libunbound/validator/val_anchor.c +++ b/sbin/unwind/libunbound/validator/val_anchor.c @@ -971,7 +971,8 @@ anchors_dnskey_unsupported(struct trust_anchor* ta) { size_t i, num = 0; for(i=0; i<ta->numDNSKEY; i++) { - if(!dnskey_algo_is_supported(ta->dnskey_rrset, i)) + if(!dnskey_algo_is_supported(ta->dnskey_rrset, i) || + !dnskey_size_is_supported(ta->dnskey_rrset, i)) num++; } return num; @@ -1048,6 +1049,10 @@ anchors_apply_cfg(struct val_anchors* anchors, struct config_file* cfg) const char** zstr; char* nm; sldns_buffer* parsebuf = sldns_buffer_new(65535); + if(!parsebuf) { + log_err("malloc error in anchors_apply_cfg."); + return 0; + } if(cfg->insecure_lan_zones) { for(zstr = as112_zones; *zstr; zstr++) { if(!anchor_insert_insecure(anchors, *zstr)) { diff --git a/sbin/unwind/libunbound/validator/val_nsec.c b/sbin/unwind/libunbound/validator/val_nsec.c index 032d2ae03a4..a4e5b3137db 100644 --- a/sbin/unwind/libunbound/validator/val_nsec.c +++ b/sbin/unwind/libunbound/validator/val_nsec.c @@ -180,6 +180,7 @@ nsec_verify_rrset(struct module_env* env, struct val_env* ve, { struct packed_rrset_data* d = (struct packed_rrset_data*) nsec->entry.data; + if(!d) return 0; if(d->security == sec_status_secure) return 1; rrset_check_sec_status(env->rrset_cache, nsec, *env->now); diff --git a/sbin/unwind/libunbound/validator/val_secalgo.c b/sbin/unwind/libunbound/validator/val_secalgo.c index 15cccf017b4..7abf66f01d2 100644 --- a/sbin/unwind/libunbound/validator/val_secalgo.c +++ b/sbin/unwind/libunbound/validator/val_secalgo.c @@ -141,6 +141,69 @@ secalgo_hash_sha256(unsigned char* buf, size_t len, unsigned char* res) #endif } +/** hash structure for keeping track of running hashes */ +struct secalgo_hash { + /** the openssl message digest context */ + EVP_MD_CTX* ctx; +}; + +/** create secalgo hash with hash type */ +static struct secalgo_hash* secalgo_hash_create_md(const EVP_MD* md) +{ + struct secalgo_hash* h; + if(!md) + return NULL; + h = calloc(1, sizeof(*h)); + if(!h) + return NULL; + h->ctx = EVP_MD_CTX_create(); + if(!h->ctx) { + free(h); + return NULL; + } + if(!EVP_DigestInit_ex(h->ctx, md, NULL)) { + EVP_MD_CTX_destroy(h->ctx); + free(h); + return NULL; + } + return h; +} + +struct secalgo_hash* secalgo_hash_create_sha384(void) +{ + return secalgo_hash_create_md(EVP_sha384()); +} + +struct secalgo_hash* secalgo_hash_create_sha512(void) +{ + return secalgo_hash_create_md(EVP_sha512()); +} + +int secalgo_hash_update(struct secalgo_hash* hash, uint8_t* data, size_t len) +{ + return EVP_DigestUpdate(hash->ctx, (unsigned char*)data, + (unsigned int)len); +} + +int secalgo_hash_final(struct secalgo_hash* hash, uint8_t* result, + size_t maxlen, size_t* resultlen) +{ + if(EVP_MD_CTX_size(hash->ctx) > (int)maxlen) { + *resultlen = 0; + log_err("secalgo_hash_final: hash buffer too small"); + return 0; + } + *resultlen = EVP_MD_CTX_size(hash->ctx); + return EVP_DigestFinal_ex(hash->ctx, result, NULL); +} + +void secalgo_hash_delete(struct secalgo_hash* hash) +{ + if(!hash) return; + EVP_MD_CTX_destroy(hash->ctx); + free(hash); +} + /** * Return size of DS digest according to its hash algorithm. * @param algo: DS digest algo. @@ -450,29 +513,13 @@ static int setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type, unsigned char* key, size_t keylen) { -#if defined(USE_DSA) && defined(USE_SHA1) - DSA* dsa; -#endif - RSA* rsa; - switch(algo) { #if defined(USE_DSA) && defined(USE_SHA1) case LDNS_DSA: case LDNS_DSA_NSEC3: - *evp_key = EVP_PKEY_new(); + *evp_key = sldns_key_dsa2pkey_raw(key, keylen); if(!*evp_key) { - log_err("verify: malloc failure in crypto"); - return 0; - } - dsa = sldns_key_buf2dsa_raw(key, keylen); - if(!dsa) { - verbose(VERB_QUERY, "verify: " - "sldns_key_buf2dsa_raw failed"); - return 0; - } - if(EVP_PKEY_assign_DSA(*evp_key, dsa) == 0) { - verbose(VERB_QUERY, "verify: " - "EVP_PKEY_assign_DSA failed"); + verbose(VERB_QUERY, "verify: sldns_key_dsa2pkey failed"); return 0; } #ifdef HAVE_EVP_DSS1 @@ -495,20 +542,9 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type, #if defined(HAVE_EVP_SHA512) && defined(USE_SHA2) case LDNS_RSASHA512: #endif - *evp_key = EVP_PKEY_new(); + *evp_key = sldns_key_rsa2pkey_raw(key, keylen); if(!*evp_key) { - log_err("verify: malloc failure in crypto"); - return 0; - } - rsa = sldns_key_buf2rsa_raw(key, keylen); - if(!rsa) { - verbose(VERB_QUERY, "verify: " - "sldns_key_buf2rsa_raw SHA failed"); - return 0; - } - if(EVP_PKEY_assign_RSA(*evp_key, rsa) == 0) { - verbose(VERB_QUERY, "verify: " - "EVP_PKEY_assign_RSA SHA failed"); + verbose(VERB_QUERY, "verify: sldns_key_rsa2pkey SHA failed"); return 0; } @@ -532,20 +568,9 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type, #endif /* defined(USE_SHA1) || (defined(HAVE_EVP_SHA256) && defined(USE_SHA2)) || (defined(HAVE_EVP_SHA512) && defined(USE_SHA2)) */ case LDNS_RSAMD5: - *evp_key = EVP_PKEY_new(); + *evp_key = sldns_key_rsa2pkey_raw(key, keylen); if(!*evp_key) { - log_err("verify: malloc failure in crypto"); - return 0; - } - rsa = sldns_key_buf2rsa_raw(key, keylen); - if(!rsa) { - verbose(VERB_QUERY, "verify: " - "sldns_key_buf2rsa_raw MD5 failed"); - return 0; - } - if(EVP_PKEY_assign_RSA(*evp_key, rsa) == 0) { - verbose(VERB_QUERY, "verify: " - "EVP_PKEY_assign_RSA MD5 failed"); + verbose(VERB_QUERY, "verify: sldns_key_rsa2pkey MD5 failed"); return 0; } *digest_type = EVP_md5(); @@ -823,6 +848,64 @@ secalgo_hash_sha256(unsigned char* buf, size_t len, unsigned char* res) (void)HASH_HashBuf(HASH_AlgSHA256, res, buf, (unsigned long)len); } +/** the secalgo hash structure */ +struct secalgo_hash { + /** hash context */ + HASHContext* ctx; +}; + +/** create hash struct of type */ +static struct secalgo_hash* secalgo_hash_create_type(HASH_HashType tp) +{ + struct secalgo_hash* h = calloc(1, sizeof(*h)); + if(!h) + return NULL; + h->ctx = HASH_Create(tp); + if(!h->ctx) { + free(h); + return NULL; + } + return h; +} + +struct secalgo_hash* secalgo_hash_create_sha384(void) +{ + return secalgo_hash_create_type(HASH_AlgSHA384); +} + +struct secalgo_hash* secalgo_hash_create_sha512(void) +{ + return secalgo_hash_create_type(HASH_AlgSHA512); +} + +int secalgo_hash_update(struct secalgo_hash* hash, uint8_t* data, size_t len) +{ + HASH_Update(hash->ctx, (unsigned char*)data, (unsigned int)len); + return 1; +} + +int secalgo_hash_final(struct secalgo_hash* hash, uint8_t* result, + size_t maxlen, size_t* resultlen) +{ + unsigned int reslen = 0; + if(HASH_ResultLenContext(hash->ctx) > (unsigned int)maxlen) { + *resultlen = 0; + log_err("secalgo_hash_final: hash buffer too small"); + return 0; + } + HASH_End(hash->ctx, (unsigned char*)result, &reslen, + (unsigned int)maxlen); + *resultlen = (size_t)reslen; + return 1; +} + +void secalgo_hash_delete(struct secalgo_hash* hash) +{ + if(!hash) return; + HASH_Destroy(hash->ctx); + free(hash); +} + size_t ds_digest_size_supported(int algo) { @@ -1451,6 +1534,82 @@ secalgo_hash_sha256(unsigned char* buf, size_t len, unsigned char* res) _digest_nettle(SHA256_DIGEST_SIZE, (uint8_t*)buf, len, res); } +/** secalgo hash structure */ +struct secalgo_hash { + /** if it is 384 or 512 */ + int active; + /** context for sha384 */ + struct sha384_ctx ctx384; + /** context for sha512 */ + struct sha512_ctx ctx512; +}; + +struct secalgo_hash* secalgo_hash_create_sha384(void) +{ + struct secalgo_hash* h = calloc(1, sizeof(*h)); + if(!h) + return NULL; + h->active = 384; + sha384_init(&h->ctx384); + return h; +} + +struct secalgo_hash* secalgo_hash_create_sha512(void) +{ + struct secalgo_hash* h = calloc(1, sizeof(*h)); + if(!h) + return NULL; + h->active = 512; + sha512_init(&h->ctx512); + return h; +} + +int secalgo_hash_update(struct secalgo_hash* hash, uint8_t* data, size_t len) +{ + if(hash->active == 384) { + sha384_update(&hash->ctx384, len, data); + } else if(hash->active == 512) { + sha512_update(&hash->ctx512, len, data); + } else { + return 0; + } + return 1; +} + +int secalgo_hash_final(struct secalgo_hash* hash, uint8_t* result, + size_t maxlen, size_t* resultlen) +{ + if(hash->active == 384) { + if(SHA384_DIGEST_SIZE > maxlen) { + *resultlen = 0; + log_err("secalgo_hash_final: hash buffer too small"); + return 0; + } + *resultlen = SHA384_DIGEST_SIZE; + sha384_digest(&hash->ctx384, SHA384_DIGEST_SIZE, + (unsigned char*)result); + } else if(hash->active == 512) { + if(SHA512_DIGEST_SIZE > maxlen) { + *resultlen = 0; + log_err("secalgo_hash_final: hash buffer too small"); + return 0; + } + *resultlen = SHA512_DIGEST_SIZE; + sha512_digest(&hash->ctx512, SHA512_DIGEST_SIZE, + (unsigned char*)result); + } else { + *resultlen = 0; + return 0; + } + return 1; +} + +void secalgo_hash_delete(struct secalgo_hash* hash) +{ + if(!hash) return; + free(hash); +} + /** * Return size of DS digest according to its hash algorithm. * @param algo: DS digest algo. diff --git a/sbin/unwind/libunbound/validator/val_secalgo.h b/sbin/unwind/libunbound/validator/val_secalgo.h index 52aaeb9f6d3..8b6080dc24a 100644 --- a/sbin/unwind/libunbound/validator/val_secalgo.h +++ b/sbin/unwind/libunbound/validator/val_secalgo.h @@ -43,6 +43,7 @@ #ifndef VALIDATOR_VAL_SECALGO_H #define VALIDATOR_VAL_SECALGO_H struct sldns_buffer; +struct secalgo_hash; /** Return size of nsec3 hash algorithm, 0 if not supported */ size_t nsec3_hash_algo_size_supported(int id); @@ -68,6 +69,48 @@ int secalgo_nsec3_hash(int algo, unsigned char* buf, size_t len, void secalgo_hash_sha256(unsigned char* buf, size_t len, unsigned char* res); /** + * Start a hash of type sha384. Allocates structure, then inits it, + * so that a series of updates can be performed, before the final result. + * @return hash structure. NULL on malloc failure or no support. + */ +struct secalgo_hash* secalgo_hash_create_sha384(void); + +/** + * Start a hash of type sha512. Allocates structure, then inits it, + * so that a series of updates can be performed, before the final result. + * @return hash structure. NULL on malloc failure or no support. + */ +struct secalgo_hash* secalgo_hash_create_sha512(void); + +/** + * Update a hash with more information to add to it. + * @param hash: the hash that is updated. + * @param data: data to add. + * @param len: length of data. + * @return false on failure. + */ +int secalgo_hash_update(struct secalgo_hash* hash, uint8_t* data, size_t len); + +/** + * Get the final result of the hash. + * @param hash: the hash that has had updates to it. + * @param result: where to store the result. + * @param maxlen: length of the result buffer, eg. size of the allocation. + * If not large enough the routine fails. + * @param resultlen: the length of the result, returned to the caller. + * How much of maxlen is used. + * @return false on failure. + */ +int secalgo_hash_final(struct secalgo_hash* hash, uint8_t* result, + size_t maxlen, size_t* resultlen); + +/** + * Delete the hash structure. + * @param hash: the hash to delete. + */ +void secalgo_hash_delete(struct secalgo_hash* hash); + +/** * Return size of DS digest according to its hash algorithm. * @param algo: DS digest algo. * @return size in bytes of digest, or 0 if not supported. diff --git a/sbin/unwind/libunbound/validator/val_sigcrypt.c b/sbin/unwind/libunbound/validator/val_sigcrypt.c index de730f68189..b15fba3f499 100644 --- a/sbin/unwind/libunbound/validator/val_sigcrypt.c +++ b/sbin/unwind/libunbound/validator/val_sigcrypt.c @@ -386,6 +386,49 @@ int dnskey_algo_is_supported(struct ub_packed_rrset_key* dnskey_rrset, dnskey_idx)); } +int dnskey_size_is_supported(struct ub_packed_rrset_key* dnskey_rrset, + size_t dnskey_idx) +{ +#ifdef DEPRECATE_RSA_1024 + uint8_t* rdata; + size_t len; + int alg = dnskey_get_algo(dnskey_rrset, dnskey_idx); + size_t keysize; + + rrset_get_rdata(dnskey_rrset, dnskey_idx, &rdata, &len); + if(len < 2+4) + return 0; + keysize = sldns_rr_dnskey_key_size_raw(rdata+2+4, len-2-4, alg); + + switch((sldns_algorithm)alg) { + case LDNS_RSAMD5: + case LDNS_RSASHA1: + case LDNS_RSASHA1_NSEC3: + case LDNS_RSASHA256: + case LDNS_RSASHA512: + /* reject RSA keys of 1024 bits and shorter */ + if(keysize <= 1024) + return 0; + break; + default: + break; + } +#else + (void)dnskey_rrset; (void)dnskey_idx; +#endif /* DEPRECATE_RSA_1024 */ + return 1; +} + +int dnskeyset_size_is_supported(struct ub_packed_rrset_key* dnskey_rrset) +{ + size_t i, num = rrset_get_count(dnskey_rrset); + for(i=0; i<num; i++) { + if(!dnskey_size_is_supported(dnskey_rrset, i)) + return 0; + } + return 1; +} + void algo_needs_init_dnskey_add(struct algo_needs* n, struct ub_packed_rrset_key* dnskey, uint8_t* sigalg) { @@ -1187,7 +1230,7 @@ rrset_canonical(struct regional* region, sldns_buffer* buf, * section, to prevent that a wildcard synthesized NSEC can be used in * the non-existence proves. */ if(ntohs(k->rk.type) == LDNS_RR_TYPE_NSEC && - section == LDNS_SECTION_AUTHORITY) { + section == LDNS_SECTION_AUTHORITY && qstate) { k->rk.dname = regional_alloc_init(qstate->region, can_owner, can_owner_len); if(!k->rk.dname) @@ -1199,6 +1242,59 @@ rrset_canonical(struct regional* region, sldns_buffer* buf, return 1; } +int +rrset_canonicalize_to_buffer(struct regional* region, sldns_buffer* buf, + struct ub_packed_rrset_key* k) +{ + struct rbtree_type* sortree = NULL; + struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; + uint8_t* can_owner = NULL; + size_t can_owner_len = 0; + struct canon_rr* walk; + struct canon_rr* rrs; + + sortree = (struct rbtree_type*)regional_alloc(region, + sizeof(rbtree_type)); + if(!sortree) + return 0; + if(d->count > RR_COUNT_MAX) + return 0; /* integer overflow protection */ + rrs = regional_alloc(region, sizeof(struct canon_rr)*d->count); + if(!rrs) { + return 0; + } + rbtree_init(sortree, &canonical_tree_compare); + canonical_sort(k, d, sortree, rrs); + + sldns_buffer_clear(buf); + RBTREE_FOR(walk, struct canon_rr*, sortree) { + /* see if there is enough space left in the buffer */ + if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4 + + d->rr_len[walk->rr_idx]) { + log_err("verify: failed to canonicalize, " + "rrset too big"); + return 0; + } + /* determine canonical owner name */ + if(can_owner) + sldns_buffer_write(buf, can_owner, can_owner_len); + else { + can_owner = sldns_buffer_current(buf); + sldns_buffer_write(buf, k->rk.dname, k->rk.dname_len); + query_dname_tolower(can_owner); + can_owner_len = k->rk.dname_len; + } + sldns_buffer_write(buf, &k->rk.type, 2); + sldns_buffer_write(buf, &k->rk.rrset_class, 2); + sldns_buffer_write_u32(buf, d->rr_ttl[walk->rr_idx]); + sldns_buffer_write(buf, d->rr_data[walk->rr_idx], + d->rr_len[walk->rr_idx]); + canonicalize_rdata(buf, k, d->rr_len[walk->rr_idx]); + } + sldns_buffer_flip(buf); + return 1; +} + /** pretty print rrsig error with dates */ static void sigdate_error(const char* str, int32_t expi, int32_t incep, int32_t now) diff --git a/sbin/unwind/libunbound/validator/val_sigcrypt.h b/sbin/unwind/libunbound/validator/val_sigcrypt.h index 755a1d6e126..bbb95780d7f 100644 --- a/sbin/unwind/libunbound/validator/val_sigcrypt.h +++ b/sbin/unwind/libunbound/validator/val_sigcrypt.h @@ -180,6 +180,23 @@ uint16_t ds_get_keytag(struct ub_packed_rrset_key* ds_rrset, size_t ds_idx); int dnskey_algo_is_supported(struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx); +/** + * See if the DNSKEY size at that algorithm is supported. + * @param dnskey_rrset: DNSKEY rrset. + * @param dnskey_idx: index of RR in rrset. + * @return true if supported. + */ +int dnskey_size_is_supported(struct ub_packed_rrset_key* dnskey_rrset, + size_t dnskey_idx); + +/** + * See if the DNSKEY size at that algorithm is supported for all the + * RRs in the DNSKEY RRset. + * @param dnskey_rrset: DNSKEY rrset. + * @return true if supported. + */ +int dnskeyset_size_is_supported(struct ub_packed_rrset_key* dnskey_rrset); + /** * See if DS digest algorithm is supported * @param ds_rrset: DS rrset @@ -334,4 +351,16 @@ int canonical_tree_compare(const void* k1, const void* k2); int rrset_canonical_equal(struct regional* region, struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2); +/** + * Canonicalize an rrset into the buffer. For an auth zone record, so + * this does not use a signature, or the RRSIG TTL or the wildcard label + * count from the RRSIG. + * @param region: temporary region. + * @param buf: the buffer to use. + * @param k: the rrset to insert. + * @return false on alloc error. + */ +int rrset_canonicalize_to_buffer(struct regional* region, + struct sldns_buffer* buf, struct ub_packed_rrset_key* k); + #endif /* VALIDATOR_VAL_SIGCRYPT_H */ diff --git a/sbin/unwind/libunbound/validator/val_utils.c b/sbin/unwind/libunbound/validator/val_utils.c index 2f36fccfd4f..dd8d320e515 100644 --- a/sbin/unwind/libunbound/validator/val_utils.c +++ b/sbin/unwind/libunbound/validator/val_utils.c @@ -418,7 +418,7 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve, struct module_qstate* qstate) { enum sec_status sec = sec_status_bogus; - size_t i, num, numchecked = 0, numhashok = 0; + size_t i, num, numchecked = 0, numhashok = 0, numsizesupp = 0; num = rrset_get_count(dnskey_rrset); for(i=0; i<num; i++) { /* Skip DNSKEYs that don't match the basic criteria. */ @@ -441,6 +441,11 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve, continue; } numhashok++; + if(!dnskey_size_is_supported(dnskey_rrset, i)) { + verbose(VERB_ALGO, "DS okay but that DNSKEY size is not supported"); + numsizesupp++; + continue; + } verbose(VERB_ALGO, "DS match digest ok, trying signature"); /* Otherwise, we have a match! Make sure that the DNSKEY @@ -452,6 +457,10 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve, } /* If it didn't validate with the DNSKEY, try the next one! */ } + if(numsizesupp != 0) { + /* there is a working DS, but that DNSKEY is not supported */ + return sec_status_insecure; + } if(numchecked == 0) algo_needs_reason(env, ds_get_key_algo(ds_rrset, ds_idx), reason, "no keys have a DS"); @@ -519,17 +528,24 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve, continue; } + sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, + ds_rrset, i, reason, qstate); + if(sec == sec_status_insecure) + continue; + /* Once we see a single DS with a known digestID and * algorithm, we cannot return INSECURE (with a * "null" KeyEntry). */ has_useful_ds = 1; - sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, - ds_rrset, i, reason, qstate); if(sec == sec_status_secure) { if(!sigalg || algo_needs_set_secure(&needs, (uint8_t)ds_get_key_algo(ds_rrset, i))) { verbose(VERB_ALGO, "DS matched DNSKEY."); + if(!dnskeyset_size_is_supported(dnskey_rrset)) { + verbose(VERB_ALGO, "DS works, but dnskeyset contain keys that are unsupported, treat as insecure"); + return sec_status_insecure; + } return sec_status_secure; } } else if(sigalg && sec == sec_status_bogus) { @@ -631,17 +647,24 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve, ds_get_digest_algo(ta_ds, i) != digest_algo) continue; + sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, + ta_ds, i, reason, qstate); + if(sec == sec_status_insecure) + continue; + /* Once we see a single DS with a known digestID and * algorithm, we cannot return INSECURE (with a * "null" KeyEntry). */ has_useful_ta = 1; - sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, - ta_ds, i, reason, qstate); if(sec == sec_status_secure) { if(!sigalg || algo_needs_set_secure(&needs, (uint8_t)ds_get_key_algo(ta_ds, i))) { verbose(VERB_ALGO, "DS matched DNSKEY."); + if(!dnskeyset_size_is_supported(dnskey_rrset)) { + verbose(VERB_ALGO, "trustanchor works, but dnskeyset contain keys that are unsupported, treat as insecure"); + return sec_status_insecure; + } return sec_status_secure; } } else if(sigalg && sec == sec_status_bogus) { @@ -658,6 +681,8 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve, /* Check to see if we can understand this DNSKEY */ if(!dnskey_algo_is_supported(ta_dnskey, i)) continue; + if(!dnskey_size_is_supported(ta_dnskey, i)) + continue; /* we saw a useful TA */ has_useful_ta = 1; @@ -668,6 +693,10 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve, if(!sigalg || algo_needs_set_secure(&needs, (uint8_t)dnskey_get_algo(ta_dnskey, i))) { verbose(VERB_ALGO, "anchor matched DNSKEY."); + if(!dnskeyset_size_is_supported(dnskey_rrset)) { + verbose(VERB_ALGO, "trustanchor works, but dnskeyset contain keys that are unsupported, treat as insecure"); + return sec_status_insecure; + } return sec_status_secure; } } else if(sigalg && sec == sec_status_bogus) { diff --git a/sbin/unwind/libunbound/validator/validator.c b/sbin/unwind/libunbound/validator/validator.c index e12180b4bbd..d4d48d95689 100644 --- a/sbin/unwind/libunbound/validator/validator.c +++ b/sbin/unwind/libunbound/validator/validator.c @@ -137,6 +137,7 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env, val_env->date_override = cfg->val_date_override; val_env->skew_min = cfg->val_sig_skew_min; val_env->skew_max = cfg->val_sig_skew_max; + val_env->max_restart = cfg->val_max_restart; c = cfg_count_numbers(cfg->val_nsec3_key_iterations); if(c < 1 || (c&1)) { log_err("validator: unparseable or odd nsec3 key " @@ -1487,7 +1488,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq, enum val_classification subtype = val_classify_response( qstate->query_flags, &qstate->qinfo, &vq->qchase, vq->orig_msg->rep, vq->rrset_skip); - if(vq->restart_count > VAL_MAX_RESTART_COUNT) { + if(vq->restart_count > ve->max_restart) { verbose(VERB_ALGO, "restart count exceeded"); return val_error(qstate, id); } @@ -1640,7 +1641,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq, errinf(qstate, key_entry_get_reason(vq->key_entry)); } /* no retries, stop bothering the authority until timeout */ - vq->restart_count = VAL_MAX_RESTART_COUNT; + vq->restart_count = ve->max_restart; vq->chase_reply->security = sec_status_bogus; vq->state = VAL_FINISHED_STATE; return 1; @@ -1848,7 +1849,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, LDNS_RR_TYPE_DNSKEY, vq->key_entry->key_class); vq->chase_reply->security = sec_status_bogus; errinf(qstate, "while building chain of trust"); - if(vq->restart_count >= VAL_MAX_RESTART_COUNT) + if(vq->restart_count >= ve->max_restart) key_cache_insert(ve->kcache, vq->key_entry, qstate); return 1; } @@ -2064,7 +2065,7 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq, * endless bogus revalidation */ if(vq->orig_msg->rep->security == sec_status_bogus) { /* see if we can try again to fetch data */ - if(vq->restart_count < VAL_MAX_RESTART_COUNT) { + if(vq->restart_count < ve->max_restart) { int restart_count = vq->restart_count+1; verbose(VERB_ALGO, "validation failed, " "blacklist and retry to fetch data"); @@ -2605,6 +2606,7 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq, int id, int rcode, struct dns_msg* msg, struct query_info* qinfo, struct sock_list* origin) { + struct val_env* ve = (struct val_env*)qstate->env->modinfo[id]; struct key_entry_key* dske = NULL; uint8_t* olds = vq->empty_DS_name; vq->empty_DS_name = NULL; @@ -2638,7 +2640,7 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq, vq->chain_blacklist = NULL; /* fresh blacklist for next part*/ /* Keep the forState.state on FINDKEY. */ } else if(key_entry_isbad(dske) - && vq->restart_count < VAL_MAX_RESTART_COUNT) { + && vq->restart_count < ve->max_restart) { vq->empty_DS_name = olds; val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; @@ -2691,7 +2693,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq, /* bad response */ verbose(VERB_DETAIL, "Missing DNSKEY RRset in response to " "DNSKEY query."); - if(vq->restart_count < VAL_MAX_RESTART_COUNT) { + if(vq->restart_count < ve->max_restart) { val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; @@ -2730,7 +2732,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq, * state. */ if(!key_entry_isgood(vq->key_entry)) { if(key_entry_isbad(vq->key_entry)) { - if(vq->restart_count < VAL_MAX_RESTART_COUNT) { + if(vq->restart_count < ve->max_restart) { val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; @@ -2807,7 +2809,7 @@ process_prime_response(struct module_qstate* qstate, struct val_qstate* vq, lock_basic_unlock(&ta->lock); if(vq->key_entry) { if(key_entry_isbad(vq->key_entry) - && vq->restart_count < VAL_MAX_RESTART_COUNT) { + && vq->restart_count < ve->max_restart) { val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; diff --git a/sbin/unwind/libunbound/validator/validator.h b/sbin/unwind/libunbound/validator/validator.h index 35da1920aa3..a928e10a65d 100644 --- a/sbin/unwind/libunbound/validator/validator.h +++ b/sbin/unwind/libunbound/validator/validator.h @@ -64,9 +64,6 @@ struct config_strlist; */ #define BOGUS_KEY_TTL 60 /* seconds */ -/** max number of query restarts, number of IPs to probe */ -#define VAL_MAX_RESTART_COUNT 5 - /** Root key sentinel is ta preamble */ #define SENTINEL_IS "root-key-sentinel-is-ta-" /** Root key sentinel is not ta preamble */ @@ -95,6 +92,9 @@ struct val_env { /** clock skew max for signatures */ int32_t skew_max; + /** max number of query restarts, number of IPs to probe */ + int32_t max_restart; + /** TTL for bogus data; used instead of untrusted TTL from data. * Bogus data will not be verified more often than this interval. * seconds. */ |