From b4216b35a8386cf47e2c59a875c655d584624d1d Mon Sep 17 00:00:00 2001 From: Oli Schacher Date: Wed, 23 Jan 2019 19:42:34 +0100 Subject: [PATCH] use jdnssec-tools patch for leading zeroes padding --- org/xbill/DNS/DNSSEC.java | 102 +++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 40 deletions(-) diff --git a/org/xbill/DNS/DNSSEC.java b/org/xbill/DNS/DNSSEC.java index 23b764f2e..c9f9c9aa4 100644 --- a/org/xbill/DNS/DNSSEC.java +++ b/org/xbill/DNS/DNSSEC.java @@ -775,42 +775,67 @@ private static class ECKeyInfo { return signature; } -private static byte [] -ECDSASignaturefromDNS(byte [] signature, ECKeyInfo keyinfo) - throws DNSSECException, IOException -{ - if (signature.length != keyinfo.length * 2) - throw new SignatureVerificationException(); - - DNSInput in = new DNSInput(signature); - DNSOutput out = new DNSOutput(); - - byte [] r = in.readByteArray(keyinfo.length); - int rlen = keyinfo.length; - if (r[0] < 0) - rlen++; - - byte [] s = in.readByteArray(keyinfo.length); - int slen = keyinfo.length; - if (s[0] < 0) - slen++; - - out.writeU8(ASN1_SEQ); - out.writeU8(rlen + slen + 4); - - out.writeU8(ASN1_INT); - out.writeU8(rlen); - if (rlen > keyinfo.length) - out.writeU8(0); - out.writeByteArray(r); - - out.writeU8(ASN1_INT); - out.writeU8(slen); - if (slen > keyinfo.length) - out.writeU8(0); - out.writeByteArray(s); - return out.toByteArray(); +/** + * Convert a DNS standard ECDSA signature (defined in RFC 6605) into a + * JCE standard ECDSA signature, which is encoded in ASN.1. + * + * The format of the ASN.1 signature is + * + * ASN1_SEQ . seq_length . ASN1_INT . r_length . R . ANS1_INT . s_length . S + * + * where R and S may have a leading zero byte if without it the values would + * be negative. + * + * The format of the DNSSEC signature is just R . S where R and S are both + * exactly "length" bytes. + * + * @param signature + * The binary signature data from an RRSIG record. + * @return signature data that may be used in a JCE Signature object for + * verification purposes. + */ +public static byte[] convertECDSASignature(byte[] signature) +{ + byte r_src_pos, r_src_len, r_pad, s_src_pos, s_src_len, s_pad, len; + + r_src_len = s_src_len = (byte) (signature.length / 2); + r_src_pos = 0; r_pad = 0; + s_src_pos = (byte) (r_src_pos + r_src_len); s_pad = 0; + len = (byte) (6 + r_src_len + s_src_len); + + // leading zeroes are forbidden + if (signature[r_src_pos] == 0) { + r_src_pos++; r_src_len--; len--; + } + if (signature[s_src_pos] == 0) { + s_src_pos++; s_src_len--; len--; + } + + // except when they are mandatory + if (signature[r_src_pos] < 0) { + r_pad = 1; len++; + } + if (signature[s_src_pos] < 0) { + s_pad = 1; len++; + } + byte[] sig = new byte[len]; + byte pos = 0; + + sig[pos++] = ASN1_SEQ; + sig[pos++] = (byte) (len - 2); + sig[pos++] = ASN1_INT; + sig[pos++] = (byte) (r_src_len + r_pad); + pos += r_pad; + System.arraycopy(signature, r_src_pos, sig, pos, r_src_len); + pos += r_src_len; + + sig[pos++] = ASN1_INT; + sig[pos++] = (byte) (s_src_len + s_pad); + pos += s_pad; + System.arraycopy(signature, s_src_pos, sig, pos, s_src_len); + + return sig; } private static byte [] @@ -869,13 +894,10 @@ private static class ECKeyInfo { GOST); break; case Algorithm.ECDSAP256SHA256: - signature = ECDSASignaturefromDNS(signature, - ECDSA_P256); - break; case Algorithm.ECDSAP384SHA384: - signature = ECDSASignaturefromDNS(signature, - ECDSA_P384); + signature = convertECDSASignature(signature); break; + default: throw new UnsupportedAlgorithmException(alg); }