001/* 002 * Copyright 2015-2024 the original author or authors 003 * 004 * This software is licensed under the Apache License, Version 2.0, 005 * the GNU Lesser General Public License version 2 or later ("LGPL") 006 * and the WTFPL. 007 * You may choose either license to govern your use of this software only 008 * upon the condition that you accept all of the terms of either 009 * the Apache License 2.0, the LGPL 2.1+ or the WTFPL. 010 */ 011package org.minidns.dnssec; 012 013import java.util.ArrayList; 014import java.util.Collections; 015import java.util.List; 016import java.util.Set; 017 018import org.minidns.constants.DnssecConstants.DigestAlgorithm; 019import org.minidns.dnsmessage.Question; 020import org.minidns.dnsname.DnsName; 021import org.minidns.record.DNSKEY; 022import org.minidns.record.Data; 023import org.minidns.record.RRSIG; 024import org.minidns.record.Record; 025import org.minidns.record.Record.TYPE; 026 027public abstract class DnssecUnverifiedReason { 028 public abstract String getReasonString(); 029 030 @Override 031 public String toString() { 032 return getReasonString(); 033 } 034 035 @Override 036 public int hashCode() { 037 return getReasonString().hashCode(); 038 } 039 040 @Override 041 public boolean equals(Object obj) { 042 return obj instanceof DnssecUnverifiedReason && ((DnssecUnverifiedReason) obj).getReasonString().equals(getReasonString()); 043 } 044 045 public static class AlgorithmNotSupportedReason extends DnssecUnverifiedReason { 046 private final String algorithm; 047 private final TYPE type; 048 private final Record<? extends Data> record; 049 050 public AlgorithmNotSupportedReason(byte algorithm, TYPE type, Record<? extends Data> record) { 051 this.algorithm = Integer.toString(algorithm & 0xff); 052 this.type = type; 053 this.record = record; 054 } 055 056 @Override 057 public String getReasonString() { 058 return type.name() + " algorithm " + algorithm + " required to verify " + record.name + " is unknown or not supported by platform"; 059 } 060 } 061 062 public static class AlgorithmExceptionThrownReason extends DnssecUnverifiedReason { 063 private final int algorithmNumber; 064 private final String kind; 065 private final Exception reason; 066 private final Record<? extends Data> record; 067 068 public AlgorithmExceptionThrownReason(DigestAlgorithm algorithm, String kind, Record<? extends Data> record, Exception reason) { 069 this.algorithmNumber = algorithm.value; 070 this.kind = kind; 071 this.record = record; 072 this.reason = reason; 073 } 074 075 @Override 076 public String getReasonString() { 077 return kind + " algorithm " + algorithmNumber + " threw exception while verifying " + record.name + ": " + reason; 078 } 079 } 080 081 public static class ConflictsWithSep extends DnssecUnverifiedReason { 082 private final Record<DNSKEY> record; 083 084 public ConflictsWithSep(Record<DNSKEY> record) { 085 this.record = record; 086 } 087 088 @Override 089 public String getReasonString() { 090 return "Zone " + record.name.ace + " is in list of known SEPs, but DNSKEY from response mismatches!"; 091 } 092 } 093 094 public static class NoTrustAnchorReason extends DnssecUnverifiedReason { 095 private final DnsName zone; 096 097 public NoTrustAnchorReason(DnsName zone) { 098 this.zone = zone; 099 } 100 101 @Override 102 public String getReasonString() { 103 return "No trust anchor was found for zone " + zone + ". Try enabling DLV"; 104 } 105 } 106 107 public static class NoSecureEntryPointReason extends DnssecUnverifiedReason { 108 private final DnsName zone; 109 110 public NoSecureEntryPointReason(DnsName zone) { 111 this.zone = zone; 112 } 113 114 @Override 115 public String getReasonString() { 116 return "No secure entry point was found for zone " + zone; 117 } 118 } 119 120 public static class NoRootSecureEntryPointReason extends DnssecUnverifiedReason { 121 public NoRootSecureEntryPointReason() { 122 } 123 124 @Override 125 public String getReasonString() { 126 return "No secure entry point was found for the root zone (\"Did you forget to configure a root SEP?\")"; 127 } 128 } 129 130 public static class CrossSignedDnskeyRrsetReason extends DnssecUnverifiedReason { 131 private final DnsName zone; 132 private final Set<DnsName> signerNames; 133 134 public CrossSignedDnskeyRrsetReason(DnsName zone, Set<DnsName> signerNames) { 135 this.zone = zone; 136 this.signerNames = Collections.unmodifiableSet(signerNames); 137 } 138 139 /** 140 * The names of the zones whose keys signed the DNSKEY RRset instead of a key of the zone itself. 141 * 142 * @return the cross-signing zones. 143 */ 144 public Set<DnsName> getSignerNames() { 145 return signerNames; 146 } 147 148 @Override 149 public String getReasonString() { 150 List<String> sortedSignerNames = new ArrayList<>(signerNames.size()); 151 for (DnsName signerName : signerNames) { 152 sortedSignerNames.add(signerName.toString()); 153 } 154 Collections.sort(sortedSignerNames); 155 return "The DNSKEY RRset of zone " + zone + " is not self-signed and hence can not be anchored. It is only " 156 + "signed by a key of the following zone(s): " + sortedSignerNames; 157 } 158 } 159 160 public static class NoSignaturesReason extends DnssecUnverifiedReason { 161 private final Question question; 162 163 public NoSignaturesReason(Question question) { 164 this.question = question; 165 } 166 167 @Override 168 public String getReasonString() { 169 return "No signatures were attached to answer on question for " + question.type + " at " + question.name; 170 } 171 } 172 173 public static class NoActiveSignaturesReason extends DnssecUnverifiedReason { 174 private final Question question; 175 private final List<RRSIG> outdatedRrSigs; 176 177 public NoActiveSignaturesReason(Question question, List<RRSIG> outdatedRrSigs) { 178 this.question = question; 179 assert !outdatedRrSigs.isEmpty(); 180 this.outdatedRrSigs = Collections.unmodifiableList(outdatedRrSigs); 181 } 182 183 @Override 184 public String getReasonString() { 185 return "No currently active signatures were attached to answer on question for " + question.type + " at " + question.name; 186 } 187 188 public List<RRSIG> getOutdatedRrSigs() { 189 return outdatedRrSigs; 190 } 191 } 192 193 public static class NSECDoesNotMatchReason extends DnssecUnverifiedReason { 194 private final Question question; 195 private final Record<? extends Data> record; 196 197 public NSECDoesNotMatchReason(Question question, Record<? extends Data> record) { 198 this.question = question; 199 this.record = record; 200 } 201 202 @Override 203 public String getReasonString() { 204 return "NSEC " + record.name + " does nat match question for " + question.type + " at " + question.name; 205 } 206 } 207}