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 org.minidns.constants.DnssecConstants.SignatureAlgorithm; 014import org.minidns.dnsname.DnsName; 015import org.minidns.record.Record.TYPE; 016import org.minidns.util.Base64; 017 018import java.io.ByteArrayInputStream; 019import java.io.DataInputStream; 020import java.io.DataOutputStream; 021import java.io.IOException; 022import java.text.SimpleDateFormat; 023import java.util.Date; 024import java.util.TimeZone; 025 026/** 027 * RRSIG record payload. 028 */ 029public class RRSIG extends Data { 030 031 /** 032 * The type of RRset covered by this signature. 033 */ 034 public final TYPE typeCovered; 035 036 /** 037 * The cryptographic algorithm used to create the signature. 038 */ 039 public final SignatureAlgorithm algorithm; 040 041 /** 042 * The cryptographic algorithm used to create the signature. 043 */ 044 public final byte algorithmByte; 045 046 /** 047 * The number of labels in the original RRSIG RR owner name. 048 */ 049 public final byte labels; 050 051 /** 052 * The TTL of the covered RRset. 053 */ 054 public final long /* unsigned int */ originalTtl; 055 056 /** 057 * The date and time this RRSIG records expires. 058 */ 059 public final Date signatureExpiration; 060 061 /** 062 * The date and time this RRSIG records starts to be valid. 063 */ 064 public final Date signatureInception; 065 066 /** 067 * The key tag value of the DNSKEY RR that validates this signature. 068 */ 069 public final int /* unsigned short */ keyTag; 070 071 /** 072 * The owner name of the DNSKEY RR that a validator is supposed to use. 073 */ 074 public final DnsName signerName; 075 076 /** 077 * Signature that covers RRSIG RDATA (excluding the signature field) and RRset data. 078 */ 079 private final byte[] signature; 080 081 public static RRSIG parse(DataInputStream dis, byte[] data, int length) throws IOException { 082 TYPE typeCovered = TYPE.getType(dis.readUnsignedShort()); 083 byte algorithm = dis.readByte(); 084 byte labels = dis.readByte(); 085 long originalTtl = dis.readInt() & 0xFFFFFFFFL; 086 Date signatureExpiration = new Date((dis.readInt() & 0xFFFFFFFFL) * 1000); 087 Date signatureInception = new Date((dis.readInt() & 0xFFFFFFFFL) * 1000); 088 int keyTag = dis.readUnsignedShort(); 089 DnsName signerName = DnsName.parse(dis, data); 090 int sigSize = length - signerName.size() - 18; 091 byte[] signature = new byte[sigSize]; 092 if (dis.read(signature) != signature.length) throw new IOException(); 093 return new RRSIG(typeCovered, null, algorithm, labels, originalTtl, signatureExpiration, signatureInception, keyTag, signerName, 094 signature); 095 } 096 097 private RRSIG(TYPE typeCovered, SignatureAlgorithm algorithm, byte algorithmByte, byte labels, long originalTtl, Date signatureExpiration, 098 Date signatureInception, int keyTag, DnsName signerName, byte[] signature) { 099 this.typeCovered = typeCovered; 100 101 assert algorithmByte == (algorithm != null ? algorithm.number : algorithmByte); 102 this.algorithmByte = algorithmByte; 103 this.algorithm = algorithm != null ? algorithm : SignatureAlgorithm.forByte(algorithmByte); 104 105 this.labels = labels; 106 this.originalTtl = originalTtl; 107 this.signatureExpiration = signatureExpiration; 108 this.signatureInception = signatureInception; 109 this.keyTag = keyTag; 110 this.signerName = signerName; 111 this.signature = signature; 112 } 113 114 public RRSIG(TYPE typeCovered, int algorithm, byte labels, long originalTtl, Date signatureExpiration, 115 Date signatureInception, int keyTag, DnsName signerName, byte[] signature) { 116 this(typeCovered, null, (byte) algorithm, labels, originalTtl, signatureExpiration, signatureInception, keyTag, signerName, signature); 117 } 118 119 public RRSIG(TYPE typeCovered, int algorithm, byte labels, long originalTtl, Date signatureExpiration, 120 Date signatureInception, int keyTag, String signerName, byte[] signature) { 121 this(typeCovered, null, (byte) algorithm, labels, originalTtl, signatureExpiration, signatureInception, keyTag, DnsName.from(signerName), signature); 122 } 123 124 public RRSIG(TYPE typeCovered, SignatureAlgorithm algorithm, byte labels, 125 long originalTtl, Date signatureExpiration, Date signatureInception, 126 int keyTag, DnsName signerName, byte[] signature) { 127 this(typeCovered, algorithm.number, labels, originalTtl, signatureExpiration, signatureInception, 128 keyTag, signerName, signature); 129 } 130 131 public RRSIG(TYPE typeCovered, SignatureAlgorithm algorithm, byte labels, 132 long originalTtl, Date signatureExpiration, Date signatureInception, 133 int keyTag, String signerName, byte[] signature) { 134 this(typeCovered, algorithm.number, labels, originalTtl, signatureExpiration, signatureInception, 135 keyTag, DnsName.from(signerName), signature); 136 } 137 138 public byte[] getSignature() { 139 return signature.clone(); 140 } 141 142 public DataInputStream getSignatureAsDataInputStream() { 143 return new DataInputStream(new ByteArrayInputStream(signature)); 144 } 145 146 public int getSignatureLength() { 147 return signature.length; 148 } 149 150 private transient String base64SignatureCache; 151 152 public String getSignatureBase64() { 153 if (base64SignatureCache == null) { 154 base64SignatureCache = Base64.encodeToString(signature); 155 } 156 return base64SignatureCache; 157 } 158 159 @Override 160 public TYPE getType() { 161 return TYPE.RRSIG; 162 } 163 164 @Override 165 public void serialize(DataOutputStream dos) throws IOException { 166 writePartialSignature(dos); 167 dos.write(signature); 168 } 169 170 public void writePartialSignature(DataOutputStream dos) throws IOException { 171 dos.writeShort(typeCovered.getValue()); 172 dos.writeByte(algorithmByte); 173 dos.writeByte(labels); 174 dos.writeInt((int) originalTtl); 175 dos.writeInt((int) (signatureExpiration.getTime() / 1000)); 176 dos.writeInt((int) (signatureInception.getTime() / 1000)); 177 dos.writeShort(keyTag); 178 signerName.writeToStream(dos); 179 } 180 181 @Override 182 public String toString() { 183 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); 184 dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); 185 StringBuilder sb = new StringBuilder() 186 .append(typeCovered).append(' ') 187 .append(algorithm).append(' ') 188 .append(labels).append(' ') 189 .append(originalTtl).append(' ') 190 .append(dateFormat.format(signatureExpiration)).append(' ') 191 .append(dateFormat.format(signatureInception)).append(' ') 192 .append(keyTag).append(' ') 193 .append(signerName).append(". ") 194 .append(getSignatureBase64()); 195 return sb.toString(); 196 } 197}