Now able to generated alg 15 keypairs

They _look_ correct, but may not be.
This commit is contained in:
David Blacka 2018-07-15 00:54:10 +00:00
parent 7706b73d8c
commit a9353b3af3
3 changed files with 152 additions and 32 deletions

View File

@ -1,11 +1,11 @@
/* /*
* $Id$ * $Id$
* *
* Copyright (c) 2006 VeriSign. All rights reserved. * Copyright (c) 2006 VeriSign. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in * this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of * binary form must reproduce the above copyright notice, this list of
@ -13,7 +13,7 @@
* materials provided with the distribution. 3. The name of the author may not * materials provided with the distribution. 3. The name of the author may not
* be used to endorse or promote products derived from this software without * be used to endorse or promote products derived from this software without
* specific prior written permission. * specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
@ -24,7 +24,7 @@
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
*/ */
package com.verisignlabs.dnssec.security; package com.verisignlabs.dnssec.security;
@ -47,12 +47,12 @@ import net.i2p.crypto.eddsa.spec.*;
/** /**
* This class handles translating DNS signing algorithm identifiers into various * This class handles translating DNS signing algorithm identifiers into various
* usable java implementations. * usable java implementations.
* *
* Besides centralizing the logic surrounding matching a DNSKEY algorithm * Besides centralizing the logic surrounding matching a DNSKEY algorithm
* identifier with various crypto implementations, it also handles algorithm * identifier with various crypto implementations, it also handles algorithm
* aliasing -- that is, defining a new algorithm identifier to be equivalent to * aliasing -- that is, defining a new algorithm identifier to be equivalent to
* an existing identifier. * an existing identifier.
* *
* @author David Blacka (orig) * @author David Blacka (orig)
* @author $Author: davidb $ (latest) * @author $Author: davidb $ (latest)
* @version $Revision: 2098 $ * @version $Revision: 2098 $
@ -265,7 +265,6 @@ public class DnsKeyAlgorithm
} }
EdAlgEntry entry = new EdAlgEntry(algorithm, sigName, baseType, ed_spec); EdAlgEntry entry = new EdAlgEntry(algorithm, sigName, baseType, ed_spec);
mAlgorithmMap.put(algorithm, entry); mAlgorithmMap.put(algorithm, entry);
} }
@ -451,7 +450,7 @@ public class DnsKeyAlgorithm
/** /**
* Translate a possible algorithm alias back to the original DNSSEC algorithm * Translate a possible algorithm alias back to the original DNSSEC algorithm
* number * number
* *
* @param algorithm * @param algorithm
* a DNSSEC algorithm that may be an alias. * a DNSSEC algorithm that may be an alias.
* @return -1 if the algorithm isn't recognised, the orignal algorithm number * @return -1 if the algorithm isn't recognised, the orignal algorithm number
@ -466,7 +465,7 @@ public class DnsKeyAlgorithm
/** /**
* Test if a given algorithm is supported. * Test if a given algorithm is supported.
* *
* @param algorithm The DNSSEC algorithm number. * @param algorithm The DNSSEC algorithm number.
* @return true if the algorithm is a recognized and supported algorithm or alias. * @return true if the algorithm is a recognized and supported algorithm or alias.
*/ */
@ -479,7 +478,7 @@ public class DnsKeyAlgorithm
/** /**
* Given an algorithm mnemonic, convert the mnemonic to a DNSSEC algorithm * Given an algorithm mnemonic, convert the mnemonic to a DNSSEC algorithm
* number. * number.
* *
* @param s * @param s
* The mnemonic string. This is case-insensitive. * The mnemonic string. This is case-insensitive.
* @return -1 if the mnemonic isn't recognized or supported, the algorithm * @return -1 if the mnemonic isn't recognized or supported, the algorithm
@ -494,7 +493,7 @@ public class DnsKeyAlgorithm
/** /**
* Given a DNSSEC algorithm number, return the "preferred" mnemonic. * Given a DNSSEC algorithm number, return the "preferred" mnemonic.
* *
* @param algorithm * @param algorithm
* A DNSSEC algorithm number. * A DNSSEC algorithm number.
* @return The preferred mnemonic string, or null if not supported or * @return The preferred mnemonic string, or null if not supported or

View File

@ -36,6 +36,11 @@ import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec; import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPrivateKeySpec; import javax.crypto.spec.DHPrivateKeySpec;
// For now, just import the native EdDSA classes
import net.i2p.crypto.eddsa.EdDSAPublicKey;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.spec.*;
import org.xbill.DNS.DNSKEYRecord; import org.xbill.DNS.DNSKEYRecord;
import org.xbill.DNS.DNSSEC; import org.xbill.DNS.DNSSEC;
import org.xbill.DNS.DNSSEC.DNSSECException; import org.xbill.DNS.DNSSEC.DNSSECException;
@ -45,7 +50,7 @@ import org.xbill.DNS.utils.base64;
/** /**
* This class handles conversions between JCA key formats and DNSSEC and BIND9 * This class handles conversions between JCA key formats and DNSSEC and BIND9
* key formats. * key formats.
* *
* @author David Blacka (original) * @author David Blacka (original)
* @author $Author$ (latest) * @author $Author$ (latest)
* @version $Revision$ * @version $Revision$
@ -56,16 +61,17 @@ public class DnsKeyConverter
private KeyFactory mDSAKeyFactory; private KeyFactory mDSAKeyFactory;
private KeyFactory mDHKeyFactory; private KeyFactory mDHKeyFactory;
private KeyFactory mECKeyFactory; private KeyFactory mECKeyFactory;
private KeyFactory mEdKeyFactory;
private DnsKeyAlgorithm mAlgorithms; private DnsKeyAlgorithm mAlgorithms;
public DnsKeyConverter() public DnsKeyConverter()
{ {
mAlgorithms = DnsKeyAlgorithm.getInstance(); mAlgorithms = DnsKeyAlgorithm.getInstance();
} }
/** /**
* Given a DNS KEY record, return the JCA public key * Given a DNS KEY record, return the JCA public key
* *
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
*/ */
public PublicKey parseDNSKEYRecord(DNSKEYRecord pKeyRecord) public PublicKey parseDNSKEYRecord(DNSKEYRecord pKeyRecord)
@ -89,8 +95,20 @@ public class DnsKeyConverter
pKeyRecord.getKey()); pKeyRecord.getKey());
} }
// do not rely on DNSJava's method for EdDSA for now.
if (mAlgorithms.baseType(originalAlgorithm) == DnsKeyAlgorithm.EDDSA)
{
try {
return parseEdDSADNSKEYRecord(pKeyRecord);
} catch (InvalidKeySpecException e) {
// just to be expedient, recast this as a NoSuchAlgorithmException.
throw new NoSuchAlgorithmException(e.getMessage());
}
}
try try
{ {
// This uses DNSJava's DNSSEC.toPublicKey() method.
return pKeyRecord.getPublicKey(); return pKeyRecord.getPublicKey();
} }
catch (DNSSECException e) catch (DNSSECException e)
@ -99,6 +117,19 @@ public class DnsKeyConverter
} }
} }
/** Since we don't (yet) have support in DNSJava for parsing the
newer EdDSA algorithms, here is a local version. */
private PublicKey parseEdDSADNSKEYRecord(DNSKEYRecord pKeyRecord)
throws IllegalArgumentException, NoSuchAlgorithmException, InvalidKeySpecException
{
EdDSAPublicKeySpec spec = new EdDSAPublicKeySpec
(pKeyRecord.getKey(), mAlgorithms.getEdwardsCurveParams(pKeyRecord.getAlgorithm()));
KeyFactory factory = KeyFactory.getInstance("EdDSA");
return factory.generatePublic(spec);
}
/** /**
* Given a JCA public key and the ancillary data, generate a DNSKEY record. * Given a JCA public key and the ancillary data, generate a DNSKEY record.
*/ */
@ -107,6 +138,9 @@ public class DnsKeyConverter
{ {
try try
{ {
if (mAlgorithms.baseType(alg) == DnsKeyAlgorithm.EDDSA) {
return generateEdDSADNSKEYRecord(name, dclass, ttl, flags, alg, key);
}
return new DNSKEYRecord(name, dclass, ttl, flags, DNSKEYRecord.Protocol.DNSSEC, alg, return new DNSKEYRecord(name, dclass, ttl, flags, DNSKEYRecord.Protocol.DNSSEC, alg,
key); key);
} }
@ -117,6 +151,14 @@ public class DnsKeyConverter
} }
} }
private DNSKEYRecord generateEdDSADNSKEYRecord(Name name, int dclass, long ttl,
int flags, int alg, PublicKey key)
{
EdDSAPublicKey ed_key = (EdDSAPublicKey) key;
return new DNSKEYRecord(name, dclass, ttl, flags, DNSKEYRecord.Protocol.DNSSEC, alg,
ed_key.getEncoded());
}
// Private Key Specific Parsing routines // Private Key Specific Parsing routines
/** /**
@ -204,6 +246,8 @@ public class DnsKeyConverter
return parsePrivateECDSA(lines, alg); return parsePrivateECDSA(lines, alg);
case DnsKeyAlgorithm.ECDSA: case DnsKeyAlgorithm.ECDSA:
return parsePrivateECDSA(lines, alg); return parsePrivateECDSA(lines, alg);
case DnsKeyAlgorithm.EDDSA:
return parsePrivateEdDSA(lines, alg);
default: default:
throw new IOException("unsupported private key algorithm: " + val); throw new IOException("unsupported private key algorithm: " + val);
} }
@ -230,7 +274,7 @@ public class DnsKeyConverter
/** /**
* Given the rest of the RSA BIND9 string format private key, parse and * Given the rest of the RSA BIND9 string format private key, parse and
* translate into a JCA private key * translate into a JCA private key
* *
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
* if the RSA algorithm is not available. * if the RSA algorithm is not available.
*/ */
@ -319,7 +363,7 @@ public class DnsKeyConverter
/** /**
* Given the remaining lines in a BIND9 style DH private key, parse the key * Given the remaining lines in a BIND9 style DH private key, parse the key
* info and translate it into a JCA private key. * info and translate it into a JCA private key.
* *
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
* if the DH algorithm is not available. * if the DH algorithm is not available.
*/ */
@ -375,7 +419,7 @@ public class DnsKeyConverter
/** /**
* Given the remaining lines in a BIND9 style DSA private key, parse the key * Given the remaining lines in a BIND9 style DSA private key, parse the key
* info and translate it into a JCA private key. * info and translate it into a JCA private key.
* *
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
* if the DSA algorithm is not available. * if the DSA algorithm is not available.
*/ */
@ -487,6 +531,60 @@ public class DnsKeyConverter
} }
} }
/**
* Given the remaining lines in a BIND9-style ECDSA private key, parse the key
* info and translate it into a JCA private key object.
* @param lines The remaining lines in a private key file (after
* @throws NoSuchAlgorithmException
* If elliptic curve is not available.
*/
private PrivateKey parsePrivateEdDSA(StringTokenizer lines, int algorithm)
throws NoSuchAlgorithmException
{
BigInteger s = null;
while (lines.hasMoreTokens())
{
String line = lines.nextToken();
if (line == null) continue;
if (line.startsWith("#")) continue;
String val = value(line);
if (val == null) continue;
byte[] data = base64.fromString(val);
if (line.startsWith("PrivateKey: "))
{
s = new BigInteger(1, data);
}
}
if (mEdKeyFactory == null)
{
mEdKeyFactory = KeyFactory.getInstance("EdDSA");
}
EdDSAParameterSpec ed_spec = mAlgorithms.getEdwardsCurveParams(algorithm);
if (ed_spec == null)
{
throw new NoSuchAlgorithmException("DNSSEC algorithm " + algorithm +
" is not a recognized Edwards Curve algorithm");
}
KeySpec spec = new EdDSAPrivateKeySpec(s.toByteArray(), ed_spec);
try
{
return mEdKeyFactory.generatePrivate(spec);
}
catch (InvalidKeySpecException e)
{
e.printStackTrace();
return null;
}
}
/** /**
* Given a private key and public key, generate the BIND9 style private key * Given a private key and public key, generate the BIND9 style private key
* format. * format.
@ -509,6 +607,11 @@ public class DnsKeyConverter
{ {
return generatePrivateEC((ECPrivateKey) priv, (ECPublicKey) pub, alg); return generatePrivateEC((ECPrivateKey) priv, (ECPublicKey) pub, alg);
} }
else if (priv instanceof EdDSAPrivateKey && pub instanceof EdDSAPublicKey)
{
return generatePrivateED((EdDSAPrivateKey) priv, (EdDSAPublicKey) pub, alg);
}
return null; return null;
} }
@ -630,4 +733,22 @@ public class DnsKeyConverter
return sw.toString(); return sw.toString();
} }
/**
* Given an edwards curve key pair, and the actual algorithm (which will
* describe the curve used), return the BIND9-style text encoding.
*/
private String generatePrivateED(EdDSAPrivateKey priv, EdDSAPublicKey pub, int alg)
{
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
out.println("Private-key-format: v1.2");
out.println("Algorithm: " + alg + " (" + mAlgorithms.algToString(alg)
+ ")");
out.print("PrivateKey: ");
out.println(base64.toString(priv.geta()));
return sw.toString();
}
} }

View File

@ -38,11 +38,11 @@ import org.xbill.DNS.utils.hexdump;
/** /**
* This class contains routines for signing DNS zones. * This class contains routines for signing DNS zones.
* *
* In particular, it contains both an ability to sign an individual RRset and * In particular, it contains both an ability to sign an individual RRset and
* the ability to sign an entire zone. It primarily glues together the more * the ability to sign an entire zone. It primarily glues together the more
* basic primitives found in {@link SignUtils}. * basic primitives found in {@link SignUtils}.
* *
* @author David Blacka (original) * @author David Blacka (original)
* @author $Author$ * @author $Author$
* @version $Revision$ * @version $Revision$
@ -69,7 +69,7 @@ public class JCEDnsSecSigner
/** /**
* Cryptographically generate a new DNSSEC key. * Cryptographically generate a new DNSSEC key.
* *
* @param owner * @param owner
* the KEY RR's owner name. * the KEY RR's owner name.
* @param ttl * @param ttl
@ -114,7 +114,7 @@ public class JCEDnsSecSigner
/** /**
* Sign an RRset. * Sign an RRset.
* *
* @param rrset * @param rrset
* the RRset to sign -- any existing signatures are ignored. * the RRset to sign -- any existing signatures are ignored.
* @param keypars * @param keypars
@ -211,7 +211,7 @@ public class JCEDnsSecSigner
/** /**
* Create a completely self-signed DNSKEY RRset. * Create a completely self-signed DNSKEY RRset.
* *
* @param keypairs * @param keypairs
* the public & private keypairs to use in the keyset. * the public & private keypairs to use in the keyset.
* @param start * @param start
@ -244,7 +244,7 @@ public class JCEDnsSecSigner
/** /**
* Conditionally sign an RRset and add it to the toList. * Conditionally sign an RRset and add it to the toList.
* *
* @param toList * @param toList
* the list to which we are adding the processed RRsets. * the list to which we are adding the processed RRsets.
* @param zonename * @param zonename
@ -263,7 +263,7 @@ public class JCEDnsSecSigner
* if true, sign the zone apex keyset with both KSKs and ZSKs. * if true, sign the zone apex keyset with both KSKs and ZSKs.
* @param last_cut * @param last_cut
* the name of the last delegation point encountered. * the name of the last delegation point encountered.
* *
* @return the name of the new last_cut. * @return the name of the new last_cut.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -324,7 +324,7 @@ public class JCEDnsSecSigner
* signing variants (NSEC with or without Opt-In, NSEC3 with or without * signing variants (NSEC with or without Opt-In, NSEC3 with or without
* Opt-Out, etc.) External users of this class are expected to use the * Opt-Out, etc.) External users of this class are expected to use the
* appropriate public signZone* methods instead of this. * appropriate public signZone* methods instead of this.
* *
* @param zonename * @param zonename
* The name of the zone * The name of the zone
* @param records * @param records
@ -363,7 +363,7 @@ public class JCEDnsSecSigner
* values will use the SOA TTL. * values will use the SOA TTL.
* @return an ordered list of {@link org.xbill.DNS.Record} objects, * @return an ordered list of {@link org.xbill.DNS.Record} objects,
* representing the signed zone. * representing the signed zone.
* *
* @throws IOException * @throws IOException
* @throws GeneralSecurityException * @throws GeneralSecurityException
*/ */
@ -459,7 +459,7 @@ public class JCEDnsSecSigner
/** /**
* Given a zone, sign it using standard NSEC records. * Given a zone, sign it using standard NSEC records.
* *
* @param zonename * @param zonename
* The name of the zone. * The name of the zone.
* @param records * @param records
@ -478,7 +478,7 @@ public class JCEDnsSecSigner
* the key signing keys). * the key signing keys).
* @param ds_digest_alg * @param ds_digest_alg
* The digest algorithm to use when generating DS records. * The digest algorithm to use when generating DS records.
* *
* @return an ordered list of {@link org.xbill.DNS.Record} objects, * @return an ordered list of {@link org.xbill.DNS.Record} objects,
* representing the signed zone. * representing the signed zone.
*/ */
@ -494,7 +494,7 @@ public class JCEDnsSecSigner
/** /**
* Given a zone, sign it using NSEC3 records. * Given a zone, sign it using NSEC3 records.
* *
* @param signer * @param signer
* A signer (utility) object used to actually sign stuff. * A signer (utility) object used to actually sign stuff.
* @param zonename * @param zonename
@ -529,7 +529,7 @@ public class JCEDnsSecSigner
* values will use the SOA TTL. * values will use the SOA TTL.
* @return an ordered list of {@link org.xbill.DNS.Record} objects, * @return an ordered list of {@link org.xbill.DNS.Record} objects,
* representing the signed zone. * representing the signed zone.
* *
* @throws IOException * @throws IOException
* @throws GeneralSecurityException * @throws GeneralSecurityException
*/ */
@ -558,7 +558,7 @@ public class JCEDnsSecSigner
/** /**
* Given a zone, sign it using experimental Opt-In NSEC records (see RFC * Given a zone, sign it using experimental Opt-In NSEC records (see RFC
* 4956). * 4956).
* *
* @param zonename * @param zonename
* the name of the zone. * the name of the zone.
* @param records * @param records