Add support for the SHA256 DS digest algorithm.

git-svn-id: https://svn.verisignlabs.com/jdnssec/tools/trunk@76 4cbd57fe-54e5-0310-bd9a-f30fe5ea5e6e
This commit is contained in:
David Blacka 2006-05-24 22:19:31 +00:00
parent 633ab040b3
commit dff0e250f6
6 changed files with 461 additions and 110 deletions

Binary file not shown.

View File

@ -56,12 +56,41 @@ public class DSTool
public boolean createDLV = false;
public String outputfile = null;
public String keyname = null;
public int digest_id = DSRecord.SHA1_DIGEST_ID;
public CLIState()
{
setupCLI();
}
/**
* Set up the command line options.
*
* @return a set of command line options.
*/
private void setupCLI()
{
opts = new Options();
// boolean options
opts.addOption("h", "help", false, "Print this message.");
opts.addOption(OptionBuilder.withLongOpt("dlv")
.withDescription("Generate a DLV record instead.").create());
// Argument options
opts.addOption(OptionBuilder.hasOptionalArg().withLongOpt("verbose")
.withArgName("level")
.withDescription("verbosity level -- 0 is silence, "
+ "5 is debug information, " + "6 is trace information.\n"
+ "default is level 5.").create('v'));
opts.addOption(OptionBuilder.hasArg().withLongOpt("digest")
.withArgName("id")
.withDescription("The Digest ID to use (numerically): "
+ "either 1 for SHA1 or 2 for SHA256").create('d'));
}
public void parseCommandLine(String[] args)
throws org.apache.commons.cli.ParseException
{
@ -91,7 +120,9 @@ public class DSTool
outputfile = cli.getOptionValue('f');
createDLV = cli.hasOption("dlv");
String optstr = cli.getOptionValue('d');
if (optstr != null) digest_id = parseInt(optstr, digest_id);
String[] cl_args = cli.getArgs();
if (cl_args.length < 1)
@ -103,32 +134,6 @@ public class DSTool
keyname = cl_args[0];
}
/**
* Set up the command line options.
*
* @return a set of command line options.
*/
private void setupCLI()
{
opts = new Options();
// boolean options
opts.addOption("h", "help", false, "Print this message.");
OptionBuilder.withLongOpt("dlv");
OptionBuilder.withDescription("Generate a DLV record instead.");
opts.addOption(OptionBuilder.create());
// Argument options
OptionBuilder.hasOptionalArg();
OptionBuilder.withLongOpt("verbose");
OptionBuilder.withArgName("level");
OptionBuilder.withDescription("verbosity level -- 0 is silence, "
+ "5 is debug information, " + "6 is trace information.\n"
+ "default is level 5.");
opts.addOption(OptionBuilder.create('v'));
}
/** Print out the usage and help statements, then quit. */
private void usage()
{
@ -176,15 +181,17 @@ public class DSTool
DnsKeyPair key = BINDKeyUtils.loadKey(state.keyname, null);
DNSKEYRecord dnskey = key.getDNSKEYRecord();
if ((dnskey.getFlags() & DNSKEYRecord.Flags.SEP_KEY) == 0)
{
log.warning("DNSKEY is not an SEP-flagged key.");
}
DSRecord ds = SignUtils.calculateDSRecord(dnskey, dnskey.getTTL());
DSRecord ds = SignUtils.calculateDSRecord(dnskey,
state.digest_id,
dnskey.getTTL());
Record res = ds;
if (state.createDLV)
{
log.fine("creating DLV.");

View File

@ -34,14 +34,9 @@ import java.util.logging.Logger;
import java.util.logging.Level;
import org.apache.commons.cli.*;
import org.apache.commons.cli.Options;
import org.xbill.DNS.DNSKEYRecord;
import org.xbill.DNS.DNSSEC;
import org.xbill.DNS.Name;
import org.xbill.DNS.RRset;
import org.xbill.DNS.Record;
import org.xbill.DNS.TextParseException;
import org.xbill.DNS.Type;
import org.xbill.DNS.*;
import org.xbill.DNS.utils.base16;
import com.verisignlabs.dnssec.security.*;
@ -73,12 +68,13 @@ public class SignZone
public String outputfile = null;
public boolean verifySigs = false;
public boolean selfSignKeys = true;
public boolean useOptIn = false;
public boolean useOptOut = false;
public boolean fullySignKeyset = false;
public List includeNames = null;
public boolean useNsec3 = false;
public byte[] salt = null;
public int iterations = 0;
public int digest_id = DSRecord.SHA1_DIGEST_ID;
public CLIState()
{
@ -104,7 +100,7 @@ public class SignZone
// Argument options
opts.addOption(OptionBuilder.hasOptionalArg().withLongOpt("verbose")
.withArgName("level").withDescription("verbosity level")
.withArgName("level").withDescription("verbosity level.")
.create('v'));
opts.addOption(OptionBuilder.hasArg().withArgName("dir")
.withLongOpt("keyset-directory")
@ -127,21 +123,19 @@ public class SignZone
+ "(default is <origin>.signed).").create('f'));
opts.addOption(OptionBuilder.hasArg().withArgName("KSK file")
.withLongOpt("ksk-file")
.withDescription("this key is the key signing key.").create('k'));
.withDescription("this key is a key signing key (may repeat).")
.create('k'));
opts.addOption(OptionBuilder.hasArg().withArgName("file")
.withLongOpt("include-file")
.withDescription("include names in this "
+ "file in the NSEC/NSEC3 chain.").create('I'));
opts.addOption(OptionBuilder.hasArg()
.withArgName("alias:original:mnemonic").withLongOpt("alg-alias")
.withDescription("Define an alias for an algorithm").create('A'));
// NSEC3 options
opts.addOption("3", "use-nsec3", false, "use NSEC3 instead of NSEC");
opts.addOption("O",
"use-opt-in",
"use-opt-out",
false,
"generate a fully Opt-In zone.");
"generate a fully Opt-Out zone (only valid with NSEC3).");
opts.addOption(OptionBuilder.hasArg().withLongOpt("salt")
.withArgName("hex value").withDescription("supply a salt value.")
@ -153,6 +147,15 @@ public class SignZone
.withArgName("value")
.withDescription("use this value for the iterations in NSEC3.")
.create());
opts.addOption(OptionBuilder.hasArg()
.withArgName("alias:original:mnemonic").withLongOpt("alg-alias")
.withDescription("Define an alias for an algorithm (may repeat).")
.create('A'));
opts.addOption(OptionBuilder.hasArg().withArgName("id")
.withLongOpt("ds-digest")
.withDescription("Digest algorithm to use for generated DSs")
.create());
}
public void parseCommandLine(String[] args)
@ -195,12 +198,12 @@ public class SignZone
if (cli.hasOption('a')) verifySigs = true;
if (cli.hasOption('3')) useNsec3 = true;
if (cli.hasOption('O')) useOptIn = true;
if (cli.hasOption('O')) useOptOut = true;
if (useOptIn && !useNsec3)
if (useOptOut && !useNsec3)
{
System.err.println("OptIn not supported without NSEC3 -- ignored.");
useOptIn = false;
System.err.println("Opt-Out not supported without NSEC3 -- ignored.");
useOptOut = false;
}
if ((optstrs = cli.getOptionValues('A')) != null)
@ -210,7 +213,7 @@ public class SignZone
addArgAlias(optstrs[i]);
}
}
if (cli.hasOption('F')) fullySignKeyset = true;
if ((optstr = cli.getOptionValue('d')) != null)
@ -294,6 +297,16 @@ public class SignZone
}
}
if ((optstr = cli.getOptionValue("ds-digest")) != null)
{
digest_id = parseInt(optstr, -1);
if (digest_id < 0)
{
System.err.println("error: DS digest ID is not a valid identifier");
usage();
}
}
String[] files = cli.getArgs();
if (files.length < 1)
@ -328,7 +341,7 @@ public class SignZone
algs.addAlias(alias, mn, orig);
}
/** Print out the usage and help statements, then quit. */
private void usage()
{
@ -477,7 +490,6 @@ public class SignZone
{
if (inDirectory == null)
{
// FIXME: dunno how cross-platform this is
inDirectory = new File(".");
}
@ -663,33 +675,26 @@ public class SignZone
/**
* Given a zone, sign it.
*
* @param zonename the name of the zone.
* @param records the records comprising the zone. They do not have to be in
* @param signer A signer (utility) object to use to actually sign stuff.
* @param zonename The name of the zone.
* @param records The records comprising the zone. They do not have to be in
* any particular order, as this method will order them as
* necessary.
* @param keysigningkeypairs the key pairs that are designated as "key
* @param keysigningkeypairs The key pairs that are designated as "key
* signing keys".
* @param zonekeypair this key pairs that are designated as "zone signing
* @param zonekeypair This key pairs that are designated as "zone signing
* keys".
* @param start the RRSIG inception time.
* @param expire the RRSIG expiration time.
* @param useOptIn generate Opt-In style NXT records. It will consider any
* insecure delegation to be unsigned. To override this, include
* the name of the insecure delegation in the NXTIncludeNames list.
* @param useConservativeOptIn if true, Opt-In NXT records will only be
* generated if there are insecure, unsigned delegations in the
* span. Not effect if useOptIn is false.
* @param fullySignKeyset sign the zone apex keyset with all available keys.
* @param NXTIncludeNames names that are to be included in the NXT chain
* regardless. This may be null and is only used if useOptIn is
* true.
* @param start The RRSIG inception time.
* @param expire The RRSIG expiration time.
* @param fullySignKeyset Sign the zone apex keyset with all available keys.
* @param digest_id The digest identifier to use when generating DS records.
*
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
* representing the signed zone.
*/
private static List signZone(JCEDnsSecSigner signer, Name zonename,
List records, List keysigningkeypairs, List zonekeypairs, Date start,
Date expire, boolean fullySignKeyset)
Date expire, boolean fullySignKeyset, int digest_id)
throws IOException, GeneralSecurityException
{
@ -703,7 +708,7 @@ public class SignZone
SignUtils.removeDuplicateRecords(records);
// Generate DS records
SignUtils.generateDSRecords(zonename, records);
SignUtils.generateDSRecords(zonename, records, digest_id);
// Generate the NSEC records
SignUtils.generateNSECRecords(zonename, records);
@ -768,10 +773,42 @@ public class SignZone
return signed_records;
}
/**
* Given a zone sign it using NSEC3 records.
*
* @param signer A signer (utility) object used to actually sign stuff.
* @param zonename The name of the zone being signed.
* @param records The records comprising the zone. They do not have to be in
* any particular order, as this method will order them as
* necessary.
* @param keysigningkeypairs The key pairs that are designated as "key
* signing keys".
* @param zonekeypairs This key pairs that are designated as "zone signing
* keys".
* @param start The RRSIG inception time.
* @param expire The RRSIG expiration time.
* @param fullySignKeyset If true then the DNSKEY RRset will be signed by
* all available keys, if false, only the key signing keys.
* @param useOptOut If true, insecure delegations will be omitted from the
* NSEC3 chain, and all NSEC3 records will have the Opt-Out flag
* set.
* @param includedNames A list of names to include in the NSEC3 chain
* regardless.
* @param salt The salt to use for the NSEC3 hashing. null means no salt.
* @param iterations The number of iterations to use for the NSEC3 hashing.
* @param ds_digest_id The digest algorithm to use when generating DS
* records.
*
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
* representing the signed zone.
*
* @throws IOException
* @throws GeneralSecurityException
*/
private static List signZoneNSEC3(JCEDnsSecSigner signer, Name zonename,
List records, List keysigningkeypairs, List zonekeypairs, Date start,
Date expire, boolean fullySignKeyset, boolean useOptIn,
List includedNames, byte[] salt, int iterations)
Date expire, boolean fullySignKeyset, boolean useOptOut,
List includedNames, byte[] salt, int iterations, int ds_digest_id)
throws IOException, GeneralSecurityException
{
// Remove any existing DNSSEC records (NSEC, NSEC3, RRSIG)
@ -779,17 +816,17 @@ public class SignZone
// Sort the zone
Collections.sort(records, new RecordComparator());
// Remove duplicate records
SignUtils.removeDuplicateRecords(records);
// Generate DS records
SignUtils.generateDSRecords(zonename, records);
SignUtils.generateDSRecords(zonename, records, ds_digest_id);
// Generate NSEC3 records
if (useOptIn)
if (useOptOut)
{
SignUtils.generateOptInNSEC3Records(zonename,
SignUtils.generateOptOutNSEC3Records(zonename,
records,
includedNames,
salt,
@ -900,14 +937,14 @@ public class SignZone
{
keypairs = kskpairs;
}
// If there *still* aren't any ZSKs defined, bail.
if (keypairs == null || keypairs.size() == 0)
{
System.err.println("No zone signing keys could be determined.");
state.usage();
}
// Read in the zone
List records = ZoneUtils.readZoneFile(state.zonefile, null);
if (records == null || records.size() == 0)
@ -941,6 +978,7 @@ public class SignZone
if (!keyPairsValidForZone(zonename, keypairs)
|| !keyPairsValidForZone(zonename, kskpairs))
{
System.err.println("error: specified keypairs are not valid for the zone.");
state.usage();
}
@ -961,7 +999,7 @@ public class SignZone
records.add(((DnsKeyPair) i.next()).getDNSKEYRecord());
}
}
// read in the keysets, if any.
List keysetrecs = getKeysets(state.keysetDirectory, zonename);
if (keysetrecs != null)
@ -984,10 +1022,11 @@ public class SignZone
state.start,
state.expire,
state.fullySignKeyset,
state.useOptIn,
state.useOptOut,
state.includeNames,
state.salt,
state.iterations);
state.iterations,
state.digest_id);
}
else
{
@ -998,7 +1037,8 @@ public class SignZone
keypairs,
state.start,
state.expire,
state.fullySignKeyset);
state.fullySignKeyset,
state.digest_id);
}
// write out the signed zone

View File

@ -264,8 +264,6 @@ public class JCEDnsSecSigner
* necessary.
* @param keysigningkeypairs the key pairs that are designated as "key
* signing keys".
* @param zonekeypair this key pairs that are designated as "zone signing
* keys".
* @param start the RRSIG inception time.
* @param expire the RRSIG expiration time.
* @param useOptIn generate Opt-In style NXT records. It will consider any
@ -275,17 +273,20 @@ public class JCEDnsSecSigner
* generated if there are insecure, unsigned delegations in the
* span. Not effect if useOptIn is false.
* @param fullySignKeyset sign the zone apex keyset with all available keys.
* @param ds_digest_id TODO
* @param zonekeypair this key pairs that are designated as "zone signing
* keys".
* @param NXTIncludeNames names that are to be included in the NXT chain
* regardless. This may be null and is only used if useOptIn is
* true.
*
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
* representing the signed zone.
*/
public List signZone(Name zonename, List records, List keysigningkeypairs,
List zonekeypairs, Date start, Date expire, boolean useOptIn,
boolean useConservativeOptIn, boolean fullySignKeyset,
List NSECIncludeNames) throws IOException, GeneralSecurityException
List NSECIncludeNames, int ds_digest_id)
throws IOException, GeneralSecurityException
{
// Remove any existing DNSSEC records (NSEC, RRSIG)
@ -297,7 +298,7 @@ public class JCEDnsSecSigner
SignUtils.removeDuplicateRecords(records);
// Generate DS records
SignUtils.generateDSRecords(zonename, records);
SignUtils.generateDSRecords(zonename, records, ds_digest_id);
// Generate NXT records
if (useOptIn)

View File

@ -0,0 +1,285 @@
/*************************************************************************
* SHA256
*
* a homebrew of the SHA256 algorithm for dnsjava. Some of the concepts
* are taken from the Cryptix crypto provider: http://www.cryptix.org
*
* Scott Rose
* NIST
* 04/16/04
*************************************************************************/
package com.verisignlabs.dnssec.security;
import java.io.ByteArrayOutputStream;
public class SHA256
{
private int Ch(int a, int b, int c)
{
return (a & b) ^ (~a & c);
}
private int Maj(int a, int b, int c)
{
return (a & b) ^ (a & c) ^ (b & c);
}
private int SHR(int x, int n)
{
return (x >>> n);
}
private int ROTR(int x, int n)
{
return ((x >>> n) | (x << (32 - n)));
}
private int SIG0(int x)
{
return (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22));
}
private int SIG1(int x)
{
return (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25));
}
private int sig0(int x)
{
return (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3));
}
private int sig1(int x)
{
return (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10));
}
// Constants "K"
private static final int K[] = {0x428a2f98, 0x71374491, 0xb5c0fbcf,
0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98,
0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7,
0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8,
0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85,
0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e,
0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c,
0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee,
0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
0xc67178f2 };
private int digest[] = new int[8];
private byte data[];
public SHA256()
{
}
public void init()
{
digest[0] = 0x6a09e667;
digest[1] = 0xbb67ae85;
digest[2] = 0x3c6ef372;
digest[3] = 0xa54ff53a;
digest[4] = 0x510e527f;
digest[5] = 0x9b05688c;
digest[6] = 0x1f83d9ab;
digest[7] = 0x5be0cd19;
}
public void setData(byte input[])
{
// clone the array
data = doDataPad(input);
}
private byte[] doDataPad(byte input[])
{
int n, fill;
n = input.length + 9;
if (input.length < 55)
{
fill = 64 - n;
}
else
{
fill = 64 - (n % 64);
}
if ((input.length % 64) != 0)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write(input, 0, input.length);
out.write(0x80);
for (int i = 0; i < fill; i++)
out.write(0x00);
long l = input.length * 8; // length is measured in bits
out.write((int) (l >>> 56) & 0xFF);
out.write((int) (l >>> 48) & 0xFF);
out.write((int) (l >>> 40) & 0xFF);
out.write((int) (l >>> 32) & 0xFF);
out.write((int) (l >>> 24) & 0xFF);
out.write((int) (l >>> 16) & 0xFF);
out.write((int) (l >>> 8) & 0xFF);
out.write((int) l & 0xFF);
// we are replacing data here with a new padded version
return out.toByteArray();
}
return input;
}
/*
* utility method to convert a byte input array to an int[] for easier
* processing. Also does the padding as necessary
*/
private int[] convertToInt(byte block[])
{
int output[] = new int[16];
int w = -1;
for (int i = 0; i < 16; i++)
{
output[i] = (block[++w] << 24) | ((block[++w] & 0xFF) << 16)
| ((block[++w] & 0xFF) << 8) | (block[++w] & 0xFF);
}
return output;
}
/*
* method called to get the SHA1 digest of the input
*/
public byte[] getDigest()
{
byte output[] = new byte[32];
int aBlock[];
byte byteBlock[];
// for (int n = 0; n < data.length; n++)
// {
// System.out.print(Integer.toHexString(data[n]) + " ");
// }
// System.out.println("\n\n");
if (data.length > 64)
{
int n = data.length / 64;
int place = 0;
for (int i = 0; i < n; i++)
{
byteBlock = new byte[64];
for (int x = 0; x < 64; x++)
{
byteBlock[x] = data[place++];
}
aBlock = convertToInt(byteBlock);
transform(aBlock);
}
}
else
{
aBlock = convertToInt(data);
transform(aBlock);
}
// convert the int array back to byte and return
int out = -1;
for (int i = 0; i < 8; i++)
{
output[++out] = (byte) ((digest[i] >>> 24) & 0xFF);
output[++out] = (byte) ((digest[i] >>> 16) & 0xFF);
output[++out] = (byte) ((digest[i] >>> 8) & 0xFF);
output[++out] = (byte) (digest[i] & 0xFF);
}
return output;
}
/*
* this is the method that actually performs the digest and returns the
* result
*/
private void transform(int block[])
{
// first, break into blocks and process one by one
int A = digest[0];
int B = digest[1];
int C = digest[2];
int D = digest[3];
int E = digest[4];
int F = digest[5];
int G = digest[6];
int H = digest[7];
// doing the message schedule
int W[] = new int[64];
for (int i = 0; i < 16; i++)
{
W[i] = block[i];
// System.out.println("W: " + Integer.toHexString(W[i]) + "\n");
}
for (int i = 16; i < 64; i++)
{
W[i] = sig1(W[i - 2]) + W[i - 7] + sig0(W[i - 15]) + W[i - 16];
}
for (int t = 0; t < 64; t++)
{
int T1 = H + SIG1(E) + Ch(E, F, G) + K[t] + W[t];
int T2 = SIG0(A) + Maj(A, B, C);
H = G;
G = F;
F = E;
E = D + T1;
D = C;
C = B;
B = A;
A = T1 + T2;
// System.out.println("A: " + Integer.toHexString(A));
// System.out.println("B: " + Integer.toHexString(B));
// System.out.println("C: " + Integer.toHexString(C));
// System.out.println("D: " + Integer.toHexString(D));
// System.out.println("E: " + Integer.toHexString(E));
// System.out.println("F: " + Integer.toHexString(F));
// System.out.println("G: " + Integer.toHexString(G));
// System.out.println("H: " + Integer.toHexString(H) + "\n");
}
digest[0] += A;
digest[1] += B;
digest[2] += C;
digest[3] += D;
digest[4] += E;
digest[6] += F;
digest[7] += G;
}
public static void main(String argv[])
{
String data1 = "abc";
SHA256 sha = new SHA256();
byte output[];
sha.init();
System.out.println("ready to set the data");
sha.setData(data1.getBytes());
System.out.println("ready to get the digest");
output = sha.getDigest();
for (int i = 0; i < output.length; i++)
{
// Integer b = new Integer((int)output[i]);
System.out.print(Integer.toHexString(output[i]) + " ");
}
}
}

View File

@ -42,15 +42,15 @@ import org.xbill.DNS.utils.base64;
public class SignUtils
{
private static final int ASN1_INT = 0x02;
private static final int ASN1_SEQ = 0x30;
private static final int ASN1_INT = 0x02;
private static final int ASN1_SEQ = 0x30;
public static final int RR_NORMAL = 0;
public static final int RR_DELEGATION = 1;
public static final int RR_GLUE = 2;
public static final int RR_INVALID = 3;
public static final int RR_NORMAL = 0;
public static final int RR_DELEGATION = 1;
public static final int RR_GLUE = 2;
public static final int RR_INVALID = 3;
private static Logger log;
private static Logger log;
static
{
@ -712,16 +712,16 @@ public class SignUtils
List nsec3s = finishNSEC3s(proto_nsec3s);
// DEBUG
// for (Iterator i = nsec3s.iterator(); i.hasNext();)
// {
// NSEC3Record nsec3 = (NSEC3Record) i.next();
// log.fine("NSEC3: " + nsec3 + "\nRDATA: "
// + base16.toString(nsec3.rdataToWireCanonical()));
// }
// for (Iterator i = nsec3s.iterator(); i.hasNext();)
// {
// NSEC3Record nsec3 = (NSEC3Record) i.next();
// log.fine("NSEC3: " + nsec3 + "\nRDATA: "
// + base16.toString(nsec3.rdataToWireCanonical()));
// }
records.addAll(nsec3s);
}
public static void generateOptInNSEC3Records(Name zonename, List records,
public static void generateOptOutNSEC3Records(Name zonename, List records,
List includedNames, byte[] salt, int iterations)
throws NoSuchAlgorithmException
{
@ -1081,8 +1081,9 @@ public class SignUtils
* @param zonename the name of the zone, used to reliably distinguish the
* zone apex from other records.
* @param records a list of {@link org.xbill.DNS.Record} objects.
* @param digest_id The digest algorithm to use.
*/
public static void generateDSRecords(Name zonename, List records)
public static void generateDSRecords(Name zonename, List records, int digest_id)
{
for (ListIterator i = records.listIterator(); i.hasNext();)
@ -1096,7 +1097,9 @@ public class SignUtils
// Convert non-zone level KEY records into DS records.
if (r.getType() == Type.DNSKEY && !r_name.equals(zonename))
{
DSRecord ds = calculateDSRecord((DNSKEYRecord) r, r.getTTL());
DSRecord ds = calculateDSRecord((DNSKEYRecord) r,
DSRecord.SHA1_DIGEST_ID,
r.getTTL());
i.set(ds);
}
@ -1155,11 +1158,13 @@ public class SignUtils
* Given a DNSKEY record, generate the DS record from it.
*
* @param keyrec the KEY record in question.
* @param digest_id The digest ID.
* @param ttl the desired TTL for the generated DS record. If zero, or
* negative, the original KEY RR's TTL will be used.
* @return the corresponding {@link org.xbill.DNS.DSRecord}
*/
public static DSRecord calculateDSRecord(DNSKEYRecord keyrec, long ttl)
public static DSRecord calculateDSRecord(DNSKEYRecord keyrec,
int digest_id, long ttl)
{
if (keyrec == null) return null;
@ -1172,12 +1177,25 @@ public class SignUtils
try
{
MessageDigest md = MessageDigest.getInstance("SHA");
byte[] digest = md.digest(os.toByteArray());
byte[] digest;
switch (digest_id)
{
case DSRecord.SHA1_DIGEST_ID :
MessageDigest md = MessageDigest.getInstance("SHA");
digest = md.digest(os.toByteArray());
break;
case DSRecord.SHA256_DIGEST_ID :
SHA256 sha = new SHA256();
sha.setData(os.toByteArray());
digest = sha.getDigest();
break;
default :
throw new IllegalArgumentException("Unknown digest id: " + digest_id);
}
return new DSRecord(keyrec.getName(), keyrec.getDClass(), ttl, keyrec
.getFootprint(), keyrec.getAlgorithm(), DSRecord.SHA1_DIGEST_ID,
.getFootprint(), keyrec.getAlgorithm(), digest_id,
digest);
}