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