001/* 002 * Copyright 2015-2018 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.record; 012 013import org.minidns.record.Record.TYPE; 014import org.minidns.util.Base32; 015 016import java.io.DataInputStream; 017import java.io.DataOutputStream; 018import java.io.IOException; 019import java.math.BigInteger; 020import java.util.HashMap; 021import java.util.Map; 022 023/** 024 * NSEC3 record payload. 025 */ 026public class NSEC3 extends Data { 027 028 /** 029 * This Flag indicates whether this NSEC3 RR may cover unsigned 030 * delegations. 031 */ 032 public static final byte FLAG_OPT_OUT = 0x1; 033 034 private static final Map<Byte, HashAlgorithm> HASH_ALGORITHM_LUT = new HashMap<>(); 035 036 /** 037 * DNSSEC NSEC3 Hash Algorithms. 038 * 039 * @see <a href= 040 * "https://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml#dnssec-nsec3-parameters-3"> 041 * IANA DNSSEC NSEC3 Hash Algorithms</a> 042 */ 043 public enum HashAlgorithm { 044 RESERVED(0, "Reserved"), 045 SHA1(1, "SHA-1"), 046 ; 047 048 HashAlgorithm(int value, String description) { 049 if (value < 0 || value > 255) { 050 throw new IllegalArgumentException(); 051 } 052 this.value = (byte) value; 053 this.description = description; 054 HASH_ALGORITHM_LUT.put(this.value, this); 055 } 056 057 public final byte value; 058 public final String description; 059 060 public static HashAlgorithm forByte(byte b) { 061 return HASH_ALGORITHM_LUT.get(b); 062 } 063 } 064 065 /** 066 * The cryptographic hash algorithm used. If MiniDNS 067 * isn't aware of the hash algorithm, then this field will be 068 * <code>null</code>. 069 * 070 * @see #hashAlgorithmByte 071 */ 072 public final HashAlgorithm hashAlgorithm; 073 074 /** 075 * The byte value of the cryptographic hash algorithm used. 076 */ 077 public final byte hashAlgorithmByte; 078 079 /** 080 * Bitmap of flags: {@link #FLAG_OPT_OUT}. 081 */ 082 public final byte flags; 083 084 /** 085 * The number of iterations the hash algorithm is applied. 086 */ 087 public final int /* unsigned short */ iterations; 088 089 /** 090 * The salt appended to the next owner name before hashing. 091 */ 092 public final byte[] salt; 093 094 /** 095 * The next hashed owner name in hash order. 096 */ 097 public final byte[] nextHashed; 098 099 private final byte[] typeBitmap; 100 101 /** 102 * The RR types existing at the original owner name. 103 */ 104 public final TYPE[] types; 105 106 public static NSEC3 parse(DataInputStream dis, int length) throws IOException { 107 byte hashAlgorithm = dis.readByte(); 108 byte flags = dis.readByte(); 109 int iterations = dis.readUnsignedShort(); 110 int saltLength = dis.readUnsignedByte(); 111 byte[] salt = new byte[saltLength]; 112 if (dis.read(salt) != salt.length) throw new IOException(); 113 int hashLength = dis.readUnsignedByte(); 114 byte[] nextHashed = new byte[hashLength]; 115 if (dis.read(nextHashed) != nextHashed.length) throw new IOException(); 116 byte[] typeBitmap = new byte[length - (6 + saltLength + hashLength)]; 117 if (dis.read(typeBitmap) != typeBitmap.length) throw new IOException(); 118 TYPE[] types = NSEC.readTypeBitMap(typeBitmap); 119 return new NSEC3(hashAlgorithm, flags, iterations, salt, nextHashed, types); 120 } 121 122 private NSEC3(HashAlgorithm hashAlgorithm, byte hashAlgorithmByte, byte flags, int iterations, byte[] salt, byte[] nextHashed, TYPE[] types) { 123 assert hashAlgorithmByte == (hashAlgorithm != null ? hashAlgorithm.value : hashAlgorithmByte); 124 this.hashAlgorithmByte = hashAlgorithmByte; 125 this.hashAlgorithm = hashAlgorithm != null ? hashAlgorithm : HashAlgorithm.forByte(hashAlgorithmByte); 126 127 this.flags = flags; 128 this.iterations = iterations; 129 this.salt = salt; 130 this.nextHashed = nextHashed; 131 this.types = types; 132 this.typeBitmap = NSEC.createTypeBitMap(types); 133 } 134 135 public NSEC3(byte hashAlgorithm, byte flags, int iterations, byte[] salt, byte[] nextHashed, TYPE[] types) { 136 this(null, hashAlgorithm, flags, iterations, salt, nextHashed, types); 137 } 138 139 @Override 140 public TYPE getType() { 141 return TYPE.NSEC3; 142 } 143 144 @Override 145 public void serialize(DataOutputStream dos) throws IOException { 146 dos.writeByte(hashAlgorithmByte); 147 dos.writeByte(flags); 148 dos.writeShort(iterations); 149 dos.writeByte(salt.length); 150 dos.write(salt); 151 dos.writeByte(nextHashed.length); 152 dos.write(nextHashed); 153 dos.write(typeBitmap); 154 } 155 156 @Override 157 public String toString() { 158 StringBuilder sb = new StringBuilder() 159 .append(hashAlgorithm).append(' ') 160 .append(flags).append(' ') 161 .append(iterations).append(' ') 162 .append(salt.length == 0 ? "-" : new BigInteger(1, salt).toString(16).toUpperCase()).append(' ') 163 .append(Base32.encodeToString(nextHashed)); 164 for (TYPE type : types) { 165 sb.append(' ').append(type); 166 } 167 return sb.toString(); 168 } 169}