323 lines
8.9 KiB
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;
|
|
}
|
|
}
|