2022-09-21 18:24:42 +00:00
|
|
|
// Copyright (C) 2001-2003, 2009, 2022 Verisign, Inc.
|
2005-08-13 23:18:03 +00:00
|
|
|
//
|
|
|
|
// This library is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
|
|
// License as published by the Free Software Foundation; either
|
|
|
|
// version 2.1 of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
|
|
// License along with this library; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
|
|
// USA
|
2005-08-14 02:08:48 +00:00
|
|
|
|
2005-08-13 23:18:03 +00:00
|
|
|
package com.verisignlabs.dnssec.security;
|
|
|
|
|
2005-08-14 02:08:48 +00:00
|
|
|
import java.io.IOException;
|
|
|
|
import java.security.GeneralSecurityException;
|
|
|
|
import java.security.KeyPair;
|
|
|
|
import java.security.NoSuchAlgorithmException;
|
|
|
|
import java.security.Signature;
|
|
|
|
import java.security.interfaces.DSAPublicKey;
|
2022-09-21 18:24:42 +00:00
|
|
|
import java.time.Instant;
|
2005-08-14 02:08:48 +00:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.ListIterator;
|
2010-12-07 05:31:58 +00:00
|
|
|
import java.util.logging.Logger;
|
2005-08-14 02:08:48 +00:00
|
|
|
|
2022-09-21 18:24:42 +00:00
|
|
|
import org.xbill.DNS.DNSKEYRecord;
|
|
|
|
import org.xbill.DNS.DNSSEC;
|
|
|
|
import org.xbill.DNS.Name;
|
|
|
|
import org.xbill.DNS.RRSIGRecord;
|
|
|
|
import org.xbill.DNS.RRset;
|
|
|
|
import org.xbill.DNS.Record;
|
|
|
|
import org.xbill.DNS.Type;
|
2010-12-05 23:08:13 +00:00
|
|
|
import org.xbill.DNS.utils.hexdump;
|
2005-08-14 02:08:48 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This class contains routines for signing DNS zones.
|
2018-07-15 00:54:10 +00:00
|
|
|
*
|
2005-08-14 02:08:48 +00:00
|
|
|
* In particular, it contains both an ability to sign an individual RRset and
|
2009-02-02 04:45:49 +00:00
|
|
|
* the ability to sign an entire zone. It primarily glues together the more
|
2005-08-14 02:08:48 +00:00
|
|
|
* basic primitives found in {@link SignUtils}.
|
2018-07-15 00:54:10 +00:00
|
|
|
*
|
2022-09-21 18:24:42 +00:00
|
|
|
* @author David Blacka
|
2005-08-13 23:18:03 +00:00
|
|
|
*/
|
2009-02-02 04:45:49 +00:00
|
|
|
|
2022-09-21 18:24:42 +00:00
|
|
|
public class JCEDnsSecSigner {
|
2006-05-23 21:24:00 +00:00
|
|
|
private DnsKeyConverter mKeyConverter;
|
2022-09-21 18:24:42 +00:00
|
|
|
private boolean mVerboseSigning = false;
|
2011-02-12 21:25:42 +00:00
|
|
|
|
2022-09-21 18:24:42 +00:00
|
|
|
private Logger log = Logger.getLogger(this.getClass().toString());
|
2010-12-05 23:08:13 +00:00
|
|
|
|
2022-09-21 18:24:42 +00:00
|
|
|
public JCEDnsSecSigner() {
|
2010-12-05 23:08:13 +00:00
|
|
|
this.mKeyConverter = null;
|
|
|
|
this.mVerboseSigning = false;
|
|
|
|
}
|
|
|
|
|
2022-09-21 18:24:42 +00:00
|
|
|
public JCEDnsSecSigner(boolean verboseSigning) {
|
2010-12-05 23:08:13 +00:00
|
|
|
this.mKeyConverter = null;
|
|
|
|
this.mVerboseSigning = verboseSigning;
|
|
|
|
}
|
2005-08-13 23:18:03 +00:00
|
|
|
|
2005-08-14 02:08:48 +00:00
|
|
|
/**
|
|
|
|
* Cryptographically generate a new DNSSEC key.
|
2018-07-15 00:54:10 +00:00
|
|
|
*
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param owner the KEY RR's owner name.
|
|
|
|
* @param ttl the KEY RR's TTL.
|
|
|
|
* @param dclass the KEY RR's DNS class.
|
|
|
|
* @param algorithm the DNSSEC algorithm (RSASHA258, RSASHA512,
|
2022-09-21 18:24:42 +00:00
|
|
|
* ECDSAP256, etc.)
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param flags any flags for the KEY RR.
|
|
|
|
* @param keysize the size of the key to generate.
|
|
|
|
* @param useLargeExponent if generating an RSA key, use the large exponent.
|
2005-08-14 02:08:48 +00:00
|
|
|
* @return a DnsKeyPair with the public and private keys populated.
|
2005-08-13 23:18:03 +00:00
|
|
|
*/
|
2010-12-05 23:08:13 +00:00
|
|
|
public DnsKeyPair generateKey(Name owner, long ttl, int dclass, int algorithm,
|
2022-09-21 18:24:42 +00:00
|
|
|
int flags, int keysize, boolean useLargeExponent)
|
|
|
|
throws NoSuchAlgorithmException {
|
2006-05-23 21:24:00 +00:00
|
|
|
DnsKeyAlgorithm algorithms = DnsKeyAlgorithm.getInstance();
|
2005-08-13 23:18:03 +00:00
|
|
|
|
2022-09-21 18:24:42 +00:00
|
|
|
if (ttl < 0)
|
|
|
|
ttl = 86400; // set to a reasonable default.
|
2005-08-13 23:18:03 +00:00
|
|
|
|
2010-12-05 23:08:13 +00:00
|
|
|
KeyPair pair = algorithms.generateKeyPair(algorithm, keysize, useLargeExponent);
|
2005-08-13 23:18:03 +00:00
|
|
|
|
2022-09-21 18:24:42 +00:00
|
|
|
if (mKeyConverter == null) {
|
2005-08-13 23:18:03 +00:00
|
|
|
mKeyConverter = new DnsKeyConverter();
|
|
|
|
}
|
|
|
|
|
2010-12-05 23:08:13 +00:00
|
|
|
DNSKEYRecord keyrec = mKeyConverter.generateDNSKEYRecord(owner, dclass, ttl, flags,
|
2022-09-21 18:24:42 +00:00
|
|
|
algorithm, pair.getPublic());
|
2006-05-23 21:24:00 +00:00
|
|
|
|
2005-08-13 23:18:03 +00:00
|
|
|
DnsKeyPair dnspair = new DnsKeyPair();
|
|
|
|
dnspair.setDNSKEYRecord(keyrec);
|
2005-08-14 02:08:48 +00:00
|
|
|
dnspair.setPublic(pair.getPublic()); // keep from conv. the keyrec back.
|
2005-08-13 23:18:03 +00:00
|
|
|
dnspair.setPrivate(pair.getPrivate());
|
|
|
|
|
|
|
|
return dnspair;
|
|
|
|
}
|
|
|
|
|
2005-08-14 02:08:48 +00:00
|
|
|
/**
|
|
|
|
* Sign an RRset.
|
2018-07-15 00:54:10 +00:00
|
|
|
*
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param rrset the RRset to sign -- any existing signatures are ignored.
|
|
|
|
* @param keypars a list of DnsKeyPair objects containing private keys.
|
|
|
|
* @param start the inception time for the resulting RRSIG records.
|
|
|
|
* @param expire the expiration time for the resulting RRSIG records.
|
2005-08-14 02:08:48 +00:00
|
|
|
* @return a list of RRSIGRecord objects.
|
2005-08-13 23:18:03 +00:00
|
|
|
*/
|
2022-09-21 18:24:42 +00:00
|
|
|
public List<RRSIGRecord> signRRset(RRset rrset, List<DnsKeyPair> keypairs, Instant start,
|
|
|
|
Instant expire) throws IOException,
|
|
|
|
GeneralSecurityException {
|
|
|
|
if (rrset == null || keypairs == null)
|
2024-03-31 02:21:32 +00:00
|
|
|
return new ArrayList<>();
|
2005-08-13 23:18:03 +00:00
|
|
|
|
|
|
|
// default start to now, expire to start + 1 second.
|
2022-09-21 18:24:42 +00:00
|
|
|
if (start == null)
|
|
|
|
start = Instant.now();
|
|
|
|
if (expire == null)
|
|
|
|
expire = start.plusSeconds(1);
|
2024-03-31 02:21:32 +00:00
|
|
|
if (keypairs.isEmpty())
|
|
|
|
return new ArrayList<>();
|
2022-09-21 18:24:42 +00:00
|
|
|
|
|
|
|
if (mVerboseSigning) {
|
2010-12-07 05:31:58 +00:00
|
|
|
log.info("Signing RRset:");
|
|
|
|
log.info(ZoneUtils.rrsetToString(rrset, false));
|
2010-12-05 23:08:13 +00:00
|
|
|
}
|
|
|
|
|
2009-02-02 04:45:49 +00:00
|
|
|
// first, pre-calculate the RRset bytes.
|
2024-03-31 02:21:32 +00:00
|
|
|
byte[] rrsetData = SignUtils.generateCanonicalRRsetData(rrset, 0, 0);
|
2005-08-13 23:18:03 +00:00
|
|
|
|
2024-03-31 02:21:32 +00:00
|
|
|
ArrayList<RRSIGRecord> sigs = new ArrayList<>(keypairs.size());
|
2005-08-13 23:18:03 +00:00
|
|
|
|
2009-02-02 04:45:49 +00:00
|
|
|
// for each keypair, sign the RRset.
|
2022-09-21 18:24:42 +00:00
|
|
|
for (DnsKeyPair pair : keypairs) {
|
2005-08-13 23:18:03 +00:00
|
|
|
DNSKEYRecord keyrec = pair.getDNSKEYRecord();
|
2022-09-21 18:24:42 +00:00
|
|
|
if (keyrec == null)
|
|
|
|
continue;
|
2005-08-13 23:18:03 +00:00
|
|
|
|
2010-12-05 23:08:13 +00:00
|
|
|
RRSIGRecord presig = SignUtils.generatePreRRSIG(rrset, keyrec, start, expire,
|
2022-09-21 18:24:42 +00:00
|
|
|
rrset.getTTL());
|
2024-03-31 02:21:32 +00:00
|
|
|
byte[] signData = SignUtils.generateSigData(rrsetData, presig);
|
2005-08-13 23:18:03 +00:00
|
|
|
|
2022-09-21 18:24:42 +00:00
|
|
|
if (mVerboseSigning) {
|
2011-02-12 21:25:42 +00:00
|
|
|
log.info("Canonical pre-signature data to sign with key "
|
|
|
|
+ keyrec.getName().toString() + "/" + keyrec.getAlgorithm() + "/"
|
|
|
|
+ keyrec.getFootprint() + ":");
|
2024-03-31 02:21:32 +00:00
|
|
|
log.info(hexdump.dump(null, signData));
|
2010-12-05 23:08:13 +00:00
|
|
|
}
|
|
|
|
|
2005-08-13 23:18:03 +00:00
|
|
|
Signature signer = pair.getSigner();
|
|
|
|
|
2022-09-21 18:24:42 +00:00
|
|
|
if (signer == null) {
|
2005-08-14 02:08:48 +00:00
|
|
|
// debug
|
2011-02-12 21:25:42 +00:00
|
|
|
log.fine("missing private key that goes with:\n" + pair.getDNSKEYRecord());
|
2010-12-05 23:08:13 +00:00
|
|
|
throw new GeneralSecurityException("cannot sign without a valid Signer "
|
|
|
|
+ "(probably missing private key)");
|
2005-08-13 23:18:03 +00:00
|
|
|
}
|
2005-08-14 02:08:48 +00:00
|
|
|
|
2005-08-13 23:18:03 +00:00
|
|
|
// sign the data.
|
2024-03-31 02:21:32 +00:00
|
|
|
signer.update(signData);
|
2005-08-13 23:18:03 +00:00
|
|
|
byte[] sig = signer.sign();
|
|
|
|
|
2022-09-21 18:24:42 +00:00
|
|
|
if (mVerboseSigning) {
|
2010-12-07 05:31:58 +00:00
|
|
|
log.info("Raw Signature:");
|
|
|
|
log.info(hexdump.dump(null, sig));
|
2010-12-05 23:08:13 +00:00
|
|
|
}
|
|
|
|
|
2006-05-23 21:24:00 +00:00
|
|
|
DnsKeyAlgorithm algs = DnsKeyAlgorithm.getInstance();
|
2005-08-13 23:18:03 +00:00
|
|
|
// Convert to RFC 2536 format, if necessary.
|
2024-03-31 02:21:32 +00:00
|
|
|
if (algs.baseType(pair.getDNSKEYAlgorithm()) == DnsKeyAlgorithm.BaseAlgorithm.DSA) {
|
2010-12-05 23:08:13 +00:00
|
|
|
DSAPublicKey pk = (DSAPublicKey) pair.getPublic();
|
|
|
|
sig = SignUtils.convertDSASignature(pk.getParams(), sig);
|
2005-08-13 23:18:03 +00:00
|
|
|
}
|
2016-12-02 22:49:09 +00:00
|
|
|
// Convert to RFC 6605, etc format
|
|
|
|
if (pair.getDNSKEYAlgorithm() == DNSSEC.Algorithm.ECDSAP256SHA256 ||
|
2022-09-21 18:24:42 +00:00
|
|
|
pair.getDNSKEYAlgorithm() == DNSSEC.Algorithm.ECDSAP384SHA384) {
|
2016-12-02 22:49:09 +00:00
|
|
|
sig = SignUtils.convertECDSASignature(pair.getDNSKEYAlgorithm(), sig);
|
|
|
|
}
|
2005-08-13 23:18:03 +00:00
|
|
|
RRSIGRecord sigrec = SignUtils.generateRRSIG(sig, presig);
|
2022-09-21 18:24:42 +00:00
|
|
|
if (mVerboseSigning) {
|
2010-12-07 05:31:58 +00:00
|
|
|
log.info("RRSIG:\n" + sigrec);
|
2010-12-05 23:08:13 +00:00
|
|
|
}
|
2005-08-13 23:18:03 +00:00
|
|
|
sigs.add(sigrec);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sigs;
|
|
|
|
}
|
|
|
|
|
2005-08-14 02:08:48 +00:00
|
|
|
/**
|
2009-02-02 04:45:49 +00:00
|
|
|
* Create a completely self-signed DNSKEY RRset.
|
2018-07-15 00:54:10 +00:00
|
|
|
*
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param keypairs the public & private keypairs to use in the keyset.
|
|
|
|
* @param start the RRSIG inception time.
|
|
|
|
* @param expire the RRSIG expiration time.
|
2005-08-14 02:08:48 +00:00
|
|
|
* @return a signed RRset.
|
2005-08-13 23:18:03 +00:00
|
|
|
*/
|
2022-09-21 18:24:42 +00:00
|
|
|
public RRset makeKeySet(List<DnsKeyPair> keypairs, Instant start, Instant expire)
|
|
|
|
throws IOException, GeneralSecurityException {
|
2005-08-13 23:18:03 +00:00
|
|
|
// Generate a KEY RR set to sign.
|
2005-08-14 02:08:48 +00:00
|
|
|
|
2005-08-13 23:18:03 +00:00
|
|
|
RRset keyset = new RRset();
|
|
|
|
|
2022-09-21 18:24:42 +00:00
|
|
|
for (DnsKeyPair pair : keypairs) {
|
2005-08-13 23:18:03 +00:00
|
|
|
keyset.addRR(pair.getDNSKEYRecord());
|
|
|
|
}
|
|
|
|
|
2011-02-12 21:25:42 +00:00
|
|
|
List<RRSIGRecord> records = signRRset(keyset, keypairs, start, expire);
|
2005-08-13 23:18:03 +00:00
|
|
|
|
2022-09-21 18:24:42 +00:00
|
|
|
for (RRSIGRecord r : records) {
|
2011-02-12 21:25:42 +00:00
|
|
|
keyset.addRR(r);
|
2005-08-13 23:18:03 +00:00
|
|
|
}
|
2005-08-14 02:08:48 +00:00
|
|
|
|
2005-08-13 23:18:03 +00:00
|
|
|
return keyset;
|
|
|
|
}
|
|
|
|
|
2005-08-14 02:08:48 +00:00
|
|
|
/**
|
|
|
|
* Conditionally sign an RRset and add it to the toList.
|
2018-07-15 00:54:10 +00:00
|
|
|
*
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param toList the list to which we are adding the processed RRsets.
|
|
|
|
* @param zonename the zone apex name.
|
|
|
|
* @param rrset the RRset under consideration.
|
|
|
|
* @param kskpairs the List of KSKs..
|
|
|
|
* @param zskpairs the List of zone keys.
|
|
|
|
* @param start the RRSIG inception time.
|
|
|
|
* @param expire the RRSIG expiration time.
|
|
|
|
* @param fullySignKeyset if true, sign the zone apex keyset with both KSKs
|
|
|
|
* and ZSKs.
|
|
|
|
* @param lastCut the name of the last delegation point encountered.
|
2018-07-15 00:54:10 +00:00
|
|
|
*
|
2005-08-14 02:08:48 +00:00
|
|
|
* @return the name of the new last_cut.
|
2005-08-13 23:18:03 +00:00
|
|
|
*/
|
2011-02-12 21:25:42 +00:00
|
|
|
private Name addRRset(List<Record> toList, Name zonename, RRset rrset,
|
2022-09-21 18:24:42 +00:00
|
|
|
List<DnsKeyPair> kskpairs, List<DnsKeyPair> zskpairs, Instant start,
|
2024-03-31 02:21:32 +00:00
|
|
|
Instant expire, boolean fullySignKeyset, Name lastCut,
|
|
|
|
Name lastDname) throws IOException, GeneralSecurityException {
|
2005-08-13 23:18:03 +00:00
|
|
|
// add the records themselves
|
2024-03-31 02:21:32 +00:00
|
|
|
rrset.rrs().forEach(toList::add);
|
2005-08-13 23:18:03 +00:00
|
|
|
|
2010-12-05 23:08:13 +00:00
|
|
|
int type = SignUtils.recordSecType(zonename, rrset.getName(), rrset.getType(),
|
2024-03-31 02:21:32 +00:00
|
|
|
lastCut, lastDname);
|
2005-08-13 23:18:03 +00:00
|
|
|
|
|
|
|
// we don't sign non-normal sets (delegations, glue, invalid).
|
2022-09-21 18:24:42 +00:00
|
|
|
if (type == SignUtils.RR_DELEGATION) {
|
2009-02-07 20:37:29 +00:00
|
|
|
return rrset.getName();
|
|
|
|
}
|
2022-09-21 18:24:42 +00:00
|
|
|
if (type == SignUtils.RR_GLUE || type == SignUtils.RR_INVALID) {
|
2024-03-31 02:21:32 +00:00
|
|
|
return lastCut;
|
2009-02-07 20:37:29 +00:00
|
|
|
}
|
2005-08-13 23:18:03 +00:00
|
|
|
|
|
|
|
// check for the zone apex keyset.
|
2024-03-31 02:21:32 +00:00
|
|
|
if (rrset.getName().equals(zonename) && rrset.getType() == Type.DNSKEY && kskpairs != null && !kskpairs.isEmpty()) {
|
2009-02-02 04:45:49 +00:00
|
|
|
// if we have ksks, sign the keyset with them, otherwise we will just sign
|
|
|
|
// them with the zsks.
|
2024-03-31 02:21:32 +00:00
|
|
|
List<RRSIGRecord> sigs = signRRset(rrset, kskpairs, start, expire);
|
|
|
|
toList.addAll(sigs);
|
|
|
|
|
|
|
|
// If we aren't going to sign with all the keys, bail out now.
|
|
|
|
if (!fullySignKeyset)
|
|
|
|
return lastCut;
|
2005-08-13 23:18:03 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise, we are OK to sign this set.
|
2011-02-12 21:25:42 +00:00
|
|
|
List<RRSIGRecord> sigs = signRRset(rrset, zskpairs, start, expire);
|
2005-08-13 23:18:03 +00:00
|
|
|
toList.addAll(sigs);
|
|
|
|
|
2024-03-31 02:21:32 +00:00
|
|
|
return lastCut;
|
2005-08-13 23:18:03 +00:00
|
|
|
}
|
|
|
|
|
2009-02-02 04:45:49 +00:00
|
|
|
// Various NSEC/NSEC3 generation modes
|
2022-09-21 18:24:42 +00:00
|
|
|
private static final int NSEC_MODE = 0;
|
|
|
|
private static final int NSEC3_MODE = 1;
|
2009-02-02 04:45:49 +00:00
|
|
|
private static final int NSEC3_OPTOUT_MODE = 2;
|
2022-09-21 18:24:42 +00:00
|
|
|
private static final int NSEC_EXP_OPT_IN = 3;
|
2009-02-02 04:45:49 +00:00
|
|
|
|
2005-08-14 02:08:48 +00:00
|
|
|
/**
|
2009-02-02 04:45:49 +00:00
|
|
|
* Master zone signing method. This method handles all of the different zone
|
|
|
|
* 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
|
|
|
|
* appropriate public signZone* methods instead of this.
|
2018-07-15 00:54:10 +00:00
|
|
|
*
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param zonename The name of the zone
|
|
|
|
* @param records The records comprising the zone. They do not have to
|
|
|
|
* be in any particular order, as this method will
|
|
|
|
* order them as necessary.
|
|
|
|
* @param kskpairs The key pairs designated as "key signing keys"
|
|
|
|
* @param zskpairs The key pairs designated as "zone signing keys"
|
|
|
|
* @param start The RRSIG inception time
|
|
|
|
* @param expire The RRSIG expiration time
|
|
|
|
* @param fullySignKeyset If true, all keys (ksk or zsk) will sign the DNSKEY
|
|
|
|
* RRset. If false, only the ksks will sign it.
|
|
|
|
* @param dsDigestAlg The hash algorithm to use for generating DS records
|
2022-09-21 18:24:42 +00:00
|
|
|
* (DSRecord.SHA1_DIGEST_ID, e.g.)
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param mode The NSEC/NSEC3 generation mode: NSEC_MODE,
|
|
|
|
* NSEC3_MODE, NSEC3_OPTOUT_MODE, etc.
|
|
|
|
* @param includedNames When using an Opt-In/Opt-Out mode, the names listed
|
|
|
|
* here will be included in the NSEC/NSEC3 chain
|
|
|
|
* regardless
|
|
|
|
* @param salt When using an NSEC3 mode, use this salt.
|
|
|
|
* @param iterations When using an NSEC3 mode, use this number of
|
2022-09-21 18:24:42 +00:00
|
|
|
* iterations
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param beConservative If true, then only turn on the Opt-In flag when
|
|
|
|
* there are insecure delegations in the span.
|
|
|
|
* Currently this only works for NSEC_EXP_OPT_IN mode.
|
|
|
|
* @param nsec3paramttl The TTL to use for the generated NSEC3PARAM record.
|
|
|
|
* Negative values will use the SOA TTL.
|
2005-08-14 02:08:48 +00:00
|
|
|
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
|
|
|
|
* representing the signed zone.
|
2018-07-15 00:54:10 +00:00
|
|
|
*
|
2009-02-02 04:45:49 +00:00
|
|
|
* @throws IOException
|
|
|
|
* @throws GeneralSecurityException
|
2005-08-13 23:18:03 +00:00
|
|
|
*/
|
2011-02-12 21:25:42 +00:00
|
|
|
private List<Record> signZone(Name zonename, List<Record> records,
|
2022-09-21 18:24:42 +00:00
|
|
|
List<DnsKeyPair> kskpairs, List<DnsKeyPair> zskpairs,
|
|
|
|
Instant start, Instant expire, boolean fullySignKeyset,
|
2024-03-31 02:21:32 +00:00
|
|
|
int dsDigestAlg, int mode, List<Name> includedNames,
|
2022-09-21 18:24:42 +00:00
|
|
|
byte[] salt, int iterations, long nsec3paramttl,
|
|
|
|
boolean beConservative) throws IOException,
|
|
|
|
GeneralSecurityException {
|
2009-02-02 04:45:49 +00:00
|
|
|
// Remove any existing generated DNSSEC records (NSEC, NSEC3, NSEC3PARAM,
|
|
|
|
// RRSIG)
|
2005-08-13 23:18:03 +00:00
|
|
|
SignUtils.removeGeneratedRecords(zonename, records);
|
2009-02-02 04:45:49 +00:00
|
|
|
|
|
|
|
RecordComparator rc = new RecordComparator();
|
2005-08-13 23:18:03 +00:00
|
|
|
// Sort the zone
|
2009-02-02 04:45:49 +00:00
|
|
|
Collections.sort(records, rc);
|
2005-08-13 23:18:03 +00:00
|
|
|
|
2009-02-02 04:45:49 +00:00
|
|
|
// Remove duplicate records
|
2005-08-13 23:18:03 +00:00
|
|
|
SignUtils.removeDuplicateRecords(records);
|
|
|
|
|
2009-02-02 04:45:49 +00:00
|
|
|
// Generate DS records. This replaces any non-zone-apex DNSKEY RRs with DS
|
|
|
|
// RRs.
|
2024-03-31 02:21:32 +00:00
|
|
|
SignUtils.generateDSRecords(zonename, records, dsDigestAlg);
|
2005-08-14 02:08:48 +00:00
|
|
|
|
2009-02-02 04:45:49 +00:00
|
|
|
// Generate the NSEC or NSEC3 records based on 'mode'
|
2022-09-21 18:24:42 +00:00
|
|
|
switch (mode) {
|
2009-02-07 20:37:29 +00:00
|
|
|
case NSEC_MODE:
|
|
|
|
SignUtils.generateNSECRecords(zonename, records);
|
|
|
|
break;
|
|
|
|
case NSEC3_MODE:
|
2010-12-05 23:08:13 +00:00
|
|
|
SignUtils.generateNSEC3Records(zonename, records, salt, iterations, nsec3paramttl);
|
2009-02-07 20:37:29 +00:00
|
|
|
break;
|
|
|
|
case NSEC3_OPTOUT_MODE:
|
2010-12-05 23:08:13 +00:00
|
|
|
SignUtils.generateOptOutNSEC3Records(zonename, records, includedNames, salt,
|
2022-09-21 18:24:42 +00:00
|
|
|
iterations, nsec3paramttl);
|
2009-02-07 20:37:29 +00:00
|
|
|
break;
|
|
|
|
case NSEC_EXP_OPT_IN:
|
|
|
|
SignUtils.generateOptInNSECRecords(zonename, records, includedNames,
|
2022-09-21 18:24:42 +00:00
|
|
|
beConservative);
|
2009-02-07 20:37:29 +00:00
|
|
|
break;
|
2024-03-31 02:21:32 +00:00
|
|
|
default:
|
|
|
|
throw new NoSuchAlgorithmException("Unknown NSEC/NSEC3 mode: " + mode);
|
2005-08-13 23:18:03 +00:00
|
|
|
}
|
2005-08-14 02:08:48 +00:00
|
|
|
|
2009-02-02 04:45:49 +00:00
|
|
|
// Re-sort so we can assemble into rrsets.
|
|
|
|
Collections.sort(records, rc);
|
|
|
|
|
2005-08-13 23:18:03 +00:00
|
|
|
// Assemble into RRsets and sign.
|
2005-08-14 02:08:48 +00:00
|
|
|
RRset rrset = new RRset();
|
2024-03-31 02:21:32 +00:00
|
|
|
ArrayList<Record> signedRecords = new ArrayList<>();
|
|
|
|
Name lastCut = null;
|
|
|
|
Name lastDname = null;
|
2005-08-13 23:18:03 +00:00
|
|
|
|
2022-09-21 18:24:42 +00:00
|
|
|
for (ListIterator<Record> i = records.listIterator(); i.hasNext();) {
|
2011-02-12 21:25:42 +00:00
|
|
|
Record r = i.next();
|
2005-08-13 23:18:03 +00:00
|
|
|
|
|
|
|
// First record
|
2022-09-21 18:24:42 +00:00
|
|
|
if (rrset.size() == 0) {
|
2005-08-13 23:18:03 +00:00
|
|
|
rrset.addRR(r);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Current record is part of the current RRset.
|
2010-12-05 23:08:13 +00:00
|
|
|
if (rrset.getName().equals(r.getName()) && rrset.getDClass() == r.getDClass()
|
2022-09-21 18:24:42 +00:00
|
|
|
&& rrset.getType() == r.getType()) {
|
2005-08-13 23:18:03 +00:00
|
|
|
rrset.addRR(r);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we have completed the RRset
|
|
|
|
// Sign the records
|
|
|
|
|
|
|
|
// add the RRset to the list of signed_records, regardless of
|
|
|
|
// whether or not we actually end up signing the set.
|
2024-03-31 02:21:32 +00:00
|
|
|
lastCut = addRRset(signedRecords, zonename, rrset, kskpairs, zskpairs, start,
|
|
|
|
expire, fullySignKeyset, lastCut, lastDname);
|
2022-09-21 18:24:42 +00:00
|
|
|
if (rrset.getType() == Type.DNAME)
|
2024-03-31 02:21:32 +00:00
|
|
|
lastDname = rrset.getName();
|
2005-08-13 23:18:03 +00:00
|
|
|
|
|
|
|
rrset.clear();
|
|
|
|
rrset.addRR(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
// add the last RR set
|
2024-03-31 02:21:32 +00:00
|
|
|
addRRset(signedRecords, zonename, rrset, kskpairs, zskpairs, start, expire,
|
|
|
|
fullySignKeyset, lastCut, lastDname);
|
2005-08-13 23:18:03 +00:00
|
|
|
|
2024-03-31 02:21:32 +00:00
|
|
|
return signedRecords;
|
2005-08-13 23:18:03 +00:00
|
|
|
}
|
2009-02-02 04:45:49 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Given a zone, sign it using standard NSEC records.
|
2018-07-15 00:54:10 +00:00
|
|
|
*
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param zonename The name of the zone.
|
|
|
|
* @param records The records comprising the zone. They do not have to
|
|
|
|
* be in any particular order, as this method will
|
|
|
|
* order them as necessary.
|
|
|
|
* @param kskpairs The key pairs that are designated as "key signing
|
2022-09-21 18:24:42 +00:00
|
|
|
* keys".
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param zskpairs This key pairs that are designated as "zone signing
|
2022-09-21 18:24:42 +00:00
|
|
|
* keys".
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param start The RRSIG inception time.
|
|
|
|
* @param expire The RRSIG expiration time.
|
|
|
|
* @param fullySignKeyset Sign the zone apex keyset with all available keys
|
|
|
|
* (instead of just the key signing keys).
|
|
|
|
* @param dsDigestAlg The digest algorithm to use when generating DS
|
2022-09-21 18:24:42 +00:00
|
|
|
* records.
|
2018-07-15 00:54:10 +00:00
|
|
|
*
|
2009-02-02 04:45:49 +00:00
|
|
|
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
|
|
|
|
* representing the signed zone.
|
|
|
|
*/
|
2011-02-12 21:25:42 +00:00
|
|
|
public List<Record> signZone(Name zonename, List<Record> records,
|
2022-09-21 18:24:42 +00:00
|
|
|
List<DnsKeyPair> kskpairs, List<DnsKeyPair> zskpairs,
|
|
|
|
Instant start, Instant expire, boolean fullySignKeyset,
|
2024-03-31 02:21:32 +00:00
|
|
|
int dsDigestAlg) throws IOException,
|
2022-09-21 18:24:42 +00:00
|
|
|
GeneralSecurityException {
|
2009-02-02 04:45:49 +00:00
|
|
|
return signZone(zonename, records, kskpairs, zskpairs, start, expire,
|
2024-03-31 02:21:32 +00:00
|
|
|
fullySignKeyset, dsDigestAlg, NSEC_MODE, null, null, 0, 0, false);
|
2009-02-02 04:45:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Given a zone, sign it using NSEC3 records.
|
2018-07-15 00:54:10 +00:00
|
|
|
*
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param signer A signer (utility) object used to actually sign
|
|
|
|
* stuff.
|
|
|
|
* @param zonename The name of the zone being signed.
|
|
|
|
* @param records The records comprising the zone. They do not have to
|
|
|
|
* be in any particular order, as this method will
|
|
|
|
* order them as necessary.
|
|
|
|
* @param kskpairs The key pairs that are designated as "key signing
|
2022-09-21 18:24:42 +00:00
|
|
|
* keys".
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param zskpairs This key pairs that are designated as "zone signing
|
2022-09-21 18:24:42 +00:00
|
|
|
* keys".
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param start The RRSIG inception time.
|
|
|
|
* @param expire The RRSIG expiration time.
|
|
|
|
* @param fullySignKeyset If true then the DNSKEY RRset will be signed by all
|
|
|
|
* available keys, if false, only the key signing keys.
|
|
|
|
* @param useOptOut If true, insecure delegations will be omitted from
|
|
|
|
* the NSEC3 chain, and all NSEC3 records will have the
|
|
|
|
* Opt-Out flag set.
|
|
|
|
* @param includedNames A list of names to include in the NSEC3 chain
|
2022-09-21 18:24:42 +00:00
|
|
|
* regardless.
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param salt The salt to use for the NSEC3 hashing. null means no
|
2022-09-21 18:24:42 +00:00
|
|
|
* salt.
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param iterations The number of iterations to use for the NSEC3
|
|
|
|
* hashing.
|
|
|
|
* @param dsDigestAlg The digest algorithm to use when generating DS
|
2022-09-21 18:24:42 +00:00
|
|
|
* records.
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param nsec3paramttl The TTL to use for the generated NSEC3PARAM record.
|
|
|
|
* Negative values will use the SOA TTL.
|
2009-02-02 04:45:49 +00:00
|
|
|
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
|
|
|
|
* representing the signed zone.
|
2018-07-15 00:54:10 +00:00
|
|
|
*
|
2009-02-02 04:45:49 +00:00
|
|
|
* @throws IOException
|
|
|
|
* @throws GeneralSecurityException
|
|
|
|
*/
|
2011-02-12 21:25:42 +00:00
|
|
|
public List<Record> signZoneNSEC3(Name zonename, List<Record> records,
|
2022-09-21 18:24:42 +00:00
|
|
|
List<DnsKeyPair> kskpairs, List<DnsKeyPair> zskpairs,
|
|
|
|
Instant start, Instant expire, boolean fullySignKeyset,
|
|
|
|
boolean useOptOut, List<Name> includedNames,
|
2024-03-31 02:21:32 +00:00
|
|
|
byte[] salt, int iterations, int dsDigestAlg,
|
2022-09-21 18:24:42 +00:00
|
|
|
long nsec3paramttl) throws IOException,
|
|
|
|
GeneralSecurityException {
|
|
|
|
if (useOptOut) {
|
2009-02-02 04:45:49 +00:00
|
|
|
return signZone(zonename, records, kskpairs, zskpairs, start, expire,
|
2024-03-31 02:21:32 +00:00
|
|
|
fullySignKeyset, dsDigestAlg, NSEC3_OPTOUT_MODE, includedNames,
|
2022-09-21 18:24:42 +00:00
|
|
|
salt, iterations, nsec3paramttl, false);
|
|
|
|
} else {
|
2009-02-02 04:45:49 +00:00
|
|
|
return signZone(zonename, records, kskpairs, zskpairs, start, expire,
|
2024-03-31 02:21:32 +00:00
|
|
|
fullySignKeyset, dsDigestAlg, NSEC3_MODE, null, salt, iterations,
|
2022-09-21 18:24:42 +00:00
|
|
|
nsec3paramttl, false);
|
2009-02-02 04:45:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Given a zone, sign it using experimental Opt-In NSEC records (see RFC
|
|
|
|
* 4956).
|
2018-07-15 00:54:10 +00:00
|
|
|
*
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param zonename the name of the zone.
|
|
|
|
* @param records the records comprising the zone. They do not
|
|
|
|
* have to be in any particular order, as this
|
|
|
|
* method will order them as necessary.
|
|
|
|
* @param kskpairs the key pairs that are designated as "key
|
|
|
|
* signing keys".
|
|
|
|
* @param zskpairs this key pairs that are designated as "zone
|
2022-09-21 18:24:42 +00:00
|
|
|
* signing keys".
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param start the RRSIG inception time.
|
|
|
|
* @param expire the RRSIG expiration time.
|
|
|
|
* @param useConservativeOptIn if true, Opt-In NSEC records will only be
|
|
|
|
* generated if there are insecure, unsigned
|
|
|
|
* delegations in the span.
|
|
|
|
* @param fullySignKeyset sign the zone apex keyset with all available
|
2022-09-21 18:24:42 +00:00
|
|
|
* keys.
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param dsDigestAlg The digest algorithm to use when generating DS
|
2022-09-21 18:24:42 +00:00
|
|
|
* records.
|
2024-03-31 02:21:32 +00:00
|
|
|
* @param nsecIncludeNames names that are to be included in the NSEC chain
|
|
|
|
* regardless. This may be null.
|
2009-02-02 04:45:49 +00:00
|
|
|
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
|
|
|
|
* representing the signed zone.
|
|
|
|
*/
|
2011-02-12 21:25:42 +00:00
|
|
|
public List<Record> signZoneOptIn(Name zonename, List<Record> records,
|
2022-09-21 18:24:42 +00:00
|
|
|
List<DnsKeyPair> kskpairs, List<DnsKeyPair> zskpairs,
|
|
|
|
Instant start, Instant expire,
|
|
|
|
boolean useConservativeOptIn,
|
2024-03-31 02:21:32 +00:00
|
|
|
boolean fullySignKeyset, List<Name> nsecIncludeNames,
|
|
|
|
int dsDigestAlg) throws IOException,
|
2022-09-21 18:24:42 +00:00
|
|
|
GeneralSecurityException {
|
2009-02-02 04:45:49 +00:00
|
|
|
|
|
|
|
return signZone(zonename, records, kskpairs, zskpairs, start, expire,
|
2024-03-31 02:21:32 +00:00
|
|
|
fullySignKeyset, dsDigestAlg, NSEC_EXP_OPT_IN, nsecIncludeNames,
|
2022-09-21 18:24:42 +00:00
|
|
|
null, 0, 0, useConservativeOptIn);
|
2009-02-02 04:45:49 +00:00
|
|
|
}
|
2005-08-13 23:18:03 +00:00
|
|
|
}
|