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