001/* 002 * Copyright 2015-2024 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 java.io.DataInputStream; 014import java.io.DataOutputStream; 015import java.io.IOException; 016import java.math.BigInteger; 017import java.util.Arrays; 018 019import org.minidns.constants.DnssecConstants.DigestAlgorithm; 020import org.minidns.constants.DnssecConstants.SignatureAlgorithm; 021 022/** 023 * DS (Delegation Signer) record payload. 024 * 025 * @see <a href="https://tools.ietf.org/html/rfc4034#section-5">RFC 4034 ยง 5</a> 026 */ 027public abstract class DelegatingDnssecRR extends Data { 028 029 /** 030 * The key tag value of the DNSKEY RR that validates this signature. 031 */ 032 public final int /* unsigned short */ keyTag; 033 034 /** 035 * The cryptographic algorithm used to create the signature. If MiniDNS 036 * isn't aware of the signature algorithm, then this field will be 037 * <code>null</code>. 038 * 039 * @see #algorithmByte 040 */ 041 public final SignatureAlgorithm algorithm; 042 043 /** 044 * The byte value of the cryptographic algorithm used to create the signature. 045 */ 046 public final byte algorithmByte; 047 048 /** 049 * The algorithm used to construct the digest. If MiniDNS 050 * isn't aware of the digest algorithm, then this field will be 051 * <code>null</code>. 052 * 053 * @see #digestTypeByte 054 */ 055 public final DigestAlgorithm digestType; 056 057 /** 058 * The byte value of algorithm used to construct the digest. 059 */ 060 public final byte digestTypeByte; 061 062 /** 063 * The digest build from a DNSKEY. 064 */ 065 protected final byte[] digest; 066 067 protected static SharedData parseSharedData(DataInputStream dis, int length) throws IOException { 068 int keyTag = dis.readUnsignedShort(); 069 byte algorithm = dis.readByte(); 070 byte digestType = dis.readByte(); 071 byte[] digest = new byte[length - 4]; 072 if (dis.read(digest) != digest.length) throw new IOException(); 073 return new SharedData(keyTag, algorithm, digestType, digest); 074 } 075 076 protected static final class SharedData { 077 protected final int keyTag; 078 protected final byte algorithm; 079 protected final byte digestType; 080 protected final byte[] digest; 081 082 private SharedData(int keyTag, byte algorithm, byte digestType, byte[] digest) { 083 this.keyTag = keyTag; 084 this.algorithm = algorithm; 085 this.digestType = digestType; 086 this.digest = digest; 087 } 088 } 089 090 protected DelegatingDnssecRR(int keyTag, SignatureAlgorithm algorithm, byte algorithmByte, DigestAlgorithm digestType, byte digestTypeByte, byte[] digest) { 091 this.keyTag = keyTag; 092 093 assert algorithmByte == (algorithm != null ? algorithm.number : algorithmByte); 094 this.algorithmByte = algorithmByte; 095 this.algorithm = algorithm != null ? algorithm : SignatureAlgorithm.forByte(algorithmByte); 096 097 assert digestTypeByte == (digestType != null ? digestType.value : digestTypeByte); 098 this.digestTypeByte = digestTypeByte; 099 this.digestType = digestType != null ? digestType : DigestAlgorithm.forByte(digestTypeByte); 100 101 assert digest != null; 102 this.digest = digest; 103 } 104 105 protected DelegatingDnssecRR(int keyTag, byte algorithm, byte digestType, byte[] digest) { 106 this(keyTag, null, algorithm, null, digestType, digest); 107 } 108 109 protected DelegatingDnssecRR(int keyTag, SignatureAlgorithm algorithm, DigestAlgorithm digestType, byte[] digest) { 110 this(keyTag, algorithm, algorithm.number, digestType, digestType.value, digest); 111 } 112 113 protected DelegatingDnssecRR(int keyTag, SignatureAlgorithm algorithm, byte digestType, byte[] digest) { 114 this(keyTag, algorithm, algorithm.number, null, digestType, digest); 115 } 116 117 @Override 118 public void serialize(DataOutputStream dos) throws IOException { 119 dos.writeShort(keyTag); 120 dos.writeByte(algorithmByte); 121 dos.writeByte(digestTypeByte); 122 dos.write(digest); 123 } 124 125 @Override 126 public String toString() { 127 StringBuilder sb = new StringBuilder() 128 .append(keyTag).append(' ') 129 .append(algorithm).append(' ') 130 .append(digestType).append(' ') 131 .append(new BigInteger(1, digest).toString(16).toUpperCase()); 132 return sb.toString(); 133 } 134 135 private transient BigInteger digestBigIntCache; 136 137 public BigInteger getDigestBigInteger() { 138 if (digestBigIntCache == null) { 139 digestBigIntCache = new BigInteger(1, digest); 140 } 141 return digestBigIntCache; 142 } 143 144 private transient String digestHexCache; 145 146 public String getDigestHex() { 147 if (digestHexCache == null) { 148 digestHexCache = getDigestBigInteger().toString(16).toUpperCase(); 149 } 150 return digestHexCache; 151 } 152 153 public boolean digestEquals(byte[] otherDigest) { 154 return Arrays.equals(digest, otherDigest); 155 } 156}