Skip to content
This repository was archived by the owner on Feb 6, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,17 @@
<url>https://github.com/ibauersachs/dnssecjava</url>

<properties>
<powermock.version>2.0.2</powermock.version>
<powermock.version>2.0.5</powermock.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<checkstyle.config.location>checkstyle.xml</checkstyle.config.location>
<slf4j.version>1.7.30</slf4j.version>
</properties>

<dependencies>
<dependency>
<groupId>dnsjava</groupId>
<artifactId>dnsjava</artifactId>
<version>3.0.0-next.1</version>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/org/jitsi/dnssec/validator/NSEC3ValUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,12 @@ private boolean validIterations(SRRset nsec, KeyCache keyCache) {
case Algorithm.ECC_GOST:
keysize = 512;
break;
case Algorithm.ED25519:
keysize = 256;
break;
case Algorithm.ED448:
keysize = 456;
break;
default:
return false;
}
Expand Down
49 changes: 26 additions & 23 deletions src/main/java/org/jitsi/dnssec/validator/ValUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,15 @@ public class ValUtils {
private Properties config = null;
private boolean digestHardenDowngrade = true;
private boolean hasGost;
private boolean hasEd25519;
private boolean hasEd448;

/** Creates a new instance of this class. */
public ValUtils() {
this.verifier = new DnsSecVerifier();
hasGost = Security.getProviders("MessageDigest.GOST3411") != null;
hasEd25519 = Security.getProviders("KeyFactory.Ed25519") != null;
hasEd448 = Security.getProviders("KeyFactory.Ed448") != null;
}

/**
Expand Down Expand Up @@ -134,6 +139,8 @@ public static void setCanonicalNsecOwner(SRRset set, RRSIGRecord sig) {
*/
public void init(Properties config) {
hasGost = Security.getProviders("MessageDigest.GOST3411") != null;
hasEd25519 = Security.getProviders("KeyFactory.Ed25519") != null;
hasEd448 = Security.getProviders("KeyFactory.Ed448") != null;
this.config = config;
String dp = config.getProperty(DIGEST_PREFERENCE);
if (dp != null) {
Expand Down Expand Up @@ -871,21 +878,13 @@ boolean isAlgorithmSupported(int alg) {
case Algorithm.RSASHA512:
case Algorithm.ECDSAP256SHA256:
case Algorithm.ECDSAP384SHA384:
if (config == null) {
return true;
}

return Boolean.parseBoolean(config.getProperty(configKey, Boolean.TRUE.toString()));
return propertyOrTrueWithPrecondition(configKey, true);
case Algorithm.ECC_GOST:
if (!hasGost) {
return false;
}

if (config == null) {
return true;
}

return Boolean.parseBoolean(config.getProperty(configKey, Boolean.TRUE.toString()));
return propertyOrTrueWithPrecondition(configKey, hasGost);
case Algorithm.ED25519:
return propertyOrTrueWithPrecondition(configKey, hasEd25519);
case Algorithm.ED448:
return propertyOrTrueWithPrecondition(configKey, hasEd448);
default:
return false;
}
Expand Down Expand Up @@ -927,17 +926,21 @@ boolean isDigestSupported(int digestID) {

return Boolean.parseBoolean(config.getProperty(configKey, Boolean.TRUE.toString()));
case Digest.GOST3411:
if (!hasGost) {
return false;
}

if (config == null) {
return true;
}

return Boolean.parseBoolean(config.getProperty(configKey, Boolean.TRUE.toString()));
return propertyOrTrueWithPrecondition(configKey, hasGost);
default:
return false;
}
}

private boolean propertyOrTrueWithPrecondition(String configKey, boolean precondition) {
if (!precondition) {
return false;
}

if (config == null) {
return true;
}

return Boolean.parseBoolean(config.getProperty(configKey, Boolean.TRUE.toString()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1329,6 +1329,11 @@ public void setTSIGKey(TSIG key) {
this.headResolver.setTSIGKey(key);
}

@Override
public Duration getTimeout() {
return this.headResolver.getTimeout();
}

@Override
public void setTimeout(Duration duration) {
this.headResolver.setTimeout(duration);
Expand Down
28 changes: 28 additions & 0 deletions src/test/java/org/jitsi/dnssec/TestAlgorithmSupport.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@

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 java.security.Security;
import java.util.Properties;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jitsi.dnssec.validator.ValUtils;
import org.junit.Test;
import org.powermock.reflect.Whitebox;
Expand Down Expand Up @@ -44,6 +48,30 @@ public void testEccgostAlgIsUnknown() throws IOException {
assertEquals("insecure.ds.noalgorithms:eccgost.ingotronic.ch.", getReason(response));
}

@Test
public void testEd25519() throws IOException {
BouncyCastleProvider bc = new BouncyCastleProvider();
Security.addProvider(bc);
resolver.init(new Properties());
Message response = resolver.send(createMessage("ed25519.nl./A"));
assertTrue("AD flag must be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.NOERROR, response.getRcode());
assertNull(getReason(response));
Security.removeProvider(bc.getName());
}

@Test
public void testEd448() throws IOException {
BouncyCastleProvider bc = new BouncyCastleProvider();
Security.addProvider(bc);
resolver.init(new Properties());
Message response = resolver.send(createMessage("ed448.nl./A"));
assertTrue("AD flag must be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.NOERROR, response.getRcode());
assertNull(getReason(response));
Security.removeProvider(bc.getName());
}

@Test
public void testDigestIdIsUnknown() throws IOException {
Message response = resolver.send(createMessage("unknown-alg.ingotronic.ch./A"));
Expand Down
19 changes: 10 additions & 9 deletions src/test/java/org/jitsi/dnssec/TestBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
import org.jitsi.dnssec.validator.ValidatingResolver;
import org.junit.Assert;
import org.junit.Before;
Expand Down Expand Up @@ -101,6 +102,7 @@ protected void starting(Description description) {
"/recordings/" + description.getClassName().replace(".", "_") + "/" + testName;
File f = new File("./src/test/resources" + filename);
if ((record || !f.exists()) && !alwaysOffline) {
resolverClock = Clock.systemUTC();
f.getParentFile().getParentFile().mkdir();
f.getParentFile().mkdir();
w = new FileWriter(f.getAbsoluteFile());
Expand Down Expand Up @@ -136,7 +138,7 @@ protected void starting(Description description) {
@Override
protected void finished(Description description) {
try {
if (record && w != null) {
if (w != null) {
w.flush();
w.close();
w = null;
Expand All @@ -157,7 +159,7 @@ public static void setupClass() {
public void setup() throws NumberFormatException, IOException, DNSSECException {
resolver =
new ValidatingResolver(
new SimpleResolver("62.192.5.131") {
new SimpleResolver("8.8.4.4") {
@Override
public CompletionStage<Message> sendAsync(Message query) {
logger.info("---{}", key(query));
Expand All @@ -168,16 +170,17 @@ public CompletionStage<Message> sendAsync(Message query) {
Assert.fail("Response for " + key(query) + " not found.");
}

Message networkResult = null;
Message networkResult;
try {
networkResult = super.send(query);
if (record) {
networkResult = super.sendAsync(query).toCompletableFuture().get();
if (w != null) {
w.write(networkResult.toString());
w.write("\n\n###############################################\n\n");
}
} catch (IOException e) {
} catch (IOException | InterruptedException | ExecutionException e) {
CompletableFuture<Message> f = new CompletableFuture<>();
f.completeExceptionally(e);
return f;
}

return CompletableFuture.completedFuture(networkResult);
Expand Down Expand Up @@ -206,9 +209,7 @@ protected void add(String query, Message response, boolean clear) throws IOExcep

try {
setup();
} catch (NumberFormatException e) {
throw new IOException(e);
} catch (DNSSECException e) {
} catch (NumberFormatException | DNSSECException e) {
throw new IOException(e);
}
}
Expand Down
55 changes: 46 additions & 9 deletions src/test/java/org/jitsi/dnssec/TestPriming.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.powermock.api.mockito.PowerMockito.doAnswer;
import static org.powermock.api.mockito.PowerMockito.doReturn;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.powermock.api.mockito.PowerMockito.whenNew;

import java.io.IOException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.stubbing.Answer;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import org.xbill.DNS.DClass;
import org.xbill.DNS.DNSKEYRecord;
import org.xbill.DNS.DNSSEC;
Expand All @@ -38,7 +41,7 @@
import org.xbill.DNS.Type;

@RunWith(PowerMockRunner.class)
@PrepareForTest(DNSKEYRecord.class)
@PrepareForTest({Record.class, DNSKEYRecord.class})
public class TestPriming extends TestBase {
@Test
public void testDnskeyPrimeResponseWithEmptyAnswerIsBad() throws IOException {
Expand Down Expand Up @@ -91,9 +94,26 @@ public void testDnskeyPrimeResponseWithMismatchedFootprintIsBad() throws Excepti
}

public void prepareTestDnskeyPrimeResponseWithMismatchedFootprintIsBad() throws Exception {
DNSKEYRecord emptyDnskeyRecord = spy(Whitebox.invokeConstructor(DNSKEYRecord.class));
when(emptyDnskeyRecord.getFootprint()).thenReturn(-1);
whenNew(DNSKEYRecord.class).withNoArguments().thenReturn(emptyDnskeyRecord);
spy(Record.class);
doAnswer(
(Answer<Record>)
getEmptyRecordInvocation -> {
Record orig = (Record) getEmptyRecordInvocation.callRealMethod();
if (orig instanceof DNSKEYRecord) {
DNSKEYRecord dr = spy((DNSKEYRecord) orig);
when(dr.getFootprint()).thenReturn(-1);
return dr;
}
return orig;
})
.when(
Record.class,
"getEmptyRecord",
any(),
eq(Type.DNSKEY),
eq(DClass.IN),
anyLong(),
anyBoolean());
}

@Test
Expand All @@ -107,9 +127,26 @@ public void testDnskeyPrimeResponseWithMismatchedAlgorithmIsBad()
}

public void prepareTestDnskeyPrimeResponseWithMismatchedAlgorithmIsBad() throws Exception {
DNSKEYRecord emptyDnskeyRecord = spy(Whitebox.invokeConstructor(DNSKEYRecord.class));
when(emptyDnskeyRecord.getAlgorithm()).thenReturn(-1);
whenNew(DNSKEYRecord.class).withNoArguments().thenReturn(emptyDnskeyRecord);
spy(Record.class);
doAnswer(
(Answer<Record>)
getEmptyRecordInvocation -> {
Record orig = (Record) getEmptyRecordInvocation.callRealMethod();
if (orig instanceof DNSKEYRecord) {
DNSKEYRecord dr = spy((DNSKEYRecord) orig);
when(dr.getAlgorithm()).thenReturn(-1);
return dr;
}
return orig;
})
.when(
Record.class,
"getEmptyRecord",
any(),
eq(Type.DNSKEY),
eq(DClass.IN),
anyLong(),
anyBoolean());
}

@Test
Expand Down
Loading