10 Commits

Author SHA1 Message Date
David Blacka
efa6dec7f7 update version to prep for an official release. 2012-05-29 13:31:40 -04:00
d3e8c4c913 Add duplicate RR detection to jdnssec-verifyzone, and a command line option to disable it. 2012-05-26 23:14:12 -04:00
b5775a8fdf update README to point to github. 2012-05-26 16:40:50 -04:00
69d965cc0f Wrap the new exceptions to mimic prior behavior. 2012-05-26 16:40:50 -04:00
ca7f10bd07 Instead of using DNSSEC.Secure, DNSSEC.Failed, etc, just use boolean results.
This means we lose the idea of Insecure, but that wasn't effectively being used anyway.
Further, remove any use of the DNSJava Cache class -- that also wasn't being used.
2012-05-26 16:40:50 -04:00
25cc81d46a Replace use of old KEYConverter with new DNSKEYRecord constructor. 2012-05-26 16:40:50 -04:00
2a90a6ccd9 byte -> int for NSEC3 digest type. 2012-05-26 16:40:49 -04:00
b18a96cbfc Change dnsjava algorithm references from DNSSEC.<alg> to DNSSEC.Algorithm.<alg> 2012-05-26 16:40:49 -04:00
cc0873a336 Upgrade local dnsjava fork to 2.3.1-vrsn-1 2012-05-26 16:40:49 -04:00
4d1acb8918 add .gitignore 2012-05-19 20:10:21 -04:00
16 changed files with 186 additions and 137 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
build
.classpath
.project
jdnssec-tools*.tar.gz
docs

View File

@@ -1,3 +1,23 @@
2012-05-29 David Blacka <davidb@verisign.com>
* Released version 0.11.
2012-05-26 David Blacka <davidb@verisign.com>
* Update dnsjava to dnsjava-2.1.3-vrsn-1. Update the code to
adjust for API changes in dnsjava-2.1.x. Highlights:
- no longer use DNSSEC.Failed, DNSSEC.Secure as those constants
are now gone. Instead, any methods returning those constants now
return a boolean, true for DNSSEC.Secure, false for DNSSEC.Failed
or DNSSEC.Insecure.
- No longer use KEYConverter. Instead, uses the new DNSKEYRecord
constructor.
- The NSEC3 digest type is now an int (rather than a byte)
- Algorithm references are now DNSSEC.Algorithm.<alg>
* jdnssec-verifyzone: Add duplicate RR detection (on by default)
and a command line option to disable it.
2011-02-14 David Blacka <davidb@verisign.com> 2011-02-14 David Blacka <davidb@verisign.com>
* Released version 0.10.1. * Released version 0.10.1.

17
README
View File

@@ -1,6 +1,7 @@
jdnssec-tools jdnssec-tools
http://www.verisignlabs.com/jdnssec-tools/ http://www.verisignlabs.com/jdnssec-tools/
https://github.com/dblacka/jdnssec-tools/wiki
Author: David Blacka (davidb@verisign.com) Author: David Blacka (davidb@verisign.com)
@@ -12,8 +13,8 @@ These tools depend upon DNSjava (http://www.xbill.org/dnsjava), the
Jakarta Commons CLI and Logging libraries (http://jakarta.apache.org), Jakarta Commons CLI and Logging libraries (http://jakarta.apache.org),
and Sun's Java Cryptography extensions. A copy of each of these and Sun's Java Cryptography extensions. A copy of each of these
libraries is included in the distribution. Currently, these tools use libraries is included in the distribution. Currently, these tools use
a custom version of the DNSjava library (for NSEC3 support), which is a custom version of the DNSjava library with minor modifications,
provided. which is provided.
See the "licenses" directory for the licensing information of this See the "licenses" directory for the licensing information of this
package and the other packages that are distributed with it. package and the other packages that are distributed with it.
@@ -48,15 +49,15 @@ run the tools directly from the build area (without building the
jdnssec-tools.jar file) by using the ./bin/_jdnssec_* wrappers. jdnssec-tools.jar file) by using the ./bin/_jdnssec_* wrappers.
The source for this project is available in subversion, at The source for this project is available in git on github:
http://svn.verisignlabs.com/jdnssec/tools/trunk. Source for https://github.com/dblacka/jdnssec-tools
the modified DNSjava library can be found in subversion at
http://svn.verisignlabs.com/jdnssec/dnsjava/trunk.
--- Source for the modified DNSjava library can be found on github as well:
https://github.com/dblacka/jdnssec-dnsjava
---
Questions or comments may be directed to the author Questions or comments may be directed to the author
(mailto:davidb@verisign.com) or sent to the (mailto:davidb@verisign.com) or sent to the
dnssec@verisignlabs.com mailing list dnssec@verisignlabs.com mailing list
(https://lists.verisignlabs.com/mailman/listinfo/dnssec). (https://lists.verisignlabs.com/mailman/listinfo/dnssec).

View File

@@ -1 +1 @@
version=0.10.1 version=0.11

View File

@@ -28,7 +28,6 @@ import java.util.List;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
import org.xbill.DNS.DNSSEC;
import org.xbill.DNS.Name; import org.xbill.DNS.Name;
import org.xbill.DNS.RRSIGRecord; import org.xbill.DNS.RRSIGRecord;
import org.xbill.DNS.RRset; import org.xbill.DNS.RRset;
@@ -186,11 +185,11 @@ public class SignKeyset extends CLBase
// skip unsigned rrsets. // skip unsigned rrsets.
if (!rrset.sigs().hasNext()) continue; if (!rrset.sigs().hasNext()) continue;
int result = verifier.verify(rrset, null); boolean result = verifier.verify(rrset);
if (result != DNSSEC.Secure) if (!result)
{ {
log.fine("Signatures did not verify for RRset: (" + result + "): " + rrset); log.fine("Signatures did not verify for RRset: " + rrset);
secure = false; secure = false;
} }
} }

View File

@@ -28,7 +28,6 @@ import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
import org.xbill.DNS.DNSSEC;
import org.xbill.DNS.Name; import org.xbill.DNS.Name;
import org.xbill.DNS.RRSIGRecord; import org.xbill.DNS.RRSIGRecord;
import org.xbill.DNS.RRset; import org.xbill.DNS.RRset;
@@ -185,11 +184,11 @@ public class SignRRset extends CLBase
// skip unsigned rrsets. // skip unsigned rrsets.
if (!rrset.sigs().hasNext()) continue; if (!rrset.sigs().hasNext()) continue;
int result = verifier.verify(rrset, null); boolean result = verifier.verify(rrset);
if (result != DNSSEC.Secure) if (!result)
{ {
log.fine("Signatures did not verify for RRset: (" + result + "): " + rrset); log.fine("Signatures did not verify for RRset: " + rrset);
secure = false; secure = false;
} }
} }

View File

@@ -34,7 +34,6 @@ import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.ParseException;
import org.xbill.DNS.DNSKEYRecord; import org.xbill.DNS.DNSKEYRecord;
import org.xbill.DNS.DNSSEC;
import org.xbill.DNS.DSRecord; import org.xbill.DNS.DSRecord;
import org.xbill.DNS.Name; import org.xbill.DNS.Name;
import org.xbill.DNS.RRset; import org.xbill.DNS.RRset;
@@ -343,11 +342,11 @@ public class SignZone extends CLBase
// skip unsigned rrsets. // skip unsigned rrsets.
if (!rrset.sigs().hasNext()) continue; if (!rrset.sigs().hasNext()) continue;
int result = verifier.verify(rrset, null); boolean result = verifier.verify(rrset);
if (result != DNSSEC.Secure) if (!result)
{ {
log.fine("Signatures did not verify for RRset: (" + result + "): " + rrset); log.fine("Signatures did not verify for RRset: " + rrset);
secure = false; secure = false;
} }
} }

View File

@@ -48,6 +48,7 @@ public class VerifyZone extends CLBase
public int startfudge = 0; public int startfudge = 0;
public int expirefudge = 0; public int expirefudge = 0;
public boolean ignoreTime = false; public boolean ignoreTime = false;
public boolean ignoreDups = false;
public CLIState() public CLIState()
{ {
@@ -71,6 +72,10 @@ public class VerifyZone extends CLBase
OptionBuilder.withLongOpt("ignore-time"); OptionBuilder.withLongOpt("ignore-time");
OptionBuilder.withDescription("Ignore RRSIG inception and expiration time errors."); OptionBuilder.withDescription("Ignore RRSIG inception and expiration time errors.");
opts.addOption(OptionBuilder.create()); opts.addOption(OptionBuilder.create());
OptionBuilder.withLongOpt("ignore-duplicate-rrs");
OptionBuilder.withDescription("Ignore duplicate record errors.");
opts.addOption(OptionBuilder.create());
} }
protected void processOptions(CommandLine cli) protected void processOptions(CommandLine cli)
@@ -80,6 +85,11 @@ public class VerifyZone extends CLBase
ignoreTime = true; ignoreTime = true;
} }
if (cli.hasOption("ignore-duplicate-rrs"))
{
ignoreDups = true;
}
String optstr = null; String optstr = null;
if ((optstr = cli.getOptionValue('S')) != null) if ((optstr = cli.getOptionValue('S')) != null)
{ {
@@ -126,6 +136,7 @@ public class VerifyZone extends CLBase
zoneverifier.getVerifier().setStartFudge(state.startfudge); zoneverifier.getVerifier().setStartFudge(state.startfudge);
zoneverifier.getVerifier().setExpireFudge(state.expirefudge); zoneverifier.getVerifier().setExpireFudge(state.expirefudge);
zoneverifier.getVerifier().setIgnoreTime(state.ignoreTime); zoneverifier.getVerifier().setIgnoreTime(state.ignoreTime);
zoneverifier.setIgnoreDuplicateRRs(state.ignoreDups);
List<Record> records = ZoneUtils.readZoneFile(state.zonefile, null); List<Record> records = ZoneUtils.readZoneFile(state.zonefile, null);

View File

@@ -105,25 +105,25 @@ public class DnsKeyAlgorithm
mIdToMnemonicMap = new HashMap<Integer, String>(); mIdToMnemonicMap = new HashMap<Integer, String>();
// Load the standard DNSSEC algorithms. // Load the standard DNSSEC algorithms.
addAlgorithm(DNSSEC.RSAMD5, new Entry("MD5withRSA", RSA)); addAlgorithm(DNSSEC.Algorithm.RSAMD5, new Entry("MD5withRSA", RSA));
addMnemonic("RSAMD5", DNSSEC.RSAMD5); addMnemonic("RSAMD5", DNSSEC.Algorithm.RSAMD5);
addAlgorithm(DNSSEC.DH, new Entry("", DH)); addAlgorithm(DNSSEC.Algorithm.DH, new Entry("", DH));
addMnemonic("DH", DNSSEC.DH); addMnemonic("DH", DNSSEC.Algorithm.DH);
addAlgorithm(DNSSEC.DSA, new Entry("SHA1withDSA", DSA)); addAlgorithm(DNSSEC.Algorithm.DSA, new Entry("SHA1withDSA", DSA));
addMnemonic("DSA", DNSSEC.DSA); addMnemonic("DSA", DNSSEC.Algorithm.DSA);
addAlgorithm(DNSSEC.RSASHA1, new Entry("SHA1withRSA", RSA)); addAlgorithm(DNSSEC.Algorithm.RSASHA1, new Entry("SHA1withRSA", RSA));
addMnemonic("RSASHA1", DNSSEC.RSASHA1); addMnemonic("RSASHA1", DNSSEC.Algorithm.RSASHA1);
addMnemonic("RSA", DNSSEC.RSASHA1); addMnemonic("RSA", DNSSEC.Algorithm.RSASHA1);
// Load the (now) standard aliases // Load the (now) standard aliases
addAlias(DNSSEC.DSA_NSEC3_SHA1, "DSA-NSEC3-SHA1", DNSSEC.DSA); addAlias(DNSSEC.Algorithm.DSA_NSEC3_SHA1, "DSA-NSEC3-SHA1", DNSSEC.Algorithm.DSA);
addAlias(DNSSEC.RSA_NSEC3_SHA1, "RSA-NSEC3-SHA1", DNSSEC.RSASHA1); addAlias(DNSSEC.Algorithm.RSA_NSEC3_SHA1, "RSA-NSEC3-SHA1", DNSSEC.Algorithm.RSASHA1);
// Also recognize the BIND 9.6 mnemonics // Also recognize the BIND 9.6 mnemonics
addMnemonic("NSEC3DSA", DNSSEC.DSA_NSEC3_SHA1); addMnemonic("NSEC3DSA", DNSSEC.Algorithm.DSA_NSEC3_SHA1);
addMnemonic("NSEC3RSASHA1", DNSSEC.RSA_NSEC3_SHA1); addMnemonic("NSEC3RSASHA1", DNSSEC.Algorithm.RSA_NSEC3_SHA1);
// Algorithms added by RFC 5702. // Algorithms added by RFC 5702.
// NOTE: these algorithms aren't available in Java 1.4's sunprovider // NOTE: these algorithms aren't available in Java 1.4's sunprovider
@@ -221,11 +221,11 @@ public class DnsKeyAlgorithm
switch (baseType(algorithm)) switch (baseType(algorithm))
{ {
case RSA: case RSA:
return DNSSEC.RSASHA1; return DNSSEC.Algorithm.RSASHA1;
case DSA: case DSA:
return DNSSEC.DSA; return DNSSEC.Algorithm.DSA;
case DH: case DH:
return DNSSEC.DH; return DNSSEC.Algorithm.DH;
default: default:
return UNKNOWN; return UNKNOWN;
} }

View File

@@ -44,10 +44,8 @@ import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPrivateKeySpec; import javax.crypto.spec.DHPrivateKeySpec;
import org.xbill.DNS.DNSKEYRecord; import org.xbill.DNS.DNSKEYRecord;
import org.xbill.DNS.DNSSEC.DNSSECException;
import org.xbill.DNS.Name; import org.xbill.DNS.Name;
import org.xbill.DNS.Record;
import org.xbill.DNS.Type;
import org.xbill.DNS.security.KEYConverter;
import org.xbill.DNS.utils.base64; import org.xbill.DNS.utils.base64;
/** /**
@@ -98,7 +96,14 @@ public class DnsKeyConverter
pKeyRecord.getKey()); pKeyRecord.getKey());
} }
return KEYConverter.parseRecord(pKeyRecord); try
{
return pKeyRecord.getPublicKey();
}
catch (DNSSECException e)
{
throw new NoSuchAlgorithmException(e);
}
} }
/** /**
@@ -107,10 +112,16 @@ public class DnsKeyConverter
public DNSKEYRecord generateDNSKEYRecord(Name name, int dclass, long ttl, public DNSKEYRecord generateDNSKEYRecord(Name name, int dclass, long ttl,
int flags, int alg, PublicKey key) int flags, int alg, PublicKey key)
{ {
Record kr = KEYConverter.buildRecord(name, Type.DNSKEY, dclass, ttl, flags, try
DNSKEYRecord.Protocol.DNSSEC, alg, key); {
return new DNSKEYRecord(name, dclass, ttl, flags, DNSKEYRecord.Protocol.DNSSEC, alg,
return (DNSKEYRecord) kr; key);
}
catch (DNSSECException e)
{
// FIXME: this mimics the behavior of KEYConverter.buildRecord(), which would return null if the algorithm was unknown.
return null;
}
} }
// Private Key Specific Parsing routines // Private Key Specific Parsing routines

View File

@@ -333,15 +333,15 @@ public class DnsKeyPair
if (pk != null) if (pk != null)
{ {
// currently, alg 5 is the default over alg 1 (RSASHA1). // currently, alg 5 is the default over alg 1 (RSASHA1).
if (pk instanceof RSAPublicKey) return DNSSEC.RSASHA1; if (pk instanceof RSAPublicKey) return DNSSEC.Algorithm.RSASHA1;
if (pk instanceof DSAPublicKey) return DNSSEC.DSA; if (pk instanceof DSAPublicKey) return DNSSEC.Algorithm.DSA;
} }
PrivateKey priv = getPrivate(); PrivateKey priv = getPrivate();
if (priv != null) if (priv != null)
{ {
if (priv instanceof RSAPrivateKey) return DNSSEC.RSASHA1; if (priv instanceof RSAPrivateKey) return DNSSEC.Algorithm.RSASHA1;
if (priv instanceof DSAPrivateKey) return DNSSEC.DSA; if (priv instanceof DSAPrivateKey) return DNSSEC.Algorithm.DSA;
} }
return -1; return -1;

View File

@@ -43,7 +43,7 @@ import org.xbill.DNS.*;
* @author $Author$ * @author $Author$
* @version $Revision$ * @version $Revision$
*/ */
public class DnsSecVerifier implements Verifier public class DnsSecVerifier
{ {
private class TrustedKeyStore private class TrustedKeyStore
@@ -157,47 +157,19 @@ public class DnsSecVerifier implements Verifier
mIgnoreTime = v; mIgnoreTime = v;
} }
@SuppressWarnings("unchecked") private DnsKeyPair findKey(Name name, int algorithm, int footprint)
private DnsKeyPair findCachedKey(Cache cache, Name name, int algorithm, int footprint)
{ {
RRset[] keysets = cache.findAnyRecords(name, Type.KEY); return mKeyStore.find(name, algorithm, footprint);
if (keysets == null) return null;
// look for the particular key
// FIXME: this assumes that name+alg+footprint is unique.
for (Iterator<Record> i = keysets[0].rrs(); i.hasNext();)
{
Record r = i.next();
if (r.getType() != Type.DNSKEY) continue;
DNSKEYRecord keyrec = (DNSKEYRecord) r;
if (keyrec.getAlgorithm() == algorithm && keyrec.getFootprint() == footprint)
{
return new DnsKeyPair(keyrec, (PrivateKey) null);
}
}
return null;
} }
private DnsKeyPair findKey(Cache cache, Name name, int algorithm, int footprint) private boolean validateSignature(RRset rrset, RRSIGRecord sigrec, List<String> reasons)
{ {
DnsKeyPair pair = mKeyStore.find(name, algorithm, footprint); if (rrset == null || sigrec == null) return false;
if (pair == null && cache != null)
{
pair = findCachedKey(cache, name, algorithm, footprint);
}
return pair;
}
private byte validateSignature(RRset rrset, RRSIGRecord sigrec, List<String> reasons)
{
if (rrset == null || sigrec == null) return DNSSEC.Failed;
if (!rrset.getName().equals(sigrec.getName())) if (!rrset.getName().equals(sigrec.getName()))
{ {
log.fine("Signature name does not match RRset name"); log.fine("Signature name does not match RRset name");
if (reasons != null) reasons.add("Signature name does not match RRset name"); if (reasons != null) reasons.add("Signature name does not match RRset name");
return DNSSEC.Failed; return false;
} }
if (rrset.getType() != sigrec.getTypeCovered()) if (rrset.getType() != sigrec.getTypeCovered())
{ {
@@ -205,7 +177,7 @@ public class DnsSecVerifier implements Verifier
if (reasons != null) reasons.add("Signature type does not match RRset type"); if (reasons != null) reasons.add("Signature type does not match RRset type");
} }
if (mIgnoreTime) return DNSSEC.Secure; if (mIgnoreTime) return true;
Date now = new Date(); Date now = new Date();
Date start = sigrec.getTimeSigned(); Date start = sigrec.getTimeSigned();
@@ -221,7 +193,7 @@ public class DnsSecVerifier implements Verifier
{ {
log.fine("Signature is not yet valid"); log.fine("Signature is not yet valid");
if (reasons != null) reasons.add("Signature not yet valid"); if (reasons != null) reasons.add("Signature not yet valid");
return DNSSEC.Failed; return false;
} }
} }
@@ -235,39 +207,37 @@ public class DnsSecVerifier implements Verifier
{ {
log.fine("Signature has expired (now = " + now + ", sig expires = " + expire); log.fine("Signature has expired (now = " + now + ", sig expires = " + expire);
if (reasons != null) reasons.add("Signature has expired."); if (reasons != null) reasons.add("Signature has expired.");
return DNSSEC.Failed; return false;
} }
} }
return DNSSEC.Secure; return true;
} }
public byte verifySignature(RRset rrset, RRSIGRecord sigrec, Cache cache) public boolean verifySignature(RRset rrset, RRSIGRecord sigrec)
{ {
return verifySignature(rrset, sigrec, cache, null); return verifySignature(rrset, sigrec, null);
} }
/** /**
* Verify an RRset against a particular signature. * Verify an RRset against a particular signature.
* *
* @return DNSSEC.Secure if the signature verified, DNSSEC.Failed if it did * @return true if the signature verified, false if it did
* not verify (for any reason), and DNSSEC.Insecure if verification * not verify (for any reason, including not finding the DNSKEY.)
* could not be completed (usually because the public key was not
* available).
*/ */
public byte verifySignature(RRset rrset, RRSIGRecord sigrec, Cache cache, List<String> reasons) public boolean verifySignature(RRset rrset, RRSIGRecord sigrec, List<String> reasons)
{ {
byte result = validateSignature(rrset, sigrec, reasons); boolean result = validateSignature(rrset, sigrec, reasons);
if (result != DNSSEC.Secure) return result; if (!result) return result;
DnsKeyPair keypair = findKey(cache, sigrec.getSigner(), sigrec.getAlgorithm(), DnsKeyPair keypair = findKey(sigrec.getSigner(), sigrec.getAlgorithm(),
sigrec.getFootprint()); sigrec.getFootprint());
if (keypair == null) if (keypair == null)
{ {
if (reasons != null) reasons.add("Could not find matching trusted key"); if (reasons != null) reasons.add("Could not find matching trusted key");
log.fine("could not find matching trusted key"); log.fine("could not find matching trusted key");
return DNSSEC.Insecure; return false;
} }
try try
@@ -290,10 +260,10 @@ public class DnsSecVerifier implements Verifier
{ {
if (reasons != null) reasons.add("Signature failed to verify cryptographically"); if (reasons != null) reasons.add("Signature failed to verify cryptographically");
log.fine("Signature failed to verify cryptographically"); log.fine("Signature failed to verify cryptographically");
return DNSSEC.Failed; return false;
} }
return DNSSEC.Secure; return true;
} }
catch (IOException e) catch (IOException e)
{ {
@@ -305,39 +275,38 @@ public class DnsSecVerifier implements Verifier
} }
if (reasons != null) reasons.add("Signature failed to verify due to exception"); if (reasons != null) reasons.add("Signature failed to verify due to exception");
log.fine("Signature failed to verify due to exception"); log.fine("Signature failed to verify due to exception");
return DNSSEC.Insecure; return false;
} }
/** /**
* Verifies an RRset. This routine does not modify the RRset. * Verifies an RRset. This routine does not modify the RRset.
* *
* @return DNSSEC.Secure if the set verified, DNSSEC.Failed if it did not, and * @return true if the set verified, false if it did not.
* DNSSEC.Insecure if verification could not complete.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public int verify(RRset rrset, Cache cache) public boolean verify(RRset rrset)
{ {
int result = mVerifyAllSigs ? DNSSEC.Secure : DNSSEC.Insecure; boolean result = mVerifyAllSigs ? true : false;
Iterator i = rrset.sigs(); Iterator i = rrset.sigs();
if (!i.hasNext()) if (!i.hasNext())
{ {
log.fine("RRset failed to verify due to lack of signatures"); log.fine("RRset failed to verify due to lack of signatures");
return DNSSEC.Insecure; return false;
} }
while (i.hasNext()) while (i.hasNext())
{ {
RRSIGRecord sigrec = (RRSIGRecord) i.next(); RRSIGRecord sigrec = (RRSIGRecord) i.next();
byte res = verifySignature(rrset, sigrec, cache); boolean res = verifySignature(rrset, sigrec);
if (!mVerifyAllSigs && res == DNSSEC.Secure) return res; // If not requiring all signature to validate, then any successful validation is sufficient.
if (!mVerifyAllSigs && res) return res;
if (!mVerifyAllSigs && res < result) result = res; // Otherwise, note if a signature failed to validate.
if (mVerifyAllSigs && !res)
if (mVerifyAllSigs && res != DNSSEC.Secure && res < result)
{ {
result = res; result = res;
} }

View File

@@ -45,7 +45,7 @@ import org.xbill.DNS.utils.base32;
public class ProtoNSEC3 public class ProtoNSEC3
{ {
private Name originalOwner; private Name originalOwner;
private byte hashAlg; private int hashAlg;
private byte flags; private byte flags;
private int iterations; private int iterations;
private byte[] salt; private byte[] salt;
@@ -63,7 +63,7 @@ public class ProtoNSEC3
* Creates an NSEC3 Record from the given data. * Creates an NSEC3 Record from the given data.
*/ */
public ProtoNSEC3(byte[] owner, Name originalOwner, Name zone, int dclass, long ttl, public ProtoNSEC3(byte[] owner, Name originalOwner, Name zone, int dclass, long ttl,
byte hashAlg, byte flags, int iterations, byte[] salt, byte[] next, int hashAlg, byte flags, int iterations, byte[] salt, byte[] next,
TypeMap typemap) TypeMap typemap)
{ {
this.zone = zone; this.zone = zone;
@@ -80,7 +80,7 @@ public class ProtoNSEC3
} }
public ProtoNSEC3(byte[] owner, Name originalOwner, Name zone, int dclass, long ttl, public ProtoNSEC3(byte[] owner, Name originalOwner, Name zone, int dclass, long ttl,
byte hashAlg, byte flags, int iterations, byte[] salt, byte[] next, int hashAlg, byte flags, int iterations, byte[] salt, byte[] next,
int[] types) int[] types)
{ {
this(owner, originalOwner, zone, dclass, ttl, hashAlg, flags, iterations, salt, next, this(owner, originalOwner, zone, dclass, ttl, hashAlg, flags, iterations, salt, next,
@@ -168,7 +168,7 @@ public class ProtoNSEC3
return dclass; return dclass;
} }
public byte getHashAlgorithm() public int getHashAlgorithm()
{ {
return hashAlg; return hashAlg;
} }

View File

@@ -1040,7 +1040,7 @@ public class SignUtils
{ {
byte[] hash = nsec3hash(name, NSEC3Record.SHA1_DIGEST_ID, iterations, salt); byte[] hash = nsec3hash(name, NSEC3Record.SHA1_DIGEST_ID, iterations, salt);
byte flags = (byte) (optIn ? 0x01 : 0x00); byte flags = (byte) (optIn ? 0x01 : 0x00);
ProtoNSEC3 r = new ProtoNSEC3(hash, name, zonename, DClass.IN, ttl, ProtoNSEC3 r = new ProtoNSEC3(hash, name, zonename, DClass.IN, ttl,
NSEC3Record.SHA1_DIGEST_ID, flags, iterations, salt, NSEC3Record.SHA1_DIGEST_ID, flags, iterations, salt,
null, types); null, types);
@@ -1430,7 +1430,7 @@ public class SignUtils
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
* If the hash algorithm is unrecognized. * If the hash algorithm is unrecognized.
*/ */
public static byte[] nsec3hash(Name n, byte hash_algorithm, int iterations, byte[] salt) public static byte[] nsec3hash(Name n, int hash_algorithm, int iterations, byte[] salt)
throws NoSuchAlgorithmException throws NoSuchAlgorithmException
{ {
MessageDigest md; MessageDigest md;

View File

@@ -33,7 +33,6 @@ import java.util.TreeMap;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.xbill.DNS.DNSKEYRecord; import org.xbill.DNS.DNSKEYRecord;
import org.xbill.DNS.DNSSEC;
import org.xbill.DNS.NSEC3PARAMRecord; import org.xbill.DNS.NSEC3PARAMRecord;
import org.xbill.DNS.NSEC3Record; import org.xbill.DNS.NSEC3Record;
import org.xbill.DNS.NSECRecord; import org.xbill.DNS.NSECRecord;
@@ -49,7 +48,7 @@ import org.xbill.DNS.utils.base32;
* A class for whole zone DNSSEC verification. Along with cryptographically * A class for whole zone DNSSEC verification. Along with cryptographically
* verifying signatures, this class will also detect invalid NSEC and NSEC3 * verifying signatures, this class will also detect invalid NSEC and NSEC3
* chains. * chains.
* *
* @author David Blacka (original) * @author David Blacka (original)
* @author $Author: davidb $ * @author $Author: davidb $
* @version $Revision: 172 $ * @version $Revision: 172 $
@@ -64,6 +63,7 @@ public class ZoneVerifier
private Name mZoneName; private Name mZoneName;
private DNSSECType mDNSSECType; private DNSSECType mDNSSECType;
private NSEC3PARAMRecord mNSEC3params; private NSEC3PARAMRecord mNSEC3params;
private boolean mIgnoreDuplicateRRs;
private DnsSecVerifier mVerifier; private DnsSecVerifier mVerifier;
private base32 mBase32; private base32 mBase32;
@@ -108,22 +108,48 @@ public class ZoneVerifier
mVerifier = new DnsSecVerifier(); mVerifier = new DnsSecVerifier();
mBase32 = new base32(base32.Alphabet.BASE32HEX, false, true); mBase32 = new base32(base32.Alphabet.BASE32HEX, false, true);
mBAcmp = new ByteArrayComparator(); mBAcmp = new ByteArrayComparator();
mIgnoreDuplicateRRs = false;
} }
/** @return the DnsSecVerifier object used to verify individual RRsets. */
public DnsSecVerifier getVerifier() public DnsSecVerifier getVerifier()
{ {
return mVerifier; return mVerifier;
} }
public void setIgnoreDuplicateRRs(boolean value)
{
mIgnoreDuplicateRRs = value;
}
private static String key(Name n, int type) private static String key(Name n, int type)
{ {
return n.toString() + ':' + type; return n.toString() + ':' + type;
} }
@SuppressWarnings("rawtypes")
private boolean addRRtoRRset(RRset rrset, Record rr)
{
if (mIgnoreDuplicateRRs)
{
rrset.addRR(rr);
return true;
}
for (Iterator i = rrset.rrs(); i.hasNext(); )
{
Record record = (Record) i.next();
if (rr.equals(record)) return false;
}
rrset.addRR(rr);
return true;
}
/** /**
* Add a record to the various maps. * Add a record to the various maps.
* @return TODO
*/ */
private void addRR(Record r) private boolean addRR(Record r)
{ {
Name r_name = r.getName(); Name r_name = r.getName();
int r_type = r.getType(); int r_type = r.getType();
@@ -139,8 +165,8 @@ public class ZoneVerifier
rrset = new MarkRRset(); rrset = new MarkRRset();
mNSECMap.put(r_name, rrset); mNSECMap.put(r_name, rrset);
} }
rrset.addRR(r);
return; return addRRtoRRset(rrset, r);
} }
if (r_type == Type.NSEC3) if (r_type == Type.NSEC3)
@@ -152,8 +178,8 @@ public class ZoneVerifier
rrset = new MarkRRset(); rrset = new MarkRRset();
mNSEC3Map.put(r_name, rrset); mNSEC3Map.put(r_name, rrset);
} }
rrset.addRR(r);
return; return addRRtoRRset(rrset, r);
} }
// Add the name and type to the node map // Add the name and type to the node map
@@ -173,7 +199,7 @@ public class ZoneVerifier
rrset = new RRset(); rrset = new RRset();
mRRsetMap.put(k, rrset); mRRsetMap.put(k, rrset);
} }
rrset.addRR(r); return addRRtoRRset(rrset, r);
} }
/** /**
@@ -199,10 +225,11 @@ public class ZoneVerifier
/** /**
* Given an unsorted list of records, load the node and rrset maps, as well as * Given an unsorted list of records, load the node and rrset maps, as well as
* determine the NSEC3 parameters and signing type. * determine the NSEC3 parameters and signing type.
* *
* @param records * @param records
* @return TODO
*/ */
private void calculateNodes(List<Record> records) private int calculateNodes(List<Record> records)
{ {
mNodeMap = new TreeMap<Name, Set<Integer>>(); mNodeMap = new TreeMap<Name, Set<Integer>>();
mRRsetMap = new HashMap<String, RRset>(); mRRsetMap = new HashMap<String, RRset>();
@@ -210,13 +237,19 @@ public class ZoneVerifier
// The zone is unsigned until we get a clue otherwise. // The zone is unsigned until we get a clue otherwise.
mDNSSECType = DNSSECType.UNSIGNED; mDNSSECType = DNSSECType.UNSIGNED;
int errors = 0;
for (Record r : records) for (Record r : records)
{ {
Name r_name = r.getName(); Name r_name = r.getName();
int r_type = r.getType(); int r_type = r.getType();
// Add the record to the various maps. // Add the record to the various maps.
addRR(r); boolean res = addRR(r);
if (!res)
{
log.warning("Record '" + r + "' detected as a duplicate");
errors++;
}
// Learn some things about the zone as we do this pass. // Learn some things about the zone as we do this pass.
if (r_type == Type.SOA) mZoneName = r_name; if (r_type == Type.SOA) mZoneName = r_name;
@@ -230,6 +263,8 @@ public class ZoneVerifier
if (mDNSSECType == DNSSECType.UNSIGNED) mDNSSECType = determineDNSSECType(r); if (mDNSSECType == DNSSECType.UNSIGNED) mDNSSECType = determineDNSSECType(r);
} }
return errors;
} }
/** /**
@@ -291,7 +326,7 @@ public class ZoneVerifier
last_cut = n; last_cut = n;
} }
// check all of the RRset that should be signed // check all of the RRsets that should be signed
for (int type : typeset) for (int type : typeset)
{ {
if (type == Type.RRSIG) continue; if (type == Type.RRSIG) continue;
@@ -354,24 +389,24 @@ public class ZoneVerifier
private int processRRset(RRset rrset) private int processRRset(RRset rrset)
{ {
List<String> reasons = new ArrayList<String>(); List<String> reasons = new ArrayList<String>();
int result = DNSSEC.Failed; boolean result = false;
for (Iterator<Record> i = rrset.sigs(); i.hasNext();) for (Iterator<Record> i = rrset.sigs(); i.hasNext();)
{ {
RRSIGRecord sigrec = (RRSIGRecord) i.next(); RRSIGRecord sigrec = (RRSIGRecord) i.next();
byte res = mVerifier.verifySignature(rrset, sigrec, null, reasons); boolean res = mVerifier.verifySignature(rrset, sigrec, reasons);
if (res != DNSSEC.Secure) if (!res)
{ {
log.warning("Signature failed to verify RRset:\n rr: " log.warning("Signature failed to verify RRset:\n rr: "
+ ZoneUtils.rrsetToString(rrset, false) + "\n sig: " + sigrec + "\n" + ZoneUtils.rrsetToString(rrset, false) + "\n sig: " + sigrec + "\n"
+ reasonListToString(reasons)); + reasonListToString(reasons));
} }
if (res > result) result = res; if (res) result = res;
} }
String rrsetname = rrset.getName() + "/" + Type.string(rrset.getType()); String rrsetname = rrset.getName() + "/" + Type.string(rrset.getType());
if (result == DNSSEC.Secure) if (result)
{ {
log.fine("RRset " + rrsetname + " verified."); log.fine("RRset " + rrsetname + " verified.");
} }
@@ -380,7 +415,7 @@ public class ZoneVerifier
log.warning("RRset " + rrsetname + " did not verify."); log.warning("RRset " + rrsetname + " did not verify.");
} }
return result == DNSSEC.Secure ? 0 : 1; return result ? 0 : 1;
} }
private String typesToString(int[] types) private String typesToString(int[] types)
@@ -710,9 +745,9 @@ public class ZoneVerifier
{ {
int errors = 0; int errors = 0;
calculateNodes(records); errors += calculateNodes(records);
errors = processNodes(); errors += processNodes();
if (mDNSSECType == DNSSECType.NSEC) if (mDNSSECType == DNSSECType.NSEC)
{ {