jdnssec-tools/src/main/java/com/verisignlabs/dnssec/security/DnsKeyPair.java

323 lines
8.9 KiB
Java

// Copyright (C) 2001-2003, 2022 VeriSign, Inc.
//
// 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
package com.verisignlabs.dnssec.security;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.logging.Logger;
import org.xbill.DNS.DClass;
import org.xbill.DNS.DNSKEYRecord;
import org.xbill.DNS.DNSSEC;
import org.xbill.DNS.Name;
/**
* This class forms the basis for representing public/private key pairs in a
* DNSSEC context. It is possible to get a JCA public and private key from this
* object, as well as a DNSKEYRecord encoding of the public key. This class is
* implemented as a UNION of all the functionality needed for handing native
* java, BIND, and possibly other underlying DNSKEY engines.
*
* JCA == Java Cryptography Architecture.
*
* @author David Blacka
*/
// NOTE: this class is designed to do "lazy" evaluation of it's
// various cached objects and format conversions, so methods should
// avoid direct access to the member variables.
public class DnsKeyPair {
/** This is the real (base) encoding of the public key. */
protected DNSKEYRecord mPublicKeyRecord;
/**
* This is a pre-calculated cache of the DNSKEYRecord converted into a JCA
* public key.
*/
private PublicKey mPublicKey;
/**
* The private key in Base64 encoded format. This version is presumed to be
* opaque, so no attempts will be made to convert it to a JCA private key.
*/
protected String mPrivateKeyString;
/**
* The private key in JCA format. This is the base encoding for instances where
* JCA private keys are used.
*/
protected PrivateKey mPrivateKey;
/** The local key converter. */
protected DnsKeyConverter mKeyConverter;
/**
* a cached Signature used for signing (initialized with the private key)
*/
protected Signature mSigner;
/**
* a caches Signature used for verifying (initialized with the public key)
*/
protected Signature mVerifier;
private Logger log;
public DnsKeyPair() {
log = Logger.getLogger(this.getClass().toString());
}
public DnsKeyPair(DNSKEYRecord keyRecord, PrivateKey privateKey) {
this();
setDNSKEYRecord(keyRecord);
setPrivate(privateKey);
}
public DnsKeyPair(DNSKEYRecord keyRecord, String privateKeyString) {
this();
setDNSKEYRecord(keyRecord);
setPrivateKeyString(privateKeyString);
}
public DnsKeyPair(DNSKEYRecord keyRecord) {
this();
setDNSKEYRecord(keyRecord);
setPrivateKeyString(null);
}
public DnsKeyPair(Name keyName, int algorithm, PublicKey publicKey,
PrivateKey privateKey) {
this();
DnsKeyConverter conv = new DnsKeyConverter();
DNSKEYRecord keyrec = conv.generateDNSKEYRecord(keyName, DClass.IN, 0, 0,
algorithm, publicKey);
setDNSKEYRecord(keyrec);
setPrivate(privateKey);
}
public DnsKeyPair(DnsKeyPair pair) {
this();
setDNSKEYRecord(pair.getDNSKEYRecord());
setPrivate(pair.getPrivate());
setPrivateKeyString(pair.getPrivateKeyString());
}
/** @return cached DnsKeyConverter object. */
protected DnsKeyConverter getKeyConverter() {
if (mKeyConverter == null) {
mKeyConverter = new DnsKeyConverter();
}
return mKeyConverter;
}
/** @return the appropriate Signature object for this keypair. */
protected Signature getSignature() {
DnsKeyAlgorithm algorithms = DnsKeyAlgorithm.getInstance();
return algorithms.getSignature(getDNSKEYAlgorithm());
}
/**
* @return the public key, translated from the KEYRecord, if necessary.
*/
public PublicKey getPublic() {
if (mPublicKey == null && getDNSKEYRecord() != null) {
try {
DnsKeyConverter conv = getKeyConverter();
setPublic(conv.parseDNSKEYRecord(getDNSKEYRecord()));
} catch (NoSuchAlgorithmException e) {
log.severe(e.toString());
return null;
}
}
return mPublicKey;
}
/**
* sets the public key. This method is generally not used directly.
*/
protected void setPublic(PublicKey k) {
mPublicKey = k;
}
/** @return the private key. */
public PrivateKey getPrivate() {
// attempt to convert the private key string format into a JCA
// private key.
if (mPrivateKey == null && mPrivateKeyString != null) {
mPrivateKey = BINDKeyUtils.convertPrivateKeyString(mPrivateKeyString);
}
return mPrivateKey;
}
/** sets the private key */
public void setPrivate(PrivateKey k) {
mPrivateKey = k;
}
/**
* @return the opaque private key string, null if one doesn't exist.
* @throws NoSuchAlgorithmException
*/
public String getPrivateKeyString() {
if (mPrivateKeyString == null && mPrivateKey != null) {
PublicKey pub = getPublic();
mPrivateKeyString = BINDKeyUtils.convertPrivateKey(mPrivateKey, pub,
getDNSKEYAlgorithm());
}
return mPrivateKeyString;
}
/** sets the opaque private key string. */
public void setPrivateKeyString(String p) {
mPrivateKeyString = p;
}
/** @return the private key in an encoded form (normally PKCS#8). */
public byte[] getEncodedPrivate() {
PrivateKey priv = getPrivate();
if (priv != null)
return priv.getEncoded();
return new byte[0];
}
/**
* Sets the private key from the encoded form (PKCS#8). This routine requires
* that the public key already be assigned. Currently it can only handle DSA
* and RSA keys.
*/
public void setEncodedPrivate(byte[] encoded) {
int alg = getDNSKEYAlgorithm();
if (alg >= 0) {
DnsKeyConverter conv = getKeyConverter();
setPrivate(conv.convertEncodedPrivateKey(encoded, alg));
}
}
/** @return the public DNSKEY record */
public DNSKEYRecord getDNSKEYRecord() {
return mPublicKeyRecord;
}
/**
* @return a Signature object initialized for signing, or null if this key
* pair does not have a valid private key.
*/
public Signature getSigner() {
if (mSigner == null) {
mSigner = getSignature();
PrivateKey priv = getPrivate();
if (mSigner != null && priv != null) {
try {
mSigner.initSign(priv);
} catch (InvalidKeyException e) {
log.severe("Signature error: " + e);
}
} else {
// do not return an uninitialized signer.
return null;
}
}
return mSigner;
}
/**
* @return a Signature object initialized for verifying, or null if this key
* pair does not have a valid public key.
* @throws NoSuchAlgorithmException
*/
public Signature getVerifier() {
if (mVerifier == null) {
mVerifier = getSignature();
PublicKey pk = getPublic();
if (mVerifier != null && pk != null) {
try {
mVerifier.initVerify(pk);
} catch (InvalidKeyException e) {
}
} else {
// do not return an uninitialized verifier
return null;
}
}
return mVerifier;
}
/** sets the public key record */
public void setDNSKEYRecord(DNSKEYRecord r) {
mPublicKeyRecord = r;
// force the conversion to PublicKey:
mPublicKey = null;
}
public Name getDNSKEYName() {
DNSKEYRecord kr = getDNSKEYRecord();
if (kr != null)
return kr.getName();
return null;
}
public int getDNSKEYAlgorithm() {
DNSKEYRecord kr = getDNSKEYRecord();
if (kr != null)
return kr.getAlgorithm();
PublicKey pk = getPublic();
if (pk != null) {
// currently, alg 5 is the default over alg 1 (RSASHA1).
if (pk instanceof RSAPublicKey)
return DNSSEC.Algorithm.RSASHA1;
if (pk instanceof DSAPublicKey)
return DNSSEC.Algorithm.DSA;
}
PrivateKey priv = getPrivate();
if (priv != null) {
if (priv instanceof RSAPrivateKey)
return DNSSEC.Algorithm.RSASHA1;
if (priv instanceof DSAPrivateKey)
return DNSSEC.Algorithm.DSA;
}
return -1;
}
public int getDNSKEYFootprint() {
DNSKEYRecord kr = getDNSKEYRecord();
if (kr != null)
return kr.getFootprint();
return -1;
}
}