remove ECC-GOST, add new DS algorithms (#18)
This commit is contained in:
parent
1727d7c7d8
commit
1406cd2e68
@ -1,3 +1,12 @@
|
|||||||
|
2024-04-13 David Blacka <david@blacka.com>
|
||||||
|
|
||||||
|
* Remove support for ECC_GOST
|
||||||
|
* Create a new DSAlgorithm class, move DS creation into that
|
||||||
|
* Add support for DS algorithms 3 and 4 -- bouncycastle crypto
|
||||||
|
provider used for DS algoirthm 3 (GOST R 34.11-94)
|
||||||
|
* Moved support for loading the bouncycastle provider to the new
|
||||||
|
DSAlgorithm class
|
||||||
|
|
||||||
2024-04-07 David Blacka <david@blacka.com>
|
2024-04-07 David Blacka <david@blacka.com>
|
||||||
|
|
||||||
* Released version 0.20
|
* Released version 0.20
|
||||||
|
@ -22,16 +22,14 @@ import java.io.IOException;
|
|||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
import org.apache.commons.cli.Option;
|
import org.apache.commons.cli.Option;
|
||||||
import org.xbill.DNS.CDSRecord;
|
|
||||||
import org.xbill.DNS.DLVRecord;
|
|
||||||
import org.xbill.DNS.DNSKEYRecord;
|
import org.xbill.DNS.DNSKEYRecord;
|
||||||
import org.xbill.DNS.DNSSEC;
|
import org.xbill.DNS.DNSSEC;
|
||||||
import org.xbill.DNS.DSRecord;
|
import org.xbill.DNS.DSRecord;
|
||||||
import org.xbill.DNS.Record;
|
import org.xbill.DNS.Record;
|
||||||
|
|
||||||
import com.verisignlabs.dnssec.security.BINDKeyUtils;
|
import com.verisignlabs.dnssec.security.BINDKeyUtils;
|
||||||
|
import com.verisignlabs.dnssec.security.DSAlgorithm;
|
||||||
import com.verisignlabs.dnssec.security.DnsKeyPair;
|
import com.verisignlabs.dnssec.security.DnsKeyPair;
|
||||||
import com.verisignlabs.dnssec.security.SignUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class forms the command line implementation of a DNSSEC DS/DLV generator
|
* This class forms the command line implementation of a DNSSEC DS/DLV generator
|
||||||
@ -59,7 +57,6 @@ public class DSTool extends CLBase {
|
|||||||
* state.
|
* state.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up the command line options.
|
* Set up the command line options.
|
||||||
*
|
*
|
||||||
@ -68,8 +65,11 @@ public class DSTool extends CLBase {
|
|||||||
protected void setupOptions() {
|
protected void setupOptions() {
|
||||||
opts.addOption(Option.builder("D").longOpt("dlv").desc("Generate a DLV record instead.").build());
|
opts.addOption(Option.builder("D").longOpt("dlv").desc("Generate a DLV record instead.").build());
|
||||||
opts.addOption(Option.builder("C").longOpt("cds").desc("Generate a CDS record instead").build());
|
opts.addOption(Option.builder("C").longOpt("cds").desc("Generate a CDS record instead").build());
|
||||||
|
String[] algStrings = DSAlgorithm.getInstance().supportedAlgorithmMnemonics();
|
||||||
|
String algStringSet = String.join(" | ", algStrings);
|
||||||
opts.addOption(
|
opts.addOption(
|
||||||
Option.builder("d").hasArg().argName("id").longOpt("digest").desc("The digest algorithm to use").build());
|
Option.builder("d").hasArg().argName("id").longOpt("digest").desc(algStringSet + ": default is SHA256")
|
||||||
|
.build());
|
||||||
opts.addOption(Option.builder("f").hasArg().argName("file").longOpt("output").desc("output to file").build());
|
opts.addOption(Option.builder("f").hasArg().argName("file").longOpt("output").desc("output to file").build());
|
||||||
opts.addOption(Option.builder("T").longOpt("ttl").hasArg().desc("TTL to use for generated DS/CDS record").build());
|
opts.addOption(Option.builder("T").longOpt("ttl").hasArg().desc("TTL to use for generated DS/CDS record").build());
|
||||||
}
|
}
|
||||||
@ -99,6 +99,7 @@ public class DSTool extends CLBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void createDS(String keyname) throws IOException {
|
public void createDS(String keyname) throws IOException {
|
||||||
|
DSAlgorithm dsAlgorithm = DSAlgorithm.getInstance();
|
||||||
DnsKeyPair key = BINDKeyUtils.loadKey(keyname, null);
|
DnsKeyPair key = BINDKeyUtils.loadKey(keyname, null);
|
||||||
DNSKEYRecord dnskey = key.getDNSKEYRecord();
|
DNSKEYRecord dnskey = key.getDNSKEYRecord();
|
||||||
|
|
||||||
@ -107,21 +108,17 @@ public class DSTool extends CLBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
long ttl = dsTTL < 0 ? dnskey.getTTL() : dsTTL;
|
long ttl = dsTTL < 0 ? dnskey.getTTL() : dsTTL;
|
||||||
DSRecord ds = SignUtils.calculateDSRecord(dnskey, digestId, ttl);
|
DSRecord ds = dsAlgorithm.calculateDSRecord(dnskey, digestId, ttl);
|
||||||
Record res;
|
Record res;
|
||||||
|
|
||||||
switch (createType) {
|
switch (createType) {
|
||||||
case DLV:
|
case DLV:
|
||||||
log.fine("creating DLV.");
|
log.fine("creating DLV.");
|
||||||
DLVRecord dlv = new DLVRecord(ds.getName(), ds.getDClass(), ds.getTTL(), ds.getFootprint(), ds.getAlgorithm(),
|
res = dsAlgorithm.dsToDLV(ds);
|
||||||
ds.getDigestID(), ds.getDigest());
|
|
||||||
res = dlv;
|
|
||||||
break;
|
break;
|
||||||
case CDS:
|
case CDS:
|
||||||
log.fine("creating CDS.");
|
log.fine("creating CDS.");
|
||||||
CDSRecord cds = new CDSRecord(ds.getName(), ds.getDClass(), ds.getTTL(), ds.getFootprint(), ds.getAlgorithm(),
|
res = dsAlgorithm.dstoCDS(ds);
|
||||||
ds.getDClass(), ds.getDigest());
|
|
||||||
res = cds;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
res = ds;
|
res = ds;
|
||||||
@ -138,7 +135,7 @@ public class DSTool extends CLBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void execute() throws Exception {
|
public void execute() throws Exception {
|
||||||
for (String keyname : keynames){
|
for (String keyname : keynames) {
|
||||||
createDS(keyname);
|
createDS(keyname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ public class KeyGen extends CLBase {
|
|||||||
String[] algStrings = DnsKeyAlgorithm.getInstance().supportedAlgMnemonics();
|
String[] algStrings = DnsKeyAlgorithm.getInstance().supportedAlgMnemonics();
|
||||||
String algStringSet = String.join(" | ", algStrings);
|
String algStringSet = String.join(" | ", algStrings);
|
||||||
opts.addOption(Option.builder("a").hasArg().argName("algorithm")
|
opts.addOption(Option.builder("a").hasArg().argName("algorithm")
|
||||||
.desc(algStringSet + " | alias, ECDSAP256SHA256 is default.").build());
|
.desc(algStringSet + " | aliases, ECDSAP256SHA256 is default.").build());
|
||||||
|
|
||||||
opts.addOption(Option.builder("b").hasArg().argName("size").desc(
|
opts.addOption(Option.builder("b").hasArg().argName("size").desc(
|
||||||
"key size, in bits (default 2048). RSA: [512..4096], DSA: [512..1024], DH: [128..4096], ECDSA: ignored, EdDSA: ignored")
|
"key size, in bits (default 2048). RSA: [512..4096], DSA: [512..1024], DH: [128..4096], ECDSA: ignored, EdDSA: ignored")
|
||||||
|
@ -134,8 +134,7 @@ public class BINDKeyUtils {
|
|||||||
public static DnsKeyPair loadKeyPair(String keyFileBasePath, File inDirectory)
|
public static DnsKeyPair loadKeyPair(String keyFileBasePath, File inDirectory)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
keyFileBasePath = fixKeyFileBasePath(keyFileBasePath);
|
keyFileBasePath = fixKeyFileBasePath(keyFileBasePath);
|
||||||
// FIXME: should we throw the IOException when one of the files
|
|
||||||
// cannot be found, or just when both cannot be found?
|
|
||||||
File publicKeyFile = new File(inDirectory, keyFileBasePath + ".key");
|
File publicKeyFile = new File(inDirectory, keyFileBasePath + ".key");
|
||||||
File privateKeyFile = new File(inDirectory, keyFileBasePath + ".private");
|
File privateKeyFile = new File(inDirectory, keyFileBasePath + ".private");
|
||||||
|
|
||||||
@ -251,8 +250,6 @@ public class BINDKeyUtils {
|
|||||||
if (privateKeyString == null)
|
if (privateKeyString == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// FIXME: should this swallow exceptions or actually propagate
|
|
||||||
// them?
|
|
||||||
try {
|
try {
|
||||||
DnsKeyConverter conv = new DnsKeyConverter();
|
DnsKeyConverter conv = new DnsKeyConverter();
|
||||||
return conv.parsePrivateKeyString(privateKeyString);
|
return conv.parsePrivateKeyString(privateKeyString);
|
||||||
|
167
src/main/java/com/verisignlabs/dnssec/security/DSAlgorithm.java
Normal file
167
src/main/java/com/verisignlabs/dnssec/security/DSAlgorithm.java
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006, 2022 Verisign. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer. 2. Redistributions in
|
||||||
|
* binary form must reproduce the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer in the documentation and/or other
|
||||||
|
* 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
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||||
|
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.verisignlabs.dnssec.security;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.Provider;
|
||||||
|
import java.security.Security;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.xbill.DNS.CDSRecord;
|
||||||
|
import org.xbill.DNS.DLVRecord;
|
||||||
|
import org.xbill.DNS.DNSKEYRecord;
|
||||||
|
import org.xbill.DNS.DNSOutput;
|
||||||
|
import org.xbill.DNS.DNSSEC;
|
||||||
|
import org.xbill.DNS.DSRecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class handles the implementation behind converting DNSKEYs into
|
||||||
|
* DSRecords. It primarily exists to bootstrap whatever crypto libraries we
|
||||||
|
* might need to do so.
|
||||||
|
*
|
||||||
|
* @author David Blacka
|
||||||
|
*/
|
||||||
|
public class DSAlgorithm {
|
||||||
|
|
||||||
|
private Logger log = Logger.getLogger(this.getClass().toString());
|
||||||
|
|
||||||
|
HashSet<Integer> mSupportedAlgorithms = null;
|
||||||
|
|
||||||
|
private static DSAlgorithm mInstance = null;
|
||||||
|
|
||||||
|
public DSAlgorithm() {
|
||||||
|
mSupportedAlgorithms = new HashSet<>();
|
||||||
|
mSupportedAlgorithms.add(DNSSEC.Digest.SHA1);
|
||||||
|
mSupportedAlgorithms.add(DNSSEC.Digest.SHA256);
|
||||||
|
mSupportedAlgorithms.add(DNSSEC.Digest.SHA384);
|
||||||
|
// Attempt to add the bouncycastle provider. This is so we can use this
|
||||||
|
// provider if it is available, but not require the user to add it as one of
|
||||||
|
// the java.security providers.
|
||||||
|
try {
|
||||||
|
Class<?> bcProviderClass = Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
|
||||||
|
Provider bcProvider = (Provider) bcProviderClass.getDeclaredConstructor().newInstance();
|
||||||
|
Security.addProvider(bcProvider);
|
||||||
|
log.fine("bouncycastle crypto provider loaded");
|
||||||
|
mSupportedAlgorithms.add(DNSSEC.Digest.GOST3411);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
// do nothing, this is the normal case
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] supportedAlgorithmMnemonics() {
|
||||||
|
ArrayList<String> algs = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int digestId : mSupportedAlgorithms) {
|
||||||
|
algs.add(DNSSEC.Digest.string(digestId));
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] result = new String[algs.size()];
|
||||||
|
return algs.toArray(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a DNSKEY record, generate the DS record from it.
|
||||||
|
*
|
||||||
|
* @param keyrec the KEY record in question.
|
||||||
|
* @param digestAlg The digest algorithm (SHA-1, SHA-256, etc.).
|
||||||
|
* @param ttl the desired TTL for the generated DS record. If zero, or
|
||||||
|
* negative, the original KEY RR's TTL will be used.
|
||||||
|
* @return the corresponding {@link org.xbill.DNS.DSRecord}
|
||||||
|
*/
|
||||||
|
public DSRecord calculateDSRecord(DNSKEYRecord keyrec, int digestAlg, long ttl) {
|
||||||
|
if (keyrec == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (ttl <= 0)
|
||||||
|
ttl = keyrec.getTTL();
|
||||||
|
|
||||||
|
DNSOutput os = new DNSOutput();
|
||||||
|
|
||||||
|
os.writeByteArray(keyrec.getName().toWireCanonical());
|
||||||
|
os.writeByteArray(keyrec.rdataToWireCanonical());
|
||||||
|
|
||||||
|
try {
|
||||||
|
byte[] digest;
|
||||||
|
MessageDigest md;
|
||||||
|
|
||||||
|
switch (digestAlg) {
|
||||||
|
case DNSSEC.Digest.SHA1:
|
||||||
|
md = MessageDigest.getInstance("SHA");
|
||||||
|
digest = md.digest(os.toByteArray());
|
||||||
|
break;
|
||||||
|
case DNSSEC.Digest.SHA256:
|
||||||
|
md = MessageDigest.getInstance("SHA-256");
|
||||||
|
digest = md.digest(os.toByteArray());
|
||||||
|
break;
|
||||||
|
case DNSSEC.Digest.GOST3411:
|
||||||
|
// The standard Java crypto providers don't have this, but bouncycastle does
|
||||||
|
if (java.security.Security.getProviders("MessageDigest.GOST3411") != null) {
|
||||||
|
md = MessageDigest.getInstance("GOST3411");
|
||||||
|
digest = md.digest(os.toByteArray());
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unsupported digest id: " + digestAlg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DNSSEC.Digest.SHA384:
|
||||||
|
md = MessageDigest.getInstance("SHA-384");
|
||||||
|
digest = md.digest(os.toByteArray());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unknown digest id: " + digestAlg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DSRecord(keyrec.getName(), keyrec.getDClass(), ttl,
|
||||||
|
keyrec.getFootprint(), keyrec.getAlgorithm(), digestAlg,
|
||||||
|
digest);
|
||||||
|
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
log.severe(e.toString());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DLVRecord dsToDLV(DSRecord ds) {
|
||||||
|
return new DLVRecord(ds.getName(), ds.getDClass(), ds.getTTL(), ds.getFootprint(), ds.getAlgorithm(),
|
||||||
|
ds.getDigestID(), ds.getDigest());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CDSRecord dstoCDS(DSRecord ds) {
|
||||||
|
return new CDSRecord(ds.getName(), ds.getDClass(), ds.getTTL(), ds.getFootprint(), ds.getAlgorithm(),
|
||||||
|
ds.getDClass(), ds.getDigest());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DSAlgorithm getInstance() {
|
||||||
|
if (mInstance == null) {
|
||||||
|
mInstance = new DSAlgorithm();
|
||||||
|
}
|
||||||
|
return mInstance;
|
||||||
|
}
|
||||||
|
}
|
@ -27,20 +27,14 @@
|
|||||||
|
|
||||||
package com.verisignlabs.dnssec.security;
|
package com.verisignlabs.dnssec.security;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.security.AlgorithmParameters;
|
import java.security.AlgorithmParameters;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.KeyPairGenerator;
|
import java.security.KeyPairGenerator;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.Provider;
|
|
||||||
import java.security.Security;
|
|
||||||
import java.security.Signature;
|
import java.security.Signature;
|
||||||
import java.security.spec.ECFieldFp;
|
|
||||||
import java.security.spec.ECGenParameterSpec;
|
import java.security.spec.ECGenParameterSpec;
|
||||||
import java.security.spec.ECParameterSpec;
|
import java.security.spec.ECParameterSpec;
|
||||||
import java.security.spec.ECPoint;
|
|
||||||
import java.security.spec.EllipticCurve;
|
|
||||||
import java.security.spec.InvalidParameterSpecException;
|
import java.security.spec.InvalidParameterSpecException;
|
||||||
import java.security.spec.NamedParameterSpec;
|
import java.security.spec.NamedParameterSpec;
|
||||||
import java.security.spec.RSAKeyGenParameterSpec;
|
import java.security.spec.RSAKeyGenParameterSpec;
|
||||||
@ -73,7 +67,6 @@ public class DnsKeyAlgorithm {
|
|||||||
RSA,
|
RSA,
|
||||||
DH,
|
DH,
|
||||||
DSA,
|
DSA,
|
||||||
ECC_GOST,
|
|
||||||
ECDSA,
|
ECDSA,
|
||||||
EDDSA;
|
EDDSA;
|
||||||
}
|
}
|
||||||
@ -129,12 +122,8 @@ public class DnsKeyAlgorithm {
|
|||||||
private KeyPairGenerator mRSAKeyGenerator;
|
private KeyPairGenerator mRSAKeyGenerator;
|
||||||
/** This is a cached key pair generator for DSA keys. */
|
/** This is a cached key pair generator for DSA keys. */
|
||||||
private KeyPairGenerator mDSAKeyGenerator;
|
private KeyPairGenerator mDSAKeyGenerator;
|
||||||
/** This is a cached key pair generator for ECC GOST keys. */
|
|
||||||
private KeyPairGenerator mECGOSTKeyGenerator;
|
|
||||||
/** This is a cached key pair generator for ECDSA_P256 keys. */
|
/** This is a cached key pair generator for ECDSA_P256 keys. */
|
||||||
private KeyPairGenerator mECKeyGenerator;
|
private KeyPairGenerator mECKeyGenerator;
|
||||||
/** This is a cached key pair generator for EdDSA keys. */
|
|
||||||
private KeyPairGenerator mEdKeyGenerator;
|
|
||||||
|
|
||||||
private Logger log = Logger.getLogger(this.getClass().toString());
|
private Logger log = Logger.getLogger(this.getClass().toString());
|
||||||
|
|
||||||
@ -142,17 +131,6 @@ public class DnsKeyAlgorithm {
|
|||||||
private static DnsKeyAlgorithm mInstance = null;
|
private static DnsKeyAlgorithm mInstance = null;
|
||||||
|
|
||||||
public DnsKeyAlgorithm() {
|
public DnsKeyAlgorithm() {
|
||||||
// Attempt to add the bouncycastle provider. This is so we can use this
|
|
||||||
// provider if it is available, but not require the user to add it as one of
|
|
||||||
// the java.security providers.
|
|
||||||
try {
|
|
||||||
Class<?> bcProviderClass = Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
|
|
||||||
Provider bcProvider = (Provider) bcProviderClass.getDeclaredConstructor().newInstance();
|
|
||||||
Security.addProvider(bcProvider);
|
|
||||||
} catch (ReflectiveOperationException e) {
|
|
||||||
log.fine("Unable to load BC provider");
|
|
||||||
}
|
|
||||||
|
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,14 +167,6 @@ public class DnsKeyAlgorithm {
|
|||||||
addAlgorithm(DNSSEC.Algorithm.RSASHA512, "SHA512withRSA", BaseAlgorithm.RSA);
|
addAlgorithm(DNSSEC.Algorithm.RSASHA512, "SHA512withRSA", BaseAlgorithm.RSA);
|
||||||
addMnemonic("RSASHA512", DNSSEC.Algorithm.RSASHA512);
|
addMnemonic("RSASHA512", DNSSEC.Algorithm.RSASHA512);
|
||||||
|
|
||||||
// ECC-GOST is not supported by Java 1.8's Sun crypto provider. The
|
|
||||||
// bouncycastle.org provider, however, does support it.
|
|
||||||
// GostR3410-2001-CryptoPro-A is the named curve in the BC provider, but we
|
|
||||||
// will get the parameters directly.
|
|
||||||
addAlgorithm(DNSSEC.Algorithm.ECC_GOST, "GOST3411withECGOST3410", BaseAlgorithm.ECC_GOST, null);
|
|
||||||
addMnemonic("ECCGOST", DNSSEC.Algorithm.ECC_GOST);
|
|
||||||
addMnemonic("ECC-GOST", DNSSEC.Algorithm.ECC_GOST);
|
|
||||||
|
|
||||||
addAlgorithm(DNSSEC.Algorithm.ECDSAP256SHA256, "SHA256withECDSA", BaseAlgorithm.ECDSA, "secp256r1");
|
addAlgorithm(DNSSEC.Algorithm.ECDSAP256SHA256, "SHA256withECDSA", BaseAlgorithm.ECDSA, "secp256r1");
|
||||||
addMnemonic("ECDSAP256SHA256", DNSSEC.Algorithm.ECDSAP256SHA256);
|
addMnemonic("ECDSAP256SHA256", DNSSEC.Algorithm.ECDSAP256SHA256);
|
||||||
addMnemonic("ECDSA-P256", DNSSEC.Algorithm.ECDSAP256SHA256);
|
addMnemonic("ECDSA-P256", DNSSEC.Algorithm.ECDSAP256SHA256);
|
||||||
@ -226,9 +196,7 @@ public class DnsKeyAlgorithm {
|
|||||||
* library (SunEC).
|
* library (SunEC).
|
||||||
*/
|
*/
|
||||||
private void addECDSAAlgorithm(int algorithm, String sigName, String curveName) {
|
private void addECDSAAlgorithm(int algorithm, String sigName, String curveName) {
|
||||||
ECParameterSpec ecSpec = ECSpecFromAlgorithm(algorithm);
|
ECParameterSpec ecSpec = ECSpecFromName(curveName);
|
||||||
if (ecSpec == null)
|
|
||||||
ecSpec = ECSpecFromName(curveName);
|
|
||||||
if (ecSpec == null)
|
if (ecSpec == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -278,10 +246,15 @@ public class DnsKeyAlgorithm {
|
|||||||
* @param curveName the name of the curve.
|
* @param curveName the name of the curve.
|
||||||
*/
|
*/
|
||||||
private void addAlgorithm(int algorithm, String sigName, BaseAlgorithm baseType, String curveName) {
|
private void addAlgorithm(int algorithm, String sigName, BaseAlgorithm baseType, String curveName) {
|
||||||
if (baseType == BaseAlgorithm.ECDSA) {
|
switch (baseType) {
|
||||||
addECDSAAlgorithm(algorithm, sigName, curveName);
|
case ECDSA:
|
||||||
} else if (baseType == BaseAlgorithm.EDDSA) {
|
addECDSAAlgorithm(algorithm, sigName, curveName);
|
||||||
addEdDSAAlgorithm(algorithm, sigName, curveName);
|
break;
|
||||||
|
case EDDSA:
|
||||||
|
addEdDSAAlgorithm(algorithm, sigName, curveName);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Non-Ellipic curve algorithm passed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,25 +297,6 @@ public class DnsKeyAlgorithm {
|
|||||||
return mAlgorithmMap.get(alg);
|
return mAlgorithmMap.get(alg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For curves where we don't (or can't) get the parameters from a standard
|
|
||||||
// name, we can construct the parameters here. For now, we only do this for
|
|
||||||
// the ECC-GOST curve.
|
|
||||||
private ECParameterSpec ECSpecFromAlgorithm(int algorithm) {
|
|
||||||
if (algorithm == DNSSEC.Algorithm.ECC_GOST) {
|
|
||||||
// From RFC 4357 Section 11.4
|
|
||||||
BigInteger p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97", 16);
|
|
||||||
BigInteger a = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94", 16);
|
|
||||||
BigInteger b = new BigInteger("A6", 16);
|
|
||||||
BigInteger gx = new BigInteger("1", 16);
|
|
||||||
BigInteger gy = new BigInteger("8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14", 16);
|
|
||||||
BigInteger n = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893", 16);
|
|
||||||
|
|
||||||
EllipticCurve curve = new EllipticCurve(new ECFieldFp(p), a, b);
|
|
||||||
return new ECParameterSpec(curve, new ECPoint(gx, gy), n, 1);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the curve parameters from a named ECDSA curve.
|
// Fetch the curve parameters from a named ECDSA curve.
|
||||||
private ECParameterSpec ECSpecFromName(String stdName) {
|
private ECParameterSpec ECSpecFromName(String stdName) {
|
||||||
try {
|
try {
|
||||||
@ -529,22 +483,6 @@ public class DnsKeyAlgorithm {
|
|||||||
pair = mDSAKeyGenerator.generateKeyPair();
|
pair = mDSAKeyGenerator.generateKeyPair();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ECC_GOST: {
|
|
||||||
if (mECGOSTKeyGenerator == null) {
|
|
||||||
mECGOSTKeyGenerator = KeyPairGenerator.getInstance("ECGOST3410");
|
|
||||||
}
|
|
||||||
|
|
||||||
ECParameterSpec ecSpec = getEllipticCurveParams(algorithm);
|
|
||||||
try {
|
|
||||||
mECGOSTKeyGenerator.initialize(ecSpec);
|
|
||||||
} catch (InvalidAlgorithmParameterException e) {
|
|
||||||
// Fold the InvalidAlgorithmParameterException into our existing
|
|
||||||
// thrown exception. Ugly, but requires less code change.
|
|
||||||
throw new NoSuchAlgorithmException("invalid key parameter spec");
|
|
||||||
}
|
|
||||||
pair = mECGOSTKeyGenerator.generateKeyPair();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ECDSA: {
|
case ECDSA: {
|
||||||
if (mECKeyGenerator == null) {
|
if (mECKeyGenerator == null) {
|
||||||
mECKeyGenerator = KeyPairGenerator.getInstance("EC");
|
mECKeyGenerator = KeyPairGenerator.getInstance("EC");
|
||||||
@ -563,9 +501,9 @@ public class DnsKeyAlgorithm {
|
|||||||
}
|
}
|
||||||
case EDDSA: {
|
case EDDSA: {
|
||||||
EdAlgEntry entry = (EdAlgEntry) getEntry(algorithm);
|
EdAlgEntry entry = (EdAlgEntry) getEntry(algorithm);
|
||||||
mEdKeyGenerator = KeyPairGenerator.getInstance(entry.curveName);
|
KeyPairGenerator edKeyGenerator = KeyPairGenerator.getInstance(entry.curveName);
|
||||||
|
|
||||||
pair = mEdKeyGenerator.generateKeyPair();
|
pair = edKeyGenerator.generateKeyPair();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -201,8 +201,6 @@ public class DnsKeyConverter {
|
|||||||
return parsePrivateDSA(lines);
|
return parsePrivateDSA(lines);
|
||||||
case DH:
|
case DH:
|
||||||
return parsePrivateDH(lines);
|
return parsePrivateDH(lines);
|
||||||
case ECC_GOST:
|
|
||||||
return parsePrivateECDSA(lines, alg);
|
|
||||||
case ECDSA:
|
case ECDSA:
|
||||||
return parsePrivateECDSA(lines, alg);
|
return parsePrivateECDSA(lines, alg);
|
||||||
case EDDSA:
|
case EDDSA:
|
||||||
|
@ -1317,6 +1317,8 @@ public class SignUtils {
|
|||||||
*/
|
*/
|
||||||
public static void generateDSRecords(Name zonename, List<Record> records, int digestAlg) {
|
public static void generateDSRecords(Name zonename, List<Record> records, int digestAlg) {
|
||||||
|
|
||||||
|
DSAlgorithm dsAlgorithm = DSAlgorithm.getInstance();
|
||||||
|
|
||||||
for (ListIterator<Record> i = records.listIterator(); i.hasNext();) {
|
for (ListIterator<Record> i = records.listIterator(); i.hasNext();) {
|
||||||
Record r = i.next();
|
Record r = i.next();
|
||||||
if (r == null)
|
if (r == null)
|
||||||
@ -1328,7 +1330,7 @@ public class SignUtils {
|
|||||||
|
|
||||||
// Convert non-zone level KEY records into DS records.
|
// Convert non-zone level KEY records into DS records.
|
||||||
if (r.getType() == Type.DNSKEY && !rName.equals(zonename)) {
|
if (r.getType() == Type.DNSKEY && !rName.equals(zonename)) {
|
||||||
DSRecord ds = calculateDSRecord((DNSKEYRecord) r, digestAlg, r.getTTL());
|
DSRecord ds = dsAlgorithm.calculateDSRecord((DNSKEYRecord) r, digestAlg, r.getTTL());
|
||||||
|
|
||||||
i.set(ds);
|
i.set(ds);
|
||||||
}
|
}
|
||||||
@ -1376,53 +1378,6 @@ public class SignUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a DNSKEY record, generate the DS record from it.
|
|
||||||
*
|
|
||||||
* @param keyrec the KEY record in question.
|
|
||||||
* @param digestAlg The digest algorithm (SHA-1, SHA-256, etc.).
|
|
||||||
* @param ttl the desired TTL for the generated DS record. If zero, or
|
|
||||||
* negative, the original KEY RR's TTL will be used.
|
|
||||||
* @return the corresponding {@link org.xbill.DNS.DSRecord}
|
|
||||||
*/
|
|
||||||
public static DSRecord calculateDSRecord(DNSKEYRecord keyrec, int digestAlg, long ttl) {
|
|
||||||
if (keyrec == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (ttl <= 0)
|
|
||||||
ttl = keyrec.getTTL();
|
|
||||||
|
|
||||||
DNSOutput os = new DNSOutput();
|
|
||||||
|
|
||||||
os.writeByteArray(keyrec.getName().toWireCanonical());
|
|
||||||
os.writeByteArray(keyrec.rdataToWireCanonical());
|
|
||||||
|
|
||||||
try {
|
|
||||||
byte[] digest;
|
|
||||||
MessageDigest md;
|
|
||||||
|
|
||||||
switch (digestAlg) {
|
|
||||||
case DNSSEC.Digest.SHA1:
|
|
||||||
md = MessageDigest.getInstance("SHA");
|
|
||||||
digest = md.digest(os.toByteArray());
|
|
||||||
break;
|
|
||||||
case DNSSEC.Digest.SHA256:
|
|
||||||
md = MessageDigest.getInstance("SHA-256");
|
|
||||||
digest = md.digest(os.toByteArray());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Unknown digest id: " + digestAlg);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DSRecord(keyrec.getName(), keyrec.getDClass(), ttl,
|
|
||||||
keyrec.getFootprint(), keyrec.getAlgorithm(), digestAlg,
|
|
||||||
digest);
|
|
||||||
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
log.severe(e.toString());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate an NSEC3 hash based on a DNS name and NSEC3 hash parameters.
|
* Calculate an NSEC3 hash based on a DNS name and NSEC3 hash parameters.
|
||||||
|
Loading…
Reference in New Issue
Block a user