1// 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} 267