• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
2 
3 package org.xbill.DNS;
4 
5 import java.io.*;
6 import java.security.*;
7 
8 import 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 
22 public class NSEC3Record extends Record {
23 
24 public static class Flags {
25 	/**
26 	 * NSEC3 flags identifiers.
27 	 */
28 
Flags()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 
37 public static class Digest {
Digest()38 	private Digest() {}
39 
40 	/** SHA-1 */
41 	public static final int SHA1 = 1;
42 }
43 
44 public static final int SHA1_DIGEST_ID = Digest.SHA1;
45 
46 private static final long serialVersionUID = -7123504635968932855L;
47 
48 private int hashAlg;
49 private int flags;
50 private int iterations;
51 private byte [] salt;
52 private byte [] next;
53 private TypeBitmap types;
54 
55 private static final base32 b32 = new base32(base32.Alphabet.BASE32HEX,
56 					     false, false);
57 
NSEC3Record()58 NSEC3Record() {}
59 
getObject()60 Record 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  */
NSEC3Record(Name name, int dclass, long ttl, int hashAlg, int flags, int iterations, byte [] salt, byte [] next, int [] types)77 public 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 
103 void
rrFromWire(DNSInput in)104 rrFromWire(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 
120 void
rrToWire(DNSOutput out, Compression c, boolean canonical)121 rrToWire(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 
137 void
rdataFromString(Tokenizer st, Name origin)138 rdataFromString(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 */
158 String
rrToString()159 rrToString() {
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 */
183 public int
getHashAlgorithm()184 getHashAlgorithm() {
185 	return hashAlg;
186 }
187 
188 /** Returns the flags */
189 public int
getFlags()190 getFlags() {
191 	return flags;
192 }
193 
194 /** Returns the number of iterations */
195 public int
getIterations()196 getIterations() {
197 	return iterations;
198 }
199 
200 /** Returns the salt */
201 public byte []
getSalt()202 getSalt()
203 {
204 	return salt;
205 }
206 
207 /** Returns the next hash */
208 public byte []
getNext()209 getNext() {
210 	return next;
211 }
212 
213   /** Returns the set of types defined for this name */
214 public int []
getTypes()215 getTypes() {
216 	return types.toArray();
217 }
218 
219 /** Returns whether a specific type is in the set of types. */
220 public boolean
hasType(int type)221 hasType(int type)
222 {
223 	return types.contains(type);
224 }
225 
226 static byte []
hashName(Name name, int hashAlg, int iterations, byte [] salt)227 hashName(Name name, int hashAlg, int iterations, byte [] salt)
228 throws 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  */
260 public byte []
hashName(Name name)261 hashName(Name name) throws NoSuchAlgorithmException
262 {
263 	return hashName(name, hashAlg, iterations, salt);
264 }
265 
266 }
267