summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcfu <cfu@c9f7a03b-bd48-0410-a16d-cbbf54688b0b>2010-03-22 21:58:54 +0000
committercfu <cfu@c9f7a03b-bd48-0410-a16d-cbbf54688b0b>2010-03-22 21:58:54 +0000
commit154f27d2fc07bb7f3b70ea72483952fc442b310a (patch)
tree03f8cd9b793d1fa136a14545b7ccd48acccf45ee
parentc089ef29c921947d1828b1932b5543789b4aa135 (diff)
downloadpki-154f27d2fc07bb7f3b70ea72483952fc442b310a.tar.gz
pki-154f27d2fc07bb7f3b70ea72483952fc442b310a.tar.xz
pki-154f27d2fc07bb7f3b70ea72483952fc442b310a.zip
Bugzilla Bug #522343 Add asynchronous key recovery mode
git-svn-id: svn+ssh://svn.fedorahosted.org/svn/pki/trunk@1027 c9f7a03b-bd48-0410-a16d-cbbf54688b0b
-rw-r--r--pki/base/common/src/LogMessages_en.properties17
-rw-r--r--pki/base/common/src/UserMessages_en.properties1
-rw-r--r--pki/base/common/src/com/netscape/certsrv/kra/IKeyService.java63
-rw-r--r--pki/base/common/src/com/netscape/cms/servlet/key/GetAsyncPk12.java241
-rw-r--r--pki/base/common/src/com/netscape/cms/servlet/key/GrantAsyncRecovery.java288
-rw-r--r--pki/base/common/src/com/netscape/cms/servlet/key/RecoverBySerial.java108
-rw-r--r--pki/base/common/src/com/netscape/cms/servlet/request/KeyReqParser.java4
-rw-r--r--pki/base/common/src/com/netscape/cms/servlet/request/QueryReq.java3
-rw-r--r--pki/base/kra/shared/webapps/kra/WEB-INF/web.xml46
-rw-r--r--pki/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java256
-rw-r--r--pki/base/kra/src/com/netscape/kra/RecoveryService.java3
-rw-r--r--pki/dogtag/common/pki-common.spec5
-rw-r--r--pki/dogtag/kra-ui/dogtag-pki-kra-ui.spec7
-rw-r--r--pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/ListRequests.html1
-rw-r--r--pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/displayBySerialForRecovery.template33
-rw-r--r--pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/finishAsyncRecovery.template101
-rw-r--r--pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/grantAsyncRecovery.template45
-rw-r--r--pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/processReq.template110
-rw-r--r--pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/recoverBySerial.template20
-rw-r--r--pki/dogtag/kra/pki-kra.spec7
20 files changed, 1303 insertions, 56 deletions
diff --git a/pki/base/common/src/LogMessages_en.properties b/pki/base/common/src/LogMessages_en.properties
index 17cfe998e..60fe43cd8 100644
--- a/pki/base/common/src/LogMessages_en.properties
+++ b/pki/base/common/src/LogMessages_en.properties
@@ -1241,6 +1241,7 @@ CMSGW_ERROR_MARKING_CERT_REVOKED=Error encountered while marking certificate rev
CMSGW_ERROR_MARKING_CERT_REVOKED_1=Error encountered while marking certificate revoked . {0}
CMSGW_NO_RECOVERY_TOKEN_FOUND_1=No Recovery Token Found for recovery reference number {0}.
CMSGW_INVALID_AGENT_3=Agent: {0} cannot retrieve PKCS #12 for recovery reference number {2}. Agent: {1} initialized the request.
+CMSGW_INVALID_AGENT_ASYNC_3=Agent: {0} cannot retrieve PKCS #12 for recovery request id {2}. Agent: {1} initialized the request.
CMSGW_ERROR_DISPLAY_FILE=I/O Error encountered while outputting file.
CMSGW_FILE_NOT_FOUND=File was not found
CMSGW_NO_CERTS_FROM_CA=Error encountered while issuing certificates.
@@ -1972,6 +1973,14 @@ LOGGING_SIGNED_AUDIT_SERVER_SIDE_KEYGEN_PROCESSED_3=<type=SERVER_SIDE_KEYGEN_PRO
#
LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_4=<type=KEY_RECOVERY_REQUEST>:[AuditEvent=KEY_RECOVERY_REQUEST][SubjectID={0}][Outcome={1}][RecoveryID={2}][PubKey={3}] key recovery request made
#
+# LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_ASYNC
+# - used when asynchronous key recovery request is made
+# RequestID must be the recovery request ID
+# PubKey must be the base-64 encoded public key associated with
+# the private key to be recovered
+#
+LOGGING_SIGNED_AUDIT_KEY_RECOVERY_REQUEST_ASYNC_4=<type=KEY_RECOVERY_REQUEST>:[AuditEvent=KEY_RECOVERY_REQUEST][SubjectID={0}][Outcome={1}][RequestID={2}][PubKey={3}] asynchronous key recovery request made
+#
# LOGGING_SIGNED_AUDIT_KEY_RECOVERY_AGENT_LOGIN
# - used when DRM agents login as recovery agents to approve
# key recovery requests
@@ -1989,6 +1998,14 @@ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_AGENT_LOGIN_4=<type=KEY_RECOVERY_AGENT_LOGIN>:
#
LOGGING_SIGNED_AUDIT_KEY_RECOVERY_PROCESSED_4=<type=KEY_RECOVERY_PROCESSED>:[AuditEvent=KEY_RECOVERY_PROCESSED][SubjectID={0}][Outcome={1}][RecoveryID={2}][RecoveryAgents={3}] key recovery request processed
#
+# LOGGING_SIGNED_AUDIT_KEY_RECOVERY_PROCESSED_ASYNC
+# - used when key recovery request is processed
+# RequestID must be the recovery request ID
+# RecoveryAgents must be a comma-separated list of
+# UIDs of the recovery agents approving this request
+#
+LOGGING_SIGNED_AUDIT_KEY_RECOVERY_PROCESSED_ASYNC_4=<type=KEY_RECOVERY_PROCESSED>:[AuditEvent=KEY_RECOVERY_PROCESSED][SubjectID={0}][Outcome={1}][ReQUESTID={2}][RecoveryAgents={3}] asynchronous key recovery request processed
+#
# LOGGING_SIGNED_AUDIT_KEY_GEN_ASYMMETRIC
# - used when asymmetric keys are generated
# (like when CA certificate requests are generated -
diff --git a/pki/base/common/src/UserMessages_en.properties b/pki/base/common/src/UserMessages_en.properties
index df5cfce41..6f272471b 100644
--- a/pki/base/common/src/UserMessages_en.properties
+++ b/pki/base/common/src/UserMessages_en.properties
@@ -235,6 +235,7 @@ CMS_GW_DECODE_CRL_FAILED=Failed to DER decode the Certificate Revocation List.
CMS_GW_CERT_SERIAL_NOT_FOUND=Certificate Serial Number {0} not found
CMS_GW_NO_RECOVERY_TOKEN_FOUND=No Recovery Token Found for recovery reference number {0}.
CMS_GW_INVALID_AGENT=Agent: {0} cannot retrieve PKCS #12 for recovery reference number {2}. Agent: {1} initialized the request.
+CMS_GW_INVALID_AGENT_ASYNC=Agent: {0} cannot retrieve PKCS #12 for recovery request id {2}. Agent: {1} initialized the request.
CMS_GW_REDIRECTING_ADMINENROLL_ERROR=Error encountered while accessing the adminEnroll page.{0}
CMS_GW_NO_PUB_MODULE=Publishing module is disabled.
CMS_GW_CONVERT_DN_TO_X500NAME_ERROR=Cannot convert the subject name from a String to an X500 Name form. \nCheck to make sure valid characters are in the subject name. \nFor example, the email address should only have IA5String characters\nand the country should only have PrintableString characters and have 2 characters exactly.
diff --git a/pki/base/common/src/com/netscape/certsrv/kra/IKeyService.java b/pki/base/common/src/com/netscape/certsrv/kra/IKeyService.java
index e90a992df..5c2da2d08 100644
--- a/pki/base/common/src/com/netscape/certsrv/kra/IKeyService.java
+++ b/pki/base/common/src/com/netscape/certsrv/kra/IKeyService.java
@@ -43,6 +43,43 @@ public interface IKeyService {
*/
public int getNoOfRequiredAgents() throws EBaseException;
+ /**
+ * is async recovery request status APPROVED -
+ * i.e. all required # of recovery agents approved
+ * @param reqID request id
+ * @return true if # of recovery required agents approved; false otherwise
+ */
+ public boolean isApprovedAsyncKeyRecovery(String reqID)
+ throws EBaseException;
+
+ /**
+ * get async recovery request initiating agent
+ * @param reqID request id
+ * @return agentUID
+ */
+ public String getInitAgentAsyncKeyRecovery(String reqID)
+ throws EBaseException;
+
+ /**
+ * Initiate asynchronous key recovery
+ * @param kid key identifier
+ * @param cert certificate embedded in PKCS12
+ * @return requestId
+ * @exception EBaseException failed to initiate async recovery
+ */
+ public String initAsyncKeyRecovery(BigInteger kid, X509CertImpl cert, String agent)
+ throws EBaseException;
+
+ /**
+ * add approving agent in asynchronous key recovery
+ * @param reqID request id
+ * @param agentID agent id
+ * @return requestId
+ * @exception EBaseException failed to initiate async recovery
+ */
+ public void addAgentAsyncKeyRecovery(String reqID, String agentID)
+ throws EBaseException;
+
/**
* Performs administrator-initiated key recovery.
*
@@ -56,7 +93,31 @@ public interface IKeyService {
*/
public byte[] doKeyRecovery(BigInteger kid,
Credential creds[], String pwd, X509CertImpl cert,
- String delivery, String nickname) throws EBaseException;
+ String delivery, String nickname, String agent) throws EBaseException;
+
+ /**
+ * 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_PROCESSED used whenever
+ * a user private key recovery request is processed (this is when the DRM
+ * processes the request)
+ * </ul>
+ * @param reqID 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;
/**
* Retrieves recovery identifier.
diff --git a/pki/base/common/src/com/netscape/cms/servlet/key/GetAsyncPk12.java b/pki/base/common/src/com/netscape/cms/servlet/key/GetAsyncPk12.java
new file mode 100644
index 000000000..eb510bf59
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/servlet/key/GetAsyncPk12.java
@@ -0,0 +1,241 @@
+// --- 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.cms.servlet.key;
+
+
+import com.netscape.cms.servlet.common.*;
+import com.netscape.cms.servlet.base.*;
+
+import java.io.*;
+import java.util.*;
+import java.net.*;
+import java.util.*;
+import java.text.*;
+import java.math.*;
+import java.security.*;
+import java.security.cert.X509Certificate;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import netscape.security.x509.*;
+import com.netscape.certsrv.common.*;
+import com.netscape.certsrv.authority.*;
+import com.netscape.certsrv.base.*;
+
+import com.netscape.certsrv.dbs.*;
+import com.netscape.certsrv.dbs.keydb.*;
+
+import com.netscape.cms.servlet.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.kra.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.authorization.*;
+
+
+/**
+ * Get the recovered key in PKCS#12 format
+ * - for asynchronous key recovery only
+ *
+ */
+public class GetAsyncPk12 extends CMSServlet {
+
+ private final static String INFO = "getAsyncPk12";
+
+ private final static String TPL_FILE = "finishAsyncRecovery.template";
+
+ private final static String IN_PASSWORD = "p12Password";
+ private final static String IN_PASSWORD_AGAIN = "p12PasswordAgain";
+ private final static String OUT_RECOVERY_SUCCESS = "recoverySuccess";
+ private final static String OUT_ERROR = "errorDetails";
+
+ private com.netscape.certsrv.kra.IKeyService mService = null;
+ private final static String OUT_STATUS = "status";
+
+ private String mFormPath = null;
+
+ /**
+ * Constructs getAsyncPk12 servlet.
+ */
+ public GetAsyncPk12() {
+ super();
+ }
+
+ /**
+ * initialize the servlet. This servlet uses the template file
+ * "finishAsyncRecovery.template" to process the response.
+ *
+ * @param sc servlet configuration, read from the web.xml file
+ */
+ public void init(ServletConfig sc) throws ServletException {
+ super.init(sc);
+ mFormPath = "/agent/" + mAuthority.getId() + "/" + TPL_FILE;
+ mService = (com.netscape.certsrv.kra.IKeyService) mAuthority;
+
+ mTemplates.remove(CMSRequest.SUCCESS);
+ if (mOutputTemplatePath != null)
+ mFormPath = mOutputTemplatePath;
+ }
+
+ /**
+ * Returns serlvet information.
+ */
+ public String getServletInfo() {
+ return INFO;
+ }
+
+ /**
+ * Process the HTTP request.
+ * <ul>
+ * <li>http.param reqID request id for recovery
+ * </ul>
+ *
+ * @param cmsReq the object holding the request and response information
+ */
+ public void process(CMSRequest cmsReq) throws EBaseException {
+
+ HttpServletRequest req = cmsReq.getHttpReq();
+ HttpServletResponse resp = cmsReq.getHttpResp();
+
+ IAuthToken authToken = authenticate(cmsReq);
+
+ AuthzToken authzToken = null;
+
+ try {
+ authzToken = authorize(mAclMethod, authToken,
+ mAuthzResourceName, "download");
+ } catch (EAuthzAccessDenied e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString()));
+ } catch (Exception e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString()));
+ }
+
+ if (authzToken == null) {
+ cmsReq.setStatus(CMSRequest.UNAUTHORIZED);
+ return;
+ }
+
+ CMSTemplate form = null;
+ Locale[] locale = new Locale[1];
+
+ try {
+ form = getTemplate(mFormPath, req, locale);
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", mFormPath, e.toString()));
+ throw new ECMSGWException(
+ CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"));
+ }
+
+ cmsReq.setStatus(CMSRequest.SUCCESS);
+ IArgBlock header = CMS.createArgBlock();
+ IArgBlock fixed = CMS.createArgBlock();
+ CMSTemplateParams argSet = new CMSTemplateParams(header, fixed);
+ int seq = -1;
+
+ // get status and populate argSet
+ try {
+ String reqID = req.getParameter("reqID");
+ header.addStringValue("reqID", reqID);
+
+ // only the init DRM agent can get the pkcs12
+ SessionContext sContext = SessionContext.getContext();
+ String agent = null;
+
+ if (sContext != null) {
+ agent = (String) sContext.get(SessionContext.USER_ID);
+ }
+
+ if (agent == null ) {
+ CMS.debug( "GetAsyncPk12::process() - agent is null!" );
+ throw new EBaseException( "agent is null" );
+ }
+
+ String initAgent = "undefined";
+ initAgent = mService.getInitAgentAsyncKeyRecovery(reqID);
+
+ if ((initAgent.equals("undefined")) || !agent.equals(initAgent)) {
+ log(ILogger.LL_SECURITY,
+ CMS.getLogMessage("CMSGW_INVALID_AGENT_ASYNC_3",
+ reqID, initAgent));
+ throw new ECMSGWException(
+ CMS.getUserMessage("CMS_GW_INVALID_AGENT_ASYNC",
+ reqID, initAgent));
+ }
+
+ // The async recovery request must be in "approved" state
+ // i.e. all required # of recovery agents approved
+ if (mService.isApprovedAsyncKeyRecovery(reqID) != true) {
+ CMS.debug("GetAsyncPk12::process() - # required recovery agents not met");
+ throw new EBaseException( "# required recovery agents not met" );
+ }
+
+ String password = req.getParameter(IN_PASSWORD);
+ String passwordAgain = req.getParameter(IN_PASSWORD_AGAIN);
+
+ if (password == null || password.equals("")) {
+ header.addStringValue(OUT_ERROR, "PKCS12 password not found");
+ throw new EBaseException( "PKCS12 password not found" );
+ }
+ if (passwordAgain == null || !passwordAgain.equals(password)) {
+ header.addStringValue(OUT_ERROR, "PKCS12 password not matched");
+ throw new EBaseException( "PKCS12 password not matched" );
+ }
+
+ // got all approval, return pk12
+ byte pkcs12[] = mService.doKeyRecovery(reqID, password);
+
+ if (pkcs12 != null) {
+ try {
+ resp.setContentType("application/x-pkcs12");
+ resp.getOutputStream().write(pkcs12);
+ mRenderResult = false;
+ return;
+ } catch (IOException e) {
+ header.addStringValue(OUT_ERROR,
+ CMS.getUserMessage(locale[0], "CMS_BASE_INTERNAL_ERROR", e.toString()));
+ }
+ } else if (((IKeyRecoveryAuthority) mService).getError(reqID) != null) {
+ // error in recovery process
+ header.addStringValue(OUT_ERROR,
+ ((IKeyRecoveryAuthority) mService).getError(reqID));
+ } else {
+ // pk12 hasn't been created yet. Shouldn't get here
+ }
+ } catch (EBaseException e) {
+ header.addStringValue(OUT_ERROR, e.toString(locale[0]));
+ }
+
+ try {
+ ServletOutputStream out = resp.getOutputStream();
+
+ resp.setContentType("text/html");
+ form.renderOutput(out, argSet);
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSGW_ERR_STREAM_TEMPLATE", e.toString()));
+ throw new ECMSGWException(
+ CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"));
+ }
+
+ cmsReq.setStatus(CMSRequest.SUCCESS);
+ }
+}
diff --git a/pki/base/common/src/com/netscape/cms/servlet/key/GrantAsyncRecovery.java b/pki/base/common/src/com/netscape/cms/servlet/key/GrantAsyncRecovery.java
new file mode 100644
index 000000000..dbb5356cc
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/servlet/key/GrantAsyncRecovery.java
@@ -0,0 +1,288 @@
+// --- 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) 2010 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.servlet.key;
+
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.cms.servlet.common.*;
+import com.netscape.cms.servlet.base.*;
+
+import java.io.*;
+import java.util.*;
+import java.net.*;
+import java.util.*;
+import java.text.*;
+import java.math.*;
+import java.security.*;
+import java.security.cert.X509Certificate;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import netscape.security.x509.*;
+import com.netscape.certsrv.common.*;
+import com.netscape.certsrv.authority.*;
+import com.netscape.certsrv.base.*;
+
+import com.netscape.certsrv.dbs.*;
+import com.netscape.certsrv.dbs.keydb.*;
+
+import com.netscape.cms.servlet.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.kra.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.authorization.*;
+
+
+/**
+ * Approve an asynchronous key recovery request
+ *
+ */
+public class GrantAsyncRecovery extends CMSServlet {
+
+ private final static String INFO = "grantAsyncRecovery";
+ private final static String TPL_FILE = "grantAsyncRecovery.template";
+
+ private final static String IN_SERIALNO = "serialNumber";
+ private final static String IN_REQ_ID = "reqID";
+ private final static String IN_UID = "uid";
+ private final static String IN_CERT = "cert";
+
+ private final static String OUT_OP = "op";
+ private final static String OUT_SERIALNO = IN_SERIALNO;
+ private final static String OUT_RECOVERY_SUCCESS = "recoverySuccess";
+ private final static String OUT_SERVICE_URL = "serviceURL";
+ private final static String OUT_ERROR = "errorDetails";
+
+ private IKeyService mService = null;
+ private String mFormPath = null;
+
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_AGENT_LOGIN =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_AGENT_LOGIN_4";
+
+ /**
+ * Constructs EA servlet.
+ */
+ public GrantAsyncRecovery() {
+ super();
+ }
+
+ /**
+ * initialize the servlet. This servlet uses the template file
+ * 'grantAsyncRecovery.template' to process the response.
+ *
+ * @param sc servlet configuration, read from the web.xml file
+ */
+ public void init(ServletConfig sc) throws ServletException {
+ super.init(sc);
+ mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE;
+ mService = (IKeyService) mAuthority;
+
+ mTemplates.remove(CMSRequest.SUCCESS);
+
+ if (mOutputTemplatePath != null)
+ mFormPath = mOutputTemplatePath;
+ }
+
+ /**
+ * Returns serlvet information.
+ */
+ public String getServletInfo() {
+ return INFO;
+ }
+
+ /**
+ * Process the HTTP request.
+ * <ul>
+ * <li>http.param reqID request ID of the request to approve
+ * <li>http.param agentID User ID of the agent approving the request
+
+ * </ul>
+ *
+ * @param cmsReq the object holding the request and response information
+ */
+ public void process(CMSRequest cmsReq) throws EBaseException {
+
+ HttpServletRequest req = cmsReq.getHttpReq();
+ HttpServletResponse resp = cmsReq.getHttpResp();
+
+ CMS.debug("GrantAsyncRecovery: process() begins");
+
+ IAuthToken authToken = authenticate(cmsReq);
+
+ AuthzToken authzToken = null;
+
+ try {
+ authzToken = authorize(mAclMethod, authToken,
+ mAuthzResourceName, "recover");
+ } catch (EAuthzAccessDenied e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString()));
+ } catch (Exception e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString()));
+ }
+
+ if (authzToken == null) {
+ cmsReq.setStatus(CMSRequest.UNAUTHORIZED);
+ return;
+ }
+
+ CMSTemplate form = null;
+ Locale[] locale = new Locale[1];
+
+ try {
+ form = getTemplate(mFormPath, req, locale);
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", mFormPath, e.toString()));
+ throw new ECMSGWException(
+ CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"));
+ }
+
+ IArgBlock header = CMS.createArgBlock();
+ IArgBlock fixed = CMS.createArgBlock();
+ CMSTemplateParams argSet = new CMSTemplateParams(header, fixed);
+
+ int seq = -1;
+
+ String agentID = authToken.getInString("uid");
+ CMS.debug("GrantAsyncRecovery: process() agent uid=" + agentID);
+ CMS.debug("GrantAsyncRecovery: process() request id=" + req.getParameter("reqID"));
+ try {
+ process(argSet, header,
+ req.getParameter("reqID"),
+ agentID,
+ req, resp, locale[0]);
+ } catch (NumberFormatException e) {
+ header.addStringValue(OUT_ERROR,
+ CMS.getUserMessage(locale[0], "CMS_BASE_INTERNAL_ERROR", e.toString()));
+ }
+ try {
+ ServletOutputStream out = resp.getOutputStream();
+
+ resp.setContentType("text/html");
+ form.renderOutput(out, argSet);
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSGW_ERR_STREAM_TEMPLATE", e.toString()));
+ throw new ECMSGWException(
+ CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"));
+ }
+ cmsReq.setStatus(CMSRequest.SUCCESS);
+ }
+
+ /**
+ * Update agent approval list
+ * <P>
+ *
+ * <ul>
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_KEY_RECOVERY_AGENT_LOGIN used
+ * whenever DRM agents login as recovery agents to approve key recovery
+ * requests
+ * </ul>
+ * @param argSet CMS template parameters
+ * @param header argument block
+ * @param reqID string containing the recovery request ID
+ * @param agentID string containing the agent ID
+ * @param req HTTP servlet request
+ * @param resp HTTP servlet response
+ * @param locale the system locale
+ */
+ private void process(CMSTemplateParams argSet,
+ IArgBlock header, String reqID,
+ String agentID,
+ HttpServletRequest req, HttpServletResponse resp,
+ Locale locale) {
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+ String auditRequestID = reqID;
+ String auditAgentID = agentID;
+
+ // "normalize" the "reqID"
+ if (auditRequestID != null) {
+ auditRequestID = auditRequestID.trim();
+
+ if (auditRequestID.equals("")) {
+ auditRequestID = ILogger.UNIDENTIFIED;
+ }
+ } else {
+ auditRequestID = ILogger.UNIDENTIFIED;
+ }
+
+ // "normalize" the "auditAgentID"
+ if (auditAgentID != null) {
+ auditAgentID = auditAgentID.trim();
+
+ if (auditAgentID.equals("")) {
+ auditAgentID = ILogger.UNIDENTIFIED;
+ }
+ } else {
+ auditAgentID = ILogger.UNIDENTIFIED;
+ }
+
+ try {
+ header.addStringValue(OUT_OP,
+ req.getParameter(OUT_OP));
+ header.addStringValue(OUT_SERVICE_URL,
+ req.getRequestURI());
+
+ // update approving agent list
+ mService.addAgentAsyncKeyRecovery(reqID, agentID);
+
+ header.addStringValue("requestID", reqID);
+ header.addStringValue("agentID", agentID);
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_AGENT_LOGIN,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRequestID,
+ auditAgentID);
+
+ audit(auditMessage);
+
+ } catch (EBaseException e) {
+ header.addStringValue(OUT_ERROR, e.toString(locale));
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_AGENT_LOGIN,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequestID,
+ auditAgentID);
+
+ audit(auditMessage);
+ } catch (Exception e) {
+ header.addStringValue(OUT_ERROR, e.toString());
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_KEY_RECOVERY_AGENT_LOGIN,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequestID,
+ auditAgentID);
+
+ audit(auditMessage);
+ }
+ }
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/servlet/key/RecoverBySerial.java b/pki/base/common/src/com/netscape/cms/servlet/key/RecoverBySerial.java
index e88abccbe..7882b815f 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/key/RecoverBySerial.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/key/RecoverBySerial.java
@@ -176,14 +176,33 @@ public class RecoverBySerial extends CMSServlet {
try {
String localAgents = req.getParameter("localAgents");
+ String initAsyncRecovery = req.getParameter("initAsyncRecovery");
// this information is needed within the server for
// various signed audit log messages to report
ctx = SessionContext.getContext();
- ctx.put(SessionContext.RECOVERY_ID,
- req.getParameter("recoveryID"));
- byte pkcs12[] = process(form, argSet, header,
+ /*
+ When Recovery is first initiated, if it is in asynch mode,
+ no pkcs#12 password is needed.
+ The initiating agent uid will be recorded in the recovery
+ request.
+ Later, as approving agents submit their approvals, they will
+ also be listed in the request.
+ */
+ if ((initAsyncRecovery != null) &&
+ initAsyncRecovery.equalsIgnoreCase("ON")) {
+ process(form, argSet, header,
+ req.getParameter(IN_SERIALNO),
+ req.getParameter(IN_CERT),
+ req, resp, locale[0]);
+
+ int requiredNumber = mService.getNoOfRequiredAgents();
+ header.addIntegerValue("noOfRequiredAgents", requiredNumber);
+ } else {
+ ctx.put(SessionContext.RECOVERY_ID,
+ req.getParameter("recoveryID"));
+ byte pkcs12[] = process(form, argSet, header,
req.getParameter(IN_SERIALNO),
req.getParameter("localAgents"),
req.getParameter(IN_PASSWORD),
@@ -193,13 +212,14 @@ public class RecoverBySerial extends CMSServlet {
req.getParameter(IN_NICKNAME),
req, resp, locale[0]);
- if (pkcs12 != null) {
+ if (pkcs12 != null) {
//resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("application/x-pkcs12");
//resp.setContentLength(pkcs12.length);
resp.getOutputStream().write(pkcs12);
mRenderResult = false;
return;
+ }
}
} catch (NumberFormatException e) {
header.addStringValue(OUT_ERROR,
@@ -228,6 +248,61 @@ public class RecoverBySerial extends CMSServlet {
}
/**
+ * Async Key Recovery - request initiation
+ */
+ private void process(CMSTemplate form, CMSTemplateParams argSet,
+ IArgBlock header, String seq, String cert,
+ HttpServletRequest req, HttpServletResponse resp,
+ Locale locale) {
+
+ // seq is the key id
+ if (seq == null) {
+ header.addStringValue(OUT_ERROR, "sequence number not found");
+ return;
+ }
+ X509CertImpl x509cert = null;
+
+ if (cert == null) {
+ header.addStringValue(OUT_ERROR, "certificate not found");
+ return;
+ } else {
+ try {
+ x509cert = Cert.mapCert(cert);
+ } catch (IOException e) {
+ header.addStringValue(OUT_ERROR, e.toString());
+ }
+ }
+ if (x509cert == null) {
+ header.addStringValue(OUT_ERROR, "invalid X.509 certificate");
+ return;
+ }
+
+ SessionContext sContext = SessionContext.getContext();
+
+ try {
+ String reqID = mService.initAsyncKeyRecovery(
+ new BigInteger(seq), x509cert,
+ (String) sContext.get(SessionContext.USER_ID));
+ header.addStringValue(OUT_SERIALNO, req.getParameter(IN_SERIALNO));
+ header.addStringValue("requestID", reqID);
+ } catch (EBaseException e) {
+ String error =
+ "Failed to recover key for key id " +
+ seq + ".\nException: " + e.toString();
+
+ CMS.getLogger().log(ILogger.EV_SYSTEM,
+ ILogger.S_KRA, ILogger.LL_FAILURE, error);
+ try {
+ ((IKeyRecoveryAuthority) mService).createError(seq, error);
+ } catch (EBaseException eb) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM,
+ ILogger.S_KRA, ILogger.LL_FAILURE, eb.toString());
+ }
+ }
+ return;
+ }
+
+ /**
* Recovers a key. The p12 will be protected by the password
* provided by the administrator.
*/
@@ -269,6 +344,12 @@ public class RecoverBySerial extends CMSServlet {
try {
Credential creds[] = null;
+ SessionContext sContext = SessionContext.getContext();
+ String agent = null;
+
+ if (sContext != null) {
+ agent = (String) sContext.get(SessionContext.USER_ID);
+ }
if (CMS.getConfigStore().getBoolean("kra.keySplitting")) {
if (localAgents == null) {
String recoveryID = req.getParameter("recoveryID");
@@ -283,12 +364,6 @@ public class RecoverBySerial extends CMSServlet {
header.addStringValue("recoveryID", recoveryID);
- SessionContext sContext = SessionContext.getContext();
- String agent = null;
-
- if (sContext != null) {
- agent = (String) sContext.get(SessionContext.USER_ID);
- }
params.put("agent", agent);
// new thread to wait for pk12
@@ -330,7 +405,7 @@ public class RecoverBySerial extends CMSServlet {
byte pkcs12[] = mService.doKeyRecovery(
new BigInteger(seq),
creds, password, x509cert,
- delivery, nickname);
+ delivery, nickname, agent);
return pkcs12;
} else {
@@ -346,12 +421,6 @@ public class RecoverBySerial extends CMSServlet {
header.addStringValue("recoveryID", recoveryID);
- SessionContext sContext = SessionContext.getContext();
- String agent = null;
-
- if (sContext != null) {
- agent = (String) sContext.get(SessionContext.USER_ID);
- }
params.put("agent", agent);
// new thread to wait for pk12
@@ -423,11 +492,14 @@ public class RecoverBySerial extends CMSServlet {
return;
}
+ SessionContext sContext = SessionContext.getContext();
+
try {
byte pkcs12[] = mService.doKeyRecovery(
new BigInteger(theSeq),
creds, thePassword, theCert,
- theDelivery, theNickname);
+ theDelivery, theNickname,
+ (String) sContext.get(SessionContext.USER_ID));
((IKeyRecoveryAuthority) mService).createPk12(theRecoveryID, pkcs12);
} catch (EBaseException e) {
diff --git a/pki/base/common/src/com/netscape/cms/servlet/request/KeyReqParser.java b/pki/base/common/src/com/netscape/cms/servlet/request/KeyReqParser.java
index 4c633cd0c..08a99b9fb 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/request/KeyReqParser.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/request/KeyReqParser.java
@@ -71,6 +71,10 @@ public class KeyReqParser extends ReqParser {
BigInteger kid = req.getExtDataInBigInteger("serialNumber");
arg.addStringValue(OUTPUT_SERIALNO, kid.toString());
+
+ // for async recovery
+ String agents = (String) req.getExtDataInString("approvingAgents");
+ arg.addStringValue("approvingAgents", agents);
} else {
System.out.println("Bad Request " + type);
// invalid request
diff --git a/pki/base/common/src/com/netscape/cms/servlet/request/QueryReq.java b/pki/base/common/src/com/netscape/cms/servlet/request/QueryReq.java
index 98f624160..664c4e838 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/request/QueryReq.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/request/QueryReq.java
@@ -51,6 +51,7 @@ public class QueryReq extends CMSServlet {
private final static String IN_SHOW_ALL = "showAll";
private final static String IN_SHOW_WAITING = "showWaiting";
private final static String IN_SHOW_IN_SERVICE = "showInService";
+ private final static String IN_SHOW_PENDING= "showPending";
private final static String IN_SHOW_CANCELLED = "showCancelled";
private final static String IN_SHOW_REJECTED = "showRejected";
private final static String IN_SHOW_COMPLETED = "showCompleted";
@@ -184,6 +185,8 @@ public class QueryReq extends CMSServlet {
filter = "(requeststate=pending)";
} else if (p.equals(IN_SHOW_IN_SERVICE)) {
filter = "(requeststate=svc_pending)";
+ } else if (p.equals(IN_SHOW_PENDING)) {
+ filter = "(requeststate=pending)";
} else if (p.equals(IN_SHOW_CANCELLED)) {
filter = "(requeststate=canceled)";
} else if (p.equals(IN_SHOW_REJECTED)) {
diff --git a/pki/base/kra/shared/webapps/kra/WEB-INF/web.xml b/pki/base/kra/shared/webapps/kra/WEB-INF/web.xml
index 8af3e56e8..8d7baae02 100644
--- a/pki/base/kra/shared/webapps/kra/WEB-INF/web.xml
+++ b/pki/base/kra/shared/webapps/kra/WEB-INF/web.xml
@@ -249,6 +249,25 @@
</servlet>
<servlet>
+ <servlet-name> kraKRAGrantAsyncRecovery </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.key.GrantAsyncRecovery </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> templatePath </param-name>
+ <param-value> /agent/kra/grantAsyncRecovery.template</param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraKRAGrantAsyncRecovery </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.key </param-value> </init-param>
+ </servlet>
+
+ <servlet>
<servlet-name> kraports </servlet-name>
<servlet-class> com.netscape.cms.servlet.base.PortsServlet </servlet-class>
<init-param><param-name> ID </param-name>
@@ -605,6 +624,23 @@
</servlet>
<servlet>
+ <servlet-name> kraKRAGetAsyncPk12 </servlet-name>
+ <servlet-class> com.netscape.cms.servlet.key.GetAsyncPk12 </servlet-class>
+ <init-param><param-name> GetClientCert </param-name>
+ <param-value> true </param-value> </init-param>
+ <init-param><param-name> AuthzMgr </param-name>
+ <param-value> BasicAclAuthz </param-value> </init-param>
+ <init-param><param-name> authority </param-name>
+ <param-value> kra </param-value> </init-param>
+ <init-param><param-name> ID </param-name>
+ <param-value> kraKRAGetAsyncPk12 </param-value> </init-param>
+ <init-param><param-name> AuthMgr </param-name>
+ <param-value> certUserDBAuthMgr </param-value> </init-param>
+ <init-param><param-name> resourceID </param-name>
+ <param-value> certServer.kra.key </param-value> </init-param>
+ </servlet>
+
+ <servlet>
<servlet-name> kraGrantRecovery </servlet-name>
<servlet-class> com.netscape.cms.servlet.base.DisplayHtmlServlet </servlet-class>
<init-param><param-name> GetClientCert </param-name>
@@ -945,6 +981,11 @@
</servlet-mapping>
<servlet-mapping>
+ <servlet-name> kraKRAGrantAsyncRecovery </servlet-name>
+ <url-pattern> /agent/kra/grantAsyncRecovery </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
<servlet-name> kraports </servlet-name>
<url-pattern> /ee/kra/ports </url-pattern>
</servlet-mapping>
@@ -1035,6 +1076,11 @@
</servlet-mapping>
<servlet-mapping>
+ <servlet-name> kraKRAGetAsyncPk12 </servlet-name>
+ <url-pattern> /agent/kra/getAsyncPk12 </url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
<servlet-name> kraGrantRecovery </servlet-name>
<url-pattern> /agent/kra/grantRecovery.html </url-pattern>
</servlet-mapping>
diff --git a/pki/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java b/pki/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java
index c55a949c0..ce2a03b20 100644
--- a/pki/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java
+++ b/pki/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java
@@ -124,8 +124,12 @@ public class KeyRecoveryAuthority implements IAuthority, IKeyService, IKeyRecove
"LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_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_PROCESSED =
"LOGGING_SIGNED_AUDIT_KEY_RECOVERY_PROCESSED_4";
+ private final static String LOGGING_SIGNED_AUDIT_KEY_RECOVERY_PROCESSED_ASYNC =
+ "LOGGING_SIGNED_AUDIT_KEY_RECOVERY_PROCESSED_ASYNC_4";
/**
* Constructs an escrow authority.
@@ -622,6 +626,7 @@ public class KeyRecoveryAuthority implements IAuthority, IKeyService, IKeyRecove
synchronized (lock) {
while (dc.size() < getNoOfRequiredAgents()) {
+ CMS.debug("KeyRecoveryAuthority: cfu in synchronized lock for getDistributedCredentials");
try {
lock.wait();
} catch (InterruptedException e) {
@@ -783,6 +788,154 @@ public class KeyRecoveryAuthority implements IAuthority, IKeyService, IKeyRecove
}
/**
+ * 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>
@@ -808,7 +961,8 @@ public class KeyRecoveryAuthority implements IAuthority, IKeyService, IKeyRecove
public byte[] doKeyRecovery(BigInteger kid,
Credential creds[], String password,
X509CertImpl cert,
- String delivery, String nickname)
+ String delivery, String nickname,
+ String agent)
throws EBaseException {
String auditMessage = null;
String auditSubjectID = auditSubjectID();
@@ -820,7 +974,7 @@ public class KeyRecoveryAuthority implements IAuthority, IKeyService, IKeyRecove
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 {
@@ -843,6 +997,8 @@ public class KeyRecoveryAuthority implements IAuthority, IKeyService, IKeyRecove
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(
@@ -919,6 +1075,102 @@ public class KeyRecoveryAuthority implements IAuthority, IKeyService, IKeyRecove
}
}
+ /**
+ * 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_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_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_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_PROCESSED_ASYNC,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRecoveryID,
+ auditAgents);
+
+ audit(auditMessage);
+ throw eAudit1;
+ }
+ }
+
/**
* Constructs a recovery request and submits it
* to the request subsystem for processing.
diff --git a/pki/base/kra/src/com/netscape/kra/RecoveryService.java b/pki/base/kra/src/com/netscape/kra/RecoveryService.java
index 39253ab68..94915640d 100644
--- a/pki/base/kra/src/com/netscape/kra/RecoveryService.java
+++ b/pki/base/kra/src/com/netscape/kra/RecoveryService.java
@@ -85,6 +85,9 @@ public class RecoveryService implements IService {
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;
diff --git a/pki/dogtag/common/pki-common.spec b/pki/dogtag/common/pki-common.spec
index 6fcf1b90a..24ff6f966 100644
--- a/pki/dogtag/common/pki-common.spec
+++ b/pki/dogtag/common/pki-common.spec
@@ -1,5 +1,5 @@
Name: pki-common
-Version: 1.3.3
+Version: 1.3.4
Release: 1%{?dist}
Summary: Dogtag Certificate System - PKI Common Framework
URL: http://pki.fedoraproject.org/
@@ -108,6 +108,9 @@ rm -rf %{buildroot}
%{_javadocdir}/%{name}-%{version}/
%changelog
+* Mon Mar 22 2010 Christina Fu <cfu@redhat.com> 1.3.4-1
+- Bugzilla Bug #522343 Add asynchronous key recovery mode
+
* Tue Mar 9 2010 Ade Lee <alee@redhat.com> 1.3.3-1
- Bugzilla Bug #545935 - Add new client-auth ee port to address CVE-2009-3555
TLS: MITM attacks via session renegotiation
diff --git a/pki/dogtag/kra-ui/dogtag-pki-kra-ui.spec b/pki/dogtag/kra-ui/dogtag-pki-kra-ui.spec
index b368b352c..afbfc8094 100644
--- a/pki/dogtag/kra-ui/dogtag-pki-kra-ui.spec
+++ b/pki/dogtag/kra-ui/dogtag-pki-kra-ui.spec
@@ -1,6 +1,6 @@
Name: dogtag-pki-kra-ui
-Version: 1.3.0
-Release: 4%{?dist}
+Version: 1.3.1
+Release: 1%{?dist}
Summary: Dogtag Certificate System - Data Recovery Authority User Interface
URL: http://pki.fedoraproject.org/
License: GPLv2
@@ -50,6 +50,9 @@ rm -rf %{buildroot}
%{_datadir}/pki/
%changelog
+* Mon Mar 22 2010 Christina Fu <cfu@redhat.com> 1.3.1-1
+- Bugzilla Bug #522343 Add asynchronous key recovery mode
+
* Thu Jan 14 2010 Matthew Harmsen <mharmsen@redhat.com> 1.3.0-4
- Bugzilla Bug #553742 - New Package for Dogtag PKI: dogtag-pki-kra-ui
- Removed "Requires: bash"
diff --git a/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/ListRequests.html b/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/ListRequests.html
index be4508589..3ce974179 100644
--- a/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/ListRequests.html
+++ b/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/ListRequests.html
@@ -59,6 +59,7 @@ Use this form to show a list of key service requests.</font>
<td valign="top">
<SELECT NAME="reqState">
<OPTION SELECTED VALUE="showCompleted">Show completed requests</OPTION>
+ <OPTION VALUE="showPending">Show pending requests</OPTION>
<OPTION VALUE="showCancelled">Show canceled requests</OPTION>
<OPTION VALUE="showRejected">Show rejected requests</OPTION>
<OPTION VALUE="showAll">Show all requests</OPTION>
diff --git a/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/displayBySerialForRecovery.template b/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/displayBySerialForRecovery.template
index 386c62dfb..6ece7dfbc 100644
--- a/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/displayBySerialForRecovery.template
+++ b/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/displayBySerialForRecovery.template
@@ -7,7 +7,21 @@
<title>Display Key</title>
<body bgcolor="white">
-<SCRIPT LANGUAGE="JavaScript"></SCRIPT>
+<SCRIPT LANGUAGE="JavaScript">
+
+function PKCS12Password()
+{
+ if (document.forms[0].initAsyncRecovery.checked) {
+ document.forms[0].p12Password.disabled= true;
+ document.forms[0].p12PasswordAgain.disabled= true;
+ document.forms[0].nickname.disabled= true;
+ } else {
+ document.forms[0].p12Password.disabled= false;
+ document.forms[0].p12PasswordAgain.disabled= false;
+ document.forms[0].nickname.disabled= false;
+ }
+}
+</SCRIPT>
<script language="JavaScript" src="../funcs.js"></script>
<script language="JavaScript" src="../helpfun.js"></script>
<script language="JavaScript">
@@ -135,21 +149,29 @@ if (result.header.errorDetails != null) {
document.writeln('</tr>');
document.writeln('<tr>');
+ document.write('<td align=right><font size="-1" face="PrimaSans BT, Verdana, sans-serif">Async Recovery:</font></td>');
+ // initiate an asynchronous recovery or not
+ document.writeln('<td>');
+ document.write('<input type="checkbox" CHECKED onClick="PKCS12Password()" name="initAsyncRecovery" value="ON">');
+ document.writeln('</td>');
+ document.writeln('</tr>');
+
+ document.writeln('<tr>');
document.writeln('</tr>');
document.writeln('<tr>');
document.write('<td align=right><font size="-1" face="PrimaSans BT, Verdana, sans-serif">PKCS #12 Password:</font></td>');
- document.write('<td align=left><font size="-1" face="PrimaSans BT, Verdana, sans-serif"><input type=password name="p12Password" value="" AutoComplete=off ></font></td>');
+ document.write('<td align=left><font size="-1" face="PrimaSans BT, Verdana, sans-serif"><input type=password disabled name="p12Password" value="" AutoComplete=off ></font></td>');
document.writeln('</tr>');
document.writeln('<tr>');
document.write('<td align=right><font size="-1" face="PrimaSans BT, Verdana, sans-serif">PKCS #12 Password again:</font></td>');
- document.write('<td align=left><font size="-1" face="PrimaSans BT, Verdana, sans-serif"><input type=password name="p12PasswordAgain" value="" AutoComplete=off ></font></td>');
+ document.write('<td align=left><font size="-1" face="PrimaSans BT, Verdana, sans-serif"><input type=password disabled name="p12PasswordAgain" value="" AutoComplete=off ></font></td>');
document.writeln('</tr>');
document.writeln('<tr>');
document.write('<td align=right><font size="-1" face="PrimaSans BT, Verdana, sans-serif">Nickname (Optional):</font></td>');
- document.write('<td align=left><font size="-1" face="PrimaSans BT, Verdana, sans-serif"><input type=text name="nickname" value=""></font></td>');
+ document.write('<td align=left><font size="-1" face="PrimaSans BT, Verdana, sans-serif"><input type=text disabled name="nickname" value=""></font></td>');
document.writeln('</tr>');
// certificate
@@ -178,12 +200,13 @@ if (result.header.errorDetails != null) {
document.writeln('</tr>');
// recovery ID
+/* recoery ID does not apply to async case
document.writeln('<tr>');
document.write('<td align=right><font size="-1" face="PrimaSans BT, Verdana, sans-serif">Recovery authorization reference number:</font></td>');
document.write('<td align=left><font size="-1" face="PrimaSans BT, Verdana, sans-serif">' + result.header.recoveryID + '</font></td>');
document.writeln('</tr>');
-
document.writeln('<input type=hidden name="op" value="recoverBySerial">');
+*/
if (result.header.keySplitting == 'true') {
document.write(renderCredentialBoxes(result.header.noOfRequiredAgents));
diff --git a/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/finishAsyncRecovery.template b/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/finishAsyncRecovery.template
new file mode 100644
index 000000000..0d2caf676
--- /dev/null
+++ b/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/finishAsyncRecovery.template
@@ -0,0 +1,101 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Key Recovery Result</title>
+</head>
+<body bgcolor="white">
+<CMS_TEMPLATE>
+
+<SCRIPT LANGUAGE="JavaScript"></SCRIPT>
+<script language="JavaScript" src="../funcs.js"></script>
+<script language="JavaScript" src="../helpfun.js"></script>
+<script language="JavaScript">
+//<!--
+function displayApprovalRecord(agentNumber, agentName)
+{
+ document.writeln("Agent" + agentNumber + " (" + agentName +
+ ") has approved the request.");
+}
+function toHex(number)
+{
+ var absValue = "", sign = "";
+ var digits = "0123456789abcdef";
+ if (number < 0) {
+ sign = "-";
+ number = -number;
+ }
+
+ for(; number >= 16 ; number = Math.floor(number/16)) {
+ absValue = digits.charAt(number % 16) + absValue;
+ }
+ absValue = digits.charAt(number % 16) + absValue;
+ return sign + absValue;
+}
+
+function renderHexNumber(number,width)
+{
+ var num = toHex(number);
+ while (num.length < width)
+ num = "0"+num;
+ return "0x"+num;
+}
+
+if (result.header.errorDetails != null) {
+ writeError(result.header.errorDetails);
+} else {
+ document.write('<font face="PrimaSans BT, Verdana, sans-serif" size=+1>Key Recovery Status</font>');
+ document.write('<center><hr width="100%"></center>');
+
+
+ document.writeln('<table border="0" cellspacing="2" cellpadding="2" width="100%">');
+ document.write('<td><font size="-1" face="PrimaSans BT, Verdana, sans-serif">Recovery Authorization Reference Number:</font> <font size="-1" face="PrimaSans BT, Verdana, sans-serif">' + result.header.recoveryID + '</font></td>');
+ document.writeln('</tr>');
+
+ document.writeln('<tr>');
+ document.write('<td><font size="-1" face="PrimaSans BT, Verdana, sans-serif">Key Identifier:</font> <font size="-1" face="PrimaSans BT, Verdana, sans-serif">' + renderHexNumber(result.header.serialNumber,8) + '</font></td>');
+ document.writeln('</tr>');
+ document.write('</table>');
+
+ document.write("<pre>");
+ document.write('<font face="PrimaSans BT, Verdana, sans-serif">');
+ document.writeln('The request has been submitted.');
+ document.writeln(result.header.noOfRequiredAgents +
+ ' recovery agents are required for authorization.' );
+ document.writeln('<p>');
+ for(var i = 0; i < result.recordSet.length; ++i ) {
+ displayApprovalRecord(i+1, result.recordSet[i].agentName);
+ }
+ if (result.recordSet.length < result.header.noOfRequiredAgents) {
+ document.writeln('Waiting for the remaining approvals ...');
+ } else if (result.header.status != "complete") {
+ document.writeln('<p>');
+ document.writeln('The key is being recovered ...');
+ }
+ document.write('</font>');
+ document.write("</pre>");
+
+ document.write('<font size="-1" face="PrimaSans BT, Verdana, sans-serif">');
+ if (result.header.status == "complete") {
+ document.writeln("<p>");
+ document.writeln("The request is completed.");
+ document.writeln("<p>");
+
+ document.writeln(
+ 'If the key is not saved, you will need to go through the ' +
+ 'recovery process again. ' +
+ 'Click ' +
+ '<a href="/kra/agent/kra/getAsyncPk12?reqID=' +
+ result.header.requestID + '"' +
+ 'onMouseOver=" return helpstatus(\'Click to get key in PKCS12 ' +
+ '\')" onMouseOut="return helpstatus(\'\')">' +
+ "here" +
+ '</a>' + ' to save the recovered key in PKCS12 format.'
+);
+ }
+ document.write('</font>');
+}
+
+//-->
+</script>
+</BODY>
+</HTML>
diff --git a/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/grantAsyncRecovery.template b/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/grantAsyncRecovery.template
new file mode 100644
index 000000000..c76e61ac4
--- /dev/null
+++ b/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/grantAsyncRecovery.template
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<CMS_TEMPLATE>
+<head><title>Key Recovery Grant Result</title></head>
+<body bgcolor="white">
+
+<SCRIPT LANGUAGE="JavaScript"></SCRIPT>
+<script language="JavaScript" src="../funcs.js"></script>
+<script language="JavaScript" src="../helpfun.js"></script>
+<script language="JavaScript">
+//<!--
+function toHex(number)
+{
+ var absValue = "", sign = "";
+ var digits = "0123456789abcdef";
+ if (number < 0) {
+ sign = "-";
+ number = -number;
+ }
+
+ for(; number >= 16 ; number = Math.floor(number/16)) {
+ absValue = digits.charAt(number % 16) + absValue;
+ }
+ absValue = digits.charAt(number % 16) + absValue;
+ return sign + absValue;
+}
+
+if (result.header.errorDetails != null) {
+ writeError(result.header.errorDetails);
+} else {
+ document.write('<font face="PrimaSans BT, Verdana, sans-serif" size=+1>Key Recovery Result</font>');
+ document.write('<center><hr width="100%"></center>');
+ document.write("<p>");
+ document.write('<font face="PrimaSans BT, Verdana, sans-serif" size=-1>');
+ document.write('Asynchronous Key recovery request' +
+'<a href="/kra/agent/kra/processReq?op=processReq&seqNum=' +
+ result.header.requestID+'"> ' + result.header.requestID + '</a>' +
+ ' has been granted by ' + result.header.agentID);
+ document.write('</font>');
+}
+
+//-->
+</script>
+</BODY>
+</HTML>
diff --git a/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/processReq.template b/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/processReq.template
index 3442f8145..25cb142ab 100644
--- a/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/processReq.template
+++ b/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/processReq.template
@@ -43,6 +43,16 @@ function renderDateFromSecs(secs)
return dateStr;
}
+function passwdValidate()
+{
+
+ if (document.forms[0].p12Password.value != document.forms[0].p12PasswordAgain.value) {
+ alert("Passwords do not match");
+ return false;
+ }
+ return true;
+}
+
//
// This form is a template that gets a preamble defining the contents
// of the request form as a JavaScript object called 'result.header'.
@@ -61,7 +71,7 @@ document.writeln(
document.writeln('<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH="100%" BACKGROUND="/graphics/hr.gif"><TR><TD></TD></TR></TABLE>');
-document.writeln('<form action="/agent/kra/processReq" method=POST>');
+document.writeln('<form action="/kra/agent/kra/getAsyncPk12" method=post onSubmit="return passwdValidate()">');
document.writeln('<table border="0" cellspacing="2" cellpadding="2" width="100%">');
document.writeln('<tr><td valign="top" align="left" colspan="3" bgcolor="#e5e5e5">');
document.writeln('<font size="-1" face="PrimaSans BT, Verdana, sans-serif">'
@@ -72,26 +82,6 @@ document.write('<td align=right><font size="-1" face="PrimaSans BT, Verdana, san
document.write('<td align=left><font size="-1" face="PrimaSans BT, Verdana, sans-serif">' + result.header.status + '</font></td>');
document.writeln('</tr>');
-if (result.header.status != "complete") {
- if (result.header.assignedTo != null) {
- document.write('<b> Assigned To: </b>',result.header.assignedTo);
- } else {
- document.write('<b> Unassigned </b>');
- }
- if (result.header.assignedTo == null) {
- document.write('<a href="/agent/kra/processReq?op=processReq&doAssign=yes&seqNum=' +
- result.header.seqNum + '"' +
- 'onMouseOver=" return helpstatus(\'Click to assign the ' +
- 'request to yourself\')" ' +
- 'onMouseOut="return helpstatus(\'\')">',
- ' Assign To Me','</a>');
- } else if (result.header.assignedTo != result.header.callerName) {
- document.write('<a href="/' +
- '/agent/kra/processReq?op=processReq&doAssign=yes&overrideAssignment=yes&seqNum=' + result.header.seqNum + '">',
- ' Re-assign To Me', '</a>');
- }
-}
-
// Note these values are filtered for safety by the server.
if (result.header.requestorName != null ||
result.header.requestorEmail != null ||
@@ -201,6 +191,84 @@ if (result.header.requestType == "enrollment") {
document.write('<td align=right><font size="-1" face="PrimaSans BT, Verdana, sans-serif">Key identifier:</font></td>');
document.write('<td align=left><font size="-1" face="PrimaSans BT, Verdana, sans-serif">' + result.header.serialNumber + '</font></td>');
document.writeln('</tr>');
+
+ // Recovery agents who have approved the recovery request
+ var initAgent="";
+ var approveAgents="";
+ if (result.header.approvingAgents.indexOf(",")== -1) {
+ initAgent = result.header.approvingAgents;
+ } else {
+ initAgent = result.header.approvingAgents.substring(0,
+ result.header.approvingAgents.indexOf(","));
+ approveAgents = result.header.approvingAgents.substring(
+ result.header.approvingAgents.indexOf(",")+1);
+ }
+ document.writeln('<tr>');
+ document.write('<td align=right><font size="-1" face="PrimaSans BT, Verdana, sans-serif">Recovery Initiating Agent:</font></td>');
+ document.write('<td align=left><font size="-1" face="PrimaSans BT, Verdana, sans-serif">' + initAgent+ '</font></td>');
+ document.writeln('</tr>');
+ document.writeln('<tr>');
+ document.write('<td align=right><font size="-1" face="PrimaSans BT, Verdana, sans-serif">Recovery Approving Agents:</font></td>');
+ document.write('<td align=left><font size="-1" face="PrimaSans BT, Verdana, sans-serif">' + approveAgents
+ + '</font></td>');
+ document.writeln('</tr>');
+}
+
+
+if (result.header.status != "complete") {
+ document.writeln('<tr><td valign="top" align="left" colspan="3" bgcolor="#e5e5e5">');
+ document.writeln('<font size="-1" face="PrimaSans BT, Verdana, sans-serif">');
+ document.writeln('Action</font></td></tr>');
+ if (result.header.requestType == "recovery") {
+ if (result.header.status == "pending") {
+document.writeln('<tr>');
+document.write('<td align=right><font size="-1" face="PrimaSans BT, Verdana, sans-serif">Asynchronous Key Recovery:</font></td>');
+ document.writeln('<td align=left><font size="-1" face="PrimaSans BT, Verdana, sans-serif"><a href="/kra/agent/kra/grantAsyncRecovery?op=grantRecovery&reqID=' +
+ result.header.seqNum + '">' + ' Grant</a></font></td>');
+document.writeln('</tr>');
+
+ } else if (result.header.status == "approved") {
+ var initAgent = result.header.approvingAgents.substring(0,
+ result.header.approvingAgents.indexOf(","));
+
+ // get PKCS#12 password
+ document.writeln('<tr>');
+ document.write('<td align=right><font size="-1" face="PrimaSans BT, Verdana, sans-serif">PKCS #12 Password:</font></td>');
+ document.write('<td align=left><font size="-1" face="PrimaSans BT, Verdana, sans-serif"><input type=password name="p12Password" value="" AutoComplete=off ></font></td>');
+ document.writeln('</tr>');
+
+ document.writeln('<tr>');
+ document.write('<td align=right><font size="-1" face="PrimaSans BT, Verdana, sans-serif">PKCS #12 Password again:</font></td>');
+ document.write('<td align=left><font size="-1" face="PrimaSans BT, Verdana, sans-serif"><input type=password name="p12PasswordAgain" value="" AutoComplete=off ></font></td>');
+ document.writeln('</tr>');
+
+ document.writeln('<tr>');
+ document.writeln('<input type=hidden name="op" VALUE="getAsyncPk12">');
+ document.writeln('<input type=hidden name="reqID" VALUE="' +
+ result.header.seqNum + '">\n');
+ document.writeln('<td align=right><font size="-1" face="PrimaSans BT, Verdana, sans-serif">(only allowed for initiating agent,' + initAgent+')</font></td>');
+ document.writeln('<td align=left><font size="-1" face="PrimaSans BT, Verdana, sans-serif"><input type=submit value="Retrieve PKCS#12"></font></td>');
+ document.writeln('</tr>');
+ }
+ } else {
+ if (result.header.assignedTo != null) {
+ document.write('<b> Assigned To: </b>',result.header.assignedTo);
+ } else {
+ document.write('<b> Unassigned </b>');
+ }
+ if (result.header.assignedTo == null) {
+ document.write('<a href="/kra/agent/kra/processReq?op=processReq&doAssign=yes&seqNum=' +
+ result.header.seqNum + '"' +
+ 'onMouseOver=" return helpstatus(\'Click to assign the ' +
+ 'request to yourself\')" ' +
+ 'onMouseOut="return helpstatus(\'\')">',
+ ' Assign To Me','</a>');
+ } else if (result.header.assignedTo != result.header.callerName) {
+ document.write('<a href="/' +
+ '/kra/agent/kra/processReq?op=processReq&doAssign=yes&overrideAssignment=yes&seqNum=' + result.header.seqNum + '">',
+ ' Re-assign To Me', '</a>');
+ }
+ }
}
document.writeln('</table>');
diff --git a/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/recoverBySerial.template b/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/recoverBySerial.template
index 7ec7a5a3f..a1209f32b 100644
--- a/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/recoverBySerial.template
+++ b/pki/dogtag/kra-ui/shared/webapps/kra/agent/kra/recoverBySerial.template
@@ -38,13 +38,24 @@ if (result.header.errorDetails != null) {
toHex(result.header.serialNumber) +
' has been submitted.\n' +
'Waiting for recovery agents\' approval...');
- document.write('</font>');
- window.location = result.fixed.scheme + "://" + result.fixed.host +
+ if (result.header.recoveryID == null) {
+ document.writeln('<p>');
+ document.writeln(result.header.noOfRequiredAgents +
+ ' recovery agents are required for authorization.' );
+ document.writeln('<p>');
+
+ document.writeln('This is an asynchronous key recovery request. You might want to notify authorized key recovery agents to grant this request by going to request' +
+ '<a href="/kra/agent/kra/processReq?op=processReq&seqNum=' +
+ result.header.requestID+'"> ' + result.header.requestID +'</a>.')
+ document.write('</font>');
+ }else {
+ document.write('</font>');
+ window.location = result.fixed.scheme + "://" + result.fixed.host +
":" + result.fixed.port + "/kra/agent/kra/getApprovalStatus?recoveryID=" +
result.header.recoveryID;
- if (result.header.status == "complete") {
+ if (result.header.status == "complete") {
document.writeln(
'<font face="PrimaSans BT, Verdana, sans-serif"><font size=+1>'+
'Click ' +
@@ -54,7 +65,8 @@ if (result.header.errorDetails != null) {
'\')" onMouseOut="return helpstatus(\'\')">' +
"here" +
'</a>' + ' to get the recovered key in PKCS12 format.</font></font>');
- }
+ }
+ }
}
diff --git a/pki/dogtag/kra/pki-kra.spec b/pki/dogtag/kra/pki-kra.spec
index 72d9538b0..96dc1cf47 100644
--- a/pki/dogtag/kra/pki-kra.spec
+++ b/pki/dogtag/kra/pki-kra.spec
@@ -1,6 +1,6 @@
Name: pki-kra
-Version: 1.3.1
-Release: 2%{?dist}
+Version: 1.3.2
+Release: 1%{?dist}
Summary: Dogtag Certificate System - Data Recovery Manager
URL: http://pki.fedoraproject.org/
License: GPLv2
@@ -112,6 +112,9 @@ fi
%{_localstatedir}/run/*
%changelog
+* Mon Mar 22 2010 Christina Fu <cfu@redhat.com> 1.3.2-1
+- Bugzilla Bug #522343 Add asynchronous key recovery mode
+
* Tue Feb 16 2010 Matthew Harmsen <mharmsen@redhat.com> 1.3.1-2
- Bugzilla Bug #566059 - Add 'pki-console' as a runtime dependency
for CA, KRA, OCSP, and TKS . . .