diff options
Diffstat (limited to 'validator')
| -rw-r--r-- | validator/val_anchor.c | 36 | ||||
| -rw-r--r-- | validator/val_anchor.h | 11 | ||||
| -rw-r--r-- | validator/val_secalgo.c | 92 | ||||
| -rw-r--r-- | validator/val_sigcrypt.c | 8 | ||||
| -rw-r--r-- | validator/val_utils.c | 11 | ||||
| -rw-r--r-- | validator/validator.c | 14 |
6 files changed, 147 insertions, 25 deletions
diff --git a/validator/val_anchor.c b/validator/val_anchor.c index 2a7e0beeb6c5..6c6322447d6d 100644 --- a/validator/val_anchor.c +++ b/validator/val_anchor.c @@ -1273,3 +1273,39 @@ anchors_delete_insecure(struct val_anchors* anchors, uint16_t c, anchors_delfunc(&ta->node, NULL); } +/** compare two keytags, return -1, 0 or 1 */ +static int +keytag_compare(const void* x, const void* y) +{ + if(*(uint16_t*)x == *(uint16_t*)y) + return 0; + if(*(uint16_t*)x > *(uint16_t*)y) + return 1; + return -1; +} + +size_t +anchor_list_keytags(struct trust_anchor* ta, uint16_t* list, size_t num) +{ + size_t i, ret = 0; + if(ta->numDS == 0 && ta->numDNSKEY == 0) + return 0; /* insecure point */ + if(ta->numDS != 0 && ta->ds_rrset) { + struct packed_rrset_data* d=(struct packed_rrset_data*) + ta->ds_rrset->entry.data; + for(i=0; i<d->count; i++) { + if(ret == num) continue; + list[ret++] = ds_get_keytag(ta->ds_rrset, i); + } + } + if(ta->numDNSKEY != 0 && ta->dnskey_rrset) { + struct packed_rrset_data* d=(struct packed_rrset_data*) + ta->dnskey_rrset->entry.data; + for(i=0; i<d->count; i++) { + if(ret == num) continue; + list[ret++] = dnskey_calc_keytag(ta->dnskey_rrset, i); + } + } + qsort(list, ret, sizeof(*list), keytag_compare); + return ret; +} diff --git a/validator/val_anchor.h b/validator/val_anchor.h index 226165514c5a..318a2b227cc7 100644 --- a/validator/val_anchor.h +++ b/validator/val_anchor.h @@ -216,4 +216,15 @@ int anchors_add_insecure(struct val_anchors* anchors, uint16_t c, uint8_t* nm); void anchors_delete_insecure(struct val_anchors* anchors, uint16_t c, uint8_t* nm); +/** + * Get a list of keytags for the trust anchor. Zero tags for insecure points. + * @param ta: trust anchor (locked by caller). + * @param list: array of uint16_t. + * @param num: length of array. + * @return number of keytags filled into array. If total number of keytags is + * bigger than the array, it is truncated at num. On errors, less keytags + * are filled in. The array is sorted. + */ +size_t anchor_list_keytags(struct trust_anchor* ta, uint16_t* list, size_t num); + #endif /* VALIDATOR_VAL_ANCHOR_H */ diff --git a/validator/val_secalgo.c b/validator/val_secalgo.c index 302820fc2f97..be88ff438660 100644 --- a/validator/val_secalgo.c +++ b/validator/val_secalgo.c @@ -74,6 +74,8 @@ /** fake DSA support for unit tests */ int fake_dsa = 0; +/** fake SHA1 support for unit tests */ +int fake_sha1 = 0; /* return size of digest if supported, or 0 otherwise */ size_t @@ -116,9 +118,12 @@ size_t ds_digest_size_supported(int algo) { switch(algo) { -#ifdef HAVE_EVP_SHA1 case LDNS_SHA1: +#if defined(HAVE_EVP_SHA1) && defined(USE_SHA1) return SHA_DIGEST_LENGTH; +#else + if(fake_sha1) return 20; + return 0; #endif #ifdef HAVE_EVP_SHA256 case LDNS_SHA256: @@ -158,7 +163,7 @@ secalgo_ds_digest(int algo, unsigned char* buf, size_t len, unsigned char* res) { switch(algo) { -#ifdef HAVE_EVP_SHA1 +#if defined(HAVE_EVP_SHA1) && defined(USE_SHA1) case LDNS_SHA1: (void)SHA1(buf, len, res); return 1; @@ -197,14 +202,22 @@ dnskey_algo_id_is_supported(int id) return 0; case LDNS_DSA: case LDNS_DSA_NSEC3: -#ifdef USE_DSA +#if defined(USE_DSA) && defined(USE_SHA1) return 1; #else - if(fake_dsa) return 1; + if(fake_dsa || fake_sha1) return 1; return 0; #endif + case LDNS_RSASHA1: case LDNS_RSASHA1_NSEC3: +#ifdef USE_SHA1 + return 1; +#else + if(fake_sha1) return 1; + return 0; +#endif + #if defined(HAVE_EVP_SHA256) && defined(USE_SHA2) case LDNS_RSASHA256: #endif @@ -215,7 +228,10 @@ dnskey_algo_id_is_supported(int id) case LDNS_ECDSAP256SHA256: case LDNS_ECDSAP384SHA384: #endif +#if (defined(HAVE_EVP_SHA256) && defined(USE_SHA2)) || (defined(HAVE_EVP_SHA512) && defined(USE_SHA2)) || defined(USE_ECDSA) return 1; +#endif + #ifdef USE_GOST case LDNS_ECC_GOST: /* we support GOST if it can be loaded */ @@ -392,13 +408,13 @@ static int setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type, unsigned char* key, size_t keylen) { -#ifdef USE_DSA +#if defined(USE_DSA) && defined(USE_SHA1) DSA* dsa; #endif RSA* rsa; switch(algo) { -#ifdef USE_DSA +#if defined(USE_DSA) && defined(USE_SHA1) case LDNS_DSA: case LDNS_DSA_NSEC3: *evp_key = EVP_PKEY_new(); @@ -424,9 +440,13 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type, #endif break; -#endif /* USE_DSA */ +#endif /* USE_DSA && USE_SHA1 */ + +#if defined(USE_SHA1) || (defined(HAVE_EVP_SHA256) && defined(USE_SHA2)) || (defined(HAVE_EVP_SHA512) && defined(USE_SHA2)) +#ifdef USE_SHA1 case LDNS_RSASHA1: case LDNS_RSASHA1_NSEC3: +#endif #if defined(HAVE_EVP_SHA256) && defined(USE_SHA2) case LDNS_RSASHA256: #endif @@ -461,9 +481,14 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type, *digest_type = EVP_sha512(); else #endif +#ifdef USE_SHA1 *digest_type = EVP_sha1(); - +#else + { verbose(VERB_QUERY, "no digest available"); return 0; } +#endif break; +#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(); if(!*evp_key) { @@ -562,7 +587,11 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, EVP_PKEY *evp_key = NULL; #ifndef USE_DSA - if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3) && fake_dsa) + if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3) &&(fake_dsa||fake_sha1)) + return sec_status_secure; +#endif +#ifndef USE_SHA1 + if(fake_sha1 && (algo == LDNS_DSA || algo == LDNS_DSA_NSEC3 || algo == LDNS_RSASHA1 || algo == LDNS_RSASHA1_NSEC3)) return sec_status_secure; #endif @@ -706,8 +735,10 @@ ds_digest_size_supported(int algo) { /* uses libNSS */ switch(algo) { +#ifdef USE_SHA1 case LDNS_SHA1: return SHA1_LENGTH; +#endif #ifdef USE_SHA2 case LDNS_SHA256: return SHA256_LENGTH; @@ -729,9 +760,11 @@ secalgo_ds_digest(int algo, unsigned char* buf, size_t len, { /* uses libNSS */ switch(algo) { +#ifdef USE_SHA1 case LDNS_SHA1: return HASH_HashBuf(HASH_AlgSHA1, res, buf, len) == SECSuccess; +#endif #if defined(USE_SHA2) case LDNS_SHA256: return HASH_HashBuf(HASH_AlgSHA256, res, buf, len) @@ -759,12 +792,15 @@ dnskey_algo_id_is_supported(int id) case LDNS_RSAMD5: /* RFC 6725 deprecates RSAMD5 */ return 0; -#ifdef USE_DSA +#if defined(USE_SHA1) || defined(USE_SHA2) +#if defined(USE_DSA) && defined(USE_SHA1) case LDNS_DSA: case LDNS_DSA_NSEC3: #endif +#ifdef USE_SHA1 case LDNS_RSASHA1: case LDNS_RSASHA1_NSEC3: +#endif #ifdef USE_SHA2 case LDNS_RSASHA256: #endif @@ -772,6 +808,8 @@ dnskey_algo_id_is_supported(int id) case LDNS_RSASHA512: #endif return 1; +#endif /* SHA1 or SHA2 */ + #ifdef USE_ECDSA case LDNS_ECDSAP256SHA256: case LDNS_ECDSAP384SHA384: @@ -1003,7 +1041,9 @@ nss_setup_key_digest(int algo, SECKEYPublicKey** pubkey, HASH_HashType* htype, */ switch(algo) { -#ifdef USE_DSA + +#if defined(USE_SHA1) || defined(USE_SHA2) +#if defined(USE_DSA) && defined(USE_SHA1) case LDNS_DSA: case LDNS_DSA_NSEC3: *pubkey = nss_buf2dsa(key, keylen); @@ -1015,8 +1055,10 @@ nss_setup_key_digest(int algo, SECKEYPublicKey** pubkey, HASH_HashType* htype, /* no prefix for DSA verification */ break; #endif +#ifdef USE_SHA1 case LDNS_RSASHA1: case LDNS_RSASHA1_NSEC3: +#endif #ifdef USE_SHA2 case LDNS_RSASHA256: #endif @@ -1043,13 +1085,22 @@ nss_setup_key_digest(int algo, SECKEYPublicKey** pubkey, HASH_HashType* htype, *prefixlen = sizeof(p_sha512); } else #endif +#ifdef USE_SHA1 { *htype = HASH_AlgSHA1; *prefix = p_sha1; *prefixlen = sizeof(p_sha1); } +#else + { + verbose(VERB_QUERY, "verify: no digest algo"); + return 0; + } +#endif break; +#endif /* SHA1 or SHA2 */ + case LDNS_RSAMD5: *pubkey = nss_buf2rsa(key, keylen); if(!*pubkey) { @@ -1131,7 +1182,7 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, return sec_status_bogus; } -#ifdef USE_DSA +#if defined(USE_DSA) && defined(USE_SHA1) /* need to convert DSA, ECDSA signatures? */ if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3)) { if(sigblock_len == 1+2*SHA1_LENGTH) { @@ -1312,7 +1363,12 @@ ds_digest_size_supported(int algo) { switch(algo) { case LDNS_SHA1: +#ifdef USE_SHA1 return SHA1_DIGEST_SIZE; +#else + if(fake_sha1) return 20; + return 0; +#endif #ifdef USE_SHA2 case LDNS_SHA256: return SHA256_DIGEST_SIZE; @@ -1334,8 +1390,10 @@ secalgo_ds_digest(int algo, unsigned char* buf, size_t len, unsigned char* res) { switch(algo) { +#ifdef USE_SHA1 case LDNS_SHA1: return _digest_nettle(SHA1_DIGEST_SIZE, buf, len, res); +#endif #if defined(USE_SHA2) case LDNS_SHA256: return _digest_nettle(SHA256_DIGEST_SIZE, buf, len, res); @@ -1359,12 +1417,14 @@ dnskey_algo_id_is_supported(int id) { /* uses libnettle */ switch(id) { -#ifdef USE_DSA +#if defined(USE_DSA) && defined(USE_SHA1) case LDNS_DSA: case LDNS_DSA_NSEC3: #endif +#ifdef USE_SHA1 case LDNS_RSASHA1: case LDNS_RSASHA1_NSEC3: +#endif #ifdef USE_SHA2 case LDNS_RSASHA256: case LDNS_RSASHA512: @@ -1381,7 +1441,7 @@ dnskey_algo_id_is_supported(int id) } } -#ifdef USE_DSA +#if defined(USE_DSA) && defined(USE_SHA1) static char * _verify_nettle_dsa(sldns_buffer* buf, unsigned char* sigblock, unsigned int sigblock_len, unsigned char* key, unsigned int keylen) @@ -1641,7 +1701,7 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, } switch(algo) { -#ifdef USE_DSA +#if defined(USE_DSA) && defined(USE_SHA1) case LDNS_DSA: case LDNS_DSA_NSEC3: *reason = _verify_nettle_dsa(buf, sigblock, sigblock_len, key, keylen); @@ -1651,9 +1711,11 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, return sec_status_secure; #endif /* USE_DSA */ +#ifdef USE_SHA1 case LDNS_RSASHA1: case LDNS_RSASHA1_NSEC3: digest_size = (digest_size ? digest_size : SHA1_DIGEST_SIZE); +#endif #ifdef USE_SHA2 case LDNS_RSASHA256: digest_size = (digest_size ? digest_size : SHA256_DIGEST_SIZE); diff --git a/validator/val_sigcrypt.c b/validator/val_sigcrypt.c index b0b2e970ff25..25278a8f3ac0 100644 --- a/validator/val_sigcrypt.c +++ b/validator/val_sigcrypt.c @@ -51,6 +51,7 @@ #include "util/module.h" #include "util/net_help.h" #include "util/regional.h" +#include "util/config_file.h" #include "sldns/keyraw.h" #include "sldns/sbuffer.h" #include "sldns/parseutil.h" @@ -318,12 +319,17 @@ int ds_digest_match_dnskey(struct module_env* env, size_t dslen; uint8_t* digest; /* generated digest */ size_t digestlen = ds_digest_size_algo(ds_rrset, ds_idx); - + if(digestlen == 0) { verbose(VERB_QUERY, "DS fail: not supported, or DS RR " "format error"); return 0; /* not supported, or DS RR format error */ } +#ifndef USE_SHA1 + if(fake_sha1 && ds_get_digest_algo(ds_rrset, ds_idx)==LDNS_SHA1) + return 1; +#endif + /* check digest length in DS with length from hash function */ ds_get_sigdata(ds_rrset, ds_idx, &ds, &dslen); if(!ds || dslen != digestlen) { diff --git a/validator/val_utils.c b/validator/val_utils.c index da8066aad7e9..e3677e1d9ceb 100644 --- a/validator/val_utils.c +++ b/validator/val_utils.c @@ -495,16 +495,21 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve, return sec_status_bogus; } - digest_algo = val_favorite_ds_algo(ds_rrset); - if(sigalg) + if(sigalg) { + /* harden against algo downgrade is enabled */ + digest_algo = val_favorite_ds_algo(ds_rrset); algo_needs_init_ds(&needs, ds_rrset, digest_algo, sigalg); + } else { + /* accept any key algo, any digest algo */ + digest_algo = -1; + } num = rrset_get_count(ds_rrset); for(i=0; i<num; i++) { /* Check to see if we can understand this DS. * And check it is the strongest digest */ if(!ds_digest_algo_is_supported(ds_rrset, i) || !ds_key_algo_is_supported(ds_rrset, i) || - ds_get_digest_algo(ds_rrset, i) != digest_algo) { + (sigalg && (ds_get_digest_algo(ds_rrset, i) != digest_algo))) { continue; } diff --git a/validator/validator.c b/validator/validator.c index 676dcdfe4d8b..81ba5fa17ba2 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -2089,18 +2089,20 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq, } /* store results in cache */ - if(!qstate->no_cache_store && qstate->query_flags&BIT_RD) { + if(qstate->query_flags&BIT_RD) { /* if secure, this will override cache anyway, no need * to check if from parentNS */ - if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo, - vq->orig_msg->rep, 0, qstate->prefetch_leeway, 0, NULL, - qstate->query_flags)) { - log_err("out of memory caching validator results"); + if(!qstate->no_cache_store) { + if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo, + vq->orig_msg->rep, 0, qstate->prefetch_leeway, 0, NULL, + qstate->query_flags)) { + log_err("out of memory caching validator results"); + } } } else { /* for a referral, store the verified RRsets */ /* and this does not get prefetched, so no leeway */ - if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo, + if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo, vq->orig_msg->rep, 1, 0, 0, NULL, qstate->query_flags)) { log_err("out of memory caching validator results"); |
