Revamp code that ignores SHA1 if something better exists
Casey Deccio
3 years ago
434 | 434 | |
435 | 435 | # RFC 4509 |
436 | 436 | if self.ds.digest_type == 1: |
437 | digest_algs = set() | |
438 | my_digest_algs = {} | |
437 | stronger_algs_all_ds = set() | |
438 | stronger_algs_this_dnskey = set() | |
439 | # Cycle through all other DS records in the DS RRset: | |
440 | # 1. Create a list of digest types that are stronger than SHA1 | |
441 | # and are being used by DS records across the *entire* DS | |
442 | # RRset. Store them in digest_algs_all_ds. | |
443 | # 2. Create a list of digest types that are stronger than SHA1, | |
444 | # correspond to DS records go with the same DNSKEY as *this* | |
445 | # DS record, and have valid or indeterminate status (i.e., not | |
446 | # invalid). These are DS records with the same DNSSEC | |
447 | # algorithm and key tag, but different digest types. Store | |
448 | # them in stronger_algs_this_dnskey. | |
449 | # | |
450 | # Note: It is possible that a DS with a different digest | |
451 | # type matches a different DNSKEY than the present DNSKEY--due | |
452 | # to key tag collisions. If it does, there will be a warning, | |
453 | # but it should be both rare and innocuous. | |
439 | 454 | for ds_rdata in self.ds_meta.rrset: |
440 | digest_algs.add(ds_rdata.digest_type) | |
455 | ||
456 | if ds_rdata.digest_type not in DS_DIGEST_ALGS_STRONGER_THAN_SHA1: | |
457 | continue | |
458 | ||
459 | stronger_algs_all_ds.add(ds_rdata.digest_type) | |
441 | 460 | if (ds_rdata.algorithm, ds_rdata.key_tag) == (self.ds.algorithm, self.ds.key_tag): |
442 | # Here we produce a status of the DS with algorithm 2 with | |
443 | # respect to the DNSKEY for comparison with the current DS | |
444 | # with algorithm 1. It is possible that the DS with the | |
445 | # different digest type matches a different DNSKEY than the | |
446 | # present DNSKEY. If it does, there will be a warning, but | |
447 | # it should be both rare and innocuous. | |
448 | 461 | if ds_rdata.digest_type == self.ds.digest_type: |
449 | 462 | continue |
450 | elif ds_rdata.digest_type not in my_digest_algs or \ | |
451 | my_digest_algs[ds_rdata.digest_type].validation_status != DS_STATUS_VALID: | |
452 | my_digest_algs[ds_rdata.digest_type] = \ | |
453 | DSStatus(ds_rdata, self.ds_meta, self.dnskey, supported_digest_algs) | |
454 | ||
455 | for digest_alg in DS_DIGEST_ALGS_STRONGER_THAN_SHA1: | |
456 | if digest_alg in supported_digest_algs and digest_alg in digest_algs and \ | |
457 | (digest_alg not in my_digest_algs or my_digest_algs[digest_alg].validation_status not in \ | |
458 | (DS_STATUS_VALID, DS_STATUS_INDETERMINATE_NO_DNSKEY, DS_STATUS_INDETERMINATE_UNKNOWN_ALGORITHM, DS_STATUS_INDETERMINATE_MATCH_PRE_REVOKE)): | |
459 | ||
460 | if digest_alg in DS_DIGEST_ALGS_IGNORING_SHA1: | |
461 | self.warnings.append(Errors.DSDigestAlgorithmIgnored(algorithm=1, new_algorithm=digest_alg)) | |
462 | if self.validation_status == DS_STATUS_VALID: | |
463 | self.validation_status = DS_STATUS_ALGORITHM_IGNORED | |
464 | 463 | else: |
465 | self.warnings.append(Errors.DSDigestAlgorithmMaybeIgnored(algorithm=1, new_algorithm=digest_alg)) | |
464 | status = DSStatus(ds_rdata, self.ds_meta, self.dnskey, supported_digest_algs) | |
465 | if status.validation_status in \ | |
466 | (DS_STATUS_VALID, DS_STATUS_INDETERMINATE_NO_DNSKEY, DS_STATUS_INDETERMINATE_UNKNOWN_ALGORITHM, DS_STATUS_INDETERMINATE_MATCH_PRE_REVOKE): | |
467 | stronger_algs_this_dnskey.add(ds_rdata.digest_type) | |
468 | ||
469 | # Consider only digest types that we actually support | |
470 | stronger_algs_all_ds.intersection_update(supported_digest_algs) | |
471 | stronger_algs_this_dnskey.intersection_update(supported_digest_algs) | |
472 | ||
473 | if stronger_algs_all_ds: | |
474 | # If there are DS records in the DS RRset with digest type | |
475 | # stronger than SHA1, then this one MUST be ignored by | |
476 | # validators (RFC 4509). We don't actually issue a warning, | |
477 | # however, unless a DS with stronger digest type is not being | |
478 | # used to validate the current DNSKEY; if there is such a DS, | |
479 | # then there is no reason to complain. | |
480 | ||
481 | if not stronger_algs_this_dnskey: | |
482 | # If there are any DS records in the DS RRset with digest type | |
483 | # stronger than SHA1, and none of them can properly validate | |
484 | # the current DNSKEY, then this one stands alone. | |
485 | for digest_alg in stronger_algs_all_ds: | |
486 | if digest_alg in DS_DIGEST_ALGS_IGNORING_SHA1: | |
487 | if self.validation_status == DS_STATUS_VALID: | |
488 | self.validation_status = DS_STATUS_ALGORITHM_IGNORED | |
489 | self.warnings.append(Errors.DSDigestAlgorithmIgnored(algorithm=1, new_algorithm=digest_alg)) | |
490 | else: | |
491 | self.warnings.append(Errors.DSDigestAlgorithmMaybeIgnored(algorithm=1, new_algorithm=digest_alg)) | |
492 | ||
493 | ||
466 | 494 | |
467 | 495 | def __str__(self): |
468 | 496 | return '%s record(s) corresponding to DNSKEY for %s (algorithm %d (%s), key tag %d)' % (dns.rdatatype.to_text(self.ds_meta.rrset.rdtype), fmt.humanize_name(self.ds_meta.rrset.name), self.ds.algorithm, fmt.DNSKEY_ALGORITHMS.get(self.ds.algorithm, self.ds.algorithm), self.ds.key_tag) |