summaryrefslogtreecommitdiffstats
path: root/pki/base/kra/src
diff options
context:
space:
mode:
Diffstat (limited to 'pki/base/kra/src')
-rw-r--r--pki/base/kra/src/CMakeLists.txt106
-rw-r--r--pki/base/kra/src/com/netscape/kra/EncryptionUnit.java539
-rw-r--r--pki/base/kra/src/com/netscape/kra/EnrollmentService.java1007
-rw-r--r--pki/base/kra/src/com/netscape/kra/KRANotify.java53
-rw-r--r--pki/base/kra/src/com/netscape/kra/KRAPolicy.java76
-rw-r--r--pki/base/kra/src/com/netscape/kra/KRAService.java98
-rw-r--r--pki/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java1778
-rw-r--r--pki/base/kra/src/com/netscape/kra/NetkeyKeygenService.java632
-rw-r--r--pki/base/kra/src/com/netscape/kra/RecoveryService.java479
-rw-r--r--pki/base/kra/src/com/netscape/kra/StorageKeyUnit.java959
-rw-r--r--pki/base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java635
-rw-r--r--pki/base/kra/src/com/netscape/kra/TransportKeyUnit.java203
12 files changed, 6565 insertions, 0 deletions
diff --git a/pki/base/kra/src/CMakeLists.txt b/pki/base/kra/src/CMakeLists.txt
new file mode 100644
index 000000000..9879fbae7
--- /dev/null
+++ b/pki/base/kra/src/CMakeLists.txt
@@ -0,0 +1,106 @@
+project(pki-kra_java Java)
+
+# '/usr/share/java/pki' jars
+find_file(PKI_CERTSRV_JAR
+ NAMES
+ pki-certsrv.jar
+ PATHS
+ /usr/share/java/pki
+)
+
+find_file(PKI_CMS_JAR
+ NAMES
+ pki-cms.jar
+ PATHS
+ /usr/share/java/pki
+)
+
+find_file(PKI_CMSCORE_JAR
+ NAMES
+ pki-cmscore.jar
+ PATHS
+ /usr/share/java/pki
+)
+
+find_file(PKI_CMSUTIL_JAR
+ NAMES
+ pki-cmsutil.jar
+ PATHS
+ /usr/share/java/pki
+)
+
+find_file(PKI_NSUTIL_JAR
+ NAMES
+ pki-nsutil.jar
+ PATHS
+ /usr/lib/java
+ /usr/share/java/pki
+)
+
+
+# '/usr/share/java' jars
+find_file(LDAPJDK_JAR
+ NAMES
+ ldapjdk.jar
+ PATHS
+ /usr/share/java
+)
+
+
+# '/usr/lib/java' jars
+find_file(JSS_JAR
+ NAMES
+ jss4.jar
+ PATHS
+ /usr/lib/java
+)
+
+find_file(OSUTIL_JAR
+ NAMES
+ osutil.jar
+ PATHS
+ /usr/lib/java
+)
+
+find_file(SYMKEY_JAR
+ NAMES
+ symkey.jar
+ PATHS
+ /usr/lib/java
+)
+
+
+# identify java sources
+set(pki-kra_java_SRCS
+ com/netscape/kra/KeyRecoveryAuthority.java
+ com/netscape/kra/EnrollmentService.java
+ com/netscape/kra/RecoveryService.java
+ com/netscape/kra/TokenKeyRecoveryService.java
+ com/netscape/kra/EncryptionUnit.java
+ com/netscape/kra/KRAService.java
+ com/netscape/kra/NetkeyKeygenService.java
+ com/netscape/kra/KRANotify.java
+ com/netscape/kra/KRAPolicy.java
+ com/netscape/kra/TransportKeyUnit.java
+ com/netscape/kra/StorageKeyUnit.java
+)
+
+
+# set classpath
+set(CMAKE_JAVA_INCLUDE_PATH
+ ${PKI_CERTSRV_JAR} ${PKI_CMS_JAR} ${PKI_CMSCORE_JAR}
+ ${PKI_CMSUTIL_JAR} ${PKI_NSUTIL_JAR}
+ ${LDAPJDK_JAR}
+ ${JSS_JAR} ${OSUTIL_JAR} ${SYMKEY_JAR})
+
+
+# set version
+set(CMAKE_JAVA_TARGET_VERSION ${APPLICATION_VERSION})
+
+
+# build pki-kra.jar
+add_jar(pki-kra ${pki-kra_java_SRCS})
+add_dependencies(pki-kra osutil symkey pki-nsutil pki-cmsutil pki-certsrv pki-cms pki-cmscore)
+install_jar(pki-kra ${JAVA_JAR_INSTALL_DIR}/pki)
+set(PKI_KRA_JAR ${pki-kra_JAR_FILE} CACHE INTERNAL "pki-kra jar file")
+
diff --git a/pki/base/kra/src/com/netscape/kra/EncryptionUnit.java b/pki/base/kra/src/com/netscape/kra/EncryptionUnit.java
new file mode 100644
index 000000000..0fc5ff610
--- /dev/null
+++ b/pki/base/kra/src/com/netscape/kra/EncryptionUnit.java
@@ -0,0 +1,539 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+
+import java.util.*;
+import java.io.*;
+import java.net.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.cert.X509Certificate;
+import netscape.security.x509.*;
+//import netscape.security.provider.*;
+import netscape.security.util.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.cmscore.util.*;
+import com.netscape.cmscore.util.Debug;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.kra.*;
+import com.netscape.certsrv.security.*;
+//import com.netscape.cmscore.kra.*;
+import com.netscape.cmscore.cert.*;
+import com.netscape.certsrv.apps.CMS;
+import org.mozilla.jss.util.*;
+import org.mozilla.jss.crypto.*;
+import org.mozilla.jss.*;
+import org.mozilla.jss.crypto.PrivateKey;
+
+
+/**
+ * A class represents the transport key pair. This key pair
+ * is used to protected EE's private key in transit.
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public abstract class EncryptionUnit implements IEncryptionUnit {
+
+ /* Establish one constant IV for base class, to be used for
+ internal operations. Constant IV acceptable for symmetric keys.
+ */
+ private byte iv[] = {0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1};
+ protected IVParameterSpec IV = null;
+
+ public EncryptionUnit() {
+ CMS.debug("EncryptionUnit.EncryptionUnit this: " + this.toString());
+
+ IV = new IVParameterSpec(iv);
+ }
+
+ public abstract CryptoToken getToken();
+
+ public abstract CryptoToken getInternalToken();
+
+ public abstract PublicKey getPublicKey();
+
+ public abstract PrivateKey getPrivateKey();
+
+ /**
+ * Protects the private key so that it can be stored in
+ * internal database.
+ */
+ public byte[] encryptInternalPrivate(byte priKey[])
+ throws EBaseException {
+ try {
+ CMS.debug("EncryptionUnit.encryptInternalPrivate");
+ CryptoToken token = getToken();
+ CryptoToken internalToken = getInternalToken();
+
+ // (1) generate session key
+ org.mozilla.jss.crypto.KeyGenerator kg =
+ internalToken.getKeyGenerator(KeyGenAlgorithm.DES3);
+ SymmetricKey sk = kg.generate();
+
+ // (2) wrap private key with session key
+ Cipher cipher = internalToken.getCipherContext(
+ EncryptionAlgorithm.DES3_CBC_PAD);
+
+ cipher.initEncrypt(sk, IV);
+ byte pri[] = cipher.doFinal(priKey);
+
+ // (3) wrap session with transport public
+ KeyWrapper rsaWrap = internalToken.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+
+ rsaWrap.initWrap(getPublicKey(), null);
+ byte session[] = rsaWrap.wrap(sk);
+
+ // use MY own structure for now:
+ // SEQUENCE {
+ // encryptedSession OCTET STRING,
+ // encryptedPrivate OCTET STRING
+ // }
+
+ DerOutputStream tmp = new DerOutputStream();
+ DerOutputStream out = new DerOutputStream();
+
+ tmp.putOctetString(session);
+ tmp.putOctetString(pri);
+ out.write(DerValue.tag_Sequence, tmp);
+
+ return out.toByteArray();
+ } catch (TokenException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ } catch (CharConversionException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ } catch (InvalidAlgorithmParameterException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ } catch (InvalidKeyException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ } catch (BadPaddingException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ } catch (IllegalBlockSizeException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ } catch (IOException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_INTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::encryptInternalPrivate " + e.toString());
+ return null;
+ }
+ }
+
+ /**
+ * Wraps the data using transport public key.
+ */
+ public byte[] wrap(PrivateKey priKey) throws EBaseException {
+ try {
+
+ CMS.debug("EncryptionUnit.wrap");
+ CryptoToken token = getToken();
+ CryptoToken internalToken = getInternalToken();
+
+ // (1) generate session key
+ org.mozilla.jss.crypto.KeyGenerator kg =
+ token.getKeyGenerator(KeyGenAlgorithm.DES3);
+ // internalToken.getKeyGenerator(KeyGenAlgorithm.DES3);
+ SymmetricKey.Usage usages[] = new SymmetricKey.Usage[3];
+ usages[0] = SymmetricKey.Usage.ENCRYPT;
+ usages[1] = SymmetricKey.Usage.WRAP;
+ usages[2] = SymmetricKey.Usage.UNWRAP;
+ kg.setKeyUsages(usages);
+ kg.temporaryKeys(true);
+ SymmetricKey sk = kg.generate();
+ CMS.debug("EncryptionUnit:wrap() session key generated on slot: "+token.getName());
+
+ // (2) wrap private key with session key
+ // KeyWrapper wrapper = internalToken.getKeyWrapper(
+ KeyWrapper wrapper = token.getKeyWrapper(
+ KeyWrapAlgorithm.DES3_CBC_PAD);
+ CMS.debug("EncryptionUnit:wrap() got key wrapper");
+
+ wrapper.initWrap(sk, IV);
+ CMS.debug("EncryptionUnit:wrap() key wrapper initialized");
+ byte pri[] = wrapper.wrap(priKey);
+ CMS.debug("EncryptionUnit:wrap() privKey wrapped");
+
+ // (3) wrap session with transport public
+ KeyWrapper rsaWrap = token.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+
+ rsaWrap.initWrap(getPublicKey(), null);
+ byte session[] = rsaWrap.wrap(sk);
+ CMS.debug("EncryptionUnit:wrap() sessin key wrapped");
+
+ // use MY own structure for now:
+ // SEQUENCE {
+ // encryptedSession OCTET STRING,
+ // encryptedPrivate OCTET STRING
+ // }
+
+ DerOutputStream tmp = new DerOutputStream();
+ DerOutputStream out = new DerOutputStream();
+
+ tmp.putOctetString(session);
+ tmp.putOctetString(pri);
+ out.write(DerValue.tag_Sequence, tmp);
+
+ return out.toByteArray();
+ } catch (TokenException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+ Debug.trace("EncryptionUnit::wrap " + e.toString());
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+ Debug.trace("EncryptionUnit::wrap " + e.toString());
+ return null;
+ } catch (CharConversionException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+ Debug.trace("EncryptionUnit::wrap " + e.toString());
+ return null;
+ } catch (InvalidAlgorithmParameterException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+ Debug.trace("EncryptionUnit::wrap " + e.toString());
+ return null;
+ } catch (InvalidKeyException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+ Debug.trace("EncryptionUnit::wrap " + e.toString());
+ return null;
+ } catch (IOException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+ Debug.trace("EncryptionUnit::wrap " + e.toString());
+ return null;
+ }
+ }
+
+ /**
+ * External unwrapping. Unwraps the data using
+ * the transport private key.
+ */
+ public SymmetricKey unwrap_sym(byte encSymmKey[], SymmetricKey.Usage usage)
+ {
+ try {
+ CryptoToken token = getToken();
+ CryptoToken internalToken = getInternalToken();
+
+ // (1) unwrap the session
+ CMS.debug("EncryptionUnit::unwrap_sym() on slot: "+token.getName());
+ PrivateKey priKey = getPrivateKey();
+ String priKeyAlgo = priKey.getAlgorithm();
+ CMS.debug("EncryptionUnit::unwrap_sym() private key algo: " + priKeyAlgo);
+ KeyWrapper keyWrapper = null;
+ if (priKeyAlgo.equals("EC")) {
+ keyWrapper = token.getKeyWrapper(KeyWrapAlgorithm.AES_ECB);
+ keyWrapper.initUnwrap(priKey, null);
+ } else {
+ keyWrapper = token.getKeyWrapper(KeyWrapAlgorithm.RSA);
+ keyWrapper.initUnwrap(priKey, null);
+ }
+ SymmetricKey sk = keyWrapper.unwrapSymmetric(encSymmKey,
+ SymmetricKey.DES3, usage,
+ 0);
+ return sk;
+ } catch (Exception e) {
+ CMS.debug("EncryptionUnit::unwrap_sym() error:" +
+ e.toString());
+ return null;
+ }
+ }
+
+ public SymmetricKey unwrap_sym(byte encSymmKey[])
+ {
+ return unwrap_sym(encSymmKey, SymmetricKey.Usage.WRAP);
+ }
+
+ public SymmetricKey unwrap_encrypt_sym(byte encSymmKey[])
+ {
+ return unwrap_sym(encSymmKey, SymmetricKey.Usage.ENCRYPT);
+ }
+
+ /**
+ * Decrypts the user private key.
+ */
+ public byte[] decryptExternalPrivate(byte encSymmKey[],
+ String symmAlgOID, byte symmAlgParams[],
+ byte encValue[])
+ throws EBaseException {
+ try {
+
+ CMS.debug("EncryptionUnit.decryptExternalPrivate");
+ CryptoToken token = getToken();
+ CryptoToken internalToken = getInternalToken();
+
+ // (1) unwrap the session
+ KeyWrapper rsaWrap = token.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+
+ rsaWrap.initUnwrap(getPrivateKey(), null);
+ SymmetricKey sk = rsaWrap.unwrapSymmetric(encSymmKey,
+ SymmetricKey.DES3, SymmetricKey.Usage.DECRYPT,
+ 0);
+
+ // (2) unwrap the pri
+ Cipher cipher = token.getCipherContext(
+ EncryptionAlgorithm.DES3_CBC_PAD // XXX
+ );
+
+ cipher.initDecrypt(sk, new IVParameterSpec(
+ symmAlgParams));
+ return cipher.doFinal(encValue);
+ } catch (IllegalBlockSizeException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_EXTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::decryptExternalPrivate " + e.toString());
+ return null;
+ } catch (BadPaddingException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_EXTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::decryptExternalPrivate " + e.toString());
+ return null;
+ } catch (TokenException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_EXTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::decryptExternalPrivate " + e.toString());
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_EXTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::decryptExternalPrivate " + e.toString());
+ return null;
+ } catch (InvalidAlgorithmParameterException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_EXTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::decryptExternalPrivate " + e.toString());
+ return null;
+ } catch (InvalidKeyException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_EXTERNAL", e.toString()));
+ Debug.trace("EncryptionUnit::decryptExternalPrivate " + e.toString());
+ return null;
+ }
+ }
+
+ /**
+ * External unwrapping. Unwraps the data using
+ * the transport private key.
+ */
+ public PrivateKey unwrap(byte encSymmKey[],
+ String symmAlgOID, byte symmAlgParams[],
+ byte encValue[], PublicKey pubKey)
+ throws EBaseException {
+ try {
+ CryptoToken token = getToken();
+ CryptoToken internalToken = getInternalToken();
+
+ CMS.debug("EncryptionUnit.unwrap symAlgParams: " + new String(symmAlgParams));
+ // (1) unwrap the session
+ KeyWrapper rsaWrap = token.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+
+ rsaWrap.initUnwrap(getPrivateKey(), null);
+ SymmetricKey sk = rsaWrap.unwrapSymmetric(encSymmKey,
+ SymmetricKey.DES3, SymmetricKey.Usage.UNWRAP,
+ 0);
+
+ // (2) unwrap the pri
+ KeyWrapper wrapper = token.getKeyWrapper(
+ KeyWrapAlgorithm.DES3_CBC_PAD // XXX
+ );
+
+ wrapper.initUnwrap(sk, new IVParameterSpec(
+ symmAlgParams));
+ PrivateKey pk = wrapper.unwrapPrivate(encValue,
+ PrivateKey.RSA, pubKey);
+
+ return pk;
+ } catch (TokenException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (InvalidAlgorithmParameterException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (InvalidKeyException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ }
+ }
+
+ public byte[] decryptInternalPrivate(byte wrappedKeyData[])
+ throws EBaseException {
+ try {
+ CMS.debug("EncryptionUnit.decryptInternalPrivate");
+ DerValue val = new DerValue(wrappedKeyData);
+ // val.tag == DerValue.tag_Sequence
+ DerInputStream in = val.data;
+ DerValue dSession = in.getDerValue();
+ byte session[] = dSession.getOctetString();
+ DerValue dPri = in.getDerValue();
+ byte pri[] = dPri.getOctetString();
+
+ CryptoToken token = getToken();
+ CryptoToken internalToken = getInternalToken();
+
+ // (1) unwrap the session
+ CMS.debug("decryptInternalPrivate(): getting key wrapper on slot:"+ token.getName());
+ KeyWrapper rsaWrap = token.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+
+ rsaWrap.initUnwrap(getPrivateKey(), null);
+ SymmetricKey sk = rsaWrap.unwrapSymmetric(session,
+ SymmetricKey.DES3, SymmetricKey.Usage.DECRYPT, 0);
+
+ // (2) unwrap the pri
+ Cipher cipher = token.getCipherContext(
+ EncryptionAlgorithm.DES3_CBC_PAD);
+
+ cipher.initDecrypt(sk, IV);
+ return cipher.doFinal(pri);
+ } catch (IllegalBlockSizeException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_DECRYPT", e.toString()));
+ Debug.trace("EncryptionUnit::decryptInternalPrivate " + e.toString());
+ return null;
+ } catch (BadPaddingException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_DECRYPT", e.toString()));
+ Debug.trace("EncryptionUnit::decryptInternalPrivate " + e.toString());
+ return null;
+ } catch (TokenException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_DECRYPT", e.toString()));
+ Debug.trace("EncryptionUnit::decryptInternalPrivate " + e.toString());
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_DECRYPT", e.toString()));
+ Debug.trace("EncryptionUnit::decryptInternalPrivate " + e.toString());
+ return null;
+ } catch (InvalidAlgorithmParameterException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_DECRYPT", e.toString()));
+ Debug.trace("EncryptionUnit::decryptInternalPrivate " + e.toString());
+ return null;
+ } catch (InvalidKeyException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_DECRYPT", e.toString()));
+ Debug.trace("EncryptionUnit::decryptInternalPrivate " + e.toString());
+ return null;
+ } catch (IOException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_DECRYPT", e.toString()));
+ Debug.trace("EncryptionUnit::decryptInternalPrivate " + e.toString());
+ return null;
+ }
+ }
+
+ /**
+ * Internal unwrapping.
+ */
+ public PrivateKey unwrap_temp(byte wrappedKeyData[], PublicKey pubKey)
+ throws EBaseException {
+ return _unwrap(wrappedKeyData, pubKey, true);
+ }
+
+ /**
+ * Internal unwrapping.
+ */
+ public PrivateKey unwrap(byte wrappedKeyData[], PublicKey pubKey)
+ throws EBaseException {
+ return _unwrap(wrappedKeyData, pubKey, false);
+ }
+
+ /**
+ * Internal unwrapping.
+ */
+ private PrivateKey _unwrap(byte wrappedKeyData[], PublicKey
+ pubKey, boolean temporary)
+ throws EBaseException {
+ try {
+ DerValue val = new DerValue(wrappedKeyData);
+ // val.tag == DerValue.tag_Sequence
+ DerInputStream in = val.data;
+ DerValue dSession = in.getDerValue();
+ byte session[] = dSession.getOctetString();
+ DerValue dPri = in.getDerValue();
+ byte pri[] = dPri.getOctetString();
+
+ CryptoToken token = getToken();
+ // (1) unwrap the session
+ KeyWrapper rsaWrap = token.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+
+ rsaWrap.initUnwrap(getPrivateKey(), null);
+ SymmetricKey sk = rsaWrap.unwrapSymmetric(session,
+ SymmetricKey.DES3, SymmetricKey.Usage.UNWRAP, 0);
+
+ // (2) unwrap the pri
+ KeyWrapper wrapper = token.getKeyWrapper(
+ KeyWrapAlgorithm.DES3_CBC_PAD);
+
+ wrapper.initUnwrap(sk, IV);
+
+ PrivateKey pk = null;
+ if (temporary) {
+ pk = wrapper.unwrapTemporaryPrivate(pri,
+ PrivateKey.RSA, pubKey);
+ } else {
+ pk = wrapper.unwrapPrivate(pri,
+ PrivateKey.RSA, pubKey);
+ }
+ return pk;
+ } catch (TokenException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ CMS.debug(e);
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (InvalidAlgorithmParameterException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (InvalidKeyException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.printStackTrace(e);
+ return null;
+ } catch (IOException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+ Debug.trace("EncryptionUnit::unwrap " + e.toString());
+ return null;
+ } catch (Exception e) {
+ Debug.printStackTrace(e);
+ return null;
+ }
+ }
+
+ /**
+ * Verify the given key pair.
+ */
+ public void verify(PublicKey publicKey, PrivateKey privateKey) throws
+ EBaseException {
+ }
+}
+
diff --git a/pki/base/kra/src/com/netscape/kra/EnrollmentService.java b/pki/base/kra/src/com/netscape/kra/EnrollmentService.java
new file mode 100644
index 000000000..239cfef0d
--- /dev/null
+++ b/pki/base/kra/src/com/netscape/kra/EnrollmentService.java
@@ -0,0 +1,1007 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.io.IOException;
+import java.io.ByteArrayInputStream;
+import java.math.BigInteger;
+import java.security.*;
+// ADDED next line and COMMENTED out following line by MLH on 1/9/99
+import netscape.security.provider.RSAPublicKey;
+// import java.security.interfaces.RSAPublicKey;
+import java.security.cert.CertificateException;
+import netscape.security.util.*;
+import netscape.security.util.BigInt;
+import netscape.security.x509.*;
+import org.mozilla.jss.asn1.*;
+import org.mozilla.jss.pkix.cms.*;
+import org.mozilla.jss.pkix.cms.EnvelopedData;
+//import org.mozilla.jss.pkcs7.*;
+import org.mozilla.jss.pkix.crmf.*;
+import org.mozilla.jss.pkix.crmf.EncryptedKey;
+import org.mozilla.jss.pkix.crmf.EncryptedKey.Type;
+import org.mozilla.jss.pkix.primitive.*;
+import org.mozilla.jss.pkix.primitive.AVA;
+import com.netscape.certsrv.util.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.security.*;
+import com.netscape.cmscore.crmf.*;
+import com.netscape.certsrv.kra.*;
+import com.netscape.certsrv.base.*;
+//import com.netscape.cmscore.ca.*;
+import com.netscape.cmscore.dbs.*;
+import com.netscape.certsrv.profile.*;
+import com.netscape.certsrv.dbs.keydb.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.apps.CMS;
+
+
+/**
+ * A class represents archival request processor. It
+ * passes the request to the policy processor, and
+ * process the request according to the policy decision.
+ * <P>
+ * If policy returns ACCEPTED, the request will be
+ * processed immediately.
+ * <P>
+ * Upon processing, the incoming user key is unwrapped
+ * with the transport key of KRA, and then wrapped
+ * with the storage key. The encrypted key is stored
+ * in the internal database for long term storage.
+ * <P>
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class EnrollmentService implements IService {
+
+ // constants
+ public static final String CRMF_REQUEST = "CRMFRequest";
+ public final static String ATTR_KEY_RECORD = "keyRecord";
+ public final static String ATTR_PROOF_OF_ARCHIVAL =
+ "proofOfArchival";
+
+ // private
+ private IKeyRecoveryAuthority mKRA = null;
+ private ITransportKeyUnit mTransportUnit = null;
+ private IStorageKeyUnit mStorageUnit = null;
+ private ILogger mSignedAuditLogger = CMS.getSignedAuditLogger();
+
+
+ private final static byte EOL[] = { Character.LINE_SEPARATOR };
+ private final static String
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_4";
+ private final static String
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED_3";
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_4";
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_4";
+ /**
+ * Constructs request processor.
+ * <P>
+ *
+ * @param kra key recovery authority
+ */
+ public EnrollmentService(IKeyRecoveryAuthority kra) {
+ mKRA = kra;
+ mTransportUnit = kra.getTransportKeyUnit();
+ mStorageUnit = kra.getStorageKeyUnit();
+ }
+
+ public PKIArchiveOptions toPKIArchiveOptions(byte options[]) {
+ ByteArrayInputStream bis = new ByteArrayInputStream(options);
+ PKIArchiveOptions archOpts = null;
+
+ try {
+ archOpts = (PKIArchiveOptions)
+ (new PKIArchiveOptions.Template()).decode(bis);
+ } catch (Exception e) {
+ CMS.debug("EnrollProfile: getPKIArchiveOptions " + e.toString());
+ }
+ return archOpts;
+ }
+
+ /**
+ * Services an enrollment/archival request.
+ * <P>
+ *
+ * @param request enrollment request
+ * @return serving successful or not
+ * @exception EBaseException failed to serve
+ */
+ public boolean serviceRequest(IRequest request)
+ throws EBaseException {
+
+ IStatsSubsystem statsSub = (IStatsSubsystem)CMS.getSubsystem("stats");
+ if (statsSub != null) {
+ statsSub.startTiming("archival", true /* main action */);
+ }
+
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+ String auditRequesterID = auditRequesterID();
+ String auditArchiveID = ILogger.UNIDENTIFIED;
+ String auditPublicKey = ILogger.UNIDENTIFIED;
+
+ String id = request.getRequestId().toString();
+ if (id != null) {
+ auditArchiveID = id.trim();
+ }
+ if (CMS.debugOn())
+ CMS.debug("EnrollmentServlet: KRA services enrollment request");
+
+ SessionContext sContext = SessionContext.getContext();
+ String agentId = (String) sContext.get(SessionContext.USER_ID);
+ AuthToken authToken = (AuthToken) sContext.get(SessionContext.AUTH_TOKEN);
+
+ mKRA.log(ILogger.LL_INFO, "KRA services enrollment request");
+ // unwrap user key with transport
+ byte unwrapped[] = null;
+ PKIArchiveOptionsContainer aOpts[] = null;
+
+ String profileId = request.getExtDataInString("profileId");
+
+ if (profileId == null || profileId.equals("")) {
+ try {
+ aOpts = CRMFParser.getPKIArchiveOptions(
+ request.getExtDataInString(IRequest.HTTP_PARAMS, CRMF_REQUEST));
+ } catch (IOException e) {
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_INVALID_PRIVATE_KEY"));
+ }
+ } else {
+ // profile-based request
+ PKIArchiveOptions options = (PKIArchiveOptions)
+ toPKIArchiveOptions(
+ request.getExtDataInByteArray(IEnrollProfile.REQUEST_ARCHIVE_OPTIONS));
+
+ aOpts = new PKIArchiveOptionsContainer[1];
+ aOpts[0] = new PKIArchiveOptionsContainer(options,
+ 0/* not matter */);
+
+ request.setExtData("dbStatus", "NOT_UPDATED");
+ }
+
+ for (int i = 0; i < aOpts.length; i++) {
+ ArchiveOptions opts = new ArchiveOptions(aOpts[i].mAO);
+
+ if (statsSub != null) {
+ statsSub.startTiming("decrypt_user_key");
+ }
+ mKRA.log(ILogger.LL_INFO, "KRA decrypts external private");
+ if (CMS.debugOn())
+ CMS.debug("EnrollmentService::about to decryptExternalPrivate");
+ unwrapped = mTransportUnit.decryptExternalPrivate(
+ opts.getEncSymmKey(),
+ opts.getSymmAlgOID(),
+ opts.getSymmAlgParams(),
+ opts.getEncValue());
+ if (statsSub != null) {
+ statsSub.endTiming("decrypt_user_key");
+ }
+ if (CMS.debugOn())
+ CMS.debug("EnrollmentService::finished decryptExternalPrivate");
+ if (unwrapped == null) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_UNWRAP_USER_KEY"));
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_INVALID_PRIVATE_KEY"));
+ }
+
+ // retrieve pubic key
+ X509Key publicKey = getPublicKey(request, aOpts[i].mReqPos);
+ byte publicKeyData[] = publicKey.getEncoded();
+
+ if (publicKeyData == null) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_PUBLIC_NOT_FOUND"));
+
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_INVALID_PUBLIC_KEY"));
+ }
+
+ /* Bugscape #54948 - verify public and private key before archiving key */
+
+ if (statsSub != null) {
+ statsSub.startTiming("verify_key");
+ }
+ if (verifyKeyPair(publicKeyData, unwrapped) == false) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_PUBLIC_NOT_FOUND"));
+
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_INVALID_PUBLIC_KEY"));
+ }
+ if (statsSub != null) {
+ statsSub.endTiming("verify_key");
+ }
+
+ /**
+ mTransportKeyUnit.verify(pKey, unwrapped);
+ **/
+ // retrieve owner name
+ String owner = getOwnerName(request, aOpts[i].mReqPos);
+
+ if (owner == null) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_OWNER_NAME_NOT_FOUND"));
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_INVALID_KEYRECORD"));
+ }
+
+ //
+ // privateKeyData ::= SEQUENCE {
+ // sessionKey OCTET_STRING,
+ // encKey OCTET_STRING,
+ // }
+ //
+ mKRA.log(ILogger.LL_INFO, "KRA encrypts internal private");
+ if (statsSub != null) {
+ statsSub.startTiming("encrypt_user_key");
+ }
+ byte privateKeyData[] = mStorageUnit.encryptInternalPrivate(
+ unwrapped);
+ if (statsSub != null) {
+ statsSub.endTiming("encrypt_user_key");
+ }
+
+ if (privateKeyData == null) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_WRAP_USER_KEY"));
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_INVALID_PRIVATE_KEY"));
+ }
+
+ // create key record
+ KeyRecord rec = new KeyRecord(null, publicKeyData,
+ privateKeyData, owner,
+ publicKey.getAlgorithmId().getOID().toString(), agentId);
+
+ if (rec == null) {
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_INVALID_KEYRECORD"));
+ }
+
+ // we deal with RSA key only
+ try {
+ RSAPublicKey rsaPublicKey = new RSAPublicKey(publicKeyData);
+
+ rec.setKeySize(Integer.valueOf(rsaPublicKey.getKeySize()));
+ } catch (InvalidKeyException e) {
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_INVALID_KEYRECORD"));
+ }
+
+
+ // if record alreay has a serial number, yell out.
+ if (rec.getSerialNumber() != null) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_INVALID_SERIAL_NUMBER",
+ rec.getSerialNumber().toString()));
+
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_INVALID_STATE"));
+ }
+ IKeyRepository storage = mKRA.getKeyRepository();
+ BigInteger serialNo = storage.getNextSerialNumber();
+
+ if (serialNo == null) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_GET_NEXT_SERIAL"));
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_INVALID_STATE"));
+ }
+ if (i == 0) {
+ rec.set(KeyRecord.ATTR_ID, serialNo);
+ request.setExtData(ATTR_KEY_RECORD, serialNo);
+ } else {
+ rec.set(KeyRecord.ATTR_ID + i, serialNo);
+ request.setExtData(ATTR_KEY_RECORD + i, serialNo);
+ }
+
+ mKRA.log(ILogger.LL_INFO, "KRA adding key record " + serialNo);
+ if (statsSub != null) {
+ statsSub.startTiming("store_key");
+ }
+ storage.addKeyRecord(rec);
+ if (statsSub != null) {
+ statsSub.endTiming("store_key");
+ }
+
+ if (CMS.debugOn())
+ CMS.debug("EnrollmentService: key record 0x" + serialNo.toString(16)
+ + " (" + owner + ") archived");
+
+ mKRA.log(ILogger.LL_INFO, "key record 0x" +
+ serialNo.toString(16)
+ + " (" + owner + ") archived");
+
+ // for audit log
+ String authMgr = AuditFormat.NOAUTH;
+
+ if (authToken != null) {
+ authMgr =
+ authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME);
+ }
+ CMS.getLogger().log(ILogger.EV_AUDIT,
+ ILogger.S_KRA,
+ AuditFormat.LEVEL,
+ AuditFormat.FORMAT,
+ new Object[] {
+ IRequest.KEYARCHIVAL_REQUEST,
+ request.getRequestId(),
+ AuditFormat.FROMAGENT + " agentID: " + agentId,
+ authMgr,
+ "completed",
+ owner,
+ "serial number: 0x" + serialNo.toString(16)}
+ );
+
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+
+ // store a message in the signed audit log file
+ auditPublicKey = auditPublicKey(rec);
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditPublicKey);
+
+ audit(auditMessage);
+
+ // Xxx - should sign this proof of archival
+ ProofOfArchival mProof = new ProofOfArchival(serialNo,
+ owner, mKRA.getX500Name().toString(),
+ rec.getCreateTime());
+
+ DerOutputStream mProofOut = new DerOutputStream();
+ mProof.encode(mProofOut);
+ if (i == 0) {
+ request.setExtData(ATTR_PROOF_OF_ARCHIVAL,
+ mProofOut.toByteArray());
+ } else {
+ request.setExtData(ATTR_PROOF_OF_ARCHIVAL + i,
+ mProofOut.toByteArray());
+ }
+
+ } // for
+
+ /*
+ request.delete(IEnrollProfile.REQUEST_SUBJECT_NAME);
+ request.delete(IEnrollProfile.REQUEST_EXTENSIONS);
+ request.delete(IEnrollProfile.REQUEST_VALIDITY);
+ request.delete(IEnrollProfile.REQUEST_KEY);
+ request.delete(IEnrollProfile.REQUEST_SIGNING_ALGORITHM);
+ request.delete(IEnrollProfile.REQUEST_LOCALE);
+ */
+
+ request.setExtData(IRequest.RESULT, IRequest.RES_SUCCESS);
+
+ // update request
+ mKRA.log(ILogger.LL_INFO, "KRA updating request");
+ mKRA.getRequestQueue().updateRequest(request);
+
+ if (statsSub != null) {
+ statsSub.endTiming("archival");
+ }
+
+ return true;
+ }
+
+ public boolean verifyKeyPair(byte publicKeyData[], byte privateKeyData[])
+ {
+ try {
+ DerValue publicKeyVal = new DerValue(publicKeyData);
+ DerInputStream publicKeyIn = publicKeyVal.data;
+ publicKeyIn.getSequence(0);
+ DerValue publicKeyDer = new DerValue(publicKeyIn.getBitString());
+ DerInputStream publicKeyDerIn = publicKeyDer.data;
+ BigInt publicKeyModulus = publicKeyDerIn.getInteger();
+ BigInt publicKeyExponent = publicKeyDerIn.getInteger();
+
+ DerValue privateKeyVal = new DerValue(privateKeyData);
+ if (privateKeyVal.tag != DerValue.tag_Sequence)
+ return false;
+ DerInputStream privateKeyIn = privateKeyVal.data;
+ privateKeyIn.getInteger();
+ privateKeyIn.getSequence(0);
+ DerValue privateKeyDer = new DerValue(privateKeyIn.getOctetString());
+ DerInputStream privateKeyDerIn = privateKeyDer.data;
+ BigInt privateKeyVersion = privateKeyDerIn.getInteger();
+ BigInt privateKeyModulus = privateKeyDerIn.getInteger();
+ BigInt privateKeyExponent = privateKeyDerIn.getInteger();
+
+ if (!publicKeyModulus.equals(privateKeyModulus)) {
+ CMS.debug("verifyKeyPair modulus mismatch publicKeyModulus=" + publicKeyModulus + " privateKeyModulus=" + privateKeyModulus);
+ return false;
+ }
+
+ if (!publicKeyExponent.equals(privateKeyExponent)) {
+ CMS.debug("verifyKeyPair exponent mismatch publicKeyExponent=" + publicKeyExponent + " privateKeyExponent=" + privateKeyExponent);
+ return false;
+ }
+
+ return true;
+ } catch (Exception e) {
+ CMS.debug("verifyKeyPair error " + e);
+ return false;
+ }
+ }
+
+ private static final OBJECT_IDENTIFIER PKIARCHIVEOPTIONS_OID =
+ new OBJECT_IDENTIFIER(new long[] {1, 3, 6, 1, 5, 5, 7, 5, 1, 4}
+ );
+
+ /**
+ * Retrieves PKIArchiveOptions from CRMF request.
+ *
+ * @param crmfBlob CRMF request
+ * @return PKIArchiveOptions
+ * @exception EBaseException failed to extrace option
+ */
+ public static PKIArchiveOptionsContainer[] getPKIArchiveOptions(String crmfBlob)
+ throws EBaseException {
+ Vector options = new Vector();
+
+ if (CMS.debugOn())
+ CMS.debug("EnrollmentService::getPKIArchiveOptions> crmfBlob=" + crmfBlob);
+ byte[] crmfBerBlob = null;
+
+ crmfBerBlob = com.netscape.osutil.OSUtil.AtoB(crmfBlob);
+ ByteArrayInputStream crmfBerBlobIn = new
+ ByteArrayInputStream(crmfBerBlob);
+ SEQUENCE crmfmsgs = null;
+
+ try {
+ crmfmsgs = (SEQUENCE) new
+ SEQUENCE.OF_Template(new
+ CertReqMsg.Template()).decode(
+ crmfBerBlobIn);
+ } catch (IOException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[crmf msgs]" + e.toString()));
+ } catch (InvalidBERException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[crmf msgs]" + e.toString()));
+ }
+
+ for (int z = 0; z < crmfmsgs.size(); z++) {
+ CertReqMsg certReqMsg = (CertReqMsg)
+ crmfmsgs.elementAt(z);
+ CertRequest certReq = certReqMsg.getCertReq();
+
+ // try to locate PKIArchiveOption control
+ AVA archAva = null;
+
+ try {
+ for (int i = 0; i < certReq.numControls(); i++) {
+ AVA ava = certReq.controlAt(i);
+ OBJECT_IDENTIFIER oid = ava.getOID();
+
+ if (oid.equals(PKIARCHIVEOPTIONS_OID)) {
+ archAva = ava;
+ break;
+ }
+ }
+ } catch (Exception e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "no PKIArchiveOptions found " + e.toString()));
+ }
+ if (archAva != null) {
+
+ ASN1Value archVal = archAva.getValue();
+ ByteArrayInputStream bis = new ByteArrayInputStream(ASN1Util.encode(archVal));
+ PKIArchiveOptions archOpts = null;
+
+ try {
+ archOpts = (PKIArchiveOptions)
+ (new PKIArchiveOptions.Template()).decode(bis);
+ } catch (IOException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[PKIArchiveOptions]" + e.toString()));
+ } catch (InvalidBERException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[PKIArchiveOptions]" + e.toString()));
+ }
+ options.addElement(new PKIArchiveOptionsContainer(archOpts, z));
+ }
+ }
+ if (options.size() == 0) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "PKIArchiveOptions found"));
+ } else {
+ PKIArchiveOptionsContainer p[] = new PKIArchiveOptionsContainer[options.size()];
+
+ options.copyInto(p);
+ return p;
+ }
+ }
+
+ /**
+ * Retrieves public key from request.
+ *
+ * @param request CRMF request
+ * @return JSS public key
+ * @exception EBaseException failed to retrieve public key
+ */
+ private X509Key getPublicKey(IRequest request, int i) throws EBaseException {
+ String profileId = request.getExtDataInString("profileId");
+
+ if (profileId != null && !profileId.equals("")) {
+ byte[] certKeyData = request.getExtDataInByteArray(IEnrollProfile.REQUEST_KEY);
+ if (certKeyData != null) {
+ try {
+ CertificateX509Key x509key = new CertificateX509Key(
+ new ByteArrayInputStream(certKeyData));
+
+ return (X509Key) x509key.get(CertificateX509Key.KEY);
+ } catch (Exception e1) {
+ CMS.debug("EnrollService: (Archival) getPublicKey " +
+ e1.toString());
+ }
+ }
+ return null;
+ }
+
+ // retrieve x509 Key from request
+ X509CertInfo certInfo[] =
+ request.getExtDataInCertInfoArray(IRequest.CERT_INFO);
+ CertificateX509Key pX509Key = null;
+
+ try {
+ pX509Key = (CertificateX509Key)
+ certInfo[i].get(X509CertInfo.KEY);
+ } catch (IOException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_GET_PUBLIC_KEY", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[" + X509CertInfo.KEY + "]" + e.toString()));
+ } catch (CertificateException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_GET_PUBLIC_KEY", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[" + X509CertInfo.KEY + "]" + e.toString()));
+ }
+ X509Key pKey = null;
+
+ try {
+ pKey = (X509Key) pX509Key.get(
+ CertificateX509Key.KEY);
+ } catch (IOException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_GET_PUBLIC_KEY", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[" + CertificateX509Key.KEY + "]" + e.toString()));
+ }
+ return pKey;
+ }
+
+ /**
+ * Retrieves key's owner name from request.
+ *
+ * @param request CRMF request
+ * @return owner name (subject name)
+ * @exception EBaseException failed to retrieve public key
+ */
+ private String getOwnerName(IRequest request, int i)
+ throws EBaseException {
+
+ String profileId = request.getExtDataInString("profileId");
+
+ if (profileId != null && !profileId.equals("")) {
+ CertificateSubjectName sub = request.getExtDataInCertSubjectName(
+ IEnrollProfile.REQUEST_SUBJECT_NAME);
+ if (sub != null) {
+ return sub.toString();
+ }
+ }
+
+ X509CertInfo certInfo[] =
+ request.getExtDataInCertInfoArray(IRequest.CERT_INFO);
+ CertificateSubjectName pSub = null;
+
+ try {
+ pSub = (CertificateSubjectName)
+ certInfo[0].get(X509CertInfo.SUBJECT);
+ } catch (IOException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_GET_OWNER_NAME", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[" + X509CertInfo.SUBJECT + "]" + e.toString()));
+ } catch (CertificateException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_GET_OWNER_NAME", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[" + X509CertInfo.SUBJECT + "]" + e.toString()));
+ }
+ String owner = pSub.toString();
+
+ return owner;
+ }
+
+ /**
+ * Signed Audit Log Public Key
+ *
+ * This method is called to obtain the public key from the passed in
+ * "KeyRecord" for a signed audit log message.
+ * <P>
+ *
+ * @param rec a Key Record
+ * @return key string containing the certificate's public key
+ */
+ private String auditPublicKey(KeyRecord rec) {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ if (rec == null) {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+
+ byte rawData[] = null;
+
+ try {
+ rawData = rec.getPublicKeyData();
+ } catch (EBaseException e) {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+
+ String key = "";
+
+ // convert "rawData" into "base64Data"
+ if (rawData != null) {
+ String base64Data = null;
+
+ base64Data = CMS.BtoA(rawData).trim();
+
+ // extract all line separators from the "base64Data"
+ StringTokenizer st = new StringTokenizer(base64Data, "\r\n");
+ while (st.hasMoreTokens()) {
+ key += st.nextToken();
+ }
+ }
+
+ if (key != null) {
+ key = key.trim();
+
+ if (key.equals("")) {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ } else {
+ return key;
+ }
+ } else {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+ }
+ /**
+ * Signed Audit Log Subject ID
+ *
+ * This method is called to obtain the "SubjectID" for
+ * a signed audit log message.
+ * <P>
+ *
+ * @return id string containing the signed audit log message SubjectID
+ */
+
+ private String auditSubjectID() {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ String subjectID = null;
+
+ // Initialize subjectID
+ SessionContext auditContext = SessionContext.getExistingContext();
+
+ if (auditContext != null) {
+ subjectID = (String)
+ auditContext.get(SessionContext.USER_ID);
+
+ if (subjectID != null) {
+ subjectID = subjectID.trim();
+ } else {
+ subjectID = ILogger.NONROLEUSER;
+ }
+ } else {
+ subjectID = ILogger.UNIDENTIFIED;
+ }
+
+ return subjectID;
+ }
+ /**
+ * Signed Audit Log Requester ID
+ *
+ * This method is called to obtain the "RequesterID" for
+ * a signed audit log message.
+ * <P>
+ *
+ * @return id string containing the signed audit log message RequesterID
+ */
+ private String auditRequesterID() {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ String requesterID = null;
+
+ // Initialize requesterID
+ SessionContext auditContext = SessionContext.getExistingContext();
+
+ if (auditContext != null) {
+ requesterID = (String)
+ auditContext.get(SessionContext.REQUESTER_ID);
+
+ if (requesterID != null) {
+ requesterID = requesterID.trim();
+ } else {
+ requesterID = ILogger.UNIDENTIFIED;
+ }
+ } else {
+ requesterID = ILogger.UNIDENTIFIED;
+ }
+
+ return requesterID;
+ }
+
+ /**
+ * Signed Audit Log Recovery ID
+ *
+ * This method is called to obtain the "RecoveryID" for
+ * a signed audit log message.
+ * <P>
+ *
+ * @return id string containing the signed audit log message RecoveryID
+ */
+ private String auditRecoveryID() {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ String recoveryID = null;
+
+ // Initialize recoveryID
+ SessionContext auditContext = SessionContext.getExistingContext();
+
+ if (auditContext != null) {
+ recoveryID = (String)
+ auditContext.get(SessionContext.RECOVERY_ID);
+
+ if (recoveryID != null) {
+ recoveryID = recoveryID.trim();
+ } else {
+ recoveryID = ILogger.UNIDENTIFIED;
+ }
+ } else {
+ recoveryID = ILogger.UNIDENTIFIED;
+ }
+
+ return recoveryID;
+ }
+
+
+ /**
+ * Signed Audit Log
+ *
+ * This method is called to store messages to the signed audit log.
+ * <P>
+ *
+ * @param msg signed audit log message
+ */
+ private void audit(String msg) {
+ // in this case, do NOT strip preceding/trailing whitespace
+ // from passed-in String parameters
+
+ if (mSignedAuditLogger == null) {
+ return;
+ }
+
+ mSignedAuditLogger.log(ILogger.EV_SIGNED_AUDIT,
+ null,
+ ILogger.S_SIGNED_AUDIT,
+ ILogger.LL_SECURITY,
+ msg);
+ }
+}
+
+
+/**
+ * Parsed and Flattened structure of PKIArchiveOptions.
+ */
+class ArchiveOptions {
+ private String mSymmAlgOID = null;
+ private byte mSymmAlgParams[] = null;
+ private byte mEncSymmKey[] = null;
+ private byte mEncValue[] = null;
+ public ArchiveOptions(PKIArchiveOptions opts) throws EBaseException {
+ try {
+ EncryptedKey key = opts.getEncryptedKey();
+ ANY enveloped_val = null;
+ EncryptedValue val = null;
+ AlgorithmIdentifier symmAlg = null;
+
+ if (key.getType() == org.mozilla.jss.pkix.crmf.EncryptedKey.ENVELOPED_DATA) {
+ CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENVELOPED_DATA");
+ // this is the new RFC4211 EncryptedKey that should
+ // have EnvelopedData to replace the deprecated EncryptedValue
+ enveloped_val = key.getEnvelopedData();
+ byte[] env_b = enveloped_val.getEncoded();
+ EnvelopedData.Template env_template = new EnvelopedData.Template();
+ EnvelopedData env_data =
+ (EnvelopedData) env_template.decode(new ByteArrayInputStream(env_b));
+ EncryptedContentInfo eCI = env_data.getEncryptedContentInfo();
+ symmAlg = eCI.getContentEncryptionAlgorithm();
+ mSymmAlgOID = symmAlg.getOID().toString();
+ mSymmAlgParams = ((OCTET_STRING) ((ANY) symmAlg.getParameters()).decodeWith(OCTET_STRING.getTemplate())).toByteArray();
+
+ SET recipients = env_data.getRecipientInfos();
+ if (recipients.size() <= 0) {
+ CMS.debug("EnrollService: ArchiveOptions() - missing recipient information ");
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[PKIArchiveOptions] missing recipient information "));
+ }
+ //check recpient - later
+ //we only handle one recipient here anyways. so, either the key
+ //can be decrypted or it can't. No risk here.
+ RecipientInfo ri = (RecipientInfo) recipients.elementAt(0);
+ OCTET_STRING key_o = ri.getEncryptedKey();
+ mEncSymmKey = key_o.toByteArray();
+
+ OCTET_STRING oString = eCI.getEncryptedContent();
+ BIT_STRING encVal = new BIT_STRING(oString.toByteArray(), 0);
+ mEncValue = encVal.getBits();
+ CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENVELOPED_DATA done");
+ } else if (key.getType() == org.mozilla.jss.pkix.crmf.EncryptedKey.ENCRYPTED_VALUE) {
+ CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENCRYPTED_VALUE");
+ // this is deprecated: EncryptedValue
+ val = key.getEncryptedValue();
+ symmAlg = val.getSymmAlg();
+ mSymmAlgOID = symmAlg.getOID().toString();
+ mSymmAlgParams = ((OCTET_STRING) ((ANY) symmAlg.getParameters()).decodeWith(OCTET_STRING.getTemplate())).toByteArray();
+ BIT_STRING encSymmKey = val.getEncSymmKey();
+
+ mEncSymmKey = encSymmKey.getBits();
+ BIT_STRING encVal = val.getEncValue();
+
+ mEncValue = encVal.getBits();
+ CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENCRYPTED_VALUE done");
+ } else {
+ CMS.debug("EnrollService: ArchiveOptions() invalid EncryptedKey type");
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[PKIArchiveOptions] type " + key.getType()));
+ }
+
+ } catch (InvalidBERException e) {
+ CMS.debug("EnrollService: ArchiveOptions(): " + e.toString());
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[PKIArchiveOptions]" + e.toString()));
+ } catch (IOException e) {
+ CMS.debug("EnrollService: ArchiveOptions(): " + e.toString());
+ throw new EBaseException("ArchiveOptions() exception caught: "+
+ e.toString());
+ } catch (Exception e) {
+ CMS.debug("EnrollService: ArchiveOptions(): " + e.toString());
+ throw new EBaseException("ArchiveOptions() exception caught: "+
+ e.toString());
+ }
+
+ }
+
+ public String getSymmAlgOID() {
+ return mSymmAlgOID;
+ }
+
+ public byte[] getSymmAlgParams() {
+ return mSymmAlgParams;
+ }
+
+ public byte[] getEncSymmKey() {
+ return mEncSymmKey;
+ }
+
+ public byte[] getEncValue() {
+ return mEncValue;
+ }
+}
diff --git a/pki/base/kra/src/com/netscape/kra/KRANotify.java b/pki/base/kra/src/com/netscape/kra/KRANotify.java
new file mode 100644
index 000000000..f58201e03
--- /dev/null
+++ b/pki/base/kra/src/com/netscape/kra/KRANotify.java
@@ -0,0 +1,53 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.kra.*;
+
+
+/**
+ * A class represents a KRA request queue notify. This
+ * object will be invoked by the request subsystem
+ * when a request is requested for processing.
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class KRANotify extends ARequestNotifier {
+ private IKeyRecoveryAuthority mKRA = null;
+
+ /**
+ * default constructor
+ */
+ public KRANotify() {
+ super();
+ }
+
+ /**
+ * Creates KRA notify.
+ */
+ public KRANotify(IKeyRecoveryAuthority kra) {
+ super();
+ mKRA = kra;
+ }
+
+ // XXX may want to do something else with mKRA ?
+}
diff --git a/pki/base/kra/src/com/netscape/kra/KRAPolicy.java b/pki/base/kra/src/com/netscape/kra/KRAPolicy.java
new file mode 100644
index 000000000..73488e749
--- /dev/null
+++ b/pki/base/kra/src/com/netscape/kra/KRAPolicy.java
@@ -0,0 +1,76 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+
+import com.netscape.certsrv.policy.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.cmscore.util.*;
+import com.netscape.certsrv.kra.*;
+import com.netscape.cmscore.policy.*;
+
+
+/**
+ * KRA Policy.
+ *
+ * @version $Revision$, $Date$
+ */
+public class KRAPolicy implements IPolicy {
+ IConfigStore mConfig = null;
+ IKeyRecoveryAuthority mKRA = null;
+
+ public GenericPolicyProcessor mPolicies = new GenericPolicyProcessor(false);
+
+ public KRAPolicy() {
+ }
+
+ public void init(ISubsystem owner, IConfigStore config)
+ throws EBaseException {
+ mKRA = (IKeyRecoveryAuthority) owner;
+ mConfig = config;
+ mPolicies.init(mKRA, mConfig);
+ }
+
+ public IPolicyProcessor getPolicyProcessor() {
+ return mPolicies;
+ }
+
+ /**
+ */
+ public PolicyResult apply(IRequest r) {
+ if (Debug.ON)
+ Debug.trace("KRA applies policies");
+ mKRA.log(ILogger.LL_INFO, "KRA applies policies");
+ PolicyResult result = mPolicies.apply(r);
+
+ if (result.equals(PolicyResult.DEFERRED)) {
+ // For KRA request, there is deferred
+ if (Debug.ON)
+ Debug.trace("KRA policies return DEFERRED");
+ return PolicyResult.REJECTED;
+ } else {
+ if (Debug.ON)
+ Debug.trace("KRA policies return ACCEPTED");
+ return mPolicies.apply(r);
+ }
+ }
+
+}
+
diff --git a/pki/base/kra/src/com/netscape/kra/KRAService.java b/pki/base/kra/src/com/netscape/kra/KRAService.java
new file mode 100644
index 000000000..0913f1487
--- /dev/null
+++ b/pki/base/kra/src/com/netscape/kra/KRAService.java
@@ -0,0 +1,98 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+
+import java.util.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.kra.*;
+import com.netscape.certsrv.policy.*;
+import com.netscape.cmscore.util.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.apps.CMS;
+
+
+/**
+ * A class represents a KRA request queue service. This
+ * is the service object that is registered with
+ * the request queue. And it acts as a broker to
+ * distribute request into different KRA specific
+ * services. This service registration allows us to support
+ * new request easier.
+ * <P>
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class KRAService implements IService {
+
+ public final static String ENROLLMENT =
+ IRequest.ENROLLMENT_REQUEST;
+ public final static String RECOVERY = IRequest.KEYRECOVERY_REQUEST;
+ public final static String NETKEY_KEYGEN = IRequest.NETKEY_KEYGEN_REQUEST;
+ public final static String NETKEY_KEYRECOVERY = IRequest.NETKEY_KEYRECOVERY_REQUEST;
+
+ // private variables
+ private IKeyRecoveryAuthority mKRA = null;
+ private Hashtable mServices = new Hashtable();
+
+ /**
+ * Constructs KRA service.
+ */
+ public KRAService(IKeyRecoveryAuthority kra) {
+ mKRA = kra;
+ mServices.put(ENROLLMENT, new EnrollmentService(kra));
+ mServices.put(RECOVERY, new RecoveryService(kra));
+ mServices.put(NETKEY_KEYGEN, new NetkeyKeygenService(kra));
+ mServices.put(NETKEY_KEYRECOVERY, new TokenKeyRecoveryService(kra));
+ }
+
+ /**
+ * Processes a KRA request. This method is invoked by
+ * request subsystem.
+ *
+ * @param r request from request subsystem
+ * @exception EBaseException failed to serve
+ */
+ public boolean serviceRequest(IRequest r) throws EBaseException {
+ if (Debug.ON)
+ Debug.trace("KRA services request " +
+ r.getRequestId().toString());
+ mKRA.log(ILogger.LL_INFO, "KRA services request " +
+ r.getRequestId().toString());
+ IService s = (IService) mServices.get(
+ r.getRequestType());
+
+ if (s == null) {
+ r.setExtData(IRequest.RESULT, IRequest.RES_ERROR);
+ r.setExtData(IRequest.ERROR, new EBaseException(
+ CMS.getUserMessage("CMS_BASE_INVALID_OPERATION")));
+ return true;
+ }
+ try {
+ return s.serviceRequest(r);
+ } catch (EBaseException e) {
+ r.setExtData(IRequest.RESULT, IRequest.RES_ERROR);
+ r.setExtData(IRequest.ERROR, e);
+ // return true;
+ // #546508
+ return false;
+ }
+ }
+}
diff --git a/pki/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java b/pki/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java
new file mode 100644
index 000000000..44fec8f32
--- /dev/null
+++ b/pki/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java
@@ -0,0 +1,1778 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+
+import java.lang.*;
+import java.util.*;
+import java.security.cert.X509Certificate;
+import java.security.cert.*;
+import java.math.*;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import netscape.security.x509.*;
+import netscape.security.util.DerOutputStream;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.authority.*;
+import com.netscape.certsrv.listeners.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.dbs.*;
+import com.netscape.certsrv.usrgrp.*;
+import com.netscape.certsrv.dbs.keydb.*;
+import com.netscape.certsrv.dbs.replicadb.*;
+import com.netscape.cmscore.dbs.*;
+import com.netscape.certsrv.policy.*;
+import com.netscape.certsrv.kra.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.security.*;
+import com.netscape.cmscore.request.*;
+import com.netscape.certsrv.apps.*;
+
+import org.mozilla.jss.*;
+import org.mozilla.jss.crypto.*;
+
+
+/**
+ * A class represents an key recovery authority (KRA). A KRA
+ * is responsible to maintain key pairs that have been
+ * escrowed. It provides archive and recovery key pairs
+ * functionalities.
+ * <P>
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class KeyRecoveryAuthority implements IAuthority, IKeyService, IKeyRecoveryAuthority {
+
+ public final static String OFFICIAL_NAME = "Data Recovery Manager";
+
+ /**
+ * Internal Constants
+ */
+
+ private static final String PR_INTERNAL_TOKEN_NAME = "internal";
+ private static final String PARAM_CREDS = "creds";
+ private static final String PARAM_LOCK = "lock";
+ private static final String PARAM_PK12 = "pk12";
+ private static final String PARAM_ERROR = "error";
+ private static final String PARAM_AGENT = "agent";
+
+ private final static String KEY_RESP_NAME = "keyRepository";
+ private static final String PROP_REPLICAID_DN = "dbs.replicadn";
+
+ private Hashtable mRequestProcessor = new Hashtable();
+
+ protected boolean mInitialized = false;
+ protected IConfigStore mConfig = null;
+ protected ILogger mLogger = CMS.getLogger();
+ protected KRAPolicy mPolicy = null;
+ protected X500Name mName = null;
+ protected boolean mQueueRequests = false;
+ protected String mId = null;
+ protected IRequestQueue mRequestQueue = null;
+ protected TransportKeyUnit mTransportKeyUnit = null;
+ protected StorageKeyUnit mStorageKeyUnit = null;
+ protected Hashtable mAutoRecovery = new Hashtable();
+ protected boolean mAutoRecoveryOn = false;
+ protected KeyRepository mKeyDB = null;
+ protected ReplicaIDRepository mReplicaRepot = null;
+ protected IRequestNotifier mNotify = null;
+ protected IRequestNotifier mPNotify = null;
+ protected ISubsystem mOwner = null;
+ protected int mRecoveryIDCounter = 0;
+ protected Hashtable mRecoveryParams = new Hashtable();
+ protected org.mozilla.jss.crypto.X509Certificate mJssCert = null;
+ protected CryptoToken mKeygenToken = null;
+
+ // holds the number of bits of entropy to collect for each keygen
+ private int mEntropyBitsPerKeyPair=0;
+
+ // the number of milliseconds which it is acceptable to block while
+ // getting entropy - anything longer will cause a warning.
+ // 0 means this warning is disabled
+ private int mEntropyBlockWarnMilliseconds = 0;
+
+
+
+ // for the notification listener
+ public IRequestListener mReqInQListener = null;
+
+ private ILogger mSignedAuditLogger = CMS.getSignedAuditLogger();
+ private final static byte EOL[] = { Character.LINE_SEPARATOR };
+ private final static String SIGNED_AUDIT_AGENT_DELIMITER = ", ";
+ private final static String
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_4";
+ private final static String
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED_3";
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_4";
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_ASYNC =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_ASYNC_4";
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_4";
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_ASYNC =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_ASYNC_4";
+
+ /**
+ * Constructs an escrow authority.
+ * <P>
+ */
+ public KeyRecoveryAuthority() {
+ super();
+ }
+
+ /**
+ * Retrieves subsystem identifier.
+ *
+ * @return subsystem id
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * Sets subsystem identifier.
+ *
+ * @param id subsystem id
+ * @exception EBaseException failed to set id
+ */
+ public void setId(String id) throws EBaseException {
+ mId = id;
+ }
+
+ public IPolicyProcessor getPolicyProcessor() {
+ return mPolicy.getPolicyProcessor();
+ }
+
+ // initialize entropy collection parameters
+ private void initEntropy(IConfigStore config)
+ {
+ mEntropyBitsPerKeyPair = 0;
+ mEntropyBlockWarnMilliseconds = 50;
+ // initialize entropy collection
+ IConfigStore ecs = config.getSubStore("entropy");
+ if (ecs != null) {
+ try {
+ mEntropyBitsPerKeyPair = ecs.getInteger("bitsperkeypair",0);
+ mEntropyBlockWarnMilliseconds = ecs.getInteger("blockwarnms",50);
+ } catch (EBaseException eb) {
+ // ok - we deal with missing parameters above
+ }
+ }
+ CMS.debug("KeyRecoveryAuthority Entropy bits = "+mEntropyBitsPerKeyPair);
+ if (mEntropyBitsPerKeyPair == 0) {
+ //log(ILogger.LL_INFO,
+ //CMS.getLogMessage("CMSCORE_KRA_ENTROPY_COLLECTION_DISABLED"));
+ } else {
+ //log(ILogger.LL_INFO,
+ //CMS.getLogMessage("CMSCORE_KRA_ENTROPY_COLLECTION_ENABLED"));
+ CMS.debug("KeyRecoveryAuthority about to add Entropy");
+ addEntropy(false);
+ CMS.debug("KeyRecoveryAuthority back from add Entropy");
+ }
+
+ }
+
+
+ public void addEntropy(boolean logflag) {
+ CMS.debug("KeyRecoveryAuthority addEntropy()");
+ if (mEntropyBitsPerKeyPair == 0) {
+ CMS.debug("KeyRecoveryAuthority returning - disabled()");
+ return;
+ }
+ long start = System.currentTimeMillis();
+ try {
+ com.netscape.cmscore.security.JssSubsystem.getInstance().
+ addEntropy(mEntropyBitsPerKeyPair);
+ } catch (Exception e) {
+ CMS.debug("KeyRecoveryAuthority returning - error - see log file");
+ CMS.debug("exception: "+e.getMessage());
+ CMS.debug(e);
+ if (logflag) {
+ log(ILogger.LL_INFO,
+ CMS.getLogMessage("CMSCORE_KRA_ENTROPY_ERROR",
+ e.getMessage()));
+ }
+ }
+ long end = System.currentTimeMillis();
+ long duration = end-start;
+
+ if (mEntropyBlockWarnMilliseconds > 0 &&
+ duration > mEntropyBlockWarnMilliseconds) {
+
+ CMS.debug("KeyRecoveryAuthority returning - warning - entropy took too long (ms="+
+ duration+")");
+ if (logflag) {
+ log(ILogger.LL_INFO,
+ CMS.getLogMessage("CMSCORE_KRA_ENTROPY_BLOCKED_WARNING",
+ ""+(int)duration));
+ }
+ }
+ CMS.debug("KeyRecoveryAuthority returning ");
+ }
+
+
+
+ /**
+ * Starts this subsystem. It loads and initializes all
+ * necessary components. This subsystem is started by
+ * KRASubsystem.
+ * <P>
+ *
+ * @param owner owner of this subsystem
+ * @param config configuration store for this subsystem
+ * @exception EBaseException failed to start subsystem
+ */
+ public void init(ISubsystem owner, IConfigStore config)
+ throws EBaseException {
+ CMS.debug("KeyRecoveryAuthority init() begins");
+ if (mInitialized)
+ return;
+
+ mConfig = config;
+ mOwner = owner;
+
+ // initialize policy processor
+ mPolicy = new KRAPolicy();
+ mPolicy.init(this, mConfig.getSubStore(PROP_POLICY));
+
+ // create key repository
+ int keydb_inc = mConfig.getInteger(PROP_KEYDB_INC, 5);
+
+ mKeyDB = new KeyRepository(getDBSubsystem(),
+ keydb_inc,
+ "ou=" + KEY_RESP_NAME + ",ou=" +
+ getId() + "," +
+ getDBSubsystem().getBaseDN());
+
+ // read transport key from internal database
+ mTransportKeyUnit = new TransportKeyUnit();
+ try {
+ mTransportKeyUnit.init(this, mConfig.getSubStore(
+ PROP_TRANSPORT_KEY));
+ } catch (EBaseException e) {
+ CMS.debug("KeyRecoveryAuthority: transport unit exception " + e.toString());
+//XXX throw e;
+ return;
+ }
+
+ // retrieve the authority name from transport cert
+ try {
+ mJssCert = mTransportKeyUnit.getCertificate();
+ X509CertImpl certImpl = new
+ X509CertImpl(mJssCert.getEncoded());
+
+ mName = (X500Name) certImpl.getSubjectDN();
+ } catch (CertificateEncodingException e) {
+ CMS.debug("KeyRecoveryAuthority: " + e.toString());
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_LOAD_FAILED",
+ "transport cert " + e.toString()));
+ } catch (CertificateException e) {
+ CMS.debug("KeyRecoveryAuthority: " + e.toString());
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_LOAD_FAILED",
+ "transport cert " + e.toString()));
+ }
+
+ // read transport key from storage key
+ mStorageKeyUnit = new StorageKeyUnit();
+ try {
+ mStorageKeyUnit.init(this,
+ mConfig.getSubStore(PROP_STORAGE_KEY));
+ } catch (EBaseException e) {
+ CMS.debug("KeyRecoveryAuthority: storage unit exception " + e.toString());
+ throw e;
+ }
+
+ // setup token for server-side key generation for user enrollments
+ String serverKeygenTokenName = mConfig.getString("serverKeygenTokenName", null);
+ if (serverKeygenTokenName == null) {
+ CMS.debug("serverKeygenTokenName set to nothing");
+ if (mStorageKeyUnit.getToken() != null) {
+ try {
+ String storageToken = mStorageKeyUnit.getToken().getName();
+ if (!storageToken.equals("internal")) {
+ CMS.debug("Auto set serverKeygenTokenName to " + storageToken);
+ serverKeygenTokenName = storageToken;
+ }
+ } catch (Exception e) {
+ }
+ }
+ }
+ if (serverKeygenTokenName == null) {
+ serverKeygenTokenName = "internal";
+ }
+ if (serverKeygenTokenName.equalsIgnoreCase(PR_INTERNAL_TOKEN_NAME))
+ serverKeygenTokenName = PR_INTERNAL_TOKEN_NAME;
+
+ try {
+ if (serverKeygenTokenName.equalsIgnoreCase(PR_INTERNAL_TOKEN_NAME)) {
+ CMS.debug("KeyRecoveryAuthority: getting internal crypto token for serverkeygen");
+ mKeygenToken = CryptoManager.getInstance().getInternalKeyStorageToken();
+ } else {
+ CMS.debug("KeyRecoveryAuthority: getting HSM token for serverkeygen");
+ mKeygenToken = CryptoManager.getInstance().getTokenByName(serverKeygenTokenName);
+ }
+ CMS.debug("KeyRecoveryAuthority: set up keygenToken");
+ } catch (NoSuchTokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_TOKEN_NOT_FOUND", serverKeygenTokenName));
+ } catch (Exception e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CRYPTOMANAGER_UNINITIALIZED"));
+ }
+
+ CMS.debug("KeyRecoveryAuthority: about to init entropy");
+ initEntropy(mConfig);
+ CMS.debug("KeyRecoveryAuthority: completed init of entropy");
+
+ getLogger().log(ILogger.EV_SYSTEM, ILogger.S_KRA,
+ ILogger.LL_INFO, mName.toString() + " is started");
+
+ // setup the KRA request queue
+ IService service = new KRAService(this);
+
+ mNotify = new KRANotify(this);
+ mPNotify = new ARequestNotifier();
+ IRequestSubsystem reqSub = RequestSubsystem.getInstance();
+ int reqdb_inc = mConfig.getInteger("reqdbInc", 5);
+
+ mRequestQueue = reqSub.getRequestQueue(getId(), reqdb_inc,
+ mPolicy, service, mNotify, mPNotify);
+
+ // set KeyStatusUpdateInterval to be 10 minutes if serial management is enabled.
+ mKeyDB.setKeyStatusUpdateInterval(
+ mRequestQueue.getRequestRepository(),
+ mConfig.getInteger("keyStatusUpdateInterval", 10 * 60));
+
+ // init request scheduler if configured
+ String schedulerClass =
+ mConfig.getString("requestSchedulerClass", null);
+
+ if (schedulerClass != null) {
+ try {
+ IRequestScheduler scheduler = (IRequestScheduler)
+ Class.forName(schedulerClass).newInstance();
+
+ mRequestQueue.setRequestScheduler(scheduler);
+ } catch (Exception e) {
+ // do nothing here
+ }
+ }
+ initNotificationListeners();
+
+ String replicaReposDN = mConfig.getString(PROP_REPLICAID_DN, null);
+ if (replicaReposDN == null) {
+ replicaReposDN = "ou=Replica," + getDBSubsystem().getBaseDN();
+ }
+
+ mReplicaRepot = new ReplicaIDRepository(
+ DBSubsystem.getInstance(), 1, replicaReposDN);
+ CMS.debug("Replica Repot inited");
+
+ }
+
+ public CryptoToken getKeygenToken() {
+ return mKeygenToken;
+ }
+
+ public IRequestListener getRequestInQListener() {
+ return mReqInQListener;
+ }
+
+ public org.mozilla.jss.crypto.X509Certificate getTransportCert() {
+ return mJssCert;
+ }
+
+ /**
+ * Clears up system during garbage collection.
+ */
+ public void finalize() {
+ shutdown();
+ }
+
+ /**
+ * Starts this service. When this method is called, all
+ * service
+ *
+ * @exception EBaseException failed to startup this subsystem
+ */
+ public void startup() throws EBaseException {
+ CMS.debug("KeyRecoveryAuthority startup() begins");
+
+ if (mRequestQueue != null) {
+ // setup administration operations if everything else is fine
+ mRequestQueue.recover();
+ CMS.debug("KeyRecoveryAuthority startup() call request Q recover");
+
+ // Note that we use our instance id for registration.
+ // This helps us to support multiple instances
+ // of a subsystem within server.
+
+ // register remote admin interface
+ mInitialized = true;
+ } else {
+ CMS.debug("KeyRecoveryAuthority: mRequestQueue is null, could be in preop mode");
+ }
+ }
+
+ /**
+ * Shutdowns this subsystem.
+ */
+ public void shutdown() {
+ if (!mInitialized)
+ return;
+
+ mTransportKeyUnit.shutdown();
+ mStorageKeyUnit.shutdown();
+ if (mKeyDB != null) {
+ mKeyDB.shutdown();
+ mKeyDB = null;
+ }
+ getLogger().log(ILogger.EV_SYSTEM, ILogger.S_KRA,
+ ILogger.LL_INFO, mName.toString() + " is stopped");
+ mInitialized = false;
+ }
+
+ /**
+ * Retrieves the configuration store of this subsystem.
+ * <P>
+ *
+ * @return configuration store
+ */
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ /**
+ * Changes the auto recovery state.
+ *
+ * @param cs list of recovery agent credentials
+ * @param on turn of auto recovery or not
+ * @return operation success or not
+ */
+ public boolean setAutoRecoveryState(Credential cs[], boolean on) {
+ if (on == true) {
+ // check credential before enabling it
+ try {
+ getStorageKeyUnit().login(cs);
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ // maintain in-memory variable; don't store it in config
+ mAutoRecoveryOn = on;
+ return true;
+ }
+
+ /**
+ * Retrieves the current auto recovery state.
+ *
+ * @return enable or not
+ */
+ public boolean getAutoRecoveryState() {
+ // maintain in-memory variable; don't store it in config
+ return mAutoRecoveryOn;
+ }
+
+ /**
+ * Returns a list of users who are in auto
+ * recovery mode.
+ *
+ * @return list of user IDs that are accepted in the
+ * auto recovery mode
+ */
+ public Enumeration getAutoRecoveryIDs() {
+ return mAutoRecovery.keys();
+ }
+
+ /**
+ * Adds auto recovery mode to the given user id.
+ *
+ * @param id new identifier to the auto recovery mode
+ * @param creds list of credentials
+ */
+ public void addAutoRecovery(String id, Credential creds[]) {
+ mAutoRecovery.put(id, creds);
+ }
+
+ /**
+ * Removes auto recovery mode from the given user id.
+ *
+ * @param id id of user to be removed from auto
+ * recovery mode
+ */
+ public void removeAutoRecovery(String id) {
+ mAutoRecovery.remove(id);
+ }
+
+ /**
+ * Retrieves logger from escrow authority.
+ *
+ * @return logger
+ */
+ public ILogger getLogger() {
+ return CMS.getLogger();
+ }
+
+ /**
+ * Retrieves number of required agents for
+ * recovery operation.
+ *
+ * @return number of required agents
+ * @exception EBaseException failed to retrieve info
+ */
+ public int getNoOfRequiredAgents() throws EBaseException {
+ if (mConfig.getBoolean("keySplitting", false)) {
+ return mStorageKeyUnit.getNoOfRequiredAgents();
+ } else {
+ int ret = -1;
+ ret = mConfig.getInteger("noOfRequiredRecoveryAgents", 1);
+ if (ret <= 0) {
+ throw new EBaseException("Invalid parameter noOfRequiredecoveryAgents");
+ }
+ return ret;
+ }
+ }
+
+ /**
+ * Sets number of required agents for
+ * recovery operation
+ *
+ * @return none
+ * @exception EBaseException invalid setting
+ */
+ public void setNoOfRequiredAgents(int number) throws EBaseException {
+ if (mConfig.getBoolean("keySplitting")) {
+ mStorageKeyUnit.setNoOfRequiredAgents(number);
+ } else {
+ mConfig.putInteger("noOfRequiredRecoveryAgents", number);
+ }
+ }
+
+ /**
+ * Distributed recovery.
+ */
+ public String getRecoveryID() {
+ return Integer.toString(mRecoveryIDCounter++);
+ }
+
+ public Hashtable createRecoveryParams(String recoveryID)
+ throws EBaseException {
+ Hashtable h = new Hashtable();
+
+ h.put(PARAM_CREDS, new Vector());
+ h.put(PARAM_LOCK, new Object());
+ mRecoveryParams.put(recoveryID, h);
+ return h;
+ }
+
+ public void destroyRecoveryParams(String recoveryID)
+ throws EBaseException {
+ mRecoveryParams.remove(recoveryID);
+ }
+
+ public Hashtable getRecoveryParams(String recoveryID)
+ throws EBaseException {
+ return (Hashtable) mRecoveryParams.get(recoveryID);
+ }
+
+ public void createPk12(String recoveryID, byte[] pk12)
+ throws EBaseException {
+ Hashtable h = getRecoveryParams(recoveryID);
+
+ h.put(PARAM_PK12, pk12);
+ }
+
+ public byte[] getPk12(String recoveryID)
+ throws EBaseException {
+ return (byte[]) getRecoveryParams(recoveryID).get(PARAM_PK12);
+ }
+
+ public void createError(String recoveryID, String error)
+ throws EBaseException {
+ Hashtable h = getRecoveryParams(recoveryID);
+
+ h.put(PARAM_ERROR, error);
+ }
+
+ public String getError(String recoveryID)
+ throws EBaseException {
+ return (String) getRecoveryParams(recoveryID).get(PARAM_ERROR);
+ }
+
+ /**
+ * Retrieve the current approval agents
+ */
+ public Vector getAppAgents(
+ String recoveryID) throws EBaseException {
+ Hashtable h = getRecoveryParams(recoveryID);
+ Vector dc = (Vector) h.get(PARAM_CREDS);
+
+ return dc;
+ }
+
+ /**
+ * Retrieves a list credentials. This puts KRA in a waiting
+ * mode, it never returns until all the necessary passwords
+ * are collected.
+ */
+ public Credential[] getDistributedCredentials(
+ String recoveryID)
+ throws EBaseException {
+ Hashtable h = getRecoveryParams(recoveryID);
+ Vector dc = (Vector) h.get(PARAM_CREDS);
+ Object lock = (Object) h.get(PARAM_LOCK);
+
+ synchronized (lock) {
+ while (dc.size() < getNoOfRequiredAgents()) {
+ CMS.debug("KeyRecoveryAuthority: cfu in synchronized lock for getDistributedCredentials");
+ try {
+ lock.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ Credential creds[] = new Credential[dc.size()];
+
+ dc.copyInto(creds);
+ return creds;
+ }
+ }
+
+ /**
+ * Verifies credential.
+ */
+ private void verifyCredential(Vector creds, String uid,
+ String pwd) throws EBaseException {
+ // see if we have the uid already
+
+ if (!mConfig.getBoolean("keySplitting")) {
+ // check if the uid is in the specified group
+ IUGSubsystem ug = (IUGSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_UG);
+ if (!ug.isMemberOf(uid, mConfig.getString("recoveryAgentGroup"))) {
+ // invalid group
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_CREDENTIALS_NOT_EXIST"));
+ }
+ }
+
+ for (int i = 0; i < creds.size(); i++) {
+ Credential c = (Credential) creds.elementAt(i);
+
+ if (c.getIdentifier().equals(uid)) {
+ // duplicated uid
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_CREDENTIALS_EXIST"));
+ }
+ }
+ if (mConfig.getBoolean("keySplitting")) {
+ mStorageKeyUnit.checkPassword(uid, pwd);
+ }
+ }
+
+ /**
+ * Adds password.
+ */
+ public void addDistributedCredential(String recoveryID,
+ String uid, String pwd) throws EBaseException {
+ Hashtable h = getRecoveryParams(recoveryID);
+ Vector dc = (Vector) h.get(PARAM_CREDS);
+ Object lock = (Object) h.get(PARAM_LOCK);
+
+ synchronized (lock) {
+ verifyCredential(dc, uid, pwd);
+ // verify password
+ dc.addElement(new Credential(uid, pwd));
+ // modify status object
+ lock.notify();
+ }
+ }
+
+ /**
+ * Archives key. This creates a key record in the key
+ * repository.
+ * <P>
+ *
+ * <ul>
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST used
+ * whenever a user private key archive request is made (this is when the
+ * DRM receives the request)
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED used
+ * whenever a user private key archive request is processed (this is when
+ * the DRM processes the request)
+ * </ul>
+ * @param rec key record to be archived
+ * @return executed request
+ * @exception EBaseException failed to archive key
+ * @return the request
+ * <P>
+ */
+ public IRequest archiveKey(KeyRecord rec)
+ throws EBaseException {
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+ String auditRequesterID = auditRequesterID();
+ String auditPublicKey = auditPublicKey(rec);
+ String auditArchiveID = ILogger.UNIDENTIFIED;
+
+ IRequestQueue queue = null;
+ IRequest r = null;
+ String id = null;
+
+ // ensure that any low-level exceptions are reported
+ // to the signed audit log and stored as failures
+ try {
+ queue = getRequestQueue();
+
+ r = queue.newRequest(KRAService.ENROLLMENT);
+
+ if (r != null) {
+ // overwrite "auditArchiveID" if and only if "id" != null
+ id = r.getRequestId().toString();
+ if (id != null) {
+ auditArchiveID = id.trim();
+ }
+ }
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ } catch (EBaseException eAudit1) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ auditArchiveID);
+
+ audit(auditMessage);
+
+ throw eAudit1;
+ }
+
+ // ensure that any low-level exceptions are reported
+ // to the signed audit log and stored as failures
+ try {
+ if (r != null) {
+ r.setExtData(EnrollmentService.ATTR_KEY_RECORD, rec.getSerialNumber());
+ queue.processRequest(r);
+ }
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditPublicKey);
+
+ audit(auditMessage);
+ } catch (EBaseException eAudit1) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditPublicKey);
+
+ audit(auditMessage);
+
+ throw eAudit1;
+ }
+
+ return r;
+ }
+
+ /**
+ * async key recovery initiation
+ */
+ public String initAsyncKeyRecovery(BigInteger kid, X509CertImpl cert, String agent)
+ throws EBaseException {
+
+ String auditPublicKey = auditPublicKey(cert);
+ String auditRecoveryID = "undefined";
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+
+ IRequestQueue queue = null;
+ IRequest r = null;
+
+ try {
+ queue = getRequestQueue();
+ r = queue.newRequest(KRAService.RECOVERY);
+
+ r.setExtData(RecoveryService.ATTR_SERIALNO, kid);
+ r.setExtData(RecoveryService.ATTR_USER_CERT, cert);
+ // first one in the "approvingAgents" list is the initiating agent
+ r.setExtData(RecoveryService.ATTR_APPROVE_AGENTS, agent);
+ r.setRequestStatus(RequestStatus.PENDING);
+ queue.updateRequest(r);
+ auditRecoveryID = r.getRequestId().toString();
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_ASYNC,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRecoveryID,
+ auditPublicKey);
+
+ audit(auditMessage);
+ } catch (EBaseException eAudit1) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_ASYNC,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ auditPublicKey);
+
+ audit(auditMessage);
+
+ throw eAudit1;
+ }
+
+ //NO call to queue.processRequest(r) because it is only initiating
+ return r.getRequestId().toString();
+ }
+
+ /**
+ * is async recovery request status APPROVED -
+ * i.e. all required # of recovery agents approved
+ */
+ public boolean isApprovedAsyncKeyRecovery(String reqID)
+ throws EBaseException {
+ IRequestQueue queue = null;
+ IRequest r = null;
+
+ queue = getRequestQueue();
+ r = queue.findRequest(new RequestId(reqID));
+ if ((r.getRequestStatus() == RequestStatus.APPROVED)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * get async recovery request initiating agent
+ */
+ public String getInitAgentAsyncKeyRecovery(String reqID)
+ throws EBaseException {
+ IRequestQueue queue = null;
+ IRequest r = null;
+
+ queue = getRequestQueue();
+ r = queue.findRequest(new RequestId(reqID));
+
+ String agents = r.getExtDataInString(RecoveryService.ATTR_APPROVE_AGENTS);
+ if (agents != null) {
+ int i = agents.indexOf(",");
+ if (i == -1) {
+ return agents;
+ }
+ return agents.substring(0, i);
+ } else { // no approvingAgents existing, can't be async recovery
+ CMS.debug("getInitAgentAsyncKeyRecovery: no approvingAgents in request");
+ }
+
+ return null;
+ }
+
+ /**
+ * add async recovery agent to approving agent list of the recovery request
+ * record
+ * This method will check to see if the agent belongs to the recovery group
+ * first before adding.
+ */
+ public void addAgentAsyncKeyRecovery(String reqID, String agentID)
+ throws EBaseException {
+ IRequestQueue queue = null;
+ IRequest r = null;
+
+ // check if the uid is in the specified group
+ IUGSubsystem ug = (IUGSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_UG);
+ if (!ug.isMemberOf(agentID, mConfig.getString("recoveryAgentGroup"))) {
+ // invalid group
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_CREDENTIALS_NOT_EXIST"));
+ }
+
+ queue = getRequestQueue();
+ r = queue.findRequest(new RequestId(reqID));
+
+ String agents = r.getExtDataInString(RecoveryService.ATTR_APPROVE_AGENTS);
+ if (agents != null) {
+ int count = 0;
+ StringTokenizer st = new StringTokenizer(agents, ",");
+ for (; st.hasMoreTokens();) {
+ String a = st.nextToken();
+ // first one is the initiating agent
+ if ((count != 0) && a.equals(agentID)) {
+ // duplicated uid
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_CREDENTIALS_EXIST"));
+ }
+ count++;
+ }
+
+ // note: if count==1 and required agents is 1, it's good to add
+ // and it'd look like "agent1,agent1" - that's the only dup allowed
+ if (count <= getNoOfRequiredAgents()) { //all good, add it
+ r.setExtData(RecoveryService.ATTR_APPROVE_AGENTS,
+ agents+","+agentID);
+ if (count == getNoOfRequiredAgents()) {
+ r.setRequestStatus(RequestStatus.APPROVED);
+ } else {
+ r.setRequestStatus(RequestStatus.PENDING);
+ }
+ queue.updateRequest(r);
+ }
+ } else { // no approvingAgents existing, can't be async recovery
+ CMS.debug("addAgentAsyncKeyRecovery: no approvingAgents in request. Async recovery request not initiated?");
+ }
+ }
+
+ /**
+ * Recovers key for administrators. This method is
+ * invoked by the agent operation of the key recovery servlet.
+ * <P>
+ *
+ * <ul>
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST used whenever
+ * a user private key recovery request is made (this is when the DRM
+ * receives the request)
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED used whenever
+ * a user private key recovery request is processed (this is when the DRM
+ * processes the request)
+ * </ul>
+ * @param kid key identifier
+ * @param creds list of recovery agent credentials
+ * @param password password of the PKCS12 package
+ * @param cert certficate that will be put in PKCS12
+ * @param delivery file, mail or something else
+ * @param nickname string containing the nickname of the id cert for this
+ * subsystem
+ * @exception EBaseException failed to recover key
+ * @return a byte array containing the key
+ */
+ public byte[] doKeyRecovery(BigInteger kid,
+ Credential creds[], String password,
+ X509CertImpl cert,
+ String delivery, String nickname,
+ String agent)
+ throws EBaseException {
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+ String auditRecoveryID = auditRecoveryID();
+ String auditPublicKey = auditPublicKey(cert);
+ String auditAgents = ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+
+ IRequestQueue queue = null;
+ IRequest r = null;
+ Hashtable params = null;
+
+ CMS.debug("KeyRecoveryAuthority: in synchronous doKeyRecovery()");
+ // ensure that any low-level exceptions are reported
+ // to the signed audit log and stored as failures
+ try {
+ queue = getRequestQueue();
+ r = queue.newRequest(KRAService.RECOVERY);
+
+ // set transient parameters
+ params = createVolatileRequest(r.getRequestId());
+
+ if (mConfig.getBoolean("keySplitting")) {
+ params.put(RecoveryService.ATTR_AGENT_CREDENTIALS, creds);
+ }
+ params.put(RecoveryService.ATTR_TRANSPORT_PWD, password);
+
+ r.setExtData(RecoveryService.ATTR_SERIALNO, kid);
+ r.setExtData(RecoveryService.ATTR_USER_CERT, cert);
+ if (nickname != null) {
+ nickname = nickname.trim();
+ if (!nickname.equals("")) {
+ r.setExtData(RecoveryService.ATTR_NICKNAME, nickname);
+ }
+ }
+ // for both sync and async recovery
+ r.setExtData(RecoveryService.ATTR_APPROVE_AGENTS, agent);
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRecoveryID,
+ auditPublicKey);
+
+ audit(auditMessage);
+ } catch (EBaseException eAudit1) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ auditPublicKey);
+
+ audit(auditMessage);
+
+ throw eAudit1;
+ }
+
+ // ensure that any low-level exceptions are reported
+ // to the signed audit log and stored as failures
+ try {
+ queue.processRequest(r);
+
+ if (r.getExtDataInString(IRequest.ERROR) == null) {
+ byte pkcs12[] = (byte[]) params.get(
+ RecoveryService.ATTR_PKCS12);
+
+ auditAgents = auditAgents(creds);
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRecoveryID,
+ auditAgents);
+
+ audit(auditMessage);
+
+ destroyVolatileRequest(r.getRequestId());
+
+ return pkcs12;
+ } else {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ auditAgents);
+
+ audit(auditMessage);
+
+ throw new EBaseException(r.getExtDataInString(IRequest.ERROR));
+ }
+ } catch (EBaseException eAudit1) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ auditAgents);
+
+ audit(auditMessage);
+
+ throw eAudit1;
+ }
+ }
+
+ /**
+ * Async Recovers key for administrators. This method is
+ * invoked by the agent operation of the key recovery servlet.
+ * <P>
+ *
+ * <ul>
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST used whenever
+ * a user private key recovery request is made (this is when the DRM
+ * receives the request)
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED used whenever
+ * a user private key recovery request is processed (this is when the DRM
+ * processes the request)
+ * </ul>
+ * @param requestID request id
+ * @param password password of the PKCS12 package
+ * subsystem
+ * @exception EBaseException failed to recover key
+ * @return a byte array containing the key
+ */
+ public byte[] doKeyRecovery(
+ String reqID,
+ String password)
+ throws EBaseException {
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+ String auditRecoveryID = reqID;
+ String auditAgents = ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ String auditPublicKey = ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+
+ IRequestQueue queue = null;
+ IRequest r = null;
+ Hashtable params = null;
+
+ CMS.debug("KeyRecoveryAuthority: in asynchronous doKeyRecovery()");
+ queue = getRequestQueue();
+ r = queue.findRequest(new RequestId(reqID));
+
+ auditAgents =
+ r.getExtDataInString(RecoveryService.ATTR_APPROVE_AGENTS);
+
+ // set transient parameters
+ params = createVolatileRequest(r.getRequestId());
+ params.put(RecoveryService.ATTR_TRANSPORT_PWD, password);
+
+ // ensure that any low-level exceptions are reported
+ // to the signed audit log and stored as failures
+ try {
+ CMS.debug("KeyRecoveryAuthority: in asynchronous doKeyRecovery(), request state ="+ r.getRequestStatus().toString());
+ // can only process requests in begin state
+ r.setRequestStatus(RequestStatus.BEGIN);
+ queue.processRequest(r);
+
+ if (r.getExtDataInString(IRequest.ERROR) == null) {
+ byte pkcs12[] = (byte[]) params.get(
+ RecoveryService.ATTR_PKCS12);
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_ASYNC,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRecoveryID,
+ auditAgents);
+
+ audit(auditMessage);
+
+ destroyVolatileRequest(r.getRequestId());
+
+ return pkcs12;
+ } else {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_ASYNC,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ auditAgents);
+
+ audit(auditMessage);
+
+ throw new EBaseException(r.getExtDataInString(IRequest.ERROR));
+ }
+ } catch (EBaseException eAudit1) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_ASYNC,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ auditAgents);
+
+ audit(auditMessage);
+ throw eAudit1;
+ }
+ }
+
+ /**
+ * Constructs a recovery request and submits it
+ * to the request subsystem for processing.
+ *
+ * @param kid key identifier
+ * @param creds list of recovery agent credentials
+ * @param password password of the PKCS12 package
+ * @param cert certficate that will be put in PKCS12
+ * @param delivery file, mail or something else
+ * @return executed request
+ * @exception EBaseException failed to recover key
+ */
+ public IRequest recoverKey(BigInteger kid,
+ Credential creds[], String password,
+ X509CertImpl cert,
+ String delivery) throws EBaseException {
+ IRequestQueue queue = getRequestQueue();
+ IRequest r = queue.newRequest("recovery");
+
+ r.setExtData(RecoveryService.ATTR_SERIALNO, kid);
+ r.setExtData(RecoveryService.ATTR_TRANSPORT_PWD, password);
+ r.setExtData(RecoveryService.ATTR_USER_CERT, cert);
+ r.setExtData(RecoveryService.ATTR_DELIVERY, delivery);
+ queue.processRequest(r);
+ return r;
+ }
+
+ /**
+ * Recovers key for end-entities.
+ *
+ * @param creds list of credentials
+ * @param encryptionChain certificate chain
+ * @param signingCert signing cert
+ * @param transportCert certificate to protect in-transit key
+ * @param ownerName owner name
+ * @return executed request
+ * @exception EBaseException failed to recover key
+ */
+ public IRequest recoverKey(Credential creds[], CertificateChain
+ encryptionChain, X509CertImpl signingCert,
+ X509CertImpl transportCert,
+ X500Name ownerName) throws EBaseException {
+ IRequestQueue queue = getRequestQueue();
+ IRequest r = queue.newRequest("recovery");
+
+ ByteArrayOutputStream certChainOut = new ByteArrayOutputStream();
+ try {
+ encryptionChain.encode(certChainOut);
+ r.setExtData(RecoveryService.ATTR_ENCRYPTION_CERTS,
+ certChainOut.toByteArray());
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE,
+ "Error encoding certificate chain");
+ }
+
+ r.setExtData(RecoveryService.ATTR_SIGNING_CERT, signingCert);
+ r.setExtData(RecoveryService.ATTR_TRANSPORT_CERT, transportCert);
+
+ DerOutputStream ownerNameOut = new DerOutputStream();
+ try {
+ ownerName.encode(ownerNameOut);
+ r.setExtData(RecoveryService.ATTR_OWNER_NAME,
+ ownerNameOut.toByteArray());
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE,
+ "Error encoding X500Name for owner name");
+ }
+
+ queue.processRequest(r);
+ return r;
+ }
+
+ /**
+ * Retrieves the storage key unit. The storage key
+ * is used to wrap the user key for long term
+ * storage.
+ *
+ * @return storage key unit.
+ */
+ public IStorageKeyUnit getStorageKeyUnit() {
+ return mStorageKeyUnit;
+ }
+
+ /**
+ * Retrieves the transport key unit.
+ *
+ * @return transport key unit
+ */
+ public ITransportKeyUnit getTransportKeyUnit() {
+ return mTransportKeyUnit;
+ }
+
+ /**
+ * Returns the name of this subsystem. This name is
+ * extracted from the transport certificate.
+ *
+ * @return KRA name
+ */
+ public X500Name getX500Name() {
+ return mName;
+ }
+
+ public String getNickName() {
+ return getNickname();
+ }
+
+ /**
+ * Returns the nickname for the id cert of this
+ * subsystem.
+ *
+ * @return nickname of the transport certificate
+ */
+ public String getNickname() {
+ try {
+ return mTransportKeyUnit.getNickName();
+ } catch (EBaseException e) {
+ return null;
+ }
+ }
+
+ public void setNickname(String str) {
+ try {
+ mTransportKeyUnit.setNickName(str);
+ } catch (EBaseException e) {
+ }
+ }
+
+ public String getNewNickName() throws EBaseException {
+ return mConfig.getString(PROP_NEW_NICKNAME, "");
+ }
+
+ public void setNewNickName(String name) {
+ mConfig.putString(PROP_NEW_NICKNAME, name);
+ }
+
+ public IPolicy getPolicy() {
+ return mPolicy;
+ }
+
+ /**
+ * Retrieves KRA request repository.
+ * <P>
+ *
+ * @return request repository
+ */
+ public IRequestQueue getRequestQueue() {
+ return mRequestQueue;
+ }
+
+ /**
+ * Retrieves the key repository. The key repository
+ * stores archived keys.
+ * <P>
+ */
+ public IKeyRepository getKeyRepository() {
+ return mKeyDB;
+ }
+
+ /**
+ * Retrieves replica repository.
+ * <P>
+ *
+ * @return replica repository
+ */
+ public IReplicaIDRepository getReplicaRepository() {
+ return mReplicaRepot;
+ }
+
+
+ /**
+ * Retrieves the DN of this escrow authority.
+ * <P>
+ *
+ * @return distinguished name
+ */
+ protected String getDN() {
+ return getX500Name().toString();
+ }
+
+ /**
+ * Retrieves database connection.
+ */
+ public IDBSubsystem getDBSubsystem() {
+ return DBSubsystem.getInstance();
+ }
+
+ /**
+ * Logs an event.
+ *
+ * @param level log level
+ * @param msg message to log
+ */
+ public void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, null, ILogger.S_KRA,
+ level, msg);
+ }
+
+ /**
+ * Registers a request listener.
+ *
+ * @param l request listener
+ */
+ public void registerRequestListener(IRequestListener l) {
+ // it's initialized.
+ if (mNotify != null)
+ mNotify.registerListener(l);
+ }
+
+ public void registerPendingListener(IRequestListener l) {
+ mPNotify.registerListener(l);
+ }
+
+ /**
+ * init notification related listeners -
+ * right now only RequestInQueue listener is available for KRA
+ */
+ private void initNotificationListeners() {
+ IConfigStore nc = null;
+
+ try {
+ nc = mConfig.getSubStore(PROP_NOTIFY_SUBSTORE);
+ if (nc != null && nc.size() > 0) {
+ // Initialize Request In Queue notification listener
+ IConfigStore rq = nc.getSubStore(PROP_REQ_IN_Q_SUBSTORE);
+ IAuthority cSub = (IAuthority) this;
+
+ String requestInQListenerClassName = nc.getString("certificateIssuedListenerClassName", "com.netscape.cms.listeners.RequestInQListener");
+
+ try {
+ mReqInQListener = (IRequestListener) Class.forName(requestInQListenerClassName).newInstance();
+ mReqInQListener.init(this, nc);
+ } catch (Exception e1) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_REGISTER_LISTENER", requestInQListenerClassName));
+ }
+ } else {
+ log(ILogger.LL_INFO,
+ "No KRA notification Module configuration found");
+ }
+ } catch (EPropertyNotFound e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_NOTIFY_ERROR", e.toString()));
+ } catch (EListenersException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_NOTIFY_ERROR", e.toString()));
+ } catch (EBaseException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_NOTIFY_ERROR", e.toString()));
+ }
+ }
+
+ /**
+ * temporary accepted ras.
+ */
+ /* code no longer used
+ public X500Name[] getAcceptedRAs() {
+ // temporary. use usr/grp for real thing.
+ X500Name radn = null;
+ String raname = null;
+
+ try {
+ raname = mConfig.getString("acceptedRA", null);
+ if (raname != null) {
+ radn = new X500Name(raname);
+ }
+ } catch (IOException e) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_KRA,
+ ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_INVALID_RA_NAME", raname, e.toString()));
+ } catch (EBaseException e) {
+ // ignore - set to null.
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_KRA,
+ ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_INVALID_RA_SETUP", e.toString()));
+ }
+ return new X500Name[] { radn };
+ }
+ */
+
+ public Hashtable mVolatileRequests = new Hashtable();
+
+ /**
+ * Creates a request object to store attributes that
+ * will not be serialized. Currently, request queue
+ * framework will try to serialize all the attribute into
+ * persistent storage. Things like passwords are not
+ * desirable to be stored.
+ */
+ public Hashtable createVolatileRequest(RequestId id) {
+ Hashtable params = new Hashtable();
+
+ mVolatileRequests.put(id.toString(), params);
+ return params;
+ }
+
+ public Hashtable getVolatileRequest(RequestId id) {
+ return (Hashtable) mVolatileRequests.get(id.toString());
+ }
+
+ public void destroyVolatileRequest(RequestId id) {
+ mVolatileRequests.remove(id.toString());
+ }
+
+ public String getOfficialName() {
+ return OFFICIAL_NAME;
+ }
+
+ /**
+ * Signed Audit Log
+ *
+ * This method is called to store messages to the signed audit log.
+ * <P>
+ *
+ * @param msg signed audit log message
+ */
+ private void audit(String msg) {
+ // in this case, do NOT strip preceding/trailing whitespace
+ // from passed-in String parameters
+
+ if (mSignedAuditLogger == null) {
+ return;
+ }
+
+ mSignedAuditLogger.log(ILogger.EV_SIGNED_AUDIT,
+ null,
+ ILogger.S_SIGNED_AUDIT,
+ ILogger.LL_SECURITY,
+ msg);
+ }
+
+ /**
+ * Signed Audit Log Subject ID
+ *
+ * This method is called to obtain the "SubjectID" for
+ * a signed audit log message.
+ * <P>
+ *
+ * @return id string containing the signed audit log message SubjectID
+ */
+ private String auditSubjectID() {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ String subjectID = null;
+
+ // Initialize subjectID
+ SessionContext auditContext = SessionContext.getExistingContext();
+
+ if (auditContext != null) {
+ subjectID = (String)
+ auditContext.get(SessionContext.USER_ID);
+
+ if (subjectID != null) {
+ subjectID = subjectID.trim();
+ } else {
+ subjectID = ILogger.NONROLEUSER;
+ }
+ } else {
+ subjectID = ILogger.UNIDENTIFIED;
+ }
+
+ return subjectID;
+ }
+
+ /**
+ * Signed Audit Log Requester ID
+ *
+ * This method is called to obtain the "RequesterID" for
+ * a signed audit log message.
+ * <P>
+ *
+ * @return id string containing the signed audit log message RequesterID
+ */
+ private String auditRequesterID() {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ String requesterID = null;
+
+ // Initialize requesterID
+ SessionContext auditContext = SessionContext.getExistingContext();
+
+ if (auditContext != null) {
+ requesterID = (String)
+ auditContext.get(SessionContext.REQUESTER_ID);
+
+ if (requesterID != null) {
+ requesterID = requesterID.trim();
+ } else {
+ requesterID = ILogger.UNIDENTIFIED;
+ }
+ } else {
+ requesterID = ILogger.UNIDENTIFIED;
+ }
+
+ return requesterID;
+ }
+
+ /**
+ * Signed Audit Log Recovery ID
+ *
+ * This method is called to obtain the "RecoveryID" for
+ * a signed audit log message.
+ * <P>
+ *
+ * @return id string containing the signed audit log message RecoveryID
+ */
+ private String auditRecoveryID() {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ String recoveryID = null;
+
+ // Initialize recoveryID
+ SessionContext auditContext = SessionContext.getExistingContext();
+
+ if (auditContext != null) {
+ recoveryID = (String)
+ auditContext.get(SessionContext.RECOVERY_ID);
+
+ if (recoveryID != null) {
+ recoveryID = recoveryID.trim();
+ } else {
+ recoveryID = ILogger.UNIDENTIFIED;
+ }
+ } else {
+ recoveryID = ILogger.UNIDENTIFIED;
+ }
+
+ return recoveryID;
+ }
+
+ /**
+ * Signed Audit Log Public Key
+ *
+ * This method is called to obtain the public key from the passed in
+ * "X509Certificate" for a signed audit log message.
+ * <P>
+ *
+ * @param cert an X509Certificate
+ * @return key string containing the certificate's public key
+ */
+ private String auditPublicKey(X509Certificate cert) {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ if (cert == null) {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+
+ byte rawData[] = cert.getPublicKey().getEncoded();
+ String key = null;
+
+ // convert "rawData" into "base64Data"
+ if (rawData != null) {
+ String base64Data = null;
+
+ base64Data = CMS.BtoA(rawData).trim();
+
+ // extract all line separators from the "base64Data"
+ for (int i = 0; i < base64Data.length(); i++) {
+ if (base64Data.substring(i, i).getBytes() != EOL) {
+ key += base64Data.substring(i, i);
+ }
+ }
+ }
+
+ if (key != null) {
+ key = key.trim();
+
+ if (key.equals("")) {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ } else {
+ return key;
+ }
+ } else {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+ }
+
+ /**
+ * Signed Audit Log Public Key
+ *
+ * This method is called to obtain the public key from the passed in
+ * "KeyRecord" for a signed audit log message.
+ * <P>
+ *
+ * @param rec a Key Record
+ * @return key string containing the certificate's public key
+ */
+ private String auditPublicKey(KeyRecord rec) {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ if (rec == null) {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+
+ byte rawData[] = null;
+
+ try {
+ rawData = rec.getPublicKeyData();
+ } catch (EBaseException e) {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+
+ String key = null;
+
+ // convert "rawData" into "base64Data"
+ if (rawData != null) {
+ String base64Data = null;
+
+ base64Data = CMS.BtoA(rawData).trim();
+
+ // extract all line separators from the "base64Data"
+ for (int i = 0; i < base64Data.length(); i++) {
+ if (base64Data.substring(i, i).getBytes() != EOL) {
+ key += base64Data.substring(i, i);
+ }
+ }
+ }
+
+ if (key != null) {
+ key = key.trim();
+
+ if (key.equals("")) {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ } else {
+ return key;
+ }
+ } else {
+ return ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+ }
+
+ /**
+ * Signed Audit Agents
+ *
+ * This method is called to extract agent uids from the passed in
+ * "Credentials[]" and return a string of comma-separated agent uids.
+ * <P>
+ *
+ * @param creds array of credentials
+ * @return a comma-separated string of agent uids
+ */
+ private String auditAgents(Credential creds[]) {
+ if (creds == null)
+ return null;
+
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ String agents = ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+
+ String uid = null;
+
+ for (int i = 0; i < creds.length; i++) {
+ uid = creds[i].getIdentifier();
+
+ if (uid != null) {
+ uid = uid.trim();
+ }
+
+ if (uid != null &&
+ !uid.equals("")) {
+
+ if (i == 0) {
+ agents = uid;
+ } else {
+ agents += SIGNED_AUDIT_AGENT_DELIMITER + uid;
+ }
+ }
+ }
+
+ return agents;
+ }
+}
+
diff --git a/pki/base/kra/src/com/netscape/kra/NetkeyKeygenService.java b/pki/base/kra/src/com/netscape/kra/NetkeyKeygenService.java
new file mode 100644
index 000000000..1310fca76
--- /dev/null
+++ b/pki/base/kra/src/com/netscape/kra/NetkeyKeygenService.java
@@ -0,0 +1,632 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+
+import com.netscape.cmscore.util.Debug;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.io.IOException;
+import java.io.ByteArrayInputStream;
+
+import java.math.BigInteger;
+import java.security.*;
+import java.security.KeyPair;
+import java.security.cert.CertificateException;
+import netscape.security.util.*;
+import netscape.security.util.BigInt;
+import netscape.security.pkcs.*;
+import netscape.security.x509.*;
+import netscape.security.provider.RSAPublicKey;
+import org.mozilla.jss.*;
+import org.mozilla.jss.crypto.*;
+import org.mozilla.jss.util.*;
+import org.mozilla.jss.crypto.PrivateKey;
+import org.mozilla.jss.asn1.*;
+import org.mozilla.jss.crypto.KeyPairGenerator;
+import org.mozilla.jss.pkix.crmf.*;
+import org.mozilla.jss.pkix.primitive.*;
+import org.mozilla.jss.pkix.primitive.AVA;
+import org.mozilla.jss.pkcs11.*;
+import com.netscape.certsrv.common.*;
+import com.netscape.cmscore.util.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.security.*;
+import com.netscape.cmscore.crmf.*;
+import com.netscape.certsrv.kra.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.cmscore.cert.*;
+//import com.netscape.cmscore.ca.*;
+import com.netscape.cmscore.dbs.*;
+import com.netscape.certsrv.dbs.*;
+import com.netscape.certsrv.dbs.repository.*;
+import com.netscape.certsrv.profile.*;
+import com.netscape.certsrv.dbs.keydb.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.policy.*;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.apps.CMS;
+
+//for b64 encoding
+import org.mozilla.jss.util.Base64OutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.*;
+
+/**
+ * A class representing keygen/archival request procesor for requests
+ * from netkey RAs.
+ * the user private key of the encryption cert is wrapped with a
+ * session symmetric key. The session symmetric key is wrapped with the
+ * storage key and stored in the internal database for long term
+ * storage.
+ * The user private key of the encryption cert is to be wrapped with the
+ * DES key which came in in the request wrapped with the KRA
+ * transport cert. The wrapped user private key is then sent back to
+ * the caller (netkey RA) ...netkey RA should already has kek-wrapped
+ * des key from the TKS. They are to be sent together back to
+ * the token.
+ *
+ * @author Christina Fu (cfu)
+ * @version $Revision$, $Date$
+ */
+
+public class NetkeyKeygenService implements IService {
+ public final static String ATTR_KEY_RECORD = "keyRecord";
+ public final static String ATTR_PROOF_OF_ARCHIVAL =
+ "proofOfArchival";
+
+ // private
+ private final static String
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_4";
+ private final static String
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED_3";
+ // these need to be defined in LogMessages_en.properties later when we do this
+ private final static String
+ LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST =
+ "LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST_3";
+ private final static String
+ LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_SUCCESS =
+ "LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_SUCCESS_4";
+ private final static String
+ LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_FAILURE =
+ "LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_FAILURE_3";
+ private final static String
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_SUCCESS =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_SUCCESS_4";
+ private final static String
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_FAILURE =
+ "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_FAILURE_4";
+ private IKeyRecoveryAuthority mKRA = null;
+ private ITransportKeyUnit mTransportUnit = null;
+ private IStorageKeyUnit mStorageUnit = null;
+ private ILogger mSignedAuditLogger = CMS.getSignedAuditLogger();
+
+ /**
+ * Constructs request processor.
+ * <P>
+ *
+ * @param kra key recovery authority
+ */
+ public NetkeyKeygenService(IKeyRecoveryAuthority kra) {
+ mKRA = kra;
+ mTransportUnit = kra.getTransportKeyUnit();
+ mStorageUnit = kra.getStorageKeyUnit();
+ }
+
+ public PKIArchiveOptions toPKIArchiveOptions(byte options[]) {
+ ByteArrayInputStream bis = new ByteArrayInputStream(options);
+ PKIArchiveOptions archOpts = null;
+
+ try {
+ archOpts = (PKIArchiveOptions)
+ (new PKIArchiveOptions.Template()).decode(bis);
+ } catch (Exception e) {
+ CMS.debug("NetkeyKeygenService: getPKIArchiveOptions " + e.toString());
+ }
+ return archOpts;
+ }
+
+ public KeyPair generateKeyPair(
+ KeyPairAlgorithm kpAlg, int keySize, PQGParams pqg)
+ throws NoSuchAlgorithmException, TokenException, InvalidAlgorithmParameterException,
+ InvalidParameterException, PQGParamGenException {
+
+ CryptoToken token = mKRA.getKeygenToken();
+
+ CMS.debug("NetkeyKeygenService: key pair is to be generated on slot: "+token.getName());
+
+ /*
+ make it temporary so can work with HSM
+ netHSM works with
+ temporary == true
+ sensitive == <do not specify>
+ extractable == <do not specify>
+ LunaSA2 works with
+ temporary == true
+ sensitive == true
+ extractable == true
+ */
+ KeyPairGenerator kpGen = token.getKeyPairGenerator(kpAlg);
+ IConfigStore config = CMS.getConfigStore();
+ IConfigStore kgConfig = config.getSubStore("kra.keygen");
+ boolean tp = false;
+ boolean sp = false;
+ boolean ep = false;
+ if (kgConfig != null) {
+ try {
+ tp = kgConfig.getBoolean("temporaryPairs", false);
+ sp = kgConfig.getBoolean("sensitivePairs", false);
+ ep = kgConfig.getBoolean("extractablePairs", false);
+ // by default, let nethsm work
+ if ((tp == false) && (sp == false) && (ep == false)) {
+ tp = true;
+ }
+ } catch (Exception e) {
+ CMS.debug("NetkeyKeygenService: kgConfig.getBoolean failed");
+ // by default, let nethsm work
+ tp = true;
+ }
+ } else {
+ // by default, let nethsm work
+ CMS.debug("NetkeyKeygenService: cannot find config store: kra.keygen, assume temporaryPairs==true");
+ tp = true;
+ }
+ /* only specified to "true" will it be set */
+ if (tp == true) {
+ CMS.debug("NetkeyKeygenService: setting temporaryPairs to true");
+ kpGen.temporaryPairs(true);
+ }
+ if (sp == true) {
+ CMS.debug("NetkeyKeygenService: setting sensitivePairs to true");
+ kpGen.sensitivePairs(true);
+ }
+ if (ep == true) {
+ CMS.debug("NetkeyKeygenService: setting extractablePairs to true");
+ kpGen.extractablePairs(true);
+ }
+
+ if (kpAlg == KeyPairAlgorithm.DSA) {
+ if (pqg == null) {
+ kpGen.initialize(keySize);
+ } else {
+ kpGen.initialize(pqg);
+ }
+ } else {
+ kpGen.initialize(keySize);
+ }
+
+ if (pqg == null) {
+ KeyPair kp = null;
+ synchronized (new Object()) {
+ CMS.debug("NetkeyKeygenService: key pair generation begins");
+ kp = kpGen.genKeyPair();
+ CMS.debug("NetkeyKeygenService: key pair generation done");
+ mKRA.addEntropy(true);
+ }
+ return kp;
+ } else {
+ // DSA
+ KeyPair kp = null;
+
+ /* no DSA for now... netkey prototype
+ do {
+ // 602548 NSS bug - to overcome it, we use isBadDSAKeyPair
+ kp = kpGen.genKeyPair();
+ }
+ while (isBadDSAKeyPair(kp));
+ */
+ return kp;
+ }
+ }
+
+
+
+ public KeyPair generateKeyPair( String alg,
+ int keySize, PQGParams pqg) throws EBaseException {
+
+ KeyPairAlgorithm kpAlg = null;
+
+ if (alg.equals("RSA"))
+ kpAlg = KeyPairAlgorithm.RSA;
+ else
+ kpAlg = KeyPairAlgorithm.DSA;
+
+ try {
+ KeyPair kp = generateKeyPair( kpAlg, keySize, pqg);
+
+ return kp;
+ } catch (InvalidParameterException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEYSIZE_PARAMS",
+ "" + keySize));
+ } catch (PQGParamGenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_PQG_GEN_FAILED"));
+ } catch (NoSuchAlgorithmException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_ALG_NOT_SUPPORTED",
+ kpAlg.toString()));
+ } catch (TokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_TOKEN_ERROR_1", e.toString()));
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_ALG_NOT_SUPPORTED", "DSA"));
+ }
+ }
+
+ private static String base64Encode(byte[] bytes) throws IOException {
+ // All this streaming is lame, but Base64OutputStream needs a
+ // PrintStream
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ Base64OutputStream b64 = new Base64OutputStream(new
+ PrintStream(new
+ FilterOutputStream(output)
+ )
+ );
+
+ b64.write(bytes);
+ b64.flush();
+
+ // This is internationally safe because Base64 chars are
+ // contained within 8859_1
+ return output.toString("8859_1");
+ }
+
+ // this encrypts bytes with a symmetric key
+ public byte[] encryptIt(byte[] toBeEncrypted, SymmetricKey symKey, CryptoToken token,
+ IVParameterSpec IV)
+ {
+ try {
+ Cipher cipher = token.getCipherContext(
+ EncryptionAlgorithm.DES3_CBC_PAD);
+
+ cipher.initEncrypt(symKey, IV);
+ byte pri[] = cipher.doFinal(toBeEncrypted);
+ return pri;
+ } catch (Exception e) {
+ CMS.debug("NetkeyKeygenService:initEncrypt() threw exception: "+e.toString());
+ return null;
+ }
+
+ }
+
+
+ /**
+ * Services an archival request from netkey.
+ * <P>
+ *
+ * @param request enrollment request
+ * @return serving successful or not
+ * @exception EBaseException failed to serve
+ */
+ public boolean serviceRequest(IRequest request)
+ throws EBaseException {
+ String auditMessage = null;
+ String auditSubjectID = null;
+ String auditRequesterID = "TPSagent";
+ String auditArchiveID = ILogger.UNIDENTIFIED;
+ String auditPublicKey = ILogger.UNIDENTIFIED;
+ byte[] wrapped_des_key;
+
+ byte iv[] = {0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1};
+ String iv_s ="";
+ try {
+ SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
+ random.nextBytes(iv);
+ } catch (Exception e) {
+ CMS.debug("NetkeyKeygenService.serviceRequest: "+ e.toString());
+ }
+
+ IVParameterSpec algParam = new IVParameterSpec(iv);
+
+ wrapped_des_key = null;
+ boolean archive = true;
+ PK11SymKey sk= null;
+ byte[] publicKeyData = null;;
+ String PubKey = "";
+
+ String id = request.getRequestId().toString();
+ if (id != null) {
+ auditArchiveID = id.trim();
+ }
+
+ String rArchive = request.getExtDataInString(IRequest.NETKEY_ATTR_ARCHIVE_FLAG);
+ if (rArchive.equals("true")) {
+ archive = true;
+ CMS.debug("NetkeyKeygenService: serviceRequest " +"archival requested for serverSideKeyGen");
+ } else {
+ archive = false;
+ CMS.debug("NetkeyKeygenService: serviceRequest " +"archival not requested for serverSideKeyGen");
+ }
+
+ String rCUID = request.getExtDataInString(IRequest.NETKEY_ATTR_CUID);
+ String rUserid = request.getExtDataInString(IRequest.NETKEY_ATTR_USERID);
+ String rKeysize = request.getExtDataInString(IRequest.NETKEY_ATTR_KEY_SIZE);
+ int keysize = Integer.parseInt(rKeysize);
+ auditSubjectID=rCUID+":"+rUserid;
+
+ SessionContext sContext = SessionContext.getContext();
+ String agentId="";
+ if (sContext != null) {
+ agentId =
+ (String) sContext.get(SessionContext.USER_ID);
+ }
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST,
+ agentId,
+ ILogger.SUCCESS,
+ auditSubjectID);
+
+ audit(auditMessage);
+
+
+ String rWrappedDesKeyString = request.getExtDataInString(IRequest.NETKEY_ATTR_DRMTRANS_DES_KEY);
+ // CMS.debug("NetkeyKeygenService: received DRM-trans-wrapped DES key ="+rWrappedDesKeyString);
+ wrapped_des_key = com.netscape.cmsutil.util.Utils.SpecialDecode(rWrappedDesKeyString);
+ CMS.debug("NetkeyKeygenService: wrapped_des_key specialDecoded");
+
+ // get the token for generating user keys
+ CryptoToken keygenToken = mKRA.getKeygenToken();
+ if (keygenToken == null) {
+ CMS.debug("NetkeyKeygenService: failed getting keygenToken");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(10));
+ return false;
+ } else
+ CMS.debug("NetkeyKeygenService: got keygenToken");
+
+ if ((wrapped_des_key != null) &&
+ (wrapped_des_key.length > 0)) {
+
+ // unwrap the DES key
+ sk= (PK11SymKey) mTransportUnit.unwrap_sym(wrapped_des_key);
+
+ /* XXX could be done in HSM*/
+ KeyPair keypair = null;
+
+ CMS.debug("NetkeyKeygenService: about to generate key pair");
+
+ keypair = generateKeyPair("RSA"/*alg*/,
+ keysize /*Integer.parseInt(len)*/, null /*pqgParams*/);
+
+ if (keypair == null) {
+ CMS.debug("NetkeyKeygenService: failed generating key pair for "+rCUID+":"+rUserid);
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_FAILURE,
+ agentId,
+ ILogger.FAILURE,
+ auditSubjectID);
+
+ audit(auditMessage);
+
+ return false;
+ }
+ CMS.debug("NetkeyKeygenService: finished generate key pair for " +rCUID+":"+rUserid);
+
+ try {
+ publicKeyData = keypair.getPublic().getEncoded();
+ if (publicKeyData == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ CMS.debug("NetkeyKeygenService: failed getting publickey encoded");
+ return false;
+ } else {
+ //CMS.debug("NetkeyKeygenService: public key binary length ="+ publicKeyData.length);
+ PubKey = base64Encode(publicKeyData);
+
+ //CMS.debug("NetkeyKeygenService: public key length =" + PubKey.length());
+ request.setExtData("public_key", PubKey);
+ }
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_SUCCESS,
+ agentId,
+ ILogger.SUCCESS,
+ auditSubjectID,
+ PubKey);
+
+ audit(auditMessage);
+
+ //...extract the private key handle (not privatekeydata)
+ java.security.PrivateKey privKey =
+ keypair.getPrivate();
+
+ if (privKey == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ CMS.debug("NetkeyKeygenService: failed getting private key");
+ return false;
+ } else {
+ CMS.debug("NetkeyKeygenService: got private key");
+ }
+
+ if (sk == null) {
+ CMS.debug("NetkeyKeygenService: no DES key");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ return false;
+ } else {
+ CMS.debug("NetkeyKeygenService: received DES key");
+ }
+
+ // 3 wrapping should be done in HSM
+ // wrap private key with DES
+ KeyWrapper symWrap =
+ keygenToken.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
+ CMS.debug("NetkeyKeygenService: wrapper token=" + keygenToken.getName());
+ CMS.debug("NetkeyKeygenService: got key wrapper");
+
+ CMS.debug("NetkeyKeygenService: key transport key is on slot: "+sk.getOwningToken().getName());
+ symWrap.initWrap((SymmetricKey)sk, algParam);
+ byte wrapped[] = symWrap.wrap((PrivateKey)privKey);
+ /*
+ CMS.debug("NetkeyKeygenService: wrap called");
+ CMS.debug(wrapped);
+ */
+ /* This is for using with my decryption tool and ASN1
+ decoder to see if the private key is indeed PKCS#8 format
+ { // cfu debug
+ String oFilePath = "/tmp/wrappedPrivKey.bin";
+ File file = new File(oFilePath);
+ FileOutputStream ostream = new FileOutputStream(oFilePath);
+ ostream.write(wrapped);
+ ostream.close();
+ }
+ */
+ String wrappedPrivKeyString = /*base64Encode(wrapped);*/
+ com.netscape.cmsutil.util.Utils.SpecialEncode(wrapped);
+ if (wrappedPrivKeyString == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ CMS.debug("NetkeyKeygenService: failed generating wrapped private key");
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_FAILURE,
+ agentId,
+ ILogger.FAILURE,
+ auditSubjectID,
+ PubKey);
+
+ audit(auditMessage);
+ return false;
+ } else {
+ request.setExtData("wrappedUserPrivate", wrappedPrivKeyString);
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_SUCCESS,
+ agentId,
+ ILogger.SUCCESS,
+ auditSubjectID,
+ PubKey);
+
+ audit(auditMessage);
+ }
+
+ iv_s = /*base64Encode(iv);*/com.netscape.cmsutil.util.Utils.SpecialEncode(iv);
+ request.setExtData("iv_s", iv_s);
+
+ /*
+ * archival - option flag "archive" controllable by the caller - TPS
+ */
+ if (archive) {
+ //
+ // privateKeyData ::= SEQUENCE {
+ // sessionKey OCTET_STRING,
+ // encKey OCTET_STRING,
+ // }
+ //
+ // mKRA.log(ILogger.LL_INFO, "KRA encrypts internal private");
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST,
+ agentId,
+ ILogger.SUCCESS,
+ auditSubjectID,
+ auditArchiveID);
+
+ audit(auditMessage);
+ CMS.debug("KRA encrypts private key to put on internal ldap db");
+ byte privateKeyData[] =
+ mStorageUnit.wrap((org.mozilla.jss.crypto.PrivateKey) privKey);
+
+ if (privateKeyData == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ CMS.debug("NetkeyKeygenService: privatekey encryption by storage unit failed");
+ return false;
+ } else
+ CMS.debug("NetkeyKeygenService: privatekey encryption by storage unit successful");
+
+ // create key record
+ KeyRecord rec = new KeyRecord(null, publicKeyData,
+ privateKeyData, rCUID+":"+rUserid,
+ keypair.getPublic().getAlgorithm(),
+ agentId);
+
+ if (rec == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(11));
+ CMS.debug("NetkeyKeygenService: privatekey recording failed");
+ return false;
+ } else
+ CMS.debug("NetkeyKeygenService: got key record");
+
+ // we deal with RSA key only
+ try {
+ RSAPublicKey rsaPublicKey = new RSAPublicKey(publicKeyData);
+
+ rec.setKeySize(Integer.valueOf(rsaPublicKey.getKeySize()));
+ } catch (InvalidKeyException e) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(11));
+ CMS.debug("NetkeyKeygenService: failed:InvalidKeyException");
+ return false;
+ }
+ //??
+ IKeyRepository storage = mKRA.getKeyRepository();
+ BigInteger serialNo = storage.getNextSerialNumber();
+
+ if (serialNo == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(11));
+ CMS.debug("NetkeyKeygenService: serialNo null");
+ return false;
+ }
+ CMS.debug("NetkeyKeygenService: before addKeyRecord");
+ rec.set(KeyRecord.ATTR_ID, serialNo);
+ request.setExtData(ATTR_KEY_RECORD, serialNo);
+ storage.addKeyRecord(rec);
+ CMS.debug("NetkeyKeygenService: key archived for "+rCUID+":"+rUserid);
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,
+ agentId,
+ ILogger.SUCCESS,
+ PubKey);
+
+ audit(auditMessage);
+
+ } //if archive
+
+ request.setExtData(IRequest.RESULT, Integer.valueOf(1));
+ } catch (Exception e) {
+ CMS.debug("NetKeyKeygenService: " + e.toString());
+ Debug.printStackTrace(e);
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ }
+ } else
+ request.setExtData(IRequest.RESULT, Integer.valueOf(2));
+
+ return true;
+ } //serviceRequest
+
+ /**
+ * Signed Audit Log
+ *y
+ * This method is called to store messages to the signed audit log.
+ * <P>
+ *
+ * @param msg signed audit log message
+ */
+ private void audit(String msg) {
+ // in this case, do NOT strip preceding/trailing whitespace
+ // from passed-in String parameters
+
+ if (mSignedAuditLogger == null) {
+ return;
+ }
+
+ mSignedAuditLogger.log(ILogger.EV_SIGNED_AUDIT,
+ null,
+ ILogger.S_SIGNED_AUDIT,
+ ILogger.LL_SECURITY,
+ msg);
+ }
+}
diff --git a/pki/base/kra/src/com/netscape/kra/RecoveryService.java b/pki/base/kra/src/com/netscape/kra/RecoveryService.java
new file mode 100644
index 000000000..7f6137ffd
--- /dev/null
+++ b/pki/base/kra/src/com/netscape/kra/RecoveryService.java
@@ -0,0 +1,479 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+
+import java.util.*;
+import java.io.*;
+import java.net.*;
+import java.math.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.KeyPair;
+import netscape.security.util.*;
+import netscape.security.pkcs.*;
+import netscape.security.x509.*;
+import com.netscape.cmscore.util.*;
+import com.netscape.certsrv.util.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.base.*;
+
+import com.netscape.certsrv.dbs.*;
+import com.netscape.certsrv.security.*;
+import com.netscape.certsrv.kra.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.dbs.repository.*;
+import com.netscape.certsrv.dbs.keydb.*;
+import com.netscape.cmscore.cert.*;
+import com.netscape.cmscore.dbs.*;
+import com.netscape.cmscore.dbs.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.authentication.*;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.asn1.*;
+import org.mozilla.jss.crypto.PBEAlgorithm;
+import org.mozilla.jss.pkcs12.*;
+import org.mozilla.jss.pkix.primitive.*;
+
+
+/**
+ * A class represents recovery request processor. There
+ * are 2 types of recovery modes: (1) administrator or
+ * (2) end-entity.
+ * <P>
+ * Administrator recovery will create a PKCS12 file where
+ * stores the certificate and the recovered key.
+ * <P>
+ * End Entity recovery will send RA or CA a response where
+ * stores the recovered key.
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class RecoveryService implements IService {
+
+ public static final String ATTR_NICKNAME = "nickname";
+ public static final String ATTR_OWNER_NAME = "ownerName";
+ public static final String ATTR_SERIALNO = "serialNumber";
+ public static final String ATTR_PUBLIC_KEY_DATA = "publicKeyData";
+ public static final String ATTR_PRIVATE_KEY_DATA = "privateKeyData";
+ public static final String ATTR_TRANSPORT_CERT = "transportCert";
+ public static final String ATTR_TRANSPORT_PWD = "transportPwd";
+ public static final String ATTR_SIGNING_CERT = "signingCert";
+ public static final String ATTR_PKCS12 = "pkcs12";
+ public static final String ATTR_ENCRYPTION_CERTS =
+ "encryptionCerts";
+ public static final String ATTR_AGENT_CREDENTIALS =
+ "agentCredentials";
+ // same as encryption certs
+ public static final String ATTR_USER_CERT = "cert";
+ public static final String ATTR_DELIVERY = "delivery";
+
+ // for Async Key Recovery
+ public static final String ATTR_APPROVE_AGENTS = "approvingAgents";
+
+ private IKeyRecoveryAuthority mKRA = null;
+ private IKeyRepository mStorage = null;
+ private IStorageKeyUnit mStorageUnit = null;
+
+ /**
+ * Constructs request processor.
+ */
+ public RecoveryService(IKeyRecoveryAuthority kra) {
+ mKRA = kra;
+ mStorage = mKRA.getKeyRepository();
+ mStorageUnit = mKRA.getStorageKeyUnit();
+ }
+
+ /**
+ * Processes a recovery request. Based on the recovery mode
+ * (either Administrator or End-Entity), the method reads
+ * the key record from the database, and tried to recover the
+ * key with the storage key unit.
+ *
+ * @param request recovery request
+ * @return operation success or not
+ * @exception EBaseException failed to serve
+ */
+ public boolean serviceRequest(IRequest request) throws EBaseException {
+
+ IStatsSubsystem statsSub = (IStatsSubsystem)CMS.getSubsystem("stats");
+ if (statsSub != null) {
+ statsSub.startTiming("recovery", true /* main action */);
+ }
+
+ if (Debug.ON)
+ Debug.trace("KRA services recovery request");
+ mKRA.log(ILogger.LL_INFO, "KRA services recovery request");
+
+ // byte publicKey[] = (byte[])request.get(ATTR_PUBLIC_KEY_DATA);
+ // X500Name owner = (X500Name)request.get(ATTR_OWNER_NAME);
+
+ Hashtable params = mKRA.getVolatileRequest(
+ request.getRequestId());
+
+ if (params == null) {
+ // possibly we are in recovery mode
+ return true;
+ }
+
+ // retrieve based on serial no
+ BigInteger serialno = request.getExtDataInBigInteger(ATTR_SERIALNO);
+
+ mKRA.log(ILogger.LL_INFO, "KRA reading key record");
+ if (statsSub != null) {
+ statsSub.startTiming("get_key");
+ }
+ KeyRecord keyRecord = (KeyRecord) mStorage.readKeyRecord(serialno);
+ if (statsSub != null) {
+ statsSub.endTiming("get_key");
+ }
+
+ // see if the certificate matches the key
+ byte pubData[] = keyRecord.getPublicKeyData();
+ X509Certificate x509cert =
+ request.getExtDataInCert(ATTR_USER_CERT);
+ byte inputPubData[] = x509cert.getPublicKey().getEncoded();
+
+ if (inputPubData.length != pubData.length) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_PUBLIC_KEY_LEN"));
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_PUBLIC_KEY_NOT_MATCHED"));
+ }
+ for (int i = 0; i < pubData.length; i++) {
+ if (pubData[i] != inputPubData[i]) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_PUBLIC_KEY_LEN"));
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_PUBLIC_KEY_NOT_MATCHED"));
+ }
+ }
+
+ // Unwrap the archived private key
+ byte privateKeyData[] = null;
+ X509Certificate transportCert =
+ request.getExtDataInCert(ATTR_TRANSPORT_CERT);
+
+ if (transportCert == null) {
+ if (statsSub != null) {
+ statsSub.startTiming("recover_key");
+ }
+ privateKeyData = recoverKey(params, keyRecord);
+ if (statsSub != null) {
+ statsSub.endTiming("recover_key");
+ }
+
+ if (statsSub != null) {
+ statsSub.startTiming("verify_key");
+ }
+ if (verifyKeyPair(pubData, privateKeyData) == false) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_PUBLIC_NOT_FOUND"));
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_INVALID_PUBLIC_KEY"));
+ }
+ if (statsSub != null) {
+ statsSub.endTiming("verify_key");
+ }
+
+ if (statsSub != null) {
+ statsSub.startTiming("create_p12");
+ }
+ createPFX(request, params, privateKeyData);
+ if (statsSub != null) {
+ statsSub.endTiming("create_p12");
+ }
+ } else {
+
+ if (CMS.getConfigStore().getBoolean("kra.keySplitting")) {
+ Credential creds[] = (Credential[])
+ params.get(ATTR_AGENT_CREDENTIALS);
+ mKRA.getStorageKeyUnit().login(creds);
+ }
+ if (statsSub != null) {
+ statsSub.startTiming("unwrap_key");
+ }
+ PrivateKey privateKey = mKRA.getStorageKeyUnit().unwrap(
+ keyRecord.getPrivateKeyData(), null);
+ if (statsSub != null) {
+ statsSub.endTiming("unwrap_key");
+ }
+
+ if (CMS.getConfigStore().getBoolean("kra.keySplitting")) {
+ mKRA.getStorageKeyUnit().logout();
+ }
+ }
+ mKRA.log(ILogger.LL_INFO, "key " +
+ serialno.toString() +
+ " recovered");
+
+ // for audit log
+ String authMgr = AuditFormat.NOAUTH;
+ String initiative = AuditFormat.FROMUSER;
+ SessionContext sContext = SessionContext.getContext();
+
+ if (sContext != null) {
+ String agentId =
+ (String) sContext.get(SessionContext.USER_ID);
+
+ initiative = AuditFormat.FROMAGENT + " agentID: " + agentId;
+ AuthToken authToken = (AuthToken) sContext.get(SessionContext.AUTH_TOKEN);
+
+ if (authToken != null) {
+ authMgr =
+ authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME);
+ }
+ }
+ CMS.getLogger().log(ILogger.EV_AUDIT,
+ ILogger.S_KRA,
+ AuditFormat.LEVEL,
+ AuditFormat.FORMAT,
+ new Object[] {
+ IRequest.KEYRECOVERY_REQUEST,
+ request.getRequestId(),
+ initiative,
+ authMgr,
+ "completed",
+ ((X509CertImpl) x509cert).getSubjectDN(),
+ "serial number: 0x" + serialno.toString(16)}
+ );
+
+ if (statsSub != null) {
+ statsSub.endTiming("recovery");
+ }
+
+ return true;
+ }
+
+ public boolean verifyKeyPair(byte publicKeyData[], byte privateKeyData[])
+ {
+ try {
+ DerValue publicKeyVal = new DerValue(publicKeyData);
+ DerInputStream publicKeyIn = publicKeyVal.data;
+ publicKeyIn.getSequence(0);
+ DerValue publicKeyDer = new DerValue(publicKeyIn.getBitString());
+ DerInputStream publicKeyDerIn = publicKeyDer.data;
+ BigInt publicKeyModulus = publicKeyDerIn.getInteger();
+ BigInt publicKeyExponent = publicKeyDerIn.getInteger();
+
+ DerValue privateKeyVal = new DerValue(privateKeyData);
+ if (privateKeyVal.tag != DerValue.tag_Sequence)
+ return false;
+ DerInputStream privateKeyIn = privateKeyVal.data;
+ privateKeyIn.getInteger();
+ privateKeyIn.getSequence(0);
+ DerValue privateKeyDer = new DerValue(privateKeyIn.getOctetString());
+ DerInputStream privateKeyDerIn = privateKeyDer.data;
+ BigInt privateKeyVersion = privateKeyDerIn.getInteger();
+ BigInt privateKeyModulus = privateKeyDerIn.getInteger();
+ BigInt privateKeyExponent = privateKeyDerIn.getInteger();
+
+ if (!publicKeyModulus.equals(privateKeyModulus)) {
+ CMS.debug("verifyKeyPair modulus mismatch publicKeyModulus=" + publicKeyModulus + " privateKeyModulus=" + privateKeyModulus);
+ return false;
+ }
+
+ if (!publicKeyExponent.equals(privateKeyExponent)) {
+ CMS.debug("verifyKeyPair exponent mismatch publicKeyExponent=" + publicKeyExponent + " privateKeyExponent=" + privateKeyExponent);
+ return false;
+ }
+
+ return true;
+ } catch (Exception e) {
+ CMS.debug("verifyKeyPair error " + e);
+ return false;
+ }
+ }
+
+ /**
+ * Recovers key.
+ */
+ public synchronized byte[] recoverKey(Hashtable request, KeyRecord keyRecord)
+ throws EBaseException {
+ if (CMS.getConfigStore().getBoolean("kra.keySplitting")) {
+ Credential creds[] = (Credential[])
+ request.get(ATTR_AGENT_CREDENTIALS);
+
+ mStorageUnit.login(creds);
+ }
+ mKRA.log(ILogger.LL_INFO, "KRA decrypts internal private");
+ byte privateKeyData[] =
+ mStorageUnit.decryptInternalPrivate(
+ keyRecord.getPrivateKeyData());
+
+ if (CMS.getConfigStore().getBoolean("kra.keySplitting")) {
+ mStorageUnit.logout();
+ }
+ if (privateKeyData == null) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_PRIVATE_KEY_NOT_FOUND"));
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1", "no private key"));
+ }
+ return privateKeyData;
+ }
+
+ /**
+ * Creates a PFX (PKCS12) file.
+ *
+ * @param request CRMF recovery request
+ * @param priData decrypted private key (PrivateKeyInfo)
+ * @exception EBaseException failed to create P12 file
+ */
+ public void createPFX(IRequest request, Hashtable params,
+ byte priData[]) throws EBaseException {
+ // create p12
+ X509Certificate x509cert =
+ request.getExtDataInCert(ATTR_USER_CERT);
+ String pwd = (String) params.get(ATTR_TRANSPORT_PWD);
+
+ try {
+
+ // add certificate
+ mKRA.log(ILogger.LL_INFO, "KRA adds certificate to P12");
+ SEQUENCE encSafeContents = new SEQUENCE();
+ ASN1Value cert = new OCTET_STRING(x509cert.getEncoded());
+ String nickname = request.getExtDataInString(ATTR_NICKNAME);
+
+ if (nickname == null) {
+ nickname = x509cert.getSubjectDN().toString();
+ }
+ byte localKeyId[] = createLocalKeyId(x509cert);
+ SET certAttrs = createBagAttrs(
+ nickname, localKeyId);
+ // attributes: user friendly name, Local Key ID
+ SafeBag certBag = new SafeBag(SafeBag.CERT_BAG,
+ new CertBag(CertBag.X509_CERT_TYPE, cert),
+ certAttrs);
+
+ encSafeContents.addElement(certBag);
+
+ // add key
+ mKRA.log(ILogger.LL_INFO, "KRA adds key to P12");
+ org.mozilla.jss.util.Password pass = new
+ org.mozilla.jss.util.Password(
+ pwd.toCharArray());
+
+ SEQUENCE safeContents = new SEQUENCE();
+ PasswordConverter passConverter = new
+ PasswordConverter();
+ byte salt[] = {0x01, 0x01, 0x01, 0x01};
+ PrivateKeyInfo pki = (PrivateKeyInfo)
+ ASN1Util.decode(PrivateKeyInfo.getTemplate(),
+ priData);
+ ASN1Value key = EncryptedPrivateKeyInfo.createPBE(
+ PBEAlgorithm.PBE_SHA1_DES3_CBC,
+ pass, salt, 1, passConverter, pki);
+ SET keyAttrs = createBagAttrs(
+ x509cert.getSubjectDN().toString(),
+ localKeyId);
+ SafeBag keyBag = new SafeBag(
+ SafeBag.PKCS8_SHROUDED_KEY_BAG, key,
+ keyAttrs); // ??
+
+ safeContents.addElement(keyBag);
+
+ // build contents
+ AuthenticatedSafes authSafes = new
+ AuthenticatedSafes();
+
+ authSafes.addSafeContents(
+ safeContents
+ );
+ authSafes.addSafeContents(
+ encSafeContents
+ );
+
+ // authSafes.addEncryptedSafeContents(
+ // authSafes.DEFAULT_KEY_GEN_ALG,
+ // pass, null, 1,
+ // encSafeContents);
+ PFX pfx = new PFX(authSafes);
+
+ pfx.computeMacData(pass, null, 5); // ??
+ ByteArrayOutputStream fos = new
+ ByteArrayOutputStream();
+
+ pfx.encode(fos);
+ pass.clear();
+
+ // put final PKCS12 into volatile request
+ params.put(ATTR_PKCS12, fos.toByteArray());
+ } catch (Exception e) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_CONSTRUCT_P12", e.toString()));
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_PKCS12_FAILED_1", e.toString()));
+ }
+
+ // update request
+ mKRA.getRequestQueue().updateRequest(request);
+ }
+
+ /**
+ * Creates local key identifier.
+ */
+ public byte[] createLocalKeyId(X509Certificate cert)
+ throws EBaseException {
+ try {
+ // SHA1 hash of the X509Cert der encoding
+ byte certDer[] = cert.getEncoded();
+
+ // XXX - should use JSS
+ MessageDigest md = MessageDigest.getInstance("SHA");
+
+ md.update(certDer);
+ return md.digest();
+ } catch (CertificateEncodingException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_CREAT_KEY_ID", e.toString()));
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_KEYID_FAILED_1", e.toString()));
+ } catch (NoSuchAlgorithmException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_CREAT_KEY_ID", e.toString()));
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_KEYID_FAILED_1", e.toString()));
+ }
+ }
+
+ /**
+ * Creates bag attributes.
+ */
+ public SET createBagAttrs(String nickName, byte localKeyId[])
+ throws EBaseException {
+ try {
+ SET attrs = new SET();
+ SEQUENCE nickNameAttr = new SEQUENCE();
+
+ nickNameAttr.addElement(SafeBag.FRIENDLY_NAME);
+ SET nickNameSet = new SET();
+
+ nickNameSet.addElement(new BMPString(nickName));
+ nickNameAttr.addElement(nickNameSet);
+ attrs.addElement(nickNameAttr);
+ SEQUENCE localKeyAttr = new SEQUENCE();
+
+ localKeyAttr.addElement(SafeBag.LOCAL_KEY_ID);
+ SET localKeySet = new SET();
+
+ localKeySet.addElement(new OCTET_STRING(localKeyId));
+ localKeyAttr.addElement(localKeySet);
+ attrs.addElement(localKeyAttr);
+ return attrs;
+ } catch (CharConversionException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_CREAT_KEY_BAG", e.toString()));
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_KEYBAG_FAILED_1", e.toString()));
+ }
+ }
+}
diff --git a/pki/base/kra/src/com/netscape/kra/StorageKeyUnit.java b/pki/base/kra/src/com/netscape/kra/StorageKeyUnit.java
new file mode 100644
index 000000000..baec75494
--- /dev/null
+++ b/pki/base/kra/src/com/netscape/kra/StorageKeyUnit.java
@@ -0,0 +1,959 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+
+import org.mozilla.jss.util.Password;
+import java.util.*;
+import java.io.*;
+import com.netscape.certsrv.security.*;
+import java.net.*;
+import java.security.*;
+import java.security.cert.*;
+import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.crypto.TokenCertificate;
+import netscape.security.x509.*;
+import netscape.security.util.*;
+import com.netscape.cmscore.util.*;
+//import com.netscape.cmscore.kra.*;
+import com.netscape.certsrv.dbs.keydb.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.security.*;
+import com.netscape.certsrv.kra.*;
+import org.mozilla.jss.crypto.PrivateKey;
+import org.mozilla.jss.*;
+import org.mozilla.jss.asn1.INTEGER;
+import org.mozilla.jss.util.*;
+import org.mozilla.jss.util.Password;
+import org.mozilla.jss.crypto.*;
+import com.netscape.cmscore.cert.*;
+
+
+/**
+ * A class represents a storage key unit. Currently, this
+ * is implemented with cryptix, the final implementation
+ * should be built on JSS/HCL.
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class StorageKeyUnit extends EncryptionUnit implements
+ ISubsystem, IStorageKeyUnit {
+
+ private IConfigStore mConfig = null;
+
+ // private RSAPublicKey mPublicKey = null;
+ // private RSAPrivateKey mPrivateKey = null;
+
+ private IConfigStore mStorageConfig = null;
+ private IKeyRecoveryAuthority mKRA = null;
+ private String mTokenFile = null;
+ private X509Certificate mCert = null;
+ private CryptoManager mManager = null;
+ private CryptoToken mToken = null;
+ private PrivateKey mPrivateKey = null;
+ private byte mPrivateKeyData[] = null;
+ private boolean mKeySplitting = false;
+
+
+ private static final String PROP_N = "n";
+ private static final String PROP_M = "m";
+ private static final String PROP_UID = "uid";
+ private static final String PROP_SHARE = "share";
+ private static final String PROP_HARDWARE = "hardware";
+ private static final String PROP_LOGOUT = "logout";
+ public static final String PROP_NICKNAME = "nickName";
+ public static final String PROP_KEYDB = "keydb";
+ public static final String PROP_CERTDB = "certdb";
+ public static final String PROP_MN = "mn";
+
+ /**
+ * Constructs this token.
+ */
+ public StorageKeyUnit() {
+ super();
+ }
+
+ /**
+ * Retrieves subsystem identifier.
+ */
+ public String getId() {
+ return "storageKeyUnit";
+ }
+
+ /**
+ * Sets subsystem identifier. Once the system is
+ * loaded, system identifier cannot be changed
+ * dynamically.
+ */
+ public void setId(String id) throws EBaseException {
+ throw new EBaseException(CMS.getUserMessage("CMS_INVALID_OPERATION"));
+ }
+
+ /**
+ * return true if byte arrays are equal, false otherwise
+ */
+ private boolean byteArraysMatch(byte a[], byte b[]) {
+ if (a==null || b==null) { return false; }
+ if (a.length != b.length) { return false; }
+ for (int i=0; i<a.length; i++) {
+ if (a[i] != b[i]) { return false; }
+ }
+ return true;
+ }
+
+
+ /**
+ * Initializes this subsystem.
+ */
+ public void init(ISubsystem owner, IConfigStore config)
+ throws EBaseException {
+ mKRA = (IKeyRecoveryAuthority) owner;
+ mConfig = config;
+
+ mKeySplitting = owner.getConfigStore().getBoolean("keySplitting", false);
+
+ try {
+ mManager = CryptoManager.getInstance();
+ mToken = getToken();
+ } catch (org.mozilla.jss.CryptoManager.NotInitializedException e) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_STORAGE_INIT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ }
+
+ if (mConfig.getString(PROP_HARDWARE, null) != null) {
+ System.setProperty("cms.skip_token", mConfig.getString(PROP_HARDWARE));
+
+// The strategy here is to read all the certs in the token
+// and cycle through them until we find one that matches the
+// kra-cert.db file
+
+ if (mKeySplitting) {
+
+ byte certFileData[] = null;
+ try {
+ File certFile = new File(
+ mConfig.getString(PROP_CERTDB));
+
+ certFileData = new byte[
+ (Long.valueOf(certFile.length())).intValue()];
+ FileInputStream fi = new FileInputStream(certFile);
+
+ fi.read(certFileData);
+ fi.close();
+
+ // pick up cert by nickName
+
+ } catch (IOException e) {
+ mKRA.log(ILogger.LL_INFO,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_CERT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ }
+
+ try {
+ X509Certificate certs[] =
+ getToken().getCryptoStore().getCertificates();
+ for (int i=0;i <certs.length;i++) {
+ if (byteArraysMatch(certs[i].getEncoded(),certFileData)) {
+ mCert = certs[i];
+ }
+ }
+ if (mCert == null) {
+ mKRA.log(ILogger.LL_FAILURE, "Storage Cert could not be initialized. No cert in token matched kra-cert file");
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", "mCert == null"));
+ } else {
+ mKRA.log(ILogger.LL_INFO, "Using Storage Cert "+mCert.getSubjectDN());
+ }
+ } catch (CertificateEncodingException e) {
+ mKRA.log(ILogger.LL_FAILURE, "Error encoding cert ");
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ } catch (TokenException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_CERT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ }
+ }
+
+ } else {
+
+ // read certificate from file
+ byte certData[] = null;
+
+ try {
+ if (mKeySplitting) {
+ File certFile = new File(
+ mConfig.getString(PROP_CERTDB));
+
+ certData = new byte[
+ (Long.valueOf(certFile.length())).intValue()];
+ FileInputStream fi = new FileInputStream(certFile);
+
+ fi.read(certData);
+ fi.close();
+
+ // pick up cert by nickName
+ mCert = mManager.findCertByNickname(
+ config.getString(PROP_NICKNAME));
+
+ } else {
+ mCert = mManager.findCertByNickname(
+ config.getString(PROP_NICKNAME));
+ }
+ } catch (IOException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_CERT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ } catch (TokenException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_CERT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ } catch (ObjectNotFoundException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_CERT", e.toString()));
+ // XXX - this import wont work
+ try {
+ mCert = mManager.importCertPackage(certData,
+ "kraStorageCert");
+ } catch (Exception ex) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_IMPORT_CERT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", ex.toString()));
+ }
+ }
+
+ if (mKeySplitting) {
+ // read private key from the file
+ try {
+ File priFile = new File(mConfig.getString(PROP_KEYDB));
+
+ mPrivateKeyData = new byte[
+ (Long.valueOf(priFile.length())).intValue()];
+ FileInputStream fi = new FileInputStream(priFile);
+
+ fi.read(mPrivateKeyData);
+ fi.close();
+ } catch (IOException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_PRIVATE", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1", e.toString()));
+ }
+ }
+
+ }
+
+ if (mKeySplitting) {
+ // open internal data storage configuration
+ mTokenFile = mConfig.getString(PROP_MN);
+ try {
+ // read m, n and no of identifier
+ mStorageConfig = CMS.createFileConfigStore(mTokenFile);
+ } catch (EBaseException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_MN",
+ e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_OPERATION"));
+
+ }
+ }
+
+ try {
+ if (mCert == null) {
+ CMS.debug("mCert is null...retrieving "+ config.getString(PROP_NICKNAME));
+ mCert = mManager.findCertByNickname(
+ config.getString(PROP_NICKNAME));
+ CMS.debug("mCert = "+mCert);
+ }
+ } catch (Exception e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_READ_CERT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ }
+
+ }
+
+ /**
+ * Starts up this subsystem.
+ */
+ public void startup() throws EBaseException {
+ }
+
+ /**
+ * Shutdowns this subsystem.
+ */
+ public void shutdown() {
+ }
+
+ /**
+ * Returns the configuration store of this token.
+ */
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ public static SymmetricKey buildSymmetricKeyWithInternalStorage(
+ String pin) throws EBaseException {
+ try {
+ return buildSymmetricKey(CryptoManager.getInstance().getInternalKeyStorageToken(), pin);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Builds symmetric key from the given password.
+ */
+ public static SymmetricKey buildSymmetricKey(CryptoToken token,
+ String pin) throws EBaseException {
+ try {
+
+ Password pass = new Password(pin.toCharArray());
+ KeyGenerator kg = null;
+
+ kg = token.getKeyGenerator(
+ PBEAlgorithm.PBE_SHA1_DES3_CBC);
+ byte salt[] = {0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01};
+ PBEKeyGenParams kgp = new PBEKeyGenParams(pass,
+ salt, 5);
+
+ pass.clear();
+ kg.initialize(kgp);
+ return kg.generate();
+ } catch (TokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "buildSymmetricKey:" +
+ e.toString()));
+ } catch (NoSuchAlgorithmException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "buildSymmetricKey:" +
+ e.toString()));
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "buildSymmetricKey:" +
+ e.toString()));
+ } catch (CharConversionException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "buildSymmetricKey:" +
+ e.toString()));
+ }
+ }
+
+ /**
+ * Unwraps the storage key with the given symmetric key.
+ */
+ public PrivateKey unwrapStorageKey(CryptoToken token,
+ SymmetricKey sk, byte wrapped[],
+ PublicKey pubKey)
+ throws EBaseException {
+ try {
+
+ CMS.debug("StorageKeyUnit.unwrapStorageKey.");
+
+ KeyWrapper wrapper = token.getKeyWrapper(
+ KeyWrapAlgorithm.DES3_CBC_PAD);
+
+ wrapper.initUnwrap(sk, IV);
+
+ // XXX - it does not like the public key that is
+ // not a crypto X509Certificate
+ PrivateKey pk = wrapper.unwrapTemporaryPrivate(wrapped,
+ PrivateKey.RSA, pubKey);
+
+ return pk;
+ } catch (TokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "unwrapStorageKey:" +
+ e.toString()));
+ } catch (NoSuchAlgorithmException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "unwrapStorageKey:" +
+ e.toString()));
+ } catch (InvalidKeyException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "unwrapStorageKey:" +
+ e.toString()));
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "unwrapStorageKey:" +
+ e.toString()));
+ }
+ }
+
+ /**
+ * Used by config-cert.
+ */
+ public byte[] wrapStorageKey(CryptoToken token,
+ SymmetricKey sk, PrivateKey pri)
+ throws EBaseException {
+ CMS.debug("StorageKeyUnit.wrapStorageKey.");
+ try {
+ // move public & private to config/storage.dat
+ // delete private key
+ KeyWrapper wrapper = token.getKeyWrapper(
+ KeyWrapAlgorithm.DES3_CBC_PAD);
+
+ // next to randomly generate a symmetric
+ // password
+
+ wrapper.initWrap(sk, IV);
+ return wrapper.wrap(pri);
+ } catch (TokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "wrapStorageKey:" +
+ e.toString()));
+ } catch (NoSuchAlgorithmException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "wrapStorageKey:" +
+ e.toString()));
+ } catch (InvalidKeyException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "wrapStorageKey:" +
+ e.toString()));
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ "wrapStorageKey:" +
+ e.toString()));
+ }
+ }
+
+ /**
+ * Logins to this token.
+ */
+ public void login(String pin) throws EBaseException {
+ if (mConfig.getString(PROP_HARDWARE, null) != null) {
+ try {
+ getToken().login(new Password(pin.toCharArray()));
+ PrivateKey pk[] = getToken().getCryptoStore().getPrivateKeys();
+
+ for (int i = 0; i < pk.length; i++) {
+ if (arraysEqual(pk[i].getUniqueID(),
+ ((TokenCertificate) mCert).getUniqueID())) {
+ mPrivateKey = pk[i];
+ }
+ }
+ } catch (Exception e) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_STORAGE_LOGIN", e.toString()));
+ }
+
+ } else {
+ try {
+ SymmetricKey sk = buildSymmetricKey(mToken, pin);
+
+ mPrivateKey = unwrapStorageKey(mToken, sk,
+ mPrivateKeyData, getPublicKey());
+ } catch (Exception e) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_STORAGE_LOGIN", e.toString()));
+ }
+ if (mPrivateKey == null) {
+ mPrivateKey = getPrivateKey();
+ }
+ }
+ }
+
+ /**
+ * Logins to this token.
+ */
+ public void login(Credential creds[])
+ throws EBaseException {
+ String pwd = constructPassword(creds);
+
+ login(pwd);
+ }
+
+ /**
+ * Logout from this token.
+ */
+ public void logout() {
+ try {
+ if (mConfig.getString(PROP_HARDWARE, null) != null) {
+ if (mConfig.getBoolean(PROP_LOGOUT, false)) {
+ getToken().logout();
+ }
+ }
+ } catch (Exception e) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_STORAGE_LOGOUT", e.toString()));
+
+ }
+ mPrivateKey = null;
+ }
+
+ /**
+ * Returns a list of recovery agent identifiers.
+ */
+ public Enumeration getAgentIdentifiers() {
+ Vector v = new Vector();
+
+ for (int i = 0;; i++) {
+ try {
+ String uid =
+ mStorageConfig.getString(PROP_UID + i);
+
+ if (uid == null)
+ break;
+ v.addElement(uid);
+ } catch (EBaseException e) {
+ break;
+ }
+ }
+ return v.elements();
+ }
+
+ /**
+ * Changes agent password.
+ */
+ public boolean changeAgentPassword(String id, String oldpwd,
+ String newpwd) throws EBaseException {
+ // locate the id(s)
+ for (int i = 0;; i++) {
+ try {
+ String uid =
+ mStorageConfig.getString(PROP_UID + i);
+
+ if (uid == null)
+ break;
+ if (id.equals(uid)) {
+ byte share[] = decryptShareWithInternalStorage(mStorageConfig.getString(PROP_SHARE + i), oldpwd);
+
+ mStorageConfig.putString(PROP_SHARE + i,
+ encryptShareWithInternalStorage(
+ share, newpwd));
+ mStorageConfig.commit(false);
+ return true;
+ }
+ } catch (Exception e) {
+ break;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Changes the m out of n recovery schema.
+ */
+ public boolean changeAgentMN(int new_n, int new_m,
+ Credential oldcreds[],
+ Credential newcreds[])
+ throws EBaseException {
+
+ if (new_n != newcreds.length) {
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_INVALID_N"));
+ }
+
+ // XXX - verify and construct original password
+ String secret = constructPassword(oldcreds);
+
+ // XXX - remove extra configuration
+ for (int j = new_n; j < getNoOfAgents(); j++) {
+ mStorageConfig.remove(PROP_UID + j);
+ mStorageConfig.remove(PROP_SHARE + j);
+ }
+
+ // XXX - split pwd into n pieces
+ byte shares[][] = new byte[newcreds.length][];
+
+ IShare s = null;
+ try {
+ String className = mConfig.getString("share_class",
+ "com.netscape.cms.shares.OldShare");
+ s = (IShare)Class.forName(className).newInstance();
+ } catch (Exception e) {
+ CMS.debug("Loading Shares error " + e);
+ }
+ if (s == null) {
+ CMS.debug("Share plugin is not found");
+ return false;
+ }
+
+ try {
+ s.initialize(secret.getBytes(), new_m);
+ } catch (Exception e) {
+ CMS.debug("Failed to initialize Share plugin");
+ return false;
+ }
+
+ for (int i = 0; i < newcreds.length; i++) {
+ byte share[] = s.createShare(i + 1);
+
+ shares[i] = share;
+ }
+
+ // store the new shares into configuration
+ mStorageConfig.putInteger(PROP_N, new_n);
+ mStorageConfig.putInteger(PROP_M, new_m);
+ for (int i = 0; i < newcreds.length; i++) {
+ mStorageConfig.putString(PROP_UID + i,
+ newcreds[i].getIdentifier());
+ // use password to encrypt shares...
+ mStorageConfig.putString(PROP_SHARE + i,
+ encryptShareWithInternalStorage(shares[i],
+ newcreds[i].getPassword()));
+ }
+
+ try {
+ mStorageConfig.commit(false);
+ return true;
+ } catch (EBaseException e) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_CHANGE_MN", e.toString()));
+ }
+ return false;
+ }
+
+ /**
+ * Returns number of recovery agents.
+ */
+ public int getNoOfAgents() throws EBaseException {
+ return mStorageConfig.getInteger(PROP_N);
+ }
+
+ /**
+ * Returns number of recovery agents required for
+ * recovery operation.
+ */
+ public int getNoOfRequiredAgents() throws EBaseException {
+ return mStorageConfig.getInteger(PROP_M);
+ }
+
+ public void setNoOfRequiredAgents(int number) {
+ mStorageConfig.putInteger(PROP_M, number);
+ }
+
+ public CryptoToken getInternalToken() {
+ try {
+ return CryptoManager.getInstance().getInternalKeyStorageToken();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public CryptoToken getToken() {
+ try {
+ if (mConfig.getString(PROP_HARDWARE, null) != null) {
+ return mManager.getTokenByName(mConfig.getString(PROP_HARDWARE));
+ } else {
+ return CryptoManager.getInstance().getInternalKeyStorageToken();
+ }
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the certificate blob.
+ */
+ public PublicKey getPublicKey() {
+ // NEED to move this key into internal storage token.
+ return mCert.getPublicKey();
+ }
+
+ public PrivateKey getPrivateKey() {
+
+ if (!mKeySplitting) {
+ try {
+ PrivateKey pk[] = getToken().getCryptoStore().getPrivateKeys();
+ for (int i = 0; i < pk.length; i++) {
+ if (arraysEqual(pk[i].getUniqueID(),
+ ((TokenCertificate) mCert).getUniqueID())) {
+ return pk[i];
+ }
+ }
+ } catch (TokenException e) {
+ }
+ return null;
+ } else {
+ return mPrivateKey;
+ }
+ }
+
+ /**
+ * Verifies the integrity of the given key pairs.
+ */
+ public void verify(byte publicKey[], PrivateKey privateKey)
+ throws EBaseException {
+ // XXX
+ }
+
+ public String encryptShareWithInternalStorage(
+ byte share[], String pwd)
+ throws EBaseException {
+ try {
+ return encryptShare(CryptoManager.getInstance().getInternalKeyStorageToken(), share, pwd);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Protectes the share with the given password.
+ */
+ public String encryptShare(CryptoToken token,
+ byte share[], String pwd)
+ throws EBaseException {
+ try {
+ CMS.debug("StorageKeyUnit.encryptShare");
+ Cipher cipher = token.getCipherContext(
+ EncryptionAlgorithm.DES3_CBC_PAD);
+ SymmetricKey sk = StorageKeyUnit.buildSymmetricKey(token, pwd);
+
+ cipher.initEncrypt(sk, IV);
+ byte prev[] = preVerify(share);
+ byte enc[] = cipher.doFinal(prev);
+
+ // #615387 - cannot use CMS.BtoA because CMS is not present during
+ // configuration
+ return com.netscape.osutil.OSUtil.BtoA(enc).trim();
+ } catch (NoSuchAlgorithmException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ e.toString()));
+ } catch (TokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ e.toString()));
+ } catch (InvalidKeyException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ e.toString()));
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ e.toString()));
+ } catch (BadPaddingException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ e.toString()));
+ } catch (IllegalBlockSizeException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1",
+ e.toString()));
+ }
+ }
+
+ public static byte[] preVerify(byte share[]) {
+ byte data[] = new byte[share.length + 2];
+
+ data[0] = 0;
+ data[1] = 0;
+ for (int i = 0; i < share.length; i++) {
+ data[2 + i] = share[i];
+ }
+ return data;
+ }
+
+ public static boolean verifyShare(byte share[]) {
+ if (share[0] == 0 && share[1] == 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static byte[] postVerify(byte share[]) {
+ byte data[] = new byte[share.length - 2];
+
+ for (int i = 2; i < share.length; i++) {
+ data[i - 2] = share[i];
+ }
+ return data;
+ }
+
+ public void checkPassword(String userid, String pwd) throws EBaseException {
+ for (int i = 0;; i++) {
+ String uid = null;
+
+ try {
+ uid = mStorageConfig.getString(PROP_UID + i);
+ if (uid == null)
+ break;
+ } catch (Exception e) {
+ break;
+ }
+ if (uid.equals(userid)) {
+ byte data[] = decryptShareWithInternalStorage(
+ mStorageConfig.getString(PROP_SHARE + i),
+ pwd);
+ if (data == null) {
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ return;
+ }
+ }
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+
+ }
+
+ public byte[] decryptShareWithInternalStorage(
+ String encoding, String pwd)
+ throws EBaseException {
+ try {
+ return decryptShare(CryptoManager.getInstance().getInternalKeyStorageToken(), encoding, pwd);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Decrypts shares with the given password.
+ */
+ public byte[] decryptShare(CryptoToken token,
+ String encoding, String pwd)
+ throws EBaseException {
+ try {
+ CMS.debug("StorageKeyUnit.decryptShare");
+ byte share[] = CMS.AtoB(encoding);
+ Cipher cipher = token.getCipherContext(
+ EncryptionAlgorithm.DES3_CBC_PAD);
+ SymmetricKey sk = StorageKeyUnit.buildSymmetricKey(
+ token, pwd);
+
+ cipher.initDecrypt(sk, IV);
+ byte dec[] = cipher.doFinal(share);
+
+ if (dec == null || !verifyShare(dec)) {
+ // invalid passwod
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ return postVerify(dec);
+ } catch (OutOfMemoryError e) {
+ // XXX - this happens in cipher.doFinal when
+ // the given share is not valid (the password
+ // given from the agent is not correct).
+ // Actulla, cipher.doFinal should return
+ // something better than this!
+ //
+ // e.printStackTrace();
+ //
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ e.toString()));
+ } catch (TokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ e.toString()));
+ } catch (NoSuchAlgorithmException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ e.toString()));
+ } catch (InvalidKeyException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ e.toString()));
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ e.toString()));
+ } catch (IllegalBlockSizeException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ e.toString()));
+ } catch (BadPaddingException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ e.toString()));
+ }
+ }
+
+ /**
+ * Reconstructs password from recovery agents.
+ */
+ private String constructPassword(Credential creds[])
+ throws EBaseException {
+ // sort the credential according to the order in
+ // configuration file
+ Hashtable v = new Hashtable();
+
+ for (int i = 0;; i++) {
+ String uid = null;
+
+ try {
+ uid = mStorageConfig.getString(PROP_UID + i);
+ if (uid == null)
+ break;
+ } catch (Exception e) {
+ break;
+ }
+ for (int j = 0; j < creds.length; j++) {
+ if (uid.equals(creds[j].getIdentifier())) {
+ byte pwd[] = decryptShareWithInternalStorage(
+ mStorageConfig.getString(
+ PROP_SHARE + i),
+ creds[j].getPassword());
+ if (pwd == null) {
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ v.put(Integer.toString(i), pwd);
+ break;
+ }
+ }
+ }
+
+ if (v.size() < 0) {
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ if (v.size() != creds.length) {
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ IJoinShares j = null;
+ try {
+ String className = mConfig.getString("joinshares_class",
+ "com.netscape.cms.shares.OldJoinShares");
+ j = (IJoinShares)Class.forName(className).newInstance();
+ } catch (Exception e) {
+ CMS.debug("JoinShares error " + e);
+ }
+ if (j == null) {
+ CMS.debug("JoinShares plugin is not found");
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ try {
+ j.initialize(v.size());
+ } catch (Exception e) {
+ CMS.debug("Failed to initialize JoinShares");
+ throw new EBaseException(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ Enumeration e = v.keys();
+
+ while (e.hasMoreElements()) {
+ String next = (String) e.nextElement();
+
+ j.addShare(Integer.parseInt(next) + 1,
+ (byte[]) v.get(next));
+ }
+ try {
+ byte secret[] = j.recoverSecret();
+ String pwd = new String(secret);
+
+ return pwd;
+ } catch (Exception ee) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_STORAGE_RECONSTRUCT", e.toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_PASSWORD",
+ ee.toString()));
+ }
+ }
+
+ public static boolean arraysEqual(byte[] bytes, byte[] ints) {
+ if (bytes == null || ints == null) {
+ return false;
+ }
+
+ if (bytes.length != ints.length) {
+ return false;
+ }
+
+ for (int i = 0; i < bytes.length; i++) {
+ if (bytes[i] != ints[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/pki/base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java b/pki/base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java
new file mode 100644
index 000000000..043602a8a
--- /dev/null
+++ b/pki/base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java
@@ -0,0 +1,635 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+
+import java.util.*;
+import java.io.*;
+import java.net.*;
+import java.math.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.KeyPair;
+import netscape.security.util.*;
+import netscape.security.pkcs.*;
+import netscape.security.x509.*;
+import netscape.security.x509.X500Name;
+
+import com.netscape.cmscore.util.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.base.*;
+
+import com.netscape.certsrv.dbs.*;
+import com.netscape.certsrv.security.*;
+import com.netscape.certsrv.kra.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.dbs.repository.*;
+import com.netscape.certsrv.dbs.keydb.*;
+import com.netscape.cmscore.cert.*;
+import com.netscape.cmscore.dbs.*;
+import com.netscape.cmscore.dbs.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.cmsutil.util.*;
+
+import org.mozilla.jss.*;
+import org.mozilla.jss.crypto.*;
+import org.mozilla.jss.util.*;
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.asn1.*;
+import org.mozilla.jss.crypto.PBEAlgorithm;
+import org.mozilla.jss.pkix.primitive.*;
+import org.mozilla.jss.pkcs11.*;
+
+
+/**
+ * A class represents recovery request processor.
+ * @author Christina Fu (cfu)
+ * @version $Revision$, $Date$
+ */
+public class TokenKeyRecoveryService implements IService {
+
+ public static final String ATTR_NICKNAME = "nickname";
+ public static final String ATTR_OWNER_NAME = "ownerName";
+ public static final String ATTR_PUBLIC_KEY_DATA = "publicKeyData";
+ public static final String ATTR_PRIVATE_KEY_DATA = "privateKeyData";
+ public static final String ATTR_TRANSPORT_CERT = "transportCert";
+ public static final String ATTR_TRANSPORT_PWD = "transportPwd";
+ public static final String ATTR_SIGNING_CERT = "signingCert";
+ public static final String ATTR_PKCS12 = "pkcs12";
+ public static final String ATTR_ENCRYPTION_CERTS =
+ "encryptionCerts";
+ public static final String ATTR_AGENT_CREDENTIALS =
+ "agentCredentials";
+ // same as encryption certs
+ public static final String ATTR_USER_CERT = "cert";
+ public static final String ATTR_DELIVERY = "delivery";
+
+ private IKeyRecoveryAuthority mKRA = null;
+ private IKeyRepository mStorage = null;
+ private IStorageKeyUnit mStorageUnit = null;
+ private ITransportKeyUnit mTransportUnit = null;
+
+ private final static String
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_4";
+
+ private final static String
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED_4";
+ private ILogger mSignedAuditLogger = CMS.getSignedAuditLogger();
+
+ /**
+ * Constructs request processor.
+ */
+ public TokenKeyRecoveryService(IKeyRecoveryAuthority kra) {
+ mKRA = kra;
+ mStorage = mKRA.getKeyRepository();
+ mStorageUnit = mKRA.getStorageKeyUnit();
+ mTransportUnit = kra.getTransportKeyUnit();
+ }
+
+ /**
+ * Process the HTTP request.
+ *
+ * @param s The URL to decode
+ */
+ protected String URLdecode(String s) {
+ if (s == null)
+ return null;
+ ByteArrayOutputStream out = new ByteArrayOutputStream(s.length());
+
+ for (int i = 0; i < s.length(); i++) {
+ int c = (int) s.charAt(i);
+
+ if (c == '+') {
+ out.write(' ');
+ } else if (c == '%') {
+ int c1 = Character.digit(s.charAt(++i), 16);
+ int c2 = Character.digit(s.charAt(++i), 16);
+
+ out.write((char) (c1 * 16 + c2));
+ } else {
+ out.write(c);
+ }
+ } // end for
+ return out.toString();
+ }
+
+ public static String normalizeCertStr(String s) {
+ String val = "";
+
+ for (int i = 0; i < s.length(); i++) {
+ if (s.charAt(i) == '\\') {
+ i++;
+ continue;
+ } else if (s.charAt(i) == '\\') {
+ i++;
+ continue;
+ } else if (s.charAt(i) == '"') {
+ continue;
+ } else if (s.charAt(i) == ' ') {
+ continue;
+ }
+ val += s.charAt(i);
+ }
+ return val;
+ }
+
+ private static String base64Encode(byte[] bytes) throws IOException {
+ // All this streaming is lame, but Base64OutputStream needs a
+ // PrintStream
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ Base64OutputStream b64 = new Base64OutputStream(new
+ PrintStream(new
+ FilterOutputStream(output)
+ )
+ );
+
+ b64.write(bytes);
+ b64.flush();
+
+ // This is internationally safe because Base64 chars are
+ // contained within 8859_1
+ return output.toString("8859_1");
+ }
+
+ // this encrypts bytes with a symmetric key
+ public byte[] encryptIt(byte[] toBeEncrypted, SymmetricKey symKey, CryptoToken token,
+ IVParameterSpec IV)
+ {
+ try {
+ Cipher cipher = token.getCipherContext(
+ EncryptionAlgorithm.DES3_CBC_PAD);
+
+ cipher.initEncrypt(symKey, IV);
+ byte pri[] = cipher.doFinal(toBeEncrypted);
+ return pri;
+ } catch (Exception e) {
+ CMS.debug("initEncrypt() threw exception: "+e.toString());
+ return null;
+ }
+
+ }
+
+
+ /**
+ * Processes a recovery request. The method reads
+ * the key record from the database, and tries to recover the
+ * key with the storage key unit. Once recovered, it wraps it
+ * with desKey
+ * In the params
+ * - cert is used for recovery record search
+ * - cuid may be used for additional validation check
+ * - userid may be used for additional validation check
+ * - wrappedDesKey is used for wrapping recovered private key
+ *
+ * @param request recovery request
+ * @return operation success or not
+ * @exception EBaseException failed to serve
+ */
+ public boolean serviceRequest(IRequest request) throws EBaseException {
+ String auditMessage = null;
+ String auditSubjectID = null;
+ String auditRequesterID = "TPSagent";
+ String auditRecoveryID = ILogger.UNIDENTIFIED;
+ String auditPublicKey = ILogger.UNIDENTIFIED;
+ String iv_s ="";
+
+ CMS.debug("KRA services token key recovery request");
+
+ byte[] wrapped_des_key;
+
+ byte iv[] = {0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1};
+ try {
+ SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
+ random.nextBytes(iv);
+ } catch (Exception e) {
+ CMS.debug("TokenKeyRecoveryService.serviceRequest: "+ e.toString());
+ }
+
+ String id = request.getRequestId().toString();
+ if (id != null) {
+ auditRecoveryID = id.trim();
+ }
+ SessionContext sContext = SessionContext.getContext();
+ String agentId="";
+ if (sContext != null) {
+ agentId =
+ (String) sContext.get(SessionContext.USER_ID);
+ }
+
+ Hashtable params = mKRA.getVolatileRequest(
+ request.getRequestId());
+
+
+ if (params == null) {
+ // possibly we are in recovery mode
+ CMS.debug("getVolatileRequest params null");
+ // return true;
+ }
+
+ wrapped_des_key = null;
+
+ PK11SymKey sk= null;
+
+ String rCUID = request.getExtDataInString(IRequest.NETKEY_ATTR_CUID);
+ String rUserid = request.getExtDataInString(IRequest.NETKEY_ATTR_USERID);
+ String rWrappedDesKeyString = request.getExtDataInString(IRequest.NETKEY_ATTR_DRMTRANS_DES_KEY);
+ auditSubjectID=rCUID+":"+rUserid;
+
+ CMS.debug("TokenKeyRecoveryService: received DRM-trans-wrapped des key ="+rWrappedDesKeyString);
+ wrapped_des_key = com.netscape.cmsutil.util.Utils.SpecialDecode(rWrappedDesKeyString);
+ CMS.debug("TokenKeyRecoveryService: wrapped_des_key specialDecoded");
+
+ if ((wrapped_des_key != null) &&
+ (wrapped_des_key.length > 0)) {
+
+ // unwrap the des key
+ sk = (PK11SymKey) mTransportUnit.unwrap_encrypt_sym(wrapped_des_key);
+
+ if (sk == null) {
+ CMS.debug("TokenKeyRecoveryService: no des key");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ } else {
+ CMS.debug("TokenKeyRecoveryService: received des key");
+ }
+ } else {
+ CMS.debug("TokenKeyRecoveryService: not receive des key");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ }
+
+ // retrieve based on Certificate
+ String cert_s = request.getExtDataInString(ATTR_USER_CERT);
+ if (cert_s == null) {
+ CMS.debug("TokenKeyRecoveryService: not receive cert");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(3));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ }
+
+ String cert = normalizeCertStr(cert_s);
+ java.security.cert.X509Certificate x509cert = null;
+ try {
+ x509cert= (java.security.cert.X509Certificate) Cert.mapCert(cert);
+ if (x509cert == null) {
+ CMS.debug("cert mapping failed");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(5));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ }
+ } catch (IOException e) {
+ CMS.debug("TokenKeyRecoveryService: mapCert failed");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(6));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ }
+
+ try {
+ /*
+ CryptoToken internalToken =
+ CryptoManager.getInstance().getInternalKeyStorageToken();
+ */
+ CryptoToken token = mStorageUnit.getToken();
+ CMS.debug("TokenKeyRecoveryService: got token slot:"+token.getName());
+ IVParameterSpec algParam = new IVParameterSpec(iv);
+
+ Cipher cipher = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
+
+ KeyRecord keyRecord = null;
+ CMS.debug( "KRA reading key record");
+ try {
+ keyRecord = (KeyRecord) mStorage.readKeyRecord(cert);
+ if (keyRecord != null)
+ CMS.debug("read key record");
+ else {
+ CMS.debug("key record not found");
+ request.setExtData(IRequest.RESULT, Integer.valueOf(8));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ }
+ }catch (Exception e) {
+ com.netscape.cmscore.util.Debug.printStackTrace(e);
+ request.setExtData(IRequest.RESULT, Integer.valueOf(9));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ }
+
+ // see if the owner name matches (cuid:userid) -XXX need make this optional
+ String owner = keyRecord.getOwnerName();
+ CMS.debug("TokenKeyRecoveryService: owner name on record =" +owner);
+ CMS.debug("TokenKeyRecoveryService: owner name from TPS =" +rCUID+":"+rUserid);
+ if (owner != null) {
+ if (owner.equals(rCUID+":"+rUserid)) {
+ CMS.debug("TokenKeyRecoveryService: owner name matches");
+ } else {
+ CMS.debug("TokenKeyRecoveryService: owner name mismatches");
+ }
+ }
+
+ // see if the certificate matches the key
+ byte pubData[] = keyRecord.getPublicKeyData();
+ byte inputPubData[] = x509cert.getPublicKey().getEncoded();
+
+ if (inputPubData.length != pubData.length) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_PUBLIC_KEY_LEN"));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_PUBLIC_KEY_NOT_MATCHED"));
+ }
+
+ for (int i = 0; i < pubData.length; i++) {
+ if (pubData[i] != inputPubData[i]) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_PUBLIC_KEY_LEN"));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_PUBLIC_KEY_NOT_MATCHED"));
+ }
+ }
+
+ // Unwrap the archived private key
+ byte privateKeyData[] = null;
+ privateKeyData = recoverKey(params, keyRecord);
+ if (privateKeyData == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ CMS.debug("TokenKeyRecoveryService: failed getting private key");
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ }
+ CMS.debug("TokenKeyRecoveryService: got private key...about to verify");
+
+ iv_s = /*base64Encode(iv);*/com.netscape.cmsutil.util.Utils.SpecialEncode(iv);
+ request.setExtData("iv_s", iv_s);
+
+ CMS.debug("request.setExtData: iv_s: " + iv_s);
+
+ /* LunaSA returns data with padding which we need to remove */
+ ByteArrayInputStream dis = new ByteArrayInputStream(privateKeyData);
+ DerValue dv = new DerValue(dis);
+ byte p[] = dv.toByteArray();
+ int l = p.length;
+ CMS.debug("length different data length=" + l +
+ " real length=" + privateKeyData.length );
+ if (l != privateKeyData.length) {
+ privateKeyData = p;
+ }
+
+ if (verifyKeyPair(pubData, privateKeyData) == false) {
+ mKRA.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSCORE_KRA_PUBLIC_NOT_FOUND"));
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ throw new EKRAException(
+ CMS.getUserMessage("CMS_KRA_INVALID_PUBLIC_KEY"));
+ } else {
+ CMS.debug("TokenKeyRecoveryService: private key verified with public key");
+ }
+
+ //encrypt and put in private key
+ cipher.initEncrypt(sk, algParam);
+ byte wrapped[] = cipher.doFinal(privateKeyData);
+
+ String wrappedPrivKeyString =
+ com.netscape.cmsutil.util.Utils.SpecialEncode(wrapped);
+ if (wrappedPrivKeyString == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ CMS.debug("TokenKeyRecoveryService: failed generating wrapped private key");
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ } else {
+ CMS.debug("TokenKeyRecoveryService: got private key data wrapped");
+ request.setExtData("wrappedUserPrivate",
+ wrappedPrivKeyString);
+ request.setExtData(IRequest.RESULT, Integer.valueOf(1));
+ CMS.debug( "TokenKeyRecoveryService: key for " +rCUID+":"+rUserid +" recovered");
+ }
+
+ //convert and put in the public key
+ String b64PKey = base64Encode(pubData);
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRecoveryID,
+ b64PKey);
+
+ audit(auditMessage);
+
+ if (b64PKey == null) {
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ CMS.debug("TokenKeyRecoveryService: failed getting publickey encoded");
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+ return false;
+ } else {
+ CMS.debug("TokenKeyRecoveryService: got publicKeyData b64 = "+
+ b64PKey);
+ }
+ request.setExtData("public_key", b64PKey);
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRecoveryID,
+ agentId);
+
+ audit(auditMessage);
+
+ return true;
+
+ } catch (Exception e) {
+ CMS.debug("TokenKeyRecoveryService: " + e.toString());
+ request.setExtData(IRequest.RESULT, Integer.valueOf(4));
+ }
+
+ return true;
+ }
+
+ public boolean verifyKeyPair(byte publicKeyData[], byte privateKeyData[])
+ {
+ try {
+ DerValue publicKeyVal = new DerValue(publicKeyData);
+ DerInputStream publicKeyIn = publicKeyVal.data;
+ publicKeyIn.getSequence(0);
+ DerValue publicKeyDer = new DerValue(publicKeyIn.getBitString());
+ DerInputStream publicKeyDerIn = publicKeyDer.data;
+ BigInt publicKeyModulus = publicKeyDerIn.getInteger();
+ BigInt publicKeyExponent = publicKeyDerIn.getInteger();
+
+ DerValue privateKeyVal = new DerValue(privateKeyData);
+ if (privateKeyVal.tag != DerValue.tag_Sequence)
+ return false;
+ DerInputStream privateKeyIn = privateKeyVal.data;
+ privateKeyIn.getInteger();
+ privateKeyIn.getSequence(0);
+ DerValue privateKeyDer = new DerValue(privateKeyIn.getOctetString());
+ DerInputStream privateKeyDerIn = privateKeyDer.data;
+ BigInt privateKeyVersion = privateKeyDerIn.getInteger();
+ BigInt privateKeyModulus = privateKeyDerIn.getInteger();
+ BigInt privateKeyExponent = privateKeyDerIn.getInteger();
+
+ if (!publicKeyModulus.equals(privateKeyModulus)) {
+ CMS.debug("verifyKeyPair modulus mismatch publicKeyModulus=" + publicKeyModulus + " privateKeyModulus=" + privateKeyModulus);
+ return false;
+ }
+
+ if (!publicKeyExponent.equals(privateKeyExponent)) {
+ CMS.debug("verifyKeyPair exponent mismatch publicKeyExponent=" + publicKeyExponent + " privateKeyExponent=" + privateKeyExponent);
+ return false;
+ }
+
+ return true;
+ } catch (Exception e) {
+ CMS.debug("verifyKeyPair error " + e);
+ return false;
+ }
+ }
+
+ /**
+ * Recovers key.
+ */
+ public synchronized byte[] recoverKey(Hashtable request, KeyRecord keyRecord)
+ throws EBaseException {
+ /*
+ Credential creds[] = (Credential[])
+ request.get(ATTR_AGENT_CREDENTIALS);
+
+ mStorageUnit.login(creds);
+ */
+ CMS.debug( "KRA decrypts internal private");
+ byte privateKeyData[] =
+ mStorageUnit.decryptInternalPrivate(
+ keyRecord.getPrivateKeyData());
+ /*
+ mStorageUnit.logout();
+ */
+ if (privateKeyData == null) {
+ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_PRIVATE_KEY_NOT_FOUND"));
+ throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1", "no private key"));
+ }
+ return privateKeyData;
+ }
+ /**
+ * Signed Audit Log
+ *y
+ * This method is called to store messages to the signed audit log.
+ * <P>
+ *
+ * @param msg signed audit log message
+ */
+ private void audit(String msg) {
+ // in this case, do NOT strip preceding/trailing whitespace
+ // from passed-in String parameters
+
+ if (mSignedAuditLogger == null) {
+ return;
+ }
+
+ mSignedAuditLogger.log(ILogger.EV_SIGNED_AUDIT,
+ null,
+ ILogger.S_SIGNED_AUDIT,
+ ILogger.LL_SECURITY,
+ msg);
+ }
+
+}
diff --git a/pki/base/kra/src/com/netscape/kra/TransportKeyUnit.java b/pki/base/kra/src/com/netscape/kra/TransportKeyUnit.java
new file mode 100644
index 000000000..385940c95
--- /dev/null
+++ b/pki/base/kra/src/com/netscape/kra/TransportKeyUnit.java
@@ -0,0 +1,203 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import org.mozilla.jss.crypto.Signature;
+
+import java.util.*;
+import com.netscape.certsrv.security.*;
+import java.io.*;
+import java.net.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.cert.X509Certificate;
+import com.netscape.cmscore.cert.*;
+import netscape.security.x509.*;
+//import netscape.security.provider.*;
+import netscape.security.util.*;
+import com.netscape.cmscore.util.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.kra.*;
+import com.netscape.certsrv.apps.CMS;
+import org.mozilla.jss.util.*;
+import org.mozilla.jss.crypto.*;
+import org.mozilla.jss.*;
+import org.mozilla.jss.crypto.PrivateKey;
+import com.netscape.cmsutil.util.Cert;
+
+
+/**
+ * A class represents the transport key pair. This key pair
+ * is used to protected EE's private key in transit.
+ *
+ * @author thomask
+ * @version $Revision$, $Date$
+ */
+public class TransportKeyUnit extends EncryptionUnit implements
+ ISubsystem, ITransportKeyUnit {
+
+ public static final String PROP_NICKNAME = "nickName";
+ public static final String PROP_SIGNING_ALGORITHM = "signingAlgorithm";
+
+ // private RSAPublicKey mPublicKey = null;
+ // private RSAPrivateKey mPrivateKey = null;
+ private IConfigStore mConfig = null;
+ private org.mozilla.jss.crypto.X509Certificate mCert = null;
+ private CryptoManager mManager = null;
+
+ /**
+ * Constructs this token.
+ */
+ public TransportKeyUnit() {
+ super();
+ }
+
+ /**
+ * Retrieves subsystem identifier.
+ */
+ public String getId() {
+ return "transportKeyUnit";
+ }
+
+ /**
+ * Sets subsystem identifier.
+ */
+ public void setId(String id) throws EBaseException {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_OPERATION"));
+ }
+
+ /**
+ * Initializes this subsystem.
+ */
+ public void init(ISubsystem owner, IConfigStore config)
+ throws EBaseException {
+ mConfig = config;
+ try {
+ mManager = CryptoManager.getInstance();
+ mCert = mManager.findCertByNickname(getNickName());
+ String algo = config.getString("signingAlgorithm", "SHA256withRSA");
+
+ // #613795 - initialize this; otherwise JSS is not happy
+ CryptoToken token = getToken();
+ SignatureAlgorithm sigalg = Cert.mapAlgorithmToJss(algo);
+ Signature signer = token.getSignatureContext(sigalg);
+ signer.initSign(getPrivateKey());
+
+
+ } catch (org.mozilla.jss.CryptoManager.NotInitializedException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+
+ } catch (TokenException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+ } catch (ObjectNotFoundException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+ } catch (Exception e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+ }
+ }
+
+ public CryptoToken getInternalToken() {
+ try {
+ return CryptoManager.getInstance().getInternalKeyStorageToken();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public CryptoToken getToken() {
+ // 390148: returning the token that owns the private
+ // key.
+ return getPrivateKey().getOwningToken();
+ }
+
+ /**
+ * Starts up this subsystem.
+ */
+ public void startup() throws EBaseException {
+ }
+
+ /**
+ * Shutdowns this subsystem.
+ */
+ public void shutdown() {
+ }
+
+ /**
+ * Returns the configuration store of this token.
+ */
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ public String getNickName() throws EBaseException {
+ return mConfig.getString(PROP_NICKNAME);
+ }
+
+ public void setNickName(String str) throws EBaseException {
+ mConfig.putString(PROP_NICKNAME, str);
+ }
+
+ public String getSigningAlgorithm() throws EBaseException {
+ return mConfig.getString(PROP_SIGNING_ALGORITHM);
+ }
+
+ public void setSigningAlgorithm(String str) throws EBaseException {
+ mConfig.putString(PROP_SIGNING_ALGORITHM, str);
+ }
+
+ /**
+ * Logins to this token.
+ */
+ public void login(String pin) throws EBaseException {
+ }
+
+ /**
+ * Logout from this token.
+ */
+ public void logout() {
+ }
+
+ /**
+ * Retrieves public key.
+ */
+ public org.mozilla.jss.crypto.X509Certificate getCertificate() {
+ return mCert;
+ }
+
+ public PublicKey getPublicKey() {
+ return mCert.getPublicKey();
+ }
+
+ public PrivateKey getPrivateKey() {
+ try {
+ return mManager.findPrivKeyByCert(mCert);
+ } catch (TokenException e) {
+ return null;
+ } catch (ObjectNotFoundException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Verifies the integrity of the given key pair.
+ */
+ public void verify(byte publicKey[], PrivateKey privateKey)
+ throws EBaseException {
+ // XXX
+ }
+}