From a4682ceae6774956461edd03b2485bbacea445f4 Mon Sep 17 00:00:00 2001 From: mharmsen Date: Tue, 4 Oct 2011 01:17:41 +0000 Subject: Bugzilla Bug #688225 - (dogtagIPAv2.1) TRACKER: of the Dogtag fixes for freeIPA 2.1 git-svn-id: svn+ssh://svn.fedorahosted.org/svn/pki/tags/IPA_v2_RHEL_6_2_20111003@2252 c9f7a03b-bd48-0410-a16d-cbbf54688b0b --- .../src/com/netscape/kra/KeyRecoveryAuthority.java | 1778 ++++++++++++++++++++ 1 file changed, 1778 insertions(+) create mode 100644 pki/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java (limited to 'pki/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java') 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. + *

+ * + * @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. + *

+ */ + 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. + *

+ * + * @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. + *

+ * + * @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. + *

+ * + *

+ * @param rec key record to be archived + * @return executed request + * @exception EBaseException failed to archive key + * @return the request + *

+ */ + 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. + *

+ * + *

+ * @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. + *

+ * + *

+ * @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. + *

+ * + * @return request repository + */ + public IRequestQueue getRequestQueue() { + return mRequestQueue; + } + + /** + * Retrieves the key repository. The key repository + * stores archived keys. + *

+ */ + public IKeyRepository getKeyRepository() { + return mKeyDB; + } + + /** + * Retrieves replica repository. + *

+ * + * @return replica repository + */ + public IReplicaIDRepository getReplicaRepository() { + return mReplicaRepot; + } + + + /** + * Retrieves the DN of this escrow authority. + *

+ * + * @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. + *

+ * + * @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. + *

+ * + * @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. + *

+ * + * @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. + *

+ * + * @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. + *

+ * + * @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. + *

+ * + * @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. + *

+ * + * @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; + } +} + -- cgit