Home | History | Annotate | Download | only in DNS
      1 // Copyright (c) 1999-2004 Brian Wellington (bwelling (at) 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 
     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 {
     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 
     58 NSEC3Record() {}
     59 
     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  */
     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
    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
    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
    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
    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
    184 getHashAlgorithm() {
    185 	return hashAlg;
    186 }
    187 
    188 /** Returns the flags */
    189 public int
    190 getFlags() {
    191 	return flags;
    192 }
    193 
    194 /** Returns the number of iterations */
    195 public int
    196 getIterations() {
    197 	return iterations;
    198 }
    199 
    200 /** Returns the salt */
    201 public byte []
    202 getSalt()
    203 {
    204 	return salt;
    205 }
    206 
    207 /** Returns the next hash */
    208 public byte []
    209 getNext() {
    210 	return next;
    211 }
    212 
    213   /** Returns the set of types defined for this name */
    214 public int []
    215 getTypes() {
    216 	return types.toArray();
    217 }
    218 
    219 /** Returns whether a specific type is in the set of types. */
    220 public boolean
    221 hasType(int type)
    222 {
    223 	return types.contains(type);
    224 }
    225 
    226 static byte []
    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 []
    261 hashName(Name name) throws NoSuchAlgorithmException
    262 {
    263 	return hashName(name, hashAlg, iterations, salt);
    264 }
    265 
    266 }
    267