diff --git a/pom.xml b/pom.xml
index bc666c1..3f77891 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,10 +8,9 @@
https://github.com/ibauersachs/dnssecjava
- 2.0.2
+ 2.0.5
UTF-8
UTF-8
- checkstyle.xml
1.7.30
@@ -19,7 +18,7 @@
dnsjava
dnsjava
- 3.0.0-next.1
+ 3.0.0
org.slf4j
diff --git a/src/main/java/org/jitsi/dnssec/validator/NSEC3ValUtils.java b/src/main/java/org/jitsi/dnssec/validator/NSEC3ValUtils.java
index 940930c..3193369 100644
--- a/src/main/java/org/jitsi/dnssec/validator/NSEC3ValUtils.java
+++ b/src/main/java/org/jitsi/dnssec/validator/NSEC3ValUtils.java
@@ -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;
}
diff --git a/src/main/java/org/jitsi/dnssec/validator/ValUtils.java b/src/main/java/org/jitsi/dnssec/validator/ValUtils.java
index cb4606b..d988aaa 100644
--- a/src/main/java/org/jitsi/dnssec/validator/ValUtils.java
+++ b/src/main/java/org/jitsi/dnssec/validator/ValUtils.java
@@ -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;
}
/**
@@ -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) {
@@ -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;
}
@@ -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()));
+ }
}
diff --git a/src/main/java/org/jitsi/dnssec/validator/ValidatingResolver.java b/src/main/java/org/jitsi/dnssec/validator/ValidatingResolver.java
index 7d3f280..4e5ba7a 100644
--- a/src/main/java/org/jitsi/dnssec/validator/ValidatingResolver.java
+++ b/src/main/java/org/jitsi/dnssec/validator/ValidatingResolver.java
@@ -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);
diff --git a/src/test/java/org/jitsi/dnssec/TestAlgorithmSupport.java b/src/test/java/org/jitsi/dnssec/TestAlgorithmSupport.java
index e9426f9..41cecb4 100644
--- a/src/test/java/org/jitsi/dnssec/TestAlgorithmSupport.java
+++ b/src/test/java/org/jitsi/dnssec/TestAlgorithmSupport.java
@@ -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;
@@ -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"));
diff --git a/src/test/java/org/jitsi/dnssec/TestBase.java b/src/test/java/org/jitsi/dnssec/TestBase.java
index 428c520..a50f97a 100644
--- a/src/test/java/org/jitsi/dnssec/TestBase.java
+++ b/src/test/java/org/jitsi/dnssec/TestBase.java
@@ -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;
@@ -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());
@@ -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;
@@ -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 sendAsync(Message query) {
logger.info("---{}", key(query));
@@ -168,16 +170,17 @@ public CompletionStage 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 f = new CompletableFuture<>();
f.completeExceptionally(e);
+ return f;
}
return CompletableFuture.completedFuture(networkResult);
@@ -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);
}
}
diff --git a/src/test/java/org/jitsi/dnssec/TestPriming.java b/src/test/java/org/jitsi/dnssec/TestPriming.java
index a4a0a84..144f4c7 100644
--- a/src/test/java/org/jitsi/dnssec/TestPriming.java
+++ b/src/test/java/org/jitsi/dnssec/TestPriming.java
@@ -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;
@@ -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 {
@@ -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)
+ 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
@@ -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)
+ 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
diff --git a/src/test/java/org/jitsi/dnssec/validator/TestNsec3ValUtilsPublicKeyLoading.java b/src/test/java/org/jitsi/dnssec/validator/TestNsec3ValUtilsPublicKeyLoading.java
index 3d6a651..9dd84d9 100644
--- a/src/test/java/org/jitsi/dnssec/validator/TestNsec3ValUtilsPublicKeyLoading.java
+++ b/src/test/java/org/jitsi/dnssec/validator/TestNsec3ValUtilsPublicKeyLoading.java
@@ -12,36 +12,47 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.withSettings;
import static org.powermock.api.mockito.PowerMockito.doAnswer;
import static org.powermock.api.mockito.PowerMockito.spy;
-import static org.powermock.api.mockito.PowerMockito.whenNew;
-import java.io.IOException;
+import java.lang.reflect.Modifier;
import java.security.PublicKey;
+import java.time.Duration;
import org.jitsi.dnssec.PrepareMocks;
import org.jitsi.dnssec.TestBase;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.internal.stubbing.answers.CallsRealMethods;
+import org.mockito.invocation.InvocationOnMock;
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;
import org.xbill.DNS.Flags;
import org.xbill.DNS.Message;
import org.xbill.DNS.Name;
import org.xbill.DNS.Rcode;
+import org.xbill.DNS.Record;
import org.xbill.DNS.Type;
@RunWith(PowerMockRunner.class)
-@PrepareForTest({Type.class})
+@PrepareForTest(Record.class)
public class TestNsec3ValUtilsPublicKeyLoading extends TestBase {
private int invocationCount = 0;
@Test
@PrepareMocks("prepareTestPublicKeyLoadingException")
- public void testPublicKeyLoadingException() throws IOException {
+ public void testPublicKeyLoadingException() throws Exception {
+ resolver.setTimeout(Duration.ofDays(1));
Message response = resolver.send(createMessage("www.wc.nsec3.ingotronic.ch./A"));
assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD));
assertEquals(Rcode.NOERROR, response.getRcode());
@@ -49,30 +60,54 @@ public void testPublicKeyLoadingException() throws IOException {
}
public void prepareTestPublicKeyLoadingException() throws Exception {
- DNSKEYRecord proto = spy(Whitebox.invokeConstructor(DNSKEYRecord.class));
+ spy(Record.class);
doAnswer(
- (Answer)
- invocationOnMock -> {
- DNSKEYRecord dr = spy(Whitebox.invokeConstructor(DNSKEYRecord.class));
- doAnswer(
- (Answer)
- invocation -> {
- DNSKEYRecord dr1 = (DNSKEYRecord) invocation.getMock();
- invocationCount++;
- if (dr1.getName()
- .equals(Name.fromConstantString("nsec3.ingotronic.ch."))
- && invocationCount == 11) {
- throw Whitebox.invokeConstructor(
- DNSSEC.DNSSECException.class, "mock-test");
- }
+ (Answer)
+ getEmptyRecordInvocation -> {
+ Record orig = (Record) getEmptyRecordInvocation.callRealMethod();
+ if (orig instanceof DNSKEYRecord) {
+ DNSKEYRecord dr =
+ mock(
+ DNSKEYRecord.class,
+ withSettings()
+ .spiedInstance(orig)
+ .defaultAnswer(
+ new CallsRealMethods() {
+ @Override
+ public Object answer(InvocationOnMock invocation)
+ throws Throwable {
+ return Modifier.isAbstract(
+ invocation.getMethod().getModifiers())
+ ? (invocation.getMethod().getName().equals("compareTo")
+ ? ((Comparable>) orig)
+ .compareTo(invocation.getArgument(0))
+ : Answers.RETURNS_DEFAULTS.answer(invocation))
+ : invocation.callRealMethod();
+ }
+ }));
+ doAnswer(
+ (Answer)
+ getPublicKeyInvocation -> {
+ if (invocationCount++ == 5) {
+ throw Whitebox.invokeConstructor(
+ DNSSEC.DNSSECException.class, "mock-test");
+ }
- return (PublicKey) invocation.callRealMethod();
- })
- .when(dr)
- .getPublicKey();
- return dr;
+ return (PublicKey) getPublicKeyInvocation.callRealMethod();
+ })
+ .when(dr)
+ .getPublicKey();
+ return dr;
+ }
+ return orig;
})
- .when(proto, "getObject");
- whenNew(DNSKEYRecord.class).withNoArguments().thenReturn(proto);
+ .when(
+ Record.class,
+ "getEmptyRecord",
+ eq(Name.fromConstantString("nsec3.ingotronic.ch.")),
+ eq(Type.DNSKEY),
+ eq(DClass.IN),
+ anyLong(),
+ anyBoolean());
}
}
diff --git a/src/test/resources/recordings/org_jitsi_dnssec_TestAlgorithmSupport/testEd25519 b/src/test/resources/recordings/org_jitsi_dnssec_TestAlgorithmSupport/testEd25519
new file mode 100644
index 0000000..312bfd7
--- /dev/null
+++ b/src/test/resources/recordings/org_jitsi_dnssec_TestAlgorithmSupport/testEd25519
@@ -0,0 +1,112 @@
+#Date: 2020-01-26T20:03:58+01:00
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28087
+;; flags: qr rd ra cd ; qd: 1 an: 2 au: 0 ad: 1
+;; QUESTIONS:
+;; ed25519.nl., type = A, class = IN
+
+;; ANSWERS:
+ed25519.nl. 3403 IN RRSIG A 15 2 3600 20200206000000 20200116000000 27662 ed25519.nl. o0g+PTzmqA+LqRcoR3qduXimU1u5/oMXJGIHOv9aq5+7sdz5Lz6V5Z+lUZyUFDUCGg+k1I0aT5mW3JwuVVi6Cw==
+ed25519.nl. 3403 IN A 77.72.150.82
+
+;; AUTHORITY RECORDS:
+
+;; ADDITIONAL RECORDS:
+. 32768 CLASS512 OPT ; payload 512, xrcode 0, version 0, flags 32768
+
+;; Message size: 161 bytes
+
+###############################################
+
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54587
+;; flags: qr rd ra ad cd ; qd: 1 an: 3 au: 0 ad: 1
+;; QUESTIONS:
+;; ., type = DNSKEY, class = IN
+
+;; ANSWERS:
+. 7303 IN DNSKEY 257 3 8 AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU=
+. 7303 IN DNSKEY 256 3 8 AwEAAeN+h0loXPKt7lFdW2zKIDkVHyJ1aYGUVE1dMNBlRH3kTn40JKcHiPOs+fy0OFVCBwoKa1s9qZtdyP1UC0hgKoldj3oELK1yLI5MUbTMcNkWbBMRuxRz/CgZJu3IxcmuZWZMbn4LQDMj5YeiUiuWns5vipFGWWpyPyozQXmenSWOK2GJOwcm7I/DyHVtVdztTvqiHqzy2aRoxwPhmEuAoYzzuNJJw6JNEnXaN/7l2TIciskFyPVPBFZYHnk+1ma906dfehIR190z3lh1ZESL2Yy3VIE2QGpRU6Px4ydH5sXxZ2wSMgqNNga4kjnfM1msBqk3EI48RvTTkuV0yb1eFuU=
+. 7303 IN RRSIG DNSKEY 8 0 172800 20200211000000 20200121000000 20326 . UaaPoqlBlRixcabCWMJ9jVvevx+Sp8W5rMt06Tozfg/gefIspEKxw4fx22mRaAQZzdHq9Lt+Who4YpUX95CDrgDYtYJ9NOyICRNlWnY9FNqOW0AreCmEK0qqS52xYb72hJYpFrCILGLD6jl4Ar0LFi29iXnVLQ99+SvD8PPHHkEiIu1WhlES7taEavtbKijyjLYXwagQxSQCzMgkbWN1+S78kJGZEMaBODTZuiiGIw5Jy3OPAQxHQyLTElR5ZuEg59/sSnTCEfmoXcxG9/g6O1qWs6d9hDVadKfXhHr8OTXGoB25Ttp3CyZGdSqRkCwwJpWJ9SlaL+khcJoLFqwm8w==
+
+;; AUTHORITY RECORDS:
+
+;; ADDITIONAL RECORDS:
+. 32768 CLASS512 OPT ; payload 512, xrcode 0, version 0, flags 32768
+
+;; Message size: 864 bytes
+
+###############################################
+
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43154
+;; flags: qr rd ra ad cd ; qd: 1 an: 2 au: 0 ad: 1
+;; QUESTIONS:
+;; nl., type = DS, class = IN
+
+;; ANSWERS:
+nl. 8754 IN DS 34112 8 2 3C5B5F9B3557455C50751A9BE9EBE9238C88E19F5F07F930976917B51B95CD22
+nl. 8754 IN RRSIG DS 8 1 86400 20200207050000 20200125040000 33853 . s8pLNGhOt2S56ZmFJCUFjh72+nDKMxDBU5mH9GUBwsuJFmFs0aCBvAE8nPkU6lUN3d+UYJg9n8PEq0KP7Ea9v+HTnbDftKbQMbyL2tYhlP1+3CXwwozmD+1keq0AyFY6k7yj/d/ETcQYbmvz4Gudm0uJ4z+s1EDaGlLsXl4D7jFPhs117ASUBKFcphKEg3nKOhId04qOMf7ULz9evHggCPs9NCls+XHomo6HTSW+ZsoAi31ShiDnxnMU85nyst1sAT3xPsUZs/9TgFvmosPEUjkWtOUhypN6MYAS/kDbGECw41iEb1R4HRh2hOEhj7TLOpn2HfqC1pUrKRY7Ap7RSw==
+
+;; AUTHORITY RECORDS:
+
+;; ADDITIONAL RECORDS:
+. 32768 CLASS512 OPT ; payload 512, xrcode 0, version 0, flags 32768
+
+;; Message size: 366 bytes
+
+###############################################
+
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27023
+;; flags: qr rd ra cd ; qd: 1 an: 3 au: 0 ad: 1
+;; QUESTIONS:
+;; nl., type = DNSKEY, class = IN
+
+;; ANSWERS:
+nl. 3529 IN DNSKEY 256 3 8 AwEAAdDXROYhplVlInShki5RxTj7vFwqk8grVOHwUjwUlvsKBJUknF1PN1TWpHoXvWFXDTviW7jVgPx6RH2I4b/Iq30zHgPxJYT3EtpTzRbX2F1WS5n31r8BrQc3V1LdCGknhpAw6c7SAntrZ6m6nkgDn6z0ySnWri659CjxUgsHCBmD
+nl. 3529 IN DNSKEY 257 3 8 AwEAAcb+4kIsKoZM+3ZZpU9kzxrzw30e3b+L0KZeX+aAS3eM+Q+q27Jw0NZ3dqsPSif61GjRW6apjDZ9Ciab3oyEu7IpihVrw94DTjWZTVViZAijAIHwKUzY0YjkT3RvN+xgpw4uZs1SnqCZxYko+15esteKXW/nJpde0d9OeFFBaS2WTCycK+A6gd9DsOw91Y7Z2vrR/2g9N9dMIVq9neB1/KXXm4MttLqJyxRWZNAFTyLGQKzPpQDp9s3qowV2+pcHOh6lUTEeOWiAtotJ/5WyO91viZ5tBfClsyGpggBTaeUQ7T5adhAtX6nRkhePyAtQgCCf63ZpHyoyxvbkDM7yuA0=
+nl. 3529 IN RRSIG DNSKEY 8 1 3600 20200202095410 20200119113801 34112 nl. YGz3Y0XlKlWblNFPyt/T1cFUJkyB/mSLr9qWloZOUI4yyG/HqHU1aaS51UppjcGnAmCvcIYJ0tC8aNwEb+PW82czWJKX01A/493jQvCFPawqSFJWEFmiIdd7GVghAL5HFkZPyN1zeB/cYO3Y+/1UccY/r3QHlKmNpspJ7OoVo5/gcGvpE3vej5/DKDz/jiSo9wyEvLY09Ifpdsg03yJXCGMgD7kPDkPtnPWNNbUzmLiZbI0O4ePGS7q3G7Ink381KVS6f+3Dyjl0LQtEGEmyYglBl3w4DNAwlTvb7m5HEMarPYCs2Hy9zumSEoxNRpOhCSC3eNFuIT+4+cvzKEFOIw==
+
+;; AUTHORITY RECORDS:
+
+;; ADDITIONAL RECORDS:
+. 32768 CLASS512 OPT ; payload 512, xrcode 0, version 0, flags 32768
+
+;; Message size: 745 bytes
+
+###############################################
+
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41875
+;; flags: qr rd ra cd ; qd: 1 an: 2 au: 0 ad: 1
+;; QUESTIONS:
+;; ed25519.nl., type = DS, class = IN
+
+;; ANSWERS:
+ed25519.nl. 3599 IN DS 45515 15 2 1579CE721A8ADF5EF5222D48D6065FDD06E7BCE5C0154EC3EF1F30CC0D06EAAA
+ed25519.nl. 3599 IN RRSIG DS 8 2 3600 20200206093417 20200123053802 63744 nl. NhT3bOB2OFPf2tm8uG4QbbZVn/zwZRbHtOIcXc+hAUwZWKD3ZS5u+2gYEDwvG6G2hCtgcpIQZLAlnrlUs2j6EqSIbGJcof9fX+P3p3MMkvLZO3Sf17qOBETeVMsFSQPEdEyFInJWi4UxnJrjWpiLtdaxDJXIOJ0CDU2w6MfasHg=
+
+;; AUTHORITY RECORDS:
+
+;; ADDITIONAL RECORDS:
+. 32768 CLASS512 OPT ; payload 512, xrcode 0, version 0, flags 32768
+
+;; Message size: 249 bytes
+
+###############################################
+
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54226
+;; flags: qr rd ra cd ; qd: 1 an: 3 au: 0 ad: 1
+;; QUESTIONS:
+;; ed25519.nl., type = DNSKEY, class = IN
+
+;; ANSWERS:
+ed25519.nl. 3599 IN RRSIG DNSKEY 15 2 3600 20200206000000 20200116000000 45515 ed25519.nl. J/S+wT1KqCBWpzHtiJKhJ+YWx498lhTnvIcvKL/+eyAooKRbVrF/gXCAZpiL1hS7visl+Vw4fjTnnKnZn8BgDQ==
+ed25519.nl. 3599 IN DNSKEY 256 3 15 2tstZAjgmlDTePn0NVXrAHBJmg84LoaFVxzLl1anjGI=
+ed25519.nl. 3599 IN DNSKEY 257 3 15 m1NELLVVQKl4fHVn/KKdeNO0PrYKGT3IGbYseT8XcKo=
+
+;; AUTHORITY RECORDS:
+
+;; ADDITIONAL RECORDS:
+. 32768 CLASS512 OPT ; payload 512, xrcode 0, version 0, flags 32768
+
+;; Message size: 241 bytes
+
+###############################################
+
diff --git a/src/test/resources/recordings/org_jitsi_dnssec_TestAlgorithmSupport/testEd448 b/src/test/resources/recordings/org_jitsi_dnssec_TestAlgorithmSupport/testEd448
new file mode 100644
index 0000000..c90dbe8
--- /dev/null
+++ b/src/test/resources/recordings/org_jitsi_dnssec_TestAlgorithmSupport/testEd448
@@ -0,0 +1,111 @@
+#Date: 2020-01-26T20:06:39+01:00
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38495
+;; flags: qr rd ra cd ; qd: 1 an: 2 au: 0 ad: 1
+;; QUESTIONS:
+;; ed448.nl., type = A, class = IN
+
+;; ANSWERS:
+ed448.nl. 3599 IN A 45.150.156.16
+ed448.nl. 3599 IN RRSIG A 16 2 3600 20200206000000 20200116000000 24480 ed448.nl. bvKGWUiNDA3bFq0ECVF+/BGtNrNZUmgvDVKtLwrBWJTd+du2exCuUWfZNW72QxIDwJxPcnbCAiwAhOXjdzWGZH5Rtyqrz+bOELH4VISCA3dTGleofgZpWBBwuzWAWd8A5hCm35eei6ffo0BCIlmFSSwA
+
+;; AUTHORITY RECORDS:
+
+;; ADDITIONAL RECORDS:
+. 32768 CLASS512 OPT ; payload 512, xrcode 0, version 0, flags 32768
+
+;; Message size: 207 bytes
+
+###############################################
+
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59993
+;; flags: qr rd ra ad cd ; qd: 1 an: 3 au: 0 ad: 1
+;; QUESTIONS:
+;; ., type = DNSKEY, class = IN
+
+;; ANSWERS:
+. 7127 IN DNSKEY 257 3 8 AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU=
+. 7127 IN DNSKEY 256 3 8 AwEAAeN+h0loXPKt7lFdW2zKIDkVHyJ1aYGUVE1dMNBlRH3kTn40JKcHiPOs+fy0OFVCBwoKa1s9qZtdyP1UC0hgKoldj3oELK1yLI5MUbTMcNkWbBMRuxRz/CgZJu3IxcmuZWZMbn4LQDMj5YeiUiuWns5vipFGWWpyPyozQXmenSWOK2GJOwcm7I/DyHVtVdztTvqiHqzy2aRoxwPhmEuAoYzzuNJJw6JNEnXaN/7l2TIciskFyPVPBFZYHnk+1ma906dfehIR190z3lh1ZESL2Yy3VIE2QGpRU6Px4ydH5sXxZ2wSMgqNNga4kjnfM1msBqk3EI48RvTTkuV0yb1eFuU=
+. 7127 IN RRSIG DNSKEY 8 0 172800 20200211000000 20200121000000 20326 . UaaPoqlBlRixcabCWMJ9jVvevx+Sp8W5rMt06Tozfg/gefIspEKxw4fx22mRaAQZzdHq9Lt+Who4YpUX95CDrgDYtYJ9NOyICRNlWnY9FNqOW0AreCmEK0qqS52xYb72hJYpFrCILGLD6jl4Ar0LFi29iXnVLQ99+SvD8PPHHkEiIu1WhlES7taEavtbKijyjLYXwagQxSQCzMgkbWN1+S78kJGZEMaBODTZuiiGIw5Jy3OPAQxHQyLTElR5ZuEg59/sSnTCEfmoXcxG9/g6O1qWs6d9hDVadKfXhHr8OTXGoB25Ttp3CyZGdSqRkCwwJpWJ9SlaL+khcJoLFqwm8w==
+
+;; AUTHORITY RECORDS:
+
+;; ADDITIONAL RECORDS:
+. 32768 CLASS512 OPT ; payload 512, xrcode 0, version 0, flags 32768
+
+;; Message size: 864 bytes
+
+###############################################
+
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53319
+;; flags: qr rd ra ad cd ; qd: 1 an: 2 au: 0 ad: 1
+;; QUESTIONS:
+;; nl., type = DS, class = IN
+
+;; ANSWERS:
+nl. 23199 IN DS 34112 8 2 3C5B5F9B3557455C50751A9BE9EBE9238C88E19F5F07F930976917B51B95CD22
+nl. 23199 IN RRSIG DS 8 1 86400 20200207200000 20200125190000 33853 . Uoj2zHzh4QFG8bFVuEz2M6KIkNDoVxcFsTlPgc9r/jcrHtmDD19FDzQxulwjsSTvg6Y55lknUriMR9A6gFbMKxVdqA1KNa7WqU3RhKvlztBK0BRnK3vYnA0FqxiuCkbckiSRJjkxGe2nLaehxP4Jkg2/1o+AvB1+8lBteKhclV4yfpMnAqdGKYvrNoFIzV90BHMLqs3nqHOg4N0LHzfFhyD7WUHp1/qAVxVD0Q7U2TfpRxWW8hoUZixl3maAcwLFoMCmwIGm9KdaynvwYNt91wfRWp2LLZ5aRDsvBeaHiTI9K1cUU007rKU9jORc7U8C43RJL4DL8afQLF4pingKgQ==
+
+;; AUTHORITY RECORDS:
+
+;; ADDITIONAL RECORDS:
+. 32768 CLASS512 OPT ; payload 512, xrcode 0, version 0, flags 32768
+
+;; Message size: 366 bytes
+
+###############################################
+
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22319
+;; flags: qr rd ra ad cd ; qd: 1 an: 3 au: 0 ad: 1
+;; QUESTIONS:
+;; nl., type = DNSKEY, class = IN
+
+;; ANSWERS:
+nl. 3511 IN DNSKEY 257 3 8 AwEAAcb+4kIsKoZM+3ZZpU9kzxrzw30e3b+L0KZeX+aAS3eM+Q+q27Jw0NZ3dqsPSif61GjRW6apjDZ9Ciab3oyEu7IpihVrw94DTjWZTVViZAijAIHwKUzY0YjkT3RvN+xgpw4uZs1SnqCZxYko+15esteKXW/nJpde0d9OeFFBaS2WTCycK+A6gd9DsOw91Y7Z2vrR/2g9N9dMIVq9neB1/KXXm4MttLqJyxRWZNAFTyLGQKzPpQDp9s3qowV2+pcHOh6lUTEeOWiAtotJ/5WyO91viZ5tBfClsyGpggBTaeUQ7T5adhAtX6nRkhePyAtQgCCf63ZpHyoyxvbkDM7yuA0=
+nl. 3511 IN DNSKEY 256 3 8 AwEAAdDXROYhplVlInShki5RxTj7vFwqk8grVOHwUjwUlvsKBJUknF1PN1TWpHoXvWFXDTviW7jVgPx6RH2I4b/Iq30zHgPxJYT3EtpTzRbX2F1WS5n31r8BrQc3V1LdCGknhpAw6c7SAntrZ6m6nkgDn6z0ySnWri659CjxUgsHCBmD
+nl. 3511 IN RRSIG DNSKEY 8 1 3600 20200202095410 20200119113801 34112 nl. YGz3Y0XlKlWblNFPyt/T1cFUJkyB/mSLr9qWloZOUI4yyG/HqHU1aaS51UppjcGnAmCvcIYJ0tC8aNwEb+PW82czWJKX01A/493jQvCFPawqSFJWEFmiIdd7GVghAL5HFkZPyN1zeB/cYO3Y+/1UccY/r3QHlKmNpspJ7OoVo5/gcGvpE3vej5/DKDz/jiSo9wyEvLY09Ifpdsg03yJXCGMgD7kPDkPtnPWNNbUzmLiZbI0O4ePGS7q3G7Ink381KVS6f+3Dyjl0LQtEGEmyYglBl3w4DNAwlTvb7m5HEMarPYCs2Hy9zumSEoxNRpOhCSC3eNFuIT+4+cvzKEFOIw==
+
+;; AUTHORITY RECORDS:
+
+;; ADDITIONAL RECORDS:
+. 32768 CLASS512 OPT ; payload 512, xrcode 0, version 0, flags 32768
+
+;; Message size: 745 bytes
+
+###############################################
+
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31479
+;; flags: qr rd ra cd ; qd: 1 an: 2 au: 0 ad: 1
+;; QUESTIONS:
+;; ed448.nl., type = DS, class = IN
+
+;; ANSWERS:
+ed448.nl. 3599 IN DS 24480 16 2 85B885E4BC43270BDAA46860687D8F62D9BEEF1C6E9BEF21A7D80DC18A7943ED
+ed448.nl. 3599 IN RRSIG DS 8 2 3600 20200207144247 20200124023802 63744 nl. iBuueusdnKMiKRoiWXOi+ikw4gAkowyAspPklGY1t7U8nO8j+gxT3ooMBd9MdTFslgO7JVqIXUzdYZltUYgw4QsbOIPHZgJRKqsDk/e1PGd14OicoIi4U9QAvxDoiVs4JI7+u3sCi7IRKf2Bjov+3K7QWhKIftyjLaHZUhf9vcE=
+
+;; AUTHORITY RECORDS:
+
+;; ADDITIONAL RECORDS:
+. 32768 CLASS512 OPT ; payload 512, xrcode 0, version 0, flags 32768
+
+;; Message size: 247 bytes
+
+###############################################
+
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50838
+;; flags: qr rd ra cd ; qd: 1 an: 2 au: 0 ad: 1
+;; QUESTIONS:
+;; ed448.nl., type = DNSKEY, class = IN
+
+;; ANSWERS:
+ed448.nl. 1799 IN DNSKEY 257 3 16 8pYFjTum61L0k+q8HiIkEPipTTbuYnZceMVTJvqMZbhZdwzpkiYHRBHcVxmnOp1RJsGyt6I0myOA
+ed448.nl. 1799 IN RRSIG DNSKEY 16 2 1800 20200206000000 20200116000000 24480 ed448.nl. hMzUYoP9CvlqYajBDuODCxSpsouc96EG5A0aYTt78vhcRAuO7SP1n+AkqujGycZoCLNEt3IWONiAXOfAoGAPw3ZRh8W/ECqvX8fleB6UHlZKxrh8WPWn/wLZ2tsnBLXSnUGLypjFb5eqIeY6eUUB0CMA
+
+;; AUTHORITY RECORDS:
+
+;; ADDITIONAL RECORDS:
+. 32768 CLASS512 OPT ; payload 512, xrcode 0, version 0, flags 32768
+
+;; Message size: 264 bytes
+
+###############################################
+
diff --git a/src/test/resources/trust_anchors b/src/test/resources/trust_anchors
index b355dad..0c74585 100644
--- a/src/test/resources/trust_anchors
+++ b/src/test/resources/trust_anchors
@@ -1,2 +1,3 @@
. IN DS 19036 8 1 B256BD09DC8DD59F0E0F0D8541B8328DD986DF6E
. IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
+. IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D