blob: aa086b8f75ec04d8074bfa7f5a2ae1a46342ab4e [file] [log] [blame]
Shuyi Chend7955ce2013-05-22 14:51:55 -07001// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
2
3package org.xbill.DNS;
4
5import java.io.*;
6import java.security.*;
7
8import org.xbill.DNS.utils.*;
9
10/**
11 * Next SECure name 3 - this record contains the next hashed name in an
12 * ordered list of hashed names in the zone, and a set of types for which
13 * records exist for this name. The presence of this record in a response
14 * signifies a negative response from a DNSSEC-signed zone.
15 *
16 * This replaces the NSEC and NXT records, when used.
17 *
18 * @author Brian Wellington
19 * @author David Blacka
20 */
21
22public class NSEC3Record extends Record {
23
24public static class Flags {
25 /**
26 * NSEC3 flags identifiers.
27 */
28
29 private Flags() {}
30
31 /** Unsigned delegation are not included in the NSEC3 chain.
32 *
33 */
34 public static final int OPT_OUT = 0x01;
35}
36
37public static class Digest {
38 private Digest() {}
39
40 /** SHA-1 */
41 public static final int SHA1 = 1;
42}
43
44public static final int SHA1_DIGEST_ID = Digest.SHA1;
45
46private static final long serialVersionUID = -7123504635968932855L;
47
48private int hashAlg;
49private int flags;
50private int iterations;
51private byte [] salt;
52private byte [] next;
53private TypeBitmap types;
54
55private static final base32 b32 = new base32(base32.Alphabet.BASE32HEX,
56 false, false);
57
58NSEC3Record() {}
59
60Record getObject() {
61 return new NSEC3Record();
62}
63
64/**
65 * Creates an NSEC3 record from the given data.
66 *
67 * @param name The ownername of the NSEC3 record (base32'd hash plus zonename).
68 * @param dclass The class.
69 * @param ttl The TTL.
70 * @param hashAlg The hash algorithm.
71 * @param flags The value of the flags field.
72 * @param iterations The number of hash iterations.
73 * @param salt The salt to use (may be null).
74 * @param next The next hash (may not be null).
75 * @param types The types present at the original ownername.
76 */
77public NSEC3Record(Name name, int dclass, long ttl, int hashAlg,
78 int flags, int iterations, byte [] salt, byte [] next,
79 int [] types)
80{
81 super(name, Type.NSEC3, dclass, ttl);
82 this.hashAlg = checkU8("hashAlg", hashAlg);
83 this.flags = checkU8("flags", flags);
84 this.iterations = checkU16("iterations", iterations);
85
86 if (salt != null) {
87 if (salt.length > 255)
88 throw new IllegalArgumentException("Invalid salt");
89 if (salt.length > 0) {
90 this.salt = new byte[salt.length];
91 System.arraycopy(salt, 0, this.salt, 0, salt.length);
92 }
93 }
94
95 if (next.length > 255) {
96 throw new IllegalArgumentException("Invalid next hash");
97 }
98 this.next = new byte[next.length];
99 System.arraycopy(next, 0, this.next, 0, next.length);
100 this.types = new TypeBitmap(types);
101}
102
103void
104rrFromWire(DNSInput in) throws IOException {
105 hashAlg = in.readU8();
106 flags = in.readU8();
107 iterations = in.readU16();
108
109 int salt_length = in.readU8();
110 if (salt_length > 0)
111 salt = in.readByteArray(salt_length);
112 else
113 salt = null;
114
115 int next_length = in.readU8();
116 next = in.readByteArray(next_length);
117 types = new TypeBitmap(in);
118}
119
120void
121rrToWire(DNSOutput out, Compression c, boolean canonical) {
122 out.writeU8(hashAlg);
123 out.writeU8(flags);
124 out.writeU16(iterations);
125
126 if (salt != null) {
127 out.writeU8(salt.length);
128 out.writeByteArray(salt);
129 } else
130 out.writeU8(0);
131
132 out.writeU8(next.length);
133 out.writeByteArray(next);
134 types.toWire(out);
135}
136
137void
138rdataFromString(Tokenizer st, Name origin) throws IOException {
139 hashAlg = st.getUInt8();
140 flags = st.getUInt8();
141 iterations = st.getUInt16();
142
143 String s = st.getString();
144 if (s.equals("-"))
145 salt = null;
146 else {
147 st.unget();
148 salt = st.getHexString();
149 if (salt.length > 255)
150 throw st.exception("salt value too long");
151 }
152
153 next = st.getBase32String(b32);
154 types = new TypeBitmap(st);
155}
156
157/** Converts rdata to a String */
158String
159rrToString() {
160 StringBuffer sb = new StringBuffer();
161 sb.append(hashAlg);
162 sb.append(' ');
163 sb.append(flags);
164 sb.append(' ');
165 sb.append(iterations);
166 sb.append(' ');
167 if (salt == null)
168 sb.append('-');
169 else
170 sb.append(base16.toString(salt));
171 sb.append(' ');
172 sb.append(b32.toString(next));
173
174 if (!types.empty()) {
175 sb.append(' ');
176 sb.append(types.toString());
177 }
178
179 return sb.toString();
180}
181
182/** Returns the hash algorithm */
183public int
184getHashAlgorithm() {
185 return hashAlg;
186}
187
188/** Returns the flags */
189public int
190getFlags() {
191 return flags;
192}
193
194/** Returns the number of iterations */
195public int
196getIterations() {
197 return iterations;
198}
199
200/** Returns the salt */
201public byte []
202getSalt()
203{
204 return salt;
205}
206
207/** Returns the next hash */
208public byte []
209getNext() {
210 return next;
211}
212
213 /** Returns the set of types defined for this name */
214public int []
215getTypes() {
216 return types.toArray();
217}
218
219/** Returns whether a specific type is in the set of types. */
220public boolean
221hasType(int type)
222{
223 return types.contains(type);
224}
225
226static byte []
227hashName(Name name, int hashAlg, int iterations, byte [] salt)
228throws NoSuchAlgorithmException
229{
230 MessageDigest digest;
231 switch (hashAlg) {
232 case Digest.SHA1:
233 digest = MessageDigest.getInstance("sha-1");
234 break;
235 default:
236 throw new NoSuchAlgorithmException("Unknown NSEC3 algorithm" +
237 "identifier: " +
238 hashAlg);
239 }
240 byte [] hash = null;
241 for (int i = 0; i <= iterations; i++) {
242 digest.reset();
243 if (i == 0)
244 digest.update(name.toWireCanonical());
245 else
246 digest.update(hash);
247 if (salt != null)
248 digest.update(salt);
249 hash = digest.digest();
250 }
251 return hash;
252}
253
254/**
255 * Hashes a name with the parameters of this NSEC3 record.
256 * @param name The name to hash
257 * @return The hashed version of the name
258 * @throws NoSuchAlgorithmException The hash algorithm is unknown.
259 */
260public byte []
261hashName(Name name) throws NoSuchAlgorithmException
262{
263 return hashName(name, hashAlg, iterations, salt);
264}
265
266}