Add options for fudging or ignoring times in verifyzone.
git-svn-id: https://svn.verisignlabs.com/jdnssec/tools/trunk@224 4cbd57fe-54e5-0310-bd9a-f30fe5ea5e6e
This commit is contained in:
parent
3d6b21b0fc
commit
86072cbcc8
@ -1,3 +1,8 @@
|
||||
2010-12-14 Blacka <davidb@verisignlabs.com>
|
||||
|
||||
* jdnssec-verifyzone: Add options to either fudge or ignore RRSIG
|
||||
inception and expiration times.
|
||||
|
||||
2010-12-06 David Blacka <davidb@verisignlabs.com>
|
||||
|
||||
* jdnssec-verifyzone: Complete refactored the verification code to
|
||||
|
@ -50,7 +50,8 @@ public class VerifyZone
|
||||
{
|
||||
private static Logger log;
|
||||
|
||||
// A log formatter that strips away all of the noise that the default SimpleFormatter has
|
||||
// A log formatter that strips away all of the noise that the default
|
||||
// SimpleFormatter has
|
||||
private static class MyLogFormatter extends java.util.logging.Formatter
|
||||
{
|
||||
@Override
|
||||
@ -58,7 +59,7 @@ public class VerifyZone
|
||||
{
|
||||
StringBuilder out = new StringBuilder();
|
||||
String lvl = arg0.getLevel().getName();
|
||||
|
||||
|
||||
out.append(lvl);
|
||||
out.append(": ");
|
||||
out.append(arg0.getMessage());
|
||||
@ -75,10 +76,11 @@ public class VerifyZone
|
||||
private static class CLIState
|
||||
{
|
||||
private Options opts;
|
||||
// public boolean strict = false;
|
||||
// public File keydir = null;
|
||||
public String zonefile = null;
|
||||
public String[] keyfiles = null;
|
||||
public String zonefile = null;
|
||||
public String[] keyfiles = null;
|
||||
public int startfudge = 0;
|
||||
public int expirefudge = 0;
|
||||
public boolean ignoreTime = false;
|
||||
|
||||
public CLIState()
|
||||
{
|
||||
@ -102,7 +104,7 @@ public class VerifyZone
|
||||
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.");
|
||||
+ "5 is debug information, 6 is trace information. default is level 5.");
|
||||
opts.addOption(OptionBuilder.create('v'));
|
||||
|
||||
OptionBuilder.hasArg();
|
||||
@ -110,6 +112,22 @@ public class VerifyZone
|
||||
OptionBuilder.withLongOpt("alg-alias");
|
||||
OptionBuilder.withDescription("Define an alias for an algorithm");
|
||||
opts.addOption(OptionBuilder.create('A'));
|
||||
|
||||
OptionBuilder.hasOptionalArg();
|
||||
OptionBuilder.withLongOpt("sig-start-fudge");
|
||||
OptionBuilder.withArgName("seconds");
|
||||
OptionBuilder.withDescription("'fudge' RRSIG inception times by 'seconds' seconds.");
|
||||
opts.addOption(OptionBuilder.create('S'));
|
||||
|
||||
OptionBuilder.hasOptionalArg();
|
||||
OptionBuilder.withLongOpt("sig-expire-fudge");
|
||||
OptionBuilder.withArgName("seconds");
|
||||
OptionBuilder.withDescription("'fudge' RRSIG expiration times by 'seconds' seconds.");
|
||||
opts.addOption(OptionBuilder.create('E'));
|
||||
|
||||
OptionBuilder.withLongOpt("ignore-time");
|
||||
OptionBuilder.withDescription("Ignore RRSIG inception and expiration time errors.");
|
||||
opts.addOption(OptionBuilder.create());
|
||||
}
|
||||
|
||||
public void parseCommandLine(String[] args)
|
||||
@ -153,6 +171,22 @@ public class VerifyZone
|
||||
org.xbill.DNS.Options.set("multiline");
|
||||
}
|
||||
|
||||
if (cli.hasOption("ignore-time"))
|
||||
{
|
||||
ignoreTime = true;
|
||||
}
|
||||
|
||||
String optstr = null;
|
||||
if ((optstr = cli.getOptionValue('S')) != null)
|
||||
{
|
||||
startfudge = parseInt(optstr, 0);
|
||||
}
|
||||
|
||||
if ((optstr = cli.getOptionValue('E')) != null)
|
||||
{
|
||||
expirefudge = parseInt(optstr, 0);
|
||||
}
|
||||
|
||||
String[] optstrs = null;
|
||||
if ((optstrs = cli.getOptionValues('A')) != null)
|
||||
{
|
||||
@ -207,7 +241,8 @@ public class VerifyZone
|
||||
|
||||
// print our own usage statement:
|
||||
f.printHelp(out, 75, "jdnssec-verifyzone [..options..] zonefile "
|
||||
+ "[keyfile [keyfile...]]", null, opts, HelpFormatter.DEFAULT_LEFT_PAD,
|
||||
+ "[keyfile [keyfile...]]", null, opts,
|
||||
HelpFormatter.DEFAULT_LEFT_PAD,
|
||||
HelpFormatter.DEFAULT_DESC_PAD, null);
|
||||
|
||||
out.flush();
|
||||
@ -242,6 +277,9 @@ public class VerifyZone
|
||||
public static void execute(CLIState state) throws Exception
|
||||
{
|
||||
ZoneVerifier zoneverifier = new ZoneVerifier();
|
||||
zoneverifier.getVerifier().setStartFudge(state.startfudge);
|
||||
zoneverifier.getVerifier().setExpireFudge(state.expirefudge);
|
||||
zoneverifier.getVerifier().setIgnoreTime(state.ignoreTime);
|
||||
|
||||
List records = ZoneUtils.readZoneFile(state.zonefile, null);
|
||||
|
||||
|
@ -94,8 +94,7 @@ public class DnsSecVerifier implements Verifier
|
||||
for (Iterator i = l.iterator(); i.hasNext();)
|
||||
{
|
||||
DnsKeyPair p = (DnsKeyPair) i.next();
|
||||
if (p.getDNSKEYAlgorithm() == algorithm
|
||||
&& p.getDNSKEYFootprint() == keyid)
|
||||
if (p.getDNSKEYAlgorithm() == algorithm && p.getDNSKEYFootprint() == keyid)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
@ -108,6 +107,7 @@ public class DnsSecVerifier implements Verifier
|
||||
private int mStartFudge = 0;
|
||||
private int mExpireFudge = 0;
|
||||
private boolean mVerifyAllSigs = false;
|
||||
private boolean mIgnoreTime = false;
|
||||
|
||||
private Logger log;
|
||||
|
||||
@ -153,8 +153,12 @@ public class DnsSecVerifier implements Verifier
|
||||
mVerifyAllSigs = v;
|
||||
}
|
||||
|
||||
private DnsKeyPair findCachedKey(Cache cache, Name name, int algorithm,
|
||||
int footprint)
|
||||
public void setIgnoreTime(boolean v)
|
||||
{
|
||||
mIgnoreTime = v;
|
||||
}
|
||||
|
||||
private DnsKeyPair findCachedKey(Cache cache, Name name, int algorithm, int footprint)
|
||||
{
|
||||
RRset[] keysets = cache.findAnyRecords(name, Type.KEY);
|
||||
if (keysets == null) return null;
|
||||
@ -166,8 +170,7 @@ public class DnsSecVerifier implements Verifier
|
||||
Object o = i.next();
|
||||
if (!(o instanceof DNSKEYRecord)) continue;
|
||||
DNSKEYRecord keyrec = (DNSKEYRecord) o;
|
||||
if (keyrec.getAlgorithm() == algorithm
|
||||
&& keyrec.getFootprint() == footprint)
|
||||
if (keyrec.getAlgorithm() == algorithm && keyrec.getFootprint() == footprint)
|
||||
{
|
||||
return new DnsKeyPair(keyrec, (PrivateKey) null);
|
||||
}
|
||||
@ -176,8 +179,7 @@ public class DnsSecVerifier implements Verifier
|
||||
return null;
|
||||
}
|
||||
|
||||
private DnsKeyPair findKey(Cache cache, Name name, int algorithm,
|
||||
int footprint)
|
||||
private DnsKeyPair findKey(Cache cache, Name name, int algorithm, int footprint)
|
||||
{
|
||||
DnsKeyPair pair = mKeyStore.find(name, algorithm, footprint);
|
||||
if (pair == null && cache != null)
|
||||
@ -194,17 +196,17 @@ public class DnsSecVerifier implements Verifier
|
||||
if (!rrset.getName().equals(sigrec.getName()))
|
||||
{
|
||||
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;
|
||||
}
|
||||
if (rrset.getType() != sigrec.getTypeCovered())
|
||||
{
|
||||
log.fine("Signature type does not match RRset type");
|
||||
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;
|
||||
|
||||
Date now = new Date();
|
||||
Date start = sigrec.getTimeSigned();
|
||||
Date expire = sigrec.getExpire();
|
||||
@ -231,8 +233,7 @@ public class DnsSecVerifier implements Verifier
|
||||
}
|
||||
if (now.after(expire))
|
||||
{
|
||||
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.");
|
||||
return DNSSEC.Failed;
|
||||
}
|
||||
@ -254,14 +255,13 @@ public class DnsSecVerifier implements Verifier
|
||||
* could not be completed (usually because the public key was not
|
||||
* available).
|
||||
*/
|
||||
public byte verifySignature(RRset rrset, RRSIGRecord sigrec, Cache cache,
|
||||
List reasons)
|
||||
public byte verifySignature(RRset rrset, RRSIGRecord sigrec, Cache cache, List reasons)
|
||||
{
|
||||
byte result = validateSignature(rrset, sigrec, reasons);
|
||||
if (result != DNSSEC.Secure) return result;
|
||||
|
||||
DnsKeyPair keypair = findKey(cache, sigrec.getSigner(), sigrec
|
||||
.getAlgorithm(), sigrec.getFootprint());
|
||||
DnsKeyPair keypair = findKey(cache, sigrec.getSigner(), sigrec.getAlgorithm(),
|
||||
sigrec.getFootprint());
|
||||
|
||||
if (keypair == null)
|
||||
{
|
||||
@ -288,8 +288,7 @@ public class DnsSecVerifier implements Verifier
|
||||
|
||||
if (!signer.verify(sig))
|
||||
{
|
||||
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");
|
||||
return DNSSEC.Failed;
|
||||
}
|
||||
@ -304,8 +303,7 @@ public class DnsSecVerifier implements Verifier
|
||||
{
|
||||
log.severe("Security error: " + e);
|
||||
}
|
||||
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");
|
||||
return DNSSEC.Insecure;
|
||||
}
|
||||
|
@ -110,6 +110,11 @@ public class ZoneVerifier
|
||||
mBAcmp = new ByteArrayComparator();
|
||||
}
|
||||
|
||||
public DnsSecVerifier getVerifier()
|
||||
{
|
||||
return mVerifier;
|
||||
}
|
||||
|
||||
private static String key(Name n, int type)
|
||||
{
|
||||
return n.toString() + ':' + type;
|
||||
@ -231,7 +236,8 @@ public class ZoneVerifier
|
||||
// All RRs at the zone apex are normal
|
||||
if (n.equals(mZoneName)) return NodeType.NORMAL;
|
||||
|
||||
// If the node is below a zone cut (either a delegation or DNAME), it is glue.
|
||||
// If the node is below a zone cut (either a delegation or DNAME), it is
|
||||
// glue.
|
||||
if (last_cut != null && n.subdomain(last_cut) && !n.equals(last_cut))
|
||||
{
|
||||
return NodeType.GLUE;
|
||||
@ -284,7 +290,8 @@ public class ZoneVerifier
|
||||
for (int type : typeset)
|
||||
{
|
||||
if (type == Type.RRSIG) continue;
|
||||
// at delegation points, only DS RRs are signed (and NSEC, but those are checked separately)
|
||||
// at delegation points, only DS RRs are signed (and NSEC, but those are
|
||||
// checked separately)
|
||||
if (ntype == NodeType.DELEGATION && type != Type.DS) continue;
|
||||
// otherwise, verify the RRset.
|
||||
String k = key(n, type);
|
||||
@ -370,22 +377,6 @@ public class ZoneVerifier
|
||||
return result == DNSSEC.Secure ? 0 : 1;
|
||||
}
|
||||
|
||||
private String typesetToString(Set<Integer> typeset)
|
||||
{
|
||||
if (typeset == null) return "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (int type : typeset)
|
||||
{
|
||||
if (!first) sb.append(' ');
|
||||
sb.append(Type.string(type));
|
||||
first = false;
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String typesToString(int[] types)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@ -400,9 +391,23 @@ public class ZoneVerifier
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String typesetToString(Set<Integer> typeset)
|
||||
{
|
||||
if (typeset == null) return "";
|
||||
|
||||
int[] types = new int[typeset.size()];
|
||||
int i = 0;
|
||||
for (int type : typeset)
|
||||
{
|
||||
types[i++] = type;
|
||||
}
|
||||
return typesToString(types);
|
||||
}
|
||||
|
||||
private boolean checkTypeMap(Set<Integer> typeset, int[] types)
|
||||
{
|
||||
// a null typeset means that we are expecting the typemap of an ENT, which should be empty.
|
||||
// a null typeset means that we are expecting the typemap of an ENT, which
|
||||
// should be empty.
|
||||
if (typeset == null) return types.length == 0;
|
||||
|
||||
Set compareTypeset = new HashSet();
|
||||
@ -446,7 +451,8 @@ public class ZoneVerifier
|
||||
|
||||
private boolean shouldCheckENTs(Name n, Set<Integer> typeset, NodeType ntype)
|
||||
{
|
||||
// if we are just one (or zero) labels longer than the zonename, the node can't create a ENT
|
||||
// if we are just one (or zero) labels longer than the zonename, the node
|
||||
// can't create a ENT
|
||||
if (n.labels() <= mZoneName.labels() + 1) return false;
|
||||
|
||||
// we probably won't ever get called for a GLUE node
|
||||
@ -455,7 +461,8 @@ public class ZoneVerifier
|
||||
// if we aren't doing opt-out, then all possible ENTs must be checked.
|
||||
if (mDNSSECType == DNSSECType.NSEC3) return true;
|
||||
|
||||
// if we are opt-out, and the node is an insecure delegation, don't check ENTs.
|
||||
// if we are opt-out, and the node is an insecure delegation, don't check
|
||||
// ENTs.
|
||||
if (ntype == NodeType.DELEGATION && !typeset.contains(Type.DS))
|
||||
{
|
||||
return false;
|
||||
@ -492,7 +499,7 @@ public class ZoneVerifier
|
||||
{
|
||||
log.warning("Typemap for NSEC3 RR " + hashname + " for " + n
|
||||
+ " did not match what was expected. Expected '" + typesetToString(typeset)
|
||||
+ "', got '" + typesToString(nsec3.getTypes()));
|
||||
+ "', got '" + typesToString(nsec3.getTypes()) + "'");
|
||||
errors++;
|
||||
}
|
||||
|
||||
@ -520,7 +527,8 @@ public class ZoneVerifier
|
||||
|
||||
for (Iterator<Map.Entry<Name, MarkRRset>> i = mNSECMap.entrySet().iterator(); i.hasNext();)
|
||||
{
|
||||
// check the internal ordering of the previous NSEC record. This avoids looking at the last one,
|
||||
// check the internal ordering of the previous NSEC record. This avoids
|
||||
// looking at the last one,
|
||||
// which is different.
|
||||
if (lastNSEC != null)
|
||||
{
|
||||
@ -536,7 +544,8 @@ public class ZoneVerifier
|
||||
Name n = entry.getKey();
|
||||
MarkRRset rrset = entry.getValue();
|
||||
|
||||
// check to see if the NSEC is marked. If not, it was not correlated to a signed node.
|
||||
// check to see if the NSEC is marked. If not, it was not correlated to a
|
||||
// signed node.
|
||||
if (!rrset.getMark())
|
||||
{
|
||||
log.warning("NSEC RR for " + n + " appears to be extra.");
|
||||
@ -545,7 +554,8 @@ public class ZoneVerifier
|
||||
|
||||
NSECRecord nsec = (NSECRecord) rrset.first();
|
||||
|
||||
// This is just a sanity check. If this isn't true, we are constructing the
|
||||
// This is just a sanity check. If this isn't true, we are constructing
|
||||
// the
|
||||
// nsec map incorrectly.
|
||||
if (!n.equals(nsec.getName()))
|
||||
{
|
||||
@ -553,7 +563,8 @@ public class ZoneVerifier
|
||||
errors++;
|
||||
}
|
||||
|
||||
// If this is the first row, ensure that the owner name equals the zone name
|
||||
// If this is the first row, ensure that the owner name equals the zone
|
||||
// name
|
||||
if (lastNSEC == null && !n.equals(mZoneName))
|
||||
{
|
||||
log.warning("The first NSEC in the chain does not match the zone name: name = "
|
||||
@ -611,7 +622,8 @@ public class ZoneVerifier
|
||||
|
||||
for (Iterator<Map.Entry<Name, MarkRRset>> i = mNSEC3Map.entrySet().iterator(); i.hasNext();)
|
||||
{
|
||||
// check the internal ordering of the previous NSEC3 record. This avoids looking at the last one,
|
||||
// check the internal ordering of the previous NSEC3 record. This avoids
|
||||
// looking at the last one,
|
||||
// which is different.
|
||||
if (lastNSEC3 != null)
|
||||
{
|
||||
@ -627,7 +639,8 @@ public class ZoneVerifier
|
||||
Name n = entry.getKey();
|
||||
MarkRRset rrset = entry.getValue();
|
||||
|
||||
// check to see if the NSEC is marked. If not, it was not correlated to a signed node.
|
||||
// check to see if the NSEC is marked. If not, it was not correlated to a
|
||||
// signed node.
|
||||
if (!rrset.getMark())
|
||||
{
|
||||
log.warning("NSEC3 RR for " + n + " appears to be extra.");
|
||||
@ -636,7 +649,8 @@ public class ZoneVerifier
|
||||
|
||||
NSEC3Record nsec3 = (NSEC3Record) rrset.first();
|
||||
|
||||
// This is just a sanity check. If this isn't true, we are constructing the
|
||||
// This is just a sanity check. If this isn't true, we are constructing
|
||||
// the
|
||||
// nsec3 map incorrectly.
|
||||
if (!n.equals(nsec3.getName()))
|
||||
{
|
||||
@ -650,7 +664,8 @@ public class ZoneVerifier
|
||||
firstNSEC3 = nsec3;
|
||||
}
|
||||
else
|
||||
// Check that the prior NSEC3's next hashed name equals this row's hashed owner name.
|
||||
// Check that the prior NSEC3's next hashed name equals this row's hashed
|
||||
// owner name.
|
||||
{
|
||||
if (compareNSEC3Hashes(nsec3.getName(), lastNSEC3.getNext()) != 0)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user