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.Collections;
014import java.util.List;
015
016import org.minidns.constants.DnssecConstants.DigestAlgorithm;
017import org.minidns.dnsmessage.Question;
018import org.minidns.dnsname.DnsName;
019import org.minidns.record.DNSKEY;
020import org.minidns.record.Data;
021import org.minidns.record.RRSIG;
022import org.minidns.record.Record;
023import org.minidns.record.Record.TYPE;
024
025public abstract class DnssecUnverifiedReason {
026    public abstract String getReasonString();
027
028    @Override
029    public String toString() {
030        return getReasonString();
031    }
032
033    @Override
034    public int hashCode() {
035        return getReasonString().hashCode();
036    }
037
038    @Override
039    public boolean equals(Object obj) {
040        return obj instanceof DnssecUnverifiedReason && ((DnssecUnverifiedReason) obj).getReasonString().equals(getReasonString());
041    }
042
043    public static class AlgorithmNotSupportedReason extends DnssecUnverifiedReason {
044        private final String algorithm;
045        private final TYPE type;
046        private final Record<? extends Data> record;
047
048        public AlgorithmNotSupportedReason(byte algorithm, TYPE type, Record<? extends Data> record) {
049            this.algorithm = Integer.toString(algorithm & 0xff);
050            this.type = type;
051            this.record = record;
052        }
053
054        @Override
055        public String getReasonString() {
056            return type.name() + " algorithm " + algorithm + " required to verify " + record.name + " is unknown or not supported by platform";
057        }
058    }
059
060    public static class AlgorithmExceptionThrownReason extends DnssecUnverifiedReason {
061        private final int algorithmNumber;
062        private final String kind;
063        private final Exception reason;
064        private final Record<? extends Data> record;
065
066        public AlgorithmExceptionThrownReason(DigestAlgorithm algorithm, String kind, Record<? extends Data> record, Exception reason) {
067            this.algorithmNumber = algorithm.value;
068            this.kind = kind;
069            this.record = record;
070            this.reason = reason;
071        }
072
073        @Override
074        public String getReasonString() {
075            return kind + " algorithm " + algorithmNumber + " threw exception while verifying " + record.name + ": " + reason;
076        }
077    }
078
079    public static class ConflictsWithSep extends DnssecUnverifiedReason {
080        private final Record<DNSKEY> record;
081
082        public ConflictsWithSep(Record<DNSKEY> record) {
083            this.record = record;
084        }
085
086        @Override
087        public String getReasonString() {
088            return "Zone " + record.name.ace + " is in list of known SEPs, but DNSKEY from response mismatches!";
089        }
090    }
091
092    public static class NoTrustAnchorReason extends DnssecUnverifiedReason {
093        private final DnsName zone;
094
095        public NoTrustAnchorReason(DnsName zone) {
096            this.zone = zone;
097        }
098
099        @Override
100        public String getReasonString() {
101            return "No trust anchor was found for zone " + zone + ". Try enabling DLV";
102        }
103    }
104
105    public static class NoSecureEntryPointReason extends DnssecUnverifiedReason {
106        private final DnsName zone;
107
108        public NoSecureEntryPointReason(DnsName zone) {
109            this.zone = zone;
110        }
111
112        @Override
113        public String getReasonString() {
114            return "No secure entry point was found for zone " + zone;
115        }
116    }
117
118    public static class NoRootSecureEntryPointReason extends DnssecUnverifiedReason {
119        public NoRootSecureEntryPointReason() {
120        }
121
122        @Override
123        public String getReasonString() {
124            return "No secure entry point was found for the root zone (\"Did you forget to configure a root SEP?\")";
125        }
126    }
127
128    public static class NoSignaturesReason extends DnssecUnverifiedReason {
129        private final Question question;
130
131        public NoSignaturesReason(Question question) {
132            this.question = question;
133        }
134
135        @Override
136        public String getReasonString() {
137            return "No signatures were attached to answer on question for " + question.type + " at " + question.name;
138        }
139    }
140
141    public static class NoActiveSignaturesReason extends DnssecUnverifiedReason {
142        private final Question question;
143        private final List<RRSIG> outdatedRrSigs;
144
145        public NoActiveSignaturesReason(Question question, List<RRSIG> outdatedRrSigs) {
146            this.question = question;
147            assert !outdatedRrSigs.isEmpty();
148            this.outdatedRrSigs = Collections.unmodifiableList(outdatedRrSigs);
149        }
150
151        @Override
152        public String getReasonString() {
153            return "No currently active signatures were attached to answer on question for " + question.type + " at " + question.name;
154        }
155
156        public List<RRSIG> getOutdatedRrSigs() {
157            return outdatedRrSigs;
158        }
159    }
160
161    public static class NSECDoesNotMatchReason extends DnssecUnverifiedReason {
162        private final Question question;
163        private final Record<? extends Data> record;
164
165        public NSECDoesNotMatchReason(Question question, Record<? extends Data> record) {
166            this.question = question;
167            this.record = record;
168        }
169
170        @Override
171        public String getReasonString() {
172            return "NSEC " + record.name + " does nat match question for " + question.type + " at " + question.name;
173        }
174    }
175}