diff --git a/lib/dnsjava-2.0.1-vrsn-1.jar b/lib/dnsjava-2.0.1-vrsn-1.jar index d31513b..ec741d3 100644 Binary files a/lib/dnsjava-2.0.1-vrsn-1.jar and b/lib/dnsjava-2.0.1-vrsn-1.jar differ diff --git a/src/com/verisignlabs/dnssec/cl/DSTool.java b/src/com/verisignlabs/dnssec/cl/DSTool.java index 44be9c4..c530c57 100644 --- a/src/com/verisignlabs/dnssec/cl/DSTool.java +++ b/src/com/verisignlabs/dnssec/cl/DSTool.java @@ -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."); diff --git a/src/com/verisignlabs/dnssec/cl/SignZone.java b/src/com/verisignlabs/dnssec/cl/SignZone.java index 0f59a5c..a9ec6f6 100644 --- a/src/com/verisignlabs/dnssec/cl/SignZone.java +++ b/src/com/verisignlabs/dnssec/cl/SignZone.java @@ -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 .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 diff --git a/src/com/verisignlabs/dnssec/security/JCEDnsSecSigner.java b/src/com/verisignlabs/dnssec/security/JCEDnsSecSigner.java index a96ef4d..76484db 100644 --- a/src/com/verisignlabs/dnssec/security/JCEDnsSecSigner.java +++ b/src/com/verisignlabs/dnssec/security/JCEDnsSecSigner.java @@ -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) diff --git a/src/com/verisignlabs/dnssec/security/SHA256.java b/src/com/verisignlabs/dnssec/security/SHA256.java new file mode 100644 index 0000000..9274976 --- /dev/null +++ b/src/com/verisignlabs/dnssec/security/SHA256.java @@ -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]) + " "); + } + } + +} diff --git a/src/com/verisignlabs/dnssec/security/SignUtils.java b/src/com/verisignlabs/dnssec/security/SignUtils.java index 3ad020d..726a6bc 100644 --- a/src/com/verisignlabs/dnssec/security/SignUtils.java +++ b/src/com/verisignlabs/dnssec/security/SignUtils.java @@ -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); }