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