ibauersachs / dnssecjava

A DNSSEC validating stub resolver for Java.
Other
43 stars 15 forks source link

Leading zeroes in in (r|s)-parameters of ECDSA signature cause validation to fail #14

Closed ralfhauser closed 5 years ago

ralfhauser commented 5 years ago

since this morning, we get . 0 CLASS65280 TXT "Could not establish validation of INSECURE status of unsigned response. Reason: Did not match a DS to a DNSKEY."

e.g. for MX of bger.ch

any hints what wrong ?

212.25.1.1 is the resolver.

<<query: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15318 ;; flags: rd ; qd: 1 an: 0 au: 0 ad: 0 ;; QUESTIONS: ;; bger.ch., type = MX, class = IN

;; ANSWERS:

;; AUTHORITY RECORDS:

;; ADDITIONAL RECORDS:

;; Message size: 0 bytes DEBUG [Thread-106] - got response: ;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 15318 ;; flags: qr ; qd: 1 an: 0 au: 0 ad: 1 ;; QUESTIONS: ;; bger.ch., type = MX, class = IN

;; ANSWERS:

;; AUTHORITY RECORDS:

;; ADDITIONAL RECORDS: . 0 CLASS65280 TXT "Could not establish validation of INSECURE status of unsigned response. Reason: Did not match a DS to a DNSKEY."

iWay claims they didn't change anything and all is working properly

ibauersachs commented 5 years ago

I can't access your resolver, so I have no idea what's going on there. A simple test based on the example in the readme and Google's public DNS or our internal AD resolver shows no errors:

package org.jitsi.dnssec;
import java.io.*;

import org.jitsi.dnssec.validator.ValidatingResolver;
import org.xbill.DNS.*;

public class Example {
    static String ROOT = ". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D";

    public static void main(String[] args) throws Exception {
        // Send two sample queries using a standard DNSJAVA resolver
        SimpleResolver sr = new SimpleResolver("8.8.4.4");
        System.out.println("Standard resolver:");
        sendAndPrint(sr, "www.dnssec-failed.org.", Type.A);
        sendAndPrint(sr, "www.isc.org.", Type.A);
        sendAndPrint(sr, "bger.ch.", Type.MX);

        // Send the same queries using the validating resolver with the
        // trust anchor of the root zone
        // http://data.iana.org/root-anchors/root-anchors.xml
        ValidatingResolver vr = new ValidatingResolver(sr);
        vr.loadTrustAnchors(new ByteArrayInputStream(ROOT.getBytes("ASCII")));
        System.out.println("\n\nValidating resolver:");
        sendAndPrint(vr, "www.dnssec-failed.org.", Type.A);
        sendAndPrint(vr, "www.isc.org.", Type.A);
        sendAndPrint(sr, "bger.ch.", Type.MX);
    }

    private static void sendAndPrint(Resolver vr, String name, int type) throws IOException {
        System.out.println("\n---" + name);
        Record qr = Record.newRecord(Name.fromConstantString(name), type, DClass.IN);
        Message response = vr.send(Message.newQuery(qr));
        System.out.println("AD-Flag: " + response.getHeader().getFlag(Flags.AD));
        System.out.println("RCode:   " + Rcode.string(response.getRcode()));
        for (RRset set : response.getSectionRRsets(Section.ADDITIONAL)) {
            if (set.getName().equals(Name.root) && set.getType() == Type.TXT
                    && set.getDClass() == ValidatingResolver.VALIDATION_REASON_QCLASS) {
                System.out.println("Reason:  " + ((TXTRecord) set.first()).getStrings().get(0));
            }
        }
    }
}

Result:

Standard resolver:

---www.dnssec-failed.org.
AD-Flag: false
RCode:   SERVFAIL

---www.isc.org.
AD-Flag: false
RCode:   NOERROR

---bger.ch.
AD-Flag: false
RCode:   NOERROR

Validating resolver:

---www.dnssec-failed.org.
AD-Flag: false
RCode:   SERVFAIL
Reason:  validate.bogus.badkey:dnssec-failed.org.:dnskey.no_ds_match

---www.isc.org.
AD-Flag: true
RCode:   NOERROR

---bger.ch.
AD-Flag: false
RCode:   NOERROR
ralfhauser commented 5 years ago

now also seeing

CLASS65280 TXT "Could not establish a chain of trust to keys for [ch.]. Reason: Did not match a DS to a DNSKEY."

ralfhauser commented 5 years ago

The problem can also be reproduced with 8.8.4.4

Your test probably has a copy-paste error.

Also the 2nd time you do: sendAndPrint(sr, "bger.ch.", Type.MX); but probably you should do sendAndPrint(vr, "bger.ch.", Type.MX);

==> did you really test bger with "vr" ?

ibauersachs commented 5 years ago

No, sorry, copy/paste. Seems like Switch generated a signature that has a leading 0, which Java since 1.8.121 rejects. See https://stackoverflow.com/a/40343731/1544715 for details (they talk about RSA but it applies to ECDSA as well). Not sure yet where to satisfy Java's (or BouncyCastle's) stupidity.

java.io.IOException: Invalid encoding: redundant leading 0s
    at java.base/sun.security.util.DerInputBuffer.getBigInteger(DerInputBuffer.java:161)
    at java.base/sun.security.util.DerValue.getPositiveBigInteger(DerValue.java:558)
    at jdk.crypto.ec/sun.security.ec.ECDSASignature.decodeSignature(ECDSASignature.java:491)
    at jdk.crypto.ec/sun.security.ec.ECDSASignature.engineVerify(ECDSASignature.java:412)
    at java.base/java.security.Signature$Delegate.engineVerify(Signature.java:1247)
    at java.base/java.security.Signature.verify(Signature.java:675)
    at org.xbill.DNS.DNSSEC.verify(DNSSEC.java:892)
    at org.xbill.DNS.DNSSEC.verify(DNSSEC.java:934)
    at org.jitsi.dnssec.validator.DnsSecVerifier.verify(DnsSecVerifier.java:198)
    at org.jitsi.dnssec.validator.ValUtils.verifyNewDNSKEYs(ValUtils.java:232)
    at org.jitsi.dnssec.validator.ValidatingResolver.processDNSKEYResponse(ValidatingResolver.java:982)
    at org.jitsi.dnssec.validator.ValidatingResolver.processFindKey(ValidatingResolver.java:779)
    at org.jitsi.dnssec.validator.ValidatingResolver.processDSResponse(ValidatingResolver.java:967)
    at org.jitsi.dnssec.validator.ValidatingResolver.processFindKey(ValidatingResolver.java:772)
    at org.jitsi.dnssec.validator.ValidatingResolver.processDNSKEYResponse(ValidatingResolver.java:994)
    at org.jitsi.dnssec.validator.ValidatingResolver.processFindKey(ValidatingResolver.java:779)
    at org.jitsi.dnssec.validator.ValidatingResolver.prepareFindKey(ValidatingResolver.java:715)
    at org.jitsi.dnssec.validator.ValidatingResolver.validateAnswerAndGetWildcards(ValidatingResolver.java:390)
    at org.jitsi.dnssec.validator.ValidatingResolver.validatePositiveResponse(ValidatingResolver.java:257)
    at org.jitsi.dnssec.validator.ValidatingResolver.processValidate(ValidatingResolver.java:1047)
    at org.jitsi.dnssec.validator.ValidatingResolver.send(ValidatingResolver.java:1236)
    at org.jitsi.dnssec.Example.sendAndPrint(Example.java:37)
    at org.jitsi.dnssec.Example.main(Example.java:31)
Habbie commented 5 years ago

https://github.com/dblacka/jdnssec-tools/pull/4 might be of interest.

gryphius commented 5 years ago

I tried out @Habbie s patch in dnsjava by simply replacing ECDSASignaturefromDNS with his fixed convertECDSASignature. This makes my test program happily validate the .ch DNSKEY RRSET with current java(1.8.0_201) again.

https://github.com/gryphius/dnsjava/commit/b4216b35a8386cf47e2c59a875c655d584624d1d

My test case:

package sigbugtest;

import org.xbill.DNS.DNSKEYRecord;
import org.xbill.DNS.DNSSEC;
import org.xbill.DNS.RRSIGRecord;
import org.xbill.DNS.RRset;
import org.xbill.DNS.Name;
import org.xbill.DNS.Record;
import org.xbill.DNS.Type;
import org.xbill.DNS.DClass;

public class SigBug {

    public static void main(String[] args) throws Exception {
        RRset rrset = new RRset();
        Record ksk = Record.fromString(Name.fromString("ch."), Type.DNSKEY, DClass.IN, 3600l,
                "257 3 13 Cm86XmSSO2FbG/3i9I++7HrRGNa1hNBZ1P7Y38Rg8uUz4YsKWSahAifo yaNMFWUu32VFj5xJQOEjqkrwD3Decw==",
                Name.fromString("ch."));
        rrset.addRR(Record.fromString(Name.fromString("ch."), Type.DNSKEY, DClass.IN, 3600l,
                "256 3 13 Qv739sZhsOAXaYY+2k0ZRr24bvi3Aae0w4JcYds9NQVp+qZbDFIWDMbB rjmELzgpAIXvdfoZScm7VD8iMrlnJQ==",
                Name.fromString("ch.")));
        rrset.addRR(ksk);
        rrset.addRR(Record.fromString(Name.fromString("ch."), Type.DNSKEY, DClass.IN, 3600l,
                "256 3 13 c/8Ej2lq1l1r/tCXl90QWJKIPGLRzwp3dTWAAw8BwsC5Ya9rBzZupYWU fY3aLGl5k8qbRcNXxacINKkWv8ahfA==",
                Name.fromString("ch.")));

        RRSIGRecord rrsig = (RRSIGRecord) Record.fromString(Name.fromString("ch."), Type.RRSIG, DClass.IN, 3600l,
                "DNSKEY 13 1 86400 20190307100909 20190120090909 11896 ch. RNSzPMRKwopYI3vwbwdpWulDrBYMn6Aappw4KXKEpUgAF9vb8DDF0GHY B5v4Af7zMTRgBoGFoPTxmjmBPJAMzA==",
                Name.fromString("ch."));

        DNSSEC.verify(rrset, rrsig, (DNSKEYRecord) ksk);
        System.out.println("SIG VERIFICATION OK");
    }

}

older java ( 1.8.0_111 ) + unpatched dnsjava validates ok current java + unpatched dnsjava fails current java + patched dnsjava validates ok

ibauersachs commented 5 years ago

@gryphius / @habbie could you please forward that patch to the dnsjava mailing list (dnsjava-users@lists.sourceforge.net) and ask Brian to do a release?

ralfhauser commented 5 years ago

reported to https://sourceforge.net/p/dnsjava/bugs/64/

primetomas commented 5 years ago

I can confirm that we tested this patch and it works for us.

ralfhauser commented 5 years ago

Due to multiple non-response to https://sourceforge.net/p/dnsjava/bugs/64/

https://github.com/xbill-dns/dns has been created to fix the above.

If you fix the problem on sf.net or are willing to continue maintaining this good software on github, it's all your's!

mwullink commented 5 years ago

this fix is great, it fixed my problems with the ECDSA signature. too bad this fix is not included in the original dnsjava project.

ibauersachs commented 5 years ago

@mwullink so far, nobody has submitted a patch to the dnsjava mailing list.

ralfhauser commented 5 years ago

@ibauersachs but a pull request https://github.com/dnsjava/dnsjava/pull/17 - isn't that even more effective than a patch ?

mwullink commented 5 years ago

The maintainer of dnsjava says he has no plans to work on the project in the near future.

https://sourceforge.net/p/dnsjava/discussion/57043/thread/132c7639a4/?limit=25#eaf6