Skip to content
This repository was archived by the owner on Feb 6, 2022. It is now read-only.

Commit 742a8c2

Browse files
committed
Merge branch 'update'
2 parents 05cb5d3 + a6980e6 commit 742a8c2

18 files changed

+1434
-127
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ A DNSSEC validating stub resolver for Java.
55
[![Build Status](https://travis-ci.org/ibauersachs/dnssecjava.svg?branch=master)](https://travis-ci.org/ibauersachs/dnssecjava)
66
[![Coverage Status](https://coveralls.io/repos/ibauersachs/dnssecjava/badge.svg)](https://coveralls.io/r/ibauersachs/dnssecjava)
77
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jitsi/dnssecjava/badge.svg)](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.jitsi%22%20AND%20a%3A%22dnssecjava%22)
8+
[![Javadocs](http://javadoc.io/badge/org.jitsi/dnssecjava.svg)](https://javadoc.io/doc/org.jitsi/dnssecjava)
89

910
Is this library safe to use?
1011
---------------------------
@@ -28,6 +29,12 @@ The Unbound prototype was stripped from all unnecessary parts, heavily
2829
modified, complemented with more than 300 unit test and found bugs were fixed.
2930

3031
### Released versions
32+
* 1.2.0:
33+
- Fix CVE-2017-15105
34+
- Add config option `org.jitsi.dnssec.harden_algo_downgrade`
35+
- Fix handling of ENT in NSEC3 zones
36+
- Fix returning YXDOMAIN RCode
37+
- Requires dnsjava 2.1.9 for proper (EC)DSA signature validation
3138
* 1.1.3:
3239
- Replace jmockit with PowerMockito due to ever changing API (and there's a Debian package for PowerMockito)
3340
- Use fixed versions for the dependencies

pom.xml

Lines changed: 6 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
<groupId>org.jitsi</groupId>
44
<artifactId>dnssecjava</artifactId>
55
<packaging>bundle</packaging>
6-
<version>1.1.4-SNAPSHOT</version>
6+
<version>1.2.0</version>
77
<name>dnssecjava</name>
8-
<url>https://jitsi.org/dnssec</url>
8+
<url>https://github.com/ibauersachs/dnssecjava</url>
99

1010
<properties>
1111
<powermock.version>1.6.6</powermock.version>
@@ -18,7 +18,7 @@
1818
<dependency>
1919
<groupId>dnsjava</groupId>
2020
<artifactId>dnsjava</artifactId>
21-
<version>2.1.7</version>
21+
<version>2.1.9</version>
2222
</dependency>
2323
<dependency>
2424
<groupId>org.slf4j</groupId>
@@ -58,7 +58,7 @@
5858
<dependency>
5959
<groupId>joda-time</groupId>
6060
<artifactId>joda-time</artifactId>
61-
<version>2.9.6</version>
61+
<version>2.10.2</version>
6262
<scope>test</scope>
6363
</dependency>
6464
</dependencies>
@@ -107,7 +107,6 @@
107107
<failsOnError>true</failsOnError>
108108
<maxAllowedViolations>0</maxAllowedViolations>
109109
<failOnViolation>true</failOnViolation>
110-
<linkXRef>false</linkXRef>
111110
<consoleOutput>true</consoleOutput>
112111
</configuration>
113112
</execution>
@@ -116,7 +115,7 @@
116115
<plugin>
117116
<groupId>org.jacoco</groupId>
118117
<artifactId>jacoco-maven-plugin</artifactId>
119-
<version>0.7.5.201505241946</version>
118+
<version>0.8.4</version>
120119
<executions>
121120
<execution>
122121
<id>prepare-agent</id>
@@ -137,42 +136,6 @@
137136
<version>2.5.3</version>
138137
</plugin>
139138
</plugins>
140-
<pluginManagement>
141-
<plugins>
142-
<!--This plugin's configuration is used to store Eclipse m2e settings
143-
only. It has no influence on the Maven build itself. -->
144-
<plugin>
145-
<groupId>org.eclipse.m2e</groupId>
146-
<artifactId>lifecycle-mapping</artifactId>
147-
<version>1.0.0</version>
148-
<configuration>
149-
<lifecycleMappingMetadata>
150-
<pluginExecutions>
151-
<pluginExecution>
152-
<pluginExecutionFilter>
153-
<groupId>
154-
org.apache.maven.plugins
155-
</groupId>
156-
<artifactId>
157-
maven-checkstyle-plugin
158-
</artifactId>
159-
<versionRange>
160-
[2.11,)
161-
</versionRange>
162-
<goals>
163-
<goal>check</goal>
164-
</goals>
165-
</pluginExecutionFilter>
166-
<action>
167-
<ignore />
168-
</action>
169-
</pluginExecution>
170-
</pluginExecutions>
171-
</lifecycleMappingMetadata>
172-
</configuration>
173-
</plugin>
174-
</plugins>
175-
</pluginManagement>
176139
</build>
177140
<organization>
178141
<name>jitsi.org</name>
@@ -182,7 +145,7 @@
182145
<url>https://github.com/ibauersachs/dnssecjava</url>
183146
<connection>scm:git:https://github.com/ibauersachs/dnssecjava.git</connection>
184147
<developerConnection>scm:git:https://github.com/ibauersachs/dnssecjava.git</developerConnection>
185-
<tag>HEAD</tag>
148+
<tag>dnssecjava-1.2.0</tag>
186149
</scm>
187150
<description>A DNSSEC validating stub resolver for Java.</description>
188151
<licenses>

src/main/java/org/jitsi/dnssec/SRRset.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
*/
5757
public class SRRset extends RRset {
5858
private SecurityStatus securityStatus;
59+
private Name ownerName;
5960

6061
/** Create a new, blank SRRset. */
6162
public SRRset() {
@@ -114,4 +115,17 @@ public Name getSignerName() {
114115

115116
return null;
116117
}
118+
119+
@Override
120+
public Name getName() {
121+
return this.ownerName == null ? super.getName() : this.ownerName;
122+
}
123+
124+
/**
125+
* Set the name of the records.
126+
* @param ownerName the {@link Name} to override the original name with.
127+
*/
128+
public void setName(Name ownerName) {
129+
this.ownerName = ownerName;
130+
}
117131
}

src/main/java/org/jitsi/dnssec/validator/DnsSecVerifier.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import java.util.Iterator;
4545
import java.util.List;
4646

47+
import org.jitsi.dnssec.SRRset;
4748
import org.jitsi.dnssec.SecurityStatus;
4849
import org.slf4j.Logger;
4950
import org.slf4j.LoggerFactory;
@@ -52,6 +53,7 @@
5253
import org.xbill.DNS.DNSSEC.DNSSECException;
5354
import org.xbill.DNS.RRSIGRecord;
5455
import org.xbill.DNS.RRset;
56+
import org.xbill.DNS.Type;
5557

5658
/**
5759
* A class for performing basic DNSSEC verification. The DNSJAVA package
@@ -112,8 +114,8 @@ private List<DNSKEYRecord> findKey(RRset dnskeyRrset, RRSIGRecord signature) {
112114
* could not be completed (usually because the public key was not
113115
* available).
114116
*/
115-
private SecurityStatus verifySignature(RRset rrset, RRSIGRecord sigrec,
116-
RRset keyRrset) {
117+
private SecurityStatus verifySignature(SRRset rrset, RRSIGRecord sigrec,
118+
RRset keyRrset) {
117119
List<DNSKEYRecord> keys = this.findKey(keyRrset, sigrec);
118120
if (keys == null) {
119121
logger.trace("could not find appropriate key");
@@ -130,10 +132,11 @@ private SecurityStatus verifySignature(RRset rrset, RRSIGRecord sigrec,
130132
}
131133

132134
DNSSEC.verify(rrset, sigrec, key);
135+
ValUtils.setCanonicalNsecOwner(rrset, sigrec);
133136
return SecurityStatus.SECURE;
134137
}
135138
catch (DNSSECException e) {
136-
logger.error("Failed to validate RRset", e);
139+
logger.error("Failed to validate RRset {}/{}", rrset.getName(), Type.string(rrset.getType()), e);
137140
status = SecurityStatus.BOGUS;
138141
}
139142
}
@@ -151,7 +154,7 @@ private SecurityStatus verifySignature(RRset rrset, RRSIGRecord sigrec,
151154
* @return SecurityStatus.SECURE if the rrest verified positively,
152155
* SecurityStatus.BOGUS otherwise.
153156
*/
154-
public SecurityStatus verify(RRset rrset, RRset keyRrset) {
157+
public SecurityStatus verify(SRRset rrset, RRset keyRrset) {
155158
Iterator<?> i = rrset.sigs();
156159
if (!i.hasNext()) {
157160
logger.info("RRset failed to verify due to lack of signatures");

src/main/java/org/jitsi/dnssec/validator/ValUtils.java

Lines changed: 59 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,34 @@ public ValUtils() {
9090
this.verifier = new DnsSecVerifier();
9191
}
9292

93+
/**
94+
* Set the owner name of NSEC RRsets to the canonical name, i.e. the name
95+
* that is <b>not</b> expanded from a wildcard label.
96+
* @param set The RRset to canonicalize.
97+
* @param sig The signature that validated this RRset.
98+
*/
99+
public static void setCanonicalNsecOwner(SRRset set, RRSIGRecord sig) {
100+
if (set.getType() != Type.NSEC) {
101+
return;
102+
}
103+
104+
Record nsec = set.first();
105+
int fqdnLabelCount = nsec.getName().labels() - 1; // don't count the root label
106+
if (nsec.getName().isWild()) {
107+
--fqdnLabelCount; // don't count the wildcard label
108+
}
109+
110+
if (sig.getLabels() == fqdnLabelCount) {
111+
set.setName(nsec.getName());
112+
}
113+
else if (sig.getLabels() < fqdnLabelCount) {
114+
set.setName(nsec.getName().wild(sig.getSigner().labels() - sig.getLabels()));
115+
}
116+
else {
117+
throw new IllegalArgumentException("invalid nsec record");
118+
}
119+
}
120+
93121
/**
94122
* Initialize the module. The recognized configuration value are
95123
* <ul>
@@ -445,13 +473,14 @@ public static boolean strictSubdomain(Name domain1, Name domain2) {
445473
* {@link NSECRecord#getNext()}).
446474
*
447475
* @param domain The name for which the closest encloser is queried.
448-
* @param nsec The covering {@link NSECRecord} to check.
476+
* @param owner The beginning of the covering {@link Name} to check.
477+
* @param next The end of the covering {@link Name} to check.
449478
* @return The closest encloser name of <code>domain</code> as defined by
450-
* <code>nsec</code>.
479+
* {@code owner} and {@code next}.
451480
*/
452-
public static Name closestEncloser(Name domain, NSECRecord nsec) {
453-
Name n1 = longestCommonName(domain, nsec.getName());
454-
Name n2 = longestCommonName(domain, nsec.getNext());
481+
public static Name closestEncloser(Name domain, Name owner, Name next) {
482+
Name n1 = longestCommonName(domain, owner);
483+
Name n2 = longestCommonName(domain, next);
455484

456485
return (n1.labels() > n2.labels()) ? n1 : n2;
457486
}
@@ -462,28 +491,29 @@ public static Name closestEncloser(Name domain, NSECRecord nsec) {
462491
*
463492
* @param domain The name for which the wildcard closest encloser is
464493
* demanded.
494+
* @param set The RRset containing {@code nsec} to check.
465495
* @param nsec The covering NSEC that defines the encloser.
466496
* @return The wildcard closest encloser name of <code>domain</code> as
467497
* defined by <code>nsec</code>.
468498
* @throws NameTooLongException If adding the wildcard label to the closest
469499
* encloser results in an invalid name.
470500
*/
471-
public static Name nsecWildcard(Name domain, NSECRecord nsec) throws NameTooLongException {
472-
Name origin = closestEncloser(domain, nsec);
501+
public static Name nsecWildcard(Name domain, SRRset set, NSECRecord nsec) throws NameTooLongException {
502+
Name origin = closestEncloser(domain, set.getName(), nsec.getNext());
473503
return Name.concatenate(WILDCARD, origin);
474504
}
475505

476506
/**
477507
* Determine if the given NSEC proves a NameError (NXDOMAIN) for a given
478508
* qname.
479509
*
510+
* @param set The RRset that contains the NSEC.
480511
* @param nsec The NSEC to check.
481512
* @param qname The qname to check against.
482-
* @param signerName The signer of the NSEC RRset.
483513
* @return true if the NSEC proves the condition.
484514
*/
485-
public static boolean nsecProvesNameError(NSECRecord nsec, Name qname, Name signerName) {
486-
Name owner = nsec.getName();
515+
public static boolean nsecProvesNameError(SRRset set, NSECRecord nsec, Name qname) {
516+
Name owner = set.getName();
487517
Name next = nsec.getNext();
488518

489519
// If NSEC owner == qname, then this NSEC proves that qname exists.
@@ -492,7 +522,7 @@ public static boolean nsecProvesNameError(NSECRecord nsec, Name qname, Name sign
492522
}
493523

494524
// deny overreaching NSECs
495-
if (!next.subdomain(signerName)) {
525+
if (!next.subdomain(set.getSignerName())) {
496526
return false;
497527
}
498528

@@ -539,29 +569,25 @@ else if (owner.compareTo(next) > 0) {
539569
* Determine if a NSEC record proves the non-existence of a wildcard that
540570
* could have produced qname.
541571
*
542-
* @param nsec The nsec to check.
572+
* @param set The RRset of the NSEC record.
573+
* @param nsec The nsec record to check.
543574
* @param qname The qname to check against.
544-
* @param signerName The signer of the NSEC RRset.
545575
* @return true if the NSEC proves the condition.
546576
*/
547-
public static boolean nsecProvesNoWC(NSECRecord nsec, Name qname, Name signerName) {
548-
int qnameLabels = qname.labels();
549-
Name ce = closestEncloser(qname, nsec);
550-
int ceLabels = ce.labels();
551-
552-
for (int i = qnameLabels - ceLabels; i > 0; i--) {
553-
Name wcName = qname.wild(i);
554-
if (nsecProvesNameError(nsec, wcName, signerName)) {
555-
return true;
556-
}
577+
public static boolean nsecProvesNoWC(SRRset set, NSECRecord nsec, Name qname) {
578+
Name ce = closestEncloser(qname, set.getName(), nsec.getNext());
579+
int labelsToStrip = qname.labels() - ce.labels();
580+
if (labelsToStrip > 0) {
581+
Name wcName = qname.wild(labelsToStrip);
582+
return nsecProvesNameError(set, nsec, wcName);
557583
}
558584

559585
return false;
560586
}
561587

562588
/**
563589
* Container for responses of
564-
* {@link ValUtils#nsecProvesNodata(NSECRecord, Name, int)}.
590+
* {@link ValUtils#nsecProvesNodata(SRRset, NSECRecord, Name, int)}.
565591
*/
566592
public static class NsecProvesNodataResponse {
567593
boolean result;
@@ -575,22 +601,23 @@ public static class NsecProvesNodataResponse {
575601
* must still be provided proof that qname did not directly exist and that
576602
* the wildcard is, in fact, *.closest_encloser.
577603
*
604+
* @param set The RRset of the NSEC record.
578605
* @param nsec The NSEC to check
579606
* @param qname The query name to check against.
580607
* @param qtype The query type to check against.
581608
* @return true if the NSEC proves the condition.
582609
*/
583-
public static NsecProvesNodataResponse nsecProvesNodata(NSECRecord nsec, Name qname, int qtype) {
610+
public static NsecProvesNodataResponse nsecProvesNodata(SRRset set, NSECRecord nsec, Name qname, int qtype) {
584611
NsecProvesNodataResponse result = new NsecProvesNodataResponse();
585-
if (!nsec.getName().equals(qname)) {
612+
if (!set.getName().equals(qname)) {
586613
// empty-non-terminal checking.
587614
// Done before wildcard, because this is an exact match,
588615
// and would prevent a wildcard from matching.
589616

590617
// If the nsec is proving that qname is an ENT, the nsec owner will
591618
// be less than qname, and the next name will be a child domain of
592619
// the qname.
593-
if (strictSubdomain(nsec.getNext(), qname) && nsec.getName().compareTo(qname) < 0) {
620+
if (strictSubdomain(nsec.getNext(), qname) && set.getName().compareTo(qname) < 0) {
594621
result.result = true;
595622
return result;
596623
}
@@ -600,9 +627,9 @@ public static NsecProvesNodataResponse nsecProvesNodata(NSECRecord nsec, Name qn
600627
// have generated qname from the wildcard and b) the type map does
601628
// not contain qtype. Note that this does NOT prove that this
602629
// wildcard was the applicable wildcard.
603-
if (nsec.getName().isWild()) {
630+
if (set.getName().isWild()) {
604631
// the is the purported closest encloser.
605-
Name ce = new Name(nsec.getName(), 1);
632+
Name ce = new Name(set.getName(), 1);
606633

607634
// The qname must be a strict subdomain of the closest encloser,
608635
// and the qtype must be absent from the type map.
@@ -720,16 +747,16 @@ public JustifiedSecStatus nsecProvesNodataDsReply(Message request, SMessage resp
720747
}
721748

722749
NSECRecord nsec = (NSECRecord)set.first();
723-
ndp = ValUtils.nsecProvesNodata(nsec, qname, Type.DS);
750+
ndp = ValUtils.nsecProvesNodata(set, nsec, qname, Type.DS);
724751
if (ndp.result) {
725752
hasValidNSEC = true;
726753
if (ndp.wc != null && nsec.getName().isWild()) {
727754
wcNsec = nsec;
728755
}
729756
}
730757

731-
if (ValUtils.nsecProvesNameError(nsec, qname, set.getSignerName())) {
732-
ce = closestEncloser(qname, nsec);
758+
if (ValUtils.nsecProvesNameError(set, nsec, qname)) {
759+
ce = closestEncloser(qname, set.getName(), nsec.getNext());
733760
}
734761
}
735762

0 commit comments

Comments
 (0)