/*
* dnssecjava - a DNSSEC validating stub resolver for Java
* Copyright (c) 2013-2015 Ingo Bauersachs
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.jitsi.dnssec.validator;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import org.jitsi.dnssec.SMessage;
import org.jitsi.dnssec.SecurityStatus;
import org.jitsi.dnssec.TestBase;
import org.junit.Test;
import org.xbill.DNS.DClass;
import org.xbill.DNS.Flags;
import org.xbill.DNS.Message;
import org.xbill.DNS.NSECRecord;
import org.xbill.DNS.Name;
import org.xbill.DNS.RRset;
import org.xbill.DNS.Rcode;
import org.xbill.DNS.Record;
import org.xbill.DNS.Section;
import org.xbill.DNS.Type;
public class TestValUtils extends TestBase {
@Test
public void testLongestCommonNameRootIsRoot() {
assertEquals(Name.root, ValUtils.longestCommonName(Name.fromConstantString("example.com."), Name.fromConstantString("example.net.")));
}
@Test
public void testNoDataWhenResultIsFromDelegationPoint() throws IOException {
Message nsec = resolver.send(createMessage("t.ingotronic.ch./A"));
Record delegationNsec = null;
Record delegationNsecSig = null;
for (RRset set : nsec.getSectionRRsets(Section.AUTHORITY)) {
if (set.getName().toString().startsWith("sub.ingotronic.ch")) {
delegationNsec = set.first();
delegationNsecSig = (Record)set.sigs().next();
break;
}
}
Message m = resolver.send(createMessage("sub.ingotronic.ch./MX"));
Message message = messageFromString(m.toString().replaceAll("sub\\.ingotronic\\.ch\\.\\s+\\d+.*", ""));
message.addRecord(delegationNsec, Section.AUTHORITY);
message.addRecord(delegationNsecSig, Section.AUTHORITY);
add("sub.ingotronic.ch./MX", message);
Message response = resolver.send(createMessage("sub.ingotronic.ch./MX"));
assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.SERVFAIL, response.getRcode());
assertEquals("failed.nodata", getReason(response));
}
@Test
public void testNameErrorWhenResultIsFromDelegationPoint() throws IOException {
Message nsec = resolver.send(createMessage("sub1.ingotronic.ch./NSEC"));
Record delegationNsec = null;
Record delegationNsecSig = null;
for (RRset set : nsec.getSectionRRsets(Section.AUTHORITY)) {
if (set.getName().toString().startsWith("sub.ingotronic.ch")) {
delegationNsec = set.first();
delegationNsecSig = (Record)set.sigs().next();
break;
}
}
Message m = createMessage("s.sub.ingotronic.ch./A");
m.getHeader().setRcode(Rcode.NXDOMAIN);
m.addRecord(delegationNsec, Section.AUTHORITY);
m.addRecord(delegationNsecSig, Section.AUTHORITY);
add("s.sub.ingotronic.ch./A", m);
Message response = resolver.send(createMessage("s.sub.ingotronic.ch./A"));
assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.SERVFAIL, response.getRcode());
assertEquals("failed.nxdomain.exists:s.sub.ingotronic.ch.", getReason(response));
}
@Test
public void testNameErrorWhenNsecIsNotFromApex() throws IOException {
Message response = resolver.send(createMessage("1.www.ingotronic.ch./A"));
assertTrue("AD flag must be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.NXDOMAIN, response.getRcode());
assertNull(getReason(response));
}
@Test
public void testNameErrorWhenNsecIsLastAndQnameBefore() throws IOException {
Message nsec = resolver.send(createMessage("zz.ingotronic.ch./NSEC"));
Record delegationNsec = null;
Record delegationNsecSig = null;
for (RRset set : nsec.getSectionRRsets(Section.AUTHORITY)) {
if (set.getName().toString().startsWith("z.ingotronic.ch")) {
delegationNsec = set.first();
delegationNsecSig = (Record)set.sigs().next();
break;
}
}
Message m = createMessage("y.ingotronic.ch./A");
m.getHeader().setRcode(Rcode.NXDOMAIN);
m.addRecord(delegationNsec, Section.AUTHORITY);
m.addRecord(delegationNsecSig, Section.AUTHORITY);
add("y.ingotronic.ch./A", m);
Message response = resolver.send(createMessage("y.ingotronic.ch./A"));
assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.SERVFAIL, response.getRcode());
assertEquals("failed.nxdomain.exists:y.ingotronic.ch.", getReason(response));
}
@Test
public void testNameErrorWhenNsecIsLastAndQnameDifferentDomain() throws IOException {
Message nsec = resolver.send(createMessage("zz.ingotronic.ch./NSEC"));
Record delegationNsec = null;
Record delegationNsecSig = null;
for (RRset set : nsec.getSectionRRsets(Section.AUTHORITY)) {
if (set.getName().toString().startsWith("z.ingotronic.ch")) {
delegationNsec = set.first();
delegationNsecSig = (Record)set.sigs().next();
break;
}
}
Message m = createMessage("zingotronic.ch./A");
m.getHeader().setRcode(Rcode.NXDOMAIN);
m.addRecord(delegationNsec, Section.AUTHORITY);
m.addRecord(delegationNsecSig, Section.AUTHORITY);
add("zingotronic.ch./A", m);
Message response = resolver.send(createMessage("zingotronic.ch./A"));
assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.SERVFAIL, response.getRcode());
assertEquals("failed.nxdomain.exists:zingotronic.ch.", getReason(response));
}
@Test
public void testNameErrorWhenNsecIsLastAndQnameIsZoneApex() throws IOException {
Message nsec = resolver.send(createMessage("zz.ingotronic.ch./NSEC"));
Record delegationNsec = null;
Record delegationNsecSig = null;
for (RRset set : nsec.getSectionRRsets(Section.AUTHORITY)) {
if (set.getName().toString().startsWith("z.ingotronic.ch")) {
delegationNsec = set.first();
delegationNsecSig = (Record)set.sigs().next();
break;
}
}
Message m = createMessage("ingotronic.ch./A");
m.getHeader().setRcode(Rcode.NXDOMAIN);
m.addRecord(delegationNsec, Section.AUTHORITY);
m.addRecord(delegationNsecSig, Section.AUTHORITY);
add("ingotronic.ch./A", m);
Message response = resolver.send(createMessage("ingotronic.ch./A"));
assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.SERVFAIL, response.getRcode());
assertEquals("failed.nxdomain.exists:ingotronic.ch.", getReason(response));
}
@Test
public void testNoDataWhenDSResultIsFromChild() throws IOException {
Message m = resolver.send(createMessage("samekey.ingotronic.ch./MX"));
// this test needs to have the key in the cache
add("samekey.ingotronic.ch./DS", m, false);
Message response = resolver.send(createMessage("samekey.ingotronic.ch./DS"));
assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.SERVFAIL, response.getRcode());
assertEquals("failed.nodata", getReason(response));
}
@Test
public void testNoDataOfDSForRoot() throws IOException {
Message response = resolver.send(createMessage("./DS"));
assertTrue("AD flag must be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.NOERROR, response.getRcode());
assertNull(getReason(response));
}
@Test
public void testNsecProvesNoDS() throws IOException {
SecurityStatus s = ValUtils.nsecProvesNoDS(new NSECRecord(Name.root, DClass.IN, 0, Name.root, new int[] { Type.SOA, Type.NS }), Name.root);
assertEquals("Root NSEC SOA and without DS must be secure", SecurityStatus.SECURE, s);
}
@Test
public void testNsecProvesNoDSWithDSPresentForRoot() throws IOException {
SecurityStatus s = ValUtils.nsecProvesNoDS(new NSECRecord(Name.root, DClass.IN, 0, Name.root, new int[] { Type.SOA, Type.NS, Type.DS }), Name.root);
assertEquals("Root NSEC with DS must be bogus", SecurityStatus.BOGUS, s);
}
@Test
public void testNsecProvesNoDSWithSOAForNonRoot() throws IOException {
Name ch = Name.fromString("ch.");
SecurityStatus s = ValUtils.nsecProvesNoDS(new NSECRecord(ch, DClass.IN, 0, ch, new int[] { Type.SOA, Type.NS }), ch);
assertEquals("Non-root NSEC with SOA must be bogus", SecurityStatus.BOGUS, s);
}
@Test
public void testNoDataOnEntWithWrongNsec() throws IOException {
Message nsec = resolver.send(createMessage("alias.ingotronic.ch./NSEC"));
Record delegationNsec = null;
Record delegationNsecSig = null;
for (RRset set : nsec.getSectionRRsets(Section.ANSWER)) {
if (set.getName().toString().startsWith("alias.ingotronic.ch")) {
delegationNsec = set.first();
delegationNsecSig = (Record)set.sigs().next();
break;
}
}
Message m = createMessage("ingotronic.ch./A");
m.getHeader().setRcode(Rcode.NOERROR);
m.addRecord(delegationNsec, Section.AUTHORITY);
m.addRecord(delegationNsecSig, Section.AUTHORITY);
add("ingotronic.ch./A", m);
Message response = resolver.send(createMessage("ingotronic.ch./A"));
assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.SERVFAIL, response.getRcode());
assertEquals("failed.nodata", getReason(response));
}
@Test
public void testNoDataWhenNsecProvesExistence() throws IOException {
Message nsec = resolver.send(createMessage("www.ingotronic.ch./NSEC"));
Record delegationNsec = null;
Record delegationNsecSig = null;
for (RRset set : nsec.getSectionRRsets(Section.ANSWER)) {
if (set.getName().toString().startsWith("www.ingotronic.ch")) {
delegationNsec = set.first();
delegationNsecSig = (Record)set.sigs().next();
break;
}
}
Message m = createMessage("www.ingotronic.ch./AAAA");
m.getHeader().setRcode(Rcode.NOERROR);
m.addRecord(delegationNsec, Section.AUTHORITY);
m.addRecord(delegationNsecSig, Section.AUTHORITY);
add("www.ingotronic.ch./AAAA", m);
Message response = resolver.send(createMessage("www.ingotronic.ch./AAAA"));
assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.SERVFAIL, response.getRcode());
assertEquals("failed.nodata", getReason(response));
}
@Test
public void testNoDataWhenNsecHasCname() throws IOException {
Message nsec = resolver.send(createMessage("csigned.ingotronic.ch./NSEC"));
Record delegationNsec = null;
Record delegationNsecSig = null;
for (RRset set : nsec.getSectionRRsets(Section.ANSWER)) {
if (set.getName().toString().startsWith("csigned.ingotronic.ch")) {
delegationNsec = set.first();
delegationNsecSig = (Record)set.sigs().next();
break;
}
}
Message m = createMessage("csigned.ingotronic.ch./A");
m.getHeader().setRcode(Rcode.NOERROR);
m.addRecord(delegationNsec, Section.AUTHORITY);
m.addRecord(delegationNsecSig, Section.AUTHORITY);
add("csigned.ingotronic.ch./A", m);
Message response = resolver.send(createMessage("csigned.ingotronic.ch./A"));
assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.SERVFAIL, response.getRcode());
assertEquals("failed.nodata", getReason(response));
}
@Test
public void testNoDataWhenWcNsecProvesType() throws IOException {
Message nsec = resolver.send(createMessage("*.c.ingotronic.ch./NSEC"));
Record delegationNsec = null;
Record delegationNsecSig = null;
for (RRset set : nsec.getSectionRRsets(Section.ANSWER)) {
if (set.getName().toString().startsWith("*.c.ingotronic.ch")) {
delegationNsec = set.first();
delegationNsecSig = (Record)set.sigs().next();
break;
}
}
Message m = createMessage("a.c.ingotronic.ch./A");
m.getHeader().setRcode(Rcode.NOERROR);
m.addRecord(delegationNsec, Section.AUTHORITY);
m.addRecord(delegationNsecSig, Section.AUTHORITY);
add("a.c.ingotronic.ch./A", m);
Message response = resolver.send(createMessage("a.c.ingotronic.ch./A"));
assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.SERVFAIL, response.getRcode());
assertEquals("failed.nodata", getReason(response));
}
@Test
public void testNoDataWhenWcNsecProvesCname() throws IOException {
Message nsec = resolver.send(createMessage("*.cwv.ingotronic.ch./NSEC"));
Record delegationNsec = null;
Record delegationNsecSig = null;
for (RRset set : nsec.getSectionRRsets(Section.ANSWER)) {
if (set.getName().toString().startsWith("*.cwv.ingotronic.ch")) {
delegationNsec = set.first();
delegationNsecSig = (Record)set.sigs().next();
break;
}
}
Message m = createMessage("a.cwv.ingotronic.ch./A");
m.getHeader().setRcode(Rcode.NOERROR);
m.addRecord(delegationNsec, Section.AUTHORITY);
m.addRecord(delegationNsecSig, Section.AUTHORITY);
add("a.cwv.ingotronic.ch./A", m);
Message response = resolver.send(createMessage("a.cwv.ingotronic.ch./A"));
assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.SERVFAIL, response.getRcode());
assertEquals("failed.nodata", getReason(response));
}
@Test
public void testNoDataWhenWcNsecIsForDifferentName() throws IOException {
Message nsec = resolver.send(createMessage("*.c.ingotronic.ch./NSEC"));
Record delegationNsec = null;
Record delegationNsecSig = null;
for (RRset set : nsec.getSectionRRsets(Section.ANSWER)) {
if (set.getName().toString().startsWith("*.c.ingotronic.ch")) {
delegationNsec = set.first();
delegationNsecSig = (Record)set.sigs().next();
break;
}
}
Message m = createMessage("b.d.ingotronic.ch./A");
m.getHeader().setRcode(Rcode.NOERROR);
m.addRecord(delegationNsec, Section.AUTHORITY);
m.addRecord(delegationNsecSig, Section.AUTHORITY);
add("b.d.ingotronic.ch./A", m);
Message response = resolver.send(createMessage("b.d.ingotronic.ch./A"));
assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.SERVFAIL, response.getRcode());
assertEquals("failed.nodata", getReason(response));
}
@Test
public void testDsNoDataWhenNsecProvesDs() throws IOException {
Message nsec = resolver.send(createMessage("sub1.ingotronic.ch./NSEC"));
Record delegationNsec = null;
Record delegationNsecSig = null;
for (RRset set : nsec.getSectionRRsets(Section.AUTHORITY)) {
if (set.getName().toString().startsWith("sub.ingotronic.ch")) {
delegationNsec = set.first();
delegationNsecSig = (Record)set.sigs().next();
break;
}
}
Message m = createMessage("sub.ingotronic.ch./DS");
m.getHeader().setRcode(Rcode.NOERROR);
m.addRecord(delegationNsec, Section.AUTHORITY);
m.addRecord(delegationNsecSig, Section.AUTHORITY);
add("sub.ingotronic.ch./DS", m);
Message response = resolver.send(createMessage("sub.ingotronic.ch./A"));
assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.SERVFAIL, response.getRcode());
assertEquals("validate.bogus.badkey:sub.ingotronic.ch.:failed.ds.nsec.hasdata", getReason(response));
}
@Test
public void testHasSignedNsecsWithoutSignedSigsReturnsFalse() {
Message m = new Message();
m.addRecord(new NSECRecord(Name.root, DClass.IN, 0, Name.root, new int[] { Type.A }), Section.AUTHORITY);
SMessage sm = new SMessage(m);
boolean result = new ValUtils().hasSignedNsecs(sm);
assertFalse(result);
}
@Test
public void testAtLeastOneSupportedAlgorithmWithOnlyNonDSRecords() {
RRset set = new RRset(new NSECRecord(Name.root, DClass.IN, 0, Name.root, new int[] { Type.A }));
boolean result = ValUtils.atLeastOneSupportedAlgorithm(set);
assertFalse(result);
}
@Test
public void testAtLeastOneDigestSupportedWithOnlyNonDSRecords() {
RRset set = new RRset(new NSECRecord(Name.root, DClass.IN, 0, Name.root, new int[] { Type.A }));
boolean result = ValUtils.atLeastOneDigestSupported(set);
assertFalse(result);
}
}