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 org.minidns.dnsmessage.DnsMessage;
014import org.minidns.dnsmessage.Question;
015import org.minidns.record.Data;
016import org.minidns.record.DelegatingDnssecRR;
017import org.minidns.record.Record;
018
019import java.io.IOException;
020import java.math.BigInteger;
021import java.security.spec.InvalidKeySpecException;
022import java.util.List;
023import java.util.Locale;
024
025public class DnssecValidationFailedException extends IOException {
026    private static final long serialVersionUID = 5413184667629832742L;
027
028    public DnssecValidationFailedException(Question question, String reason) {
029        super("Validation of request to " + question + " failed: " + reason);
030    }
031
032    public DnssecValidationFailedException(String message) {
033        super(message);
034    }
035
036    public DnssecValidationFailedException(String message, Throwable cause) {
037        super(message, cause);
038    }
039
040    public DnssecValidationFailedException(Record<? extends Data> record, String reason) {
041        super("Validation of record " + record + " failed: " + reason);
042    }
043
044    public DnssecValidationFailedException(List<Record<? extends Data>> records, String reason) {
045        super("Validation of " + records.size() + " " + records.get(0).type + " record" + (records.size() > 1 ? "s" : "") + " failed: " + reason);
046    }
047
048    public static class DataMalformedException extends DnssecValidationFailedException {
049
050        /**
051         * 
052         */
053        private static final long serialVersionUID = 1L;
054
055        private final byte[] data;
056
057        public DataMalformedException(IOException exception, byte[] data) {
058            super("Malformed data", exception);
059            this.data = data;
060        }
061
062        public DataMalformedException(String message, IOException exception, byte[] data) {
063            super(message, exception);
064            this.data = data;
065        }
066
067        public byte[] getData() {
068            return data;
069        }
070    }
071
072    public static class DnssecInvalidKeySpecException extends DnssecValidationFailedException {
073
074        /**
075         * 
076         */
077        private static final long serialVersionUID = 1L;
078
079        public DnssecInvalidKeySpecException(InvalidKeySpecException exception) {
080            super("Invalid key spec", exception);
081        }
082
083        public DnssecInvalidKeySpecException(String message, InvalidKeySpecException exception, byte[] data) {
084            super(message, exception);
085        }
086
087    }
088
089    public static class AuthorityDoesNotContainSoa extends DnssecValidationFailedException {
090
091        /**
092         *
093         */
094        private static final long serialVersionUID = 1L;
095
096        private final DnsMessage response;
097
098        public AuthorityDoesNotContainSoa(DnsMessage response) {
099            super("Autority does not contain SOA");
100            this.response = response;
101        }
102
103        public DnsMessage getResponse() {
104            return response;
105        }
106    }
107
108    public static final class DigestComparisonFailedException extends DnssecValidationFailedException {
109
110        /**
111        *
112        */
113       private static final long serialVersionUID = 1L;
114
115       private final Record<? extends Data> record;
116       private final DelegatingDnssecRR ds;
117       private final byte[] digest;
118       private final String digestHex;
119
120       private DigestComparisonFailedException(String message, Record<? extends Data> record, DelegatingDnssecRR ds, byte[] digest, String digestHex) {
121           super(message);
122           this.record = record;
123           this.ds = ds;
124           this.digest = digest;
125           this.digestHex = digestHex;
126       }
127
128       public Record<? extends Data> getRecord() {
129           return record;
130       }
131
132       public DelegatingDnssecRR getDelegaticDnssecRr() {
133           return ds;
134       }
135
136       public byte[] getDigest() {
137           return digest.clone();
138       }
139
140       public String getDigestHex() {
141           return digestHex;
142       }
143
144       public static DigestComparisonFailedException from(Record<? extends Data> record, DelegatingDnssecRR ds, byte[] digest) {
145           BigInteger digestBigInteger = new BigInteger(1, digest);
146           String digestHex = digestBigInteger.toString(16).toUpperCase(Locale.ROOT);
147
148           String message = "Digest for " + record + " does not match. Digest of delegating DNSSEC RR " + ds + " is '"
149                   + ds.getDigestHex() + "' while we calculated '" + digestHex + "'";
150           return new DigestComparisonFailedException(message, record, ds, digest, digestHex);
151       }
152    }
153}