summaryrefslogtreecommitdiffstats
path: root/base/tps/src
diff options
context:
space:
mode:
Diffstat (limited to 'base/tps/src')
-rw-r--r--base/tps/src/CMakeLists.txt170
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/TPSPhoneHome.java95
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/TPSServlet.java65
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/TPSSession.java174
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/TPSSubsystem.java231
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/TPSTokenPolicy.java158
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java425
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/authentication/AuthUIParameter.java92
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/authentication/AuthenticationManager.java287
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/authentication/TPSAuthenticator.java148
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java1045
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/CAEnrollCertResponse.java52
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java760
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/CARenewCertResponse.java52
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/CARetrieveCertResponse.java45
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/CARevokeCertResponse.java39
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/ConnectionManager.java229
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/KRARecoverKeyResponse.java51
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/KRARemoteRequestHandler.java322
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/KRAServerSideKeyGenResponse.java51
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/RemoteRequestHandler.java91
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/RemoteResponse.java40
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/TKSComputeRandomDataResponse.java41
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/TKSComputeSessionKeyResponse.java65
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/TKSCreateKeySetDataResponse.java41
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/TKSEncryptDataResponse.java41
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/TKSRemoteRequestHandler.java448
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/cms/TKSResponse.java40
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/config/AuthenticatorDatabase.java143
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/config/AuthenticatorRecord.java28
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/config/ConfigDatabase.java191
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/config/ConfigRecord.java126
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/config/ConfigService.java135
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/config/ConnectorDatabase.java242
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/config/ConnectorRecord.java28
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/config/ProfileDatabase.java144
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/config/ProfileMappingDatabase.java144
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/config/ProfileMappingRecord.java28
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/config/ProfileRecord.java28
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/dbs/ActivityDatabase.java100
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/dbs/ActivityRecord.java214
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/dbs/TPSCertDatabase.java71
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/dbs/TPSCertRecord.java313
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/dbs/TokenDatabase.java68
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/dbs/TokenRecord.java271
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java589
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/installer/CAInfoPanel.java171
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/installer/DRMInfoPanel.java154
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/installer/TKSInfoPanel.java150
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/installer/TPSInstaller.java124
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/main/AttributeSpec.java71
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/main/ObjectSpec.java456
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/main/PKCS11Obj.java689
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/processor/AppletInfo.java115
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/processor/CertEnrollInfo.java270
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/processor/EnrolledCertsInfo.java262
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java2789
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/processor/TPSPinResetProcessor.java66
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java2404
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/profile/BaseTokenProfileResolver.java38
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/profile/MappingTokenProfileResolver.java294
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/profile/TokenProfileParams.java145
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/profile/TokenProfileResolverManager.java114
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/rest/ActivityService.java177
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/rest/AuthenticatorService.java350
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/rest/ConnectorService.java350
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/rest/ProfileMappingService.java341
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/rest/ProfileService.java351
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/rest/TPSApplication.java105
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/rest/TPSCertService.java179
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/rest/TPSInstallerService.java153
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/rest/TokenService.java562
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/selftests/TPSPresence.java187
-rw-r--r--base/tps/src/org/dogtagpki/server/tps/selftests/TPSValidity.java197
-rw-r--r--base/tps/src/pki-tps.mf3
75 files changed, 19428 insertions, 0 deletions
diff --git a/base/tps/src/CMakeLists.txt b/base/tps/src/CMakeLists.txt
new file mode 100644
index 000000000..b36a01526
--- /dev/null
+++ b/base/tps/src/CMakeLists.txt
@@ -0,0 +1,170 @@
+project(pki-tps_java NONE)
+
+find_file(LDAPJDK_JAR
+ NAMES
+ ldapjdk.jar
+ PATHS
+ /usr/share/java
+)
+
+find_file(JSS_JAR
+ NAMES
+ jss4.jar
+ PATHS
+ ${JAVA_LIB_INSTALL_DIR}
+)
+
+find_file(COMMONS_CODEC_JAR
+ NAMES
+ commons-codec.jar
+ PATHS
+ /usr/share/java
+)
+
+find_file(COMMONS_LANG_JAR
+ NAMES
+ commons-lang.jar
+ PATHS
+ /usr/share/java
+)
+
+find_file(JAXRS_API_JAR
+ NAMES
+ jaxrs-api.jar
+ PATHS
+ ${RESTEASY_LIB}
+)
+
+find_file(TOMCAT_CATALINA_JAR
+ NAMES
+ catalina.jar
+ PATHS
+ /usr/share/java/tomcat
+)
+
+find_file(PKI_CERTSRV_JAR
+ NAMES
+ pki-certsrv.jar
+ PATHS
+ /usr/share/java/pki
+)
+
+find_file(PKI_CMS_JAR
+ NAMES
+ pki-cms.jar
+ PATHS
+ /usr/share/java/pki
+)
+
+find_file(PKI_CMSCORE_JAR
+ NAMES
+ pki-cmscore.jar
+ PATHS
+ /usr/share/java/pki
+)
+
+find_file(PKI_CMSUTIL_JAR
+ NAMES
+ pki-cmsutil.jar
+ PATHS
+ /usr/share/java/pki
+)
+
+find_file(PKI_NSUTIL_JAR
+ NAMES
+ pki-nsutil.jar
+ PATHS
+ /usr/share/java/pki
+)
+
+find_file(JAXRS_API_JAR
+ NAMES
+ jaxrs-api.jar
+ PATHS
+ ${RESTEASY_LIB}
+)
+
+find_file(RESTEASY_JAXRS_JAR
+ NAMES
+ resteasy-jaxrs.jar
+ PATHS
+ ${RESTEASY_LIB}
+)
+
+find_file(RESTEASY_ATOM_PROVIDER_JAR
+ NAMES
+ resteasy-atom-provider.jar
+ PATHS
+ ${RESTEASY_LIB}
+)
+
+find_file(SERVLET_JAR
+ NAMES
+ servlet.jar
+ PATHS
+ ${JAVA_LIB_INSTALL_DIR}
+ /usr/share/java
+)
+
+find_file(SYMKEY_JAR
+ NAMES
+ symkey.jar
+ PATHS
+ ${JAVA_LIB_INSTALL_DIR}
+ /usr/share/java
+)
+
+find_file(VELOCITY_JAR
+ NAMES
+ velocity.jar
+ PATHS
+ ${JAVA_LIB_INSTALL_DIR}
+ /usr/share/java
+)
+
+# build pki-tps
+javac(pki-tps-classes
+ SOURCES
+ org/dogtagpki/server/tps/*.java
+ CLASSPATH
+ ${COMMONS_CODEC_JAR} ${COMMONS_LANG_JAR}
+ ${LDAPJDK_JAR}
+ ${JSS_JAR} ${SYMKEY_JAR}
+ ${JAXRS_API_JAR} ${RESTEASY_JAXRS_JAR} ${RESTEASY_ATOM_PROVIDER_JAR}
+ ${SERVLET_JAR} ${TOMCAT_CATALINA_JAR} ${VELOCITY_JAR}
+ ${PKI_CMSUTIL_JAR} ${PKI_NSUTIL_JAR}
+ ${PKI_CERTSRV_JAR} ${PKI_CMS_JAR} ${PKI_CMSCORE_JAR}
+ OUTPUT_DIR
+ ${CMAKE_BINARY_DIR}/classes
+ DEPENDS
+ pki-nsutil-jar pki-cmsutil-jar pki-certsrv-jar pki-cms-jar pki-cmscore-jar
+)
+
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/pki-tps.mf
+ ${CMAKE_CURRENT_BINARY_DIR}/pki-tps.mf
+)
+
+jar(pki-tps-jar
+ CREATE
+ ${CMAKE_BINARY_DIR}/dist/pki-tps.jar
+ OPTIONS
+ m
+ PARAMS
+ ${CMAKE_CURRENT_BINARY_DIR}/pki-tps.mf
+ INPUT_DIR
+ ${CMAKE_BINARY_DIR}/classes
+ FILES
+ org/dogtagpki/server/tps/*.class
+ DEPENDS
+ pki-tps-classes
+)
+
+install(
+ FILES
+ ${CMAKE_BINARY_DIR}/dist/pki-tps.jar
+ DESTINATION
+ ${JAVA_JAR_INSTALL_DIR}/pki
+)
+
+set(PKI_TPS_JAR ${CMAKE_BINARY_DIR}/dist/pki-tps.jar CACHE INTERNAL "pki-tps jar file")
diff --git a/base/tps/src/org/dogtagpki/server/tps/TPSPhoneHome.java b/base/tps/src/org/dogtagpki/server/tps/TPSPhoneHome.java
new file mode 100644
index 000000000..e0b3b6b87
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/TPSPhoneHome.java
@@ -0,0 +1,95 @@
+package org.dogtagpki.server.tps;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.dogtagpki.tps.main.TPSBuffer;
+
+import com.netscape.certsrv.apps.CMS;
+
+public class TPSPhoneHome extends HttpServlet {
+
+ private static final long serialVersionUID = 1864386666927370987L;
+ private static String phoneHomeName = "phoneHome.xml";
+
+ public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
+ //Simply return xml file to the client
+ //In the future we could get this info from elsewhere such as LDAP
+
+ CMS.debug("TPSPhoneHome entering.");
+
+ renderPhoneHome(request, response);
+ }
+
+ private void renderPhoneHome(HttpServletRequest request, HttpServletResponse response) throws ServletException,
+ IOException {
+ ServletOutputStream stream = null;
+ BufferedInputStream buf = null;
+ FileInputStream input = null;
+
+ try {
+
+ stream = response.getOutputStream();
+ response.setContentType("application/xml");
+
+ String confPath = getConfigPath();
+
+ confPath += File.separator + phoneHomeName;
+
+ input = new FileInputStream(confPath);
+ // InputStream input = ctx.getResourceAsStream(phoneHomeName);
+ buf = new BufferedInputStream(input);
+
+ int readBytes = 0;
+ TPSBuffer readData = new TPSBuffer();
+ while ((readBytes = buf.read()) != -1) {
+ stream.write(readBytes);
+ readData.add((byte) readBytes);
+ }
+
+ CMS.debug("TPSPhoneHome.renderPhoneHome: data: " + readData.toHexString());
+
+ } catch (IOException e) {
+ CMS.debug("TPSPhoneHome.renderPhoneHome: Error encountered: " + e);
+ throw new ServletException("TPSPhoneHome.renderPhoneHome: Error encountered: " + e);
+ } finally {
+ if (stream != null)
+ stream.close();
+ if (buf != null)
+ buf.close();
+ if (input != null)
+ input.close();
+ }
+
+ }
+
+ private String getConfigPath() {
+
+ String path = null;
+ String context = getServletContext().getContextPath();
+
+ // get subsystem name by removing the / prefix from the context
+ String subsystem = context.startsWith("/") ? context.substring(1) : context;
+
+ // catalina.base points to instance dir
+ String instanceDir = System.getProperty("catalina.base");
+
+ //Finish off path of conf directory
+ path = instanceDir + File.separator + "conf" + File.separator +
+ subsystem + File.separator;
+
+ CMS.debug("TPSPhoneHome.getConfigPath: returning: " + path);
+
+ return path;
+
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/TPSServlet.java b/base/tps/src/org/dogtagpki/server/tps/TPSServlet.java
new file mode 100644
index 000000000..87c416b3e
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/TPSServlet.java
@@ -0,0 +1,65 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.dogtagpki.tps.TPSConnection;
+
+import com.netscape.certsrv.apps.CMS;
+
+/**
+ * @author Endi S. Dewata <edewata@redhat.com>
+ */
+public class TPSServlet extends HttpServlet {
+
+ private static final long serialVersionUID = -1092227495262381074L;
+
+ public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
+
+ String encoding = request.getHeader("Transfer-Encoding");
+
+ CMS.debug("Encoding: " + encoding);
+
+ if (encoding.equals("chunked") == false) {
+ throw new IOException("TPSServlet.service: incorrect encoding! ");
+ }
+
+ response.setHeader("Transfer-Encoding", "chunked");
+
+ TPSConnection con = new TPSConnection(
+ request.getInputStream(), response.getOutputStream(), true);
+
+ CMS.debug("TPSConnection created: " + con);
+
+ String ipAddress = request.getRemoteAddr();
+
+ TPSSession session = new TPSSession(con, ipAddress);
+
+ CMS.debug("TPSSession created: " + session);
+
+ session.process();
+
+ CMS.debug("After session.process() exiting ...");
+
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/TPSSession.java b/base/tps/src/org/dogtagpki/server/tps/TPSSession.java
new file mode 100644
index 000000000..4a175e698
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/TPSSession.java
@@ -0,0 +1,174 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps;
+
+import java.io.IOException;
+
+import org.dogtagpki.server.tps.dbs.TokenRecord;
+import org.dogtagpki.server.tps.processor.TPSEnrollProcessor;
+import org.dogtagpki.server.tps.processor.TPSPinResetProcessor;
+import org.dogtagpki.server.tps.processor.TPSProcessor;
+import org.dogtagpki.tps.TPSConnection;
+import org.dogtagpki.tps.main.TPSException;
+import org.dogtagpki.tps.msg.BeginOpMsg;
+import org.dogtagpki.tps.msg.EndOpMsg;
+import org.dogtagpki.tps.msg.TPSMessage;
+
+import com.netscape.certsrv.apps.CMS;
+
+public class TPSSession {
+
+ private TPSConnection connection;
+ private String ipAddress; /* remote IP */
+ private TokenRecord tokenRecord;
+
+ public TPSSession(TPSConnection conn, String ip) {
+
+ if (conn == null) {
+ throw new NullPointerException("TPSSession incoming connection is null!");
+ }
+
+ CMS.debug("TPSSession constructor conn: " + conn);
+ connection = conn;
+
+ if (ip == null) {
+ // probably unlikely to happen; log it and continue anyway
+ CMS.debug("TPSSession constructor remote ipAddress null");
+ } else {
+ CMS.debug("TPSSession constructor remote ipAddress: " + getIpAddress());
+ }
+ setIpAddress(ip);
+
+ }
+
+ public TPSConnection getConnection() {
+ return connection;
+ }
+
+ public TPSMessage read() throws IOException {
+ TPSMessage message = null;
+
+ CMS.debug("TPSSession.process() about to call read on connection : " + connection);
+
+ try {
+ message = connection.read();
+ CMS.debug("TPSSession.process() created message " + message);
+
+ } catch (IOException e) {
+ //Catch here so we can log
+ CMS.debug("TPSSession.process: Exception reading from the client: " + e.toString());
+ throw e;
+ }
+
+ return message;
+ }
+
+ public void write(TPSMessage msg) throws IOException {
+
+ try {
+ connection.write(msg);
+ } catch (Exception e) {
+ //Catch here so we can log
+ CMS.debug("Exception writing to client: " + e.toString());
+ throw e;
+ }
+
+ }
+
+ public void process() throws IOException {
+ EndOpMsg.TPSStatus status = EndOpMsg.TPSStatus.STATUS_NO_ERROR;
+ CMS.debug("In TPSSession.process()");
+
+ TPSMessage firstMsg = read();
+
+ TPSMessage.MsgType msg_type = firstMsg.getType();
+ TPSMessage.OpType op_type = firstMsg.getOpType();
+
+ if (msg_type != TPSMessage.MsgType.MSG_BEGIN_OP) {
+ throw new IOException("Wrong first message type read in TPSSession.process!");
+ }
+
+ int result = EndOpMsg.RESULT_ERROR;
+ BeginOpMsg beginOp = (BeginOpMsg) firstMsg;
+ try {
+ switch (op_type) {
+ case OP_FORMAT:
+
+ //Assume success, processor will indicate otherwise
+ result = EndOpMsg.RESULT_GOOD;
+ TPSProcessor processor = new TPSProcessor(this);
+ processor.process(beginOp);
+ break;
+
+ case OP_ENROLL:
+ //Assume success, processor will indicate otherwise
+ result = EndOpMsg.RESULT_GOOD;
+ TPSEnrollProcessor enrollProcessor = new TPSEnrollProcessor(this);
+ enrollProcessor.process(beginOp);
+ break;
+ case OP_RENEW:
+ break;
+ case OP_RESET_PIN:
+ result = EndOpMsg.RESULT_GOOD;
+ TPSPinResetProcessor pinResetProcessor = new TPSPinResetProcessor(this);
+ pinResetProcessor.process(beginOp);
+ break;
+ case OP_UNBLOCK:
+ break;
+ case OP_UNDEFINED:
+ break;
+ default:
+ break;
+
+ }
+ } catch (TPSException e) {
+ //Get the status from the exception and return it to the client.
+ CMS.debug("TPSSession.process: Message processing failed: " + e);
+ status = e.getStatus();
+ result = EndOpMsg.RESULT_ERROR;
+ } catch (IOException e) {
+ CMS.debug("TPSSession.process: IO error happened during processing: " + e);
+ // We get here we are done.
+ throw e;
+
+ }
+
+ EndOpMsg endOp = new EndOpMsg(firstMsg.getOpType(), result, status);
+ write(endOp);
+
+ CMS.debug("TPSSession.process: leaving: result: " + result + " status: " + status);
+
+ }
+
+ public TokenRecord getTokenRecord() {
+ return tokenRecord;
+ }
+
+ public void setTokenRecord(TokenRecord tokenRecord) {
+ this.tokenRecord = tokenRecord;
+ }
+
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
+ private void setIpAddress(String ipAddress) {
+ this.ipAddress = ipAddress;
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/TPSSubsystem.java b/base/tps/src/org/dogtagpki/server/tps/TPSSubsystem.java
new file mode 100644
index 000000000..75cdddadb
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/TPSSubsystem.java
@@ -0,0 +1,231 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps;
+
+import org.dogtagpki.server.tps.authentication.AuthenticationManager;
+import org.dogtagpki.server.tps.cms.ConnectionManager;
+import org.dogtagpki.server.tps.config.AuthenticatorDatabase;
+import org.dogtagpki.server.tps.config.ConfigDatabase;
+import org.dogtagpki.server.tps.config.ConnectorDatabase;
+import org.dogtagpki.server.tps.config.ProfileDatabase;
+import org.dogtagpki.server.tps.config.ProfileMappingDatabase;
+import org.dogtagpki.server.tps.dbs.ActivityDatabase;
+import org.dogtagpki.server.tps.dbs.TPSCertDatabase;
+import org.dogtagpki.server.tps.dbs.TokenDatabase;
+import org.dogtagpki.server.tps.engine.TPSEngine;
+import org.dogtagpki.server.tps.profile.TokenProfileResolverManager;
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.CryptoManager.NotInitializedException;
+import org.mozilla.jss.crypto.ObjectNotFoundException;
+import org.mozilla.jss.crypto.TokenException;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authority.IAuthority;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.ISubsystem;
+import com.netscape.certsrv.dbs.IDBSubsystem;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.request.IRequestListener;
+import com.netscape.certsrv.request.IRequestQueue;
+import com.netscape.cmscore.dbs.DBSubsystem;
+
+/**
+ * @author Endi S. Dewata <edewata@redhat.com>
+ */
+public class TPSSubsystem implements IAuthority, ISubsystem {
+
+ public final static String ID = "tps";
+
+ public ILogger logger = CMS.getLogger();
+
+ public String id;
+ public String nickname;
+ public ISubsystem owner;
+ public IConfigStore config;
+
+ public ActivityDatabase activityDatabase;
+ public AuthenticatorDatabase authenticatorDatabase;
+ public TPSCertDatabase certDatabase;
+ public ConfigDatabase configDatabase;
+ public ConnectorDatabase connectorDatabase;
+ public ProfileDatabase profileDatabase;
+ public ProfileMappingDatabase profileMappingDatabase;
+ public TokenDatabase tokenDatabase;
+ public ConnectionManager connManager;
+ public AuthenticationManager authManager;
+ public TokenProfileResolverManager profileResolverManager;
+ public TPSEngine engine;
+ public TPSTokendb tdb;
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public void setId(String id) throws EBaseException {
+ this.id = id;
+ }
+
+ @Override
+ public void init(ISubsystem owner, IConfigStore config) throws EBaseException {
+ this.owner = owner;
+ this.config = config;
+
+ IDBSubsystem dbSubsystem = DBSubsystem.getInstance();
+ IConfigStore cs = CMS.getConfigStore();
+
+ String activityDatabaseDN = cs.getString("tokendb.activityBaseDN");
+ activityDatabase = new ActivityDatabase(dbSubsystem, activityDatabaseDN);
+
+ String certDatabaseDN = cs.getString("tokendb.certBaseDN");
+ certDatabase = new TPSCertDatabase(dbSubsystem, certDatabaseDN);
+
+ String tokenDatabaseDN = cs.getString("tokendb.baseDN");
+ tokenDatabase = new TokenDatabase(dbSubsystem, tokenDatabaseDN);
+
+ configDatabase = new ConfigDatabase();
+ authenticatorDatabase = new AuthenticatorDatabase();
+ connectorDatabase = new ConnectorDatabase();
+ profileDatabase = new ProfileDatabase();
+ profileMappingDatabase = new ProfileMappingDatabase();
+ tdb = new TPSTokendb(this);
+
+ engine = new TPSEngine();
+ engine.init();
+
+ }
+
+ @Override
+ public void startup() throws EBaseException {
+ CMS.debug("TPSSubsystem: startup() begins");
+ connManager = new ConnectionManager();
+ connManager.initConnectors();
+ authManager = new AuthenticationManager();
+ authManager.initAuthInstances();
+ profileResolverManager = new TokenProfileResolverManager();
+ profileResolverManager.initProfileResolverInstances();
+ CMS.debug("TPSSubsystem: startup() ends.");
+ }
+
+ @Override
+ public void shutdown() {
+ }
+
+ @Override
+ public IConfigStore getConfigStore() {
+ return config;
+ }
+
+ @Override
+ public IRequestQueue getRequestQueue() {
+ return null;
+ }
+
+ @Override
+ public void registerRequestListener(IRequestListener listener) {
+ }
+
+ @Override
+ public void registerPendingListener(IRequestListener listener) {
+ }
+
+ @Override
+ public void log(int level, String msg) {
+ logger.log(ILogger.EV_SYSTEM, ILogger.S_TPS, level, msg);
+ }
+
+ @Override
+ public String getNickname() {
+ return nickname;
+ }
+
+ public void setNickname(String nickname) {
+ this.nickname = nickname;
+ }
+
+ @Override
+ public String getOfficialName() {
+ return "tps";
+ }
+
+ public ActivityDatabase getActivityDatabase() {
+ return activityDatabase;
+ }
+
+ public AuthenticatorDatabase getAuthenticatorDatabase() {
+ return authenticatorDatabase;
+ }
+
+ public TPSCertDatabase getCertDatabase() {
+ return certDatabase;
+ }
+
+ public ConfigDatabase getConfigDatabase() {
+ return configDatabase;
+ }
+
+ public ConnectorDatabase getConnectorDatabase() {
+ return connectorDatabase;
+ }
+
+ public ProfileDatabase getProfileDatabase() {
+ return profileDatabase;
+ }
+
+ public ProfileMappingDatabase getProfileMappingDatabase() {
+ return profileMappingDatabase;
+ }
+
+ public TokenDatabase getTokenDatabase() {
+ return tokenDatabase;
+ }
+
+ public ConnectionManager getConnectionManager() {
+ return connManager;
+ }
+
+ public AuthenticationManager getAuthenticationManager() {
+ return authManager;
+ }
+
+ public TokenProfileResolverManager getProfileResolverManager() {
+ return profileResolverManager;
+ }
+
+ public TPSTokendb getTokendb() {
+ return tdb;
+ }
+
+ public org.mozilla.jss.crypto.X509Certificate getSubsystemCert() throws EBaseException, NotInitializedException,
+ ObjectNotFoundException, TokenException {
+ IConfigStore cs = CMS.getConfigStore();
+ String nickname = cs.getString("tps.subsystem.nickname", "");
+ String tokenname = cs.getString("tps.subsystem.tokenname", "");
+ if (!tokenname.equals("internal") && !tokenname.equals("Internal Key Storage Token"))
+ nickname = tokenname + ":" + nickname;
+
+ CryptoManager cm = CryptoManager.getInstance();
+ return cm.findCertByNickname(nickname);
+ }
+
+ public TPSEngine getEngine() {
+ return engine;
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/TPSTokenPolicy.java b/base/tps/src/org/dogtagpki/server/tps/TPSTokenPolicy.java
new file mode 100644
index 000000000..1a866f737
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/TPSTokenPolicy.java
@@ -0,0 +1,158 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps;
+
+import org.dogtagpki.server.tps.dbs.TokenRecord;
+import org.dogtagpki.tps.main.TPSException;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.EPropertyNotFound;
+import com.netscape.certsrv.base.IConfigStore;
+
+/*
+ * TPSTokenPolicy - handles token enrollment related policies
+ *
+ * @author cfu
+ */
+public class TPSTokenPolicy {
+ private TPSSubsystem tps;
+ private static final String DEFAULT_POLICY_SET_STRING =
+ "RE_ENROLL=YES;RENEW=NO;FORCE_FORMAT=NO;PIN_RESET=NO;RESET_PIN_RESET_TO_NO=NO";
+ private boolean re_enroll = true;
+ private boolean renew = false;
+ private boolean force_format = false;
+ private boolean pin_reset = true;
+ private boolean reset_pin_reset_to_no = false;
+
+ public TPSTokenPolicy (TPSSubsystem tps) throws TPSException {
+ if (tps == null) {
+ String msg = "TPSTokenPolicy.TPSTokenPolicy: tps cannnot be null";
+ CMS.debug(msg);
+ throw new TPSException(msg);
+ }
+ this.tps = tps;
+ // init from config first
+ String policySetString = getDefaultPolicySetString();
+ parsePolicySetString(policySetString);
+
+ }
+
+ public String getDefaultPolicySetString() {
+ IConfigStore configStore = CMS.getConfigStore();
+ String configName = "tokendb.defaultPolicy";
+ String policySetString;
+ try {
+ policySetString = configStore.getString(configName);
+ } catch (EPropertyNotFound e) {
+ policySetString = DEFAULT_POLICY_SET_STRING;
+ } catch (EBaseException e) {
+ policySetString = DEFAULT_POLICY_SET_STRING;
+ }
+
+ return policySetString;
+ }
+
+ public void parsePolicySetString (String policySetString) {
+ if (policySetString == null)
+ return; // take the default
+
+ String[] policySet = policySetString.split(";");
+ for (String policyString : policySet) {
+ String[] policy = policyString.split("=");
+ if (policy[0].equalsIgnoreCase("RE_ENROLL"))
+ re_enroll = getBool(policy[1], true);
+ else if (policy[0].equalsIgnoreCase("RENEW"))
+ renew = getBool(policy[1], false);
+ else if (policy[0].equalsIgnoreCase("FORCE_FORMAT"))
+ force_format = getBool(policy[1], false);
+ else if (policy[0].equalsIgnoreCase("PIN_RESET"))
+ pin_reset = getBool(policy[1], false);
+ else if (policy[0].equalsIgnoreCase("RESET_PIN_RESET_TO_NO"))
+ reset_pin_reset_to_no = getBool(policy[1], false);
+ //else no change, just take the default;
+ }
+ }
+
+/*
+ * getBool translates string to boolean:
+ * true: "YES", "yes", "TRUE", "true"
+ * false: "NO", "no", "FALSE", "false"
+ *
+ * if tring is null or Anything othrer than the above, defaultbool is returned
+ */
+ private boolean getBool(String string, boolean defaultBool) {
+ if (string == null)
+ return defaultBool;
+
+ if (string.equalsIgnoreCase("YES") ||
+ string.equalsIgnoreCase("true")) {
+ return true;
+ } else if (string.equalsIgnoreCase("NO") ||
+ string.equalsIgnoreCase("false")) {
+ return false;
+ }
+
+ return defaultBool;
+ }
+
+ private void getUpdatedPolicy(String cuid) {
+ // note: default policy already initialized in the constructor
+ TokenRecord tokenRecord = null;
+ String policySetString = null;
+ try {
+ tokenRecord = tps.tdb.tdbGetTokenEntry(cuid);
+ } catch (Exception e) {
+ // just take the default;
+ return;
+ }
+
+ policySetString = tokenRecord.getPolicy();
+ parsePolicySetString(policySetString);
+ }
+
+ public boolean isAllowedTokenPinReset(String cuid) {
+ getUpdatedPolicy(cuid);
+
+ return reset_pin_reset_to_no;
+ }
+
+ public boolean isAllowedPinReset(String cuid) {
+ getUpdatedPolicy(cuid);
+
+ return pin_reset;
+ }
+
+ public boolean isForceTokenFormat(String cuid) {
+ getUpdatedPolicy(cuid);
+
+ return force_format;
+ }
+
+ public boolean isAllowdTokenReenroll(String cuid) {
+ getUpdatedPolicy(cuid);
+
+ return re_enroll;
+ }
+
+ public boolean isAllowdTokenRenew(String cuid) {
+ getUpdatedPolicy(cuid);
+
+ return renew;
+ }
+} \ No newline at end of file
diff --git a/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java b/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java
new file mode 100644
index 000000000..914706dd9
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java
@@ -0,0 +1,425 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+
+import netscape.security.x509.RevocationReason;
+
+import org.dogtagpki.server.tps.cms.CARemoteRequestHandler;
+import org.dogtagpki.server.tps.cms.CARevokeCertResponse;
+import org.dogtagpki.server.tps.dbs.TPSCertRecord;
+import org.dogtagpki.server.tps.dbs.TokenRecord;
+import org.dogtagpki.tps.main.TPSException;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.tps.token.TokenStatus;
+
+/*
+ * TPSTokendb class offers a collection of tokendb management convenience routines
+ */
+public class TPSTokendb {
+ private TPSSubsystem tps;
+ private Map<TokenStatus, Collection<TokenStatus>> allowedTransitions = new HashMap<TokenStatus, Collection<TokenStatus>>();
+
+ public TPSTokendb(TPSSubsystem tps) throws EBaseException {
+ if (tps == null) {
+ String msg = "TPStokendb.TPSTokendb: tps cannot be null";
+ CMS.debug(msg);
+ throw new EBaseException(msg);
+ }
+ this.tps = tps;
+ try {
+ initAllowedTransitions();
+ } catch (Exception e) {
+ CMS.debug("TPSTokendb: initAllowedTransitions() failed:" + e);
+ throw new EBaseException(e.toString());
+ }
+ }
+
+ void initAllowedTransitions()
+ throws Exception {
+ CMS.debug("TPSTokendb.initAllowedTransitions()");
+ IConfigStore configStore = CMS.getConfigStore();
+
+ // load allowed token state transitions
+ CMS.debug("TPSTokendbs: allowed transitions:");
+
+ for (String transition : configStore.getString("tokendb.allowedTransitions").split(",")) {
+ String states[] = transition.split(":");
+ TokenStatus fromState = TokenStatus.fromInt(Integer.valueOf(states[0]));
+ TokenStatus toState = TokenStatus.fromInt(Integer.valueOf(states[1]));
+ CMS.debug("TPSTokendb: - " + fromState + " to " + toState);
+
+ Collection<TokenStatus> nextStates = allowedTransitions.get(fromState);
+ if (nextStates == null) {
+ nextStates = new HashSet<TokenStatus>();
+ allowedTransitions.put(fromState, nextStates);
+ }
+ nextStates.add(toState);
+ }
+ }
+
+ public boolean isTransitionAllowed(TokenRecord tokenRecord, TokenStatus newState) {
+ boolean result = false;
+ TokenStatus currentTokenStatus = tokenRecord.getTokenStatus();
+ CMS.debug("TokenRecord.isTransitionAllowed(): current status: " + currentTokenStatus);
+ Collection<TokenStatus> nextStatuses = allowedTransitions.get(currentTokenStatus);
+ CMS.debug("TokenRecord.isTransitionAllowed(): allowed next statuses: " + nextStatuses);
+ if (nextStatuses == null || !nextStatuses.contains(newState)) {
+ CMS.debug("TokenRecord.isTransitionAllowed(): next status not allowed: " + newState);
+
+ result = false;
+ } else {
+ //status change allowed
+ result = true;
+ }
+ return result;
+ }
+
+ /*
+ * tdbActivity logs token activities; This version is called by non-administrative functions
+ */
+ public void tdbActivity(
+ String op, TokenRecord tokenRecord, String ip, String msg, String result) {
+ try {
+ tps.activityDatabase.log(
+ ip,
+ (tokenRecord != null)? tokenRecord.getId():null,
+ op,
+ result,
+ msg,
+ (tokenRecord != null)? tokenRecord.getUserID():null,
+ (tokenRecord != null)? tokenRecord.getType():null);
+ } catch (Exception e) {
+ msg = msg + ";" + " tokendb activity logging failure: " + e;
+ }
+ }
+
+ /*
+ * tdbActivity logs token activities; This version is called by administrative functions
+ */
+ public void tdbActivity(
+ String op, TokenRecord tokenRecord, String ip, String msg, String result, String uid) {
+ try {
+ tps.activityDatabase.log(
+ ip,
+ (tokenRecord != null)? tokenRecord.getId():null,
+ op,
+ result,
+ msg,
+ uid,
+ (tokenRecord != null)? tokenRecord.getType():null);
+ } catch (Exception e) {
+ msg = msg + ";" + " tokendb activity logging failure: " + e;
+ }
+ }
+
+ public boolean isTokenPresent(String cuid) {
+ boolean present = false;
+ try {
+ tps.tokenDatabase.getRecord(cuid);
+ present = true;
+ } catch (Exception e) {
+ CMS.debug("TPSTokendb.isTokenPresent: token entry not found");
+ present = false;
+ }
+ return present;
+ }
+
+ public TokenRecord tdbGetTokenEntry(String cuid)
+ throws Exception {
+ return tps.tokenDatabase.getRecord(cuid);
+ }
+
+ /*
+ * tdbFindTokenRecordsByUID finds and returns token records belong to one user
+ * @param uid the uid of the owner to the token
+ * @return ArrayList of the token records
+ */
+ public ArrayList<TokenRecord> tdbFindTokenRecordsByUID(String uid)
+ throws Exception {
+ ArrayList<TokenRecord> tokenRecords = new ArrayList<TokenRecord>();
+ String filter = uid;
+ Iterator<TokenRecord> records = null;
+ records = tps.tokenDatabase.findRecords(filter).iterator();
+
+ while (records.hasNext()) {
+ TokenRecord tokenRecord = records.next();
+ tokenRecords.add(tokenRecord);
+ }
+
+ return tokenRecords;
+ }
+
+ public void tdbHasActiveToken(String userid)
+ throws Exception {
+ if (userid == null)
+ throw new Exception("TPSTokendb.tdbhasActiveToken: uerid null");
+
+ ArrayList<TokenRecord> tokens =
+ tdbFindTokenRecordsByUID(userid);
+ boolean foundActive = false;
+ for (TokenRecord tokenRecord:tokens) {
+ if (tokenRecord.getStatus().equals("active")) {
+ foundActive = true;
+ }
+ }
+ if (!foundActive) {
+ throw new Exception("TPSTokendb.tdbhasActiveToken: active token not found");
+ }
+ }
+
+ public void tdbAddTokenEntry(TokenRecord tokenRecord, String status)
+ throws Exception {
+ tokenRecord.setStatus(status);
+
+ tps.tokenDatabase.addRecord(tokenRecord.getId(), tokenRecord);
+ }
+
+ public void tdbUpdateTokenEntry(TokenRecord tokenRecord)
+ throws Exception {
+ String id = tokenRecord.getId();
+ TokenRecord existingTokenRecord;
+ try {
+ existingTokenRecord = tps.tokenDatabase.getRecord(id);
+ } catch (Exception e) {
+ CMS.debug("TPSTokendb.tdbUpdateTokenEntry: token entry not found; Adding");
+ // add and exit
+ tdbAddTokenEntry(tokenRecord, "uninitialized");
+ return;
+ }
+ // token found; modify
+ CMS.debug("TPSTokendb.tdbUpdateTokenEntry: token entry found; Modifying with status: "+ tokenRecord.getStatus());
+ // don't change the create time of an existing token record; put it back
+ tokenRecord.setCreateTimestamp(existingTokenRecord.getCreateTimestamp());
+ tps.tokenDatabase.updateRecord(id, tokenRecord);
+ }
+
+ /*
+ * tdbAddCertificatesForCUID adds certificates issued for the token CUID
+ * @param cuid the cuid of the token
+ * @param certs an ArrayList of TPSCertRecord
+ */
+ public void tdbAddCertificatesForCUID(String cuid, ArrayList<TPSCertRecord> certs)
+ throws TPSException {
+ boolean tokenExist = isTokenPresent(cuid);
+ if (!tokenExist){
+ CMS.debug("TPSTokendb.tdbAddCertificatesForCUID: token not found: "+ cuid);
+ throw new TPSException("TPSTokendb:tdbUpdateCertificates: token "+ cuid + " does not exist");
+ }
+
+ CMS.debug("TPSTokendb.tdbAddCertificatesForCUID: found token "+ cuid);
+ CMS.debug("TPSTokendb.tdbAddCertificatesForCUID: number of certs to update:"+ certs.size());
+ try {
+ for (TPSCertRecord cert: certs) {
+ // cert.setOrigin(cuid);
+
+ try {
+ tps.certDatabase.addRecord(cert.getId(), cert);
+ } catch (Exception e) {
+
+ //If this is due to a dup, try to update the record.
+ tps.certDatabase.updateRecord(cert.getId(), cert);
+ }
+ }
+ } catch (Exception e) {
+ CMS.debug("TPSTokendb.tdbAddCertificatesForCUID: "+ e);
+ // TODO: what if it throws in the middle of the cert list -- some cert records already updated?
+ throw new TPSException(e.getMessage());
+ }
+ }
+
+ /*
+ * tdbGetCertificatesByCUID finds and returns certificate records belong to a token cuid
+ * @param cuid the cuid of the token
+ * @return ArrayList of the cert records
+ */
+ public ArrayList<TPSCertRecord> tdbGetCertificatesByCUID(String cuid)
+ throws TPSException {
+ if (cuid == null)
+ throw new TPSException("TPSTokendb.tdbGetCertificatesByCUID: cuid null");
+
+ ArrayList<TPSCertRecord> certRecords = new ArrayList<TPSCertRecord>();
+ String filter = cuid;
+ Iterator<TPSCertRecord> records;
+ try {
+ records = tps.certDatabase.findRecords(filter).iterator();
+ } catch (Exception e) {
+ CMS.debug("TPSTokendb.tdbGetCertificatesByCUID:" + e);
+ throw new TPSException(e.getMessage());
+ }
+
+ while (records.hasNext()) {
+ TPSCertRecord certRecord = records.next();
+ certRecords.add(certRecord);
+ }
+
+ return certRecords;
+ }
+
+ public void revokeCertsByCUID(String cuid, String tokenReason) throws Exception {
+ String method = "TPStokendb.revokeCertsByCUID";
+ CMS.debug(method + ": called");
+ if (cuid == null)
+ throw new TPSException(method + ": cuid null");
+ revokeCertsByCUID(true, cuid, tokenReason);
+ }
+
+ public void unRevokeCertsByCUID(String cuid) throws Exception {
+ String method = "TPStokendb.unRevokeCertsByCUID";
+ CMS.debug(method + ": called");
+ if (cuid == null)
+ throw new TPSException(method + ": cuid null");
+ revokeCertsByCUID(false, cuid, null /* null for unrevoke*/);
+ }
+
+ /*
+ * revokeCertsByCUID
+ * @param isRevoke true if to revoke; false to unrevoke
+ * @param cuid cuid of token to revoke/unrevoke
+ * @param onHold true if revocation is to put onHold; false if to really revoke
+ */
+ private void revokeCertsByCUID(boolean isRevoke, String cuid, String tokenReason) throws Exception {
+ String method = "TPSTokendb.revokeCertsByCUID";
+ if (cuid == null)
+ throw new TPSException(method + ": cuid null");
+ String auditMsg;
+ IConfigStore configStore = CMS.getConfigStore();
+ ArrayList<TPSCertRecord> certRecords = tps.getTokendb().tdbGetCertificatesByCUID(cuid);
+ if (tokenReason != null) {
+ if (!tokenReason.equalsIgnoreCase("onHold") &&
+ !tokenReason.equalsIgnoreCase("destroyed") &&
+ !tokenReason.equalsIgnoreCase("keyCompromise")) {
+ auditMsg = "unknown tokenRecord lost reason:" + tokenReason;
+ CMS.debug(method + ":" + auditMsg);
+ throw new Exception(method + ":" + auditMsg);
+ }
+
+ }
+ for (TPSCertRecord cert : certRecords) {
+ // get conn id
+ String config = "op.enroll." + cert.getType() + ".keyGen." + cert.getKeyType() + ".ca.conn";
+ String connID = configStore.getString(config);
+
+ RevocationReason revokeReason = RevocationReason.UNSPECIFIED;
+
+ if (isRevoke) {
+ auditMsg = "called to revoke";
+ CMS.debug(method + ":" + auditMsg);
+ boolean revokeCert = false;
+
+ // get revoke or not
+ config = "op.enroll." + cert.getType() + ".keyGen." + cert.getKeyType() +
+ ".recovery." + tokenReason + ".revokeCert";
+ //TODO: temporaryToken doesn't have all params; default to false if not found for now
+ revokeCert = configStore.getBoolean(config, false); // default to false
+ if (!revokeCert) {
+ auditMsg = "cert not to be revoked:" + cert.getSerialNumber();
+ CMS.debug(method + ":" + auditMsg);
+ continue;
+ }
+ auditMsg = "cert to be revoked:" + cert.getSerialNumber();
+ CMS.debug(method + ":" + auditMsg);
+
+ // get revoke reason
+ config = "op.enroll." + cert.getType() + ".keyGen." + cert.getKeyType() +
+ ".recovery." + tokenReason + ".revokeCert.reason";
+ int reasonInt = configStore.getInteger(config, 0);
+ revokeReason = RevocationReason.fromInt(reasonInt);
+ } else { // is unrevoke
+ auditMsg = "called to unrevoke";
+ CMS.debug(method + ":" + auditMsg);
+ if (!cert.getStatus().equalsIgnoreCase("revoked_on_hold")) {
+ auditMsg = "cert record current status is not revoked_on_hold; cannot unrevoke";
+ CMS.debug(method + ":" + auditMsg);
+ continue;// TODO: continue or bail?
+ }
+ }
+
+ CARemoteRequestHandler caRH = null;
+ caRH = new CARemoteRequestHandler(connID);
+ String hexSerial = cert.getSerialNumber();
+ if (hexSerial.length() >= 3 && hexSerial.startsWith("0x")) {
+ String serial = hexSerial.substring(2); // skip over the '0x'
+ BigInteger bInt = new BigInteger(serial, 16);
+ String serialStr = bInt.toString();
+ CMS.debug(method + ": found cert hex serial: " + serial +
+ " dec serial:" + serialStr);
+ CARevokeCertResponse response =
+ caRH.revokeCertificate(isRevoke, serialStr, cert.getCertificate(),
+ revokeReason);
+ CMS.debug(method + ": response status =" + response.getStatus());
+ } else {
+ auditMsg = "mulformed hex serial number :" + hexSerial;
+ CMS.debug(method + ": " + auditMsg);
+ throw new Exception(auditMsg);
+ }
+
+ // update certificate status
+ if (isRevoke) {
+ if (revokeReason == RevocationReason.CERTIFICATE_HOLD) {
+ cert.setStatus("revoked_on_hold");
+ } else {
+ cert.setStatus("revoked");
+ }
+ } else {
+ cert.setStatus("active");
+ }
+ tps.certDatabase.updateRecord(cert.getId(), cert);
+ auditMsg = "cert (un)revoked:" + cert.getSerialNumber();
+ CMS.debug(method + ":" + auditMsg);
+ //TODO: tdbActivity
+ }
+ }
+
+ public void tdbAddCertEntry(TPSCertRecord certRecord, String status)
+ throws Exception {
+ certRecord.setStatus(status);
+
+ tps.certDatabase.addRecord(certRecord.getId(), certRecord);
+ }
+
+ public void tdbUpdateCertEntry(TPSCertRecord certRecord)
+ throws Exception {
+ String method = "TPSTokendb.tdbUpdateCertEntry";
+ String id = certRecord.getId();
+ TPSCertRecord existingCertRecord;
+ try {
+ existingCertRecord = tps.certDatabase.getRecord(id);
+ } catch (Exception e) {
+ CMS.debug(method + ": token entry not found; Adding");
+ // add and exit
+ tdbAddCertEntry(certRecord, certRecord.getStatus());
+ return;
+ }
+ // cert found; modify
+ CMS.debug(method + ": cert entry found; Modifying with status: "+ certRecord.getStatus());
+ // don't change the create time of an existing token record; put it back
+ certRecord.setCreateTime(existingCertRecord.getCreateTime());
+ tps.certDatabase.updateRecord(id, certRecord);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/authentication/AuthUIParameter.java b/base/tps/src/org/dogtagpki/server/tps/authentication/AuthUIParameter.java
new file mode 100644
index 000000000..16d57f948
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/authentication/AuthUIParameter.java
@@ -0,0 +1,92 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps.authentication;
+
+import java.util.HashMap;
+
+import com.netscape.certsrv.base.EBaseException;
+
+/*
+ * AuthUIParameters is a class for per locale parameter sets
+ *
+ * @author cfu
+ */
+public class AuthUIParameter {
+
+ private String paramId;
+ /*
+ * auths.instance.<authInst>.ui.id.<param>.name.<locale>=<name>
+ * auths.instance.<authInst>.ui.id.<param>.description.<locale>=<description>
+ * e.g.
+ * auths.instance.ldap1.ui.id.PASSWORD.description.en=LDAP Password
+ * auths.instance.ldap1.ui.id.PASSWORD.name.en=LDAP Password
+ * auths.instance.ldap1.ui.id.UID.description.en=LDAP User ID
+ * auths.instance.ldap1.ui.id.UID.name.en=LDAP User ID
+ *
+ * for each id param <locale, name>
+ */
+ private HashMap<String, String> uiParamIdName;
+ private HashMap<String, String> uiParamIdDescription;
+
+ public AuthUIParameter(String id)
+ throws EBaseException {
+ paramId = id;
+ uiParamIdName = new HashMap<String, String>();
+ uiParamIdDescription = new HashMap<String, String>();
+ }
+
+ public void setParamName(String locale, String name) {
+ uiParamIdName.put(locale, name);
+ }
+
+ public String getParamName(String locale) {
+ return uiParamIdName.get(locale);
+ }
+
+ public void setParamDescription(String locale, String desc) {
+ uiParamIdDescription.put(locale, desc);
+ }
+
+ public String getParamDescription(String locale) {
+ return uiParamIdDescription.get(locale);
+ }
+
+ public String toString(String locale) {
+ String name = getParamName(locale);
+ if (name == null)
+ name = getParamName("en");
+
+ String desc = getParamDescription(locale);
+ if (desc == null)
+ desc = getParamDescription("en");
+
+ String typeValue = "string";
+
+ if(paramId.equals("PASSWORD")){
+ typeValue = "password";
+ }
+
+ String string =
+ "id=" + paramId +
+ "&name=" + name +
+ "&desc=" + desc +
+ "&type=" + typeValue +
+ "&option=";
+ return string;
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/authentication/AuthenticationManager.java b/base/tps/src/org/dogtagpki/server/tps/authentication/AuthenticationManager.java
new file mode 100644
index 000000000..e163bf6b1
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/authentication/AuthenticationManager.java
@@ -0,0 +1,287 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.authentication;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+
+/**
+ * AuthenticationManager is a class for management of authentication
+ * instances
+ *
+ * @author cfu
+ */
+public class AuthenticationManager
+{
+ private Hashtable<String, TPSAuthenticator> authInstances;
+
+ public AuthenticationManager() {
+ }
+
+ /*
+ * initAuthInstances initializes authentication manager instances
+ *
+ * configuration e.g.
+ *
+ * auths.instance.ldap1.ui.description.en=This authenticates user against the LDAP directory.
+ * auths.instance.ldap1.ui.title.en=LDAP Authentication
+ * auths.instance.ldap1.ui.id.PASSWORD.description.en=LDAP Password
+ * auths.instance.ldap1.ui.id.PASSWORD.name.en=LDAP Password
+ * auths.instance.ldap1.ui.id.PASSWORD.credMap.authCred=pwd
+ * auths.instance.ldap1.ui.id.PASSWORD.credMap.msgCred.extlogin=PASSWORD
+ * auths.instance.ldap1.ui.id.PASSWORD.credMap.msgCred.login=password
+ * auths.instance.ldap1.ui.id.UID.description.en=LDAP User ID
+ * auths.instance.ldap1.ui.id.UID.name.en=LDAP User ID
+ * auths.instance.ldap1.ui.id.UID.credMap.authCred=uid
+ * auths.instance.ldap1.ui.id.UID.credMap.msgCred.extlogin=UID
+ * auths.instance.ldap1.ui.id.UID.credMap.msgCred.login=screen_name
+ * auths.instance.ldap1.ui.retries=1
+ *
+ * # the following are handled by the IAuthManager itself
+ * auths.instance.ldap1.dnpattern=
+ * auths.instance.ldap1.ldap.basedn=dc=idm,dc=lab,dc=bos,dc=redhat,dc=com
+ * auths.instance.ldap1.ldap.ldapauth.authtype=BasicAuth
+ * auths.instance.ldap1.ldap.ldapauth.bindDN=
+ * auths.instance.ldap1.ldap.ldapauth.bindPWPrompt=ldap1
+ * auths.instance.ldap1.ldap.ldapauth.clientCertNickname=
+ * auths.instance.ldap1.ldap.ldapconn.host=vm-060.idm.lab.bos.redhat.com
+ * auths.instance.ldap1.ldap.ldapconn.port=389
+ * auths.instance.ldap1.ldap.ldapconn.secureConn=False
+ * auths.instance.ldap1.ldap.ldapconn.version=3
+ * auths.instance.ldap1.ldap.maxConns=15
+ * auths.instance.ldap1.ldap.minConns=3
+ * auths.instance.ldap1.ldapByteAttributes=
+ * auths.instance.ldap1.ldapStringAttributes=mail,cn,uid
+ * auths.instance.ldap1.pluginName=UidPwdDirAuth
+ */
+ public void initAuthInstances() throws EBaseException {
+ CMS.debug("AuthenticationManager: initAuthInstances(): begins.");
+ IConfigStore conf = CMS.getConfigStore();
+ IConfigStore authInstSubstore = conf.getSubStore("auths.instance");
+ Enumeration<String> auth_enu = authInstSubstore.getSubStoreNames();
+ authInstances = new Hashtable<String, TPSAuthenticator>();
+ while (auth_enu.hasMoreElements()) {
+ String authInstID = auth_enu.nextElement();
+ CMS.debug("AuthenticationManager: initAuthInstances(): initializing authentication instance " + authInstID);
+ IConfigStore authInstSub =
+ authInstSubstore.getSubStore(authInstID);
+ TPSAuthenticator authInst =
+ createAuthentication(authInstSub, authInstID);
+ authInstances.put(authInstID, authInst);
+ CMS.debug("AuthenticationManager: initAuthInstances(): authentication instance "
+ + authInstID +
+ " initialized.");
+ }
+ CMS.debug("AuthenticationManager: initAuthInstances(): ends.");
+ }
+
+ /*
+ * createAuthentication creates and returns an Authenticaiton
+ *
+ * @param conf config store of the authentication instance
+ * @return Authentication the authentication instance
+ */
+ private TPSAuthenticator createAuthentication(IConfigStore conf, String authInstID)
+ throws EBaseException {
+
+ CMS.debug("AuthenticationManager: createAuthentication(): begins for " +
+ authInstID);
+
+ if (conf == null || conf.size() <= 0) {
+ CMS.debug("AuthenticationManager: createAuthentication(): conf null or empty.");
+ throw new EBaseException("called with null config store");
+ }
+
+ TPSAuthenticator auth = new TPSAuthenticator(authInstID);
+
+ IConfigStore uiSub = conf.getSubStore("ui");
+ if (uiSub == null) {
+ CMS.debug("AuthenticationManager: createAuthentication(): conf "
+ + conf.getName() + ".ui" + " null or empty.");
+ throw new EBaseException("config " + conf.getName() + ".ui" + " not found");
+ }
+
+ // init ui title
+ IConfigStore uiTitleSub = uiSub.getSubStore("title");
+ if (uiTitleSub == null) {
+ CMS.debug("AuthenticationManager: createAuthentication(): conf "
+ + uiSub.getName() + ".title" + " null or empty.");
+ throw new EBaseException("config " + uiSub.getName() + ".title" + " not found");
+ }
+
+ Enumeration<String> uiTitle_enu = uiTitleSub.getPropertyNames();
+
+ while (uiTitle_enu.hasMoreElements()) {
+ String locale = uiTitle_enu.nextElement();
+ String title = uiTitleSub.getString(locale);
+ if (title.isEmpty()) {
+ CMS.debug("AuthenticationManager: createAuthentication(): title for locale "
+ + locale + " not found");
+ continue;
+ }
+ auth.setUiTitle(locale, title);
+ CMS.debug("AuthenticationManager: createAuthentication(): added title="
+ + title + ", locale= " + locale);
+ }
+
+ // init ui description
+ IConfigStore uiDescSub = uiSub.getSubStore("description");
+ if (uiDescSub == null) {
+ CMS.debug("AuthenticationManager: createAuthentication(): conf "
+ + uiSub.getName() + ".description" + " null or empty.");
+ throw new EBaseException("config " + uiSub.getName() + ".description" + " not found");
+ }
+ Enumeration<String> uiDesc_enu = uiDescSub.getPropertyNames();
+
+ while (uiDesc_enu.hasMoreElements()) {
+ String locale = uiDesc_enu.nextElement();
+ String description = uiDescSub.getString(locale);
+ if (description.isEmpty()) {
+ CMS.debug("AuthenticationManager: createAuthentication(): description for locale "
+ + locale + " not found");
+ continue;
+ }
+ auth.setUiDescription(locale, description);
+ CMS.debug("AuthenticationManager: createAuthentication(): added description="
+ + description + ", locale= " + locale);
+ }
+
+ // init ui parameters
+ IConfigStore uiParamSub = uiSub.getSubStore("id");
+ if (uiParamSub == null) {
+ CMS.debug("AuthenticationManager: createAuthentication(): conf "
+ + uiSub.getName() + ".id" + " null or empty.");
+ throw new EBaseException("config " + uiSub.getName() + ".id" + " not found");
+ }
+ Enumeration<String> uiParam_enu = uiParamSub.getSubStoreNames();
+ while (uiParam_enu.hasMoreElements()) {
+ String id = uiParam_enu.nextElement();
+ CMS.debug("AuthenticationManager: createAuthentication(): id param=" +
+ id);
+ IConfigStore idNameSub = uiParamSub.getSubStore(id + ".name");
+ if (idNameSub == null) {
+ CMS.debug("AuthenticationManager: createAuthentication(): conf "
+ + uiParamSub.getName() + ".name" + " null or empty.");
+ continue;
+ }
+
+ AuthUIParameter up = new AuthUIParameter(id);
+ Enumeration<String> idName_enu = idNameSub.getPropertyNames();
+ while (idName_enu.hasMoreElements()) {
+ String locale = idName_enu.nextElement();
+ String name = idNameSub.getString(locale);
+ if (name.isEmpty()) {
+ CMS.debug("AuthenticationManager: createAuthentication(): name for locale "
+ + locale + " not found");
+ continue;
+ }
+ CMS.debug("AuthenticationManager: createAuthentication(): name =" +
+ name + " for locale " + locale);
+ up.setParamName(locale, name);
+ }
+
+ IConfigStore idDescSub = uiParamSub.getSubStore(id + ".description");
+ if (idDescSub == null) {
+ CMS.debug("AuthenticationManager: createAuthentication(): conf "
+ + uiParamSub.getName() + ".description" + " null or empty.");
+ continue;
+ }
+ Enumeration<String> idDesc_enu = idDescSub.getPropertyNames();
+ while (idDesc_enu.hasMoreElements()) {
+ String locale = idDesc_enu.nextElement();
+ String desc = idDescSub.getString(locale);
+ if (desc.isEmpty()) {
+ CMS.debug("AuthenticationManager: createAuthentication(): description for locale "
+ + locale + " not found");
+ continue;
+ }
+ CMS.debug("AuthenticationManager: createAuthentication(): desc =" +
+ desc);
+ up.setParamDescription(locale, desc);
+ }
+
+ auth.setUiParam(id, up);
+ CMS.debug("AuthenticationManager: createAuthentication(): added param="
+ + id);
+
+ // map the auth mgr required cred to cred name in request message
+ IConfigStore credMapSub = uiParamSub.getSubStore(id + ".credMap");
+ if (credMapSub == null) {
+ CMS.debug("AuthenticationManager: createAuthentication(): conf "
+ + uiParamSub.getName() + ".credMap" + " null or empty.");
+ continue;
+ }
+ String authCred = credMapSub.getString("authCred");
+ if (authCred.isEmpty()) {
+ CMS.debug("AuthenticationManager: createAuthentication(): conf "
+ + credMapSub.getName() + ".authCred" + " null or empty.");
+ continue;
+ }
+
+ IConfigStore msgCredSub = credMapSub.getSubStore("msgCred");
+ if (msgCredSub == null) {
+ CMS.debug("AuthenticationManager: createAuthentication(): conf "
+ + uiParamSub.getName() + ".msgCred" + " null or empty.");
+ continue;
+ }
+
+ String msgCred_login = msgCredSub.getString("login");
+ if (msgCred_login.isEmpty()) {
+ CMS.debug("AuthenticationManager: createAuthentication(): conf "
+ + msgCredSub.getName() + ".login" + " null or empty.");
+ continue;
+ }
+ auth.setCredMap(authCred, msgCred_login,
+ false /* not extendedLogin*/);
+ CMS.debug("AuthenticationManager: createAuthentication(): added cred map_login="
+ + authCred + ":" + msgCred_login);
+
+ String msgCred_extlogin = msgCredSub.getString("extlogin");
+ if (msgCred_extlogin.isEmpty()) {
+ CMS.debug("AuthenticationManager: createAuthentication(): conf "
+ + msgCredSub.getName() + ".extlogin" + " null or empty.");
+ continue;
+ }
+
+ auth.setCredMap(authCred, msgCred_extlogin,
+ true /* extendedLogin*/);
+ CMS.debug("AuthenticationManager: createAuthentication(): added cred map_extlogin="
+ + authCred + ":" + msgCred_extlogin);
+
+ }
+
+ Integer retries = uiSub.getInteger("retries", 1);
+ auth.setNumOfRetries(retries.intValue());
+
+ CMS.debug("AuthenticationManager: createAuthentication(): completed for " +
+ authInstID);
+ return auth;
+ }
+
+ /*
+ * gets an established Authentication instance
+ */
+ public TPSAuthenticator getAuthInstance(String id) {
+ return authInstances.get(id);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/authentication/TPSAuthenticator.java b/base/tps/src/org/dogtagpki/server/tps/authentication/TPSAuthenticator.java
new file mode 100644
index 000000000..8d84cf5f6
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/authentication/TPSAuthenticator.java
@@ -0,0 +1,148 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps.authentication;
+
+import java.util.HashMap;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authentication.IAuthManager;
+import com.netscape.certsrv.authentication.IAuthSubsystem;
+import com.netscape.certsrv.base.EBaseException;
+
+/**
+ * Authentication is a class for an authentication instance
+ *
+ * @author cfu
+ */
+public class TPSAuthenticator {
+ private String id;
+ private IAuthManager authManager;
+
+ /*
+ * for auths instance ui <locale, value>
+ * e.g.
+ * auths.instance.ldap1.ui.description.en=
+ * This authenticates user against the LDAP directory.
+ * auths.instance.ldap1.ui.title.en=LDAP Authentication
+ */
+ private HashMap<String, String> uiTitle;
+ private HashMap<String, String> uiDescription;
+
+ private HashMap<String, AuthUIParameter> uiParameters;
+ /*
+ * credMap is for authentication manager required
+ * credential names (authCred) mapping to the
+ * client message credentail names (msgCred)
+ * e.g.
+ * auths.instance.ldap1.ui.id.UID.credMap.authCred=uid
+ * auths.instance.ldap1.ui.id.UID.credMap.msgCred=screen_name
+ * auths.instance.ldap1.ui.id.PASSWORD.credMap.authCred=pwd
+ * auths.instance.ldap1.ui.id.PASSWORD.credMap.msgCred=password
+ */
+ private HashMap<String, String> credMap_login;
+ private HashMap<String, String> credMap_extlogin;
+
+ // retries if the user entered the wrong password/securid
+ private int maxLoginRetries = 1;
+
+ private String authCredName;
+
+ /*
+ * Authentication constructor
+ * @param authId authentication instance id
+ */
+ public TPSAuthenticator(String authId)
+ throws EBaseException {
+ id = authId;
+ // retrieves and set authentication manager
+ IAuthSubsystem authSub =
+ (IAuthSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_AUTH);
+ authManager = authSub.getAuthManager(authId);
+ uiTitle = new HashMap<String, String>();
+ uiDescription = new HashMap<String, String>();
+ uiParameters = new HashMap<String, AuthUIParameter>();
+ credMap_login = new HashMap<String, String>();
+ credMap_extlogin = new HashMap<String, String>();
+ }
+
+ public String getID() {
+ return id;
+ }
+
+ public IAuthManager getAuthManager() {
+ return authManager;
+ }
+
+ public void setUiTitle(String locale, String title) {
+ uiTitle.put(locale, title);
+ }
+
+ public String getUiTitle(String locale) {
+ return uiTitle.get(locale);
+ }
+
+ public void setUiDescription(String locale, String desc) {
+ uiDescription.put(locale, desc);
+ }
+
+ public String getUiDescription(String locale) {
+ return uiDescription.get(locale);
+ }
+
+ public void setUiParam(String id, AuthUIParameter up) {
+ uiParameters.put(id, up);
+ }
+
+ public AuthUIParameter getUiParam(String id) {
+ return uiParameters.get(id);
+ }
+
+ public HashMap<String, AuthUIParameter> getUiParamSet() {
+ return uiParameters;
+ }
+
+ public void setCredMap(String authCred, String msgCred, boolean extLogin) {
+ if (extLogin)
+ credMap_extlogin.put(authCred, msgCred);
+ else
+ credMap_login.put(authCred, msgCred);
+ }
+
+ public String getCredMap(String authCred, boolean extLogin) {
+ if (extLogin)
+ return credMap_extlogin.get(authCred);
+ else
+ return credMap_login.get(authCred);
+ }
+
+ public int getNumOfRetries() {
+ return maxLoginRetries;
+ }
+
+ public void setNumOfRetries(int num) {
+ maxLoginRetries = num;
+ }
+
+ public String getAuthCredName() {
+ return authCredName;
+ }
+
+ public void setAuthCredName(String authCredName) {
+ this.authCredName = authCredName;
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java b/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java
new file mode 100644
index 000000000..7c3a01ba7
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java
@@ -0,0 +1,1045 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps.channel;
+
+import java.io.IOException;
+
+import org.dogtagpki.server.tps.processor.TPSProcessor;
+import org.dogtagpki.tps.apdu.APDU;
+import org.dogtagpki.tps.apdu.APDUResponse;
+import org.dogtagpki.tps.apdu.CreateObjectAPDU;
+import org.dogtagpki.tps.apdu.CreatePinAPDU;
+import org.dogtagpki.tps.apdu.DeleteFileAPDU;
+import org.dogtagpki.tps.apdu.ExternalAuthenticateAPDU;
+import org.dogtagpki.tps.apdu.ExternalAuthenticateAPDU.SecurityLevel;
+import org.dogtagpki.tps.apdu.GenerateKeyAPDU;
+import org.dogtagpki.tps.apdu.GenerateKeyECCAPDU;
+import org.dogtagpki.tps.apdu.ImportKeyEncAPDU;
+import org.dogtagpki.tps.apdu.InstallAppletAPDU;
+import org.dogtagpki.tps.apdu.InstallLoadAPDU;
+import org.dogtagpki.tps.apdu.LifecycleAPDU;
+import org.dogtagpki.tps.apdu.LoadFileAPDU;
+import org.dogtagpki.tps.apdu.PutKeyAPDU;
+import org.dogtagpki.tps.apdu.ReadObjectAPDU;
+import org.dogtagpki.tps.apdu.SetIssuerInfoAPDU;
+import org.dogtagpki.tps.apdu.SetPinAPDU;
+import org.dogtagpki.tps.apdu.WriteObjectAPDU;
+import org.dogtagpki.tps.main.TPSBuffer;
+import org.dogtagpki.tps.main.TPSException;
+import org.dogtagpki.tps.main.Util;
+import org.dogtagpki.tps.msg.EndOpMsg.TPSStatus;
+import org.mozilla.jss.pkcs11.PK11SymKey;
+
+import sun.security.pkcs11.wrapper.PKCS11Constants;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+
+public class SecureChannel {
+
+ // Have not written all code to use all of these as of yet.
+
+ private TPSProcessor processor;
+ private PK11SymKey sessionKey;
+ private PK11SymKey encSessionKey;
+ private TPSBuffer drmDesKey;
+ private TPSBuffer kekDesKey;
+ private TPSBuffer keyCheck;
+ private TPSBuffer keyDiversificationData;
+ private TPSBuffer cardChallenge;
+ private TPSBuffer cardCryptogram;
+ private TPSBuffer hostChallenge;
+ private TPSBuffer hostCryptogram;
+ private TPSBuffer icv;
+ private TPSBuffer keyInfoData;
+ private SecurityLevel secLevel;
+
+ public enum TokenKeyType {
+ KEY_TYPE_ENCRYPTION,
+ KEY_TYPE_SIGNING,
+ KEY_TYPE_SIGNING_AND_ENCRYPTION
+ }
+
+ public SecureChannel(TPSProcessor processor, PK11SymKey sessionKey, PK11SymKey encSessionKey, TPSBuffer drmDesKey,
+ TPSBuffer kekDesKey, TPSBuffer keyCheck, TPSBuffer keyDiversificationData, TPSBuffer cardChallenge,
+ TPSBuffer cardCryptogram, TPSBuffer hostChallenge, TPSBuffer hostCryptogram, TPSBuffer keyInfoData)
+ throws TPSException {
+
+ if (processor == null || sessionKey == null | encSessionKey == null || keyDiversificationData == null
+ || cardChallenge == null || cardCryptogram == null || hostChallenge == null || hostCryptogram == null
+ || keyInfoData == null) {
+ throw new TPSException("SecureChannel.SecureChannel: Invalid data in constructor!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ this.processor = processor;
+ this.sessionKey = sessionKey;
+ this.encSessionKey = encSessionKey;
+ this.drmDesKey = drmDesKey;
+ this.setKekDesKey(kekDesKey);
+ this.keyCheck = keyCheck;
+ this.keyDiversificationData = keyDiversificationData;
+ this.cardChallenge = cardChallenge;
+ this.cardCryptogram = cardCryptogram;
+ this.hostChallenge = hostChallenge;
+ this.hostCryptogram = hostCryptogram;
+ this.icv = new TPSBuffer(8);
+ this.keyInfoData = keyInfoData;
+
+ this.secLevel = SecurityLevel.SECURE_MSG_MAC_ENC;
+ //ToDo: Write method that reads this from the config
+
+ }
+
+ public static void main(String[] args) {
+ }
+
+ public void appendPKCS11Attribute(TPSBuffer buffer, long type, TPSBuffer attribute) {
+
+ buffer.addLong4Bytes(type);
+
+ buffer.addInt2Bytes(attribute.size());
+ buffer.add(attribute);
+ }
+
+ public void appendKeyCapabilities(TPSBuffer buffer, String keyTypePrefix, String keyType) throws TPSException {
+
+ if (buffer == null || keyTypePrefix == null || keyType == null) {
+ throw new TPSException("SecureChannel.appdndKeyCabalities: Invalid input datat.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ IConfigStore configStore = CMS.getConfigStore();
+
+ final String keyCapabilities = "keyCapabilities";
+
+ try {
+
+ boolean value = false;
+ String configName = keyTypePrefix + "." + keyType + "." + keyCapabilities + "." + "encrypt";
+
+ value = configStore.getBoolean(configName);
+
+ TPSBuffer attr = new TPSBuffer(Util.bool2Byte(value));
+ appendPKCS11Attribute(buffer, PKCS11Constants.CKA_ENCRYPT, attr);
+
+ configName = keyTypePrefix + "." + keyType + "." + keyCapabilities + "." + "sign";
+ value = configStore.getBoolean(configName);
+ attr = new TPSBuffer(Util.bool2Byte(value));
+ appendPKCS11Attribute(buffer, PKCS11Constants.CKA_SIGN, attr);
+
+ configName = keyTypePrefix + "." + keyType + "." + keyCapabilities + "." + "signRecover";
+ value = configStore.getBoolean(configName);
+ attr = new TPSBuffer(Util.bool2Byte(value));
+ appendPKCS11Attribute(buffer, PKCS11Constants.CKA_SIGN_RECOVER, attr);
+
+ configName = keyTypePrefix + "." + keyType + "." + keyCapabilities + "." + "decrypt";
+ value = configStore.getBoolean(configName);
+ attr = new TPSBuffer(Util.bool2Byte(value));
+ appendPKCS11Attribute(buffer, PKCS11Constants.CKA_DECRYPT, attr);
+
+ configName = keyTypePrefix + "." + keyType + "." + keyCapabilities + "." + "derive";
+ value = configStore.getBoolean(configName);
+ attr = new TPSBuffer(Util.bool2Byte(value));
+ appendPKCS11Attribute(buffer, PKCS11Constants.CKA_DERIVE, attr);
+
+ configName = keyTypePrefix + "." + keyType + "." + keyCapabilities + "." + "unwrap";
+ value = configStore.getBoolean(configName);
+ attr = new TPSBuffer(Util.bool2Byte(value));
+ appendPKCS11Attribute(buffer, PKCS11Constants.CKA_UNWRAP, attr);
+
+ configName = keyTypePrefix + "." + keyType + "." + keyCapabilities + "." + "wrap";
+ value = configStore.getBoolean(configName);
+ attr = new TPSBuffer(Util.bool2Byte(value));
+ appendPKCS11Attribute(buffer, PKCS11Constants.CKA_WRAP, attr);
+
+ configName = keyTypePrefix + "." + keyType + "." + keyCapabilities + "." + "verifyRecover";
+ value = configStore.getBoolean(configName);
+ attr = new TPSBuffer(Util.bool2Byte(value));
+ appendPKCS11Attribute(buffer, PKCS11Constants.CKA_VERIFY_RECOVER, attr);
+
+ configName = keyTypePrefix + "." + keyType + "." + keyCapabilities + "." + "verify";
+ value = configStore.getBoolean(configName);
+ attr = new TPSBuffer(Util.bool2Byte(value));
+ appendPKCS11Attribute(buffer, PKCS11Constants.CKA_VERIFY, attr);
+
+ configName = keyTypePrefix + "." + keyType + "." + keyCapabilities + "." + "sensitive";
+ value = configStore.getBoolean(configName);
+ attr = new TPSBuffer(Util.bool2Byte(value));
+ appendPKCS11Attribute(buffer, PKCS11Constants.CKA_SENSITIVE, attr);
+
+ configName = keyTypePrefix + "." + keyType + "." + keyCapabilities + "." + "private";
+ value = configStore.getBoolean(configName);
+ attr = new TPSBuffer(Util.bool2Byte(value));
+ appendPKCS11Attribute(buffer, PKCS11Constants.CKA_PRIVATE, attr);
+
+ configName = keyTypePrefix + "." + keyType + "." + keyCapabilities + "." + "token";
+ value = configStore.getBoolean(configName);
+ attr = new TPSBuffer(Util.bool2Byte(value));
+ appendPKCS11Attribute(buffer, PKCS11Constants.CKA_TOKEN, attr);
+
+ CMS.debug("SecureChannel.appendKeyCapabilities: returning: " + buffer.toHexString());
+
+ } catch (EBaseException e) {
+ throw new TPSException("SecureChannel.appentKeyCapabilities. Can't obtain config value!",
+ TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+ }
+ }
+
+ public void externalAuthenticate() throws TPSException, IOException {
+
+ CMS.debug("SecureChannel.externalAuthenticate: entering.");
+
+ ExternalAuthenticateAPDU externalAuth = new ExternalAuthenticateAPDU(hostCryptogram,
+ secLevel);
+
+ computeAPDUMac(externalAuth);
+
+ APDUResponse response = processor.handleAPDURequest(externalAuth);
+
+ if (!response.checkResult()) {
+ throw new TPSException("SecureChannel.eternalAuthenticate. Failed to external authenticate to token.",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ CMS.debug("SecureChannel.externalAuthenticate: Successfully completed, exiting ...");
+
+ }
+
+ //This method computes the mac AND encryption if needed.
+ private void computeAPDU(APDU apdu) throws TPSException {
+
+ CMS.debug("SecureChannel.computeAPDU: entering..");
+
+ if (apdu == null) {
+ throw new TPSException("SecureChannel.computeAPDU: bad input apdu!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ computeAPDUMac(apdu);
+
+ if (secLevel == SecurityLevel.SECURE_MSG_MAC_ENC) {
+ try {
+ // CMS.debug("SecureChannel.computeAPDU: Before encryption data value: " + apdu.getData().toHexString());
+ apdu.secureMessage(encSessionKey);
+ // CMS.debug("SecureChannel.computeAPDU: After encryption data value: " + apdu.getData().toHexString());
+ } catch (EBaseException e) {
+ throw new TPSException("SecureChannel.computeAPDU: Can't encrypt outgoing data! " + e);
+ }
+
+ CMS.debug("SecureChannel.computeAPDU: Successfully encrypted apdu data.");
+ }
+ }
+
+ // This method computes MAC only.
+ private void computeAPDUMac(APDU apdu) throws TPSException {
+ TPSBuffer newMac = null;
+ TPSBuffer data = null;
+
+ if (apdu == null) {
+ throw new TPSException("SecureChannel.computeAPDUMac: bad input apdu!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ data = apdu.getDataToMAC();
+
+ CMS.debug("SecureChannel.computeAPDUMac: data To MAC: " + data.toHexString());
+
+ try {
+ newMac = Util.computeMAC(sessionKey, data, icv);
+ } catch (EBaseException e) {
+ CMS.debug("SecureChannel.compuatAPDUMac: Can't compute mac. " + e);
+ throw new TPSException("SecureChannel.compuatAPDUMac: Can't compute mac.",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ CMS.debug("SecureChannel.computeAPDUMac: computed MAC: " + newMac.toHexString());
+
+ apdu.setMAC(newMac);
+
+ icv.set(newMac);
+ }
+
+ public void deleteFileX(TPSBuffer aid) throws TPSException, IOException {
+ CMS.debug("SecureChannel.deleteFileX: entering...");
+ if (aid == null) {
+ throw new TPSException("SecureChannel.deleteFileX: no input aid!");
+ }
+
+ DeleteFileAPDU deleteFile = new DeleteFileAPDU(aid);
+
+ computeAPDU(deleteFile);
+
+ processor.handleAPDURequest(deleteFile);
+
+ }
+
+ // Begin process of loading applet onto token.
+ public void installLoad(TPSBuffer packageAID, TPSBuffer sdAID, int fileLength) throws TPSException, IOException {
+
+ CMS.debug("SecureChannel.installLoad: entering ...");
+
+ if (packageAID == null || sdAID == null || fileLength <= 0) {
+ throw new TPSException("SecureChannel.insallLoad bad input parameters!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ InstallLoadAPDU install = new InstallLoadAPDU(packageAID, sdAID, fileLength);
+
+ CMS.debug("SecureChannel.installLoad: Pre computed apdu: " + install.getEncoding().toHexString());
+
+ computeAPDU(install);
+
+ APDUResponse response = processor.handleAPDURequest(install);
+
+ if (!response.checkResult()) {
+ throw new TPSException("SecureChannel.installLoad. Failed to perform installLoad operation.",
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ }
+
+ }
+
+ //Actually load applet file onto the token.
+
+ public void loadFile(TPSBuffer programFile, int blockSize, int startProgress, int endProgress) throws TPSException,
+ IOException {
+ CMS.debug("SecureChannel.loadFile entering...");
+
+ if (programFile == null || blockSize <= 0) {
+ throw new TPSException("ScureChannel.loadFile. Bad input data.", TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ }
+
+ TPSBuffer length = null;
+
+ TPSBuffer tag = new TPSBuffer(1, (byte) 0xC4);
+
+ int progSize = programFile.size();
+
+ if (progSize < 128) {
+ length = new TPSBuffer(1, (byte) progSize);
+ } else if (progSize <= 255) {
+ length = new TPSBuffer(1, (byte) 0x81);
+ length.add((byte) progSize);
+ } else {
+ length = new TPSBuffer(1, (byte) 0x82);
+ length.add((byte) ((progSize >> 8) & 0xff));
+ length.add((byte) (progSize & 0xff));
+
+ }
+
+ TPSBuffer tbsProgramFile = new TPSBuffer(tag);
+ tbsProgramFile.add(length);
+ tbsProgramFile.add(programFile);
+
+ int totalLen = tbsProgramFile.size();
+ int sizeToSend = totalLen;
+
+ int finalBlockSize = 0;
+ float progressBlockSize = 0;
+
+ if (secLevel == SecurityLevel.SECURE_MSG_MAC_ENC) {
+ // need leave room for possible encryption padding
+ finalBlockSize = blockSize - 0x10;
+ } else {
+ finalBlockSize = blockSize - 8;
+ }
+
+ //rough number is good enough
+ int numLoops = sizeToSend / blockSize;
+
+ if (numLoops == 0) { // We have bogus data here. Good bye.
+ throw new TPSException("SecureChannel.loadFile. Bad input data.", TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ }
+ progressBlockSize = (float) (endProgress - startProgress) / numLoops;
+
+ int count = 0;
+ byte refControl = 0x00;
+
+ do {
+ if (sizeToSend < finalBlockSize) {
+ finalBlockSize = sizeToSend;
+ refControl = (byte) 0x80;
+
+ }
+
+ CMS.debug("SecureChannel.loadFile: taking data substring from: " + (totalLen - sizeToSend) + " size: "
+ + finalBlockSize + " to: " + ((totalLen - sizeToSend) + finalBlockSize));
+
+ TPSBuffer piece = tbsProgramFile.substr(totalLen - sizeToSend, finalBlockSize);
+
+ CMS.debug("SecureChannel.loadFile: attempting to send piece: " + sizeToSend);
+
+ loadFileSegment(refControl, count, piece);
+
+ if (processor.requiresStatusUpdate()) {
+ processor.statusUpdate(startProgress + (int) (count * progressBlockSize), "PROGRESS_APPLET_BLOCK");
+ }
+
+ sizeToSend -= finalBlockSize;
+
+ count++;
+
+ } while (sizeToSend > 0);
+
+ }
+
+ //Load one piece of the applet file onto the token.
+ private void loadFileSegment(byte refControl, int count, TPSBuffer piece) throws TPSException, IOException {
+
+ if (piece == null || count < 0) {
+ throw new TPSException("SecureChannel.loadFileSegment: invalid input data.",
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ }
+
+ LoadFileAPDU loadFile = new LoadFileAPDU(refControl, (byte) count, piece);
+
+ computeAPDU(loadFile);
+
+ APDUResponse response = processor.handleAPDURequest(loadFile);
+
+ if (!response.checkResult()) {
+ throw new TPSException(
+ "SecureChannel.loadFileSegment. Failed to perform loadFileSegmentInstallLoad operation.",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ }
+
+ // Kick off the applet loading process.
+ public void installApplet(TPSBuffer netkeyPAIDBuff, TPSBuffer netkeyAIDBuff, byte appPrivileges,
+ int channelInstanceSize,
+ int channelAppletMemSize) throws TPSException, IOException {
+
+ CMS.debug("SecureChannel.installApplet: entering...");
+
+ // Would be tough to put a check on the various input sizes, let the applet
+ // decide if the values are appropriate for channelInstanceSize and channelAppletMemSize
+
+ if (netkeyPAIDBuff == null || netkeyAIDBuff == null || channelInstanceSize < 0 || channelAppletMemSize < 0) {
+ throw new TPSException("SecureChannel.installApplet. Invalid input parameters!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+
+ }
+
+ InstallAppletAPDU install = new InstallAppletAPDU(netkeyPAIDBuff, netkeyAIDBuff, appPrivileges,
+ channelInstanceSize, channelAppletMemSize);
+
+ computeAPDU(install);
+
+ APDUResponse response = processor.handleAPDURequest(install);
+
+ if (!response.checkResult()) {
+ throw new TPSException("SecureChannel.installApplett. Failed installApplet operation.",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ }
+
+ // Burn the phone home URL into the token.
+ public void setIssuerInfo(TPSBuffer issuerInfoBuff) throws TPSException, IOException {
+ CMS.debug("SecureChannel.setIssuerInfo entering...");
+
+ final int finalIssuerLength = 224;
+ final int approxMinUrlSize = 5;
+
+ if (issuerInfoBuff == null || issuerInfoBuff.size() < approxMinUrlSize) {
+ throw new TPSException("SecureChannel.setIssuerInfo: Invalid input data.",
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ }
+
+ int issuerLen = issuerInfoBuff.size();
+
+ int paddingLen = finalIssuerLength - issuerLen;
+
+ TPSBuffer paddingBuff = new TPSBuffer(paddingLen, (byte) 0x0);
+
+ TPSBuffer finalIssuerBuff = new TPSBuffer(issuerInfoBuff);
+
+ finalIssuerBuff.add(paddingBuff);
+
+ CMS.debug("finalIssuerBuff len: " + finalIssuerBuff.size() + " issuerInfo: " + finalIssuerBuff.toString());
+ SetIssuerInfoAPDU setIssuer = new SetIssuerInfoAPDU((byte) 0x0, (byte) 0x0, finalIssuerBuff);
+
+ computeAPDU(setIssuer);
+
+ APDUResponse response = processor.handleAPDURequest(setIssuer);
+
+ if (!response.checkResult()) {
+ throw new TPSException("SecureChannel.setIssuerInfo. Failed to set issuer info!",
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ }
+
+ CMS.debug("SecureChannel.setIssuerInfo: leaving...");
+
+ }
+
+ public TPSBuffer getKeyDiversificationData() {
+ return keyDiversificationData;
+ }
+
+ public TPSBuffer getCardChallenge() {
+ return cardChallenge;
+ }
+
+ public TPSBuffer getHostChallenge() {
+ return hostChallenge;
+ }
+
+ public TPSBuffer getHostCryptogram() {
+ return hostCryptogram;
+ }
+
+ public TPSBuffer getCardCryptogram() {
+ return cardCryptogram;
+ }
+
+ public TPSBuffer getKeyInfoData() {
+ return keyInfoData;
+ }
+
+ public void writeObject(TPSBuffer objectID, TPSBuffer objectData) throws TPSException, IOException {
+ CMS.debug("SecureChannel.writeObject: entering ...");
+
+ if (objectID == null || objectData == null) {
+ throw new TPSException("SecureChannel.writeObject: invalid input data.");
+ }
+
+ final int MAX_WRITE_SIZE = 0xd0;
+
+ int offset = 0;
+ int toSend = objectData.size();
+ int blockSize = 0;
+
+ boolean moreToGo = true;
+ do {
+
+ if (toSend > MAX_WRITE_SIZE) {
+ blockSize = MAX_WRITE_SIZE;
+ } else {
+ blockSize = toSend;
+ }
+
+ TPSBuffer blockToSend = objectData.substr(offset, blockSize);
+
+ WriteObjectAPDU write = new WriteObjectAPDU(objectID.toBytesArray(), offset, blockToSend);
+
+ computeAPDU(write);
+
+ APDUResponse response = processor.handleAPDURequest(write);
+
+ if (!response.checkResult()) {
+ CMS.debug("SecureChannel.writeObject: bad apdu return!");
+ //Throw this return code because this happens during enrollment and we don't have
+ // a more specific error code.
+ throw new TPSException("SecureChannel.writeObject. Failed in middle of writeObject.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ offset += blockSize;
+ toSend -= blockSize;
+
+ if (toSend <= 0) {
+ moreToGo = false;
+ }
+
+ } while (moreToGo);
+
+ }
+
+ public TPSBuffer readObject(TPSBuffer objectID, int offset, int len) throws TPSException, IOException {
+
+ CMS.debug("SecureChannel.readObject: entering ...");
+
+ if (objectID == null || len == 0) {
+ throw new TPSException("SecureChannel.readObject: invalid input data.",
+ TPSStatus.STATUS_ERROR_READ_OBJECT_PDU);
+ }
+
+ final int MAX_READ_BUFFER_SIZE = 0xd0;
+
+ ReadObjectAPDU read = null;
+ TPSBuffer result = new TPSBuffer();
+
+ int cur_read = 0;
+ int cur_offset = 0;
+ int sum = 0;
+
+ if (len > MAX_READ_BUFFER_SIZE) {
+ cur_offset = offset;
+ cur_read = MAX_READ_BUFFER_SIZE;
+ } else {
+ cur_offset = offset;
+ cur_read = len;
+ }
+
+ while (sum < len) {
+
+ read = new ReadObjectAPDU(objectID.toBytesArray(), cur_offset, cur_read);
+ computeAPDU(read);
+
+ APDUResponse response = processor.handleAPDURequest(read);
+
+ if (!response.checkResult()) {
+ CMS.debug("SecureChannel.readObject: bad apdu return!");
+ throw new TPSException("SecureChannel.installApplett. Failed in middle of readObject.",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ TPSBuffer resp = response.getResultDataNoCode();
+
+ result.add(resp);
+
+ sum += resp.size();
+ cur_offset += resp.size();
+
+ if ((len - sum) < MAX_READ_BUFFER_SIZE) {
+ cur_read = len - sum;
+ } else {
+ cur_read = MAX_READ_BUFFER_SIZE;
+ }
+
+ }
+
+ return result;
+ }
+
+ public void createObject(TPSBuffer objectID, TPSBuffer permissions, TPSBuffer object) throws TPSException,
+ IOException {
+
+ CMS.debug("SecureChannel.createObject: with full object. entering...");
+
+ if (objectID == null || permissions == null || object == null) {
+ throw new TPSException("SecureChannel.createObject, with full object. Bad input data.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+
+ }
+
+ createObject(objectID, permissions, object.size());
+
+ writeObject(objectID, object);
+
+ }
+
+ public void createCertificate(TPSBuffer objectID, TPSBuffer cert) throws TPSException, IOException {
+ CMS.debug("SecureChannel.createCertificate: entering...");
+
+ if (objectID == null || cert == null) {
+ throw new TPSException("SecureChannel.createCertificate. Bad input data.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ byte[] perms = { (byte) 0xff, (byte) 0xff, 0x40, 0x00, 0x40, 0x00 };
+
+ TPSBuffer permissions = new TPSBuffer(perms);
+
+ createObject(objectID, permissions, cert);
+
+ }
+
+ public void createPKCS11CertAttrs(TokenKeyType keyType, String id, String label, TPSBuffer keyid)
+ throws TPSException, IOException {
+
+ TPSBuffer buffer = createPKCS11CertAttrsBuffer(keyType, id, label, keyid);
+
+ byte[] perms = { (byte) 0xff, (byte) 0xff, 0x40, 0x00, 0x40, 0x00 };
+
+ TPSBuffer permissions = new TPSBuffer(perms);
+
+ createObject(new TPSBuffer(id), permissions, buffer);
+
+ }
+
+ public TPSBuffer createPKCS11PriKeyAttrsBuffer(String id, String label, TPSBuffer keyid,
+ TPSBuffer modulus, String keyTypePrefix) throws TPSException {
+
+ TPSBuffer result = new TPSBuffer();
+
+ CMS.debug("SecureChannel.createPKCS11PriKeyAttrsBuffer: entering...");
+
+ if (id == null || label == null || keyid == null || modulus == null || keyTypePrefix == null) {
+ throw new TPSException("SecureChannel.craetePKCS11PriKeyAttrsBuffer: invalid input data.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ CMS.debug("SecureChannel.createPKCS11PriKeyAttrsBuffer: id: " + id + " label: " + label + " keyid: "
+ + keyid.toHexString());
+
+ byte keytype[] = { 0, 0, 0, 0 };
+ byte p11class[] = { 3, 0, 0, 0 };
+
+ appendPKCS11Attribute(result, PKCS11Constants.CKA_MODULUS, modulus);
+ appendPKCS11Attribute(result, PKCS11Constants.CKA_KEY_TYPE, new TPSBuffer(keytype));
+ appendPKCS11Attribute(result, PKCS11Constants.CKA_CLASS, new TPSBuffer(p11class));
+ appendPKCS11Attribute(result, PKCS11Constants.CKA_ID, keyid);
+ appendKeyCapabilities(result, keyTypePrefix, "private");
+
+ finalizeObjectBuffer(result, id);
+
+ CMS.debug("SecureChannel.createPKCS11PriKeyAttrsBuffer: returing: " + result.toHexString());
+
+ return result;
+
+ }
+
+ public void createPKCS11PriKeyAttrs(String id, String label, TPSBuffer keyid,
+ TPSBuffer modulus, String keyTypePrefix) throws TPSException, IOException {
+
+ CMS.debug("SecureChannel.createPKCS11PriKeyAttrsBuffer: entering...");
+
+ if (id == null || label == null || keyid == null || modulus == null || keyTypePrefix == null) {
+ throw new TPSException("SecureChannel.craetePKCS11PriKeyAttrsBuffer: invalid input data.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ TPSBuffer buffer = createPKCS11PriKeyAttrsBuffer(id, label, keyid, modulus, keyTypePrefix);
+
+ byte[] perms = { (byte) 0xff, (byte) 0xff, 0x40, 0x00, 0x40, 0x00 };
+
+ TPSBuffer permissions = new TPSBuffer(perms);
+
+ createObject(new TPSBuffer(id), permissions, buffer);
+ }
+
+ public TPSBuffer createPKCS11PublicKeyAttrsBuffer(String id, String label, TPSBuffer keyid,
+ TPSBuffer modulus, TPSBuffer exponent, String keyTypePrefix) throws TPSException {
+
+ TPSBuffer result = new TPSBuffer();
+ CMS.debug("SecureChannel.createPKCS11PublicKeyAttrsBuffer: entering...");
+
+ if (id == null || label == null || keyid == null || modulus == null || exponent == null
+ || keyTypePrefix == null) {
+ throw new TPSException("SecureChannel.craetePKCS11PublicKeyAttrsBuffer: invalid input data.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ byte p11class[] = { 2, 0, 0, 0 };
+
+ appendPKCS11Attribute(result, PKCS11Constants.CKA_PUBLIC_EXPONENT, exponent);
+ appendPKCS11Attribute(result, PKCS11Constants.CKA_MODULUS, modulus);
+ appendPKCS11Attribute(result, PKCS11Constants.CKA_ID, keyid);
+ appendPKCS11Attribute(result, PKCS11Constants.CKA_CLASS, new TPSBuffer(p11class));
+ appendKeyCapabilities(result, keyTypePrefix, "public");
+
+ finalizeObjectBuffer(result, id);
+
+ CMS.debug("SecureChannel.createPKCS11PublicKeyAttrsBuffer: returing: " + result.toHexString());
+
+ return result;
+
+ }
+
+ public void createPKCS11PublicKeyAttrs(String id, String label, TPSBuffer keyid,
+ TPSBuffer modulus, TPSBuffer exponent, String keyTypePrefix) throws TPSException, IOException {
+
+ CMS.debug("SecureChannel.createPKCS11PublicKeyAttrsBuffer: entering...");
+
+ if (id == null || label == null || keyid == null || modulus == null || exponent == null
+ || keyTypePrefix == null) {
+ throw new TPSException("SecureChannel.craetePKCS11PriKeyAttrsBuffer: invalid input data.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ TPSBuffer buffer = createPKCS11PriKeyAttrsBuffer(id, label, keyid, modulus, keyTypePrefix);
+
+ byte[] perms = { (byte) 0xff, (byte) 0xff, 0x40, 0x00, 0x40, 0x00 };
+
+ TPSBuffer permissions = new TPSBuffer(perms);
+
+ createObject(new TPSBuffer(id), permissions, buffer);
+
+ }
+
+ public void finalizeObjectBuffer(TPSBuffer buffer, String id) {
+
+ TPSBuffer header = new TPSBuffer();
+
+ header.add((byte) 0);
+ header.add((byte) id.charAt(0));
+ header.add((byte) id.charAt(1));
+ header.add((byte) 0);
+ header.add((byte) 0);
+
+ header.add((byte) ((buffer.size()) / 256));
+ header.add((byte) ((buffer.size()) % 256));
+
+ buffer.prepend(header);
+
+ }
+
+ public TPSBuffer createPKCS11CertAttrsBuffer(TokenKeyType keyType, String id, String label, TPSBuffer keyid)
+ throws TPSException {
+
+ CMS.debug("SecureChannel.createPKCS11CertAttrsBuffer: entering... id: " + id);
+ if (keyType == null || id == null || label == null || keyid == null) {
+ throw new TPSException("SecureChannel.createPKCS11CertAttrsBuffer. Bad input data.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+
+ }
+
+ CMS.debug("SecureChannel.createPKCS11CertAttrsBuffer: ... id: " + id + " label: " + label + " keyid: "
+ + keyid.toHexString());
+
+ byte[] type = { 0x0, 0x0, 0x0, 0x0 };
+ byte[] p11class = { 0x1, 0x0, 0x0, 0x0 };
+ byte[] tokenFlag = { 0x1 };
+
+ TPSBuffer result = new TPSBuffer();
+
+ CMS.debug("SecureChannel.createPKCS11CertAttrsBuffer: label: " + label + " label bytes: "
+ + (new TPSBuffer(label)).toHexString());
+
+ appendPKCS11Attribute(result, PKCS11Constants.CKA_LABEL, new TPSBuffer(label.getBytes()));
+ appendPKCS11Attribute(result, PKCS11Constants.CKA_ID, keyid);
+ appendPKCS11Attribute(result, PKCS11Constants.CKA_CERTIFICATE_TYPE, new TPSBuffer(type));
+ appendPKCS11Attribute(result, PKCS11Constants.CKA_CLASS, new TPSBuffer(p11class));
+ appendPKCS11Attribute(result, PKCS11Constants.CKA_TOKEN, new TPSBuffer(tokenFlag));
+
+ finalizeObjectBuffer(result, id);
+
+ CMS.debug("SecureChannel.createPKCS11CertAttrsBuffer: returing: " + result.toHexString());
+
+ return result;
+
+ }
+
+ public void createObject(TPSBuffer objectID, TPSBuffer permissions, int len) throws TPSException, IOException {
+
+ CMS.debug("SecureChannel.createObject: entering...");
+ if (objectID == null || permissions == null || len <= 0) {
+ throw new TPSException("SecureChannel.createObject. Bad input data.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ CreateObjectAPDU create = new CreateObjectAPDU(objectID.toBytesArray(), permissions.toBytesArray(), len);
+
+ computeAPDU(create);
+
+ APDUResponse response = processor.handleAPDURequest(create);
+
+ //Throw this return code because this happens during enrollment and we don't have
+ // a more specific error code.
+ if (!response.checkResult()) {
+ throw new TPSException("SecureChannel.createObject. Failed to create object on token.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ }
+
+ public int startEnrollment(int pe1, int pe2, TPSBuffer wrappedChallenge, TPSBuffer keyCheck, int algorithm,
+ int keySize, int option) throws TPSException, IOException {
+
+ if (wrappedChallenge == null) {
+ throw new TPSException("SecureChannel.startEnrollment. Bad input data.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ CMS.debug("SecureChannel.startEnrollment: entering ...");
+
+ boolean isECC = processor.getTPSEngine().isAlgorithmECC(algorithm);
+
+ GenerateKeyAPDU generate_key_apdu = null;
+ GenerateKeyECCAPDU generate_ecc_key_apdu = null;
+
+ APDUResponse response = null;
+ if (isECC) {
+
+ generate_ecc_key_apdu = new GenerateKeyECCAPDU((byte) pe1, (byte) pe2, (byte) algorithm, keySize,
+ (byte) option, (byte) 0, wrappedChallenge, keyCheck);
+
+ computeAPDU(generate_ecc_key_apdu);
+
+ response = processor.handleAPDURequest(generate_ecc_key_apdu);
+
+ if (!response.checkResult()) {
+ throw new TPSException("SecureChannel.startEnrollment. Failed generate key on token.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ } else {
+
+ generate_key_apdu = new GenerateKeyAPDU((byte) pe1, (byte) pe2, (byte) algorithm, keySize,
+ (byte) option, (byte) 0, wrappedChallenge, keyCheck);
+
+ computeAPDU(generate_key_apdu);
+
+ response = processor.handleAPDURequest(generate_key_apdu);
+
+ if (!response.checkResult()) {
+ throw new TPSException("SecureChannel.startEnrollment. Failed generate key on token.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ }
+
+ TPSBuffer data = response.getData();
+
+ int size = data.getIntFrom2Bytes(0);
+
+ CMS.debug("SecureChannel.startEnrollment: returning key size: " + size);
+
+ return size;
+
+ }
+
+ public int tokenTypeToInt(TokenKeyType type) {
+
+ if (type == TokenKeyType.KEY_TYPE_ENCRYPTION)
+ return 0;
+
+ if (type == TokenKeyType.KEY_TYPE_SIGNING)
+ return 1;
+ else
+ return 2;
+ }
+
+ public void setLifeycleState(byte flag) throws TPSException, IOException {
+
+ CMS.debug("SecureChannel.setLifecycleState: flage: " + flag);
+
+ LifecycleAPDU life = new LifecycleAPDU(flag);
+
+ computeAPDU(life);
+
+ APDUResponse response = processor.handleAPDURequest(life);
+
+ if (!response.checkResult()) {
+ throw new TPSException("SecureChannel.setLifecycleState. Failed to set Lifecycle State!.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ }
+
+ public void createPin(int pinNumber, int maxRetries, String pin) throws TPSException, IOException {
+
+ CMS.debug("SecureChannel.createPin: entering...");
+
+ if (pin == null) {
+ throw new TPSException("SecureChannel.createPin: invalid intput data.",
+ TPSStatus.STATUS_ERROR_TOKEN_RESET_PIN_FAILED);
+ }
+
+ TPSBuffer pinBuf = new TPSBuffer(pin.getBytes());
+ CreatePinAPDU create = new CreatePinAPDU((byte) pinNumber, (byte) maxRetries, pinBuf);
+
+ computeAPDU(create);
+
+ @SuppressWarnings("unused")
+ APDUResponse response = processor.handleAPDURequest(create);
+
+ //If the pin already exists we may get an error here, but we go on.
+
+ }
+
+ public void resetPin(int pinNumber, String new_pin) throws TPSException, IOException {
+
+ CMS.debug("SecureChannel.resetPin");
+
+ if (new_pin == null) {
+ throw new TPSException("SecureChannel.resetPin: invalid intput data.",
+ TPSStatus.STATUS_ERROR_TOKEN_RESET_PIN_FAILED);
+ }
+
+ TPSBuffer newPinBuf = new TPSBuffer(new_pin.getBytes());
+
+ SetPinAPDU reset = new SetPinAPDU((byte) 0x0, (byte) 0x0, newPinBuf);
+
+ computeAPDU(reset);
+
+ APDUResponse response = processor.handleAPDURequest(reset);
+
+ if (!response.checkResult()) {
+ throw new TPSException("SecureChannel.resetPin: failed to reset pin.",
+ TPSStatus.STATUS_ERROR_TOKEN_RESET_PIN_FAILED);
+ }
+
+ }
+
+ public void putKeys(byte curVersion, byte curIndex, TPSBuffer keySetData) throws TPSException, IOException {
+
+ CMS.debug("SecureChannel.putKeys: entering..");
+
+ if (keySetData == null) {
+ throw new TPSException("SecureChannel.putKeys: Invalid input data!", TPSStatus.STATUS_ERROR_KEY_CHANGE_OVER);
+ }
+
+ byte keyVersion = curVersion;
+
+ if (curVersion == 0xff) {
+ keyVersion = 0x0;
+ }
+
+ PutKeyAPDU putKey = new PutKeyAPDU(keyVersion, (byte) (0x80 | curIndex), keySetData);
+
+ computeAPDU(putKey);
+
+ APDUResponse response = processor.handleAPDURequest(putKey);
+
+ if (!response.checkResult()) {
+ throw new TPSException("SecureChannel.putKeys: failed to upgrade key set!",
+ TPSStatus.STATUS_ERROR_KEY_CHANGE_OVER);
+ }
+
+ }
+
+ public TPSBuffer getDRMWrappedDesKey() {
+ return drmDesKey;
+ }
+
+ public void setDRMWrappedDesKey(TPSBuffer drmDesKey) {
+ this.drmDesKey = drmDesKey;
+ }
+
+ public TPSBuffer getKeyCheck() {
+ return keyCheck;
+ }
+
+ public void setKeyCheck(TPSBuffer theKeyCheck) {
+ this.keyCheck = theKeyCheck;
+ }
+
+ public void importKeyEnc(int pe1, int pe2, TPSBuffer data) throws TPSException, IOException {
+
+ CMS.debug("SecureChannel.importKeyEnc entering...");
+
+ if(data == null) {
+ throw new TPSException("SecureChannel.importKeyEnc: Invalid input data!",TPSStatus.STATUS_ERROR_MAC_CERT_PDU);
+ }
+
+ ImportKeyEncAPDU importKeyEnc = new ImportKeyEncAPDU((byte)pe1,(byte) pe2, data);
+
+ computeAPDU(importKeyEnc);
+
+ APDUResponse response = processor.handleAPDURequest(importKeyEnc);
+
+ if (!response.checkResult()) {
+ throw new TPSException("SecureChannel.importKeyEnc: failed to import private key!",
+ TPSStatus.STATUS_ERROR_MAC_CERT_PDU);
+ }
+
+ }
+
+ public TPSBuffer getKekDesKey() {
+ return kekDesKey;
+ }
+
+ public void setKekDesKey(TPSBuffer kekDesKey) {
+ this.kekDesKey = kekDesKey;
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/CAEnrollCertResponse.java b/base/tps/src/org/dogtagpki/server/tps/cms/CAEnrollCertResponse.java
new file mode 100644
index 000000000..9c83e0842
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/CAEnrollCertResponse.java
@@ -0,0 +1,52 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import netscape.security.x509.X509CertImpl;
+import java.util.Hashtable;
+
+import org.dogtagpki.server.connector.IRemoteRequest;
+
+/**
+ * CAEnrollCertResponse is the class for the response to
+ * CA Remote Request: enrollCertificate()
+ *
+ */
+public class CAEnrollCertResponse extends RemoteResponse
+{
+ public CAEnrollCertResponse(Hashtable<String, Object> ht) {
+ nameValTable = ht;
+ }
+
+ public String getCertB64() {
+ return (String) nameValTable.get(IRemoteRequest.CA_RESPONSE_Certificate_b64);
+ }
+
+ public String getCertSerialHex() {
+ return (String) nameValTable.get(IRemoteRequest.CA_RESPONSE_Certificate_serial);
+ }
+
+ public String getCertSubjectDN() {
+ return (String) nameValTable.get(IRemoteRequest.CA_RESPONSE_Certificate_SubjectDN);
+ }
+
+ public X509CertImpl getCert() {
+ return (X509CertImpl) nameValTable.get(IRemoteRequest.CA_RESPONSE_Certificate_x509);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java b/base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java
new file mode 100644
index 000000000..5851d2f69
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java
@@ -0,0 +1,760 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CertificateException;
+import java.util.Hashtable;
+import java.util.List;
+
+import netscape.security.x509.RevocationReason;
+import netscape.security.x509.X509CertImpl;
+
+import org.dogtagpki.server.connector.IRemoteRequest;
+import org.dogtagpki.server.tps.TPSSubsystem;
+import org.dogtagpki.server.tps.engine.TPSEngine;
+import org.dogtagpki.tps.main.TPSBuffer;
+import org.dogtagpki.tps.main.Util;
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.CryptoManager.NotInitializedException;
+import org.mozilla.jss.crypto.X509Certificate;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.EPropertyNotFound;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.cmscore.connector.HttpConnector;
+import com.netscape.cmsutil.http.HttpResponse;
+import com.netscape.cmsutil.util.Utils;
+import com.netscape.cmsutil.xml.XMLObject;
+
+/**
+ * CARemoteRequestHandler is a class representing remote requests
+ * offered by the Certificate Authority (CA)
+ *
+ * @author cfu
+ */
+public class CARemoteRequestHandler extends RemoteRequestHandler
+{
+ public CARemoteRequestHandler(String connID)
+ throws EBaseException {
+ if (connID == null) {
+ throw new EBaseException("CARemoteRequestHandler: CARemoteRequestHandler(): connID null.");
+ }
+ connid = connID;
+ }
+
+ /**
+ * enrollCertificate enrolls a certificate in the CA
+ *
+ * @param pubKeybuf public key for enrollment
+ * @param uid uid for enrollment
+ * @param cuid token id
+ *
+ * @returns CAEnrollCertResponse
+ */
+ public CAEnrollCertResponse enrollCertificate(
+ TPSBuffer pubKeybuf,
+ String uid,
+ String cuid,
+ String tokenType,
+ String keyType)
+ throws EBaseException {
+
+ CMS.debug("CARemoteRequestHandler: enrollCertificate(): begins.");
+ if (pubKeybuf == null || uid == null || cuid == null) {
+ throw new EBaseException("CARemoteRequestHandler: enrollCertificate(): input parameter null.");
+ }
+
+ IConfigStore conf = CMS.getConfigStore();
+ String profileId =
+ conf.getString(TPSEngine.OP_ENROLL_PREFIX + "." +
+ tokenType + ".keyGen." +
+ keyType + ".ca.profileId");
+
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ HttpConnector conn =
+ (HttpConnector) subsystem.getConnectionManager().getConnector(connid);
+ CMS.debug("CARemoteRequestHandler: enrollCertificate(): sending request to CA");
+ String encodedPubKey = null;
+ try {
+ encodedPubKey = Util.uriEncode(CMS.BtoA(pubKeybuf.toBytesArray()));
+ } catch (Exception e) {
+ CMS.debug("CARemoteRequestHandler: enrollCertificate(): uriEncode of pubkey failed: " + e);
+ throw new EBaseException("CARemoteRequestHandler: enrollCertificate(): uriEncode of pubkey failed: " + e);
+ }
+ HttpResponse resp =
+ conn.send("enrollment",
+ IRemoteRequest.GET_XML + "=" +
+ true +
+ "&" + IRemoteRequest.TOKEN_CUID + "=" +
+ cuid +
+ "&" + IRemoteRequest.CA_ENROLL_screenname + "=" +
+ uid +
+ "&" + IRemoteRequest.CA_ENROLL_publickey + "=" +
+ encodedPubKey +
+ "&" + IRemoteRequest.CA_ProfileId + "=" +
+ profileId);
+
+ String content = resp.getContent();
+
+ CMS.debug("CARemoteRequestHandler: enrollCertificate(): got content = " + content);
+
+ if (content != null && !content.equals("")) {
+ XMLObject xmlResponse =
+ getXMLparser(content);
+
+ Hashtable<String, Object> response =
+ new Hashtable<String, Object>();
+
+ CMS.debug("CARemoteRequestHandler: enrollCertificate(): received:" +
+ content);
+
+ /**
+ * When a value is not found in response, keep going so we know
+ * what else is missing
+ * Note: serverKeygen and !serverKeygen returns different set of
+ * response values so "missing" might not be bad
+ */
+ Integer ist = new Integer(IRemoteRequest.RESPONSE_STATUS_NOT_FOUND);
+ String value = xmlResponse.getValue(IRemoteRequest.RESPONSE_STATUS_XML);
+ if (value == null) {
+ CMS.debug("CARemoteRequestHandler: enrollCertificate(): Status not found.");
+ CMS.debug("CARemoteRequestHandler: enrollCertificate(): got content = " + content);
+ } else {
+ CMS.debug("CARemoteRequestHandler: enrollCertificate(): got Status = " + value);
+ ist = Integer.parseInt(value);
+ }
+ response.put(IRemoteRequest.RESPONSE_STATUS, ist);
+
+ value = xmlResponse.getValue("SubjectDN");
+ if (value == null) {
+ CMS.debug("CARemoteRequestHandler:: enrollCertificate(): response missing name-value pair for: " +
+ IRemoteRequest.CA_RESPONSE_Certificate_SubjectDN);
+ } else {
+ CMS.debug("CARemoteRequestHandler:: enrollCertificate(): got IRemoteRequest.CA_RESPONSE_Certificate_SubjectDN = "
+ + value);
+ response.put(IRemoteRequest.CA_RESPONSE_Certificate_SubjectDN, value);
+ }
+
+ value = xmlResponse.getValue(IRemoteRequest.CA_RESPONSE_Certificate_serial);
+ if (value == null) {
+ CMS.debug("CARemoteRequestHandler:: enrollCertificate(): response missing name-value pair for: " +
+ IRemoteRequest.CA_RESPONSE_Certificate_serial);
+ } else {
+ CMS.debug("CARemoteRequestHandler:: enrollCertificate(): got IRemoteRequest.CA_RESPONSE_Certificate_serial = 0x"
+ + value);
+ response.put(IRemoteRequest.CA_RESPONSE_Certificate_serial, value);
+ }
+
+ value = xmlResponse.getValue(IRemoteRequest.CA_RESPONSE_Certificate_b64);
+ if (value == null) {
+ CMS.debug("CARemoteRequestHandler:: enrollCertificate(): response missing name-value pair for: " +
+ IRemoteRequest.CA_RESPONSE_Certificate_b64);
+ } else {
+ try {
+ CMS.debug("CARemoteRequestHandler:: enrollCertificate(): got IRemoteRequest.CA_RESPONSE_Certificate_b64 = "
+ + value);
+ response.put(IRemoteRequest.CA_RESPONSE_Certificate_b64, value);
+ X509CertImpl newCert = new X509CertImpl(Utils.base64decode(value));
+ response.put(IRemoteRequest.CA_RESPONSE_Certificate_x509, newCert);
+ CMS.debug("CARemoteRequestHandler: enrollCertificate(): new cert parsed successfully");
+ } catch (Exception e) {
+ // we don't exit. Keep going.
+ CMS.debug("CARemoteRequestHandler: enrollCertificate(): exception:" + e);
+ }
+ }
+
+ CMS.debug("CARemoteRequestHandler: enrollCertificate(): ends.");
+ return new CAEnrollCertResponse(response);
+ } else {
+ CMS.debug("CARemoteRequestHandler: enrollCertificate(): no response content");
+ throw new EBaseException("CARemoteRequestHandler: enrollCertificate(): no response content.");
+ }
+ }
+
+ /**
+ * retrieveCertificate retrieves a certificate by serial number
+ *
+ * @param serialno the serial number of the cert to be retrieved
+ * @return CARetrieveCertResponse
+ */
+ public CARetrieveCertResponse retrieveCertificate(
+ BigInteger serialno)
+ throws EBaseException {
+
+ CMS.debug("CARemoteRequestHandler: retrieveCertificate(): begins.");
+ if (serialno == null) {
+ throw new EBaseException("CARemoteRequestHandler: retrieveCertificate(): input parameter null.");
+ }
+
+ //ToDo: I"m not sure why these are not used, let's check this out.
+ //It's working though.
+
+ /*
+ IConfigStore conf = CMS.getConfigStore();
+ String configName = "tps.connector." + connid + ".uri.getBySerial";
+ String servlet = conf.getString(configName, "/ca/ee/ca/displayBySerial");
+ */
+
+
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ HttpConnector conn =
+ (HttpConnector) subsystem.getConnectionManager().getConnector(connid);
+ CMS.debug("CARemoteRequestHandler: retrieveCertificate(): sending request to CA");
+ HttpResponse resp =
+ conn.send("getcert",
+ IRemoteRequest.GET_XML + "=" + true +
+ "&" + IRemoteRequest.CA_GET_CERT_B64CertOnly + "=" + true +
+ "&" + IRemoteRequest.CA_GET_CERT_SERIAL + "=" + serialno.toString());
+
+ String content = resp.getContent();
+ if (content != null && !content.equals("")) {
+ XMLObject xmlResponse =
+ getXMLparser(content);
+
+ Hashtable<String, Object> response =
+ new Hashtable<String, Object>();
+
+ CMS.debug("CARemoteRequestHandler: retrieveCertificate(): received:" +
+ content);
+
+ /**
+ * When a value is not found in response, keep going so we know
+ * what else is missing
+ */
+ Integer ist = new Integer(IRemoteRequest.RESPONSE_STATUS_NOT_FOUND);
+ String value = xmlResponse.getValue(IRemoteRequest.RESPONSE_STATUS_XML);
+ if (value == null) {
+ CMS.debug("CARemoteRequestHandler: retrieveCertificate(): Status not found.");
+ CMS.debug("CARemoteRequestHandler: retrieveCertificate(): got content = " + content);
+ } else {
+ CMS.debug("CARemoteRequestHandler: retrieveCertificate(): got Status = " + value);
+ ist = Integer.parseInt(value);
+ }
+ response.put(IRemoteRequest.RESPONSE_STATUS, ist);
+
+ value = xmlResponse.getValue(IRemoteRequest.CA_RESPONSE_Certificate_chain_b64);
+ if (value == null) {
+ CMS.debug("CARemoteRequestHandler:: retrieveCertificate(): response missing name-value pair for: " +
+ IRemoteRequest.CA_RESPONSE_Certificate_chain_b64);
+ } else {
+ CMS.debug("CARemoteRequestHandler:: retrieveCertificate(): got IRemoteRequest.CA_RESPONSE_Certificate_chain_b64 = "
+ + value);
+ response.put(IRemoteRequest.CA_RESPONSE_Certificate_chain_b64, value);
+ try {
+ X509CertImpl newCert = new X509CertImpl(Utils.base64decode(value));
+ response.put(IRemoteRequest.CA_RESPONSE_Certificate_x509, newCert);
+ CMS.debug("CARemoteRequestHandler: retrieveCertificate(): retrieved cert parsed successfully");
+ } catch (CertificateException e) {
+ // we don't exit. Keep going.
+ CMS.debug("CARemoteRequestHandler: retrieveCertificate(): exception:" + e);
+ }
+ }
+
+ CMS.debug("CARemoteRequestHandler: retrieveCertificate(): ends.");
+ return new CARetrieveCertResponse(response);
+ } else {
+ CMS.debug("CARemoteRequestHandler: retrieveCertificate(): no response content");
+ throw new EBaseException("CARemoteRequestHandler: retrieveCertificate(): no response content.");
+ }
+ }
+
+ /**
+ * renewCertificate renew a certificate by serial number
+ *
+ * @param serialno the serial number of the cert to be renewed
+ * @return CARenewCertResponse
+ */
+ public CARenewCertResponse renewCertificate(
+ BigInteger serialno,
+ String tokenType,
+ String keyType)
+ throws EBaseException {
+
+ CMS.debug("CARemoteRequestHandler: renewCertificate(): begins.");
+ if (serialno == null) {
+ throw new EBaseException("CARemoteRequestHandler: renewCertificate(): input parameter null.");
+ }
+
+ IConfigStore conf = CMS.getConfigStore();
+
+ String profileId =
+ conf.getString(TPSEngine.OP_ENROLL_PREFIX + "." +
+ tokenType + ".renewal." +
+ keyType + ".ca.profileId");
+
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ HttpConnector conn =
+ (HttpConnector) subsystem.getConnectionManager().getConnector(connid);
+ CMS.debug("CARemoteRequestHandler: renewCertificate(): sending request to CA");
+ HttpResponse resp =
+ conn.send("renewal",
+ IRemoteRequest.GET_XML + "=" + true +
+ "&" + IRemoteRequest.CA_RENEWAL + "=" + true +
+ "&" + IRemoteRequest.CA_RENEWAL_SerialNum + "=" + serialno.toString() +
+ "&" + IRemoteRequest.CA_ProfileId + "=" + profileId);
+
+ String content = resp.getContent();
+
+ if (content != null && !content.equals("")) {
+ XMLObject xmlResponse =
+ getXMLparser(content);
+
+ Hashtable<String, Object> response =
+ new Hashtable<String, Object>();
+
+ CMS.debug("CARemoteRequestHandler: renewCertificate(): received:" +
+ content);
+
+ /**
+ * When a value is not found in response, keep going so we know
+ * what else is missing
+ * Note: serverKeygen and !serverKeygen returns different set of
+ * response values so "missing" might not be bad
+ */
+ Integer ist = new Integer(IRemoteRequest.RESPONSE_STATUS_NOT_FOUND);
+ String value = xmlResponse.getValue(IRemoteRequest.RESPONSE_STATUS_XML);
+ if (value == null) {
+ CMS.debug("CARemoteRequestHandler: renewCertificate(): Status not found.");
+ CMS.debug("CARemoteRequestHandler: renewCertificate(): got content = " + content);
+ } else {
+ CMS.debug("CARemoteRequestHandler: renewCertificate(): got Status = " + value);
+ ist = Integer.parseInt(value);
+ }
+ response.put(IRemoteRequest.RESPONSE_STATUS, ist);
+
+ value = xmlResponse.getValue("SubjectDN");
+ if (value == null) {
+ CMS.debug("CARemoteRequestHandler:: renewCertificate(): response missing name-value pair for: " +
+ IRemoteRequest.CA_RESPONSE_Certificate_SubjectDN);
+ } else {
+ CMS.debug("CARemoteRequestHandler:: renewCertificate(): got IRemoteRequest.CA_RESPONSE_Certificate_SubjectDN = "
+ + value);
+ response.put(IRemoteRequest.CA_RESPONSE_Certificate_SubjectDN, value);
+ }
+
+ value = xmlResponse.getValue(IRemoteRequest.CA_RESPONSE_Certificate_serial);
+ if (value == null) {
+ CMS.debug("CARemoteRequestHandler:: renewCertificate(): response missing name-value pair for: " +
+ IRemoteRequest.CA_RESPONSE_Certificate_serial);
+ } else {
+ CMS.debug("CARemoteRequestHandler:: renewCertificate(): got IRemoteRequest.CA_RESPONSE_Certificate_serial = 0x"
+ + value);
+ response.put(IRemoteRequest.CA_RESPONSE_Certificate_serial, value);
+ }
+
+ value = xmlResponse.getValue(IRemoteRequest.CA_RESPONSE_Certificate_b64);
+ if (value == null) {
+ CMS.debug("CARemoteRequestHandler:: renewCertificate(): response missing name-value pair for: " +
+ IRemoteRequest.CA_RESPONSE_Certificate_b64);
+ } else {
+ CMS.debug("CARemoteRequestHandler:: renewCertificate(): got IRemoteRequest.CA_RESPONSE_Certificate_b64 = "
+ + value);
+ response.put(IRemoteRequest.CA_RESPONSE_Certificate_b64, value);
+ try {
+ X509CertImpl newCert = new X509CertImpl(Utils.base64decode(value));
+ response.put(IRemoteRequest.CA_RESPONSE_Certificate_x509, newCert);
+ CMS.debug("CARemoteRequestHandler: renewCertificate(): new cert parsed successfully");
+ } catch (CertificateException e) {
+ // we don't exit. Keep going.
+ CMS.debug("CARemoteRequestHandler: renewCertificate(): exception:" + e);
+ }
+ }
+
+ CMS.debug("CARemoteRequestHandler: renewCertificate(): ends.");
+ return new CARenewCertResponse(response);
+ } else {
+ CMS.debug("CARemoteRequestHandler: renewCertificate(): no response content");
+ throw new EBaseException("CARemoteRequestHandler: renewCertificate(): no response content.");
+ }
+ }
+
+ /**
+ * revokeCertificate provides the basic revocation of a certificate from
+ * the CA
+ *
+ * @param serialno serial number of the cert to revoke
+ * @param reason reason to revoke per definition in RevocationReason
+ *
+ * @returns CARevokeCertResponse
+ */
+ private CARevokeCertResponse revokeCertificate(
+ String serialno,
+ RevocationReason reason)
+ throws EBaseException {
+
+ CMS.debug("CARemoteRequestHandler: revokeCertificate(): begins on serial#:"+ serialno);
+ if (serialno == null || reason == null) {
+ throw new EBaseException("CARemoteRequestHandler: revokeCertificate(): input parameter null.");
+ }
+
+ // IConfigStore conf = CMS.getConfigStore();
+
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ HttpConnector conn =
+ (HttpConnector) subsystem.getConnectionManager().getConnector(connid);
+ CMS.debug("CARemoteRequestHandler: revokeCertificate(): sending request to CA");
+ HttpResponse resp =
+ conn.send("revoke",
+ IRemoteRequest.CA_OP + "=" + IRemoteRequest.CA_REVOKE +
+ "&" + IRemoteRequest.CA_REVOCATION_REASON + "=" + reason.getCode() +
+ "&" + IRemoteRequest.CA_REVOKE_ALL + "=(" +
+ IRemoteRequest.CA_REVOKE_SERIAL + "=" + serialno + ")&" +
+ IRemoteRequest.CA_REVOKE_COUNT + "=1");
+ String content = resp.getContent();
+
+ CMS.debug("CARemoteRequestHandler: revokeCertificate(): got content = " + content);
+ if (content != null && !content.equals("")) {
+ Hashtable<String, Object> response =
+ parseResponse(content);
+
+ /**
+ * When a value is not found in response, keep going so we know
+ * what else is missing
+ */
+ Integer ist = new Integer(IRemoteRequest.RESPONSE_STATUS_NOT_FOUND);
+ String value = (String) response.get(IRemoteRequest.RESPONSE_STATUS);
+
+ CMS.debug("CARemoteRequestHandler: revokeCertificate(): got status = " + value);
+ ist = Integer.parseInt(value);
+ if (ist != 0) {
+ CMS.debug("CARemoteRequestHandler: revokeCertificate(): status not 0, getting error string... ");
+ value = (String) response.get(IRemoteRequest.RESPONSE_ERROR_STRING);
+ if (value == null) {
+ CMS.debug("CARemoteRequestHandler: revokeCertificate(): response missing name-value pair for: " +
+ IRemoteRequest.RESPONSE_ERROR_STRING);
+ } else {
+ CMS.debug("CARemoteRequestHandler: revokeCertificate(): got IRemoteRequest.RESPONSE_ERROR_STRING = "
+ + value);
+ response.put(IRemoteRequest.RESPONSE_ERROR_STRING, value);
+ }
+ }
+ response.put(IRemoteRequest.RESPONSE_STATUS, ist);
+
+ CMS.debug("CARemoteRequestHandler: revokeCertificate(): ends.");
+ return new CARevokeCertResponse(response);
+ } else {
+ CMS.debug("CARemoteRequestHandler: revokeCertificate(): no response content.");
+ throw new EBaseException("CARemoteRequestHandler: revokeCertificate(): no response content.");
+ }
+ }
+
+ /**
+ * unrevokeCertificate provides the basic unrevocation of a certificate from
+ * the CA
+ *
+ * @param serialno serial number of the cert to unrevoke
+ *
+ * @returns CARevokeCertResponse
+ */
+ private CARevokeCertResponse unrevokeCertificate(
+ String serialno)
+ throws EBaseException {
+
+ CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): begins on serial#:"+ serialno);
+ if (serialno == null) {
+ throw new EBaseException("CARemoteRequestHandler: unrevokeCertificate(): input parameter null.");
+ }
+
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ HttpConnector conn =
+ (HttpConnector) subsystem.getConnectionManager().getConnector(connid);
+ CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): sending request to CA");
+ HttpResponse resp =
+ conn.send("unrevoke",
+ IRemoteRequest.CA_UNREVOKE_SERIAL + "=" + serialno);
+ String content = resp.getContent();
+
+ CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): got content = " + content);
+ if (content != null && !content.equals("")) {
+ Hashtable<String, Object> response =
+ parseResponse(content);
+
+ /**
+ * When a value is not found in response, keep going so we know
+ * what else is missing
+ */
+ Integer ist = new Integer(IRemoteRequest.RESPONSE_STATUS_NOT_FOUND);
+ String value = (String) response.get(IRemoteRequest.RESPONSE_STATUS);
+
+ CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): got status = " + value);
+ ist = Integer.parseInt(value);
+ if (ist != 0) {
+ CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): status not 0, getting error string... ");
+ value = (String) response.get(IRemoteRequest.RESPONSE_ERROR_STRING);
+ if (value == null) {
+ CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): response missing name-value pair for: " +
+ IRemoteRequest.RESPONSE_ERROR_STRING);
+ } else {
+ CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): got IRemoteRequest.RESPONSE_ERROR_STRING = "
+ + value);
+ response.put(IRemoteRequest.RESPONSE_ERROR_STRING, value);
+ }
+ }
+ response.put(IRemoteRequest.RESPONSE_STATUS, ist);
+
+ CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): ends.");
+ return new CARevokeCertResponse(response);
+ } else {
+ CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): no response content.");
+ throw new EBaseException("CARemoteRequestHandler: unrevokeCertificate(): no response content.");
+ }
+ }
+
+ /**
+ * revokeFromOtherCA searches through all defined ca entries
+ * to find the cert's signing ca for revocation / unrevocation.
+ * It is called from revokeCertificate() when the cert's
+ * AKI does not match that of the current signing ca.
+ *
+ * @param revoke true to revoke; false to unrevoke
+ * @param cert cert to (un)revoke
+ * @param serialno parameter for the (Un)RevokeCertificate() functions
+ * @param reason RevocationReason for the base revokeCertificate() function
+ * @throws IOException
+ */
+ @SuppressWarnings("unused")
+ private CARevokeCertResponse revokeFromOtherCA(
+ boolean revoke, // true==revoke; false==unrevoke
+ X509CertImpl cert,
+ RevocationReason reason)
+ throws EBaseException, IOException {
+ if (cert == null) {
+ throw new EBaseException("CARemoteRequestHandler: revokeFromOtherCA(): input parameter cert null.");
+ }
+ String certAkiString = null;
+ try {
+ certAkiString = Util.getCertAkiString(cert);
+ } catch (Exception e) {
+ throw new EBaseException("CARemoteRequestHandler: revokeFromOtherCA(): getCertAkiString failed:" + e);
+ }
+ return revokeFromOtherCA(revoke, cert.getSerialNumber().toString(), certAkiString, reason);
+ }
+
+
+ private CARevokeCertResponse revokeFromOtherCA(
+ boolean revoke, // true==revoke; false==unrevoke
+ String serialno,
+ String certAkiString,
+ RevocationReason reason)
+ throws EBaseException {
+
+
+ CMS.debug("CARemoteRequestHandler: revokeFromOtherCA: begins");
+
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ List<String> caList =
+ subsystem.getConnectionManager().getCAList();
+
+ Exception exception = null;
+
+ for (String ca : caList) {
+ try {
+ String caSkiString = getCaSki(ca);
+ if (certAkiString.equals(caSkiString)) {
+ CMS.debug("CARemoteRequestHandler: revokeFromOtherCA() cert AKI and caCert SKI matched");
+ if (revoke) {
+ return revokeCertificate(serialno, reason);
+ } else {
+ return unrevokeCertificate(serialno);
+ }
+ } else { // not a match then iterate to next ca in list
+ CMS.debug("CARemoteRequestHandler: revokeFromOtherCA() cert AKI and caCert SKI not matched");
+ }
+ } catch (Exception e) {
+ // any issue then iterate to next ca in list
+ CMS.debug("CARemoteRequestHandler: revokeFromOtherCA() issue found, iterate to next ca in list. Exception:"
+ + e);
+ exception = e;
+ }
+ }
+ if (exception == null) {
+ throw new EBaseException("revokeFromOtherCA: signing ca not found");
+ } else {
+ throw new EBaseException(exception.toString());
+ }
+ }
+
+ /**
+ * getCaSki returns the CA's Subject Key Identifier (ski)
+ * associated with the connector id.
+ * If the ca's ski has not been calculated, it will do so and
+ * save to the connector's caSKI config entry
+ *
+ * @param conn connector id
+ * @returns ca's ski associated with conn
+ */
+ private String getCaSki(String conn)
+ throws EBaseException, IOException {
+
+ String caSkiString = null;
+ if (conn == null) {
+ throw new EBaseException("CARemoteRequestHandler: getCaSki(): input parameter conn null.");
+ }
+
+ IConfigStore conf = CMS.getConfigStore();
+
+ /*
+ * first, see if ca Subject Key Identifier (SKI) is in
+ * config store. If not, put it in, so we don't have to
+ * calculate that every time.
+ */
+ try {
+ String configName = "tps.connector." + conn + ".caSKI";
+ CMS.debug("CARemoteRequestHandler: getCaSki() retriving configName=" + configName);
+ return conf.getString(configName);
+ } catch (EPropertyNotFound e) {
+ // caSKI not yet calculated; proceed to calculate
+ CMS.debug("CARemoteRequestHandler: getCaSki() caSKI not yet calculated:" + e);
+ } catch (EBaseException e) {
+ throw e;
+ }
+
+ try {
+ String caNickname =
+ conf.getString("tps.connector." + conn + ".caNickname");
+ CMS.debug("CARemoteRequestHandler: getCaSki() Calculating caSKI...searching for ca cert in nss db:"
+ + caNickname);
+ CryptoManager cm = CryptoManager.getInstance();
+ try {
+ X509Certificate c = cm.findCertByNickname(caNickname);
+ X509CertImpl caCert = new X509CertImpl(c.getEncoded());
+ // now retrieve caSKI and store in config
+ caSkiString = Util.getCertSkiString(caCert);
+ CMS.debug("CARemoteRequestHandler: getCaSki() caSKI calculated. Saving it.");
+ conf.putString("tps.connector." + conn + ".caSKI", caSkiString);
+ conf.commit(false);
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception et) {
+ /* ca cert not found in nss db; no match needed */
+ CMS.debug("CARemoteRequestHandler: getCaSki() caSKI calculation failure." + et);
+ throw new EBaseException("CARemoteRequestHandler: getCaSki(): skip match.");
+ }
+ } catch (EBaseException e) {
+ /*
+ * if it gets here, that means config is missing both:
+ * 1. tps.connector.ca<n>.caSKI
+ * 2. tps.connector.ca<n>.caNickname
+ * now assume default of just using the issuing ca and
+ * no search performed
+ */
+ CMS.debug("CARemoteRequestHandler: getCaSki() caSKI calculation failure." + e);
+ throw e;
+ } catch (NotInitializedException e) {
+ CMS.debug("CARemoteRequestHandler: getCaSki() caSKI calculation failure." + e);
+ throw new EBaseException("CARemoteRequestHandler: getCaSki(): skip match.:" + e);
+ }
+
+ return caSkiString;
+ }
+
+
+
+ /**
+ * revokeCertificate() supports revocation routing by providing
+ * CA discovery. When needed, it searchs through all listed ca
+ * entries to find the cert's signing ca for revocation.
+ *
+ * Note: in the configuration, the ca signing cert of each ca
+ * id must be imported into the db and have its nickname present.
+ * e.g. tps.connector.ca1.caNickname=CA1nickname
+ *
+ * See design:
+ * http://pki.fedoraproject.org/wiki/TPS_-_Revocation_Routing
+ *
+ * @param revoke true to revoke; false to unrevoke
+ * @param serialno serial number for the (Un)RevokeCertificate() functions
+ * @param reason RevocationReason for the base revokeCertificate() function
+ */
+ public CARevokeCertResponse revokeCertificate(
+ boolean revoke, // true==revoke; false==unrevoke
+ X509CertImpl cert,
+ RevocationReason reason)
+ throws EBaseException {
+ if (cert == null) {
+ throw new EBaseException("CARemoteRequestHandler: revokeCertificate(): input parameter cert null.");
+ }
+ String certAkiString = null;
+ try {
+ certAkiString = Util.getCertAkiString(cert);
+ } catch (IOException e) {
+ throw new EBaseException("CARemoteRequestHandler: revokeCertificate(): getCertAkiString failed:" + e);
+ }
+
+ return revokeCertificate(revoke, cert.getSerialNumber().toString(), certAkiString, reason);
+ }
+
+ public CARevokeCertResponse revokeCertificate(
+ boolean revoke, // true==revoke; false==unrevoke
+ String serialno,
+ String certAkiString,
+ RevocationReason reason)
+ throws EBaseException {
+
+ CMS.debug("CARemoteRequestHandler: revokeCertificate() begins with CA discovery");
+
+ if (revoke == true && reason == null) {
+ throw new EBaseException("CARemoteRequestHandler: revokeCertificate(): input parameter reason null.");
+ }
+
+ boolean skipMatch = false;
+
+ String caSkiString = null;
+
+ try {
+ caSkiString = getCaSki(connid);
+ } catch (Exception e) {
+ CMS.debug("CARemoteRequestHandler: revokeCertificate() exception:" + e);
+ skipMatch = true;
+ }
+ if (!skipMatch) {
+ /* now compare cert's AKI to the ca's SKI
+ * if matched, continue,
+ * if not, search in the ca list
+ */
+ CMS.debug("CARemoteRequestHandler: revokeCertificate() cert AKI and caCert SKI matching begins");
+ if (certAkiString.equals(caSkiString)) {
+ CMS.debug("CARemoteRequestHandler: revokeCertificate() cert AKI and caCert SKI matched");
+ if (revoke) {
+ return revokeCertificate(serialno, reason);
+ } else {
+ return unrevokeCertificate(serialno);
+ }
+ } else {
+ CMS.debug("CARemoteRequestHandler: revokeCertificate() cert AKI and caCert SKI of the designated issuing ca do not match...calling revokeFromOtherCA to search for another ca");
+ return revokeFromOtherCA(revoke, serialno, certAkiString, reason);
+ }
+ } else {
+ if (revoke) {
+ return revokeCertificate(serialno, reason);
+ } else {
+ return unrevokeCertificate(serialno);
+ }
+ }
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/CARenewCertResponse.java b/base/tps/src/org/dogtagpki/server/tps/cms/CARenewCertResponse.java
new file mode 100644
index 000000000..bb9ebbb44
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/CARenewCertResponse.java
@@ -0,0 +1,52 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import netscape.security.x509.X509CertImpl;
+import java.util.Hashtable;
+
+import org.dogtagpki.server.connector.IRemoteRequest;
+
+/**
+ * CARenewCertResponse is the class for the response to
+ * CA Remote Request: renewCertificate()
+ *
+ */
+public class CARenewCertResponse extends RemoteResponse
+{
+ public CARenewCertResponse(Hashtable<String, Object> ht) {
+ nameValTable = ht;
+ }
+
+ public String getRenewedCertB64() {
+ return (String) nameValTable.get(IRemoteRequest.CA_RESPONSE_Certificate_b64);
+ }
+
+ public String getRenewedCertSerialHex() {
+ return (String) nameValTable.get(IRemoteRequest.CA_RESPONSE_Certificate_serial);
+ }
+
+ public String getRenewedCertSubjectDN() {
+ return (String) nameValTable.get(IRemoteRequest.CA_RESPONSE_Certificate_SubjectDN);
+ }
+
+ public X509CertImpl getRenewedCert() {
+ return (X509CertImpl) nameValTable.get(IRemoteRequest.CA_RESPONSE_Certificate_x509);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/CARetrieveCertResponse.java b/base/tps/src/org/dogtagpki/server/tps/cms/CARetrieveCertResponse.java
new file mode 100644
index 000000000..a356907fa
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/CARetrieveCertResponse.java
@@ -0,0 +1,45 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import java.util.Hashtable;
+
+import netscape.security.x509.X509CertImpl;
+
+import org.dogtagpki.server.connector.IRemoteRequest;
+
+/**
+ * CARetrieveCertResponse is the class for the response to
+ * CA Remote Request: retrieveCertificate()
+ *
+ */
+public class CARetrieveCertResponse extends RemoteResponse
+{
+ public CARetrieveCertResponse(Hashtable<String, Object> ht) {
+ nameValTable = ht;
+ }
+
+ public String getCertB64() {
+ return (String) nameValTable.get(IRemoteRequest.CA_RESPONSE_Certificate_chain_b64);
+ }
+
+ public X509CertImpl getCert() {
+ return (X509CertImpl) nameValTable.get(IRemoteRequest.CA_RESPONSE_Certificate_x509);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/CARevokeCertResponse.java b/base/tps/src/org/dogtagpki/server/tps/cms/CARevokeCertResponse.java
new file mode 100644
index 000000000..d7db5976c
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/CARevokeCertResponse.java
@@ -0,0 +1,39 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import java.util.Hashtable;
+
+import org.dogtagpki.server.connector.IRemoteRequest;
+
+/**
+ * CARevokeCertResponse is the class for the response to
+ * CA Remote Request: revoteCertificate()
+ *
+ */
+public class CARevokeCertResponse extends RemoteResponse
+{
+ public CARevokeCertResponse(Hashtable<String, Object> ht) {
+ nameValTable = ht;
+ }
+
+ public String getErrorString() {
+ return (String) nameValTable.get(IRemoteRequest.RESPONSE_ERROR_STRING);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/ConnectionManager.java b/base/tps/src/org/dogtagpki/server/tps/cms/ConnectionManager.java
new file mode 100644
index 000000000..2b5ab2208
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/ConnectionManager.java
@@ -0,0 +1,229 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.ws.rs.core.MediaType;
+
+import org.dogtagpki.server.tps.TPSSubsystem;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.connector.IConnector;
+import com.netscape.cmscore.connector.HttpConnector;
+import com.netscape.cmscore.connector.RemoteAuthority;
+
+/**
+ * ConnectionManager is a class for connection management
+ * of its Remote Authorities
+ *
+ * @author cfu
+ */
+public class ConnectionManager
+{
+ private Hashtable<String, IConnector> connectors;
+ List<String> caList;
+
+ public ConnectionManager() {
+ // initialize the ca list for revocation routing:
+ // tps.connCAList=ca1,ca2...ca<n>
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ IConfigStore conf = subsystem.getConfigStore();
+ String caListString;
+ try {
+ caListString = conf.getString("connCAList");
+ CMS.debug("ConnectionManager: ConnectionManager(): Initializing CA routing list");
+ } catch (EBaseException e) {
+ CMS.debug("ConnectionManager: ConnectionManager(): no connCAList for ca discovery. No revocation routing");
+ return;
+ }
+
+ caList = Arrays.asList(caListString.split(","));
+ CMS.debug("ConnectionManager: ConnectionManager(): CA routing list initialized.");
+ }
+
+ public List<String> getCAList() {
+ return caList;
+ }
+
+ /*
+ * connector establishment with multi-uri support
+ *
+ * Initialize all connectors
+ * tps.connector.<connID>.xxx
+ *
+ * e.g. (with Failover list under "host", separated by a space)
+ *
+ * tps.connector.ca1.enable=true
+ * tps.connector.ca1.minHttpConns=1
+ * tps.connector.ca1.maxHttpConns=15
+ * tps.connector.ca1.host=host1.EXAMPLE.com:8445 host2.EXAMPLE.com:8445
+ * tps.connector.ca1.port=<port number; unused if for failover case>
+ * tps.connector.ca1.nickName=subsystemCert cert-pki-tomcat TPS
+ * tps.connector.ca1.timeout=30
+ * # In the example below,
+ * # "enrollment", "getcert", "renewal", "revoke", and "unrevoke"
+ * # are what's being referred to as "op" in the multi-uri support code
+ * tps.connector.ca1.uri.enrollment=/ca/ee/ca/profileSubmitSSLClient
+ * tps.connector.ca1.uri.renewal=/ca/ee/ca/profileSubmitSSLClient
+ * tps.connector.ca1.uri.getcert=/ca/ee/ca/displayBySerial
+ * tps.connector.ca1.uri.revoke=/ca/ee/subsystem/ca/doRevoke
+ * tps.connector.ca1.uri.unrevoke=/ca/ee/subsystem/ca/doUnrevoke
+ */
+ public void initConnectors() throws EBaseException {
+ CMS.debug("ConnectionManager: initConnectors(): begins.");
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ IConfigStore conf = subsystem.getConfigStore();
+ IConfigStore connectorSubstore = conf.getSubStore("connector");
+ Enumeration<String> connector_enu = connectorSubstore.getSubStoreNames();
+ connectors = new Hashtable<String, IConnector>();
+ while (connector_enu.hasMoreElements()) {
+ String connectorID = connector_enu.nextElement();
+ CMS.debug("ConnectionManager: initConnectors(): initializing connector " + connectorID);
+ IConfigStore connectorConfig =
+ connectorSubstore.getSubStore(connectorID);
+ IConnector conn = null;
+ boolean enable = connectorConfig.getBoolean("enable", false);
+ if (!enable) {
+ CMS.debug("ConnectionManager: initConnectors(): connector disabled.");
+ continue;
+ }
+ CMS.debug("ConnectionManager: initConnectors(): connector enabled.");
+ conn = createConnector(connectorConfig);
+
+ connectors.put(connectorID, conn);
+ CMS.debug("ConnectionManager: initConnectors(): connector "
+ + connectorID +
+ " initialized.");
+ }
+ CMS.debug("ConnectionManager: initConnectors(): ends.");
+ }
+
+ /*
+ * Creates and returns a connector
+ *
+ * @param conf config store of the connector
+ * @return IConnector the connector if created successfully; null if not
+ */
+ private IConnector createConnector(IConfigStore conf)
+ throws EBaseException {
+ IConnector connector = null;
+
+ CMS.debug("ConnectionManager: createConnector(): begins.");
+ if (conf == null || conf.size() <= 0) {
+ CMS.debug("ConnectionManager: createConnector(): conf null or empty.");
+ throw new EBaseException("called with null config store");
+ }
+
+ String host = conf.getString("host");
+ if (host == null) {
+ CMS.debug("ConnectionManager: createConnector(): host not found in config.");
+ throw new EBaseException("host not found in config");
+ }
+ // port doesn't have to contain anything if failover supplied in host
+ int port = conf.getInteger("port");
+
+ Hashtable<String, String> uris = new Hashtable<String, String>();
+ IConfigStore uriSubstore = conf.getSubStore("uri");
+ if (uriSubstore == null) {
+ CMS.debug("ConnectionManager: createConnector(): uri(s) not found in config.");
+ throw new EBaseException("uri(s) not found in config");
+ }
+ CMS.debug("ConnectionManager: createConnector(): uriSubstore name=" + uriSubstore.getName() + " size ="
+ + uriSubstore.size());
+
+ Enumeration<String> uri_enu = uriSubstore.getPropertyNames();
+ while (uri_enu.hasMoreElements()) {
+ String op = uri_enu.nextElement();
+ if ((op != null) && !op.equals(""))
+ CMS.debug("ConnectionManager: createConnector(): op name=" + op);
+ else
+ continue;
+
+ String uriValue = uriSubstore.getString(op);
+ if ((uriValue != null) && !uriValue.equals(""))
+ CMS.debug("ConnectionManager: createConnector(): uri value=" + uriValue);
+ else
+ continue;
+ uris.put(op, uriValue);
+ }
+
+ String nickname = conf.getString("nickName", null);
+ if (nickname != null)
+ CMS.debug("ConnectionManager: createConnector(): nickName=" + nickname);
+ else {
+ CMS.debug("ConnectionManager: createConnector(): nickName not found in config");
+ throw new EBaseException("nickName not found in config");
+ }
+
+ // "resendInterval" is for Request Queue, and not supported in TPS
+ int resendInterval = -1;
+ int timeout = conf.getInteger("timeout", 0);
+ RemoteAuthority remauthority =
+ new RemoteAuthority(host, port, uris, timeout, MediaType.APPLICATION_FORM_URLENCODED);
+
+ CMS.debug("ConnectionManager: createConnector(): establishing HttpConnector");
+ if (timeout == 0) {
+ connector =
+ new HttpConnector(null, nickname, remauthority, resendInterval, conf);
+ } else {
+ connector =
+ new HttpConnector(null, nickname, remauthority, resendInterval, conf, timeout);
+ }
+
+ CMS.debug("ConnectionManager: createConnector(): ends.");
+ return connector;
+ }
+
+ /*
+ * Gets an established connector to be used to send requests
+ * to a remote Authority (Note that Failover is supported in the
+ * underlying connector framework.
+ *
+ * Example usage (with example config for "ca1" defined above
+ * in initConnectors():
+ *
+ * TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ * HttpConnector testConn =
+ * (HttpConnector) subsystem.getConnectionManager().getConnector(connectionID);
+ * HttpResponse resp =
+ * testConn.send("renewal",
+ * "serial_num=6&profileId=caTokenUserEncryptionKeyRenewal&renewal=true");
+ * if (resp != null) {
+ * CMS.debug("Connector test: HttpResponse content:"+
+ * resp.getContent());
+ * } else {
+ * CMS.debug("Connector test: HttpResponse content null");
+ * }
+ *
+ * @param connID connection id per defined in the configuration
+ * @return IConnector the connector matching the connection id
+ */
+ public IConnector getConnector(String connID) {
+ return connectors.get(connID);
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/KRARecoverKeyResponse.java b/base/tps/src/org/dogtagpki/server/tps/cms/KRARecoverKeyResponse.java
new file mode 100644
index 000000000..9d0c5ff5f
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/KRARecoverKeyResponse.java
@@ -0,0 +1,51 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import java.util.Hashtable;
+
+import org.dogtagpki.server.connector.IRemoteRequest;
+
+/**
+ * KRARecoverKeyResponse is the class for the response to
+ * KRA Remote Request: recoverKey()
+ *
+ */
+public class KRARecoverKeyResponse extends RemoteResponse
+{
+ public KRARecoverKeyResponse(Hashtable<String, Object> ht) {
+ nameValTable = ht;
+ }
+
+ public String getErrorString() {
+ return (String) nameValTable.get(IRemoteRequest.RESPONSE_ERROR_STRING);
+ }
+
+ public String getPublicKey() {
+ return (String) nameValTable.get(IRemoteRequest.KRA_RESPONSE_PublicKey);
+ }
+
+ public String getWrappedPrivKey() {
+ return (String) nameValTable.get(IRemoteRequest.KRA_RESPONSE_Wrapped_PrivKey);
+ }
+
+ public String getIVParam() {
+ return (String) nameValTable.get(IRemoteRequest.KRA_RESPONSE_IV_Param);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/KRARemoteRequestHandler.java b/base/tps/src/org/dogtagpki/server/tps/cms/KRARemoteRequestHandler.java
new file mode 100644
index 000000000..87388ff99
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/KRARemoteRequestHandler.java
@@ -0,0 +1,322 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import java.util.Hashtable;
+
+import org.dogtagpki.server.connector.IRemoteRequest;
+import org.dogtagpki.server.tps.TPSSubsystem;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.cmscore.connector.HttpConnector;
+import com.netscape.cmsutil.http.HttpResponse;
+
+/**
+ * KRARemoteRequestHandler is a class representing remote requests
+ * offered by the Key Recovery Authority (KRA)
+ * On a successful return, name/value pairs are provided in a Hashtable where
+ * all contents are URL decoded if needed
+ *
+ * @author cfu
+ */
+public class KRARemoteRequestHandler extends RemoteRequestHandler
+{
+ public KRARemoteRequestHandler(String connID)
+ throws EBaseException {
+ if (connID == null) {
+ throw new EBaseException("KRARemoteRequestHandler: KRARemoteRequestHandler(): connID null.");
+ }
+
+ connid = connID;
+ }
+
+ /**
+ * serverSideKeyGen generates key pairs on the KRA
+ *
+ * @param cuid is the token id
+ * @param userid is the user id
+ * @param sDesKey is the des key provided by the TKS for key encryption
+ * @param archive true or false
+ *
+ * @returns KRAServerSideKeyGenResponse
+ */
+ public KRAServerSideKeyGenResponse serverSideKeyGen(
+ boolean isECC,
+ int keysize,
+ String cuid,
+ String userid,
+ String sDesKey,
+ boolean archive)
+ throws EBaseException {
+
+ CMS.debug("KRARemoteRequestHandler: serverSideKeyGen(): begins.");
+ if (cuid == null || userid == null || sDesKey == null) {
+ throw new EBaseException("KRARemoteRequestHandler: serverSideKeyGen(): input parameter null.");
+ }
+
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ HttpConnector conn =
+ (HttpConnector) subsystem.getConnectionManager().getConnector(connid);
+ CMS.debug("KRARemoteRequestHandler: serverSideKeyGen(): sending request to CA");
+ HttpResponse resp;
+ String request;
+ if (isECC) {
+ String eckeycurve;
+ if (keysize == 521) {
+ eckeycurve = "nistp521";
+ } else if (keysize == 384) {
+ eckeycurve = "nistp384";
+ } else if (keysize == 256) {
+ eckeycurve = "nistp256";
+ } else {
+ CMS.debug("KRARemoteRequestHandler: serverSideKeyGen(): unrecognized ECC keysize" + keysize
+ + ", setting to nistp256");
+ keysize = 256;
+ eckeycurve = "nistp256";
+ }
+
+ request = IRemoteRequest.KRA_KEYGEN_Archive + "=" +
+ archive +
+ "&" + IRemoteRequest.TOKEN_CUID + "=" +
+ cuid +
+ "&" + IRemoteRequest.KRA_UserId + "=" +
+ userid +
+ "&" + IRemoteRequest.KRA_KEYGEN_KeyType + "=" +
+ "EC" +
+ "&" + IRemoteRequest.KRA_KEYGEN_EC_KeyCurve + "=" +
+ eckeycurve +
+ "&" + IRemoteRequest.KRA_Trans_DesKey + "=" +
+ sDesKey;
+
+ CMS.debug("KRARemoteRequestHandler: outgoing request for ECC: " + request);
+
+ resp =
+ conn.send("GenerateKeyPair",
+ request);
+ } else { // RSA
+
+ request = IRemoteRequest.KRA_KEYGEN_Archive + "=" +
+ archive +
+ "&" + IRemoteRequest.TOKEN_CUID + "=" +
+ cuid +
+ "&" + IRemoteRequest.KRA_UserId + "=" +
+ userid +
+ "&" + IRemoteRequest.KRA_KEYGEN_KeyType + "=" +
+ "RSA" +
+ "&" + IRemoteRequest.KRA_KEYGEN_KeySize + "=" +
+ keysize +
+ "&" + IRemoteRequest.KRA_Trans_DesKey + "=" +
+ sDesKey;
+
+ CMS.debug("KRARemoteRequestHandler: outgoing request for RSA: " + request);
+
+ resp =
+ conn.send("GenerateKeyPair",
+ request);
+ }
+
+ //For some reason the send method can return null and not throw an exception.
+ // Check here;
+
+ if(resp == null) {
+ throw new EBaseException("KRARemoteRequestHandler: serverSideKeyGen(): No response object returned from connection.");
+ }
+
+ String content = resp.getContent();
+
+ CMS.debug("KRARemoteRequestHandler: serverSideKeyGen(): got content = " + content);
+ if (content != null && !content.equals("")) {
+ Hashtable<String, Object> response =
+ parseResponse(content);
+
+ /**
+ * When a value is not found in response, keep going so we know
+ * what else is missing
+ * Note: response values "missing" might not be bad for some cases
+ */
+ Integer ist = new Integer(IRemoteRequest.RESPONSE_STATUS_NOT_FOUND);
+ String value = (String) response.get(IRemoteRequest.RESPONSE_STATUS);
+
+ if(value == null) {
+ throw new EBaseException("KRARemoteRequestHandler: serverSideKeyGen(): Invalide status returned!");
+ }
+
+ CMS.debug("KRARemoteRequestHandler: serverSideKeyGen(): got status = " + value);
+ ist = Integer.parseInt(value);
+ if (ist != 0) {
+ CMS.debug("KRARemoteRequestHandler: serverSideKeyGen(): status not 0, getting error string... ");
+ value = (String) response.get(IRemoteRequest.RESPONSE_ERROR_STRING);
+ if (value == null) {
+ CMS.debug("KRARemoteRequestHandler: serverSideKeyGen(): response missing name-value pair for: " +
+ IRemoteRequest.RESPONSE_ERROR_STRING);
+ } else {
+ CMS.debug("KRARemoteRequestHandler: serverSideKeyGen(): got IRemoteRequest.RESPONSE_ERROR_STRING = "
+ + value);
+ response.put(IRemoteRequest.RESPONSE_ERROR_STRING, value);
+ }
+ }
+ response.put(IRemoteRequest.RESPONSE_STATUS, ist);
+
+ value = (String) response.get(IRemoteRequest.KRA_RESPONSE_PublicKey);
+ if (value == null) {
+ CMS.debug("KRARemoteRequestHandler: serverSideKeyGen(): response missing name-value pair for: " +
+ IRemoteRequest.KRA_RESPONSE_PublicKey);
+ } else {
+ CMS.debug("KRARemoteRequestHandler:serverSideKeyGen(): got IRemoteRequest.KRA_RESPONSE_PublicKey= "
+ + value);
+ response.put(IRemoteRequest.KRA_RESPONSE_PublicKey, value);
+ }
+
+ value = (String) response.get(IRemoteRequest.KRA_RESPONSE_Wrapped_PrivKey);
+ if (value == null) {
+ CMS.debug("KRARemoteRequestHandler: serverSideKeyGen(): response missing name-value pair for: " +
+ IRemoteRequest.KRA_RESPONSE_Wrapped_PrivKey);
+ } else {
+ CMS.debug("KRARemoteRequestHandler:serverSideKeyGen(): got IRemoteRequest.KRA_RESPONSE_Wrapped_PrivKey= "
+ + value);
+ response.put(IRemoteRequest.KRA_RESPONSE_Wrapped_PrivKey, value);
+ }
+
+ value = (String) response.get(IRemoteRequest.KRA_RESPONSE_IV_Param);
+ if (value == null) {
+ CMS.debug("KRARemoteRequestHandler: serverSideKeyGen(): response missing name-value pair for: " +
+ IRemoteRequest.KRA_RESPONSE_IV_Param);
+ } else {
+ CMS.debug("KRARemoteRequestHandler:serverSideKeyGen(): got IRemoteRequest.KRA_RESPONSE_IV_Param= "
+ + value);
+ response.put(IRemoteRequest.KRA_RESPONSE_IV_Param, value);
+ }
+
+ CMS.debug("KRARemoteRequestHandler: serverSideKeyGen(): ends.");
+ return new KRAServerSideKeyGenResponse(response);
+ } else {
+ CMS.debug("KRARemoteRequestHandler: serverSideKeyGen(): no response content.");
+ throw new EBaseException("KRARemoteRequestHandler: serverSideKeyGen(): no response content.");
+ }
+
+ }
+
+ /**
+ * recoverKey recovers keys from KRA
+ *
+ * @param cuid is the token id
+ * @param userid is the user id
+ * @param sDesKey is the des key provided by the TKS for key encryption
+ * @param b64cert is the Base64 encoding of a certificate used to recover
+ *
+ * @returns KRARecoverKeyResponse
+ */
+ public KRARecoverKeyResponse recoverKey(
+ String cuid,
+ String userid,
+ String sDesKey,
+ String b64cert)
+ throws EBaseException {
+
+ CMS.debug("KRARemoteRequestHandler: recoverKey(): begins.");
+ if (cuid == null || userid == null || sDesKey == null || b64cert == null) {
+ throw new EBaseException("KRARemoteRequestHandler: recoverKey(): input parameter null.");
+ }
+
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ HttpConnector conn =
+ (HttpConnector) subsystem.getConnectionManager().getConnector(connid);
+ CMS.debug("KRARemoteRequestHandler: recoverKey(): sending request to CA");
+
+ HttpResponse resp =
+ conn.send("TokenKeyRecovery",
+ "&" + IRemoteRequest.TOKEN_CUID + "=" +
+ cuid +
+ "&" + IRemoteRequest.KRA_UserId + "=" +
+ userid +
+ "&" + IRemoteRequest.KRA_RECOVERY_CERT + "=" +
+ b64cert +
+ "&" + IRemoteRequest.KRA_Trans_DesKey + "=" +
+ sDesKey);
+
+ String content = resp.getContent();
+
+ CMS.debug("KRARemoteRequestHandler: recoverKey(): got content = " + content);
+ if (content != null && !content.equals("")) {
+ Hashtable<String, Object> response =
+ parseResponse(content);
+
+ /**
+ * When a value is not found in response, keep going so we know
+ * what else is missing
+ * Note: response values "missing" might not be bad for some cases
+ */
+ Integer ist = new Integer(IRemoteRequest.RESPONSE_STATUS_NOT_FOUND);
+ String value = (String) response.get(IRemoteRequest.RESPONSE_STATUS);
+
+ CMS.debug("KRARemoteRequestHandler: recoverKey(): got status = " + value);
+ ist = Integer.parseInt(value);
+ if (ist != 0) {
+ CMS.debug("KRARemoteRequestHandler: recoverKey(): status not 0, getting error string... ");
+ value = (String) response.get(IRemoteRequest.RESPONSE_ERROR_STRING);
+ if (value == null) {
+ CMS.debug("KRARemoteRequestHandler: recoverKey(): response missing name-value pair for: " +
+ IRemoteRequest.RESPONSE_ERROR_STRING);
+ } else {
+ CMS.debug("KRARemoteRequestHandler: recoverKey(): got IRemoteRequest.RESPONSE_ERROR_STRING = "
+ + value);
+ response.put(IRemoteRequest.RESPONSE_ERROR_STRING, value);
+ }
+ }
+ response.put(IRemoteRequest.RESPONSE_STATUS, ist);
+
+ value = (String) response.get(IRemoteRequest.KRA_RESPONSE_PublicKey);
+ if (value == null) {
+ CMS.debug("KRARemoteRequestHandler: recoverKey(): response missing name-value pair for: " +
+ IRemoteRequest.KRA_RESPONSE_PublicKey);
+ } else {
+ CMS.debug("KRARemoteRequestHandler:recoverKey(): got IRemoteRequest.KRA_RESPONSE_PublicKey= " + value);
+ response.put(IRemoteRequest.KRA_RESPONSE_PublicKey, value);
+ }
+
+ value = (String) response.get(IRemoteRequest.KRA_RESPONSE_Wrapped_PrivKey);
+ if (value == null) {
+ CMS.debug("KRARemoteRequestHandler: recoverKey(): response missing name-value pair for: " +
+ IRemoteRequest.KRA_RESPONSE_Wrapped_PrivKey);
+ } else {
+ CMS.debug("KRARemoteRequestHandler:recoverKey(): got IRemoteRequest.KRA_RESPONSE_Wrapped_PrivKey= "
+ + value);
+ response.put(IRemoteRequest.KRA_RESPONSE_Wrapped_PrivKey, value);
+ }
+
+ value = (String) response.get(IRemoteRequest.KRA_RESPONSE_IV_Param);
+ if (value == null) {
+ CMS.debug("KRARemoteRequestHandler: recoverKey(): response missing name-value pair for: " +
+ IRemoteRequest.KRA_RESPONSE_IV_Param);
+ } else {
+ CMS.debug("KRARemoteRequestHandler:recoverKey(): got IRemoteRequest.KRA_RESPONSE_IV_Param= " + value);
+ response.put(IRemoteRequest.KRA_RESPONSE_IV_Param, value);
+ }
+
+ CMS.debug("KRARemoteRequestHandler: recoverKey(): ends.");
+ return new KRARecoverKeyResponse(response);
+ } else {
+ CMS.debug("KRARemoteRequestHandler: recoverKey(): no response content.");
+ throw new EBaseException("KRARemoteRequestHandler: recoverKey(): no response content.");
+ }
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/KRAServerSideKeyGenResponse.java b/base/tps/src/org/dogtagpki/server/tps/cms/KRAServerSideKeyGenResponse.java
new file mode 100644
index 000000000..1836bcdbd
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/KRAServerSideKeyGenResponse.java
@@ -0,0 +1,51 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import java.util.Hashtable;
+
+import org.dogtagpki.server.connector.IRemoteRequest;
+
+/**
+ * KRAServerSideKeyGenResponse is the class for the response to
+ * KRA Remote Request: serverSideKeyGen()
+ *
+ */
+public class KRAServerSideKeyGenResponse extends RemoteResponse
+{
+ public KRAServerSideKeyGenResponse(Hashtable<String, Object> ht) {
+ nameValTable = ht;
+ }
+
+ public String getErrorString() {
+ return (String) nameValTable.get(IRemoteRequest.RESPONSE_ERROR_STRING);
+ }
+
+ public String getPublicKey() {
+ return (String) nameValTable.get(IRemoteRequest.KRA_RESPONSE_PublicKey);
+ }
+
+ public String getWrappedPrivKey() {
+ return (String) nameValTable.get(IRemoteRequest.KRA_RESPONSE_Wrapped_PrivKey);
+ }
+
+ public String getIVParam() {
+ return (String) nameValTable.get(IRemoteRequest.KRA_RESPONSE_IV_Param);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/RemoteRequestHandler.java b/base/tps/src/org/dogtagpki/server/tps/cms/RemoteRequestHandler.java
new file mode 100644
index 000000000..ceed1c11c
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/RemoteRequestHandler.java
@@ -0,0 +1,91 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import java.io.ByteArrayInputStream;
+import java.util.Hashtable;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.cmsutil.xml.XMLObject;
+
+/**
+ * RemoteRequestHandler is the base class for the remote authorities
+ *
+ * @author cfu
+ */
+public abstract class RemoteRequestHandler
+{
+ private static final String RESPONSE_SEPARATOR = "\\&";
+ private static final String NAME_VALUE_EQUAL = "=";
+
+ protected String connid;
+
+ /**
+ * parseResponse parses remote responses that take the form of '&'-separated
+ * name-value pairs
+ *
+ * @param content The exact string content in the HTTP response
+ * @return name-value pairs in a Hashtable
+ */
+ protected Hashtable<String, Object> parseResponse(String content)
+ throws EBaseException {
+ CMS.debug("RemoteRequestHandler: parseResponse(): begins:");
+ if (content == null) {
+ throw new EBaseException("RemoteRequestHandler: parserResponse(): no response content.");
+ }
+ Hashtable<String, Object> vars = new Hashtable<String, Object>();
+ String[] elements = content.split(RESPONSE_SEPARATOR);
+ CMS.debug("RemoteRequestHandler: parseResponse(): # of elements:" +
+ elements.length);
+ for (String nvs : elements) {
+ String[] nv = nvs.split(NAME_VALUE_EQUAL);
+ if (nv.length == 2) {
+ vars.put(nv[0], nv[1]);
+ } else {
+ // continue to parse through
+ CMS.debug("RemoteRequestHandler: parseResponse(): content contains element not conforming to <name>=<value>.");
+ }
+ }
+ return vars;
+ }
+
+ /**
+ * Get the XML parser for XML in text
+ *
+ * @param text XML in text
+ * @return XMLObject the parser
+ */
+ protected XMLObject getXMLparser(String text) {
+ if (text == null) {
+ return null;
+ } else {
+ CMS.debug("RemoteRequestHandler: getXMLparser(): parsing: " + text);
+ }
+ try {
+ ByteArrayInputStream bis =
+ new ByteArrayInputStream(text.getBytes());
+ return new XMLObject(bis);
+ } catch (Exception e) {
+ CMS.debug("RemoteRequestHandler: getXMLparser(): failed: " + e);
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/RemoteResponse.java b/base/tps/src/org/dogtagpki/server/tps/cms/RemoteResponse.java
new file mode 100644
index 000000000..c2c7818b0
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/RemoteResponse.java
@@ -0,0 +1,40 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import java.util.Hashtable;
+
+import org.dogtagpki.server.connector.IRemoteRequest;
+
+/**
+ * RemoteResponse is the base class for remote requests
+ *
+ */
+public abstract class RemoteResponse
+{
+ protected Hashtable<String, Object> nameValTable;
+
+ public int getStatus() {
+ Integer iValue = (Integer) nameValTable.get(IRemoteRequest.RESPONSE_STATUS);
+ if (iValue == null)
+ return IRemoteRequest.RESPONSE_STATUS_NOT_FOUND;
+ else
+ return iValue.intValue();
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/TKSComputeRandomDataResponse.java b/base/tps/src/org/dogtagpki/server/tps/cms/TKSComputeRandomDataResponse.java
new file mode 100644
index 000000000..f241c88ad
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/TKSComputeRandomDataResponse.java
@@ -0,0 +1,41 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import java.util.Hashtable;
+
+import org.dogtagpki.server.connector.IRemoteRequest;
+import org.dogtagpki.tps.main.TPSBuffer;
+
+/**
+ * TKSComputeRandomDataResponse is the class for the response to
+ * TKS Remote Request: computeRandomData()
+ *
+ */
+public class TKSComputeRandomDataResponse extends RemoteResponse
+{
+ public TKSComputeRandomDataResponse(Hashtable<String, Object> ht) {
+ nameValTable = ht;
+ }
+
+ public TPSBuffer getRandomData() {
+ byte [] random = (byte[]) nameValTable.get(IRemoteRequest.TKS_RESPONSE_RandomData);
+ return new TPSBuffer(random);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/TKSComputeSessionKeyResponse.java b/base/tps/src/org/dogtagpki/server/tps/cms/TKSComputeSessionKeyResponse.java
new file mode 100644
index 000000000..2fe382539
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/TKSComputeSessionKeyResponse.java
@@ -0,0 +1,65 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import java.util.Hashtable;
+
+import org.dogtagpki.server.connector.IRemoteRequest;
+import org.dogtagpki.tps.main.TPSBuffer;
+
+/**
+ * TKSComputeSessionKeyResponse is the class for the response to
+ * TKS Remote Request: computeSessionKey()
+ *
+ */
+public class TKSComputeSessionKeyResponse extends RemoteResponse
+{
+
+ public TKSComputeSessionKeyResponse(Hashtable<String, Object> ht) {
+ nameValTable = ht;
+ }
+
+ public TPSBuffer getKeySetData() {
+ return (TPSBuffer) nameValTable.get(IRemoteRequest.TKS_RESPONSE_KeySetData);
+ }
+
+ public TPSBuffer getSessionKey() {
+ return (TPSBuffer) nameValTable.get(IRemoteRequest.TKS_RESPONSE_SessionKey);
+ }
+
+ public TPSBuffer getEncSessionKey() {
+ return (TPSBuffer) nameValTable.get(IRemoteRequest.TKS_RESPONSE_EncSessionKey);
+ }
+
+ public TPSBuffer getDRM_Trans_DesKey() {
+ return (TPSBuffer) nameValTable.get(IRemoteRequest.TKS_RESPONSE_DRM_Trans_DesKey);
+ }
+
+ public TPSBuffer getKeyCheck() {
+ return (TPSBuffer) nameValTable.get(IRemoteRequest.TKS_RESPONSE_KeyCheck);
+ }
+
+ public TPSBuffer getHostCryptogram() {
+ return (TPSBuffer) nameValTable.get(IRemoteRequest.TKS_RESPONSE_HostCryptogram);
+ }
+
+ public TPSBuffer getKekWrappedDesKey() {
+ return (TPSBuffer) nameValTable.get(IRemoteRequest.TKS_RESPONSE_KEK_DesKey);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/TKSCreateKeySetDataResponse.java b/base/tps/src/org/dogtagpki/server/tps/cms/TKSCreateKeySetDataResponse.java
new file mode 100644
index 000000000..f887c63bb
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/TKSCreateKeySetDataResponse.java
@@ -0,0 +1,41 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import java.util.Hashtable;
+
+import org.dogtagpki.server.connector.IRemoteRequest;
+import org.dogtagpki.tps.main.TPSBuffer;
+
+/**
+ * TKSCreateKeySetDataResponse is the class for the response to
+ * TKS Remote Request: createKeySetData
+ *
+ */
+public class TKSCreateKeySetDataResponse extends RemoteResponse
+{
+
+ public TKSCreateKeySetDataResponse(Hashtable<String, Object> ht) {
+ nameValTable = ht;
+ }
+
+ public TPSBuffer getKeySetData() {
+ return (TPSBuffer) nameValTable.get(IRemoteRequest.TKS_RESPONSE_KeySetData);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/TKSEncryptDataResponse.java b/base/tps/src/org/dogtagpki/server/tps/cms/TKSEncryptDataResponse.java
new file mode 100644
index 000000000..7dba17148
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/TKSEncryptDataResponse.java
@@ -0,0 +1,41 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import java.util.Hashtable;
+
+import org.dogtagpki.server.connector.IRemoteRequest;
+import org.dogtagpki.tps.main.TPSBuffer;
+
+/**
+ * TKSEncryptDataResponse is the class for the response to
+ * TKS Remote Request: encryptData
+ *
+ */
+public class TKSEncryptDataResponse extends RemoteResponse
+{
+
+ public TKSEncryptDataResponse(Hashtable<String, Object> ht) {
+ nameValTable = ht;
+ }
+
+ public TPSBuffer getEncryptedData() {
+ return (TPSBuffer) nameValTable.get(IRemoteRequest.TKS_RESPONSE_EncryptedData);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/TKSRemoteRequestHandler.java b/base/tps/src/org/dogtagpki/server/tps/cms/TKSRemoteRequestHandler.java
new file mode 100644
index 000000000..3c371a45e
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/TKSRemoteRequestHandler.java
@@ -0,0 +1,448 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import java.util.Hashtable;
+
+import org.dogtagpki.server.connector.IRemoteRequest;
+import org.dogtagpki.server.tps.TPSSubsystem;
+import org.dogtagpki.tps.main.TPSBuffer;
+import org.dogtagpki.tps.main.Util;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.cmscore.connector.HttpConnector;
+import com.netscape.cmsutil.http.HttpResponse;
+
+/**
+ * TKSRemoteRequestHandler is a class representing remote requests
+ * offered by the Token Key Service Authority (TKS)
+ * On a successful return, name/value pairs are provided in a Hashtable where
+ * all contents are URL decoded if needed
+ *
+ * @author cfu
+ */
+public class TKSRemoteRequestHandler extends RemoteRequestHandler
+{
+ public TKSRemoteRequestHandler(String connID)
+ throws EBaseException {
+
+ if (connID == null) {
+ throw new EBaseException("TKSRemoteRequestHandler: TKSRemoteRequestHandler(): connID null.");
+ }
+
+ connid = connID;
+ }
+
+ /*
+ * computeSessionKey
+ *
+ * Usage Example:
+ * TKSRemoteRequestHandler tksReq = new TKSRemoteRequestHandler("tks1");
+ * TKSComputeSessionKeyResponse responseObj =
+ * tksReq.computeSessionKey(
+ * cuid,
+ * keyInfo,
+ * card_challenge,
+ * card_cryptogram,
+ * host_challenge);
+ * - on success return, one can say
+ * TPSBuffer value = responseObj.getSessionKey();
+ * to get response param value session key
+ *
+ * @param cuid token cuid
+ * @param keyInfo keyInfo
+ * @param card_challenge card challenge
+ * @param card_cryptogram card cryptogram
+ * @param host_challenge host challenge
+ * @return response TKSComputeSessionKeyResponse class object
+ */
+ public TKSComputeSessionKeyResponse computeSessionKey(
+ TPSBuffer cuid,
+ TPSBuffer keyInfo,
+ TPSBuffer card_challenge,
+ TPSBuffer card_cryptogram,
+ TPSBuffer host_challenge,
+ String tokenType)
+ throws EBaseException {
+
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): begins.");
+ if (cuid == null || keyInfo == null || card_challenge == null
+ || card_cryptogram == null || host_challenge == null) {
+ throw new EBaseException("TKSRemoteRequestHandler: computeSessionKey(): input parameter null.");
+ }
+
+ IConfigStore conf = CMS.getConfigStore();
+
+ boolean serverKeygen =
+ conf.getBoolean("op.enroll." +
+ tokenType + ".keyGen.encryption.serverKeygen.enable",
+ false);
+ String keySet =
+ conf.getString("connector." + connid + "keySet", "defKeySet");
+
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ HttpConnector conn =
+ (HttpConnector) subsystem.getConnectionManager().getConnector(connid);
+
+ String requestString = IRemoteRequest.SERVER_SIDE_KEYGEN + "=" + serverKeygen +
+ "&" + IRemoteRequest.TOKEN_CUID + "=" + Util.specialURLEncode(cuid) +
+ "&" + IRemoteRequest.TOKEN_CARD_CHALLENGE + "=" + Util.specialURLEncode(card_challenge) +
+ "&" + IRemoteRequest.TOKEN_HOST_CHALLENGE + "=" + Util.specialURLEncode(host_challenge) +
+ "&" + IRemoteRequest.TOKEN_KEYINFO + "=" + Util.specialURLEncode(keyInfo) +
+ "&" + IRemoteRequest.TOKEN_CARD_CRYPTOGRAM + "="
+ + Util.specialURLEncode(card_cryptogram.toBytesArray()) +
+ "&" + IRemoteRequest.TOKEN_KEYSET + "=" + keySet;
+
+ CMS.debug("TKSRemoteRequestHandler.computeSessionKey: outgoing message: " + requestString);
+
+ HttpResponse resp =
+ conn.send("computeSessionKey",
+ requestString
+ );
+
+ String content = resp.getContent();
+
+ if (content != null && !content.equals("")) {
+ Hashtable<String, Object> response =
+ parseResponse(content);
+
+ /*
+ * When a value is not found in response, keep going so we know
+ * what else is missing
+ * Note: serverKeygen and !serverKeygen returns different set of
+ * response values so "missing" might not be bad
+ */
+ Integer ist = new Integer(IRemoteRequest.RESPONSE_STATUS_NOT_FOUND);
+ String value = (String) response.get(IRemoteRequest.RESPONSE_STATUS);
+ if (value == null) {
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): status not found.");
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): got content = " + content);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): got status = " + value);
+ ist = Integer.parseInt(value);
+ }
+ response.put(IRemoteRequest.RESPONSE_STATUS, ist);
+
+ value = (String) response.get(IRemoteRequest.TKS_RESPONSE_SessionKey);
+ if (value == null) {
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): response missing name-value pair for: " +
+ IRemoteRequest.TKS_RESPONSE_SessionKey);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): got IRemoteRequest.TKS_RESPONSE_SessionKey = ");
+ response.put(IRemoteRequest.TKS_RESPONSE_SessionKey, Util.specialDecode(value));
+ }
+
+ value = (String) response.get(IRemoteRequest.TKS_RESPONSE_EncSessionKey);
+ if (value == null) {
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): response missing name-value pair for: " +
+ IRemoteRequest.TKS_RESPONSE_EncSessionKey);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): got IRemoteRequest.TKS_RESPONSE_EncSessionKey = ");
+ response.put(IRemoteRequest.TKS_RESPONSE_EncSessionKey, Util.specialDecode(value));
+ }
+
+ value = (String) response.get(IRemoteRequest.TKS_RESPONSE_DRM_Trans_DesKey);
+ if (value == null) {
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): response missing name-value pair for: " +
+ IRemoteRequest.TKS_RESPONSE_DRM_Trans_DesKey);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): got IRemoteRequest.TKS_RESPONSE_DRM_Trans_DesKey = ");
+ response.put(IRemoteRequest.TKS_RESPONSE_DRM_Trans_DesKey, Util.specialDecode(value));
+ }
+
+ value = (String) response.get(IRemoteRequest.TKS_RESPONSE_KEK_DesKey);
+ if (value == null) {
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): response missing name-value pair for: " +
+ IRemoteRequest.TKS_RESPONSE_KEK_DesKey);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): got IRemoteRequest.TKS_RESPONSE_KEK_DesKey = ");
+ response.put(IRemoteRequest.TKS_RESPONSE_KEK_DesKey, Util.specialDecode(value));
+ }
+
+ value = (String) response.get(IRemoteRequest.TKS_RESPONSE_KeyCheck);
+ if (value == null) {
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): response missing name-value pair for: " +
+ IRemoteRequest.TKS_RESPONSE_KeyCheck);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): got IRemoteRequest.TKS_RESPONSE_KeyCheck = ");
+ response.put(IRemoteRequest.TKS_RESPONSE_KeyCheck, Util.specialDecode(value));
+ }
+
+ value = (String) response.get(IRemoteRequest.TKS_RESPONSE_HostCryptogram);
+ if (value == null) {
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): response missing name-value pair for: " +
+ IRemoteRequest.TKS_RESPONSE_HostCryptogram);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): got IRemoteRequest.TKS_RESPONSE_HostCryptogram = ");
+ response.put(IRemoteRequest.TKS_RESPONSE_HostCryptogram, Util.specialDecode(value));
+ }
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): ends.");
+
+ return new TKSComputeSessionKeyResponse(response);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: computeSessionKey(): no response content.");
+ throw new EBaseException("TKSRemoteRequestHandler: computeSessionKey(): no response content.");
+ }
+ }
+
+ /*
+ * createKeySetData
+ *
+ * Usage Example:
+ * TKSRemoteRequestHandler tksReq = new TKSRemoteRequestHandler("tks1");
+ * TKSCreateKeySetDataResponse responseObj =
+ * tksReq.createKeySetData(
+ * NewMasterVer,
+ * version,
+ * cuid)
+ * - on success return, one can say
+ * TPSBuffer value = responseObj.getKeySetData();
+ * to get response param value keySetData
+ *
+ * @param NewMasterVer newKeyInfo
+ * @param version keyInfo
+ * @param cuid token cuid
+ * @return response TKSCreateKeySetDataResponse class object
+ */
+ public TKSCreateKeySetDataResponse createKeySetData(
+ TPSBuffer NewMasterVer,
+ TPSBuffer version,
+ TPSBuffer cuid)
+ throws EBaseException {
+ CMS.debug("TKSRemoteRequestHandler: createKeySetData(): begins.");
+ if (cuid == null || NewMasterVer == null || version == null) {
+ throw new EBaseException("TKSRemoteRequestHandler: createKeySetData(): input parameter null.");
+ }
+
+ IConfigStore conf = CMS.getConfigStore();
+ String keySet =
+ conf.getString("connector." + connid + "keySet", "defKeySet");
+
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ HttpConnector conn =
+ (HttpConnector) subsystem.getConnectionManager().getConnector(connid);
+ CMS.debug("TKSRemoteRequestHandler: createKeySetData(): sending request to tks.");
+ HttpResponse resp =
+ conn.send("createKeySetData",
+ IRemoteRequest.TOKEN_NEW_KEYINFO + "=" + Util.specialURLEncode(NewMasterVer) +
+ "&" + IRemoteRequest.TOKEN_CUID + "=" + Util.specialURLEncode(cuid) +
+ "&" + IRemoteRequest.TOKEN_KEYINFO + "=" + Util.specialURLEncode(version) +
+ "&" + IRemoteRequest.TOKEN_KEYSET + "=" + keySet);
+
+ String content = resp.getContent();
+
+ if (content != null && !content.equals("")) {
+ Hashtable<String, Object> response =
+ parseResponse(content);
+ if (response == null) {
+ CMS.debug("TKSRemoteRequestHandler: createKeySetData(): parseResponse returned null.");
+ return null;
+ }
+
+ /*
+ * When a value is not found in response, keep going so we know
+ * what else is missing
+ */
+ Integer ist = new Integer(IRemoteRequest.RESPONSE_STATUS_NOT_FOUND);
+ String value = (String) response.get(IRemoteRequest.RESPONSE_STATUS);
+ if (value == null) {
+ CMS.debug("TKSRemoteRequestHandler: createKeySetData(): status not found.");
+ CMS.debug("TKSRemoteRequestHandler: createKeySetData(): got content = " + content);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: createKeySetData(): got status = " + value);
+ ist = Integer.parseInt(value);
+ }
+ response.put(IRemoteRequest.RESPONSE_STATUS, ist);
+
+ value = (String) response.get(IRemoteRequest.TKS_RESPONSE_KeySetData);
+ if (value == null) {
+ CMS.debug("TKSRemoteRequestHandler: createKeySetData(): response missing name-value pair for: " +
+ IRemoteRequest.TKS_RESPONSE_KeySetData);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: createKeySetData(): got IRemoteRequest.TKS_RESPONSE_KeySetData = ");
+ response.put(IRemoteRequest.TKS_RESPONSE_KeySetData, Util.specialDecode(value));
+ }
+ CMS.debug("TKSRemoteRequestHandler: createKeySetData(): ends.");
+
+ return new TKSCreateKeySetDataResponse(response);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: createKeySetData(): no response content.");
+ throw new EBaseException("TKSRemoteRequestHandler: createKeySetData(): no response content.");
+ }
+ }
+
+ /*
+ * computeRandomData
+ *
+ * Usage Example:
+ * TKSRemoteRequestHandler tksReq = new TKSRemoteRequestHandler("tks1");
+ * TKSComputeRandomDataResponse responseObj =
+ * tksReq.computeRandomData(
+ * dataSize)
+ * - on success return, one can say
+ * TPSBuffer value = responseObj.getRandomData();
+ * to get response param value random data
+ *
+ * @param dataSize size of random data to be generated in number of bytes
+ * @return response TKSComputeRandomDataResponse class object
+ */
+ public TKSComputeRandomDataResponse computeRandomData(int dataSize)
+ throws EBaseException {
+ CMS.debug("TKSRemoteRequestHandler: computeRandomData(): begins.");
+ /*
+ * check for absurd dataSize values
+ */
+ if (dataSize <= 0 || dataSize > 1024) {
+ CMS.debug("TKSRemoteRequestHandler: computeRandomData(): invalid dataSize requested:" + dataSize);
+ throw new EBaseException("TKSRemoteRequestHandler: computeRandomData(): invalid dataSize requested");
+ }
+ CMS.debug("TKSRemoteRequestHandler: computeRandomData(): sending request to tks.");
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ HttpConnector conn =
+ (HttpConnector) subsystem.getConnectionManager().getConnector(connid);
+ HttpResponse resp =
+ conn.send("computeRandomData",
+ IRemoteRequest.TOKEN_DATA_NUM_BYTES + "=" + dataSize);
+
+ String content = resp.getContent();
+
+ if (content != null && !content.equals("")) {
+ Hashtable<String, Object> response =
+ parseResponse(content);
+
+ /*
+ * When a value is not found in response, keep going so we know
+ * what else is missing
+ */
+ Integer ist = new Integer(IRemoteRequest.RESPONSE_STATUS_NOT_FOUND);
+ String value = (String) response.get(IRemoteRequest.RESPONSE_STATUS);
+ if (value == null) {
+ CMS.debug("TKSRemoteRequestHandler: computeRandomData(): status not found.");
+ CMS.debug("TKSRemoteRequestHandler: computeRandomData(): got content = " + content);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: computeRandomData(): got status = " + value);
+ ist = Integer.parseInt(value);
+ }
+ response.put(IRemoteRequest.RESPONSE_STATUS, ist);
+
+ value = (String) response.get(IRemoteRequest.TKS_RESPONSE_RandomData);
+ if (value == null) {
+ CMS.debug("TKSRemoteRequestHandler: computeRandomData(): response missing name-value pair for: " +
+ IRemoteRequest.TKS_RESPONSE_RandomData);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: computeRandomData(): got IRemoteRequest.TKS_RESPONSE_RandomData = "
+ + value);
+ response.put(IRemoteRequest.TKS_RESPONSE_RandomData, Util.uriDecodeFromHex(value));
+ }
+ CMS.debug("TKSRemoteRequestHandler: computeRandomData(): ends.");
+
+ return new TKSComputeRandomDataResponse(response);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: computeRandomData(): no response content.");
+ throw new EBaseException("TKSRemoteRequestHandler: computeRandomData(): no response content.");
+ }
+ }
+
+ /*
+ * encryptData
+ *
+ * Usage Example:
+ * TKSRemoteRequestHandler tksReq = new TKSRemoteRequestHandler("tks1");
+ * TKSEncryptDataResponse responseObj =
+ * tksReq.encryptData(
+ * dataSize)
+ * - on success return, one can say
+ * TPSBuffer value = responseObj.getEncryptedData();
+ * to get response param value encrypted data
+ *
+ * @param cuid token cuid
+ * @param version keyInfo
+ * @param inData data to be encrypted
+ * @return response TKSEncryptDataResponse class object
+ */
+ public TKSEncryptDataResponse encryptData(
+ TPSBuffer cuid,
+ TPSBuffer version,
+ TPSBuffer inData)
+ throws EBaseException {
+ CMS.debug("TKSRemoteRequestHandler: encryptData(): begins.");
+ if (cuid == null || version == null || inData == null) {
+ throw new EBaseException("TKSRemoteRequestHandler: encryptData(): input parameter null.");
+ }
+
+ IConfigStore conf = CMS.getConfigStore();
+
+ String keySet =
+ conf.getString("connector." + connid + "keySet", "defKeySet");
+
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ HttpConnector conn =
+ (HttpConnector) subsystem.getConnectionManager().getConnector(connid);
+ CMS.debug("TKSRemoteRequestHandler: encryptData(): sending request to tks.");
+ HttpResponse resp =
+ conn.send("encryptData",
+ IRemoteRequest.TOKEN_DATA + "=" + Util.specialURLEncode(inData) +
+ "&" + IRemoteRequest.TOKEN_CUID + "=" + Util.specialURLEncode(cuid) +
+ "&" + IRemoteRequest.TOKEN_KEYINFO + "=" + Util.specialURLEncode(version) +
+ "&" + IRemoteRequest.TOKEN_KEYSET + "=" + keySet);
+
+ String content = resp.getContent();
+
+ if (content != null && !content.equals("")) {
+ Hashtable<String, Object> response =
+ parseResponse(content);
+
+ /*
+ * When a value is not found in response, keep going so we know
+ * what else is missing
+ */
+ Integer ist = new Integer(IRemoteRequest.RESPONSE_STATUS_NOT_FOUND);
+ String value = (String) response.get(IRemoteRequest.RESPONSE_STATUS);
+ if (value == null) {
+ CMS.debug("TKSRemoteRequestHandler: encryptData(): status not found.");
+ CMS.debug("TKSRemoteRequestHandler: encryptData(): got content = " + content);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: encryptData(): got status = " + value);
+ ist = Integer.parseInt(value);
+ }
+ response.put(IRemoteRequest.RESPONSE_STATUS, ist);
+
+ value = (String) response.get(IRemoteRequest.TKS_RESPONSE_EncryptedData);
+ if (value == null) {
+ CMS.debug("TKSRemoteRequestHandler: encryptData(): response missing name-value pair for: " +
+ IRemoteRequest.TKS_RESPONSE_EncryptedData);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: encryptData(): got IRemoteRequest.TKS_RESPONSE_EncryptedData = ");
+ response.put(IRemoteRequest.TKS_RESPONSE_EncryptedData, Util.specialDecode(value));
+ }
+ CMS.debug("TKSRemoteRequestHandler: encryptData(): ends.");
+
+ return new TKSEncryptDataResponse(response);
+ } else {
+ CMS.debug("TKSRemoteRequestHandler: encryptData(): no response content.");
+ throw new EBaseException("TKSRemoteRequestHandler: encryptData(): no response content.");
+ }
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/TKSResponse.java b/base/tps/src/org/dogtagpki/server/tps/cms/TKSResponse.java
new file mode 100644
index 000000000..37269c765
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/TKSResponse.java
@@ -0,0 +1,40 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.cms;
+
+import java.util.Hashtable;
+
+import org.dogtagpki.server.connector.IRemoteRequest;
+
+/**
+ * TKSResponse is the base class for TKS remote requests
+ *
+ */
+public abstract class TKSResponse
+{
+ protected Hashtable<String, Object> nameValTable;
+
+ public int getStatus() {
+ Integer iValue = (Integer) nameValTable.get(IRemoteRequest.RESPONSE_STATUS);
+ if (iValue == null)
+ return IRemoteRequest.RESPONSE_STATUS_NOT_FOUND;
+ else
+ return iValue.intValue();
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/config/AuthenticatorDatabase.java b/base/tps/src/org/dogtagpki/server/tps/config/AuthenticatorDatabase.java
new file mode 100644
index 000000000..292b80afb
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/config/AuthenticatorDatabase.java
@@ -0,0 +1,143 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.config;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.cmscore.dbs.CSCfgDatabase;
+
+/**
+ * This class provides access to the authenticators in CS.cfg.
+ *
+ * @author Endi S. Dewata
+ */
+public class AuthenticatorDatabase extends CSCfgDatabase<AuthenticatorRecord> {
+
+ public AuthenticatorDatabase() {
+ super("Authenticator", "Authentication_Sources");
+ }
+
+ public AuthenticatorRecord createAuthenticatorRecord(ConfigDatabase configDatabase, ConfigRecord configRecord, String authenticatorID) throws EBaseException {
+ AuthenticatorRecord authenticatorRecord = new AuthenticatorRecord();
+ authenticatorRecord.setID(authenticatorID);
+
+ String status = getRecordStatus(authenticatorID);
+ authenticatorRecord.setStatus(status);
+
+ Map<String, String> properties = configDatabase.getProperties(configRecord, authenticatorID);
+ authenticatorRecord.setProperties(properties);
+ return authenticatorRecord;
+ }
+
+ @Override
+ public Collection<AuthenticatorRecord> findRecords(String filter) throws Exception {
+
+ Collection<AuthenticatorRecord> result = new ArrayList<AuthenticatorRecord>();
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ for (String authenticatorID : configRecord.getKeys()) {
+ if (filter != null && !authenticatorID.contains(filter)) continue;
+ AuthenticatorRecord authenticatorRecord = createAuthenticatorRecord(configDatabase, configRecord, authenticatorID);
+ result.add(authenticatorRecord);
+ }
+
+ return result;
+ }
+
+ @Override
+ public AuthenticatorRecord getRecord(String authenticatorID) throws Exception {
+
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ return createAuthenticatorRecord(configDatabase, configRecord, authenticatorID);
+ }
+
+ @Override
+ public void addRecord(String authenticatorID, AuthenticatorRecord authenticatorRecord) throws Exception {
+
+ CMS.debug("AuthenticatorDatabase.addRecord(\"" + authenticatorID + "\")");
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ // validate new properties
+ Map<String, String> properties = authenticatorRecord.getProperties();
+ configDatabase.validateProperties(configRecord, authenticatorID, properties);
+
+ // add new connection
+ configRecord.addKey(authenticatorID);
+ configDatabase.updateRecord(substoreName, configRecord);
+
+ // store new properties
+ configDatabase.addProperties(configRecord, authenticatorID, properties);
+
+ // create status
+ setRecordStatus(authenticatorID, authenticatorRecord.getStatus());
+
+ configDatabase.commit();
+ }
+
+ @Override
+ public void updateRecord(String authenticatorID, AuthenticatorRecord authenticatorRecord) throws Exception {
+
+ CMS.debug("AuthenticatorDatabase.updateRecord(\"" + authenticatorID + "\")");
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ // validate new properties
+ Map<String, String> properties = authenticatorRecord.getProperties();
+ configDatabase.validateProperties(configRecord, authenticatorID, properties);
+
+ // remove old properties
+ configDatabase.removeProperties(configRecord, authenticatorID);
+
+ // add new properties
+ configDatabase.addProperties(configRecord, authenticatorID, properties);
+
+ // update status
+ setRecordStatus(authenticatorID, authenticatorRecord.getStatus());
+
+ configDatabase.commit();
+ }
+
+ @Override
+ public void removeRecord(String authenticatorID) throws Exception {
+
+ CMS.debug("AuthenticatorDatabase.removeRecord(\"" + authenticatorID + "\")");
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ // remove properties
+ configDatabase.removeProperties(configRecord, authenticatorID);
+
+ // remove connection
+ configRecord.removeKey(authenticatorID);
+ configDatabase.updateRecord(substoreName, configRecord);
+
+ // remove status
+ removeRecordStatus(authenticatorID);
+
+ configDatabase.commit();
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/config/AuthenticatorRecord.java b/base/tps/src/org/dogtagpki/server/tps/config/AuthenticatorRecord.java
new file mode 100644
index 000000000..937a25e51
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/config/AuthenticatorRecord.java
@@ -0,0 +1,28 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.config;
+
+import com.netscape.cmscore.dbs.CSCfgRecord;
+
+
+/**
+ * @author Endi S. Dewata
+ */
+public class AuthenticatorRecord extends CSCfgRecord {
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/config/ConfigDatabase.java b/base/tps/src/org/dogtagpki/server/tps/config/ConfigDatabase.java
new file mode 100644
index 000000000..db0fa9aa6
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/config/ConfigDatabase.java
@@ -0,0 +1,191 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.config;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.commons.lang.StringUtils;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.BadRequestException;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.ResourceNotFoundException;
+import com.netscape.cmscore.dbs.Database;
+
+/**
+ * This class implements in-memory connection database. In the future this
+ * will be replaced with LDAP database.
+ *
+ * @author Endi S. Dewata
+ */
+public class ConfigDatabase extends Database<ConfigRecord> {
+
+ IConfigStore configStore = CMS.getConfigStore();
+
+ public ConfigDatabase() throws EBaseException {
+ super("Configuration");
+ }
+
+ public String createFilter(ConfigRecord record, String key) {
+ String pattern = record.getPattern();
+ if (key == null) return pattern;
+ return pattern.replace("$name", key);
+ }
+
+ @Override
+ public Collection<ConfigRecord> findRecords(String filter) throws Exception {
+
+ CMS.debug("ConfigDatabase.findRecords()");
+
+ Collection<ConfigRecord> result = new ArrayList<ConfigRecord>();
+
+ Collection<String> configIDs = new LinkedHashSet<String>();
+ configIDs.add("Generals");
+
+ String list = configStore.get("target.configure.list");
+ if (list != null) {
+ configIDs.addAll(Arrays.asList(list.split(",")));
+ }
+
+ list = configStore.get("target.agent_approve.list");
+ if (list != null) {
+ configIDs.addAll(Arrays.asList(list.split(",")));
+ }
+
+ for (String configID : configIDs) {
+ if (filter != null && !configID.contains(filter)) continue;
+ ConfigRecord configData = getRecord(configID);
+ result.add(configData);
+ }
+
+ return result;
+ }
+
+ @Override
+ public ConfigRecord getRecord(String configID) throws Exception {
+
+ CMS.debug("ConfigDatabase.getRecord(\"" + configID + "\")");
+
+ ConfigRecord record = new ConfigRecord();
+ record.setID(configID);
+
+ String displayName = configStore.get("target." + configID + ".displayname");
+ if (StringUtils.isEmpty(displayName)) {
+ throw new ResourceNotFoundException("Configuration " + configID + " not found.");
+ }
+ record.setDisplayName(displayName);
+
+ String pattern = configStore.get("target." + configID + ".pattern");
+ if (StringUtils.isEmpty(pattern)) {
+ throw new ResourceNotFoundException("Missing pattern for " + configID + " configuration.");
+ }
+
+ // replace \| with |
+ record.setPattern(pattern.replace("\\|", "|"));
+
+ String list = configStore.get("target." + configID + ".list");
+ if (!StringUtils.isEmpty(list)) {
+ record.setKeys(Arrays.asList(list.split(",")));
+ }
+
+ return record;
+ }
+
+
+ @Override
+ public void updateRecord(String configID, ConfigRecord newRecord) throws Exception {
+
+ CMS.debug("ConfigDatabase.updateRecord(\"" + configID + "\")");
+
+ configStore.put("target." + configID + ".displayname", newRecord.getDisplayName());
+ configStore.put("target." + configID + ".pattern", newRecord.getPattern());
+ configStore.put("target." + configID + ".list", StringUtils.join(newRecord.getKeys(), ","));
+
+ configStore.commit(true);
+ }
+
+ public Map<String, String> getProperties(ConfigRecord record, String key) throws EBaseException {
+
+ CMS.debug("ConfigDatabase.getProperties(\"" + record.getID() + "\", \"" + key + "\")");
+
+ if (key != null && !record.containsKey(key)) {
+ throw new ResourceNotFoundException("Entry does not exist: " + key);
+ }
+
+ Map<String, String> properties = new TreeMap<String, String>();
+
+ // get properties that match the filter
+ String filter = createFilter(record, key);
+ Map<String, String> map = configStore.getProperties();
+ for (String name : map.keySet()) {
+ if (!name.matches(filter)) continue;
+
+ String value = map.get(name);
+ properties.put(name, value);
+ }
+
+ return properties;
+ }
+
+ public void validateProperties(ConfigRecord record, String key, Map<String, String> properties) throws Exception {
+
+ CMS.debug("ConfigDatabase.validateProperties(\"" + record.getID() + "\")");
+
+ String filter = createFilter(record, key);
+ for (String name : properties.keySet()) {
+ if (name.matches(filter)) continue;
+ CMS.debug("Property " + name + " doesn't match filter " + filter + ".");
+ throw new BadRequestException("Invalid property: " + name);
+ }
+ }
+
+ public void addProperties(ConfigRecord record, String key, Map<String, String> properties) throws Exception {
+
+ CMS.debug("ConfigDatabase.addProperties(\"" + record.getID() + "\")");
+
+ for (String name : properties.keySet()) {
+ String value = properties.get(name);
+ configStore.put(name, value);
+ }
+ }
+
+ public void removeProperties(ConfigRecord record, String key) throws Exception {
+
+ CMS.debug("ConfigDatabase.removeProperties(\"" + record.getID() + "\")");
+
+ Map<String, String> oldProperties = getProperties(record, key);
+ for (String name : oldProperties.keySet()) {
+ configStore.remove(name);
+ }
+ }
+
+ public void commit() throws Exception {
+
+ CMS.debug("ConfigDatabase.commit()");
+
+ // save configuration
+ configStore.commit(true);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/config/ConfigRecord.java b/base/tps/src/org/dogtagpki/server/tps/config/ConfigRecord.java
new file mode 100644
index 000000000..f1a87ddfe
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/config/ConfigRecord.java
@@ -0,0 +1,126 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.config;
+
+import java.util.Collection;
+import java.util.LinkedHashSet;
+
+import com.netscape.certsrv.base.ConflictingOperationException;
+import com.netscape.certsrv.base.ResourceNotFoundException;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class ConfigRecord {
+
+ String id;
+ String displayName;
+ String pattern;
+ Collection<String> keys = new LinkedHashSet<String>();
+
+ public String getID() {
+ return id;
+ }
+
+ public void setID(String id) {
+ this.id = id;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+ public String getPattern() {
+ return pattern;
+ }
+
+ public void setPattern(String pattern) {
+ this.pattern = pattern;
+ }
+
+ public Collection<String> getKeys() {
+ return keys;
+ }
+
+ public void setKeys(Collection<String> keys) {
+ this.keys.clear();
+ this.keys.addAll(keys);
+ }
+
+ public boolean containsKey(String key) {
+ return keys.contains(key);
+ }
+
+ public void addKey(String key) {
+ if (keys.contains(key)) throw new ConflictingOperationException("Entry already exists: " + key);
+ keys.add(key);
+ }
+
+ public void removeKey(String key) {
+ if (!keys.contains(key)) throw new ResourceNotFoundException("Entry does not exist: " + key);
+ keys.remove(key);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((displayName == null) ? 0 : displayName.hashCode());
+ result = prime * result + ((id == null) ? 0 : id.hashCode());
+ result = prime * result + ((keys == null) ? 0 : keys.hashCode());
+ result = prime * result + ((pattern == null) ? 0 : pattern.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ConfigRecord other = (ConfigRecord) obj;
+ if (displayName == null) {
+ if (other.displayName != null)
+ return false;
+ } else if (!displayName.equals(other.displayName))
+ return false;
+ if (id == null) {
+ if (other.id != null)
+ return false;
+ } else if (!id.equals(other.id))
+ return false;
+ if (keys == null) {
+ if (other.keys != null)
+ return false;
+ } else if (!keys.equals(other.keys))
+ return false;
+ if (pattern == null) {
+ if (other.pattern != null)
+ return false;
+ } else if (!pattern.equals(other.pattern))
+ return false;
+ return true;
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/config/ConfigService.java b/base/tps/src/org/dogtagpki/server/tps/config/ConfigService.java
new file mode 100644
index 000000000..6cd5e9f7d
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/config/ConfigService.java
@@ -0,0 +1,135 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.config;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.jboss.resteasy.plugins.providers.atom.Link;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.BadRequestException;
+import com.netscape.certsrv.base.PKIException;
+import com.netscape.certsrv.tps.config.ConfigData;
+import com.netscape.certsrv.tps.config.ConfigResource;
+import com.netscape.cms.servlet.base.PKIService;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class ConfigService extends PKIService implements ConfigResource {
+
+ @Context
+ private UriInfo uriInfo;
+
+ @Context
+ private HttpHeaders headers;
+
+ @Context
+ private Request request;
+
+ @Context
+ private HttpServletRequest servletRequest;
+
+ public ConfigService() {
+ CMS.debug("ConfigService.<init>()");
+ }
+
+ public ConfigData createConfigData(Map<String, String> properties) throws UnsupportedEncodingException {
+
+ ConfigData configData = new ConfigData();
+ configData.setProperties(properties);
+
+ URI uri = uriInfo.getBaseUriBuilder().path(ConfigResource.class).build();
+ configData.setLink(new Link("self", uri));
+
+ return configData;
+ }
+
+ @Override
+ public Response getConfig() {
+
+ CMS.debug("ConfigService.getConfig()");
+
+ try {
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord("Generals");
+
+ Map<String, String> properties = configDatabase.getProperties(configRecord, null);
+
+ return createOKResponse(createConfigData(properties));
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response updateConfig(ConfigData configData) {
+
+ if (configData == null) throw new BadRequestException("Config data is null.");
+
+ CMS.debug("ConfigService.updateConfig()");
+
+ try {
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord("Generals");
+
+ Map<String, String> properties = configData.getProperties();
+ if (properties != null) {
+ // validate new properties
+ configDatabase.validateProperties(configRecord, null, properties);
+
+ // remove old properties
+ configDatabase.removeProperties(configRecord, null);
+
+ // add new properties
+ configDatabase.addProperties(configRecord, null, properties);
+ }
+
+ configDatabase.commit();
+
+ properties = configDatabase.getProperties(configRecord, null);
+ configData = createConfigData(properties);
+
+ return Response
+ .ok(configData)
+ .build();
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/config/ConnectorDatabase.java b/base/tps/src/org/dogtagpki/server/tps/config/ConnectorDatabase.java
new file mode 100644
index 000000000..4b1589797
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/config/ConnectorDatabase.java
@@ -0,0 +1,242 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.config;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.cmscore.dbs.CSCfgDatabase;
+
+/**
+ * This class provides access to the connections in CS.cfg.
+ *
+ * @author Endi S. Dewata
+ */
+public class ConnectorDatabase extends CSCfgDatabase<ConnectorRecord> {
+
+ public String prefix = "tps.connector";
+
+ public ConnectorDatabase() {
+ super("Connector", "Subsystem_Connections");
+ }
+
+ public ConnectorRecord createConnectorRecord(ConfigDatabase configDatabase, ConfigRecord configRecord, String connectorID) throws EBaseException {
+ ConnectorRecord connectorRecord = new ConnectorRecord();
+ connectorRecord.setID(connectorID);
+
+ String status = getRecordStatus(connectorID);
+ connectorRecord.setStatus(status);
+
+ Map<String, String> properties = configDatabase.getProperties(configRecord, connectorID);
+ connectorRecord.setProperties(properties);
+ return connectorRecord;
+ }
+
+ @Override
+ public Collection<ConnectorRecord> findRecords(String filter) throws Exception {
+
+ Collection<ConnectorRecord> result = new ArrayList<ConnectorRecord>();
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ for (String connectorID : configRecord.getKeys()) {
+ if (filter != null && !connectorID.contains(filter)) continue;
+ ConnectorRecord connectorRecord = createConnectorRecord(configDatabase, configRecord, connectorID);
+ result.add(connectorRecord);
+ }
+
+ return result;
+ }
+
+ @Override
+ public ConnectorRecord getRecord(String connectionID) throws Exception {
+
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ return createConnectorRecord(configDatabase, configRecord, connectionID);
+ }
+
+ @Override
+ public void addRecord(String connectorID, ConnectorRecord connectorRecord) throws Exception {
+
+ CMS.debug("ConnectorDatabase.addRecord(\"" + connectorID + "\")");
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ // validate new properties
+ Map<String, String> properties = connectorRecord.getProperties();
+ configDatabase.validateProperties(configRecord, connectorID, properties);
+
+ // add new connector
+ configRecord.addKey(connectorID);
+ configDatabase.updateRecord(substoreName, configRecord);
+
+ // store new properties
+ configDatabase.addProperties(configRecord, connectorID, properties);
+
+ // create status
+ setRecordStatus(connectorID, connectorRecord.getStatus());
+
+ configDatabase.commit();
+ }
+
+ @Override
+ public void updateRecord(String connectorID, ConnectorRecord connectorRecord) throws Exception {
+
+ CMS.debug("ConnectorDatabase.updateRecord(\"" + connectorID + "\")");
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ // validate new properties
+ Map<String, String> properties = connectorRecord.getProperties();
+ configDatabase.validateProperties(configRecord, connectorID, properties);
+
+ // remove old properties
+ configDatabase.removeProperties(configRecord, connectorID);
+
+ // add new properties
+ configDatabase.addProperties(configRecord, connectorID, properties);
+
+ // update status
+ setRecordStatus(connectorID, connectorRecord.getStatus());
+
+ configDatabase.commit();
+ }
+
+ @Override
+ public void removeRecord(String connectorID) throws Exception {
+
+ CMS.debug("ConnectorDatabase.removeRecord(\"" + connectorID + "\")");
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ // remove properties
+ configDatabase.removeProperties(configRecord, connectorID);
+
+ // remove connector
+ configRecord.removeKey(connectorID);
+ configDatabase.updateRecord(substoreName, configRecord);
+
+ // remove status
+ removeRecordStatus(connectorID);
+
+ configDatabase.commit();
+ }
+
+ public String getNextID(String type) throws Exception {
+
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+ Collection<String> keys = configRecord.getKeys();
+
+ String id;
+ int n = 1;
+
+ while (true) {
+ id = type + n;
+
+ if (keys.contains(id)) {
+ // ID is already used, find the next one.
+ n++;
+
+ } else {
+ // ID is available, use this one.
+ break;
+ }
+ }
+
+ return id;
+ }
+
+ public void addCAConnector(String hostname, Integer port, String nickname) throws Exception {
+
+ String id = getNextID("ca");
+
+ ConnectorRecord record = new ConnectorRecord();
+ record.setID(id);
+ record.setStatus("Enabled");
+
+ record.setProperty(prefix + "." + id + ".enable", "true");
+ record.setProperty(prefix + "." + id + ".host", hostname);
+ record.setProperty(prefix + "." + id + ".port", port.toString());
+ record.setProperty(prefix + "." + id + ".minHttpConns", "1");
+ record.setProperty(prefix + "." + id + ".maxHttpConns", "15");
+ record.setProperty(prefix + "." + id + ".nickName", nickname);
+ record.setProperty(prefix + "." + id + ".timeout", "30");
+ record.setProperty(prefix + "." + id + ".uri.enrollment", "/ca/ee/ca/profileSubmitSSLClient");
+ record.setProperty(prefix + "." + id + ".uri.getcert", "/ca/ee/ca/displayBySerial");
+ record.setProperty(prefix + "." + id + ".uri.renewal", "/ca/ee/ca/profileSubmitSSLClient");
+ record.setProperty(prefix + "." + id + ".uri.revoke", "/ca/ee/subsystem/ca/doRevoke");
+ record.setProperty(prefix + "." + id + ".uri.unrevoke", "/ca/ee/subsystem/ca/doUnrevoke");
+
+ addRecord(id, record);
+ }
+
+ public void addKRAConnector(String hostname, Integer port, String nickname) throws Exception {
+
+ String id = getNextID("kra");
+
+ ConnectorRecord record = new ConnectorRecord();
+ record.setID(id);
+ record.setStatus("Enabled");
+
+ record.setProperty(prefix + "." + id + ".enable", "true");
+ record.setProperty(prefix + "." + id + ".host", hostname);
+ record.setProperty(prefix + "." + id + ".port", port.toString());
+ record.setProperty(prefix + "." + id + ".minHttpConns", "1");
+ record.setProperty(prefix + "." + id + ".maxHttpConns", "15");
+ record.setProperty(prefix + "." + id + ".nickName", nickname);
+ record.setProperty(prefix + "." + id + ".timeout", "30");
+ record.setProperty(prefix + "." + id + ".uri.GenerateKeyPair", "/kra/agent/kra/GenerateKeyPair");
+ record.setProperty(prefix + "." + id + ".uri.TokenKeyRecovery", "/kra/agent/kra/TokenKeyRecovery");
+
+ addRecord(id, record);
+ }
+
+ public void addTKSConnector(String hostname, Integer port, String nickname, Boolean keygen) throws Exception {
+
+ String id = getNextID("tks");
+
+ ConnectorRecord record = new ConnectorRecord();
+ record.setID(id);
+ record.setStatus("Enabled");
+
+ record.setProperty(prefix + "." + id + ".enable", "true");
+ record.setProperty(prefix + "." + id + ".host", hostname);
+ record.setProperty(prefix + "." + id + ".port", port.toString());
+ record.setProperty(prefix + "." + id + ".minHttpConns", "1");
+ record.setProperty(prefix + "." + id + ".maxHttpConns", "15");
+ record.setProperty(prefix + "." + id + ".nickName", nickname);
+ record.setProperty(prefix + "." + id + ".timeout", "30");
+ record.setProperty(prefix + "." + id + ".generateHostChallenge", "true");
+ record.setProperty(prefix + "." + id + ".serverKeygen", keygen.toString());
+ record.setProperty(prefix + "." + id + ".keySet", "defKeySet");
+ record.setProperty(prefix + "." + id + ".tksSharedSymKeyName", "sharedSecret");
+ record.setProperty(prefix + "." + id + ".uri.computeRandomData", "/tks/agent/tks/computeRandomData");
+ record.setProperty(prefix + "." + id + ".uri.computeSessionKey", "/tks/agent/tks/computeSessionKey");
+ record.setProperty(prefix + "." + id + ".uri.createKeySetData", "/tks/agent/tks/createKeySetData");
+ record.setProperty(prefix + "." + id + ".uri.encryptData", "/tks/agent/tks/encryptData");
+
+ addRecord(id, record);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/config/ConnectorRecord.java b/base/tps/src/org/dogtagpki/server/tps/config/ConnectorRecord.java
new file mode 100644
index 000000000..3123718b1
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/config/ConnectorRecord.java
@@ -0,0 +1,28 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.config;
+
+import com.netscape.cmscore.dbs.CSCfgRecord;
+
+
+/**
+ * @author Endi S. Dewata
+ */
+public class ConnectorRecord extends CSCfgRecord {
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/config/ProfileDatabase.java b/base/tps/src/org/dogtagpki/server/tps/config/ProfileDatabase.java
new file mode 100644
index 000000000..01225d309
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/config/ProfileDatabase.java
@@ -0,0 +1,144 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.config;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.cmscore.dbs.CSCfgDatabase;
+
+/**
+ * This class provides access to the profiles in CS.cfg.
+ *
+ * @author Endi S. Dewata
+ */
+public class ProfileDatabase extends CSCfgDatabase<ProfileRecord> {
+
+ public ProfileDatabase() {
+ super("Profile", "Profiles");
+ }
+
+ public ProfileRecord createProfileRecord(ConfigDatabase configDatabase, ConfigRecord configRecord, String profileID) throws EBaseException {
+ ProfileRecord profileRecord = new ProfileRecord();
+ profileRecord.setID(profileID);
+
+ String status = getRecordStatus(profileID);
+ profileRecord.setStatus(status);
+
+ Map<String, String> properties = configDatabase.getProperties(configRecord, profileID);
+ profileRecord.setProperties(properties);
+
+ return profileRecord;
+ }
+
+ @Override
+ public Collection<ProfileRecord> findRecords(String filter) throws Exception {
+
+ Collection<ProfileRecord> result = new ArrayList<ProfileRecord>();
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ for (String profileID : configRecord.getKeys()) {
+ if (filter != null && !profileID.contains(filter)) continue;
+ ProfileRecord profileRecord = createProfileRecord(configDatabase, configRecord, profileID);
+ result.add(profileRecord);
+ }
+
+ return result;
+ }
+
+ @Override
+ public ProfileRecord getRecord(String profileID) throws Exception {
+
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ return createProfileRecord(configDatabase, configRecord, profileID);
+ }
+
+ @Override
+ public void addRecord(String profileID, ProfileRecord profileRecord) throws Exception {
+
+ CMS.debug("ProfileDatabase.addRecord(\"" + profileID + "\")");
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ // validate new properties
+ Map<String, String> properties = profileRecord.getProperties();
+ configDatabase.validateProperties(configRecord, profileID, properties);
+
+ // add new profile
+ configRecord.addKey(profileID);
+ configDatabase.updateRecord(substoreName, configRecord);
+
+ // store new properties
+ configDatabase.addProperties(configRecord, profileID, properties);
+
+ // create status
+ setRecordStatus(profileID, profileRecord.getStatus());
+
+ configDatabase.commit();
+ }
+
+ @Override
+ public void updateRecord(String profileID, ProfileRecord profileRecord) throws Exception {
+
+ CMS.debug("ProfileDatabase.updateRecord(\"" + profileID + "\")");
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ // validate new properties
+ Map<String, String> properties = profileRecord.getProperties();
+ configDatabase.validateProperties(configRecord, profileID, properties);
+
+ // remove old properties
+ configDatabase.removeProperties(configRecord, profileID);
+
+ // add new properties
+ configDatabase.addProperties(configRecord, profileID, properties);
+
+ // update status
+ setRecordStatus(profileID, profileRecord.getStatus());
+
+ configDatabase.commit();
+ }
+
+ @Override
+ public void removeRecord(String profileID) throws Exception {
+
+ CMS.debug("ProfileDatabase.removeRecord(\"" + profileID + "\")");
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ // remove properties
+ configDatabase.removeProperties(configRecord, profileID);
+
+ // remove profile
+ configRecord.removeKey(profileID);
+ configDatabase.updateRecord(substoreName, configRecord);
+
+ // remove status
+ removeRecordStatus(profileID);
+
+ configDatabase.commit();
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/config/ProfileMappingDatabase.java b/base/tps/src/org/dogtagpki/server/tps/config/ProfileMappingDatabase.java
new file mode 100644
index 000000000..67a21d6ac
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/config/ProfileMappingDatabase.java
@@ -0,0 +1,144 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.config;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.cmscore.dbs.CSCfgDatabase;
+
+/**
+ * This class provides access to the profileMappings in CS.cfg.
+ *
+ * @author Endi S. Dewata
+ */
+public class ProfileMappingDatabase extends CSCfgDatabase<ProfileMappingRecord> {
+
+ public ProfileMappingDatabase() {
+ super("Profile Mapping", "Profile_Mappings");
+ }
+
+ public ProfileMappingRecord createProfileMappingRecord(ConfigDatabase configDatabase, ConfigRecord configRecord, String profileMappingID) throws EBaseException {
+ ProfileMappingRecord profileMappingRecord = new ProfileMappingRecord();
+ profileMappingRecord.setID(profileMappingID);
+
+ String status = getRecordStatus(profileMappingID);
+ profileMappingRecord.setStatus(status);
+
+ Map<String, String> properties = configDatabase.getProperties(configRecord, profileMappingID);
+ profileMappingRecord.setProperties(properties);
+ return profileMappingRecord;
+ }
+
+ @Override
+ public Collection<ProfileMappingRecord> findRecords(String filter) throws Exception {
+
+ Collection<ProfileMappingRecord> result = new ArrayList<ProfileMappingRecord>();
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ for (String profileMappingID : configRecord.getKeys()) {
+ if (filter != null && !profileMappingID.contains(filter)) continue;
+ ProfileMappingRecord profileMappingRecord = createProfileMappingRecord(configDatabase, configRecord, profileMappingID);
+ result.add(profileMappingRecord);
+ }
+
+ return result;
+ }
+
+ @Override
+ public ProfileMappingRecord getRecord(String profileMappingID) throws Exception {
+
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ return createProfileMappingRecord(configDatabase, configRecord, profileMappingID);
+ }
+
+
+ @Override
+ public void addRecord(String profileMappingID, ProfileMappingRecord profileMappingRecord) throws Exception {
+
+ CMS.debug("ProfileMappingDatabase.addRecord(\"" + profileMappingID + "\")");
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ // validate new properties
+ Map<String, String> properties = profileMappingRecord.getProperties();
+ configDatabase.validateProperties(configRecord, profileMappingID, properties);
+
+ // add new profileMapping
+ configRecord.addKey(profileMappingID);
+ configDatabase.updateRecord(substoreName, configRecord);
+
+ // store new properties
+ configDatabase.addProperties(configRecord, profileMappingID, properties);
+
+ // create status
+ setRecordStatus(profileMappingID, profileMappingRecord.getStatus());
+
+ configDatabase.commit();
+ }
+
+ @Override
+ public void updateRecord(String profileMappingID, ProfileMappingRecord profileMappingRecord) throws Exception {
+
+ CMS.debug("ProfileMappingDatabase.updateRecord(\"" + profileMappingID + "\")");
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ // validate new properties
+ Map<String, String> properties = profileMappingRecord.getProperties();
+ configDatabase.validateProperties(configRecord, profileMappingID, properties);
+
+ // remove old properties
+ configDatabase.removeProperties(configRecord, profileMappingID);
+
+ // add new properties
+ configDatabase.addProperties(configRecord, profileMappingID, properties);
+
+ // update status
+ setRecordStatus(profileMappingID, profileMappingRecord.getStatus());
+
+ configDatabase.commit();
+ }
+
+ @Override
+ public void removeRecord(String profileMappingID) throws Exception {
+
+ CMS.debug("ProfileMappingDatabase.removeRecord(\"" + profileMappingID + "\")");
+ ConfigDatabase configDatabase = new ConfigDatabase();
+ ConfigRecord configRecord = configDatabase.getRecord(substoreName);
+
+ // remove properties
+ configDatabase.removeProperties(configRecord, profileMappingID);
+
+ // remove profileMapping
+ configRecord.removeKey(profileMappingID);
+ configDatabase.updateRecord(substoreName, configRecord);
+
+ // remove status
+ removeRecordStatus(profileMappingID);
+
+ configDatabase.commit();
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/config/ProfileMappingRecord.java b/base/tps/src/org/dogtagpki/server/tps/config/ProfileMappingRecord.java
new file mode 100644
index 000000000..92793ce5e
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/config/ProfileMappingRecord.java
@@ -0,0 +1,28 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.config;
+
+import com.netscape.cmscore.dbs.CSCfgRecord;
+
+
+/**
+ * @author Endi S. Dewata
+ */
+public class ProfileMappingRecord extends CSCfgRecord {
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/config/ProfileRecord.java b/base/tps/src/org/dogtagpki/server/tps/config/ProfileRecord.java
new file mode 100644
index 000000000..a84b7f5ba
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/config/ProfileRecord.java
@@ -0,0 +1,28 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.config;
+
+import com.netscape.cmscore.dbs.CSCfgRecord;
+
+
+/**
+ * @author Endi S. Dewata
+ */
+public class ProfileRecord extends CSCfgRecord {
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/dbs/ActivityDatabase.java b/base/tps/src/org/dogtagpki/server/tps/dbs/ActivityDatabase.java
new file mode 100644
index 000000000..9b4a4b28d
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/dbs/ActivityDatabase.java
@@ -0,0 +1,100 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.dbs;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import org.apache.commons.lang.StringUtils;
+import org.dogtagpki.tps.main.Util;
+
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.dbs.IDBSubsystem;
+import com.netscape.cmscore.dbs.LDAPDatabase;
+import com.netscape.cmsutil.ldap.LDAPUtil;
+
+/**
+ * This class implements in-memory activity database. In the future this
+ * will be replaced with LDAP database.
+ *
+ * @author Endi S. Dewata
+ */
+public class ActivityDatabase extends LDAPDatabase<ActivityRecord> {
+ public final static String OP_DO_TOKEN = "do_token";
+ public final static String OP_ADD = "add"; // add a token
+ public final static String OP_DELETE = "delete"; // delete a token
+ //public final static String OP_MODIFY_AUDIT_SIGNING = "modify_audit_signing";
+ public final static String OP_ENROLLMENT = "enrollment";
+ public final static String OP_RENEWAL = "renewal";
+ public final static String OP_PIN_RESET = "pin_reset";
+ public final static String OP_FORMAT = "format";
+
+ public ActivityDatabase(IDBSubsystem dbSubsystem, String baseDN) throws EBaseException {
+ super("Activity", dbSubsystem, baseDN, ActivityRecord.class);
+ }
+
+ public ActivityRecord log(
+ String ip, String tokenID, String operation, String result,
+ String message, String userID, String tokenType) throws Exception {
+ Calendar c = Calendar.getInstance();
+
+ String timeString = Util.getTimeStampString(true);
+ long threadID = Thread.currentThread().getId();
+ String threadIDS = String.format("%x", threadID);
+ String id = timeString + "." + threadIDS;
+
+ ActivityRecord activityRecord = new ActivityRecord();
+ activityRecord.setId(id);
+ activityRecord.setIP(ip);
+ activityRecord.setTokenID(tokenID);
+ activityRecord.setOperation(operation);
+ activityRecord.setResult(result);
+ activityRecord.setMessage(message);
+ activityRecord.setUserID(userID);
+ activityRecord.setType(tokenType);
+ activityRecord.setDate(c.getTime());
+
+ super.addRecord(id, activityRecord);
+
+ return activityRecord;
+ }
+
+ @Override
+ public void addRecord(String id, ActivityRecord activityRecord) throws Exception {
+ activityRecord.setDate(new Date());
+
+ super.addRecord(id, activityRecord);
+ }
+
+ @Override
+ public String createDN(String id) {
+ return "cn=" + id + "," + baseDN;
+ }
+
+ @Override
+ public String createFilter(String filter) {
+
+ if (StringUtils.isEmpty(filter)) {
+ return "(id=*)";
+ }
+
+ filter = LDAPUtil.escapeFilter(filter);
+ return "(|(tokenID=*" + filter + "*)(userID=*" + filter + "*))";
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/dbs/ActivityRecord.java b/base/tps/src/org/dogtagpki/server/tps/dbs/ActivityRecord.java
new file mode 100644
index 000000000..fe5b1f91c
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/dbs/ActivityRecord.java
@@ -0,0 +1,214 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.dbs;
+
+import java.util.Date;
+
+import com.netscape.cmscore.dbs.DBAttribute;
+import com.netscape.cmscore.dbs.DBObjectClasses;
+import com.netscape.cmscore.dbs.DBRecord;
+
+/**
+ * @author Endi S. Dewata
+ */
+@DBObjectClasses({ "top", "tokenActivity" })
+public class ActivityRecord extends DBRecord {
+
+ private static final long serialVersionUID = 1L;
+
+ String id;
+ String tokenID;
+ String userID;
+ String ip;
+ String operation;
+ String result;
+ String message;
+ String extensions;
+ String type;
+ Date date;
+
+ @DBAttribute("cn")
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ @DBAttribute("tokenID")
+ public String getTokenID() {
+ return tokenID;
+ }
+
+ public void setTokenID(String tokenID) {
+ this.tokenID = tokenID;
+ }
+
+ @DBAttribute("tokenUserID")
+ public String getUserID() {
+ return userID;
+ }
+
+ public void setUserID(String userID) {
+ this.userID = userID;
+ }
+
+ @DBAttribute("tokenIP")
+ public String getIP() {
+ return ip;
+ }
+
+ public void setIP(String ip) {
+ this.ip = ip;
+ }
+
+ @DBAttribute("tokenOp")
+ public String getOperation() {
+ return operation;
+ }
+
+ public void setOperation(String operation) {
+ this.operation = operation;
+ }
+
+ @DBAttribute("tokenResult")
+ public String getResult() {
+ return result;
+ }
+
+ public void setResult(String result) {
+ this.result = result;
+ }
+
+ @DBAttribute("tokenMsg")
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ @DBAttribute("extensions")
+ public String getExtensions() {
+ return extensions;
+ }
+
+ public void setExtensions(String extensions) {
+ this.extensions = extensions;
+ }
+
+ @DBAttribute("tokenType")
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ @DBAttribute("dateOfCreate")
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((date == null) ? 0 : date.hashCode());
+ result = prime * result + ((extensions == null) ? 0 : extensions.hashCode());
+ result = prime * result + ((id == null) ? 0 : id.hashCode());
+ result = prime * result + ((ip == null) ? 0 : ip.hashCode());
+ result = prime * result + ((message == null) ? 0 : message.hashCode());
+ result = prime * result + ((operation == null) ? 0 : operation.hashCode());
+ result = prime * result + ((this.result == null) ? 0 : this.result.hashCode());
+ result = prime * result + ((tokenID == null) ? 0 : tokenID.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ result = prime * result + ((userID == null) ? 0 : userID.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ActivityRecord other = (ActivityRecord) obj;
+ if (date == null) {
+ if (other.date != null)
+ return false;
+ } else if (!date.equals(other.date))
+ return false;
+ if (extensions == null) {
+ if (other.extensions != null)
+ return false;
+ } else if (!extensions.equals(other.extensions))
+ return false;
+ if (id == null) {
+ if (other.id != null)
+ return false;
+ } else if (!id.equals(other.id))
+ return false;
+ if (ip == null) {
+ if (other.ip != null)
+ return false;
+ } else if (!ip.equals(other.ip))
+ return false;
+ if (message == null) {
+ if (other.message != null)
+ return false;
+ } else if (!message.equals(other.message))
+ return false;
+ if (operation == null) {
+ if (other.operation != null)
+ return false;
+ } else if (!operation.equals(other.operation))
+ return false;
+ if (result == null) {
+ if (other.result != null)
+ return false;
+ } else if (!result.equals(other.result))
+ return false;
+ if (tokenID == null) {
+ if (other.tokenID != null)
+ return false;
+ } else if (!tokenID.equals(other.tokenID))
+ return false;
+ if (type == null) {
+ if (other.type != null)
+ return false;
+ } else if (!type.equals(other.type))
+ return false;
+ if (userID == null) {
+ if (other.userID != null)
+ return false;
+ } else if (!userID.equals(other.userID))
+ return false;
+ return true;
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/dbs/TPSCertDatabase.java b/base/tps/src/org/dogtagpki/server/tps/dbs/TPSCertDatabase.java
new file mode 100644
index 000000000..7450b0665
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/dbs/TPSCertDatabase.java
@@ -0,0 +1,71 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.dbs;
+
+import java.util.Date;
+
+import org.apache.commons.lang.StringUtils;
+
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.dbs.IDBSubsystem;
+import com.netscape.cmscore.dbs.LDAPDatabase;
+import com.netscape.cmsutil.ldap.LDAPUtil;
+
+/**
+ * This class implements in-memory activity database. In the future this
+ * will be replaced with LDAP database.
+ *
+ * @author Endi S. Dewata
+ */
+public class TPSCertDatabase extends LDAPDatabase<TPSCertRecord> {
+
+ public TPSCertDatabase(IDBSubsystem dbSubsystem, String baseDN) throws EBaseException {
+ super("Certificate", dbSubsystem, baseDN, TPSCertRecord.class);
+ }
+
+ @Override
+ public void addRecord(String id, TPSCertRecord certRecord) throws Exception {
+ certRecord.setCreateTime(new Date());
+
+ super.addRecord(id, certRecord);
+ }
+
+ @Override
+ public void updateRecord(String id, TPSCertRecord certRecord) throws Exception {
+ certRecord.setModifyTime(new Date());
+
+ super.updateRecord(id, certRecord);
+ }
+
+ @Override
+ public String createDN(String id) {
+ return "cn=" + id + "," + baseDN;
+ }
+
+ @Override
+ public String createFilter(String filter) {
+
+ if (StringUtils.isEmpty(filter)) {
+ return "(id=*)";
+ }
+
+ filter = LDAPUtil.escapeFilter(filter);
+ return "(|(id=*" + filter + "*)(tokenID=*" + filter + "*)(userID=*" + filter + "*))";
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/dbs/TPSCertRecord.java b/base/tps/src/org/dogtagpki/server/tps/dbs/TPSCertRecord.java
new file mode 100644
index 000000000..288f25f53
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/dbs/TPSCertRecord.java
@@ -0,0 +1,313 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.dbs;
+
+import java.util.Date;
+
+import com.netscape.cmscore.dbs.DBAttribute;
+import com.netscape.cmscore.dbs.DBObjectClasses;
+import com.netscape.cmscore.dbs.DBRecord;
+
+/**
+ * @author Endi S. Dewata
+ */
+@DBObjectClasses({ "top", "tokenCert" })
+public class TPSCertRecord extends DBRecord {
+
+ private static final long serialVersionUID = 1L;
+
+ String id;
+ String serialNumber;
+ String subject;
+ String tokenID;
+ String keyType;
+ String status;
+ String userID;
+ String certificate;
+ String issuedBy;
+ String origin;
+ String type;
+ Date validNotBefore;
+ Date validNotAfter;
+ String extensions;
+ Date createTime;
+ Date modifyTime;
+
+ @DBAttribute("cn")
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ // the serial number is in HEX
+ @DBAttribute("tokenSerial")
+ public String getSerialNumber() {
+ return serialNumber;
+ }
+
+ public void setSerialNumber(String serialNumber) {
+ this.serialNumber = serialNumber;
+ }
+
+ @DBAttribute("tokenSubject")
+ public String getSubject() {
+ return subject;
+ }
+
+ public void setSubject(String subject) {
+ this.subject = subject;
+ }
+
+ @DBAttribute("tokenID")
+ public String getTokenID() {
+ return tokenID;
+ }
+
+ public void setTokenID(String tokenID) {
+ this.tokenID = tokenID;
+ }
+
+ @DBAttribute("tokenKeyType")
+ public String getKeyType() {
+ return keyType;
+ }
+
+ public void setKeyType(String keyType) {
+ this.keyType = keyType;
+ }
+
+ @DBAttribute("tokenStatus")
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ @DBAttribute("tokenUserID")
+ public String getUserID() {
+ return userID;
+ }
+
+ public void setUserID(String userID) {
+ this.userID = userID;
+ }
+
+ @DBAttribute("userCertificate")
+ // Alternative to the actual certificate -- certificate AKI
+ public String getCertificate() {
+ return certificate;
+ }
+
+ // Alternative to the actual certificate -- certificate AKI
+ public void setCertificate(String certificate) {
+ this.certificate = certificate;
+ }
+
+ @DBAttribute("tokenIssuer")
+ public String getIssuedBy() {
+ return issuedBy;
+ }
+
+ public void setIssuedBy(String issuedBy) {
+ this.issuedBy = issuedBy;
+ }
+
+ @DBAttribute("tokenOrigin")
+ public String getOrigin() {
+ return origin;
+ }
+
+ public void setOrigin(String origin) {
+ this.origin = origin;
+ }
+
+ @DBAttribute("tokenType")
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ @DBAttribute("tokenNotBefore")
+ public Date getValidNotBefore() {
+ return validNotBefore;
+ }
+
+ public void setValidNotBefore(Date validNotBefore) {
+ this.validNotBefore = validNotBefore;
+ }
+
+ @DBAttribute("tokenNotAfter")
+ public Date getValidNotAfter() {
+ return validNotAfter;
+ }
+
+ public void setValidNotAfter(Date validNotAfter) {
+ this.validNotAfter = validNotAfter;
+ }
+
+ @DBAttribute("extensions")
+ public String getExtensions() {
+ return extensions;
+ }
+
+ public void setExtensions(String extensions) {
+ this.extensions = extensions;
+ }
+
+ @DBAttribute("dateOfCreate")
+ public Date getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(Date createTime) {
+ this.createTime = createTime;
+ }
+
+ @DBAttribute("dateOfModify")
+ public Date getModifyTime() {
+ return modifyTime;
+ }
+
+ public void setModifyTime(Date modifyTime) {
+ this.modifyTime = modifyTime;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((certificate == null) ? 0 : certificate.hashCode());
+ result = prime * result + ((createTime == null) ? 0 : createTime.hashCode());
+ result = prime * result + ((extensions == null) ? 0 : extensions.hashCode());
+ result = prime * result + ((id == null) ? 0 : id.hashCode());
+ result = prime * result + ((issuedBy == null) ? 0 : issuedBy.hashCode());
+ result = prime * result + ((keyType == null) ? 0 : keyType.hashCode());
+ result = prime * result + ((modifyTime == null) ? 0 : modifyTime.hashCode());
+ result = prime * result + ((origin == null) ? 0 : origin.hashCode());
+ result = prime * result + ((serialNumber == null) ? 0 : serialNumber.hashCode());
+ result = prime * result + ((status == null) ? 0 : status.hashCode());
+ result = prime * result + ((subject == null) ? 0 : subject.hashCode());
+ result = prime * result + ((tokenID == null) ? 0 : tokenID.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ result = prime * result + ((userID == null) ? 0 : userID.hashCode());
+ result = prime * result + ((validNotAfter == null) ? 0 : validNotAfter.hashCode());
+ result = prime * result + ((validNotBefore == null) ? 0 : validNotBefore.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ TPSCertRecord other = (TPSCertRecord) obj;
+ if (certificate == null) {
+ if (other.certificate != null)
+ return false;
+ } else if (!certificate.equals(other.certificate))
+ return false;
+ if (createTime == null) {
+ if (other.createTime != null)
+ return false;
+ } else if (!createTime.equals(other.createTime))
+ return false;
+ if (extensions == null) {
+ if (other.extensions != null)
+ return false;
+ } else if (!extensions.equals(other.extensions))
+ return false;
+ if (id == null) {
+ if (other.id != null)
+ return false;
+ } else if (!id.equals(other.id))
+ return false;
+ if (issuedBy == null) {
+ if (other.issuedBy != null)
+ return false;
+ } else if (!issuedBy.equals(other.issuedBy))
+ return false;
+ if (keyType == null) {
+ if (other.keyType != null)
+ return false;
+ } else if (!keyType.equals(other.keyType))
+ return false;
+ if (modifyTime == null) {
+ if (other.modifyTime != null)
+ return false;
+ } else if (!modifyTime.equals(other.modifyTime))
+ return false;
+ if (origin == null) {
+ if (other.origin != null)
+ return false;
+ } else if (!origin.equals(other.origin))
+ return false;
+ if (serialNumber == null) {
+ if (other.serialNumber != null)
+ return false;
+ } else if (!serialNumber.equals(other.serialNumber))
+ return false;
+ if (status == null) {
+ if (other.status != null)
+ return false;
+ } else if (!status.equals(other.status))
+ return false;
+ if (subject == null) {
+ if (other.subject != null)
+ return false;
+ } else if (!subject.equals(other.subject))
+ return false;
+ if (tokenID == null) {
+ if (other.tokenID != null)
+ return false;
+ } else if (!tokenID.equals(other.tokenID))
+ return false;
+ if (type == null) {
+ if (other.type != null)
+ return false;
+ } else if (!type.equals(other.type))
+ return false;
+ if (userID == null) {
+ if (other.userID != null)
+ return false;
+ } else if (!userID.equals(other.userID))
+ return false;
+ if (validNotAfter == null) {
+ if (other.validNotAfter != null)
+ return false;
+ } else if (!validNotAfter.equals(other.validNotAfter))
+ return false;
+ if (validNotBefore == null) {
+ if (other.validNotBefore != null)
+ return false;
+ } else if (!validNotBefore.equals(other.validNotBefore))
+ return false;
+ return true;
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/dbs/TokenDatabase.java b/base/tps/src/org/dogtagpki/server/tps/dbs/TokenDatabase.java
new file mode 100644
index 000000000..f86c6e203
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/dbs/TokenDatabase.java
@@ -0,0 +1,68 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.dbs;
+
+import java.util.Date;
+
+import org.apache.commons.lang.StringUtils;
+
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.dbs.IDBSubsystem;
+import com.netscape.cmscore.dbs.LDAPDatabase;
+import com.netscape.cmsutil.ldap.LDAPUtil;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class TokenDatabase extends LDAPDatabase<TokenRecord> {
+
+ public TokenDatabase(IDBSubsystem dbSubsystem, String baseDN) throws EBaseException {
+ super("Token", dbSubsystem, baseDN, TokenRecord.class);
+ }
+
+ @Override
+ public void addRecord(String id, TokenRecord tokenRecord) throws Exception {
+ tokenRecord.setCreateTimestamp(new Date());
+
+ super.addRecord(id, tokenRecord);
+ }
+
+ @Override
+ public void updateRecord(String id, TokenRecord tokenRecord) throws Exception {
+ tokenRecord.setModifyTimestamp(new Date());
+
+ super.updateRecord(id, tokenRecord);
+ }
+
+ @Override
+ public String createDN(String id) {
+ return "cn=" + id + "," + baseDN;
+ }
+
+ @Override
+ public String createFilter(String filter) {
+
+ if (StringUtils.isEmpty(filter)) {
+ return "(id=*)";
+ }
+
+ filter = LDAPUtil.escapeFilter(filter);
+ return "(|(id=*" + filter + "*)(userID=*" + filter + "*))";
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/dbs/TokenRecord.java b/base/tps/src/org/dogtagpki/server/tps/dbs/TokenRecord.java
new file mode 100644
index 000000000..a1aef5720
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/dbs/TokenRecord.java
@@ -0,0 +1,271 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.dbs;
+
+import java.util.Date;
+
+import com.netscape.certsrv.tps.token.TokenStatus;
+import com.netscape.cmscore.dbs.DBAttribute;
+import com.netscape.cmscore.dbs.DBObjectClasses;
+import com.netscape.cmscore.dbs.DBRecord;
+
+/**
+ * @author Endi S. Dewata
+ */
+@DBObjectClasses({ "top", "tokenRecord" })
+public class TokenRecord extends DBRecord {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * objectClasses: ( tokenRecord-oid
+ * NAME 'tokenRecord'
+ * DESC 'CMS defined class'
+ * SUP top
+ * STRUCTURAL
+ * MUST cn
+ * MAY (
+ * dateOfCreate $
+ * dateOfModify $
+ * modified $ (unused)
+ * tokenReason $
+ * tokenUserID $
+ * tokenStatus $
+ * tokenAppletID $
+ * keyInfo $
+ * tokenPolicy $
+ * extensions $ (unused)
+ * numberOfResets $ (unused)
+ * numberOfEnrollments $ (unused)
+ * numberOfRenewals $ (unused)
+ * numberOfRecoveries $ (unused)
+ * userCertificate $ (unused)
+ * tokenType )
+ * X-ORIGIN 'user defined' )
+ */
+ String id;
+ String userID;
+ String type;
+ String status;
+ String reason;
+ String appletID;
+ String keyInfo;
+ String policy;
+ Date createTimestamp;
+ Date modifyTimestamp;
+
+ @DBAttribute("cn")
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ @DBAttribute("tokenUserID")
+ public String getUserID() {
+ return userID;
+ }
+
+ public void setUserID(String userID) {
+ this.userID = userID;
+ }
+
+ @DBAttribute("tokenType")
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ @DBAttribute("tokenStatus")
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ @DBAttribute("tokenReason")
+ public String getReason() {
+ return reason;
+ }
+
+ public void setReason(String reason) {
+ this.reason = reason;
+ }
+
+ @DBAttribute("tokenAppletID")
+ public String getAppletID() {
+ return appletID;
+ }
+
+ public void setAppletID(String appletID) {
+ this.appletID = appletID;
+ }
+
+ @DBAttribute("keyInfo")
+ public String getKeyInfo() {
+ return keyInfo;
+ }
+
+ public void setKeyInfo(String keyInfo) {
+ this.keyInfo = keyInfo;
+ }
+
+ @DBAttribute("tokenPolicy")
+ public String getPolicy() {
+ return policy;
+ }
+
+ public void setPolicy(String policy) {
+ this.policy = policy;
+ }
+
+ @DBAttribute("dateOfCreate")
+ public Date getCreateTimestamp() {
+ return createTimestamp;
+ }
+
+ public void setCreateTimestamp(Date createTimestamp) {
+ this.createTimestamp = createTimestamp;
+ }
+
+ @DBAttribute("dateOfModify")
+ public Date getModifyTimestamp() {
+ return modifyTimestamp;
+ }
+
+ public void setModifyTimestamp(Date modifyTimestamp) {
+ this.modifyTimestamp = modifyTimestamp;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((appletID == null) ? 0 : appletID.hashCode());
+ result = prime * result + ((createTimestamp == null) ? 0 : createTimestamp.hashCode());
+ result = prime * result + ((id == null) ? 0 : id.hashCode());
+ result = prime * result + ((keyInfo == null) ? 0 : keyInfo.hashCode());
+ result = prime * result + ((modifyTimestamp == null) ? 0 : modifyTimestamp.hashCode());
+ result = prime * result + ((policy == null) ? 0 : policy.hashCode());
+ result = prime * result + ((reason == null) ? 0 : reason.hashCode());
+ result = prime * result + ((status == null) ? 0 : status.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ result = prime * result + ((userID == null) ? 0 : userID.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ TokenRecord other = (TokenRecord) obj;
+ if (appletID == null) {
+ if (other.appletID != null)
+ return false;
+ } else if (!appletID.equals(other.appletID))
+ return false;
+ if (createTimestamp == null) {
+ if (other.createTimestamp != null)
+ return false;
+ } else if (!createTimestamp.equals(other.createTimestamp))
+ return false;
+ if (id == null) {
+ if (other.id != null)
+ return false;
+ } else if (!id.equals(other.id))
+ return false;
+ if (keyInfo == null) {
+ if (other.keyInfo != null)
+ return false;
+ } else if (!keyInfo.equals(other.keyInfo))
+ return false;
+ if (modifyTimestamp == null) {
+ if (other.modifyTimestamp != null)
+ return false;
+ } else if (!modifyTimestamp.equals(other.modifyTimestamp))
+ return false;
+ if (policy == null) {
+ if (other.policy != null)
+ return false;
+ } else if (!policy.equals(other.policy))
+ return false;
+ if (reason == null) {
+ if (other.reason != null)
+ return false;
+ } else if (!reason.equals(other.reason))
+ return false;
+ if (status == null) {
+ if (other.status != null)
+ return false;
+ } else if (!status.equals(other.status))
+ return false;
+ if (type == null) {
+ if (other.type != null)
+ return false;
+ } else if (!type.equals(other.type))
+ return false;
+ if (userID == null) {
+ if (other.userID != null)
+ return false;
+ } else if (!userID.equals(other.userID))
+ return false;
+ return true;
+ }
+
+ public TokenStatus getTokenStatus() {
+ String status = getStatus();
+
+ if ("uninitialized".equals(status)) {
+ return TokenStatus.UNINITIALIZED;
+
+ } else if ("active".equals(status)) {
+ return TokenStatus.ACTIVE;
+
+ } else if ("lost".equals(status)) {
+ String reason = getReason();
+
+ if ("keyCompromise".equals(reason)) {
+ return TokenStatus.PERM_LOST;
+
+ } else if ("destroyed".equals(reason)) {
+ return TokenStatus.DAMAGED;
+
+ } else if ("onHold".equals(reason)) {
+ return TokenStatus.TEMP_LOST;
+ }
+
+ } else if ("terminated".equals(status)) {
+ return TokenStatus.TERMINATED;
+ }
+
+ return TokenStatus.PERM_LOST;
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java b/base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java
new file mode 100644
index 000000000..c4b485c45
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java
@@ -0,0 +1,589 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps.engine;
+
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+
+import org.dogtagpki.server.tps.cms.CARemoteRequestHandler;
+import org.dogtagpki.server.tps.cms.CARenewCertResponse;
+import org.dogtagpki.server.tps.cms.CARetrieveCertResponse;
+import org.dogtagpki.server.tps.cms.KRARecoverKeyResponse;
+import org.dogtagpki.server.tps.cms.KRARemoteRequestHandler;
+import org.dogtagpki.server.tps.cms.KRAServerSideKeyGenResponse;
+import org.dogtagpki.server.tps.cms.TKSComputeSessionKeyResponse;
+import org.dogtagpki.server.tps.cms.TKSCreateKeySetDataResponse;
+import org.dogtagpki.server.tps.cms.TKSRemoteRequestHandler;
+import org.dogtagpki.server.tps.dbs.TPSCertRecord;
+import org.dogtagpki.tps.main.TPSBuffer;
+import org.dogtagpki.tps.main.TPSException;
+import org.dogtagpki.tps.main.Util;
+import org.dogtagpki.tps.msg.EndOpMsg.TPSStatus;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.tps.token.TokenStatus;
+
+public class TPSEngine {
+
+ public enum RA_Algs {
+ ALG_RSA,
+ ALG_RSA_CRT,
+ ALG_DSA,
+ ALG_EC_F2M,
+ ALG_EC_FP
+ };
+
+ public enum ENROLL_MODES {
+ MODE_ENROLL,
+ MODE_RECOVERY,
+ MODE_RENEWAL
+ }
+
+ public static final String CFG_DEBUG_ENABLE = "logging.debug.enable";
+ public static final String CFG_DEBUG_FILENAME = "logging.debug.filename";
+ public static final String CFG_DEBUG_LEVEL = "logging.debug.level";
+ public static final String CFG_AUDIT_ENABLE = "logging.audit.enable";
+ public static final String CFG_AUDIT_FILENAME = "logging.audit.filename";
+ public static final String CFG_SIGNED_AUDIT_FILENAME = "logging.audit.signedAuditFilename";
+ public static final String CFG_AUDIT_LEVEL = "logging.audit.level";
+ public static final String CFG_AUDIT_SIGNED = "logging.audit.logSigning";
+ public static final String CFG_AUDIT_SIGNING_CERT_NICK = "logging.audit.signedAuditCertNickname";
+ public static final String CFG_ERROR_ENABLE = "logging.error.enable";
+ public static final String CFG_ERROR_FILENAME = "logging.error.filename";
+ public static final String CFG_ERROR_LEVEL = "logging.error.level";
+ public static final String CFG_SELFTEST_ENABLE = "selftests.container.logger.enable";
+ public static final String CFG_SELFTEST_FILENAME = "selftests.container.logger.fileName";
+ public static final String CFG_SELFTEST_LEVEL = "selftests.container.logger.level";
+ public static final String CFG_CHANNEL_SEC_LEVEL = "channel.securityLevel";
+ public static final String CFG_CHANNEL_ENCRYPTION = "channel.encryption";
+ public static final String CFG_APPLET_CARDMGR_INSTANCE_AID = "applet.aid.cardmgr_instance";
+ public static final String CFG_APPLET_NETKEY_INSTANCE_AID = "applet.aid.netkey_instance";
+ public static final String CFG_APPLET_NETKEY_FILE_AID = "applet.aid.netkey_file";
+ public static final String CFG_APPLET_NETKEY_OLD_INSTANCE_AID = "applet.aid.netkey_old_instance";
+ public static final String CFG_APPLET_NETKEY_OLD_FILE_AID = "applet.aid.netkey_old_file";
+ public static final String CFG_APPLET_SO_PIN = "applet.so_pin";
+ public static final String CFG_APPLET_DELETE_NETKEY_OLD = "applet.delete_old";
+ public static final String CFG_AUDIT_SELECTED_EVENTS = "logging.audit.selected.events";
+ public static final String CFG_AUDIT_NONSELECTABLE_EVENTS = "logging.audit.nonselectable.events";
+ public static final String CFG_AUDIT_SELECTABLE_EVENTS = "logging.audit.selectable.events";
+ public static final String CFG_AUDIT_BUFFER_SIZE = "logging.audit.buffer.size";
+ public static final String CFG_AUDIT_FLUSH_INTERVAL = "logging.audit.flush.interval";
+ public static final String CFG_AUDIT_FILE_TYPE = "logging.audit.file.type";
+ public static final String CFG_DEBUG_FILE_TYPE = "logging.debug.file.type";
+ public static final String CFG_ERROR_FILE_TYPE = "logging.error.file.type";
+ public static final String CFG_SELFTEST_FILE_TYPE = "selftests.container.logger.file.type";
+ public static final String CFG_AUDIT_PREFIX = "logging.audit";
+ public static final String CFG_ERROR_PREFIX = "logging.error";
+ public static final String CFG_DEBUG_PREFIX = "logging.debug";
+ public static final String CFG_SELFTEST_PREFIX = "selftests.container.logger";
+ public static final String CFG_TOKENDB_ALLOWED_TRANSITIONS = "tokendb.allowedTransitions";
+ public static final String CFG_OPERATIONS_ALLOWED_TRANSITIONS = "tps.operations.allowedTransitions";
+
+ public static final String CFG_PRINTBUF_FULL = "tps.printBufFull";
+ public static final String CFG_RECV_BUF_SIZE = "tps.recvBufSize";
+ public static final String CFG_AUTHS_ENABLE = "auth.enable";
+ public static final String CFG_PROFILE_MAPPING_ORDER = "mapping.order";
+ public static final String CFG_ALLOW_UNKNOWN_TOKEN = "allowUnkonwnToken";
+ public static final String CFG_ALLOW_NO_APPLET = "update.applet.emptyToken.enable";
+ public static final String CFG_APPLET_UPDATE_REQUIRED_VERSION = "update.applet.requiredVersion";
+ public static final String CFG_APPLET_DIRECTORY = "update.applet.directory";
+ public static final String CFG_APPLET_EXTENSION = "general.applet_ext";
+
+ public static final String CFG_CHANNEL_BLOCK_SIZE = "channel.blockSize";
+ public static final String CFG_CHANNEL_INSTANCE_SIZE = "channel.instanceSize";
+ public static final String CFG_CHANNEL_DEFKEY_VERSION = "channel.defKeyVersion";
+ public static final String CFG_CHANNEL_APPLET_MEMORY_SIZE = "channel.appletMemorySize";
+ public static final String CFG_CHANNEL_DEFKEY_INDEX = "channel.defKeyIndex";
+ public static final String CFG_ISSUER_INFO_ENABLE = "issuerinfo.enable";
+ public static final String CFG_ISSUER_INFO_VALUE = "issuerinfo.value";
+ public static final String CFG_UPDATE_APPLET_ENCRYPTION = "update.applet.encryption";
+ public static final String CFG_UPDATE_APPLET_ENABLE = "update.applet.enable";
+ public static final String CFG_SYMM_KEY_UPGRADE_ENABLED = "update.symmetricKeys.enable";
+
+ /* default values */
+ public static final String CFG_DEF_CARDMGR_INSTANCE_AID = "A0000000030000";
+ public static final String CFG_DEF_NETKEY_INSTANCE_AID = "627601FF000000";
+ public static final String CFG_DEF_NETKEY_FILE_AID = "627601FF0000";
+ public static final String CFG_DEF_NETKEY_OLD_INSTANCE_AID = "A00000000101";
+ public static final String CFG_DEF_NETKEY_OLD_FILE_AID = "A000000001";
+ public static final String CFG_DEF_APPLET_SO_PIN = "000000000000";
+ public static final String CFG_ENABLED = "Enabled";
+
+ public static final int CFG_CHANNEL_DEF_BLOCK_SIZE = 242;
+ public static final int CFG_CHANNEL_DEF_INSTANCE_SIZE = 18000;
+ public static final int CFG_CHANNEL_DEF_APPLET_MEMORY_SIZE = 5000;
+
+ /* token enrollment values */
+ public static final String CFG_SIGNING = "signing";
+ public static final String CFG_ENCRYPTION = "encryption";
+ public static final String CFG_KEYGEN_ENCRYPTION = "keyGen." + CFG_ENCRYPTION;
+ public static final String CFG_KEYGEN_SIGNING = "keyGen." + CFG_SIGNING;
+ public static final String CFG_KEYTYPE_NUM = "keyType.num";
+ public static final String CFG_KEYTYPE_VALUE = "keyType.value";
+ public static final String CFG_KEYGEN_KEYTYPE_NUM = "keyGen." + CFG_KEYTYPE_NUM;
+ public static final String CFG_KEYGEN_KEYTYPE_VALUE = "keyGen." + CFG_KEYTYPE_VALUE;
+ public static final String CFG_SERVER_KEYGEN_ENABLE = "serverKeygen.enable";
+ public static final String CFG_SERVER_KEY_ARCHIVAL = "serverKeygen.archive";
+ public static final String CFG_DRM_CONNECTOR = "serverKeygen.drm.conn";
+ public static final String CFG_KEYGEN = "keyGen";
+ public static final String CFG_ALG = "alg";
+
+ /* token renewal values */
+ public static final String CFG_RENEW_KEYTYPE_NUM = "renewal.keyType.num";
+ public static final String CFG_RENEW_KEYTYPE_VALUE = "renewal.keyType.value";
+
+ /* External reg values */
+
+ public static final String CFG_EXTERNAL_REG = "externalReg";
+
+ /* misc values */
+
+ public static final String ENROLL_OP = "enroll";
+ public static final String FORMAT_OP = "format";
+ public static final String RECOVERY_OP = "recovery";
+ public static final String RENEWAL_OP = "renewal";
+
+ public static final String OP_FORMAT_PREFIX = "op." + FORMAT_OP;
+ public static final String CFG_PROFILE_RESOLVER = "tokenProfileResolver";
+ public static final String CFG_DEF_FORMAT_PROFILE_RESOLVER = "formatMappingResolver";
+ public static final String CFG_DEF_ENROLL_PROFILE_RESOLVER = "enrollMappingResolver";
+ public static final String CFG_DEF_PIN_RESET_PROFILE_RESOLVER = "pinResetMappingResolver";
+ public static final String OP_ENROLL_PREFIX = "op." + ENROLL_OP;
+ public static final String OP_RECOVERY_PREFIX = "op." + RECOVERY_OP;
+
+ public static final String OP_PIN_RESET_PREFIX = "op.pinReset";
+ public static final String CFG_PIN_RESET_ENABLE = "pinReset.enable";
+ public static final String CFG_PIN_RESET_MIN_LEN = "pinReset.pin.minLen";
+ public static final String CFG_PIN_RESET_MAX_LEN = "pinReset.pin.maxLen";
+ public static final String CFG_PIN_RESET_MAX_RETRIES = "pinReset.pin.maxRetries";
+ public static final String CFG_PIN_RESET_STRING = "create_pin.string";
+
+ public static final String CFG_SCHEME = "scheme";
+ public static final String RECOVERY_SCHEME_GENERATE_NEW_KEY_AND_RECOVER_LAST = "GenerateNewKeyandRecoverLast";
+ public static final Object RECOVERY_GENERATE_NEW_KEY = "GenerateNewKey";
+ public static final Object RECOVERY_RECOVER_LAST = "RecoverLast";
+
+ public static final String CFG_OVERWRITE = "overwrite";
+ public static final String PIN_RESET_OP = "pin_reset";
+ public static final String ENROLL_MODE_ENROLLMENT = ENROLL_OP;
+ public static final String ENROLL_MODE_RECOVERY = RECOVERY_OP;
+ public static final String ERNOLL_MODE_RENEWAL = RENEWAL_OP;
+ private static final String CFG_OPERATIONS_TRANSITIONS = "tps.operations.allowedTransitions";
+
+ private static String transitionList;
+
+ public void init() {
+ //ToDo
+ }
+
+ public TPSEngine() {
+ }
+
+ public int initialize(String cfg_path) {
+
+ int rc = -1;
+
+ return rc;
+ }
+
+ public TKSComputeSessionKeyResponse computeSessionKey(TPSBuffer cuid,
+ TPSBuffer keyInfo,
+ TPSBuffer card_challenge,
+ TPSBuffer host_challenge,
+ TPSBuffer card_cryptogram,
+ String connId,
+ String tokenType) throws TPSException {
+
+ if (cuid == null || keyInfo == null || card_challenge == null || host_challenge == null
+ || card_cryptogram == null || connId == null || tokenType == null) {
+
+ throw new TPSException("TPSEngine.computeSessionKey: Invalid input data!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+
+ }
+
+ CMS.debug("TPSEngine.computeSessionKey");
+
+ TKSRemoteRequestHandler tks = null;
+
+ TKSComputeSessionKeyResponse resp = null;
+ try {
+ tks = new TKSRemoteRequestHandler(connId);
+ resp = tks.computeSessionKey(cuid, keyInfo, card_challenge, card_cryptogram, host_challenge, tokenType);
+ } catch (EBaseException e) {
+ throw new TPSException("TPSEngine.computeSessionKey: Error computing session key!" + e,
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ int status = resp.getStatus();
+ if (status != 0) {
+ CMS.debug("TPSEngine.computeSessionKey: Non zero status result: " + status);
+ throw new TPSException("TPSEngine.computeSessionKey: invalid returned status: " + status);
+
+ }
+
+ return resp;
+
+ }
+
+ public CARetrieveCertResponse recoverCertificate(TPSCertRecord cert, String serialS, String keyType, String caConnID)
+ throws TPSException {
+
+ String method = "TPSEngine.recoverCertificate";
+
+ CMS.debug(method + ": serial # =" + serialS);
+
+ if (cert == null || serialS == null || keyType == null || caConnID == null) {
+ throw new TPSException(method + " Invalid input data!", TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+
+ String serialhex = serialS.substring(2); // strip off the "0x"
+ BigInteger serialBI = new BigInteger(serialhex, 16);
+
+ CARetrieveCertResponse retrieveResponse = null;
+
+ String retrievedCertB64 = null;
+
+ try {
+
+ CARemoteRequestHandler caRH = new CARemoteRequestHandler(caConnID);
+
+ retrieveResponse = caRH.retrieveCertificate(serialBI);
+ retrievedCertB64 = retrieveResponse.getCertB64();
+ CMS.debug(method + ": retrieved cert: " + retrievedCertB64);
+ // test ends - remove up to here
+
+ } catch (EBaseException e) {
+ CMS.debug(method + ":" + e);
+ throw new TPSException(method + ": Exception thrown: " + e,
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ if (retrievedCertB64 == null) {
+ throw new TPSException(method + " Unable to get valid cert blob.", TPSStatus.STATUS_ERROR_CA_RESPONSE);
+ }
+
+ return retrieveResponse;
+
+ }
+
+ public CARenewCertResponse renewCertificate(TPSCertRecord cert, String serialS, String tokenType, String keyType,
+ String caConnID) throws TPSException {
+
+ String method = "TPSEngine.renewCertificate";
+
+ CMS.debug(method + " entering...");
+
+ if (cert == null || serialS == null || keyType == null || tokenType == null || caConnID == null) {
+ throw new TPSException(method + " Invalid input data!", TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+
+ CMS.debug(method + ": serial # =" + serialS);
+ String serialhex = serialS.substring(2); // strip off the "0x"
+ BigInteger serialBI = new BigInteger(serialhex, 16);
+
+ CARenewCertResponse renewResponse = null;
+
+ String retrievedCertB64 = null;
+
+ try {
+
+ CARemoteRequestHandler caRH = new CARemoteRequestHandler(caConnID);
+
+ /*
+ * testing retrieveCertificate() to retrieve the old cert (to be used by Recovery)
+ * TODO: remove
+ */
+ renewResponse = caRH.renewCertificate(serialBI, tokenType, keyType);
+ retrievedCertB64 = renewResponse.getRenewedCertB64();
+ CMS.debug(method + ": retrieved cert: " + retrievedCertB64);
+
+ } catch (EBaseException e) {
+ CMS.debug(method + ":" + e);
+ throw new TPSException(method + ": Exception thrown: " + e,
+ TPSStatus.STATUS_ERROR_RENEWAL_FAILED);
+ }
+
+ if (retrievedCertB64 == null) {
+ throw new TPSException(method + " Unable to get valid cert blob.", TPSStatus.STATUS_ERROR_CA_RESPONSE);
+ }
+
+ return renewResponse;
+
+ }
+
+ public TPSBuffer createKeySetData(TPSBuffer newMasterVersion, TPSBuffer oldVersion, TPSBuffer cuid, String connId)
+ throws TPSException {
+ CMS.debug("TPSEngine.createKeySetData. entering...");
+
+ if (newMasterVersion == null || oldVersion == null || cuid == null || connId == null) {
+ throw new TPSException("TPSEngine.createKeySetData: Invalid input data",
+ TPSStatus.STATUS_ERROR_KEY_CHANGE_OVER);
+ }
+
+ TKSRemoteRequestHandler tks = null;
+
+ TKSCreateKeySetDataResponse resp = null;
+
+ try {
+ tks = new TKSRemoteRequestHandler(connId);
+ resp = tks.createKeySetData(newMasterVersion, oldVersion, cuid);
+ } catch (EBaseException e) {
+
+ throw new TPSException("TPSEngine.createKeySetData, failure to get key set data from TKS",
+ TPSStatus.STATUS_ERROR_KEY_CHANGE_OVER);
+ }
+
+ int status = resp.getStatus();
+ if (status != 0) {
+ CMS.debug("TPSEngine.createKeySetData: Non zero status result: " + status);
+ throw new TPSException("TPSEngine.computeSessionKey: invalid returned status: " + status,
+ TPSStatus.STATUS_ERROR_KEY_CHANGE_OVER);
+
+ }
+
+ TPSBuffer keySetData = resp.getKeySetData();
+
+ if (keySetData == null) {
+ CMS.debug("TPSEngine.createKeySetData: No valid key set data returned.");
+ throw new TPSException("TPSEngine.createKeySetData: No valid key set data returned.",
+ TPSStatus.STATUS_ERROR_KEY_CHANGE_OVER);
+
+ }
+
+ return keySetData;
+ }
+
+ public static void main(String[] args) {
+
+ }
+
+ public boolean raForceTokenFormat(String cuid) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isAlgorithmECC(int algorithm) {
+
+ RA_Algs algEnum = intToRAAlgs(algorithm);
+
+ boolean isECC = false;
+
+ if (algEnum == RA_Algs.ALG_EC_F2M || algEnum == RA_Algs.ALG_EC_FP) {
+ isECC = true;
+ }
+
+ CMS.debug("TPSEngine.isAlgorithmECC: result: " + isECC);
+ return isECC;
+
+ }
+
+ public static RA_Algs intToRAAlgs(int alg) {
+
+ RA_Algs def = RA_Algs.ALG_RSA;
+
+ switch (alg) {
+
+ case 1:
+ return RA_Algs.ALG_RSA;
+
+ case 2:
+ return RA_Algs.ALG_RSA_CRT;
+ case 3:
+ return RA_Algs.ALG_DSA;
+ case 4:
+ return RA_Algs.ALG_EC_F2M;
+ case 5:
+ return RA_Algs.ALG_EC_FP;
+
+ default:
+ return def;
+
+ }
+
+ }
+
+ public KRARecoverKeyResponse recoverKey(String cuid,
+ String userid,
+ TPSBuffer sDesKey,
+ String b64cert, String drmConnId) throws TPSException {
+ String method = "TPSEngine.recoverKey";
+ CMS.debug("TPSEngine.recoverKey");
+ if (cuid == null)
+ CMS.debug(method + ": cuid null");
+ else if (userid == null)
+ CMS.debug(method + ": userid null");
+ else if (sDesKey == null)
+ CMS.debug(method + ": isDesKey null");
+ else if (b64cert == null)
+ CMS.debug(method + ": b64cert null");
+ else if (drmConnId == null)
+ CMS.debug(method + ": drmConnId null");
+
+ if (cuid == null || userid == null || sDesKey == null || b64cert == null || drmConnId == null) {
+ throw new TPSException("TPSEngine.recoverKey: invalid input data!", TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+
+ KRARecoverKeyResponse resp = null;
+ KRARemoteRequestHandler kra = null;
+
+ try {
+ kra = new KRARemoteRequestHandler(drmConnId);
+
+ resp = kra.recoverKey(cuid, userid, Util.specialURLEncode(sDesKey), Util.uriEncode(b64cert));
+ } catch (EBaseException e) {
+ throw new TPSException("TPSEngine.recoverKey: Problem creating or using KRARemoteRequestHandler! "
+ + e.toString(), TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+
+ } catch (UnsupportedEncodingException e) {
+ throw new TPSException("TPSEngine.recoverKey: Problem creating or using KRARemoteRequestHandler! "
+ + e.toString(), TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+
+ int status = resp.getStatus();
+
+ if (status != 0) {
+ throw new TPSException("TPSEngine.recoverKey: Bad status from server: " + status,
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+
+ if (resp.getPublicKey() == null) {
+ throw new TPSException("TPSEngine.recoverKey: invalid public key from server! ",
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+
+ if (resp.getWrappedPrivKey() == null) {
+ throw new TPSException("TPSEngine.recoverKey: invalid private key from server! ",
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+
+ }
+
+ if (resp.getIVParam() == null) {
+ throw new TPSException("TPSEngine.recoverKey: invalid iv vector from server!",
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+
+ return resp;
+
+ }
+
+ public KRAServerSideKeyGenResponse serverSideKeyGen(int keySize, String cuid, String userid, String drmConnId,
+ TPSBuffer wrappedDesKey,
+ boolean archive,
+ boolean isECC) throws TPSException {
+
+ CMS.debug("TPSEngine.serverSideKeyGen entering... keySize: " + keySize + " cuid: " + cuid + " userid: "
+ + userid + " drConnId: " + drmConnId + " wrappedDesKey: " + wrappedDesKey + " archive: " + archive
+ + " isECC: " + isECC);
+
+ if (cuid == null || userid == null || drmConnId == null || wrappedDesKey == null) {
+ throw new TPSException("TPSEngine.serverSideKeyGen: Invalid input data!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ KRARemoteRequestHandler kra = null;
+ KRAServerSideKeyGenResponse resp = null;
+
+ try {
+ kra = new KRARemoteRequestHandler(drmConnId);
+
+ resp = kra.serverSideKeyGen(isECC, keySize, cuid, userid,
+ Util.specialURLEncode(wrappedDesKey), archive);
+
+ } catch (EBaseException e) {
+ throw new TPSException("TPSEngine.serverSideKeyGen: Problem creating or using KRARemoteRequestHandler! "
+ + e.toString());
+ }
+
+ int status = resp.getStatus();
+
+ if (status != 0) {
+ throw new TPSException("TPSEngine.serverSideKeyGen: Bad status from server: " + status,
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ if (resp.getPublicKey() == null) {
+ throw new TPSException("TPSEngine.serverSideKeyGen: invalid public key from server! ",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ if (resp.getWrappedPrivKey() == null) {
+ throw new TPSException("TPSEngine.serverSideKeyGen: invalid private key from server! ",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+
+ }
+
+ if (resp.getIVParam() == null) {
+ throw new TPSException("TPSEngine.serverSideKeyGen: invalid iv vector from server!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ //We return this resonse we know that all the data is present and can be accessed
+ return resp;
+
+ }
+
+ //Check to see if special operations transition is allowed
+
+ public boolean isOperationTransitionAllowed(TokenStatus oldState, TokenStatus newState) throws TPSException {
+ boolean allowed = true;
+
+ if(transitionList == null) {
+
+ IConfigStore configStore = CMS.getConfigStore();
+
+ String transConfig = CFG_OPERATIONS_TRANSITIONS;
+
+ CMS.debug("TPSEngine.isOperationTransistionAllowed: getting config: " + transConfig);
+ try {
+ transitionList = configStore.getString(transConfig,null);
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "TPSProcessor.isOperationTransitionAllowed: Internal error getting config value for operations transition list!",
+ TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+ }
+
+ if(transitionList == null) {
+ throw new TPSException(
+ "TPSProcessor.isOperationTransitionAllowed: Can't find non null config value for operations transition list!",
+ TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+ }
+
+ CMS.debug("TPSEngine.isOperationTransistionAllowed: transitionList is: " + transitionList);
+
+
+ }
+
+ String transition = oldState.toInt() + ":" + newState.toInt();
+
+ CMS.debug("TPSEngine.isOperationTransistionAllowed: checking for transition: " + transition);
+
+ if(transitionList.indexOf(transition) == -1) {
+ CMS.debug("TPSEngine.isOperationTransistionAllowed: checking for transition: " + transition);
+ allowed = false;
+ }
+
+ CMS.debug("TPSEngine.isOperationTransistionAllowed: checking for transition: " + transition + " allowed: " + allowed);
+
+ return allowed;
+
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/installer/CAInfoPanel.java b/base/tps/src/org/dogtagpki/server/tps/installer/CAInfoPanel.java
new file mode 100644
index 000000000..4c5371f20
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/installer/CAInfoPanel.java
@@ -0,0 +1,171 @@
+package org.dogtagpki.server.tps.installer;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.cert.CertificateException;
+import java.util.Vector;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.velocity.context.Context;
+import org.mozilla.jss.CryptoManager.NotInitializedException;
+import org.mozilla.jss.crypto.TokenException;
+import org.xml.sax.SAXException;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.property.PropertySet;
+import com.netscape.certsrv.util.HttpInput;
+import com.netscape.cms.servlet.csadmin.ConfigurationUtils;
+import com.netscape.cms.servlet.csadmin.WizardPanelBase;
+import com.netscape.cms.servlet.wizard.WizardServlet;
+
+public class CAInfoPanel extends WizardPanelBase {
+
+ public CAInfoPanel() {
+ }
+
+ public void init(ServletConfig config, int panelno)
+ throws ServletException {
+ setPanelNo(panelno);
+ setName("CA Information");
+ }
+
+ public void init(WizardServlet servlet, ServletConfig config, int panelno, String id)
+ throws ServletException {
+ setPanelNo(panelno);
+ setName("CA Information");
+ setId(id);
+ }
+
+ public boolean shouldSkip() {
+ return false;
+ }
+
+ public void cleanUp() throws IOException {
+ IConfigStore cs = CMS.getConfigStore();
+ cs.putString("preop.cainfo.select", "");
+ }
+
+ public boolean isPanelDone() {
+ IConfigStore cs = CMS.getConfigStore();
+ try {
+ String s = cs.getString("preop.cainfo.select", "");
+ if (s != null && !s.isEmpty()) {
+ return true;
+ }
+ } catch (EBaseException e) {
+ }
+ return false;
+ }
+
+ public PropertySet getUsage() {
+ return new PropertySet();
+ }
+
+ public void display(HttpServletRequest request,
+ HttpServletResponse response,
+ Context context) {
+ String errorString = "";
+ context.put("title", "CA Information");
+ context.put("panel", "admin/console/config/cainfopanel.vm");
+ IConfigStore config = CMS.getConfigStore();
+
+ if (isPanelDone()) {
+ // TODO - put the selected URL in selection box.
+ // String s = config.getString("preop.cainfo.select");
+ }
+
+ // get CA URLs
+ Vector<String> v;
+ try {
+ v = null;
+ v = ConfigurationUtils.getUrlListFromSecurityDomain(config, "CA", "SecurePort");
+ if (v == null) {
+ errorString = "No CA found. CA, TKS and optionally DRM " +
+ " must be installed prior to TPS installation";
+ context.put("errorString", errorString);
+ context.put("preop.cainfo.errorString", errorString);
+ return;
+ }
+
+ config.putString("preop.ca.list", StringUtils.join(v,","));
+ config.commit(false);
+ } catch (EBaseException | IOException | SAXException | ParserConfigurationException e) {
+ e.printStackTrace();
+ errorString = "Failed to get CA information from security domain. " + e;
+ context.put("errorString", errorString);
+ context.put("preop.cainfo.errorString", errorString);
+ return;
+ }
+
+ context.put("urls", v);
+ context.put("urls_size", v.size());
+ context.put("errorString", "");
+ context.put("preop.cainfo.errorString", "");
+ }
+
+ public void validate(HttpServletRequest request,
+ HttpServletResponse response,
+ Context context) throws IOException {
+ }
+
+ public void update(HttpServletRequest request,
+ HttpServletResponse response,
+ Context context) throws IOException {
+ IConfigStore config = CMS.getConfigStore();
+ String subsystemNick;
+ try {
+ subsystemNick = config.getString("preop.cert.subsystem.nickname");
+ } catch (EBaseException e1) {
+ e1.printStackTrace();
+ throw new IOException("Failed to get subsystem certificate nickname");
+ }
+
+ String url = HttpInput.getString(request, "urls");
+ URI caUri = null;
+ String parsedURI = url.substring(url.lastIndexOf("http"));
+ try {
+ caUri = new URI(parsedURI);
+ } catch (URISyntaxException e) {
+ throw new IOException("Invalid URI " + parsedURI);
+ }
+
+ // TODO: get installer from session
+ TPSInstaller installer = new TPSInstaller();
+ installer.configureCAConnector(caUri, subsystemNick);
+
+ String host = caUri.getHost();
+ int port = caUri.getPort();
+
+ // Note -
+ // list contains EE port. If admin port is different, it needs to
+ // be obtained from security domain and used to get the cert chain
+
+ /* int admin_port = ConfigurationUtils.getPortFromSecurityDomain(domainXML,
+ host, port, "CA", "SecurePort", "SecureAdminPort");
+ */
+
+ try {
+ ConfigurationUtils.importCertChain(host, port, "/ca/admin/ca/getCertChain", "ca");
+ } catch (CertificateException | SAXException | ParserConfigurationException
+ | NotInitializedException | TokenException | EBaseException e) {
+ e.printStackTrace();
+ throw new IOException("Failed to import certificate chain from CA");
+ }
+
+ context.put("updateStatus", "success");
+ }
+
+ public void displayError(HttpServletRequest request,
+ HttpServletResponse response,
+ Context context) {
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/installer/DRMInfoPanel.java b/base/tps/src/org/dogtagpki/server/tps/installer/DRMInfoPanel.java
new file mode 100644
index 000000000..2237f9e53
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/installer/DRMInfoPanel.java
@@ -0,0 +1,154 @@
+package org.dogtagpki.server.tps.installer;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Vector;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.velocity.context.Context;
+import org.xml.sax.SAXException;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.property.PropertySet;
+import com.netscape.certsrv.util.HttpInput;
+import com.netscape.cms.servlet.csadmin.ConfigurationUtils;
+import com.netscape.cms.servlet.csadmin.WizardPanelBase;
+import com.netscape.cms.servlet.wizard.WizardServlet;
+
+public class DRMInfoPanel extends WizardPanelBase {
+
+ public DRMInfoPanel() {
+ }
+
+ public void init(ServletConfig config, int panelno)
+ throws ServletException {
+ setPanelNo(panelno);
+ setName("DRM Information");
+ }
+
+ public void init(WizardServlet servlet, ServletConfig config, int panelno, String id)
+ throws ServletException {
+ setPanelNo(panelno);
+ setName("DRM Information");
+ setId(id);
+ }
+
+ public boolean shouldSkip() {
+ return false;
+ }
+
+ public void cleanUp() throws IOException {
+ IConfigStore cs = CMS.getConfigStore();
+ cs.putString("preop.krainfo.select", "");
+ }
+
+ public boolean isPanelDone() {
+ IConfigStore cs = CMS.getConfigStore();
+ try {
+ String s = cs.getString("preop.krainfo.select", "");
+ if (s != null && ! s.isEmpty()) {
+ return true;
+ }
+ } catch (EBaseException e) {
+ }
+ return false;
+ }
+
+ public PropertySet getUsage() {
+ return new PropertySet();
+ }
+
+ public void display(HttpServletRequest request,
+ HttpServletResponse response,
+ Context context) {
+ String errorString = "";
+ context.put("title", "DRM Information");
+ context.put("panel", "admin/console/config/drminfopanel.vm");
+ IConfigStore config = CMS.getConfigStore();
+
+ if (isPanelDone()) {
+ //TODO - put selected entry in selection box.
+ //String s = config.getString("preop.krainfo.select");
+ }
+
+ // get KRA URLs
+ Vector<String> v = null;
+ try {
+ v = ConfigurationUtils.getUrlListFromSecurityDomain(config, "KRA", "SecurePort");
+ if (v == null) {
+ errorString = "No DRM found. CA, TKS and optionally DRM " +
+ " must be installed prior to TPS installation";
+ context.put("errorString", errorString);
+ context.put("preop.krainfo.errorString", errorString);
+ return;
+ }
+
+ config.putString("preop.kra.list", StringUtils.join(v,","));
+ config.commit(false);
+ } catch (EBaseException | IOException | SAXException | ParserConfigurationException e1) {
+ e1.printStackTrace();
+ errorString = "Failed to get DRM information from security domain. " + e1;
+ context.put("errorString", errorString);
+ context.put("preop.krainfo.errorString", errorString);
+ return;
+ }
+
+ context.put("urls", v);
+ context.put("urls_size", v.size());
+ context.put("errorString", "");
+ context.put("preop.krainfo.errorString", "");
+ }
+
+ public void validate(HttpServletRequest request,
+ HttpServletResponse response,
+ Context context) throws IOException {
+ }
+
+ public void update(HttpServletRequest request,
+ HttpServletResponse response,
+ Context context) throws IOException {
+ IConfigStore config = CMS.getConfigStore();
+ String subsystemNick;
+ try {
+ subsystemNick = config.getString("preop.cert.subsystem.nickname");
+ } catch (EBaseException e1) {
+ e1.printStackTrace();
+ throw new IOException("Failed to get subsystem certificate nickname");
+ }
+
+ String url = HttpInput.getString(request, "urls");
+ String parsedURI = url.substring(url.lastIndexOf("http"));
+ URI kraUri = null;
+ try {
+ kraUri = new URI(parsedURI);
+ } catch (URISyntaxException e) {
+ throw new IOException("Invalid URI " + parsedURI);
+ }
+
+ String choice = HttpInput.getString(request, "choice");
+ boolean keyGen = choice.equalsIgnoreCase("keygen");
+
+ // TODO: get installer from session
+ TPSInstaller installer = new TPSInstaller();
+ installer.configureKRAConnector(keyGen, kraUri, subsystemNick);
+
+ context.put("updateStatus", "success");
+ }
+
+ /**
+ * If validate() returns false, this method will be called.
+ */
+ public void displayError(HttpServletRequest request,
+ HttpServletResponse response,
+ Context context) {
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/installer/TKSInfoPanel.java b/base/tps/src/org/dogtagpki/server/tps/installer/TKSInfoPanel.java
new file mode 100644
index 000000000..0c0cf62a7
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/installer/TKSInfoPanel.java
@@ -0,0 +1,150 @@
+package org.dogtagpki.server.tps.installer;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Vector;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.velocity.context.Context;
+import org.xml.sax.SAXException;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.property.PropertySet;
+import com.netscape.certsrv.util.HttpInput;
+import com.netscape.cms.servlet.csadmin.ConfigurationUtils;
+import com.netscape.cms.servlet.csadmin.WizardPanelBase;
+import com.netscape.cms.servlet.wizard.WizardServlet;
+
+public class TKSInfoPanel extends WizardPanelBase {
+
+ public TKSInfoPanel() {
+ }
+
+ public void init(ServletConfig config, int panelno)
+ throws ServletException {
+ setPanelNo(panelno);
+ setName("TKS Information");
+ }
+
+ public void init(WizardServlet servlet, ServletConfig config, int panelno, String id)
+ throws ServletException {
+ setPanelNo(panelno);
+ setName("TKS Information");
+ setId(id);
+ }
+
+ public boolean shouldSkip() {
+ return false;
+ }
+
+ public void cleanUp() throws IOException {
+ IConfigStore cs = CMS.getConfigStore();
+ cs.putString("preop.tksinfo.select", "");
+ }
+
+ public boolean isPanelDone() {
+ IConfigStore cs = CMS.getConfigStore();
+ try {
+ String s = cs.getString("preop.tksinfo.select", "");
+ if (s != null && !s.isEmpty()) {
+ return true;
+ }
+ } catch (EBaseException e) {
+ }
+ return false;
+ }
+
+ public PropertySet getUsage() {
+ return new PropertySet();
+ }
+
+
+ public void display(HttpServletRequest request,
+ HttpServletResponse response,
+ Context context) {
+ String errorString = "";
+ context.put("title", "TKS Information");
+ context.put("panel", "admin/console/config/tksinfopanel.vm");
+ IConfigStore config = CMS.getConfigStore();
+
+ if (isPanelDone()) {
+ // TODO - put selected URL in selection box
+ // String s = config.getString("preop.tksinfo.select");
+ }
+
+ // get TKS URLs
+ Vector<String> v = null;
+ try {
+ v = ConfigurationUtils.getUrlListFromSecurityDomain(config, "TKS", "SecureAdminPort");
+ if (v == null) {
+ errorString = "No TKS found. CA, TKS and optionally DRM " +
+ " must be installed prior to TPS installation";
+ context.put("errorString", errorString);
+ context.put("preop.tksinfo.errorString", errorString);
+ return;
+ }
+
+ config.putString("preop.tks.list", StringUtils.join(v,","));
+ config.commit(false);
+ } catch (EBaseException | IOException | SAXException | ParserConfigurationException e) {
+ e.printStackTrace();
+ errorString = "Failed to get TKS information from security domain. " + e;
+ context.put("errorString", errorString);
+ context.put("preop.tksinfo.errorString", errorString);
+ return;
+ }
+
+ context.put("urls", v);
+ context.put("urls_size", v.size());
+ context.put("errorString", "");
+ context.put("preop.tksinfo.errorString", "");
+ }
+
+ public void validate(HttpServletRequest request,
+ HttpServletResponse response,
+ Context context) throws IOException {
+ }
+
+ public void update(HttpServletRequest request,
+ HttpServletResponse response,
+ Context context) throws IOException {
+ IConfigStore config = CMS.getConfigStore();
+ String subsystemNick;
+ try {
+ subsystemNick = config.getString("preop.cert.subsystem.nickname");
+ } catch (EBaseException e1) {
+ e1.printStackTrace();
+ throw new IOException("Failed to get subsystem certificate nickname");
+ }
+
+ String url = HttpInput.getString(request, "urls");
+ String parsedURI = url.substring(url.lastIndexOf("http"));
+ URI tksUri = null;
+ try {
+ tksUri = new URI(parsedURI);
+ } catch (URISyntaxException e) {
+ throw new IOException("Invalid URI " + parsedURI);
+ }
+
+ // TODO: get installer from session
+ TPSInstaller installer = new TPSInstaller();
+ installer.configureTKSConnector(tksUri, subsystemNick);
+
+ context.put("updateStatus", "success");
+ }
+
+ public void displayError(HttpServletRequest request,
+ HttpServletResponse response,
+ Context context) {
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/installer/TPSInstaller.java b/base/tps/src/org/dogtagpki/server/tps/installer/TPSInstaller.java
new file mode 100644
index 000000000..2779e5b98
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/installer/TPSInstaller.java
@@ -0,0 +1,124 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps.installer;
+
+import java.net.URI;
+
+import org.dogtagpki.server.tps.TPSSubsystem;
+import org.dogtagpki.server.tps.config.ConnectorDatabase;
+import org.dogtagpki.server.tps.config.ConnectorRecord;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.PKIException;
+
+/**
+ * Utility class for TPS installation to be used both by the RESTful installer
+ * and the UI Panels.
+ *
+ * @author alee
+ *
+ */
+
+public class TPSInstaller {
+
+ public TPSInstaller() {
+ }
+
+ public void configureCAConnector(URI uri, String nickname) {
+
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ConnectorDatabase database = subsystem.getConnectorDatabase();
+ IConfigStore cs = CMS.getConfigStore();
+
+ // TODO: see if this is only needed by wizard-based installation
+ cs.putString("preop.cainfo.select", uri.toString());
+
+ try {
+ database.addCAConnector(uri.getHost(), uri.getPort(), nickname);
+
+ } catch (Exception e) {
+ throw new PKIException("Unable to create CA connector", e);
+ }
+ }
+
+ public void configureTKSConnector(URI uri, String nickname) {
+
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ConnectorDatabase database = subsystem.getConnectorDatabase();
+ IConfigStore cs = CMS.getConfigStore();
+
+ // TODO: see if this is only needed by wizard-based installation
+ cs.putString("preop.tksinfo.select", uri.toString());
+
+ try {
+ database.addTKSConnector(uri.getHost(), uri.getPort(), nickname, false);
+
+ } catch (Exception e) {
+ throw new PKIException("Unable to create TKS connector", e);
+ }
+ }
+
+ public void configureKRAConnector(Boolean keygen, URI uri, String nickname) {
+
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ConnectorDatabase database = subsystem.getConnectorDatabase();
+ IConfigStore cs = CMS.getConfigStore();
+
+ if (keygen) {
+ // TODO: see if this is only needed by wizard-based installation
+ cs.putString("preop.krainfo.select", uri.toString());
+
+ // TODO: see if there are other profiles need to be configured
+ cs.putString("op.enroll.userKey.keyGen.encryption.serverKeygen.enable", "true");
+ cs.putString("op.enroll.userKeyTemporary.keyGen.encryption.serverKeygen.enable", "true");
+ cs.putString("op.enroll.soKey.keyGen.encryption.serverKeygen.enable", "true");
+ cs.putString("op.enroll.soKeyTemporary.keyGen.encryption.serverKeygen.enable", "true");
+
+ try {
+ database.addKRAConnector(uri.getHost(), uri.getPort(), nickname);
+
+ } catch (Exception e) {
+ throw new PKIException("Unable to create KRA connector", e);
+ }
+
+ } else { // no keygen
+ // TODO: see if there are other profiles need to be configured
+ cs.putString("op.enroll.userKey.keyGen.encryption.serverKeygen.enable", "false");
+ cs.putString("op.enroll.userKeyTemporary.keyGen.encryption.serverKeygen.enable", "false");
+ cs.putString("op.enroll.userKey.keyGen.encryption.recovery.destroyed.scheme", "GenerateNewKey");
+ cs.putString("op.enroll.userKeyTemporary.keyGen.encryption.recovery.onHold.scheme", "GenerateNewKey");
+ cs.putString("op.enroll.soKey.keyGen.encryption.serverKeygen.enable", "false");
+ cs.putString("op.enroll.soKeyTemporary.keyGen.encryption.serverKeygen.enable", "false");
+ cs.putString("op.enroll.soKey.keyGen.encryption.recovery.destroyed.scheme", "GenerateNewKey");
+ cs.putString("op.enroll.soKeyTemporary.keyGen.encryption.recovery.onHold.scheme", "GenerateNewKey");
+ }
+
+ try {
+ String id = "tks1"; // there is only one default TKS connector
+
+ // update keygen in TKS connector
+ ConnectorRecord record = database.getRecord(id);
+ record.setProperty(database.prefix + "." + id + ".serverKeygen", keygen.toString());
+ database.updateRecord(id, record);
+
+ } catch (Exception e) {
+ throw new PKIException("Unable to update TKS connector", e);
+ }
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/main/AttributeSpec.java b/base/tps/src/org/dogtagpki/server/tps/main/AttributeSpec.java
new file mode 100644
index 000000000..444f22c4b
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/main/AttributeSpec.java
@@ -0,0 +1,71 @@
+package org.dogtagpki.server.tps.main;
+
+import org.dogtagpki.tps.main.TPSBuffer;
+
+public class AttributeSpec {
+
+ public AttributeSpec() {
+ }
+
+ private long id;
+ private byte type;
+ private TPSBuffer data;
+
+ public void setAttributeID(long attribute_id) {
+ id = attribute_id;
+ }
+
+ public long getAttributeID() {
+ return id;
+ }
+
+ public void setType(byte type) {
+ this.type = type;
+ }
+
+ public byte getType() {
+ return type;
+ }
+
+ public void setData(TPSBuffer data) {
+ this.data = data;
+
+ }
+
+ public TPSBuffer getData() {
+ TPSBuffer theData = new TPSBuffer();
+ theData.addLong4Bytes(id);
+ theData.add(type);
+
+ if (type == 0) { /* String */
+ theData.addInt2Bytes(data.size());
+ }
+ theData.add(data);
+ return theData;
+ }
+
+ public TPSBuffer getValue() {
+ return data;
+ }
+
+ public static AttributeSpec parse(TPSBuffer b, int offset) {
+ AttributeSpec o = new AttributeSpec();
+
+ long id = b.getLongFrom4Bytes(offset);
+
+ o.setAttributeID(id);
+
+ o.setType(b.at(offset + 4));
+ // DatatypeString contains two bytes for AttributeLen of AttributeData
+ TPSBuffer theData;
+ if (o.getType() == (byte) 0)
+ theData = b.substr(offset + 5 + 2, b.size() - 5 - 2);
+ else
+ theData = b.substr(offset + 5, b.size() - 5);
+
+ o.setData(theData);
+ return o;
+
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/main/ObjectSpec.java b/base/tps/src/org/dogtagpki/server/tps/main/ObjectSpec.java
new file mode 100644
index 000000000..a8dbdb1bc
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/main/ObjectSpec.java
@@ -0,0 +1,456 @@
+package org.dogtagpki.server.tps.main;
+
+import java.util.ArrayList;
+
+import org.dogtagpki.tps.main.TPSBuffer;
+import org.dogtagpki.tps.main.TPSException;
+
+import sun.security.pkcs11.wrapper.PKCS11Constants;
+
+import com.netscape.certsrv.apps.CMS;
+
+public class ObjectSpec {
+
+ public ObjectSpec()
+ {
+ attributeSpecs = new ArrayList<AttributeSpec>();
+ }
+
+ final static int DATATYPE_STRING = 0;
+ final static int DATATYPE_INTEGER = 1;
+ final static int DATATYPE_BOOL_FALSE = 2;
+ final static int DATATYPE_BOOL_TRUE = 3;
+
+ private long objectID;
+ private long fixedAttributes;
+ private ArrayList<AttributeSpec> attributeSpecs;
+ private int parseRead;
+
+ public int getParseReadSize() {
+ return parseRead;
+ }
+
+ /**
+ * Parse 'c' object.
+ */
+ public static void parseAttributes(String objectID, ObjectSpec objectSpec, TPSBuffer b)
+ {
+ int curpos = 7;
+ long fixedAttrs = 0;
+ int xclass = 0;
+ int id = 0;
+
+ /* skip first 7 bytes */
+
+ while (curpos < ((b.size()))) {
+ long attribute_id = b.getLongFrom4Bytes(curpos);
+ int attribute_size = b.getIntFrom2Bytes(curpos + 4);
+
+ byte type = 0;
+ TPSBuffer data = new TPSBuffer();
+ boolean found = false;
+ /* modify fixed attributes */
+
+ switch ((int) attribute_id) {
+ case (int) PKCS11Constants.CKA_TOKEN:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00000080;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_PRIVATE:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00000100;
+ } else {
+ }
+ break;
+ case (int) PKCS11Constants.CKA_MODIFIABLE:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00000200;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_DERIVE:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00000400;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_LOCAL:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00000800;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_ENCRYPT:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00001000;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_DECRYPT:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00002000;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_WRAP:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00004000;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_UNWRAP:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00008000;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_SIGN:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00010000;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_SIGN_RECOVER:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00020000;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_VERIFY:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00040000;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_VERIFY_RECOVER:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00080000;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_SENSITIVE:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00100000;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_ALWAYS_SENSITIVE:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00200000;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_EXTRACTABLE:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00400000;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_NEVER_EXTRACTABLE:
+ if (b.at(curpos + 6) != 0) {
+ fixedAttrs |= 0x00800000;
+ }
+ break;
+ case (int) PKCS11Constants.CKA_SUBJECT:
+ type = DATATYPE_STRING;
+ data = b.substr(curpos + 6, attribute_size);
+ /* build by PKCS11 */
+ break;
+ case (int) PKCS11Constants.CKA_LABEL:
+ type = DATATYPE_STRING;
+ data = b.substr(curpos + 6, attribute_size);
+ found = true;
+ break;
+ case (int) PKCS11Constants.CKA_MODULUS:
+ type = DATATYPE_STRING;
+ data = b.substr(curpos + 6, attribute_size);
+ /* build by PKCS11 */
+ break;
+ case (int) PKCS11Constants.CKA_ID:
+ type = DATATYPE_STRING;
+ data = b.substr(curpos + 6, attribute_size);
+ /* build by PKCS11 */
+ break;
+ case (int) PKCS11Constants.CKA_KEY_TYPE:
+ type = DATATYPE_INTEGER;
+ data = b.substr(curpos + 6, 4);
+ found = true;
+ /* build by PKCS11 */
+ break;
+ case (int) PKCS11Constants.CKA_CLASS:
+ type = DATATYPE_INTEGER;
+ data = b.substr(curpos + 6, 4);
+ xclass = data.at(0);
+ /* build by PKCS11 */
+ break;
+ case (int) PKCS11Constants.CKA_PUBLIC_EXPONENT:
+ type = DATATYPE_STRING;
+ data = b.substr(curpos + 6, attribute_size);
+ /* build by PKCS11 */
+ break;
+ case (int) PKCS11Constants.CKA_CERTIFICATE_TYPE:
+ type = DATATYPE_INTEGER;
+ data = b.substr(curpos + 6, 4);
+ /* build by PKCS11 */
+ break;
+
+ case (int) PKCS11Constants.CKA_EC_PARAMS:
+ type = DATATYPE_STRING;
+ data = b.substr(curpos + 6, attribute_size);
+ found = true;
+ break;
+
+ case (int) PKCS11Constants.CKA_EC_POINT:
+ type = DATATYPE_STRING;
+ data = b.substr(curpos + 6, attribute_size);
+ found = true;
+ break;
+ default:
+ CMS.debug("ObjectSpec.parseKeyBlob" +
+ "skipped attribute_id = " +
+ attribute_id);
+ break;
+ }
+
+ if (found) {
+ /* add attribute spec */
+ AttributeSpec attrSpec = new AttributeSpec();
+ attrSpec.setAttributeID(attribute_id);
+ attrSpec.setType(type);
+
+ switch (type) {
+ case DATATYPE_STRING:
+ attrSpec.setData(data);
+ break;
+ case DATATYPE_INTEGER:
+ attrSpec.setData(data);
+ break;
+ case DATATYPE_BOOL_FALSE:
+ break;
+ case DATATYPE_BOOL_TRUE:
+ break;
+ default:
+ break;
+ }
+
+ objectSpec.addAttributeSpec(attrSpec);
+ }
+
+ curpos += 4 + 2 + attribute_size;
+ }
+
+ //Here the objectID fixed attribute gets massaged. Here's how:
+ // The objectID becomes the cert container id, ex: 01
+ // Each key pair associated with the cert must have the same ID.
+ // This is done by math using the following formula:
+ // Given a cert id of "2", the keyAttrIds of the keys are originally
+ // configured as k4 and k5. Note that one is twice the cert id, and
+ // the other is twice the cert id plus 1. In order to map the key ids
+ // down to the cert's id, the code below changes both "4" and "5" back
+ // to "2".
+
+ int val = (objectID.charAt(1) - '0');
+ switch (objectID.charAt(0)) {
+ case 'c':
+
+ id = val;
+
+ break;
+ case 'k':
+ if ((val % 2) != 0) {
+ id = (val - 1) / 2;
+ } else {
+ id = (val / 2);
+
+ }
+
+ break;
+ }
+
+ objectSpec.setFixedAttributes(fixedAttrs | (xclass << 4) | id);
+ }
+
+ /**
+ * Parse 'c' object.
+ */
+ public static void parseCertificateAttributes(String objectID, ObjectSpec objectSpec, TPSBuffer b)
+ {
+ parseAttributes(objectID, objectSpec, b);
+ }
+
+ /**
+ * Parse 'k' object.
+ */
+ public static void parseKeyAttributes(String objectID, ObjectSpec objectSpec, TPSBuffer b)
+ {
+ parseAttributes(objectID, objectSpec, b);
+ }
+
+ /**
+ * Parse 'C' object.
+ */
+ public static void parseCertificateBlob(String objectID, ObjectSpec objectSpec, TPSBuffer b)
+ {
+ long fixedAttrs = 0;
+ int xclass = 0;
+ int id = 0;
+
+ AttributeSpec value = new AttributeSpec();
+ value.setAttributeID((int) PKCS11Constants.CKA_VALUE);
+ value.setType((byte) DATATYPE_STRING);
+ value.setData(b);
+ objectSpec.addAttributeSpec(value);
+
+ fixedAttrs = 0x00000080; /* CKA_TOKEN */
+ xclass = (int) PKCS11Constants.CKO_CERTIFICATE;
+ id = objectID.charAt(1) - '0';
+
+ objectSpec.setFixedAttributes(fixedAttrs | (xclass << 4) | id);
+ }
+
+ /**
+ * Convert object from token into object spec.
+ *
+ * Reference:
+ * http://netkey/design/applet_readable_object_spec-0.1.txt
+ * http://netkey/design/pkcs11obj.txt
+ *
+ * @throws TPSException
+ */
+ public static ObjectSpec parseFromTokenData(long objid, TPSBuffer b) throws TPSException
+ {
+ String objectID = null;
+
+ StringBuilder idBuilder = new StringBuilder();
+
+ ObjectSpec o = new ObjectSpec();
+ o.setObjectID(objid);
+
+ char[] b1 = new char[4];
+ b1[0] = (char) ((objid >> 24) & 0xff);
+ b1[1] = (char) ((objid >> 16) & 0xff);
+ b1[2] = (char) ((objid >> 8) & 0xff);
+ b1[3] = (char) (objid & 0xff);
+
+ idBuilder.append(b1[0]);
+ idBuilder.append(b1[1]);
+ idBuilder.append(b1[2]);
+ idBuilder.append(b1[3]);
+
+ objectID = idBuilder.toString();
+ switch (b1[0]) {
+ case 'c': /* certificate attributes */
+ parseCertificateAttributes(objectID, o, b);
+ break;
+ case 'k': /* public key or private key attributes */
+ parseKeyAttributes(objectID, o, b);
+ break;
+ case 'C': /* certificate in DER */
+ parseCertificateBlob(objectID, o, b);
+ break;
+ default:
+ CMS.debug("ObjectSpec::ParseKeyBlob" +
+ "unknown objectID = " + objectID.charAt(0));
+ throw new TPSException("ObjectSpec parseFromToken data: Invalid object type, aborting..");
+ }
+
+ return o;
+ }
+
+ public static ObjectSpec parse(TPSBuffer b, int offset) throws TPSException
+ {
+ int sum = 0;
+
+ if ((b.size() - offset) < 10)
+ return null;
+
+ ObjectSpec o = new ObjectSpec();
+ long id = b.getLongFrom4Bytes(offset);
+
+ o.setObjectID(id);
+ long attribute = b.getLongFrom4Bytes(offset + 4);
+
+ o.setFixedAttributes(attribute);
+ int count = b.getIntFrom2Bytes(offset + 8);
+ sum += 10;
+ int curpos = offset + 10;
+ for (int i = 0; i < count; i++) {
+ int len = 0;
+ switch (b.at(curpos + 4)) {
+ case DATATYPE_STRING:
+ len = 4 + 1 + 2 + b.getIntFrom2Bytes(curpos + 5);
+ break;
+ case DATATYPE_INTEGER:
+ len = 4 + 1 + 4;
+ break;
+ case DATATYPE_BOOL_FALSE:
+ len = 4 + 1;
+ break;
+ case DATATYPE_BOOL_TRUE:
+ len = 4 + 1;
+ break;
+ default:
+ CMS.debug("ObjectSpec::parse" +
+ "unknown DataType = " + b.at(curpos + 4));
+ throw new TPSException("ObjectSpec parse: Invalid data type, aborting..");
+ }
+ TPSBuffer attr = b.substr(curpos, len);
+ AttributeSpec attrSpec = AttributeSpec.parse(attr, 0);
+ o.addAttributeSpec(attrSpec);
+ curpos += len;
+ sum += len;
+ }
+ o.setParseRead(sum);
+ return o;
+ }
+
+ private void setParseRead(int nread) {
+ parseRead = nread;
+ }
+
+ void setObjectID(long v)
+ {
+ objectID = v;
+ }
+
+ public long getObjectID()
+ {
+ return objectID;
+ }
+
+ public void setFixedAttributes(long v)
+ {
+ fixedAttributes = v;
+ }
+
+ public long getFixedAttributes()
+ {
+ return fixedAttributes;
+ }
+
+ public int getAttributeSpecCount()
+ {
+ return attributeSpecs.size();
+ }
+
+ public AttributeSpec getAttributeSpec(int p)
+ {
+ return attributeSpecs.get(p);
+ }
+
+ public void addAttributeSpec(AttributeSpec p)
+ {
+ attributeSpecs.add(p);
+ }
+
+ public void removeAttributeSpec(int p)
+ {
+ attributeSpecs.remove(p);
+
+ }
+
+ TPSBuffer getData()
+ {
+ TPSBuffer data = new TPSBuffer();
+
+ data.addLong4Bytes(objectID);
+ data.addLong4Bytes(fixedAttributes);
+
+ int attributeCount = getAttributeSpecCount();
+ data.addInt2Bytes(attributeCount);
+ for (int i = 0; i < attributeCount; i++) {
+ AttributeSpec spec = getAttributeSpec(i);
+ data.add(spec.getData());
+ }
+
+ return data;
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/main/PKCS11Obj.java b/base/tps/src/org/dogtagpki/server/tps/main/PKCS11Obj.java
new file mode 100644
index 000000000..6224c3f81
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/main/PKCS11Obj.java
@@ -0,0 +1,689 @@
+package org.dogtagpki.server.tps.main;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+import org.dogtagpki.tps.main.TPSBuffer;
+import org.dogtagpki.tps.main.TPSException;
+import org.dogtagpki.tps.main.Util;
+
+import sun.security.pkcs11.wrapper.PKCS11Constants;
+
+import com.netscape.certsrv.apps.CMS;
+
+public class PKCS11Obj {
+
+ private ArrayList<ObjectSpec> objectSpecs;
+
+ public PKCS11Obj() {
+ objectSpecs = new ArrayList<ObjectSpec>();
+ }
+
+ private int oldFormatVersion;
+ private int oldObjectVersion;
+
+ private int formatVersion;
+ private int objectVersion;
+
+ private TPSBuffer tokenName;
+ private TPSBuffer cuid;
+
+ public static PKCS11Obj parse(TPSBuffer b, int offset) throws TPSException, DataFormatException, IOException
+ {
+ PKCS11Obj o = new PKCS11Obj();
+
+ int formatVersion = b.getIntFrom2Bytes(0);
+
+ CMS.debug("PKCS11Obj.parse: formatVersion read from blob: " + formatVersion);
+
+ o.setFormatVersion(formatVersion);
+ int objectVersion = b.getIntFrom2Bytes(2);
+
+ CMS.debug("PKCS11Obj.parse: objectVersion read from blob: " + objectVersion);
+
+ o.setObjectVersion(objectVersion);
+ o.setCUID(b.substr(offset + 4, 10));
+
+ int compressionType = b.getIntFrom2Bytes(14);
+ int dataSize = b.getIntFrom2Bytes(16);
+
+ int dataOffset = b.getIntFrom2Bytes(18);
+
+ CMS.debug("PKCS11Obj.parse: commpressionType: " + compressionType + " DataSize:"
+ + dataSize + "DataOffset: " + dataOffset + " data: " + b.toHexString());
+
+ TPSBuffer data = new TPSBuffer();
+
+ if (compressionType == 0) { /* no compression */
+ data.add(b.substr(offset + dataOffset, dataSize));
+ } else if (compressionType == 1) { /* zlib */
+ TPSBuffer compressedData = b.substr(offset + dataOffset, dataSize);
+
+ TPSBuffer uncompressedData = uncompress(
+ compressedData);
+
+ data = new TPSBuffer(uncompressedData);
+ } else {
+ throw new TPSException("PKCS11Obj.parse: error parsing object data!");
+ }
+
+ CMS.debug("PKCS11Obj.parse: uncompressed data: " + data.toHexString());
+
+ int objOffset = data.getIntFrom2Bytes(0);
+ int objCount = data.getIntFrom2Bytes(2);
+
+ //Check for absurd number of objects
+ if (objCount < 0 || objCount > 100) {
+ throw new TPSException("PKCS11Obj.parse: error parsing object data!");
+ }
+
+ TPSBuffer tokenName = data.substr(5, data.at(4));
+ o.setTokenName(tokenName);
+
+ if (tokenName != null)
+ System.out.println("tokenName: " + tokenName.toHexString());
+ System.out.println("uncompressed data size: " + data.size());
+
+ CMS.debug("PKCS11Obj.parse" + "objcount = " + objCount);
+
+ int curpos = objOffset;
+ int nread = 0;
+ for (int i = 0; i < objCount; i++) {
+ CMS.debug("PKCS11Ob.parse: working on object " + i);
+ ObjectSpec objSpec = ObjectSpec.parse(data, curpos);
+
+ if (objSpec == null)
+ continue;
+
+ nread = objSpec.getParseReadSize();
+ o.addObjectSpec(objSpec);
+
+ long oid = objSpec.getObjectID();
+ char[] b1 = new char[2];
+
+ b1[0] = (char) ((oid >> 24) & 0xff);
+ b1[1] = (char) ((oid >> 16) & 0xff);
+
+ CMS.debug("PKCS11Obj.parse " + "About to parse = " + b1[0] + ":" + b1[1]);
+ System.out.println("PKCS11Obj.parse " + "About to parse = " + b1[0] + ":" + b1[1]);
+
+ // add corresponding 'C' object for 'c'
+ if (b1[0] == 'c') {
+ for (int j = 0; j < objSpec.getAttributeSpecCount(); j++) {
+ AttributeSpec as = objSpec.getAttributeSpec(j);
+ if (as.getAttributeID() == PKCS11Constants.CKA_VALUE) {
+ if (as.getType() == (byte) 0) {
+ TPSBuffer cert = as.getValue();
+
+ long l1 = 0x43; // 'C'
+ long l2 = b1[1];
+
+ l1 = (l1 & 0xff) << 24;
+ l2 = (l2 & 0xff) << 16;
+ long certid = l1 + l2;
+
+ ObjectSpec certSpec =
+ ObjectSpec.parseFromTokenData(
+ certid, cert);
+ o.addObjectSpec(certSpec);
+
+ objSpec.removeAttributeSpec(j);
+ break;
+ }
+ }
+ }
+
+ }
+
+ curpos += nread;
+ }
+ return o;
+ }
+
+ public boolean doesCertIdExist(String certId) {
+
+ boolean foundObj = false;
+ char[] certChars = certId.toCharArray();
+
+ for (ObjectSpec objSpec : objectSpecs) {
+
+ long oid = objSpec.getObjectID();
+
+ char[] b1 = new char[2];
+
+ b1[0] = (char) ((oid >> 24) & 0xff);
+ b1[1] = (char) ((oid >> 16) & 0xff);
+
+ if (Arrays.equals(b1, certChars)) {
+ foundObj = true;
+ CMS.debug("PKCD11Obj.doesCertIdExist: match found!");
+ break;
+ }
+
+ }
+
+ return foundObj;
+ }
+
+ public void setFormatVersion(int v)
+ {
+ formatVersion = v;
+ }
+
+ public void setObjectVersion(int v)
+ {
+ CMS.debug("PKCS11Obj.setObjectVersion: setting to: " + v);
+ objectVersion = v;
+ }
+
+ public int getFormatVersion()
+ {
+ return formatVersion;
+ }
+
+ public int getObjectVersion()
+ {
+ return objectVersion;
+ }
+
+ public void setCUID(TPSBuffer cuid)
+ {
+ this.cuid = cuid;
+ ;
+ }
+
+ public TPSBuffer getCUID()
+ {
+ return cuid;
+ }
+
+ public void setTokenName(TPSBuffer tokenName)
+ {
+ this.tokenName = tokenName;
+ }
+
+ public TPSBuffer getTokenName()
+ {
+ return tokenName;
+ }
+
+ int getObjectSpecCount()
+ {
+ return objectSpecs.size();
+ }
+
+ public ObjectSpec getObjectSpec(int p)
+ {
+ return objectSpecs.get(p);
+ }
+
+ public void addObjectSpec(ObjectSpec p)
+ {
+ CMS.debug("PKCS11Obj.adObjectSpec entering.. " + p);
+ for (ObjectSpec objSpec : objectSpecs) {
+
+ long oid = objSpec.getObjectID();
+
+ if (oid == p.getObjectID()) {
+ objectSpecs.remove(objSpec);
+ char[] b1 = new char[2];
+
+ b1[0] = (char) ((oid >> 24) & 0xff);
+ b1[1] = (char) ((oid >> 16) & 0xff);
+ String oidStr = new String(b1);
+ CMS.debug("PKCS11Obj.addObjectSpec: found dup, removing...: " + oidStr);
+ break;
+ }
+ }
+
+ objectSpecs.add(p);
+ }
+
+ public void removeObjectSpec(int p)
+ {
+ objectSpecs.remove(p);
+
+ }
+
+ public void removeAllObjectSpecs() {
+
+ objectSpecs.clear();
+ }
+
+ private TPSBuffer getRawHeaderData(int compressionType, TPSBuffer data) {
+ TPSBuffer header = new TPSBuffer();
+
+ CMS.debug("PKCS11Obj.getRawHeaderData: " + " formatVersion: " + formatVersion + " objectVersion: "
+ + objectVersion);
+ header.add((byte) ((formatVersion >> 8) & 0xff));
+ header.add((byte) (formatVersion & 0xff));
+ header.add((byte) ((objectVersion >> 8) & 0xff));
+ header.add((byte) (objectVersion & 0xff));
+ header.add(cuid);
+ // COMP_NONE = 0x00
+ // COMP_ZLIB = 0x01
+
+ header.add((byte) ((compressionType >> 8) & 0xff));
+ header.add((byte) (compressionType & 0xff));
+ int compressedDataSize = data.size();
+ header.add((byte) ((compressedDataSize >> 8) & 0xff));
+ header.add((byte) (compressedDataSize & 0xff));
+ int compressedDataOffset = 20;
+ header.add((byte) ((compressedDataOffset >> 8) & 0xff));
+ header.add((byte) (compressedDataOffset & 0xff));
+
+ CMS.debug("PKCS11Obj.getRawHeaderData: returning: " + header.toHexString());
+
+ return header;
+
+ }
+
+ private TPSBuffer getRawData() {
+ TPSBuffer data = new TPSBuffer();
+
+ int objectOffset = tokenName.size() + 2 + 3;
+
+ data.add((byte) ((objectOffset >> 8) & 0xff));
+ data.add((byte) (objectOffset & 0xff));
+ int objectCount = getObjectSpecCount();
+ int objectCountX = objectCount;
+ if (objectCountX == 0) {
+ objectCountX = 0;
+ } else {
+ objectCountX = objectCountX - (objectCountX / 4);
+ }
+
+ data.add((byte) ((objectCountX >> 8) & 0xff));
+ data.add((byte) (objectCountX & 0xff));
+ data.add((byte) (tokenName.size() & 0xff));
+ data.add(tokenName);
+
+ CMS.debug("PKCS11Obj:getRawData: objectCount: " + objectCount);
+
+ for (int i = 0; i < objectCount; i++) {
+ ObjectSpec spec = getObjectSpec(i);
+ long objectID = spec.getObjectID();
+ char c = (char) ((objectID >> 24) & 0xff);
+ long fixedAttrs = spec.getFixedAttributes();
+ int xclass = (int) ((fixedAttrs & 0x70) >> 4);
+ char cont_id = (char) ((objectID >> 16) & 0xff);
+ long id = (int) (fixedAttrs & 0x0f);
+ /* locate all certificate objects */
+ if (c == 'c' && xclass == PKCS11Constants.CKO_CERTIFICATE) {
+
+ //We need to use the container id, there may be more than one cert
+ //with the same CKA_ID byte
+
+ id = cont_id - '0';
+
+ /* locate the certificate object */
+ for (int u = 0; u < objectCount; u++) {
+ ObjectSpec u_spec = getObjectSpec(u);
+ long u_objectID = u_spec.getObjectID();
+ char u_c = (char) ((u_objectID >> 24) & 0xff);
+ long u_fixedAttrs =
+ u_spec.getFixedAttributes();
+ int u_xclass = (int) ((u_fixedAttrs & 0x70) >> 4);
+ int u_id = (int) (u_fixedAttrs & 0x0f);
+ if (u_c == 'C' && u_xclass == PKCS11Constants.CKO_CERTIFICATE && u_id == id) {
+ CMS.debug("PKCSObj:getRawData: found cert object: id: " + id + " u_id: " + u_id);
+
+ AttributeSpec u_attr =
+ u_spec.getAttributeSpec(0);
+ AttributeSpec n_attr = new AttributeSpec();
+ n_attr.setAttributeID(u_attr.getAttributeID());
+ n_attr.setType(u_attr.getType());
+ n_attr.setData(u_attr.getValue());
+ spec.addAttributeSpec(n_attr);
+ }
+ }
+
+ data.add(spec.getData());
+
+ /* locate public object */
+ for (int x = 0; x < objectCount; x++) {
+ ObjectSpec x_spec = getObjectSpec(x);
+ long x_fixedAttrs =
+ x_spec.getFixedAttributes();
+ int x_xclass = (int) ((x_fixedAttrs & 0x70) >> 4);
+ int x_id = (int) (x_fixedAttrs & 0x0f);
+ if (x_xclass == PKCS11Constants.CKO_PUBLIC_KEY && x_id == id) {
+ CMS.debug("PKCSObj:getRawData: found public key object: id: " + id);
+ data.add(x_spec.getData());
+ }
+ }
+
+ /* locate private object */
+ for (int y = 0; y < objectCount; y++) {
+ ObjectSpec y_spec = getObjectSpec(y);
+ long y_fixedAttrs =
+ y_spec.getFixedAttributes();
+ int y_xclass = (int) ((y_fixedAttrs & 0x70) >> 4);
+ int y_id = (int) (y_fixedAttrs & 0x0f);
+ if (y_xclass == PKCS11Constants.CKO_PRIVATE_KEY && y_id == id) {
+ CMS.debug("PKCSObj:getRawData: found private key object: id: " + id);
+ data.add(y_spec.getData());
+ }
+ }
+ }
+ }
+
+ return data;
+
+ }
+
+ public TPSBuffer getData()
+ {
+ TPSBuffer data = getRawData();
+ TPSBuffer header = getRawHeaderData(0, data);
+
+ TPSBuffer result = new TPSBuffer(header);
+ result.add(data);
+ return result;
+ }
+
+ public TPSBuffer getCompressedData() throws TPSException, IOException
+ {
+ TPSBuffer data = getRawData(); // new TPSBuffer();
+
+ CMS.debug("PKCS11Obj.getCompressedData: " + "before compress length = " + data.size());
+ CMS.debug("PKCS11Obj.getCompressedData: " + "before compress data = " + data.toHexString());
+
+ System.out.println("Raw data before compress length: " + data.size());
+
+ TPSBuffer src_buffer = new TPSBuffer(data);
+
+ CMS.debug("PKCS11Obj.getCompressedData: " + "sizeof src_buffer = " + src_buffer.size());
+ CMS.debug("PKCS11Obj.getCompressedData: " + "data size = " + data.size());
+
+ TPSBuffer compressed = compress(src_buffer);
+ TPSBuffer header = getRawHeaderData(0x01, compressed);
+
+ TPSBuffer result = new TPSBuffer(header);
+ result.add(compressed);
+
+ CMS.debug("PKCS11Obj.getCompressedData: PKCS11 Data: " + result.toHexString());
+
+ return result;
+ }
+
+ static private TPSBuffer compress(TPSBuffer uncompressedData) throws TPSException, IOException {
+
+ if (uncompressedData == null) {
+ throw new TPSException("PKCS11Obj.uncompress: bad input data!");
+ }
+
+ byte[] data = uncompressedData.toBytesArray();
+
+ Deflater deflater = new Deflater();
+
+ deflater.setInput(data);
+
+ byte[] buffer = new byte[1024];
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
+ deflater.finish();
+ while (!deflater.finished()) {
+ int count = deflater.deflate(buffer);
+ outputStream.write(buffer, 0, count);
+ }
+ outputStream.close();
+ byte[] output = outputStream.toByteArray();
+ CMS.debug("Original: " + data.length);
+ CMS.debug("Compressed: " + output.length);
+
+ TPSBuffer result = new TPSBuffer(output);
+
+ return result;
+
+ }
+
+ static private TPSBuffer uncompress(TPSBuffer compressedData) throws TPSException, DataFormatException, IOException {
+
+ if (compressedData == null) {
+ throw new TPSException("PKCS11Obj.uncompress: bad input data!");
+ }
+ byte[] data = compressedData.toBytesArray();
+
+ Inflater inflater = new Inflater();
+ inflater.setInput(data);
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
+ byte[] buffer = new byte[1024];
+ while (!inflater.finished()) {
+ int count = inflater.inflate(buffer);
+ outputStream.write(buffer, 0, count);
+ }
+ outputStream.close();
+ byte[] output = outputStream.toByteArray();
+ CMS.debug("Original: " + data.length);
+ CMS.debug("Uncompressed: " + output.length);
+
+ TPSBuffer result = new TPSBuffer(output);
+
+ return result;
+ }
+
+ public static void main(String[] args) throws TPSException, DataFormatException, IOException {
+
+ //Sample token data taken from previous server for
+ // testing this functionality.
+
+ String compressedTokenData =
+
+ "%01%00%38%4c%53%4e%06%50%00%01" +
+ "%00%00%01%08%00%01%04%03%00%14" +
+ "%78%9c%63%e0%61%e0%64%cf%ca%4d" +
+ "%4c%cf%4b%55%48%36%64%00%81%89" +
+ "%0c%4c%40%92%99%81%41%ac%38%33" +
+ "%3d%2f%33%2f%5d%21%3b%b5%52%21" +
+ "%2d%bf%48%01%a2%0e%28%29%c8%c0" +
+ "%f8%c7%a0%89%f1%07%10%cf%59%c0" +
+ "%cc%c4%c8%c4%c4%e8%69%c0%c3%c6" +
+ "%a1%d5%e6%71%ce%96%85%99%89%95" +
+ "%c1%20%d2%50%c1%40%8e%8d%39%94" +
+ "%85%4b%58%3c%28%35%45%c1%23%b1" +
+ "%44%21%38%35%b9%b4%28%b3%a4%52" +
+ "%c1%25%3f%37%31%33%cf%50%d4%40" +
+ "%18%a4%82%5b%98%a7%20%3b%53%37" +
+ "%39%51%37%2b%31%39%db%c8%50%ce" +
+ "%40%06%24%cc%2c%2c%ea%9c%5a%54" +
+ "%92%99%96%99%9c%58%92%aa%e0%58" +
+ "%5a%92%91%0f%d2%6d%20%27%ce%6b" +
+ "%68%62%60%68%60%61%60%64%68%69" +
+ "%6a%10%05%e4%5a%02%b9%e6%50%ae" +
+ "%81%a1%a1%b8%81%28%c4%6a%be%90" +
+ "%fc%ec%d4%3c%05%6f%a0%07%42%8b" +
+ "%53%8b%0c%c5%0c%44%d8%b8%38%27" +
+ "%a9%75%4e%fe%a4%93%c2%c8%28%cc" +
+ "%06%f1%92%41%24%d0%25%ec%60%d7" +
+ "%33%31%42%bd%c1%cc%c8%ce%ec%c4" +
+ "%c0%12%dc%1d%9d%b7%91%ef%a6%dd" +
+ "%8a%27%01%3f%cf%3e%3d%7e%23%78" +
+ "%4e%8f%8c%c4%89%f7%ad%4b%1c%92" +
+ "%0c%2e%1d%5d%b5%46%ad%7a%aa%d9" +
+ "%7b%13%c7%6d%07%fb%0d%67%f5%45" +
+ "%ce%3e%52%b6%fc%ed%14%87%8a%04" +
+ "%29%3d%4e%b5%b5%2e%0f%33%fc%17" +
+ "%57%1b%54%1a%f0%01%5d%23%cb%cf" +
+ "%c8%f8%9f%05%18%38%6c%07%c0%fe" +
+ "%93%15%64%01%fa%bf%51%10%e2%02" +
+ "%87%a2%d4%94%8c%c4%12%bd%e4%fc" +
+ "%5c%03%59%90%2c%1f%8b%18%8b%88" +
+ "%d6%6f%81%1f%09%45%05%16%cf%64" +
+ "%27%1d%fe%e2%99%df%c7%64%c1%37" +
+ "%cf%40%1e%24%ad%cc%22%61%20%d6" +
+ "%20%72%ec%2a%6b%5d%94%e1%bb%c0" +
+ "%6f%05%33%5a%0e%ec%90%bb%b6%29" +
+ "%b1%d4%d1%80%13%a4%40%98%85%c9" +
+ "%80%01%35%4e%98%3d%18%0c%5c%99" +
+ "%14%19%16%d6%14%64%1c%9b%d2%a4" +
+ "%90%6e%1b%e3%56%cc%d6%36%7f%5a" +
+ "%8b%1a%87%f9%79%a7%a8%92%24%c7" +
+ "%49%4b%59%02%1e%32%29%78%9a%f0" +
+ "%70%45%1c%57%b9%77%60%b7%82%c6" +
+ "%fc%fc%09%8b%f7%a8%ec%6e%51%3d" +
+ "%60%cb%58%b3%e5%5d%af%c0%f9%a6" +
+ "%c7%d9%c6%c0%44%c0%c3%b0%10%94" +
+ "%4a%18%81%10%9c%5c%18%1b%18%18" +
+ "%b8%10%81%07%14%68%64%60%70%a4" +
+ "%38%00%b3%8d%80%c6%0b%33%6e%04" +
+ "%a5%4a%5c%76%25%1b%81%53%ee%24" +
+ "%58%ca%95%4c%cd%4b%2e%aa%2c%28" +
+ "%c9%cc%cf%c3%9a%78%7f%03%13%ee" +
+ "%77%a4%c4%eb%35%50%89%d7%10%35" +
+ "%f1%1a%52%39%f1%06%de%54%65%71" +
+ "%10%e3%2a%fe%5e%aa%7a%9e%77%f3" +
+ "%fe%e6%0d%ed%02%0d%37%0e%33%71" +
+ "%2c%58%65%c4%2f%b9%53%6c%5d%f7" +
+ "%c4%53%07%d7%eb%5d%79%df%d8%fc" +
+ "%43%c3%c0%6b%f3%89%ef%47%96%3e" +
+ "%72%7e%9b%fc%f6%4c%83%77%bf%ce" +
+ "%5d%7b%35%cc%c4%cb%aa%40%74%e2" +
+ "%fd%7d%75%09%57%fb%01%4f%cd%ab" +
+ "%4b%b3%58%5b%f7%9f%bf%a7%be%4a" +
+ "%2c%85%82%c4%eb%ce%60%e0%c2%a4" +
+ "%10%1f%7c%75%eb%26%9f%83%2d%8f" +
+ "%f5%3a%76%b5%f2%d4%cf%3b%de%b7" +
+ "%bb%e9%56%8a%ef%f4%af%3c%31%3c" +
+ "%76%77%b9%1a%98%14%32%3e%09%cd" +
+ "%fc%c8%f9%f3%c9%b2%45%21%f3%b6" +
+ "%2c%56%0c%39%fb%2d%e5%7f%da%de" +
+ "%fd%ce%33%17%d4%c8%af%15%c8%dd" +
+ "%99%6d%0a%4a%2a%01%8b%88%49%bb" +
+ "%94%86%5f%b6%09%d0%78%81%85%9b" +
+ "%f0%a6%5d%63%70%da%9d%0c%4b%bb" +
+ "%32%38%d3%ae%02%58%29%96%b2%d7" +
+ "%84%be%c9%d7%d8%d0%c8%c8%00%98" +
+ "%50%4d%8c%c1%65%af%85%a1%11%28" +
+ "%09%83%b9%d4%4d%be%49%31%e1%27" +
+ "%cf%4e%93%9b%7a%35%6d%1b%db%e1" +
+ "%10%3b%ee%c5%1e%b6%1f%23%ee%7c" +
+ "%9c%b7%6e%ee%aa%57%a2%7f%95%fb" +
+ "%fd%3a%3b%ab%de%46%cb%ff%62%9e" +
+ "%ac%90%66%b3%f0%58%b3%dd%ed%38" +
+ "%e1%16%9f%a4%56%8d%fb%6b%db%96" +
+ "%ba%ef%aa%a4%28%f9%66%b5%2f%9d" +
+ "%36%cd%7b%52%6b%4b%68%e5%8d%57" +
+ "%92%92%5f%78%36%7e%31%a4%b4%ec" +
+ "%55%a8%95%da%7c%76%42%8a%19%a3" +
+ "%d9%f1%03%27%af%cb%14%fb%3b%44" +
+ "%cf%dc%b1%fc%a1%dc%8f%95%31%b9" +
+ "%5f%ff%2e%aa%b8%00%2c%9d%f7%b9" +
+ "%1e%bd%c5%2e%78%b4%48%4e%aa%7b" +
+ "%92%e1%16%5d%af%cd%1f%94%93%96" +
+ "%3b%27%c5%ed%ab%f6%0c%dd%cb%73" +
+ "%fd%7a%b6%39%38%fd%2e%26%26%fd" +
+ "%52%1a%80%d9%66%e0%f4%bb%19%5f" +
+ "%fa%05%00%21%15%7f%b0";
+
+ System.out.println("Test PKCS11 Blob data: " + compressedTokenData);
+ System.out.println("Test Data: Len: " + compressedTokenData.length());
+
+ // Test getting integer values from a TPSBuffer
+
+ byte[] value = { (byte) 99, (byte) 49, (byte) 0, (byte) 0 };
+
+ TPSBuffer valBuf = new TPSBuffer(value);
+
+ long l1 = valBuf.getLongFrom4Bytes(0);
+
+ int i1 = valBuf.getIntFrom2Bytes(0);
+
+ int i2 = valBuf.getIntFrom1Byte(0);
+
+ System.out.println("4 bytes long: " + l1 + " 2 bytes int: " + i1 + " 1 byte int: " + i2);
+
+ // Now test the parsing and un-parsing of the data, the result at the end should be
+ // the same as the original data.
+ // The data above is an exact copy of a blob taken off of a real token in the
+ // old TPS.
+
+ byte[] decoded = Util.uriDecodeFromHex(compressedTokenData);
+
+ System.out.println("decoded compressed datat size: " + decoded.length);
+
+ // This is buffer containing sample copressed pkcs#11 blob.
+ TPSBuffer tokenData = new TPSBuffer(decoded);
+
+ // Parse the given token data into PKCS#11 objects and attributes
+
+ PKCS11Obj object = PKCS11Obj.parse(tokenData, 0);
+
+ String certId = "C1";
+ boolean exists = object.doesCertIdExist(certId);
+
+ System.out.println("CertID " + certId + " exists: " + exists);
+
+ // This gets the compressed blob that will go out to token of the parsed data.
+ TPSBuffer implodedData = object.getCompressedData();
+
+ System.out.println("imploded token data size: " + implodedData.size());
+
+ String encodedImplodedData = implodedData.toHexString();
+
+ System.out.println("encodedImplodedData: " + encodedImplodedData);
+
+ // Now test to see if both blobs are identical
+
+ boolean identical = implodedData.equals(tokenData);
+
+ System.out.println("Before and after comparison result: Are the blobs identical?: " + identical);
+
+ }
+
+ public int getOldFormatVersion() {
+ return oldFormatVersion;
+ }
+
+ public void setOldFormatVersion(int oldFormatVersion) {
+ this.oldFormatVersion = oldFormatVersion;
+ }
+
+ public int getOldObjectVersion() {
+ return oldObjectVersion;
+ }
+
+ public void setOldObjectVersion(int oldObjectVersion) {
+ this.oldObjectVersion = oldObjectVersion;
+ }
+
+ public int getNextFreeCertIdNumber() {
+
+ int highest_cert_id = 0;
+
+ int numObjs = getObjectSpecCount();
+
+ for (int i = 0; i < numObjs; i++) {
+ ObjectSpec os = getObjectSpec(i);
+ if (os == null)
+ continue;
+
+ long objid = os.getObjectID();
+
+ char[] b1 = new char[2];
+
+ b1[0] = (char) ((objid >> 24) & 0xff);
+ b1[1] = (char) ((objid >> 16) & 0xff);
+
+ if (b1[0] == 'C') { //found a certificate
+
+ int id_int = b1[1] - '0';
+
+ if (id_int > highest_cert_id) {
+ highest_cert_id = id_int;
+ }
+ }
+
+ }
+
+ highest_cert_id++;
+ CMS.debug("TPSEnrollProcessor.getNextFreeCertIdNumber: returning: " + highest_cert_id);
+
+ return highest_cert_id;
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/AppletInfo.java b/base/tps/src/org/dogtagpki/server/tps/processor/AppletInfo.java
new file mode 100644
index 000000000..bc46eaba8
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/AppletInfo.java
@@ -0,0 +1,115 @@
+package org.dogtagpki.server.tps.processor;
+
+import org.dogtagpki.tps.main.TPSBuffer;
+
+
+public class AppletInfo {
+
+ private byte majorVersion;
+ private byte minorVersion;
+ private byte appMajorVersion;
+ private byte appMinorVersion;
+
+ private TPSBuffer aid;
+ private TPSBuffer cuid;
+ private TPSBuffer msn;
+ private int totalMem;
+ private int freeMem;
+
+ public AppletInfo(byte appletMajorVer,byte appletMinorVer,byte appMajorVer,byte appMinorVer) {
+
+ majorVersion = appletMajorVer;
+ minorVersion = appletMinorVer;
+ appMajorVersion = appMajorVer;
+ appMinorVersion = appMinorVer;
+
+ }
+
+ public void setCUID(TPSBuffer theCuid) {
+ cuid = new TPSBuffer(theCuid);
+ }
+
+ public TPSBuffer getCUID() {
+ return cuid;
+ }
+
+ public void setMSN(TPSBuffer theMsn) {
+ msn = new TPSBuffer(theMsn);
+ }
+
+ public TPSBuffer getMSN() {
+ return msn;
+ }
+
+ public String getCUIDhexString(){
+ if(cuid != null) {
+ return cuid.toHexString();
+ }
+
+ return null;
+ }
+
+ /*
+ * getCUIDhexString2 returns hex string without the '%'
+ */
+ public String getCUIDhexStringPlain() {
+ if(cuid != null) {
+ return cuid.toHexStringPlain();
+ }
+
+ return null;
+ }
+
+ public String getMSNString() {
+ if(msn != null) {
+ return msn.toHexString();
+ }
+ return null;
+ }
+
+ public byte getMajorVersion() {
+ return majorVersion;
+ }
+
+ public byte getMinorVersion() {
+ return minorVersion;
+ }
+
+ public byte getAppMinorVersion() {
+ return appMinorVersion;
+ }
+
+ public byte getAppMajorVersion() {
+ return appMajorVersion;
+ }
+
+ public static void main(String[] args) {
+
+ }
+
+ public void setTotalMem(int total_mem) {
+ totalMem = total_mem;
+
+ }
+
+ public int getTotalMem() {
+ return totalMem;
+ }
+
+ public void setFreeMem(int free_mem) {
+ freeMem = free_mem;
+ }
+
+ public int getFreeMem() {
+ return freeMem;
+ }
+
+ public TPSBuffer getAid() {
+ return aid;
+ }
+
+ public void setAid(TPSBuffer aid) {
+ this.aid = aid;
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/CertEnrollInfo.java b/base/tps/src/org/dogtagpki/server/tps/processor/CertEnrollInfo.java
new file mode 100644
index 000000000..9dfb3f114
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/CertEnrollInfo.java
@@ -0,0 +1,270 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps.processor;
+
+import org.dogtagpki.server.tps.channel.SecureChannel.TokenKeyType;
+import org.dogtagpki.server.tps.cms.CARenewCertResponse;
+import org.dogtagpki.server.tps.cms.CARetrieveCertResponse;
+import org.dogtagpki.server.tps.cms.KRARecoverKeyResponse;
+import org.dogtagpki.server.tps.dbs.TokenRecord;
+import org.dogtagpki.server.tps.engine.TPSEngine;
+
+public class CertEnrollInfo {
+
+ private TokenKeyType keyTypeEnum;
+ private String profileId;
+ private String certId;
+ private String certAttrId;
+ private String privateKeyAttrId;
+ private String publicKeyAttrId;
+ private String publisherId;
+ private String keyType;
+ private String keyTypePrefix;
+
+ private CARetrieveCertResponse recoveredCertData;
+ private KRARecoverKeyResponse recoveredKeyData;
+ private TokenRecord toBeRecoveredRecord;
+
+ private CARenewCertResponse renewedCertData;
+
+ private int keySize;
+ private int algorithm;
+ private int keyUsage;
+ private int keyUser;
+ private int privateKeyNumber;
+ private int publicKeyNumber;
+ private int startProgress;
+ private int endProgress;
+
+ private TPSEngine.ENROLL_MODES enrollmentMode = TPSEngine.ENROLL_MODES.MODE_ENROLL;
+
+ public void setEnrollmentMode(TPSEngine.ENROLL_MODES mode) {
+ enrollmentMode = mode;
+ }
+
+ public TPSEngine.ENROLL_MODES getEnrollmentMode() {
+ return enrollmentMode;
+ }
+
+ public void setRecoveredCertData(CARetrieveCertResponse cData) {
+ recoveredCertData = cData;
+ }
+
+ public CARetrieveCertResponse getRecoveredCertData() {
+ return recoveredCertData;
+ }
+
+ public void setRecoveredKeyData(KRARecoverKeyResponse kData) {
+ recoveredKeyData = kData;
+ }
+
+ public KRARecoverKeyResponse getRecoveredKeyData() {
+ return recoveredKeyData;
+ }
+
+
+ public void setStartProgressValue(int progress) {
+ startProgress = progress;
+ }
+
+ public int getStartProgressValue() {
+ return startProgress;
+ }
+
+ public void setEndProgressValue(int progress) {
+ endProgress = progress;
+ }
+
+ public int getEndProgressValue() {
+ return endProgress;
+ }
+
+ public void setKeyTypeEnum(TokenKeyType keyTypeEnum) {
+ this.keyTypeEnum = keyTypeEnum;
+ }
+
+ public TokenKeyType getKeyTypeEnum() {
+ return keyTypeEnum;
+ }
+
+ public void setProfileId(String profileId) {
+ this.profileId = profileId;
+ }
+
+ public String getProfileId() {
+ return profileId;
+ }
+
+ public void setCertId(String certId) {
+ this.certId = certId;
+ }
+
+ public String getCertId() {
+ return certId;
+ }
+
+ public void setCertAttrId(String certAttrId) {
+ this.certAttrId = certAttrId;
+ }
+
+ public String getCertAttrId() {
+ return certAttrId;
+ }
+
+ public void setPrivateKeyAttrId(String priKeyAttrId) {
+ privateKeyAttrId = priKeyAttrId;
+ }
+
+ public String getPrivateKeyAttrId() {
+ return privateKeyAttrId;
+ }
+
+ public void setPublicKeyAttrId(String publicKeyAttrId) {
+ this.publicKeyAttrId = publicKeyAttrId;
+ }
+
+ public String getPublicKeyAttrId() {
+ return publicKeyAttrId;
+ }
+
+ public void setKeySize(int keySize) {
+ this.keySize = keySize;
+ }
+
+ public int getKeySize() {
+ return keySize;
+ }
+
+ public void setPublisherId(String publisherId) {
+ this.publisherId = publisherId;
+ }
+
+ public String getPublisherId() {
+ return publisherId;
+ }
+
+ public void setAlgorithm(int algorithm) {
+ this.algorithm = algorithm;
+ }
+
+ public int getAlgorithm() {
+ return algorithm;
+ }
+
+ public void setKeyUsage(int keyUsage) {
+ this.keyUsage = keyUsage;
+ }
+
+ public int getKeyUsage() {
+ return keyUsage;
+ }
+
+ public void setKeyUser(int keyUser) {
+ this.keyUser = keyUser;
+ }
+
+ public int getKeyUser() {
+ return keyUser;
+ }
+
+ public void setPrivateKeyNumber(int priKeyNumber) {
+ privateKeyNumber = priKeyNumber;
+ }
+
+ public int getPrivateKeyNumber() {
+ return privateKeyNumber;
+ }
+
+ public void setPublicKeyNumber(int pubKeyNumber) {
+ publicKeyNumber = pubKeyNumber;
+ }
+
+ public int getPublicKeyNumber() {
+ return publicKeyNumber;
+ }
+
+ public void setKeyType(String keyType) {
+ this.keyType = keyType;
+ }
+
+ public String getKeyType() {
+ return keyType;
+ }
+
+ public void setKeyTypePrefix(String keyTypePrefix) {
+ this.keyTypePrefix = keyTypePrefix;
+ }
+
+ public String getKeyTypePrefix() {
+ return keyTypePrefix;
+ }
+
+ public boolean getIsRecoveryMode() {
+ if (enrollmentMode == TPSEngine.ENROLL_MODES.MODE_RECOVERY) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean getIsRenewalMode() {
+ if (enrollmentMode == TPSEngine.ENROLL_MODES.MODE_RENEWAL) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean getIsEnrollmentMode() {
+ if (enrollmentMode == TPSEngine.ENROLL_MODES.MODE_ENROLL) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public void setTokenToBeRecovered(TokenRecord toBeRecovered) {
+ toBeRecoveredRecord = toBeRecovered;
+
+ }
+
+ public TokenRecord getTokenToBeRecovered() {
+ return toBeRecoveredRecord;
+ }
+
+ public void setRenewedCertData(CARenewCertResponse certResponse) {
+ renewedCertData = certResponse;
+ }
+
+ public CARenewCertResponse getRenewedCertData() {
+ return renewedCertData;
+ }
+
+ public int getCertIdIndex() {
+ int result = 0;
+
+ if(certId != null && certId.length() == 2) {
+ result = certId.charAt(1) - '0';
+ }
+
+ return result;
+ }
+
+
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/EnrolledCertsInfo.java b/base/tps/src/org/dogtagpki/server/tps/processor/EnrolledCertsInfo.java
new file mode 100644
index 000000000..87b86f7d7
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/EnrolledCertsInfo.java
@@ -0,0 +1,262 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps.processor;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.ArrayList;
+
+import netscape.security.x509.X509CertImpl;
+
+import org.dogtagpki.server.tps.dbs.TPSCertRecord;
+import org.dogtagpki.server.tps.main.PKCS11Obj;
+import org.dogtagpki.tps.main.TPSBuffer;
+import org.dogtagpki.tps.main.Util;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+
+public class EnrolledCertsInfo {
+
+ EnrolledCertsInfo() {
+ certificates = new ArrayList<X509CertImpl>();
+ ktypes = new ArrayList<String>();
+ origins = new ArrayList<String>();
+ tokenTypes = new ArrayList<String>();
+ }
+
+ EnrolledCertsInfo(PKCS11Obj obj, TPSBuffer wrappedChallenge, TPSBuffer plainChallenge, int keyTypeNum,
+ int startProgress, int endProgress) {
+ this();
+ this.wrappedChallenge = wrappedChallenge;
+ plaintextChallenge = plainChallenge;
+ pkcs11objx = obj;
+ numCertsToEnroll = keyTypeNum;
+ this.startProgress = startProgress;
+ this.endProgress = endProgress;
+ }
+
+ //Tables that will get set during processing
+ private ArrayList<String> origins;
+ private ArrayList<String> ktypes;
+ private ArrayList<String> tokenTypes;
+ private ArrayList<X509CertImpl> certificates;
+
+ //Input challenge data
+ private TPSBuffer wrappedChallenge;
+ private TPSBuffer plaintextChallenge;
+ private TPSBuffer keyCheck;
+
+ private int numCertsToEnroll;
+ private int currentCertIndex;
+
+ private int startProgress;
+ private int endProgress;
+
+ public int getCurrentCertIndex() {
+ return currentCertIndex;
+ }
+
+ public void setCurrentCertIndex(int index) {
+ currentCertIndex = index;
+ }
+
+ public void setNumCertsToEnroll(int num) {
+ numCertsToEnroll = num;
+ }
+
+ public int getNumCertsToEnroll() {
+ return numCertsToEnroll;
+ }
+
+ int getStartProgressValue() {
+ return startProgress;
+ }
+
+ int getEndProgressValue() {
+ return endProgress;
+ }
+
+ public void setKeyCheck(TPSBuffer keyCheck) {
+ this.keyCheck = keyCheck;
+ }
+
+ public TPSBuffer getKeyCheck() {
+ return keyCheck;
+ }
+
+ //PKCS11Object that will have values added to it during processing
+ private PKCS11Obj pkcs11objx;
+
+ public void setWrappedChallenge(TPSBuffer wrappedChallenge) {
+ this.wrappedChallenge = wrappedChallenge;
+ }
+
+ public TPSBuffer getWrappedChallenge() {
+ return wrappedChallenge;
+ }
+
+ public void setPlaintextChallenge(TPSBuffer plaintextChallenge) {
+ this.plaintextChallenge = plaintextChallenge;
+ }
+
+ public TPSBuffer getPlaintextChallenge() {
+ return plaintextChallenge;
+ }
+
+ public void setPKCS11Obj(PKCS11Obj pkcs11obj) {
+ pkcs11objx = pkcs11obj;
+ }
+
+ public PKCS11Obj getPKCS11Obj() {
+ return pkcs11objx;
+ }
+
+ public void addOrigin(String origin) {
+
+ CMS.debug("EnrolledCertsInfo.addOrigin: " + origin);
+ origins.add(origin);
+ }
+
+ public void addKType(String ktype) {
+ ktypes.add(ktype);
+ }
+
+ public void addTokenType(String tokenType) {
+ tokenTypes.add(tokenType);
+ }
+
+ public void addCertificate(X509CertImpl x509Cert) {
+ certificates.add(x509Cert);
+ }
+
+ public void setStartProgress(int startP) {
+ startProgress = startP;
+
+ }
+
+ public void setEndProgress(int endP) {
+ endProgress = endP;
+
+ }
+
+ public ArrayList<TPSCertRecord> toTPSCertRecords(String cuid, String uid) {
+ ArrayList<TPSCertRecord> certs = new ArrayList<TPSCertRecord>();
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: starts");
+ int index = 0;
+ for (X509CertImpl cert: certificates) {
+ TPSCertRecord certRecord = new TPSCertRecord();
+
+ //serial number
+ BigInteger serial_BigInt = cert.getSerialNumber();
+
+ String hexSerial = serial_BigInt.toString(16);
+ String serialNumber = "0x" + hexSerial;
+ certRecord.setSerialNumber(serialNumber);
+
+ String uniqueString = Util.getTimeStampString(false);
+ String id = hexSerial + "." + uniqueString;
+
+ certRecord.setId(id);
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: converting cert:"+ certRecord.getId());
+
+ //token id
+ certRecord.setTokenID(cuid);
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: cuid =" + cuid);
+
+ //origin
+ if ((!origins.isEmpty()) && index <origins.size() && origins.get(index)!= null) {
+ certRecord.setOrigin(origins.get(index));
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: origin =" + origins.get(index));
+ } else {
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: origin not found for index:"+ index);
+ }
+
+ //user id
+ certRecord.setUserID(uid);
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: uid =" + uid);
+
+ //KeyType
+ if ((!ktypes.isEmpty()) && index <ktypes.size() && ktypes.get(index)!= null) {
+ certRecord.setKeyType(ktypes.get(index));
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: keyType =" + ktypes.get(index));
+ } else {
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: keyType not found for index:"+ index);
+ }
+
+ //token type
+ if ((!tokenTypes.isEmpty()) && index <tokenTypes.size() && tokenTypes.get(index)!= null) {
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: tokenType=" + tokenTypes.get(index));
+ certRecord.setType(tokenTypes.get(index));
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: tokenType set");
+ } else {
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: tokenType not found for index:"+ index);
+ //certRecord.setType("");
+ }
+
+ //Issuer
+ String issuedBy = cert.getIssuerDN().toString();
+ certRecord.setIssuedBy(issuedBy);
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: issuer ="+ issuedBy);
+
+ //Subject
+ String subject = cert.getSubjectDN().toString();
+ certRecord.setSubject(subject);
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: subject ="+ subject);
+
+ //NotBefore
+ certRecord.setValidNotBefore(cert.getNotBefore());
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: notBefore ="+ cert.getNotBefore().toString());
+
+ //NotAfter
+ certRecord.setValidNotAfter(cert.getNotAfter());
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: notAfter ="+ cert.getNotAfter().toString());
+
+ //status
+ certRecord.setStatus("active");
+
+ /* certificate
+ byte[] certBytes = null;
+ try {
+ certBytes = cert.getEncoded();
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: certBytes ="+ CMS.BtoA(certBytes));
+ } catch (CertificateEncodingException e) {
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecord: "+ e);
+ //TODO: throw
+
+ }
+ certRecord.setCertificate(CMS.BtoA(certBytes));
+ */
+ // Alternative to the actual certificate -- certificate AKI
+ try {
+ String aki = Util.getCertAkiString(cert);
+ certRecord.setCertificate(aki);
+ } catch (EBaseException | IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ certs.add(certRecord);
+
+ index++;
+ }
+ CMS.debug("EnrolledCertsInfo.toTPSCertRecords: ends");
+ return certs;
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
new file mode 100644
index 000000000..cff615752
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
@@ -0,0 +1,2789 @@
+package org.dogtagpki.server.tps.processor;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.zip.DataFormatException;
+
+import netscape.security.provider.RSAPublicKey;
+//import org.mozilla.jss.pkcs11.PK11ECPublicKey;
+import netscape.security.util.BigInt;
+import netscape.security.x509.X509CertImpl;
+
+import org.dogtagpki.server.tps.TPSSession;
+import org.dogtagpki.server.tps.TPSSubsystem;
+import org.dogtagpki.server.tps.TPSTokenPolicy;
+import org.dogtagpki.server.tps.authentication.TPSAuthenticator;
+import org.dogtagpki.server.tps.channel.SecureChannel;
+import org.dogtagpki.server.tps.channel.SecureChannel.TokenKeyType;
+import org.dogtagpki.server.tps.cms.CAEnrollCertResponse;
+import org.dogtagpki.server.tps.cms.CARemoteRequestHandler;
+import org.dogtagpki.server.tps.cms.CARenewCertResponse;
+import org.dogtagpki.server.tps.cms.CARetrieveCertResponse;
+import org.dogtagpki.server.tps.cms.CARevokeCertResponse;
+import org.dogtagpki.server.tps.cms.KRARecoverKeyResponse;
+import org.dogtagpki.server.tps.cms.KRAServerSideKeyGenResponse;
+import org.dogtagpki.server.tps.dbs.ActivityDatabase;
+import org.dogtagpki.server.tps.dbs.TPSCertRecord;
+import org.dogtagpki.server.tps.dbs.TokenRecord;
+import org.dogtagpki.server.tps.engine.TPSEngine;
+import org.dogtagpki.server.tps.engine.TPSEngine.ENROLL_MODES;
+import org.dogtagpki.server.tps.main.ObjectSpec;
+import org.dogtagpki.server.tps.main.PKCS11Obj;
+import org.dogtagpki.tps.apdu.ExternalAuthenticateAPDU.SecurityLevel;
+import org.dogtagpki.tps.main.TPSBuffer;
+import org.dogtagpki.tps.main.TPSException;
+import org.dogtagpki.tps.main.Util;
+import org.dogtagpki.tps.msg.BeginOpMsg;
+import org.dogtagpki.tps.msg.EndOpMsg;
+import org.dogtagpki.tps.msg.EndOpMsg.TPSStatus;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.crypto.InvalidKeyFormatException;
+import org.mozilla.jss.pkcs11.PK11PubKey;
+import org.mozilla.jss.pkcs11.PK11RSAPublicKey;
+import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authentication.IAuthCredentials;
+import com.netscape.certsrv.authentication.IAuthToken;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.EPropertyNotFound;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.tps.token.TokenStatus;
+import com.netscape.cmsutil.util.Utils;
+
+public class TPSEnrollProcessor extends TPSProcessor {
+
+ public TPSEnrollProcessor(TPSSession session) {
+ super(session);
+ }
+
+ @Override
+ public void process(BeginOpMsg beginMsg) throws TPSException, IOException {
+ if (beginMsg == null) {
+ throw new TPSException("TPSEnrollrocessor.process: invalid input data, not beginMsg provided.",
+ TPSStatus.STATUS_ERROR_CONTACT_ADMIN);
+ }
+ setBeginMessage(beginMsg);
+ setCurrentTokenOperation("enroll");
+ checkIsExternalReg();
+
+ enroll();
+
+ }
+
+ private void enroll() throws TPSException, IOException {
+ CMS.debug("TPSEnrollProcessor enroll: entering...");
+ String auditMsg = null;
+ TPSSubsystem tps = (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ TPSTokenPolicy tokenPolicy = new TPSTokenPolicy(tps);
+
+ AppletInfo appletInfo = null;
+ TokenRecord tokenRecord = null;
+ try {
+ appletInfo = getAppletInfo();
+ } catch (TPSException e) {
+ auditMsg = e.toString();
+ tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
+ "failure");
+
+ throw e;
+ }
+ appletInfo.setAid(getCardManagerAID());
+
+ CMS.debug("TPSEnrollProcessor.enroll: token cuid: " + appletInfo.getCUIDhexStringPlain());
+ boolean isTokenPresent = false;
+
+ tokenRecord = isTokenRecordPresent(appletInfo);
+
+ if (tokenRecord != null) {
+ CMS.debug("TPSEnrollProcessor.enroll: found token...");
+ isTokenPresent = true;
+ } else {
+ CMS.debug("TPSEnrollProcessor.enroll: token does not exist in tokendb... create one in memory");
+ tokenRecord = new TokenRecord();
+ tokenRecord.setId(appletInfo.getCUIDhexStringPlain());
+ }
+
+ fillTokenRecord(tokenRecord, appletInfo);
+ session.setTokenRecord(tokenRecord);
+
+ String resolverInstName = getResolverInstanceName();
+
+ String tokenType = null;
+
+ tokenType = resolveTokenProfile(resolverInstName, appletInfo.getCUIDhexString(), appletInfo.getMSNString(),
+ appletInfo.getMajorVersion(), appletInfo.getMinorVersion());
+ CMS.debug("TPSEnrollProcessor.enroll: resolved tokenType: " + tokenType);
+
+ checkProfileStateOK();
+ String cuid = appletInfo.getCUIDhexStringPlain();
+
+ boolean do_force_format = false;
+ if (isTokenPresent) {
+ CMS.debug("TPSEnrollProcessor.enroll: token exists in tokendb");
+
+ TokenStatus newState = TokenStatus.ACTIVE;
+ // Check for transition to ACTIVE status.
+
+ if (!tps.engine.isOperationTransitionAllowed(tokenRecord.getTokenStatus(), newState)) {
+ CMS.debug("TPSEnrollProcessor.enroll: token transition disallowed " +
+ tokenRecord.getTokenStatus() +
+ " to " + newState);
+ auditMsg = "Operation for CUID " + cuid +
+ " Disabled, illegal transition attempted " + tokenRecord.getTokenStatus() +
+ " to " + newState;
+ tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
+ "failure");
+
+ throw new TPSException(auditMsg,
+ TPSStatus.STATUS_ERROR_DISABLED_TOKEN);
+ } else {
+ CMS.debug("TPSPEnrollrocessor.enroll: token transition allowed " +
+ tokenRecord.getTokenStatus() +
+ " to " + newState);
+ }
+
+ do_force_format = tokenPolicy.isForceTokenFormat(cuid);
+
+ if (!tokenPolicy.isAllowdTokenReenroll(cuid) &&
+ !tokenPolicy.isAllowdTokenRenew(cuid)) {
+ CMS.debug("TPSEnrollProcessor.enroll: token renewal or reEnroll disallowed ");
+ auditMsg = "Operation renewal or reEnroll for CUID " + cuid +
+ " Disabled";
+ tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
+ "failure");
+
+ throw new TPSException(auditMsg,
+ TPSStatus.STATUS_ERROR_DISABLED_TOKEN);
+ }
+ } else {
+ CMS.debug("TPSEnrollProcessor.enroll: token does not exist");
+ tokenRecord.setStatus("uninitialized");
+
+ checkAllowUnknownToken(TPSEngine.OP_FORMAT_PREFIX);
+ }
+ checkAndAuthenticateUser(appletInfo, tokenType);
+
+ if (do_force_format) {
+ CMS.debug("TPSEnrollProcessor.enroll: About to force format first due to policy.");
+ //We will skip the auth step inside of format
+ format(true);
+ } else {
+ checkAndUpgradeApplet(appletInfo);
+ //Get new applet info
+ appletInfo = getAppletInfo();
+ }
+
+ CMS.debug("TPSEnrollProcessor.enroll: Finished updating applet if needed.");
+
+ //Check and upgrade keys if called for
+
+ SecureChannel channel = checkAndUpgradeSymKeys();
+ channel.externalAuthenticate();
+
+ //Reset the token's pin, create one if we don't have one already
+
+ checkAndHandlePinReset(channel);
+ tokenRecord.setKeyInfo(channel.getKeyInfoData().toHexStringPlain());
+ String tksConnId = getTKSConnectorID();
+ TPSBuffer plaintextChallenge = computeRandomData(16, tksConnId);
+
+ //These will be used shortly
+ TPSBuffer wrappedChallenge = encryptData(appletInfo, channel.getKeyInfoData(), plaintextChallenge, tksConnId);
+ PKCS11Obj pkcs11objx = null;
+
+ try {
+ pkcs11objx = getCurrentObjectsOnToken(channel);
+ } catch (DataFormatException e) {
+ auditMsg = "TPSEnrollProcessor.enroll: Failed to parse original token data: " + e.toString();
+ tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
+ "failure");
+
+ throw new TPSException(auditMsg);
+ }
+
+ pkcs11objx.setCUID(appletInfo.getCUID());
+
+ if (!isTokenPresent) {
+ try {
+ tps.tdb.tdbAddTokenEntry(tokenRecord, "uninitialized");
+ } catch (Exception e) {
+ String failMsg = "add token failure";
+ auditMsg = failMsg + ":" + e.toString();
+ throw new TPSException(auditMsg);
+ }
+ }
+
+ statusUpdate(10, "PROGRESS_PROCESS_PROFILE");
+
+ EnrolledCertsInfo certsInfo = new EnrolledCertsInfo();
+ certsInfo.setWrappedChallenge(wrappedChallenge);
+ certsInfo.setPlaintextChallenge(plaintextChallenge);
+ certsInfo.setPKCS11Obj(pkcs11objx);
+ certsInfo.setStartProgress(15);
+ certsInfo.setEndProgress(90);
+
+ boolean renewed = false;
+ TPSStatus status = generateCertsAfterRenewalRecoveryPolicy(certsInfo, channel, appletInfo);
+ //most failed would have thrown an exception
+ String statusString = "Unknown"; // gives some meaningful debug message
+ if (status == TPSStatus.STATUS_NO_ERROR)
+ statusString = "Enrollment to follow";
+ else if (status == TPSStatus.STATUS_ERROR_RECOVERY_IS_PROCESSED)
+ statusString = "Recovery processed";
+ else if (status == TPSStatus.STATUS_ERROR_RENEWAL_IS_PROCESSED)
+ statusString = "Renewal processed";
+ else {
+ auditMsg = " generateCertsAfterRenewalRecoveryPolicy returned status=" + status;
+ CMS.debug("TPSEnrollProcessor.enroll:" + auditMsg);
+ throw new TPSException(auditMsg);
+ }
+ auditMsg = "generateCertsAfterRenewalRecoveryPolicy returns status:"
+ + EndOpMsg.statusToInt(status) + " : " + statusString;
+ CMS.debug("TPSEnrollProcessor.enroll: " + auditMsg);
+ if (status == TPSStatus.STATUS_NO_ERROR) {
+ if (!generateCertificates(certsInfo, channel, appletInfo)) {
+ CMS.debug("TPSEnrollProcessor.enroll:generateCertificates returned false means some certs failed enrollment; clean up (format) the token");
+ format(true /*skipAuth*/);
+ throw new TPSException("generateCertificates failed");
+ } else {
+ CMS.debug("TPSEnrollProcessor.enroll:generateCertificates returned true means cert enrollment successful");
+ }
+ }
+ // at this point, enrollment, renewal, or recovery have been processed accordingly;
+ if (status == TPSStatus.STATUS_ERROR_RENEWAL_IS_PROCESSED &&
+ tokenPolicy.isAllowdTokenRenew(cuid)) {
+ renewed = true;
+ CMS.debug("TPSEnrollProcessor.enroll: renewal happened.. ");
+ }
+ /*
+ * TODO:
+ * find the point to do the following...
+ * when total available memory is exceeded on the token ...
+ * if(!renewed) //Renewal should leave what they have on the token.
+ * format(true);
+ */
+ String tokenLabel = buildTokenLabel(certsInfo, appletInfo);
+
+ pkcs11objx.setTokenName(new TPSBuffer(tokenLabel.getBytes()));
+
+ int lastObjVer = pkcs11objx.getOldObjectVersion();
+
+ CMS.debug("TPSEnrollProcessor.enroll: getOldObjectVersion: returning: " + lastObjVer);
+
+ if (lastObjVer != 0) {
+ while (lastObjVer == 0xff) {
+ Random randomGenerator = new Random();
+ lastObjVer = randomGenerator.nextInt(1000);
+ }
+
+ lastObjVer = lastObjVer + 1;
+ CMS.debug("TPSEnrollProcessor.enroll: Setting objectVersion to: " + lastObjVer);
+ pkcs11objx.setObjectVersion(lastObjVer);
+
+ }
+
+ pkcs11objx.setFormatVersion(pkcs11objx.getOldFormatVersion());
+
+ // Make sure we have a good secure channel before writing out the final objects
+ channel = setupSecureChannel();
+
+ statusUpdate(92, "PROGRESS_WRITE_OBJECTS");
+
+ writeFinalPKCS11ObjectToToken(pkcs11objx, appletInfo, channel);
+ statusUpdate(98, "PROGRESS_ISSUER_INFO");
+ writeIssuerInfoToToken(channel);
+
+ statusUpdate(99, "PROGRESS_SET_LIFECYCLE");
+ channel.setLifeycleState((byte) 0x0f);
+
+ try {
+ tokenRecord.setStatus("active");
+ tps.tdb.tdbUpdateTokenEntry(tokenRecord);
+ } catch (Exception e) {
+ String failMsg = "update token failure";
+ auditMsg = failMsg + ":" + e.toString();
+ tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), failMsg,
+ "failure");
+ throw new TPSException(auditMsg);
+ }
+ //update the tokendb with new certs
+ CMS.debug("TPSEnrollProcessor.enroll: updating tokendb with certs.");
+ ArrayList<TPSCertRecord> certRecords = certsInfo.toTPSCertRecords(tokenRecord.getId(), tokenRecord.getUserID());
+ tps.tdb.tdbAddCertificatesForCUID(tokenRecord.getId(), certRecords);
+
+ auditMsg = "appletVersion=" + lastObjVer + "; tokenType =" + selectedTokenType + "; userid =" + userid;
+ if (renewed) {
+ tps.tdb.tdbActivity(ActivityDatabase.OP_RENEWAL, tokenRecord, session.getIpAddress(), auditMsg, "success");
+ } else {
+ tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg,
+ "success");
+ }
+
+ CMS.debug("TPSEnrollProcessor.enroll: leaving ...");
+
+ statusUpdate(100, "PROGRESS_DONE_ENROLLMENT");
+ }
+
+ private void writeFinalPKCS11ObjectToToken(PKCS11Obj pkcs11objx, AppletInfo ainfo, SecureChannel channel)
+ throws TPSException, IOException {
+ if (pkcs11objx == null || ainfo == null || channel == null) {
+ throw new TPSException("TPSErollProcessor.writeFinalPKCS11ObjectToToken: invalid input data!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ CMS.debug("TPSEnrollProcessor.writeFinalPKCS11ObjectToToken: entering...");
+
+ IConfigStore configStore = CMS.getConfigStore();
+
+ String compressConfig = "op." + currentTokenOperation + "." + selectedTokenType + "."
+ + "pkcs11obj.compress.enable";
+
+ CMS.debug("TPSEnrollProcessor.writeFinalPKCS11ObjectToToken: config to check: " + compressConfig);
+
+ boolean doCompress = false;
+
+ try {
+ doCompress = configStore.getBoolean(compressConfig, true);
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "TPSEnrollProcessor.writeFinalPKCS11ObjectToToken: internal error obtaining config value " + e);
+ }
+
+ CMS.debug("TPSEnrollProcessor.writeFinalPKCS11ObjectToToken: doCompress: " + doCompress);
+
+ TPSBuffer tokenData = null;
+
+ if (doCompress) {
+ tokenData = pkcs11objx.getCompressedData();
+
+ } else {
+ tokenData = pkcs11objx.getData();
+ }
+
+ if (tokenData.size() > ainfo.getTotalMem()) {
+
+ throw new TPSException(
+ "TPSEnrollProcessor.writeFinalPKCS11ObjectToToken: NOt enough memory to write certificates!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+
+ }
+
+ byte[] zobjectid = { (byte) 'z', (byte) '0', 0, 0 };
+ byte[] perms = { (byte) 0xff, (byte) 0xff, 0x40, 0x00, 0x40, 0x00 };
+ TPSBuffer zobjidBuf = new TPSBuffer(zobjectid);
+
+ channel.createObject(zobjidBuf, new TPSBuffer(perms), tokenData.size());
+
+ channel.writeObject(zobjidBuf, tokenData);
+
+ CMS.debug("TPSEnrollProcessor.writeFinalPKCS11ObjectToToken: leaving successfully ...");
+
+ }
+
+ private void checkAndAuthenticateUser(AppletInfo appletInfo, String tokenType) throws TPSException {
+ IAuthCredentials userCred;
+ IAuthToken authToken;
+ TokenRecord tokenRecord = getTokenRecord();
+ if (!isExternalReg) {
+ // authenticate per profile/tokenType configuration
+ String configName = TPSEngine.OP_ENROLL_PREFIX + "." + tokenType + ".auth.enable";
+ IConfigStore configStore = CMS.getConfigStore();
+
+ TPSSubsystem tps =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ //TPSSession session = getSession();
+ boolean isAuthRequired;
+ try {
+ CMS.debug("TPSEnrollProcessor.checkAndAuthenticateUser: getting config: " + configName);
+ isAuthRequired = configStore.getBoolean(configName, true);
+ } catch (EBaseException e) {
+ CMS.debug("TPSEnrollProcessor.checkAndAuthenticateUser: Internal Error obtaining mandatory config values. Error: "
+ + e);
+ throw new TPSException("TPS error getting config values from config store.",
+ TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+ }
+ if (isAuthRequired) {
+ try {
+ TPSAuthenticator userAuth =
+ getAuthentication(TPSEngine.OP_ENROLL_PREFIX, tokenType);
+ userCred = requestUserId(TPSEngine.ENROLL_OP, appletInfo.getCUIDhexString(), userAuth,
+ beginMsg.getExtensions());
+ userid = (String) userCred.get(userAuth.getAuthCredName());
+ CMS.debug("TPSEnrollProcessor.checkAndAuthenticateUser: userCred (attempted) userid=" + userid);
+ // initialize userid first for logging purposes in case authentication fails
+ tokenRecord.setUserID(userid);
+ authToken = authenticateUser(TPSEngine.ENROLL_OP, userAuth, userCred);
+ userid = authToken.getInString("userid");
+ tokenRecord.setUserID(userid);
+ CMS.debug("TPSEnrollProcessor.checkAndAuthenticateUser: auth passed: userid: "
+ + authToken.get("userid"));
+
+ } catch (Exception e) {
+ // all exceptions are considered login failure
+ CMS.debug("TPSEnrollProcessor.checkAndAuthenticateUser:: authentication exception thrown: " + e);
+ String msg = "TPS error user authentication failed:" + e;
+ tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), msg,
+ "failure");
+
+ throw new TPSException(msg,
+ TPSStatus.STATUS_ERROR_LOGIN);
+ }
+ } else {
+ throw new TPSException(
+ "TPSEnrollProcessor.checkAndAuthenticateUser: TPS enrollment must have authentication enabled.",
+ TPSStatus.STATUS_ERROR_LOGIN);
+
+ }
+
+ }
+ }
+
+ private void checkAndHandlePinReset(SecureChannel channel) throws TPSException, IOException {
+
+ CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset entering...");
+
+ if (channel == null) {
+ throw new TPSException("TPSEnrollProcessor.checkAndHandlePinReset: invalid input data!",
+ TPSStatus.STATUS_ERROR_TOKEN_RESET_PIN_FAILED);
+ }
+
+ IConfigStore configStore = CMS.getConfigStore();
+
+ String pinResetEnableConfig = "op." + currentTokenOperation + "." + selectedTokenType + "."
+ + TPSEngine.CFG_PIN_RESET_ENABLE;
+
+ CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset config to check: " + pinResetEnableConfig);
+
+ String minLenConfig = "op." + currentTokenOperation + "." + selectedTokenType + "."
+ + TPSEngine.CFG_PIN_RESET_MIN_LEN;
+
+ CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset config to check: " + minLenConfig);
+
+ String maxLenConfig = "op." + currentTokenOperation + "." + selectedTokenType + "."
+ + TPSEngine.CFG_PIN_RESET_MAX_LEN;
+
+ CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset config to check: " + maxLenConfig);
+
+ String maxRetriesConfig = "op." + currentTokenOperation + "." + selectedTokenType + "."
+ + TPSEngine.CFG_PIN_RESET_MAX_RETRIES;
+
+ CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset config to check: " + maxRetriesConfig);
+
+ String pinStringConfig = TPSEngine.CFG_PIN_RESET_STRING;
+
+ CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset config to check: " + pinStringConfig);
+
+ boolean enabled = false;
+ int minLen;
+ int maxLen;
+ int maxRetries;
+ String stringName;
+
+ try {
+
+ enabled = configStore.getBoolean(pinResetEnableConfig, true);
+
+ if (enabled == false) {
+ CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset: Pin Reset not allowed by configuration, exiting...");
+ return;
+
+ }
+
+ minLen = configStore.getInteger(minLenConfig, 4);
+ maxLen = configStore.getInteger(maxLenConfig, 10);
+ maxRetries = configStore.getInteger(maxRetriesConfig, 0x7f);
+ stringName = configStore.getString(pinStringConfig, "password");
+
+ CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset: config vals: enabled: " + enabled + " minLen: "
+ + minLen + " maxLen: " + maxLen);
+
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "TPSEnrollProcessor.checkAndHandlePinReset: internal error in getting value from config.");
+ }
+
+ String new_pin = requestNewPin(minLen, maxLen);
+
+ channel.createPin(0x0, maxRetries, stringName);
+
+ channel.resetPin(0x0, new_pin);
+
+ }
+
+ private void checkAndUpgradeApplet(AppletInfo appletInfo) throws TPSException, IOException {
+ // TODO Auto-generated method stub
+
+ CMS.debug("checkAndUpgradeApplet: entering..");
+
+ SecurityLevel securityLevel = SecurityLevel.SECURE_MSG_MAC;
+
+ boolean useEncryption = checkUpdateAppletEncryption();
+
+ String tksConnId = getTKSConnectorID();
+ if (useEncryption)
+ securityLevel = SecurityLevel.SECURE_MSG_MAC_ENC;
+
+ if (checkForAppletUpdateEnabled()) {
+
+ String targetAppletVersion = checkForAppletUpgrade("op." + currentTokenOperation);
+ targetAppletVersion = targetAppletVersion.toLowerCase();
+
+ String currentAppletVersion = formatCurrentAppletVersion(appletInfo);
+
+ CMS.debug("TPSEnrollProcessor.checkAndUpgradeApplet: currentAppletVersion: " + currentAppletVersion
+ + " targetAppletVersion: " + targetAppletVersion);
+
+ if (targetAppletVersion.compareTo(currentAppletVersion) != 0) {
+
+ CMS.debug("TPSEnrollProessor.checkAndUpgradeApplet: Upgrading applet to : " + targetAppletVersion);
+ upgradeApplet("op." + currentTokenOperation, targetAppletVersion, securityLevel, getBeginMessage()
+ .getExtensions(),
+ tksConnId, 5, 12);
+ } else {
+ CMS.debug("TPSEnrollProcessor.checkAndUpgradeApplet: applet already at correct version.");
+ }
+ }
+
+ }
+
+ protected boolean checkUpdateAppletEncryption() throws TPSException {
+
+ CMS.debug("TPSEnrollProcessor.checkUpdateAppletEncryption entering...");
+
+ IConfigStore configStore = CMS.getConfigStore();
+
+ String appletEncryptionConfig = "op." + currentTokenOperation + "." + selectedTokenType + "."
+ + TPSEngine.CFG_UPDATE_APPLET_ENCRYPTION;
+
+ CMS.debug("TPSEnrollProcessor.checkUpdateAppletEncryption config to check: " + appletEncryptionConfig);
+
+ boolean appletEncryption = false;
+
+ try {
+ appletEncryption = configStore.getBoolean(appletEncryptionConfig, false);
+ } catch (EBaseException e) {
+ //Default TPSException will return a "contact admin" error code.
+ throw new TPSException(
+ "TPSEnrollProcessor.checkUpdateAppletEncryption: internal error in getting value from config.");
+ }
+
+ CMS.debug("TPSEnrollProcessor.checkUpdateAppletEncryption returning: " + appletEncryption);
+ return appletEncryption;
+
+ }
+
+ private PKCS11Obj getCurrentObjectsOnToken(SecureChannel channel) throws TPSException, IOException,
+ DataFormatException {
+
+ byte seq = 0;
+
+ TPSBuffer objects = null;
+
+ int lastFormatVersion = 0x0100;
+ int lastObjectVersion;
+ Random randomGenerator = new Random();
+
+ lastObjectVersion = randomGenerator.nextInt(1000);
+
+ CMS.debug("PKCS11Obj.getCurrentObjectsOnToken: Random lastObjectVersion: " + lastObjectVersion);
+
+ PKCS11Obj pkcs11objx = new PKCS11Obj();
+ pkcs11objx.setOldFormatVersion(lastFormatVersion);
+ pkcs11objx.setOldObjectVersion(lastObjectVersion);
+
+ do {
+
+ objects = listObjects(seq);
+
+ if (objects != null) {
+ CMS.debug("PKCS11Obj.getCurrentObjectsOnToken: objects: " + objects.toHexString());
+ }
+
+ if (objects == null) {
+ pkcs11objx.setOldObjectVersion(lastObjectVersion);
+ seq = 0;
+ } else {
+ seq = 1; // get next entry
+
+ TPSBuffer objectID = objects.substr(0, 4);
+ TPSBuffer objectLen = objects.substr(4, 4);
+
+ long objectIDVal = objectID.getLongFrom4Bytes(0);
+
+ long objectLenVal = objectLen.getLongFrom4Bytes(0);
+
+ TPSBuffer obj = channel.readObject(objectID, 0, (int) objectLenVal);
+
+ if (obj != null) {
+ CMS.debug("PKCS11Obj.getCurrentObjectsOnToken: obj: " + obj.toHexString());
+ }
+
+ if ((char) objectID.at(0) == (byte) 'z' && objectID.at(1) == (byte) '0') {
+ lastFormatVersion = obj.getIntFrom2Bytes(0);
+ lastObjectVersion = obj.getIntFrom2Bytes(2);
+
+ CMS.debug("PKCS11Obj.getCurrentObjectsOnToken: Versions read from token: lastFormatVersion : "
+ + lastFormatVersion
+ + " lastObjectVersion: " + lastObjectVersion);
+
+ pkcs11objx = PKCS11Obj.parse(obj, 0);
+
+ pkcs11objx.setOldFormatVersion(lastFormatVersion);
+ pkcs11objx.setOldObjectVersion(lastObjectVersion);
+ seq = 0;
+
+ } else {
+ ObjectSpec objSpec = ObjectSpec.parseFromTokenData(objectIDVal, obj);
+ pkcs11objx.addObjectSpec(objSpec);
+ }
+
+ CMS.debug("TPSEnrollProcessor.getCurrentObjectsOnToken. just read object from token: "
+ + obj.toHexString());
+ }
+
+ } while (seq != 0);
+
+ return pkcs11objx;
+ }
+
+ /*
+ * generateCertsAfterRenewalRecoveryPolicy determines whether a renewal or recovery is needed;
+ * if recovery is needed, it determines which certificates (from which old token)
+ * to recover onto the new token.
+ *
+ * Note: renewal and recovery are invoked in this method; However, if a new enrollment is determined
+ * to be the proper course of action, it is done after this method.
+ */
+ private TPSStatus generateCertsAfterRenewalRecoveryPolicy(EnrolledCertsInfo certsInfo, SecureChannel channel,
+ AppletInfo aInfo)
+ throws TPSException, IOException {
+ TPSStatus status = TPSStatus.STATUS_NO_ERROR;
+ String auditMsg;
+ final String method = "TPSEnrollProcessor.generateCertsAfterRenewalRecoveryPolicy";
+ CMS.debug(method + ": begins");
+ TPSSubsystem tps =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ TPSTokenPolicy tokenPolicy = new TPSTokenPolicy(tps);
+
+ ArrayList<TokenRecord> tokenRecords = null;
+ try {
+ tokenRecords = tps.tdb.tdbFindTokenRecordsByUID(userid);
+ } catch (Exception e) {
+ // no existing record, means no "renewal" or "recovery" actions needed
+ auditMsg = "no token associated with user: " + userid;
+ CMS.debug(method + auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_INACTIVE_TOKEN_NOT_FOUND);
+ }
+ CMS.debug(method + " found " + tokenRecords.size() + " tokens for user:" + userid);
+ boolean isRecover = false;
+
+ TokenRecord lostToken = null;
+ for (TokenRecord tokenRecord : tokenRecords) {
+ CMS.debug(method + " token id:"
+ + tokenRecord.getId() + "; status="
+ + tokenRecord.getStatus());
+
+ //Is this the same token (current token)?
+ if (tokenRecord.getId().equals(aInfo.getCUIDhexStringPlain())) {
+ //same token
+ auditMsg = "found current token entry";
+ CMS.debug(method + ":" + auditMsg);
+ if (tokenRecord.getStatus().equals("uninitialized")) {
+ // this is the current token
+ if (tokenRecords.size() == 1) {
+ // the current token is the only token owned by the user
+ CMS.debug(method + ": need to do enrollment");
+ // need to do enrollment outside
+ break;
+ } else {
+ CMS.debug(method + ": There are multiple token entries for user "
+ + userid);
+ try {
+ // this is assuming that the user can only have one single active token
+ // TODO: for future, maybe should allow multiple active tokens
+ tps.tdb.tdbHasActiveToken(userid);
+
+ } catch (Exception e1) {
+ /*
+ * user has no active token, need to find a token to recover from
+ * there are no other active tokens for this user
+ */
+ isRecover = true;
+ continue; // TODO: or break?
+ }
+ auditMsg = method + ": user already has an active token";
+ CMS.debug(auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_HAS_AT_LEAST_ONE_ACTIVE_TOKEN);
+ }
+ } else if (tokenRecord.getStatus().equals("active")) {
+ // current token is already active; renew if allowed
+ if (tokenPolicy.isAllowdTokenRenew(aInfo.getCUIDhexStringPlain())) {
+ return processRenewal(certsInfo, channel, aInfo, tokenRecord);
+ } else {
+ auditMsg = "token is already active; can't renew because renewal is not allowed; will re-enroll if allowed";
+ CMS.debug(method + ":" + auditMsg);
+ }
+ break;
+ } else if (tokenRecord.getStatus().equals("terminated")) {
+ auditMsg = "terminated token cuid="
+ + aInfo.getCUIDhexStringPlain() + " cannot be reused";
+ CMS.debug(method + ":" + auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_CONTACT_ADMIN);
+ } else if (tokenRecord.getStatus().equals("lost")) {
+ String reasonStr = tokenRecord.getReason();
+ if (reasonStr.equals("keyCompromise")) {
+ auditMsg = "This token cannot be reused because it has been reported lost";
+ CMS.debug(method + ": "
+ + auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_UNUSABLE_TOKEN_KEYCOMPROMISE);
+ } else if (reasonStr.equals("onHold")) {
+ try {
+ tps.tdb.tdbHasActiveToken(userid);
+ auditMsg = "user already has an active token";
+ CMS.debug(method + ": "
+ + auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_HAS_AT_LEAST_ONE_ACTIVE_TOKEN);
+ } catch (Exception e2) {
+ auditMsg = "User needs to contact administrator to report lost token (it should be put on Hold).";
+ CMS.debug(method + ": "
+ + auditMsg);
+ break;
+ }
+ } else if (reasonStr.equals("destroyed")) {
+ auditMsg = "This destroyed lost case should not be executed because the token is so damaged. It should not get here";
+ CMS.debug(method + ": "
+ + auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_TOKEN_DISABLED);
+ } else {
+ auditMsg = "No such lost reason: " + reasonStr + " for this cuid: "
+ + aInfo.getCUIDhexStringPlain();
+ CMS.debug(method + ":" + auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_NO_SUCH_LOST_REASON);
+ }
+
+ } else {
+ auditMsg = "No such token status for this cuid=" + aInfo.getCUIDhexStringPlain();
+ CMS.debug(method + ":" + auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_NO_SUCH_TOKEN_STATE);
+ }
+ } else { //cuid != current token
+ auditMsg = "found token entry different from current token";
+ CMS.debug(method + ":" + auditMsg);
+ if (tokenRecord.getStatus().equals("lost")) {
+ //lostostToken keeps track of the latest token that's lost
+ //last one in the look should be the latest
+ lostToken = tokenRecord;
+ auditMsg = "found a lost token: cuid = " + tokenRecord.getId();
+ CMS.debug(method + ":" + auditMsg);
+ }
+ continue;
+ }
+ }
+
+ if (isRecover == true) { // this could be set in previous iteration
+ if (lostToken == null) {
+ auditMsg = "No lost token to be recovered; do enrollment";
+ CMS.debug(method + ":" + auditMsg);
+ //shouldn't even get here; But if we do, just enroll
+ } else {
+ String reasonStr = lostToken.getReason();
+ //RevocationReason reason = RevocationReason.valueOf(reasonStr);
+ auditMsg = "isRecover true; reasonStr =" + reasonStr;
+ CMS.debug(method + ":" + auditMsg);
+
+ if (reasonStr.equals("keyCompromise")) {
+ return processRecovery(lostToken, certsInfo, channel, aInfo);
+ } else if (reasonStr.equals("onHold")) {
+ /*
+ * the inactive one becomes the temp token
+ * No recovery scheme, basically we are going to
+ * do the brand new enrollment
+ *
+ *
+ */
+
+ // ToDo: This section has not been tested to work.. Make sure this works.
+
+ IConfigStore configStore = CMS.getConfigStore();
+ String configName = TPSEngine.OP_ENROLL_PREFIX + "." + getSelectedTokenType()
+ + ".temporaryToken.tokenType";
+ try {
+ String tmpTokenType = configStore.getString(configName);
+ setSelectedTokenType(tmpTokenType);
+ } catch (EPropertyNotFound e) {
+ auditMsg = " configuration " + configName + " not found";
+ CMS.debug(method + ":" + auditMsg);
+ throw new TPSException(method + ":" + auditMsg);
+ } catch (EBaseException e) {
+ auditMsg = " configuration " + configName + " not found";
+ CMS.debug(method + ":" + auditMsg);
+ throw new TPSException(method + ":" + auditMsg);
+ }
+ return processRecovery(lostToken, certsInfo, channel, aInfo);
+
+ } else if (reasonStr.equals("destroyed")) {
+ return processRecovery(lostToken, certsInfo, channel, aInfo);
+ } else {
+ auditMsg = "No such lost reason: " + reasonStr + " for this cuid: " + aInfo.getCUIDhexStringPlain();
+ CMS.debug(method + ":" + auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_NO_SUCH_LOST_REASON);
+ }
+ }
+ }
+
+ CMS.debug(method + ": ends");
+ return status;
+ }
+
+ /*
+ * Renewal logic
+ * 1. Create Optional local TPS grace period per token profile,
+ * per token type, such as signing or encryption.
+ * This grace period must match how the CA is configured. Ex:
+ * op.enroll.userKey.renewal.encryption.enable=true
+ * op.enroll.userKey.renewal.encryption.gracePeriod.enable=true
+ * op.enroll.userKey.renewal.encryption.gracePeriod.before=30
+ * op.enroll.userKey.renewal.encryption.gracePeriod.after=30
+ * 2. In case of a grace period failure the code will go on
+ * and attempt to renew the next certificate in the list.
+ * 3. In case of any other code failure, the code will abort
+ * and leave the token untouched, while informing the user
+ * with an error message.
+ *
+ */
+ private TPSStatus processRenewal(EnrolledCertsInfo certsInfo, SecureChannel channel, AppletInfo aInfo,
+ TokenRecord tokenRecord)
+ throws TPSException, IOException {
+ TPSStatus status = TPSStatus.STATUS_ERROR_RENEWAL_FAILED;
+ String method = "TPSEnrollProcess.processRenewal";
+ String auditMsg;
+ CMS.debug(method + ": begins");
+
+ boolean noFailedCerts = true;
+
+ if (certsInfo == null || aInfo == null || channel == null) {
+ throw new TPSException(method + ": Bad Input data!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ TPSSubsystem tps =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ int keyTypeNum = getNumberCertsToRenew();
+ /*
+ * Get certs from the tokendb for this token to find out about
+ * renewal possibility
+ */
+ ArrayList<TPSCertRecord> allCerts = tps.tdb.tdbGetCertificatesByCUID(tokenRecord.getId());
+
+ certsInfo.setNumCertsToEnroll(keyTypeNum);
+
+ CMS.debug(method + ": Number of certs to renew: " + keyTypeNum);
+
+ for (int i = 0; i < keyTypeNum; i++) {
+ /*
+ * e.g. op.enroll.userKey.renewal.keyType.value.0=signing
+ * e.g. op.enroll.userKey.renewal.keyType.value.1=encryption
+ */
+ String keyType = getRenewConfigKeyType(i);
+ boolean renewEnabled = getRenewEnabled(keyType);
+ CMS.debug(method + ": key type " + keyType);
+ if (!renewEnabled) {
+ CMS.debug(method + ": renew not enabled");
+ continue;
+ }
+
+ CMS.debug(method + ": renew enabled");
+
+ certsInfo.setCurrentCertIndex(i);
+
+ CertEnrollInfo cEnrollInfo = new CertEnrollInfo();
+ IConfigStore configStore = CMS.getConfigStore();
+
+ // find all config
+ String configName = null;
+ boolean graceEnabled = false;
+ String graceBeforeS = null;
+ String graceAfterS = null;
+ try {
+ String keyTypePrefix = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + ".renewal." + keyType;
+
+ //TODO: profileId is actually gotten in the CARemoteRequestHandler.
+ configName = keyTypePrefix + ".ca.profileId";
+ String profileId;
+ profileId = configStore.getString(configName);
+ CMS.debug(method + ": profileId: " + profileId);
+
+ configName = keyTypePrefix + ".gracePeriod.enable";
+ graceEnabled = configStore.getBoolean(configName, false);
+ if (graceEnabled) {
+ CMS.debug(method + ": grace period check is enabled");
+ configName = keyTypePrefix + ".gracePeriod.before";
+ graceBeforeS = configStore.getString(configName, "");
+ configName = keyTypePrefix + ".gracePeriod.after";
+ graceAfterS = configStore.getString(configName, "");
+ } else {
+ CMS.debug(method + ": grace period check is not enabled");
+ }
+
+ configName = keyTypePrefix + ".certId";
+ String certId = configStore.getString(configName, "C0");
+ CMS.debug(method + ": certId: " + certId);
+
+ configName = keyTypePrefix + ".certAttrId";
+ String certAttrId = configStore.getString(configName, "c0");
+ CMS.debug(method + ": certAttrId: " + certAttrId);
+
+ configName = keyTypePrefix + ".privateKeyAttrId";
+ String priKeyAttrId = configStore.getString(configName, "k0");
+ CMS.debug(method + ": privateKeyAttrId: " + priKeyAttrId);
+
+ configName = keyTypePrefix + ".publicKeyAttrId";
+ String publicKeyAttrId = configStore.getString(configName, "k1");
+ CMS.debug(method + ": publicKeyAttrId: " + publicKeyAttrId);
+
+ } catch (EBaseException e) {
+ throw new TPSException(method + ": Internal error finding config value: " + configName + ":"
+ + e,
+ TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+ }
+
+ // find the certs that match the keyType to renew
+ for (TPSCertRecord cert : allCerts) {
+ if (keyType.equals(cert.getKeyType())) {
+ try {
+ CMS.debug(method + ": cert " + cert.getId() + " with status:" + cert.getStatus());
+ if (cert.getStatus().equals("revoked") ||
+ cert.getStatus().equals("renewed")) {
+ CMS.debug(method + ": cert status is not to be renewed");
+ continue;
+ }
+
+ // check if within grace period to save us a trip (note: CA makes the final decision)
+ if (graceEnabled) {
+ try {
+ if (!isCertWithinRenewalGracePeriod(cert, graceBeforeS, graceAfterS))
+ continue;
+ } catch (TPSException ge) {
+ // error in this will just log and keep going
+ CMS.debug(method + ":" + ge + "; continue to try renewal");
+ }
+ }
+
+ //Renew and fetch the renewed cert blob.
+
+ CARenewCertResponse certResponse = tps.getEngine().renewCertificate(cert,
+ cert.getSerialNumber(), selectedTokenType, keyType, getCAConnectorID());
+ cEnrollInfo.setRenewedCertData(certResponse);
+
+ generateCertificate(certsInfo, channel, aInfo, keyType, TPSEngine.ENROLL_MODES.MODE_RENEWAL,
+ 0, cEnrollInfo);
+
+ //renewCertificate(cert, certsInfo, channel, aInfo, keyType);
+ status = TPSStatus.STATUS_ERROR_RENEWAL_IS_PROCESSED;
+ } catch (TPSException e) {
+ CMS.debug(method + "renewCertificate: exception:" + e);
+ noFailedCerts = false;
+ break; //need to clean up half-done token later
+ }
+ }
+ }
+ }
+
+ if (!noFailedCerts) {
+ // TODO: handle cleanup
+ auditMsg = "There has been failed cert renewal";
+ CMS.debug(method + ":" + auditMsg);
+ throw new TPSException(auditMsg + TPSStatus.STATUS_ERROR_RENEWAL_FAILED);
+ }
+ return status;
+ }
+
+ /*
+ * isCertWithinRenewalGracePeriod - check if a cert is within the renewal grace period
+ * @param cert the cert to be renewed
+ * @param renewGraceBeforeS string representation of the # of days "before" cert expiration date
+ * @param renewGraceAfterS string representation of the # of days "after" cert expiration date
+ */
+ private boolean isCertWithinRenewalGracePeriod(TPSCertRecord cert, String renewGraceBeforeS, String renewGraceAfterS)
+ throws TPSException {
+ String method = "TPSEnrollProcessor.isCertWithinRenewalGracePeriod";
+ int renewGraceBefore = 0;
+ int renewGraceAfter = 0;
+
+ if (cert == null || renewGraceBeforeS == null || renewGraceAfterS == null) {
+ CMS.debug(method + ": missing some input");
+ throw new TPSException(method + ": Bad Input data!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+ BigInteger renewGraceBeforeBI = new BigInteger(renewGraceBeforeS);
+ BigInteger renewGraceAfterBI = new BigInteger(renewGraceAfterS);
+
+ // -1 means no limit
+ if (renewGraceBeforeS == "")
+ renewGraceBefore = -1;
+ else
+ renewGraceBefore = Integer.parseInt(renewGraceBeforeS);
+
+ if (renewGraceAfterS == "")
+ renewGraceAfter = -1;
+ else
+ renewGraceAfter = Integer.parseInt(renewGraceAfterS);
+
+ if (renewGraceBefore > 0)
+ renewGraceBeforeBI = renewGraceBeforeBI.multiply(BigInteger.valueOf(1000 * 86400));
+ if (renewGraceAfter > 0)
+ renewGraceAfterBI = renewGraceAfterBI.multiply(BigInteger.valueOf(1000 * 86400));
+
+ Date origExpDate = cert.getValidNotAfter();
+ Date current = CMS.getCurrentDate();
+ long millisDiff = origExpDate.getTime() - current.getTime();
+ CMS.debug(method + ": millisDiff="
+ + millisDiff + " origExpDate=" + origExpDate.getTime() + " current=" + current.getTime());
+
+ /*
+ * "days", if positive, has to be less than renew_grace_before
+ * "days", if negative, means already past expiration date,
+ * (abs value) has to be less than renew_grace_after
+ * if renew_grace_before or renew_grace_after are negative
+ * the one with negative value is ignored
+ */
+ if (millisDiff >= 0) {
+ if ((renewGraceBefore > 0) && (millisDiff > renewGraceBeforeBI.longValue())) {
+ CMS.debug(method + ": renewal attempted outside of grace period;" +
+ renewGraceBefore + " days before and " +
+ renewGraceAfter + " days after original cert expiration date");
+ return false;
+ }
+ } else {
+ if ((renewGraceAfter > 0) && ((0 - millisDiff) > renewGraceAfterBI.longValue())) {
+ CMS.debug(method + ": renewal attempted outside of grace period;" +
+ renewGraceBefore + " days before and " +
+ renewGraceAfter + " days after original cert expiration date");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean getRenewEnabled(String keyType) {
+ String method = "TPSEnrollProcessor.getRenewEnabled";
+ IConfigStore configStore = CMS.getConfigStore();
+ boolean enabled = false;
+
+ try {
+ String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + ".renewal."
+ + keyType + "." + "enable";
+ enabled = configStore.getBoolean(
+ configValue, false);
+
+ } catch (EBaseException e) {
+ //default to false
+ }
+
+ CMS.debug(method + ": returning " + enabled);
+ return enabled;
+ }
+
+ private String getRenewConfigKeyType(int keyTypeIndex) throws TPSException {
+ String method = "TPSEnrollProcessor.getRenewConfigKeyType";
+ IConfigStore configStore = CMS.getConfigStore();
+ String keyType = null;
+
+ try {
+ String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "."
+ + TPSEngine.CFG_RENEW_KEYTYPE_VALUE + "." + keyTypeIndex;
+ keyType = configStore.getString(
+ configValue, null);
+
+ } catch (EBaseException e) {
+ throw new TPSException(
+ method + ": Internal error finding config value: " + e,
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ //We would really like one of these to exist
+ if (keyType == null) {
+ throw new TPSException(
+ method + ": Internal error finding config value: ",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ CMS.debug(method + ": returning: " + keyType);
+
+ return keyType;
+
+ }
+
+ private int getNumberCertsToRenew() throws TPSException {
+ String method = "TPSEnrollProcessor.getNumberCertsToRenew";
+
+ IConfigStore configStore = CMS.getConfigStore();
+ int keyTypeNum = 0;
+ try {
+ String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "."
+ + TPSEngine.CFG_RENEW_KEYTYPE_NUM;
+ keyTypeNum = configStore.getInteger(
+ configValue, 0);
+
+ } catch (EBaseException e) {
+ throw new TPSException(method + ": Internal error finding config value: "
+ + e,
+ TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+ }
+
+ if (keyTypeNum == 0) {
+ throw new TPSException(
+ method + ": invalid number of certificates to renew configured!",
+ TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+ }
+ CMS.debug(method + ": returning: " + keyTypeNum);
+
+ return keyTypeNum;
+ }
+
+ private TPSStatus processRecovery(TokenRecord toBeRecovered, EnrolledCertsInfo certsInfo, SecureChannel channel,
+ AppletInfo aInfo) throws TPSException, IOException {
+ String method = "TPSEnrollProcessor.processRecover";
+ String auditMsg;
+ TPSStatus status = TPSStatus.STATUS_ERROR_RECOVERY_IS_PROCESSED;
+
+ TPSSubsystem tps = (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ IConfigStore configStore = CMS.getConfigStore();
+
+ CMS.debug("TPSEnrollProcessor.processRecovery: entering:");
+
+ if (toBeRecovered == null || certsInfo == null || channel == null || aInfo == null) {
+ throw new TPSException("TPSEnrollProcessor.processRecovery: Invalid reason!",
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+
+ String reason = toBeRecovered.getReason();
+
+ int num = getNumberCertsForRecovery(reason);
+
+ int totalNumCerts = 0;
+
+ //We will have to rifle through the configuration to see if there any recovery operations with
+ //scheme "GenerateNewKeyandRecoverLast" which allows for recovering the old key AND generating a new
+ // one for the encryption type only. If this scheme is present, the number of certs for bump by
+ // 1 for each occurrence.
+
+ String keyTypeValue = null;
+ String scheme = null;
+ CMS.debug("TPSEnrollProcessor.processRecovery: About to find if we have any GenerateNewAndRecoverLast schemes.");
+ for (int i = 0; i < num; i++) {
+ keyTypeValue = getRecoveryKeyTypeValue(reason, i);
+ scheme = getRecoveryScheme(reason, keyTypeValue);
+
+ if (scheme.equals(TPSEngine.RECOVERY_SCHEME_GENERATE_NEW_KEY_AND_RECOVER_LAST)) {
+
+ //Make sure we are not signing:
+ if (keyTypeValue.equals(TPSEngine.CFG_SIGNING)) {
+ throw new TPSException(
+ "TPSEnrollProcessor.processRecovery: Can't have GenerateNewAndRecoverLast scheme with a signing key!",
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+ totalNumCerts++;
+ }
+ totalNumCerts++;
+ }
+
+ CMS.debug("TPSEnrollProcessor.processRecovery: About to perform actual recoveries: totalNumCerts: "
+ + totalNumCerts);
+
+ if (!(totalNumCerts > num)) {
+ totalNumCerts = num;
+ }
+
+ boolean isGenerateAndRecover = false;
+ int actualCertIndex = 0;
+ boolean legalScheme = false;
+
+ //Go through again and do the recoveries/enrollments
+
+ certsInfo.setNumCertsToEnroll(totalNumCerts);
+ for (int i = 0; i < num; i++) {
+
+ keyTypeValue = getRecoveryKeyTypeValue(reason, i);
+ scheme = getRecoveryScheme(reason, keyTypeValue);
+
+ if (scheme.equals(TPSEngine.RECOVERY_SCHEME_GENERATE_NEW_KEY_AND_RECOVER_LAST)) {
+ CMS.debug("TPSEnrollProcessor.processRecovery: scheme GenerateNewKeyAndRecoverLast found.");
+ isGenerateAndRecover = true;
+
+ } else {
+ isGenerateAndRecover = false;
+ }
+
+ if (scheme.equals(TPSEngine.RECOVERY_GENERATE_NEW_KEY) || isGenerateAndRecover) {
+ legalScheme = true;
+ CertEnrollInfo cEnrollInfo = new CertEnrollInfo();
+ generateCertificate(certsInfo, channel, aInfo, keyTypeValue, TPSEngine.ENROLL_MODES.MODE_ENROLL,
+ actualCertIndex, cEnrollInfo);
+
+ actualCertIndex = cEnrollInfo.getCertIdIndex();
+ CMS.debug("TPSEnrollProcessor.processRecovery: scheme GenerateNewKey found, or isGenerateAndRecove is true: actualCertIndex, after enrollment: "
+ + actualCertIndex);
+
+ }
+
+ if (scheme.equals(TPSEngine.RECOVERY_RECOVER_LAST) || isGenerateAndRecover) {
+ legalScheme = true;
+ CMS.debug("TPSEnrollProcessor.processRecovery: scheme RecoverLast found, or isGenerateAndRecove is true");
+ if (isGenerateAndRecover) {
+ CMS.debug("TPSEnrollProcessor.processRecovery: isGenerateAndRecover is true.");
+ actualCertIndex++;
+ }
+
+ ArrayList<TPSCertRecord> certs = tps.tdb.tdbGetCertificatesByCUID(toBeRecovered.getId());
+
+ String serialToRecover = null;
+ TPSCertRecord certToRecover = null;
+ for (TPSCertRecord rec : certs) {
+
+ //Just take the end of the list most recent cert of given type.
+ CMS.debug("TPSEnrollProcessor.processRecovery: Looking for keyType record: " + keyTypeValue
+ + " curSererial: " + rec.getSerialNumber());
+
+ if (rec.getKeyType().equals(keyTypeValue)) {
+ serialToRecover = rec.getSerialNumber();
+ certToRecover = rec;
+ CMS.debug("TPSCertRecord: serial number: " + serialToRecover);
+ }
+
+ }
+ String b64cert = null;
+ if (serialToRecover != null) {
+ // get recovery conn id
+ String caConnId;
+ String config = "op.enroll." + certToRecover.getType() + ".keyGen." + certToRecover.getKeyType() + ".ca.conn";
+ try {
+ caConnId = configStore.getString(config);
+ } catch (Exception e) {
+ auditMsg = "cannot find config:" + config;
+ CMS.debug(method + ":" + auditMsg);
+ throw new TPSException(
+ method + ":" + auditMsg,
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+ CMS.debug("TPSEnrollProcessor.processRecovery: Selecting cert to recover: " + serialToRecover);
+
+ CARetrieveCertResponse certResponse = tps.getEngine().recoverCertificate(certToRecover,
+ serialToRecover, keyTypeValue, caConnId);
+
+ b64cert = certResponse.getCertB64();
+ CMS.debug("TPSEnrollProcessor.processRecovery: recoverd cert blob: " + b64cert);
+
+ KRARecoverKeyResponse keyResponse = tps.getEngine().recoverKey(toBeRecovered.getId(),
+ toBeRecovered.getUserID(),
+ channel.getDRMWrappedDesKey(), b64cert, getDRMConnectorID());
+
+ CertEnrollInfo cEnrollInfo = new CertEnrollInfo();
+
+ cEnrollInfo.setTokenToBeRecovered(toBeRecovered);
+ cEnrollInfo.setRecoveredCertData(certResponse);
+ cEnrollInfo.setRecoveredKeyData(keyResponse);
+
+ generateCertificate(certsInfo, channel, aInfo, keyTypeValue, TPSEngine.ENROLL_MODES.MODE_RECOVERY,
+ actualCertIndex, cEnrollInfo);
+
+ // unrevoke cert if needed
+ if (certToRecover.getStatus().equalsIgnoreCase("revoked_on_hold")) {
+ auditMsg = "unrevoking cert...";
+ CMS.debug(method + ":" + auditMsg);
+
+ CARemoteRequestHandler caRH = null;
+ try {
+ caRH = new CARemoteRequestHandler(caConnId);
+
+ CARevokeCertResponse response =
+ caRH.revokeCertificate(false /*unrevoke*/, serialToRecover,
+ certToRecover.getCertificate(),
+ null);
+ CMS.debug(method + ": response status =" + response.getStatus());
+
+ } catch (EBaseException e) {
+ auditMsg = "failed getting CARemoteRequestHandler";
+ CMS.debug(method + ":" + auditMsg);
+ throw new TPSException(method + ":" + auditMsg, TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+ }
+
+ // set cert status to active
+ certToRecover.setStatus("active");
+ try {
+ tps.tdb.tdbUpdateCertEntry(certToRecover);
+ } catch (Exception e) {
+ auditMsg = "failed tdbUpdateCertEntry";
+ CMS.debug(method + ":" + auditMsg);
+ throw new TPSException(method + ":" + auditMsg, TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+ } else {
+
+ }
+
+ }
+
+ if (!legalScheme) {
+ throw new TPSException("TPSEnrollProcessor.processRecovery: Invalid recovery configuration!",
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+ actualCertIndex++;
+
+ }
+
+ return status;
+ }
+
+ //Stub to generate a certificate, more to come
+ private boolean generateCertificates(EnrolledCertsInfo certsInfo, SecureChannel channel, AppletInfo aInfo)
+ throws TPSException, IOException {
+
+ CMS.debug("TPSEnrollProcess.generateCertificates: begins ");
+ boolean noFailedCerts = true;
+
+ if (certsInfo == null || aInfo == null || channel == null) {
+ throw new TPSException("TPSEnrollProcessor.generateCertificates: Bad Input data!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ int keyTypeNum = getNumberCertsToEnroll();
+
+ certsInfo.setNumCertsToEnroll(keyTypeNum);
+
+ CMS.debug("TPSEnrollProcessor.generateCertificate: Number of certs to enroll: " + keyTypeNum);
+
+ for (int i = 0; i < keyTypeNum; i++) {
+ String keyType = getConfiguredKeyType(i);
+ certsInfo.setCurrentCertIndex(i);
+ try {
+ generateCertificate(certsInfo, channel, aInfo, keyType, TPSEngine.ENROLL_MODES.MODE_ENROLL, 0, null);
+ } catch (TPSException e) {
+ CMS.debug("TPSEnrollProcessor.generateCertificate: exception:" + e);
+ noFailedCerts = false;
+ break; //need to clean up half-done token later
+ }
+ }
+
+ /*
+ * In this special case of RE_ENROLL, Revoke current certs for this token
+ * if so configured
+ */
+ /*TODO: format that follows should do this already based on the returned noFailedCerts value
+ if (noFailedCerts == true) {
+ revokeCertificates(aInfo.getCUIDhexStringPlain());
+ }
+ */
+
+ CMS.debug("TPSEnrollProcessor.generateCertificates: ends ");
+ return noFailedCerts;
+ }
+
+ private String buildTokenLabel(EnrolledCertsInfo certsInfo, AppletInfo ainfo) throws TPSException {
+ String label = null;
+
+ if (certsInfo == null || ainfo == null) {
+ throw new TPSException("TPSEnrollProcessor.buildTokenLabel: invalide input data!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ CMS.debug("TPSEnrollProcessor.buildTokenLabel: entering...");
+
+ IConfigStore configStore = CMS.getConfigStore();
+
+ String configName = TPSEngine.OP_ENROLL_PREFIX + "." + getSelectedTokenType() + ".keyGen.tokenName";
+ String pattern = null;
+
+ try {
+ pattern = configStore.getString(configName, "$cuid$");
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "TPSEnrollProcessor.buildTokenLabel: Internal error finding config value: " + e,
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+
+ }
+
+ CMS.debug("TPSEnrollProcessor.buildTokenLabel: pattern: " + pattern);
+
+ Map<String, String> nv = new LinkedHashMap<String, String>();
+
+ nv.put("cuid", ainfo.getCUIDhexString());
+ nv.put("msn", ainfo.getMSNString());
+ nv.put("userid", userid);
+ nv.put("auth.cn", userid);
+ nv.put("profileId", getSelectedTokenType());
+
+ label = mapPattern((LinkedHashMap<String, String>) nv, pattern);
+
+ CMS.debug("TPSEnrollProcessor.buildTokenLabel: returning: " + label);
+
+ return label;
+
+ }
+
+ /* This routine will be able to handle:
+ * regular enrollment
+ * recovery enrollment
+ * renewal enrollment
+ */
+ private void generateCertificate(EnrolledCertsInfo certsInfo, SecureChannel channel, AppletInfo aInfo,
+ String keyType, TPSEngine.ENROLL_MODES mode, int certIdNumOverride, CertEnrollInfo cEnrollInfo)
+ throws TPSException, IOException {
+
+ CMS.debug("TPSEnrollProcessor.generateCertificate: entering ... certIdNumOverride: " + certIdNumOverride
+ + " mode: " + mode);
+
+ if (certsInfo == null || aInfo == null || channel == null || aInfo == null) {
+ throw new TPSException("TPSEnrollProcessor.generateCertificate: Bad Input data!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ //get the params needed all at once
+
+ IConfigStore configStore = CMS.getConfigStore();
+
+ boolean isRenewal = false;
+
+ // This operation modifier allows us to get config entries for either
+ // regular enrollment and renewal. Allows the re-use of repetitive config processing code below.
+ String operationModifier = "keyGen";
+ if (mode == ENROLL_MODES.MODE_RENEWAL) {
+ isRenewal = true;
+ operationModifier = "renewal";
+ }
+
+ if (cEnrollInfo == null)
+ cEnrollInfo = new CertEnrollInfo();
+
+ try {
+
+ String keyTypePrefix = TPSEngine.OP_ENROLL_PREFIX + "." + getSelectedTokenType() + "." + operationModifier
+ + "." + keyType;
+ CMS.debug("TPSEnrollProcessor.generateCertificate: keyTypePrefix: " + keyTypePrefix);
+
+ String configName = keyTypePrefix + ".ca.profileId";
+ String profileId = configStore.getString(configName);
+ CMS.debug("TPSEnrollProcessor.generateCertificate: profileId: " + profileId);
+
+ configName = keyTypePrefix + ".certId";
+ String certId = configStore.getString(configName, "C0");
+ CMS.debug("TPSEnrollProcessor.generateCertificate: certId: " + certId);
+
+ configName = keyTypePrefix + ".certAttrId";
+ String certAttrId = configStore.getString(configName, "c0");
+ CMS.debug("TPSEnrollProcessor.generateCertificate: certAttrId: " + certAttrId);
+
+ configName = keyTypePrefix + ".privateKeyAttrId";
+ String priKeyAttrId = configStore.getString(configName, "k0");
+ CMS.debug("TPSEnrollProcessor.generateCertificate: priKeyAttrId: " + priKeyAttrId);
+
+ configName = keyTypePrefix + ".publicKeyAttrId";
+ String publicKeyAttrId = configStore.getString(configName, "k1");
+ CMS.debug("TPSEnrollProcessor.generateCertificate: publicKeyAttrId: " + publicKeyAttrId);
+
+ configName = keyTypePrefix + ".keySize";
+ int keySize = configStore.getInteger(configName, 1024);
+ CMS.debug("TPSEnrollProcessor.generateCertificate: keySize: " + keySize);
+
+ //Default RSA_CRT=2
+ configName = keyTypePrefix + ".alg";
+ int algorithm = configStore.getInteger(configName, 2);
+ CMS.debug("TPSEnrollProcessor.generateCertificate: algorithm: " + algorithm);
+
+ configName = keyTypePrefix + ".publisherId";
+ String publisherId = configStore.getString(configName, "");
+ CMS.debug("TPSEnrollProcessor.generateCertificate: publisherId: " + publisherId);
+
+ configName = keyTypePrefix + ".keyUsage";
+ int keyUsage = configStore.getInteger(configName, 0);
+ CMS.debug("TPSEnrollProcessor.generateCertificate: keyUsage: " + keyUsage);
+
+ configName = keyTypePrefix + ".keyUser";
+ int keyUser = configStore.getInteger(configName, 0);
+ CMS.debug("TPSEnrollProcessor.generateCertificate: keyUser: " + keyUser);
+
+ configName = keyTypePrefix + ".privateKeyNumber";
+ int priKeyNumber = configStore.getInteger(configName, 0);
+ CMS.debug("TPSEnrollProcessor.generateCertificate: privateKeyNumber: " + priKeyNumber);
+
+ configName = keyTypePrefix + ".publicKeyNumber";
+ int pubKeyNumber = configStore.getInteger(configName, 0);
+ CMS.debug("TPSEnrollProcessor.generateCertificate: pubKeyNumber: " + pubKeyNumber);
+
+ // get key capabilites to determine if the key type is SIGNING,
+ // ENCRYPTION, or SIGNING_AND_ENCRYPTION
+
+ configName = keyTypePrefix + ".private.keyCapabilities.sign";
+ boolean isSigning = configStore.getBoolean(configName, false);
+ CMS.debug("TPSEnrollProcessor.generateCertificate: isSigning: " + isSigning);
+
+ configName = keyTypePrefix + ".public.keyCapabilities.encrypt";
+ CMS.debug("TPSEnrollProcessor.generateCertificate: encrypt config name: " + configName);
+ boolean isEncrypt = configStore.getBoolean(configName, true);
+ CMS.debug("TPSEnrollProcessor.generateCertificate: isEncrypt: " + isEncrypt);
+
+ TokenKeyType keyTypeEnum;
+
+ if (isSigning && isEncrypt) {
+ keyTypeEnum = TokenKeyType.KEY_TYPE_SIGNING_AND_ENCRYPTION;
+ } else if (isSigning) {
+ keyTypeEnum = TokenKeyType.KEY_TYPE_SIGNING;
+ } else if (isEncrypt) {
+ keyTypeEnum = TokenKeyType.KEY_TYPE_ENCRYPTION;
+ } else {
+ CMS.debug("TPSEnrollProcessor.generateCertificate: Illegal toke key type!");
+ throw new TPSException("TPSEnrollProcessor.generateCertificate: Illegal toke key type!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ CMS.debug("TPSEnrollProcessor.generateCertificate: keyTypeEnum value: " + keyTypeEnum);
+
+ // The certIdNumOverride allows us to place the certs and keys into a different slot.
+ // Thus overriding what is found in the config.
+ // Used in recovery mostly up to this point.
+
+ if (certIdNumOverride > 0) {
+ CMS.debug("TPSEnrollProcessor.generateCertificate: called with overridden cert id number: "
+ + certIdNumOverride);
+
+ pubKeyNumber = 2 * certIdNumOverride + 1;
+ priKeyNumber = 2 * certIdNumOverride;
+
+ certId = "C" + certIdNumOverride;
+ certAttrId = "c" + certIdNumOverride;
+ priKeyAttrId = "k" + priKeyNumber;
+ publicKeyAttrId = "k" + pubKeyNumber;
+
+ CMS.debug("TPSEnrollProcessor.generateCertificate: called with overridden cert no: certId: " + certId
+ + " certAttrId: " + certAttrId + " priKeyAttrId: " + priKeyAttrId + " publicKeyAttrId: "
+ + publicKeyAttrId);
+
+ }
+
+ cEnrollInfo.setKeyTypeEnum(keyTypeEnum);
+ cEnrollInfo.setProfileId(profileId);
+ cEnrollInfo.setCertId(certId);
+ cEnrollInfo.setCertAttrId(certAttrId);
+
+ // These setting are key related and have no meaning in renewal.
+ if (isRenewal == false) {
+ cEnrollInfo.setPrivateKeyAttrId(priKeyAttrId);
+ cEnrollInfo.setPublicKeyAttrId(publicKeyAttrId);
+ cEnrollInfo.setKeySize(keySize);
+ cEnrollInfo.setAlgorithm(algorithm);
+ cEnrollInfo.setPublisherId(publisherId);
+ cEnrollInfo.setKeyUsage(keyUsage);
+ cEnrollInfo.setKeyUser(keyUser);
+ cEnrollInfo.setPrivateKeyNumber(priKeyNumber);
+ cEnrollInfo.setPublicKeyNumber(pubKeyNumber);
+ cEnrollInfo.setKeyType(keyType);
+ cEnrollInfo.setKeyTypePrefix(keyTypePrefix);
+ }
+
+ int certsStartProgress = certsInfo.getStartProgressValue();
+ int certsEndProgress = certsInfo.getEndProgressValue();
+ int currentCertIndex = certsInfo.getCurrentCertIndex();
+ int totalNumCerts = certsInfo.getNumCertsToEnroll();
+
+ int progressBlock = (certsEndProgress - certsStartProgress) / totalNumCerts;
+
+ int startCertProgValue = certsStartProgress + currentCertIndex * progressBlock;
+
+ int endCertProgValue = startCertProgValue + progressBlock;
+
+ cEnrollInfo.setStartProgressValue(startCertProgValue);
+ cEnrollInfo.setEndProgressValue(endCertProgValue);
+
+ } catch (EBaseException e) {
+
+ throw new TPSException(
+ "TPSEnrollProcessor.generateCertificate: Internal error finding config value: " + e,
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ enrollOneCertificate(certsInfo, cEnrollInfo, aInfo, channel, mode);
+
+ }
+
+ /* Core method handles the following modes:
+ * Regular enrollment
+ * Recovery enrollment
+ * Renewal enrollment
+ */
+ private void enrollOneCertificate(EnrolledCertsInfo certsInfo, CertEnrollInfo cEnrollInfo, AppletInfo aInfo,
+ SecureChannel channel, TPSEngine.ENROLL_MODES mode)
+ throws TPSException, IOException {
+
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate: entering ... mode: " + mode);
+
+ if (certsInfo == null || aInfo == null || cEnrollInfo == null || channel == null) {
+ throw new TPSException("TPSEnrollProcessor.enrollOneCertificate: Bad Input data!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ statusUpdate(cEnrollInfo.getStartProgressValue(), "PROGRESS_KEY_GENERATION");
+ boolean serverSideKeyGen = checkForServerSideKeyGen(cEnrollInfo);
+ boolean objectOverwrite = checkForObjectOverwrite(cEnrollInfo);
+
+ PKCS11Obj pkcs11obj = certsInfo.getPKCS11Obj();
+
+ int keyAlg = cEnrollInfo.getAlgorithm();
+
+ boolean isECC = getTPSEngine().isAlgorithmECC(keyAlg);
+
+ if (objectOverwrite) {
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate: We are configured to overwrite existing cert objects.");
+
+ } else {
+
+ boolean certIdExists = pkcs11obj.doesCertIdExist(cEnrollInfo.getCertId());
+
+ //Bomb out if cert exists, we ca't overwrite
+
+ if (certIdExists) {
+ throw new TPSException(
+ "TPSEnrollProcessor.enrollOneCertificate: Overwrite of certificates not allowed!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ }
+
+ TPSBuffer public_key_blob = null;
+ KRAServerSideKeyGenResponse ssKeyGenResponse = null;
+ KRARecoverKeyResponse keyResp = null;
+ RSAPublicKey parsedPubKey = null;
+ PK11PubKey parsedPK11PubKey = null;
+ byte[] parsedPubKey_ba = null;
+
+ boolean isRecovery = false;
+ boolean isRenewal = false;
+
+ if (mode == ENROLL_MODES.MODE_RECOVERY) {
+ isRecovery = true;
+
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate: detecting recovery mode!");
+ if (isRecovery && !serverSideKeyGen) {
+ throw new TPSException(
+ "TPSEnrollProcessor.enrollOneCertificate: Attempting illegal recovery when archival is not enabled!",
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+ }
+
+ if (mode == ENROLL_MODES.MODE_RENEWAL) {
+ isRenewal = true;
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate: detecting renewal mode!");
+ }
+
+ if (serverSideKeyGen || isRecovery) {
+ //Handle server side keyGen/recovery
+ // The main difference is where the key and cert data is obtained.
+ // In recovery the cert and key are recovered.
+ // In server side key gen, cert is enrolled and key is generated and recovered.
+
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate: either generate private key on the server, or preform recovery or perform renewal.");
+ boolean archive = checkForServerKeyArchival(cEnrollInfo);
+ String drmConnId = getDRMConnectorID();
+
+ String publicKeyStr = null;
+ //Do this for JUST server side keygen
+ if (isRecovery == false) {
+ ssKeyGenResponse = getTPSEngine()
+ .serverSideKeyGen(cEnrollInfo.getKeySize(),
+ aInfo.getCUIDhexStringPlain(), userid, drmConnId, channel.getDRMWrappedDesKey(),
+ archive, isECC);
+
+ publicKeyStr = ssKeyGenResponse.getPublicKey();
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate: public key string from server: " + publicKeyStr);
+ public_key_blob = new TPSBuffer(Utils.base64decode(publicKeyStr));
+
+ } else {
+ //Here we have a recovery, get the key data from the CertInfo object
+
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate: Attempt to get key data in recovery mode!");
+ keyResp = cEnrollInfo.getRecoveredKeyData();
+
+ publicKeyStr = keyResp.getPublicKey();
+ public_key_blob = new TPSBuffer(Utils.base64decode(publicKeyStr));
+
+ }
+
+ try {
+ parsedPK11PubKey = PK11RSAPublicKey.fromSPKI(public_key_blob.toBytesArray());
+
+ } catch (InvalidKeyFormatException e) {
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate, can't create public key object from server side key generated public key blob!");
+ throw new TPSException(
+ "TPSEnrollProcessor.enrollOneCertificate, can't create public key object from server side key generated public key blob!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ parsedPubKey_ba = parsedPK11PubKey.getEncoded();
+
+ } else if (isRenewal) {
+
+ CMS.debug("TPSEnrollProcessor: We are in renewal mode, no work to do with the keys, in renewal the keys remain on the token.");
+
+ } else {
+ //Handle token side keyGen
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate: about to generate the private key on the token.");
+
+ int algorithm = 0x80;
+
+ if (certsInfo.getKeyCheck() != null) {
+ algorithm = 0x81;
+ }
+
+ if (isECC) {
+ algorithm = keyAlg;
+ }
+
+ int pe1 = (cEnrollInfo.getKeyUser() << 4) + cEnrollInfo.getPrivateKeyNumber();
+ int pe2 = (cEnrollInfo.getKeyUsage() << 4) + cEnrollInfo.getPublicKeyNumber();
+
+ int size = channel.startEnrollment(pe1, pe2, certsInfo.getWrappedChallenge(), certsInfo.getKeyCheck(),
+ algorithm, cEnrollInfo.getKeySize(), 0x0);
+
+ byte[] iobytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
+ TPSBuffer iobuf = new TPSBuffer(iobytes);
+
+ public_key_blob = channel.readObject(iobuf, 0, size);
+
+ parsedPubKey = parsePublicKeyBlob(public_key_blob, isECC);
+
+ parsedPubKey_ba = parsedPubKey.getEncoded();
+ }
+
+ // enrollment/recovery begins
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: enrollment begins");
+ X509CertImpl x509Cert = null;
+ byte[] cert_bytes = null;
+ try {
+
+ if (isRecovery == false && isRenewal == false) {
+ String caConnID = getCAConnectorID();
+ CARemoteRequestHandler caRH = new CARemoteRequestHandler(caConnID);
+ TPSBuffer encodedParsedPubKey = new TPSBuffer(parsedPubKey_ba);
+
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: userid =" + userid + ", cuid="
+ + aInfo.getCUIDhexString());
+ CAEnrollCertResponse caEnrollResp = caRH.enrollCertificate(encodedParsedPubKey, userid,
+ aInfo.getCUIDhexString(), getSelectedTokenType(),
+ cEnrollInfo.getKeyType());
+ String retCertB64 = caEnrollResp.getCertB64();
+
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate: retCertB64: " + retCertB64);
+
+ cert_bytes = Utils.base64decode(retCertB64);
+
+ TPSBuffer cert_bytes_buf = new TPSBuffer(cert_bytes);
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate: retCertB64: " + cert_bytes_buf.toHexString());
+
+ if (retCertB64 != null)
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: new cert b64 =" + retCertB64);
+ else {
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: new cert b64 not found");
+ throw new TPSException("TPSEnrollProcessor.enrollOneCertificate: new cert b64 not found",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+ x509Cert = caEnrollResp.getCert();
+ if (x509Cert != null)
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: new cert retrieved");
+ else {
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: new cert not found");
+ throw new TPSException("TPSEnrollProcessor.enrollOneCertificate: new cert not found",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ } else {
+ //Import the cert data from the CertEnrollObject or from Renewal object
+
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate: Attempt to import cert data in recovery mode or renew mode!");
+
+ if (isRecovery) {
+ CARetrieveCertResponse certResp = cEnrollInfo.getRecoveredCertData();
+
+ if (certResp == null) {
+ throw new TPSException(
+ "TPSEnrollProcessor.enrollOneCertificate: In recovery mode, CARetieveCertResponse object not found!",
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+
+ String retCertB64 = certResp.getCertB64();
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate: recovering: retCertB64: " + retCertB64);
+ cert_bytes = Utils.base64decode(retCertB64);
+
+ TPSBuffer cert_bytes_buf = new TPSBuffer(cert_bytes);
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate: recovering: retCertB64: "
+ + cert_bytes_buf.toHexString());
+
+ if (retCertB64 != null)
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: recovering: new cert b64 =" + retCertB64);
+ else {
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: recovering new cert b64 not found");
+ throw new TPSException(
+ "TPSEnrollProcessor.enrollOneCertificate: recovering: new cert b64 not found",
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+ x509Cert = certResp.getCert();
+ if (x509Cert != null)
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: recovering new cert retrieved");
+ else {
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: recovering new cert not found");
+ throw new TPSException("TPSEnrollProcessor.enrollOneCertificate: new cert not found",
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+
+ }
+
+ // If we are here, it has to be one or the other.
+
+ if (isRenewal) {
+
+ CARenewCertResponse certResp = cEnrollInfo.getRenewedCertData();
+ if (certResp == null) {
+ throw new TPSException(
+ "TPSEnrollProcessor.enrollOneCertificate: In renewal mode, CARemewCertResponse object not found!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ String retCertB64 = certResp.getRenewedCertB64();
+ cert_bytes = Utils.base64decode(retCertB64);
+
+ if (retCertB64 != null)
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: renewing: new cert b64 =" + retCertB64);
+ else {
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: renewing new cert b64 not found");
+ throw new TPSException(
+ "TPSEnrollProcessor.enrollOneCertificate: remewomg: new cert b64 not found",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ x509Cert = certResp.getRenewedCert();
+
+ if (x509Cert != null)
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: renewing new cert retrieved");
+ else {
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: renewing new cert not found");
+ throw new TPSException("TPSEnrollProcessor.enrollOneCertificate: new cert not found",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+
+ TPSBuffer cert_bytes_buf = new TPSBuffer(cert_bytes);
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate: renewing: retCertB64: "
+ + cert_bytes_buf.toHexString());
+
+ }
+
+ }
+
+ certsInfo.addCertificate(x509Cert);
+ // In renewal case, we don't need to save this info.
+ if (!isRenewal) {
+ certsInfo.addKType(cEnrollInfo.getKeyType());
+ }
+
+ //Add origin, special handling for recovery case.
+ if (isRecovery == true) {
+ TokenRecord recordToRecover = cEnrollInfo.getTokenToBeRecovered();
+ //We need to have this token record otherwise bomb out.
+
+ if (recordToRecover == null) {
+ throw new TPSException(
+ "TPSEnrollProcessor.enrollOneCertificate: TokenRecord of token to be recovered not found.",
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+
+ certsInfo.addOrigin(recordToRecover.getId());
+
+ } else {
+ certsInfo.addOrigin(aInfo.getCUIDhexStringPlain());
+ }
+
+ certsInfo.addTokenType(selectedTokenType);
+
+ SubjectPublicKeyInfo publicKeyInfo = null;
+
+ String label = null;
+ TPSBuffer keyid = null;
+ TPSBuffer modulus = null;
+ TPSBuffer exponent = null;
+
+ if (!isRenewal) {
+
+ try {
+ if (serverSideKeyGen) {
+ publicKeyInfo = new SubjectPublicKeyInfo(parsedPK11PubKey);
+ } else {
+ publicKeyInfo = new SubjectPublicKeyInfo(parsedPubKey);
+ }
+ } catch (InvalidBERException e) {
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: cant get publicKeyInfo object.");
+ throw new TPSException("TPSEnrollProcessor.enrollOneCertificate: can't get publcKeyInfo object.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ //Create label ToDo: Do this the correct way later
+
+ label = buildCertificateLabel(cEnrollInfo, aInfo);
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: cert label: " + label);
+
+ keyid = new TPSBuffer(makeKeyIDFromPublicKeyInfo(publicKeyInfo.getEncoded()));
+
+ modulus = null;
+ exponent = null;
+
+ if (serverSideKeyGen) {
+ modulus = new TPSBuffer(((PK11RSAPublicKey) parsedPK11PubKey).getModulus().toByteArray());
+ exponent = new TPSBuffer(((PK11RSAPublicKey) parsedPK11PubKey).getPublicExponent().toByteArray());
+
+ } else {
+ modulus = new TPSBuffer(parsedPubKey.getModulus().toByteArray());
+ exponent = new TPSBuffer(parsedPubKey.getPublicExponent().toByteArray());
+ }
+
+ }
+
+ //Write cert to the token,do this in all modes
+
+ long l1, l2;
+ long objid;
+ PKCS11Obj pkcs11Obj = certsInfo.getPKCS11Obj();
+
+ String certId = cEnrollInfo.getCertId();
+
+ l1 = (certId.charAt(0) & 0xff) << 24;
+ l2 = (certId.charAt(1) & 0xff) << 16;
+ objid = l1 + l2;
+
+ CMS.debug("TPSEnrollProcess.enrollOneCertificate: cert objid long: " + objid);
+
+ ObjectSpec certObjSpec = ObjectSpec.parseFromTokenData(objid, new TPSBuffer(cert_bytes));
+ pkcs11Obj.addObjectSpec(certObjSpec);
+
+ //Do the rest of this stuff only in enrollment or recovery case, in renewal, we need not deal with the keys
+
+ if (isRenewal == false) {
+
+ String certAttrId = cEnrollInfo.getCertAttrId();
+
+ TPSBuffer certAttrsBuffer = channel.createPKCS11CertAttrsBuffer(cEnrollInfo.getKeyTypeEnum(),
+ certAttrId, label, keyid);
+
+ l1 = (certAttrId.charAt(0) & 0xff) << 24;
+ l2 = (certAttrId.charAt(1) & 0xff) << 16;
+ objid = l1 + l2;
+
+ CMS.debug("TPSEnrollProcess.enrollOneCertificate: cert attr objid long: " + objid);
+ ObjectSpec certAttrObjSpec = ObjectSpec.parseFromTokenData(objid, certAttrsBuffer);
+ pkcs11Obj.addObjectSpec(certAttrObjSpec);
+
+ //Add the pri key attrs object
+
+ String priKeyAttrId = cEnrollInfo.getPrivateKeyAttrId();
+
+ l1 = (priKeyAttrId.charAt(0) & 0xff) << 24;
+ l2 = (priKeyAttrId.charAt(1) & 0xff) << 16;
+
+ objid = l1 + l2;
+
+ CMS.debug("TPSEnrollProcess.enrollOneCertificate: pri key objid long: " + objid);
+
+ TPSBuffer privKeyAttrsBuffer = channel.createPKCS11PriKeyAttrsBuffer(priKeyAttrId, label, keyid,
+ modulus, cEnrollInfo.getKeyTypePrefix());
+
+ ObjectSpec priKeyObjSpec = ObjectSpec.parseFromTokenData(objid, privKeyAttrsBuffer);
+ pkcs11obj.addObjectSpec(priKeyObjSpec);
+
+ // Now add the public key object
+
+ String pubKeyAttrId = cEnrollInfo.getPublicKeyAttrId();
+
+ l1 = (pubKeyAttrId.charAt(0) & 0xff) << 24;
+ l2 = (pubKeyAttrId.charAt(1) & 0xff) << 16;
+
+ objid = l1 + l2;
+ CMS.debug("TPSEnrollProcess.enrollOneCertificate: pub key objid long: " + objid);
+
+ TPSBuffer pubKeyAttrsBuffer = channel.createPKCS11PublicKeyAttrsBuffer(pubKeyAttrId, label, keyid,
+ modulus, exponent, cEnrollInfo.getKeyTypePrefix());
+ ObjectSpec pubKeyObjSpec = ObjectSpec.parseFromTokenData(objid, pubKeyAttrsBuffer);
+ pkcs11obj.addObjectSpec(pubKeyObjSpec);
+
+ }
+ } catch (EBaseException e) {
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate::" + e);
+ throw new TPSException("TPSEnrollProcessor.enrollOneCertificate: Exception thrown: " + e,
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ if (serverSideKeyGen || isRecovery) {
+ //Handle injection of private key onto token
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate: About to inject private key");
+
+ if (!isRecovery) {
+
+ // SecureChannel newChannel = setupSecureChannel();
+ importPrivateKeyPKCS8(ssKeyGenResponse, cEnrollInfo, channel, isECC);
+
+ } else {
+ importPrivateKeyPKCS8(keyResp, cEnrollInfo, channel, isECC);
+ }
+
+ }
+
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: enrollment ends");
+
+ statusUpdate(cEnrollInfo.getEndProgressValue(), "PROGRESS_ENROLL_CERT");
+ CMS.debug("TPSEnrollProcessor.enrollOneCertificate ends");
+
+ }
+
+ private void importPrivateKeyPKCS8(KRARecoverKeyResponse keyResp, CertEnrollInfo cEnrollInfo,
+ SecureChannel channel,
+ boolean isECC) throws TPSException, IOException {
+
+ if (keyResp == null || cEnrollInfo == null || channel == null) {
+ throw new TPSException("TPSEnrollProcessor.importPrivateKeyPKCS8: invalid input data!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ importPrivateKeyPKCS8(keyResp.getWrappedPrivKey(), keyResp.getIVParam(), cEnrollInfo, channel, isECC);
+
+ }
+
+ private void importPrivateKeyPKCS8(KRAServerSideKeyGenResponse ssKeyGenResponse, CertEnrollInfo cEnrollInfo,
+ SecureChannel channel,
+ boolean isECC) throws TPSException, IOException {
+
+ if (ssKeyGenResponse == null || cEnrollInfo == null || channel == null) {
+ throw new TPSException("TPSEnrollProcessor.importPrivateKeyPKCS8: invalid input data!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ importPrivateKeyPKCS8(ssKeyGenResponse.getWrappedPrivKey(), ssKeyGenResponse.getIVParam(), cEnrollInfo,
+ channel, isECC);
+
+ }
+
+ private void importPrivateKeyPKCS8(String wrappedPrivKeyStr, String ivParams, CertEnrollInfo cEnrollInfo,
+ SecureChannel channel,
+ boolean isECC) throws TPSException, IOException {
+
+ CMS.debug("TPSEnrollProcessor.importprivateKeyPKCS8 entering..");
+ if (wrappedPrivKeyStr == null || ivParams == null || cEnrollInfo == null || channel == null) {
+ throw new TPSException("TPSEnrollProcessor.importPrivateKeyPKCS8: invalid input data!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ byte[] objid = {
+ (byte) 0xFF,
+ 0x00,
+ (byte) 0xFF,
+ (byte) 0xF3 };
+
+ byte keytype = 0x09; //RSAPKCS8Pair
+
+ // String wrappedPrivKeyStr = ssKeyGenResponse.getWrappedPrivKey();
+ int keysize = cEnrollInfo.getKeySize();
+
+ TPSBuffer privKeyBlob = new TPSBuffer();
+
+ privKeyBlob.add((byte) 0x1); // encryption
+ privKeyBlob.add(keytype);
+ privKeyBlob.add((byte) (keysize / 256));
+ privKeyBlob.add((byte) (keysize % 256));
+
+ TPSBuffer privKeyBuff = new TPSBuffer(Util.uriDecodeFromHex(wrappedPrivKeyStr));
+ privKeyBlob.add(privKeyBuff);
+
+ CMS.debug("TPSEnrollProcessor.importprivateKeyPKCS8 privKeyBlob: " + privKeyBlob.toHexString());
+
+ byte[] perms = { 0x40,
+ 0x00,
+ 0x40,
+ 0x00,
+ 0x40,
+ 0x00 };
+
+ TPSBuffer objIdBuff = new TPSBuffer(objid);
+
+ channel.createObject(objIdBuff, new TPSBuffer(perms), privKeyBlob.size());
+
+ channel.writeObject(objIdBuff, privKeyBlob);
+
+ TPSBuffer keyCheck = channel.getKeyCheck();
+
+ CMS.debug("TPSEnrollProcessor.importprivateKeyPKCS8 : keyCheck: " + keyCheck.toHexString());
+
+ // String ivParams = ssKeyGenResponse.getIVParam();
+ CMS.debug("TPSEnrollProcessor.importprivateKeyPKCS8: ivParams: " + ivParams);
+ TPSBuffer ivParamsBuff = new TPSBuffer(Util.uriDecodeFromHex(ivParams));
+
+ if (ivParamsBuff.size() == 0) {
+ throw new TPSException("TPSEnrollProcessor.importPrivateKeyPKCS8: invalid iv vector!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+
+ }
+
+ TPSBuffer kekWrappedDesKey = channel.getKekDesKey();
+
+ if (kekWrappedDesKey != null)
+ CMS.debug("TPSEnrollProcessor.importPrivateKeyPKCS8: keyWrappedDesKey: " + kekWrappedDesKey.toHexString());
+ else
+ CMS.debug("TPSEnrollProcessor.iportPrivateKeyPKC8: null kekWrappedDesKey!");
+
+ byte alg = (byte) 0x80;
+ if (kekWrappedDesKey == null || kekWrappedDesKey.size() > 0) {
+ alg = (byte) 0x81;
+ }
+
+ TPSBuffer data = new TPSBuffer();
+
+ data.add(objIdBuff);
+ data.add(alg);
+ data.add((byte) kekWrappedDesKey.size());
+ data.add(kekWrappedDesKey);
+ data.add((byte) keyCheck.size());
+ data.add(keyCheck);
+ data.add((byte) ivParamsBuff.size());
+ data.add(ivParamsBuff);
+
+ int pe1 = (cEnrollInfo.getKeyUser() << 4) + cEnrollInfo.getPrivateKeyNumber();
+ int pe2 = (cEnrollInfo.getKeyUsage() << 4) + cEnrollInfo.getPublicKeyNumber();
+
+ channel.importKeyEnc(pe1, pe2, data);
+
+ CMS.debug("TPSEnrollProcessor.importprivateKeyPKCS8 successful, leaving...");
+
+ }
+
+ private String buildCertificateLabel(CertEnrollInfo cEnrollInfo, AppletInfo ainfo) throws TPSException {
+
+ CMS.debug("TPSEnrollProcessor.buildCertificateLabel");
+
+ if (cEnrollInfo == null) {
+ throw new TPSException("TPSErollProcessor.buildCertificateLabel: Invalid input params!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ String label = null;
+ String pattern = null;
+
+ String defaultLabel = cEnrollInfo.getKeyType() + " key for $userid$";
+
+ IConfigStore configStore = CMS.getConfigStore();
+
+ String configValue = "op." + currentTokenOperation + "." + selectedTokenType + ".keyGen."
+ + cEnrollInfo.getKeyType() + ".label";
+
+ CMS.debug("TPSEnrollProcessor.buildCertificateLabel: label config: " + configValue);
+
+ try {
+ pattern = configStore.getString(
+ configValue, defaultLabel);
+
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "TPSEnrollProcessor.buildCertificateLabel: Internal error finding config value: " + e,
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ Map<String, String> nv = new LinkedHashMap<String, String>();
+
+ nv.put("cuid", ainfo.getCUIDhexString());
+ nv.put("msn", ainfo.getMSNString());
+ nv.put("userid", userid);
+ nv.put("auth.cn", userid);
+ nv.put("profileId", getSelectedTokenType());
+
+ label = mapPattern((LinkedHashMap<String, String>) nv, pattern);
+
+ CMS.debug("TPSEnrollProcessor.buildCertificateLabel: returning: " + label);
+
+ return label;
+ }
+
+ /**
+ * Extracts information from the public key blob and verify proof.
+ *
+ * Muscle Key Blob Format (RSA Public Key)
+ * ---------------------------------------
+ *
+ * The key generation operation places the newly generated key into
+ * the output buffer encoding in the standard Muscle key blob format.
+ * For an RSA key the data is as follows:
+ *
+ * Byte Encoding (0 for plaintext)
+ *
+ * Byte Key Type (1 for RSA public)
+ *
+ * Short Key Length (1024 û high byte first)
+ *
+ * Short Modulus Length
+ *
+ * Byte[] Modulus
+ *
+ * Short Exponent Length
+ *
+ * Byte[] Exponent
+ *
+ *
+ * ECC KeyBlob Format (ECC Public Key)
+ * ----------------------------------
+ *
+ * Byte Encoding (0 for plaintext)
+ *
+ * Byte Key Type (10 for ECC public)
+ *
+ * Short Key Length (256, 384, 521 high byte first)
+ *
+ * Byte[] Key (W)
+ *
+ *
+ * Signature Format (Proof)
+ * ---------------------------------------
+ *
+ * The key generation operation creates a proof-of-location for the
+ * newly generated key. This proof is a signature computed with the
+ * new private key using the RSA-with-MD5 signature algorithm. The
+ * signature is computed over the Muscle Key Blob representation of
+ * the new public key and the challenge sent in the key generation
+ * request. These two data fields are concatenated together to form
+ * the input to the signature, without any other data or length fields.
+ *
+ * Byte[] Key Blob Data
+ *
+ * Byte[] Challenge
+ *
+ *
+ * Key Generation Result
+ * ---------------------------------------
+ *
+ * The key generation command puts the key blob and the signature (proof)
+ * into the output buffer using the following format:
+ *
+ * Short Length of the Key Blob
+ *
+ * Byte[] Key Blob Data
+ *
+ * Short Length of the Proof
+ *
+ * Byte[] Proof (Signature) Data
+ *
+ * @param blob the publickey blob to be parsed
+ * @param challenge the challenge generated by TPS
+ *
+ ******/
+ private RSAPublicKey parsePublicKeyBlob(
+ TPSBuffer public_key_blob,
+ /* TPSBuffer challenge,*/
+ boolean isECC)
+ throws TPSException {
+ RSAPublicKey parsedPubKey = null;
+
+ if (public_key_blob == null /*|| challenge == null*/) {
+ throw new TPSException(
+ "TPSEnrollProcessor.parsePublicKeyBlob: Bad input data! Missing public_key_blob or challenge",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: public key blob from token to parse: "
+ + public_key_blob.toHexString());
+ /*
+ * decode blob into structures
+ */
+
+ // offset to the beginning of the public key length. should be 0
+ int pkeyb_len_offset = 0;
+
+ /*
+ * now, convert lengths
+ */
+ // 1st, keyblob length
+ /*
+ byte len0 = public_key_blob.at(pkeyb_len_offset);
+ byte len1 = public_key_blob.at(pkeyb_len_offset + 1);
+ int pkeyb_len = (len0 << 8) | (len1 & 0xFF);
+ */
+ int pkeyb_len = public_key_blob.getIntFrom2Bytes(pkeyb_len_offset);
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: pkeyb_len = " +
+ pkeyb_len + ", isECC: " + isECC);
+ // public key blob
+ TPSBuffer pkeyb = public_key_blob.substr(pkeyb_len_offset + 2, pkeyb_len);
+ if (pkeyb == null) {
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: pkeyb null ");
+ throw new TPSException("TPSEnrollProcessor.parsePublicKeyBlob: Bad input data! pkeyb null",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: pkeyb = "
+ + pkeyb.toHexString());
+
+ // 2nd, proof blob length
+ int proofb_len_offset = pkeyb_len_offset + 2 + pkeyb_len;
+ /*
+ len0 = public_key_blob.at(proofb_len_offset);
+ len1 = public_key_blob.at(proofb_len_offset + 1);
+ int proofb_len = (len0 << 8 | len1 & 0xFF);
+ */
+ int proofb_len = public_key_blob.getIntFrom2Bytes(proofb_len_offset);
+ // proof blob
+ TPSBuffer proofb = public_key_blob.substr(proofb_len_offset + 2, proofb_len);
+ if (proofb == null) {
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: proofb null ");
+ throw new TPSException("TPSEnrollProcessor.parsePublicKeyBlob: Bad input data! proofb null",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: proofb = "
+ + proofb.toHexString());
+
+ // convert pkeyb to pkey
+ // 1 byte encoding, 1 byte key type, 2 bytes key length, then the key
+ int pkey_offset = 4;
+ /*
+ len0 = pkeyb.at(pkey_offset);
+ len1 = pkeyb.at(pkey_offset + 1);
+ */
+ if (!isECC) {
+ // int mod_len = len0 << 8 | len1 & 0xFF;
+ int mod_len = pkeyb.getIntFrom2Bytes(pkey_offset);
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: mod_len= " + mod_len);
+ /*
+ len0 = pkeyb.at(pkey_offset + 2 + mod_len);
+ len1 = pkeyb.at(pkey_offset + 2 + mod_len + 1);
+ int exp_len = len0 << 8 | len1 & 0xFF;
+ */
+ int exp_len = pkeyb.getIntFrom2Bytes(pkey_offset + 2 + mod_len);
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: exp_len= " + exp_len);
+
+ TPSBuffer modb = pkeyb.substr(pkey_offset + 2, mod_len);
+ if (modb == null) {
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: modb null ");
+ throw new TPSException("TPSEnrollProcessor.parsePublicKeyBlob: Bad input data! modb null",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: modb= "
+ + modb.toHexString());
+ TPSBuffer expb = pkeyb.substr(pkey_offset + 2 + mod_len + 2, exp_len);
+
+ if (expb == null) {
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: expb null ");
+ throw new TPSException("TPSEnrollProcessor.parsePublicKeyBlob: Bad input data! expb null",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: expb= "
+ + expb.toHexString());
+ BigInt modb_bi = new BigInt(modb.toBytesArray());
+ BigInt expb_bi = new BigInt(expb.toBytesArray());
+ try {
+ RSAPublicKey rsa_pub_key = new RSAPublicKey(modb_bi, expb_bi);
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: public key blob converted to RSAPublicKey");
+ if (rsa_pub_key != null) {
+ parsedPubKey = rsa_pub_key;
+ }
+ } catch (InvalidKeyException e) {
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob:InvalidKeyException thrown");
+ throw new TPSException("TPSEnrollProcessor.parsePublicKeyBlob: Exception thrown: " + e,
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+ } else {
+ // TODO: handle ECC
+ }
+
+ // TODO: challenge verification
+
+ // sanity-check parsedPubKey before return
+ if (parsedPubKey == null) {
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: parsedPubKey null");
+ throw new TPSException(
+ "TPSEnrollProcessor.parsePublicKeyBlob: parsedPubKey null.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ } else {
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: parsedPubKey not null");
+ }
+ byte[] parsedPubKey_ba = parsedPubKey.getEncoded();
+ if (parsedPubKey_ba == null) {
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: parsedPubKey_ba null");
+ throw new TPSException(
+ "TPSEnrollProcessor.parsePublicKeyBlob: parsedPubKey encoding failure.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ } else {
+ CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: parsedPubKey getEncoded not null");
+ }
+
+ return parsedPubKey;
+ }
+
+ private boolean checkForServerSideKeyGen(CertEnrollInfo cInfo) throws TPSException {
+
+ if (cInfo == null) {
+ throw new TPSException("TPSEnrollProcessor.checkForServerSideKeyGen: invalid cert info.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+ IConfigStore configStore = CMS.getConfigStore();
+ boolean serverSideKeygen = false;
+
+ try {
+ String configValue = cInfo.getKeyTypePrefix() + "." + TPSEngine.CFG_SERVER_KEYGEN_ENABLE;
+ CMS.debug("TPSEnrollProcessor.checkForServerSideKeyGen: config: " + configValue);
+ serverSideKeygen = configStore.getBoolean(
+ configValue, false);
+
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "TPSEnrollProcessor.checkForServerSideKeyGen: Internal error finding config value: " + e,
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ CMS.debug("TPSProcess.checkForServerSideKeyGen: returning: " + serverSideKeygen);
+
+ return serverSideKeygen;
+
+ }
+
+ private boolean checkForServerKeyArchival(CertEnrollInfo cInfo) throws TPSException {
+
+ if (cInfo == null) {
+ throw new TPSException("TPSEnrollProcessor.checkForServerKeyArchival: invalid cert info.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+ IConfigStore configStore = CMS.getConfigStore();
+ boolean serverKeyArchival = false;
+
+ try {
+ String configValue = cInfo.getKeyTypePrefix() + "." + TPSEngine.CFG_SERVER_KEY_ARCHIVAL;
+ CMS.debug("TPSEnrollProcessor.checkForServerKeyArchival: config: " + configValue);
+ serverKeyArchival = configStore.getBoolean(
+ configValue, false);
+
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "TPSEnrollProcessor.checkForServerKeyArchival: Internal error finding config value: " + e,
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ CMS.debug("TPSProcess.checkForServerKeyArchival: returning: " + serverKeyArchival);
+
+ return serverKeyArchival;
+
+ }
+
+ private boolean checkForObjectOverwrite(CertEnrollInfo cInfo) throws TPSException {
+
+ if (cInfo == null) {
+ throw new TPSException("TPSEnrollProcessor.checkForObjectOverwrite: invalid cert info.",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+ IConfigStore configStore = CMS.getConfigStore();
+ boolean objectOverwrite = false;
+
+ try {
+ String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + getSelectedTokenType() + ".keyGen."
+ + cInfo.getKeyType() + "." + TPSEngine.CFG_OVERWRITE;
+
+ CMS.debug("TPSProcess.checkForObjectOverwrite: config: " + configValue);
+ objectOverwrite = configStore.getBoolean(
+ configValue, true);
+
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "TPSEnrollProcessor.checkForServerSideKeyGen: Internal error finding config value: " + e,
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ CMS.debug("TPSProcess.checkForObjectOverwrite: returning: " + objectOverwrite);
+
+ return objectOverwrite;
+
+ }
+
+ private String getConfiguredKeyType(int keyTypeIndex) throws TPSException {
+
+ IConfigStore configStore = CMS.getConfigStore();
+ String keyType = null;
+
+ try {
+ String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "."
+ + TPSEngine.CFG_KEYGEN_KEYTYPE_VALUE + "." + keyTypeIndex;
+ keyType = configStore.getString(
+ configValue, null);
+
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "TPSEnrollProcessor.getConfiguredKeyType: Internal error finding config value: " + e,
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ //We would really like one of these to exist
+
+ if (keyType == null) {
+ throw new TPSException(
+ "TPSEnrollProcessor.getConfiguredKeyType: Internal error finding config value: ",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ CMS.debug("TPSProcess.getConfiguredKeyType: returning: " + keyType);
+
+ return keyType;
+
+ }
+
+ private String getDRMConnectorID() throws TPSException {
+ IConfigStore configStore = CMS.getConfigStore();
+ String id = null;
+
+ String config = "op." + currentTokenOperation + "." + selectedTokenType + "." + TPSEngine.CFG_KEYGEN_ENCRYPTION
+ + "." + TPSEngine.CFG_DRM_CONNECTOR;
+
+ CMS.debug("TPSEnrollProcessor.getDRMConnectorID: config value: " + config);
+ try {
+ id = configStore.getString(config, "kra1");
+ } catch (EBaseException e) {
+ throw new TPSException("TPSEnrollProcessor.getDRMConnectorID: Internal error finding config value.");
+
+ }
+
+ CMS.debug("TPSEnrollProcessor.getDRMConectorID: returning: " + id);
+
+ return id;
+ }
+
+ protected int getNumberCertsToEnroll() throws TPSException {
+ IConfigStore configStore = CMS.getConfigStore();
+ int keyTypeNum = 0;
+ try {
+ String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "."
+ + TPSEngine.CFG_KEYGEN_KEYTYPE_NUM;
+ keyTypeNum = configStore.getInteger(
+ configValue, 0);
+
+ } catch (EBaseException e) {
+ throw new TPSException("TPSEnrollProcessor.getNumberCertsToEnroll: Internal error finding config value: "
+ + e,
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+
+ }
+
+ if (keyTypeNum == 0) {
+ throw new TPSException(
+ "TPSEnrollProcessor.getNumberCertsToEnroll: invalid number of certificates configured!",
+ TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+ }
+ CMS.debug("TPSProcess.getNumberCertsToEnroll: returning: " + keyTypeNum);
+
+ return keyTypeNum;
+ }
+
+ protected int getEnrollmentAlg() throws TPSException {
+ IConfigStore configStore = CMS.getConfigStore();
+ int enrollmentAlg;
+ try {
+ String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "."
+ + TPSEngine.CFG_KEYGEN_ENCRYPTION + "." + TPSEngine.CFG_ALG;
+
+ CMS.debug("TPSProcess.getEnrollmentAlg: configValue: " + configValue);
+
+ enrollmentAlg = configStore.getInteger(
+ configValue, 2);
+
+ } catch (EBaseException e) {
+ throw new TPSException("TPSEnrollProcessor.getEnrollmentAlg: Internal error finding config value: "
+ + e,
+ TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+
+ }
+
+ CMS.debug("TPSProcess.getEnrollmentAlg: returning: " + enrollmentAlg);
+
+ return enrollmentAlg;
+ }
+
+ protected String getRecoveryKeyTypeValue(String reason, int index) throws TPSException {
+
+ if (reason == null || index < 0) {
+ throw new TPSException("TPSEnrollProcessor.getRecoveryKeyTypeValue: invalide input data!",
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+
+ IConfigStore configStore = CMS.getConfigStore();
+ String keyTypeValue;
+ try {
+ String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "." + TPSEngine.CFG_KEYGEN
+ + "."
+ + TPSEngine.RECOVERY_OP + "." + reason + "." + TPSEngine.CFG_KEYTYPE_VALUE + "." + index;
+ ;
+
+ CMS.debug("TPSProcess.getRecoveryKeyTypeValue: configValue: " + configValue);
+
+ keyTypeValue = configStore.getString(
+ configValue, null);
+
+ } catch (EBaseException e) {
+ throw new TPSException("TPSEnrollProcessor.getRecoveryKeyTypeValue: Internal error finding config value: "
+ + e,
+ TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+
+ }
+
+ if (keyTypeValue == null) {
+ throw new TPSException("TPSEnrollProcessor.getRecoveryKeyTypeValue: Invalid keyTypeValue found! ",
+ TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+ }
+
+ CMS.debug("TPSProcess.getRecoveryKeyTypeValue: returning: " + keyTypeValue);
+
+ return keyTypeValue;
+ }
+
+ protected String getRecoveryScheme(String reason, String keyTypeValue) throws TPSException {
+
+ if (reason == null || keyTypeValue == null) {
+ throw new TPSException("TPSEnrollProcessor.getRecoveryScheme: invalid input data!",
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+
+ IConfigStore configStore = CMS.getConfigStore();
+ String scheme = null;
+ try {
+ String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "." + TPSEngine.CFG_KEYGEN
+ + "." + keyTypeValue + "."
+ + TPSEngine.RECOVERY_OP + "." + reason + "." + TPSEngine.CFG_SCHEME;
+ ;
+
+ CMS.debug("TPSProcess.getRecoveryScheme: configValue: " + configValue);
+
+ scheme = configStore.getString(
+ configValue, null);
+
+ } catch (EBaseException e) {
+ throw new TPSException("TPSEnrollProcessor.getRecoveryScheme: Internal error finding config value: "
+ + e,
+ TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+
+ }
+
+ if (scheme == null) {
+ throw new TPSException("TPSEnrollProcessor.getRecoverScheme: Invalid scheme found! ",
+ TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+ }
+
+ CMS.debug("TPSProcess.getRecoveryScheme: returning: " + scheme);
+
+ return scheme;
+ }
+
+ protected int getNumberCertsForRecovery(String reason) throws TPSException {
+ if (reason == null) {
+ throw new TPSException("TPSEnrollProcessor.getNumberCertsForRecovery: invlalid input data!",
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+
+ IConfigStore configStore = CMS.getConfigStore();
+ int keyTypeNum = 0;
+ try {
+ String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "." + TPSEngine.CFG_KEYGEN
+ + "." + TPSEngine.RECOVERY_OP
+ + "." + reason + "." + TPSEngine.CFG_KEYTYPE_NUM;
+
+ CMS.debug("TPSEnrollProcessor.getNumberCertsForRecovery: configValue: " + configValue);
+ keyTypeNum = configStore.getInteger(
+ configValue, 0);
+
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "TPSEnrollProcessor.getNumberCertsForRecovery: Internal error finding config value: "
+ + e,
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+
+ }
+
+ if (keyTypeNum == 0) {
+ throw new TPSException(
+ "TPSEnrollProcessor.getNumberCertsForRecovery: invalid number of certificates configured!",
+ TPSStatus.STATUS_ERROR_RECOVERY_FAILED);
+ }
+ CMS.debug("TPSProcess.getNumberCertsForRecovery: returning: " + keyTypeNum);
+
+ return keyTypeNum;
+ }
+
+ protected String getCAConnectorID() throws TPSException {
+ IConfigStore configStore = CMS.getConfigStore();
+ String id = null;
+
+ String config = "op." + currentTokenOperation + "." + selectedTokenType + ".ca.conn";
+
+ try {
+ id = configStore.getString(config, "ca1");
+ } catch (EBaseException e) {
+ throw new TPSException("TPSEnrollProcessor.getCAConnectorID: Internal error finding config value.");
+
+ }
+
+ CMS.debug("TPSEnrollProcessor.getCAConectorID: returning: " + id);
+
+ return id;
+ }
+
+ private TPSBuffer makeKeyIDFromPublicKeyInfo(byte[] publicKeyInfo) throws TPSException {
+
+ final String alg = "SHA1";
+
+ if (publicKeyInfo == null) {
+ throw new TPSException("TPSEnrollProcessor.makeKeyIDFromPublicKeyInfo: invalid input data",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ TPSBuffer keyID = null;
+
+ byte[] mozillaDigestOut;
+
+ java.security.MessageDigest mozillaDigest;
+ try {
+ mozillaDigest = java.security.MessageDigest.getInstance(alg);
+ } catch (NoSuchAlgorithmException e) {
+ throw new TPSException("TPSEnrollProcessor.makeKeyIDFromPublicKeyInfo: " + e,
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ mozillaDigestOut = mozillaDigest.digest(publicKeyInfo);
+
+ if (mozillaDigestOut.length == mozillaDigest.getDigestLength()) {
+ System.out.println(mozillaDigest.getAlgorithm() + " " +
+ " digest output size is " + mozillaDigestOut.length);
+ } else {
+ throw new TPSException("ERROR: digest output size is " +
+ mozillaDigestOut.length + ", should be " +
+ mozillaDigest.getDigestLength(), TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ keyID = new TPSBuffer(mozillaDigestOut);
+
+ CMS.debug("TPSEnrollProcessor.makeKeyIDFromPublicKeyInfo: " + keyID.toHexString());
+
+ return keyID;
+ }
+
+ public BigInteger serialNoToBigInt(String serialS) {
+ if (serialS == null)
+ return new BigInteger("0", 16);
+
+ CMS.debug("TPSEnrollProcessor.seralNoToBigInt: serial # =" + serialS);
+ String serialhex = serialS.substring(2); // strip off the "0x"
+ BigInteger serialBI = new BigInteger(serialhex, 16);
+
+ return serialBI;
+ }
+
+ public static void main(String[] args) {
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSPinResetProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSPinResetProcessor.java
new file mode 100644
index 000000000..b92cd8b91
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSPinResetProcessor.java
@@ -0,0 +1,66 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps.processor;
+
+import java.io.IOException;
+
+import org.dogtagpki.server.tps.TPSSession;
+import org.dogtagpki.tps.main.TPSException;
+import org.dogtagpki.tps.msg.BeginOpMsg;
+import org.dogtagpki.tps.msg.EndOpMsg.TPSStatus;
+
+import com.netscape.certsrv.apps.CMS;
+
+public class TPSPinResetProcessor extends TPSProcessor {
+
+ public TPSPinResetProcessor(TPSSession session) {
+ super(session);
+ // TODO Auto-generated constructor stub
+ }
+
+ @Override
+ public void process(BeginOpMsg beginMsg) throws TPSException, IOException {
+ if (beginMsg == null) {
+ throw new TPSException("TPSPinResetProcessor.process: invalid input data, not beginMsg provided.",
+ TPSStatus.STATUS_ERROR_CONTACT_ADMIN);
+ }
+ setBeginMessage(beginMsg);
+ setCurrentTokenOperation("pinReset");
+
+ resetPin();
+
+ }
+
+ private void resetPin() throws TPSException {
+
+ //ToDo: Implement full pin reset processor, the pin reset portion
+ // of an enrollment works fine. We just need to finish this to perform
+ // a completely stand alone pin reset of an already enrolled token.
+ CMS.debug("TPSPinResetProcessor.resetPin: entering...");
+
+ throw new TPSException("TPSPinResetProcessor.resetPin: Pin Reset standalone operation not yet supported!",
+ TPSStatus.STATUS_ERROR_MAC_RESET_PIN_PDU);
+
+ }
+
+ public static void main(String[] args) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
new file mode 100644
index 000000000..e23cea0ad
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
@@ -0,0 +1,2404 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps.processor;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import netscape.security.x509.RevocationReason;
+
+import org.dogtagpki.server.tps.TPSSession;
+import org.dogtagpki.server.tps.TPSSubsystem;
+import org.dogtagpki.server.tps.authentication.AuthUIParameter;
+import org.dogtagpki.server.tps.authentication.TPSAuthenticator;
+import org.dogtagpki.server.tps.channel.SecureChannel;
+import org.dogtagpki.server.tps.cms.CARemoteRequestHandler;
+import org.dogtagpki.server.tps.cms.CARevokeCertResponse;
+import org.dogtagpki.server.tps.cms.TKSComputeRandomDataResponse;
+import org.dogtagpki.server.tps.cms.TKSComputeSessionKeyResponse;
+import org.dogtagpki.server.tps.cms.TKSEncryptDataResponse;
+import org.dogtagpki.server.tps.cms.TKSRemoteRequestHandler;
+import org.dogtagpki.server.tps.dbs.ActivityDatabase;
+import org.dogtagpki.server.tps.dbs.TPSCertRecord;
+import org.dogtagpki.server.tps.dbs.TokenRecord;
+import org.dogtagpki.server.tps.engine.TPSEngine;
+import org.dogtagpki.server.tps.profile.BaseTokenProfileResolver;
+import org.dogtagpki.server.tps.profile.TokenProfileParams;
+import org.dogtagpki.tps.apdu.APDU;
+import org.dogtagpki.tps.apdu.APDUResponse;
+import org.dogtagpki.tps.apdu.ExternalAuthenticateAPDU.SecurityLevel;
+import org.dogtagpki.tps.apdu.GetDataAPDU;
+import org.dogtagpki.tps.apdu.GetStatusAPDU;
+import org.dogtagpki.tps.apdu.GetVersionAPDU;
+import org.dogtagpki.tps.apdu.InitializeUpdateAPDU;
+import org.dogtagpki.tps.apdu.ListObjectsAPDU;
+import org.dogtagpki.tps.apdu.SelectAPDU;
+import org.dogtagpki.tps.main.TPSBuffer;
+import org.dogtagpki.tps.main.TPSException;
+import org.dogtagpki.tps.msg.BeginOpMsg;
+import org.dogtagpki.tps.msg.EndOpMsg.TPSStatus;
+import org.dogtagpki.tps.msg.ExtendedLoginRequestMsg;
+import org.dogtagpki.tps.msg.ExtendedLoginResponseMsg;
+import org.dogtagpki.tps.msg.LoginRequestMsg;
+import org.dogtagpki.tps.msg.LoginResponseMsg;
+import org.dogtagpki.tps.msg.NewPinRequestMsg;
+import org.dogtagpki.tps.msg.NewPinResponseMsg;
+import org.dogtagpki.tps.msg.StatusUpdateRequestMsg;
+import org.dogtagpki.tps.msg.TPSMessage;
+import org.dogtagpki.tps.msg.TokenPDURequestMsg;
+import org.dogtagpki.tps.msg.TokenPDUResponseMsg;
+import org.mozilla.jss.CryptoManager.NotInitializedException;
+import org.mozilla.jss.pkcs11.PK11SymKey;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authentication.IAuthCredentials;
+import com.netscape.certsrv.authentication.IAuthManager;
+import com.netscape.certsrv.authentication.IAuthToken;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.EPropertyNotFound;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.tps.token.TokenStatus;
+import com.netscape.symkey.SessionKey;
+
+public class TPSProcessor {
+
+ public static final int RESULT_NO_ERROR = 0;
+ public static final int RESULT_ERROR = -1;
+
+ public static final int CPLC_DATA_SIZE = 47;
+ public static final int CPLC_MSN_INDEX = 41;
+ public static final int CPLC_MSN_SIZE = 4;
+
+ public static final int INIT_UPDATE_DATA_SIZE = 28;
+ public static final int DIVERSIFICATION_DATA_SIZE = 10;
+ public static final int CARD_CRYPTOGRAM_OFFSET = 20;
+ public static final int CARD_CRYPTOGRAM_SIZE = 8;
+ public static final int CARD_CHALLENGE_OFFSET = 12;
+ public static final int CARD_CHALLENGE_SIZE = 8;
+
+ protected boolean isExternalReg;
+
+ protected TPSSession session;
+ //protected TokenRecord tokenRecord;
+ protected String selectedTokenType;
+
+ protected String userid = null;
+ protected String currentTokenOperation;
+
+ protected BeginOpMsg beginMsg;
+
+ public TPSProcessor(TPSSession session) {
+ setSession(session);
+ }
+
+ protected void setCurrentTokenOperation(String op) {
+ currentTokenOperation = op;
+ }
+
+ protected void setSession(TPSSession session) {
+ if (session == null) {
+ throw new NullPointerException("TPS session is null");
+ }
+ this.session = session;
+ }
+
+ protected TPSSession getSession() {
+ return session;
+ }
+
+ protected TokenRecord getTokenRecord() {
+ TPSSession session = getSession();
+ return session.getTokenRecord();
+ }
+
+ protected void setBeginMessage(BeginOpMsg msg) {
+ beginMsg = msg;
+ }
+
+ public BeginOpMsg getBeginMessage() {
+ return beginMsg;
+ }
+
+ protected void setSelectedTokenType(String theTokenType) {
+
+ if (theTokenType == null) {
+ throw new NullPointerException("TPSProcessor.setSelectedTokenType: Attempt to set invalid null token type!");
+ }
+ CMS.debug("TPS_Processor.setSelectedTokenType: tokenType=" +
+ theTokenType);
+ selectedTokenType = theTokenType;
+
+ TokenRecord tokenRecord = getTokenRecord();
+ tokenRecord.setType(selectedTokenType);
+ }
+
+ public String getSelectedTokenType() {
+ return selectedTokenType;
+ }
+
+ protected TPSBuffer extractTokenMSN(TPSBuffer cplc_data) throws TPSException {
+ //Just make sure no one is inputing bogus cplc_data
+ if (cplc_data == null || cplc_data.size() < CPLC_DATA_SIZE) {
+ throw new TPSException("TPSProcessor.extractTokenMSN: Can't extract token msn from cplc data!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ TPSBuffer token_msn = cplc_data.substr(CPLC_MSN_INDEX, CPLC_MSN_SIZE);
+ return token_msn;
+
+ }
+
+ protected TPSBuffer extractTokenCUID(TPSBuffer cplc_data) throws TPSException {
+ //Just make sure no one is inputing bogus cplc_data
+ if (cplc_data == null || cplc_data.size() < CPLC_DATA_SIZE) {
+ CMS.debug("TPS_Processor.extractTokenCUID: cplc_data: invalid length.");
+ throw new TPSException("TPSProcessor.extractTokenCUID: Can't extract cuid from cplc data!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ TPSBuffer token1 = cplc_data.substr(3, 4);
+ TPSBuffer token2 = cplc_data.substr(19, 2);
+ TPSBuffer token3 = cplc_data.substr(15, 4);
+
+ TPSBuffer token_cuid = new TPSBuffer();
+
+ token_cuid.add(token1);
+ token_cuid.add(token2);
+ token_cuid.add(token3);
+
+ return token_cuid;
+
+ }
+
+ /**
+ * Select applet.
+ *
+ * Global Platform Open Platform Card Specification
+ * Version 2.0.1 Page 9-22
+ *
+ * Sample Data:
+ *
+ * _____________ CLA
+ * | __________ INS
+ * | | _______ P1
+ * | | | ____ P2
+ * | | | | _ Len
+ * | | | | |
+ * 00 A4 04 00 07
+ * 53 4C 42 47 49 4E 41
+ *
+ * @throws IOException
+ * @throws TPSException
+ *
+ */
+
+ protected APDUResponse selectApplet(byte p1, byte p2, TPSBuffer aid) throws IOException, TPSException {
+
+ CMS.debug("In TPS_Processor.SelectApplet.");
+
+ if (aid == null || aid.size() == 0) {
+ throw new TPSException("TPSProcessor.selectApplet: Invalid aid value!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ SelectAPDU select_apdu = new SelectAPDU(p1, p2, aid);
+
+ //return the Response because the caller can
+ //decide what to do, not every failure is fatal.
+ //For instance the coolkey applet may not yet exist.
+ return handleAPDURequest(select_apdu);
+
+ }
+
+ protected TPSBuffer getStatus() throws IOException, TPSException {
+
+ CMS.debug("In TPS_Processor.GetStatus.");
+
+ GetStatusAPDU get_status_apdu = new GetStatusAPDU();
+
+ return handleAPDURequest(get_status_apdu).getData();
+ }
+
+ public APDUResponse handleAPDURequest(APDU apdu) throws IOException, TPSException {
+
+ if (apdu == null) {
+ throw new TPSException("TPSProcessor.handleAPDURequest: invalid incoming apdu!");
+ }
+
+ TokenPDURequestMsg request_msg = new TokenPDURequestMsg(apdu);
+
+ try {
+ session.write(request_msg);
+ } catch (IOException e) {
+ CMS.debug("TPS_Processor.HandleAPDURequest failed WriteMsg: " + e.toString());
+ throw e;
+
+ }
+
+ TokenPDUResponseMsg response_msg = null;
+
+ try {
+ response_msg = (TokenPDUResponseMsg) session.read();
+ } catch (IOException e) {
+ CMS.debug("TPS_Processor.HandleAPDURequest failed ReadMsg: " + e.toString());
+ throw e;
+
+ }
+
+ return response_msg.getResponseAPDU();
+ }
+
+ protected TPSBuffer getCplcData() throws IOException, TPSException {
+ CMS.debug("In TPS_Processor.GetData");
+
+ GetDataAPDU get_data_apdu = new GetDataAPDU();
+
+ APDUResponse respApdu = handleAPDURequest(get_data_apdu);
+
+ if (!respApdu.checkResult()) {
+ throw new TPSException("TPSProcessor.getCplcData: Can't get data!", TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+ TPSBuffer cplcData = respApdu.getData();
+
+ if (cplcData.size() != CPLC_DATA_SIZE) {
+ throw new TPSException("TPSProcessor.cplcData: Data invalid size!", TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ return respApdu.getData();
+ }
+
+ protected TPSBuffer getAppletVersion() throws IOException, TPSException {
+ //We return null if no applet present
+ // This is not an error, the token can be blank.
+
+ CMS.debug("In TPSProcessor.getAppletVersion");
+
+ GetVersionAPDU get_version_apdu = new GetVersionAPDU();
+
+ APDUResponse respApdu = handleAPDURequest(get_version_apdu);
+
+ if (!respApdu.checkResult()) {
+ CMS.debug("TPSProcessor.getAppletVersion: No applet version found on card!");
+ return null;
+ }
+
+ TPSBuffer apdu_data = respApdu.getData();
+
+ if (apdu_data.size() != 6) {
+ CMS.debug("TPSProcessor.getAppletVersion: incorrect return data size!");
+ throw new TPSException("TPSProcessor.getAppletVersion: invalid applet version string returned!");
+ }
+
+ TPSBuffer build_id = apdu_data.substr(0, 4);
+
+ CMS.debug("TPSProcessor.getAppletVersion: returning: " + build_id.toHexString());
+
+ return build_id;
+
+ }
+
+ protected TPSBuffer encryptData(AppletInfo appletInfo, TPSBuffer keyInfo, TPSBuffer plaintextChallenge,
+ String connId) throws TPSException {
+
+ TKSRemoteRequestHandler tks = null;
+
+ TKSEncryptDataResponse data = null;
+
+ try {
+ tks = new TKSRemoteRequestHandler(connId);
+ data = tks.encryptData(appletInfo.getCUID(), keyInfo, plaintextChallenge);
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.encryptData: Erorr getting wrapped data from TKS!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ int status = data.getStatus();
+
+ if (status != 0) {
+ throw new TPSException("TPSProcessor.computeRandomData: Erorr getting wrapped data from TKS!",
+ TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+ }
+
+ return data.getEncryptedData();
+ }
+
+ TPSBuffer computeRandomData(int dataSize, String connId) throws TPSException {
+
+ TKSRemoteRequestHandler tks = null;
+
+ TKSComputeRandomDataResponse data = null;
+
+ try {
+ tks = new TKSRemoteRequestHandler(connId);
+ data = tks.computeRandomData(dataSize);
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.computeRandomData: Erorr getting random data from TKS!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ int status = data.getStatus();
+
+ if (status != 0) {
+ throw new TPSException("TPSProcessor.computeRandomData: Erorr getting random data from TKS!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ return data.getRandomData();
+ }
+
+ protected TPSBuffer initializeUpdate(byte keyVersion, byte keyIndex, TPSBuffer randomData) throws IOException,
+ TPSException {
+
+ CMS.debug("In TPS_Processor.initializeUpdate.");
+ InitializeUpdateAPDU initUpdate = new InitializeUpdateAPDU(keyVersion, keyIndex, randomData);
+
+ APDUResponse resp = handleAPDURequest(initUpdate);
+
+ if (!resp.checkResult()) {
+ CMS.debug("TPSProcessor.initializeUpdate: Failed intializeUpdate!");
+ throw new TPSException("TPSBuffer.initializeUpdate: Failed initializeUpdate!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+
+ }
+
+ TPSBuffer data = resp.getResultDataNoCode();
+
+ if (data.size() != INIT_UPDATE_DATA_SIZE) {
+ throw new TPSException("TPSBuffer.initializeUpdate: Invalid response from token!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ return data;
+
+ }
+
+ protected SecureChannel setupSecureChannel() throws TPSException, IOException {
+ SecureChannel channel = null;
+
+ //Create a standard secure channel with current key set.
+ CMS.debug("TPSProcessor.setupSecureChannel: No arguments entering...");
+
+ int defKeyVersion = getChannelDefKeyVersion();
+ int defKeyIndex = getChannelDefKeyIndex();
+
+ channel = setupSecureChannel((byte) defKeyVersion, (byte) defKeyIndex, SecurityLevel.SECURE_MSG_MAC_ENC,
+ getTKSConnectorID());
+
+ channel.externalAuthenticate();
+
+ return channel;
+ }
+
+ protected SecureChannel setupSecureChannel(byte keyVersion, byte keyIndex, SecurityLevel securityLevel,
+ String connId)
+ throws IOException, TPSException {
+
+ //Assume generating host challenge on TKS, we no longer support not involving the TKS.
+
+ TPSBuffer randomData = computeRandomData(8, connId);
+ CMS.debug("TPSProcessor.setupSecureChannel: obtained randomData: " + randomData.toHexString());
+
+ TPSBuffer initUpdateResp = initializeUpdate(keyVersion, keyIndex, randomData);
+
+ TPSBuffer key_diversification_data = initUpdateResp.substr(0, DIVERSIFICATION_DATA_SIZE);
+ CMS.debug("TPSProcessor.setupSecureChannel: diversification data: " + key_diversification_data.toHexString());
+
+ TPSBuffer key_info_data = initUpdateResp.substr(DIVERSIFICATION_DATA_SIZE, 2);
+ CMS.debug("TPSProcessor.setupSecureChannel: key info data: " + key_info_data.toHexString());
+
+ TokenRecord tokenRecord = getTokenRecord();
+ tokenRecord.setKeyInfo(key_info_data.toHexStringPlain());
+
+ TPSBuffer card_cryptogram = initUpdateResp.substr(CARD_CRYPTOGRAM_OFFSET, CARD_CRYPTOGRAM_SIZE);
+ CMS.debug("TPSProcessor.setupSecureChannel: card cryptogram: " + card_cryptogram.toHexString());
+
+ TPSBuffer card_challenge = initUpdateResp.substr(CARD_CHALLENGE_OFFSET, CARD_CHALLENGE_SIZE);
+ CMS.debug("TPSProcessor.setupSecureChannel: card challenge: " + card_challenge.toHexString());
+
+ SecureChannel channel = null;
+
+ try {
+ channel = generateSecureChannel(connId, key_diversification_data, key_info_data, card_challenge,
+ card_cryptogram,
+ randomData);
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.setupSecureChannel: Can't set up secure channel: " + e,
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ return channel;
+
+ }
+
+ protected SecureChannel generateSecureChannel(String connId, TPSBuffer keyDiversificationData,
+ TPSBuffer keyInfoData, TPSBuffer cardChallenge, TPSBuffer cardCryptogram, TPSBuffer hostChallenge)
+ throws EBaseException, TPSException {
+
+ CMS.debug("TPSProcessor.generateSecureChannel: entering..");
+
+ TPSEngine engine = getTPSEngine();
+
+ SecureChannel channel = null;
+ TPSBuffer hostCryptogram = null;
+
+ TKSComputeSessionKeyResponse resp = engine.computeSessionKey(keyDiversificationData, keyInfoData,
+ cardChallenge, hostChallenge, cardCryptogram,
+ connId, getSelectedTokenType());
+
+ hostCryptogram = resp.getHostCryptogram();
+
+ if (hostCryptogram == null) {
+ new TPSException("TPSProcessor.generateSecureChannel: No host cryptogram returned from token!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+
+ }
+
+ PK11SymKey sharedSecret = null;
+
+ try {
+ sharedSecret = getSharedSecretTransportKey(connId);
+ } catch (Exception e) {
+ CMS.debug(e);
+ throw new TPSException("TPSProcessor.generateSecureChannel: Can't get shared secret key!: " + e,
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ PK11SymKey sessionKey = null;
+ PK11SymKey encSessionKey = null;
+ String tokenName = "Internal Key Storage Token";
+
+ try {
+ TPSBuffer sessionKeyWrapped = resp.getSessionKey();
+ TPSBuffer encSessionKeyWrapped = resp.getEncSessionKey();
+
+ sessionKey = SessionKey.UnwrapSessionKeyWithSharedSecret(tokenName, sharedSecret,
+ sessionKeyWrapped.toBytesArray());
+
+ if (sessionKey == null) {
+ CMS.debug("TPSProcessor.generateSecureChannel: Can't extract session key!");
+ throw new TPSException("TPSProcessor.generateSecureChannel: Can't extract session key!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+ CMS.debug("TPSProcessor.generateSecureChannel: retrieved session key: " + sessionKey);
+
+ encSessionKey = SessionKey.UnwrapSessionKeyWithSharedSecret(tokenName, sharedSecret,
+ encSessionKeyWrapped.toBytesArray());
+
+ if (encSessionKey == null) {
+ CMS.debug("TPSProcessor.generateSecureChannel: Can't extract enc session key!");
+ throw new TPSException("TPSProcessor.generateSecureChannel: Can't extract enc session key!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ CMS.debug("TPSProcessor.generateSecureChannel: retrieved enc session key: " + encSessionKey);
+ } catch (Exception e) {
+ CMS.debug(e);
+ e.printStackTrace();
+ throw new TPSException("TPSProcessor.generateSecureChannel: Problem extracting session keys! " + e,
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ TPSBuffer drmDesKey = null;
+ TPSBuffer kekDesKey = null;
+ TPSBuffer keyCheck = null;
+
+ drmDesKey = resp.getDRM_Trans_DesKey();
+ keyCheck = resp.getKeyCheck();
+ kekDesKey = resp.getKekWrappedDesKey();
+
+ if (checkServerSideKeyGen(connId)) {
+
+ CMS.debug("TPSProcessor.generateSecureChannel: drmDesKey: " + drmDesKey + " kekDesKey : " + kekDesKey
+ + " keyCheck: " + keyCheck);
+ //ToDo handle server side keygen.
+
+ }
+ channel = new SecureChannel(this, sessionKey, encSessionKey, drmDesKey,
+ kekDesKey, keyCheck, keyDiversificationData, cardChallenge,
+ cardCryptogram, hostChallenge, hostCryptogram, keyInfoData);
+
+ return channel;
+ }
+
+ protected void upgradeApplet(String operation, String new_version, SecurityLevel securityLevel,
+ Map<String, String> extensions, String connId, int startProgress, int endProgress) throws IOException,
+ TPSException {
+
+ TPSBuffer netkeyAIDBuff = null;
+ TPSBuffer cardMgrAIDBuff = null;
+ TPSBuffer netkeyPAIDBuff = null;
+
+ netkeyAIDBuff = getNetkeyAID();
+ netkeyPAIDBuff = getNetkeyPAID();
+ cardMgrAIDBuff = getCardManagerAID();
+
+ int channelBlockSize = getChannelBlockSize();
+ int channelInstanceSize = getChannelInstanceSize();
+ int channelAppletMemSize = getAppletMemorySize();
+ int defKeyVersion = getChannelDefKeyVersion();
+ int defKeyIndex = getChannelDefKeyIndex();
+
+ byte[] appletData = null;
+
+ TokenRecord tokenRecord = getTokenRecord();
+
+ String directory = getAppletDirectory(operation);
+
+ CMS.debug("TPSProcessor.upgradeApplet: applet target directory: " + directory);
+
+ String appletFileExt = getAppletExtension();
+
+ String appletFilePath = directory + "/" + new_version + "." + appletFileExt;
+
+ CMS.debug("TPSProcessor.upgradeApplet: targe applet file name: " + appletFilePath);
+
+ appletData = getAppletFileData(appletFilePath);
+
+ APDUResponse select = selectApplet((byte) 0x04, (byte) 0x00, cardMgrAIDBuff);
+
+ if (!select.checkResult()) {
+ throw new TPSException("TPSProcessor.upgradeApplet: Can't selelect the card manager!");
+ }
+
+ SecureChannel channel = setupSecureChannel((byte) defKeyVersion, (byte) defKeyIndex, securityLevel, connId);
+
+ channel.externalAuthenticate();
+ channel.deleteFileX(netkeyAIDBuff);
+ channel.deleteFileX(netkeyPAIDBuff);
+
+ // Next step will be to load the applet file to token.
+
+ TPSBuffer empty = new TPSBuffer();
+
+ channel.installLoad(netkeyPAIDBuff, empty, appletData.length);
+
+ TPSBuffer appletDataBuff = new TPSBuffer(appletData);
+
+ channel.loadFile(appletDataBuff, channelBlockSize, startProgress, endProgress);
+
+ channel.installApplet(netkeyPAIDBuff, netkeyAIDBuff, (byte) 0, channelInstanceSize, channelAppletMemSize);
+
+ //Now select our new applet
+
+ select = selectApplet((byte) 0x04, (byte) 0x00, netkeyAIDBuff);
+
+ if (!select.checkResult()) {
+ throw new TPSException("TPSProcessor.upgradeApplet: Cannot select newly created applet!",
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ }
+ tokenRecord.setAppletID(new_version);
+
+ }
+
+ public void selectCoolKeyApplet() throws TPSException, IOException {
+
+ TPSBuffer netkeyAIDBuff = getNetkeyAID();
+
+ APDUResponse select = selectApplet((byte) 0x04, (byte) 0x00, netkeyAIDBuff);
+
+ if (!select.checkResult()) {
+ CMS.debug("TPSProcessor.selectCoolKeyApplet: Can't select coolkey, token may be blank.");
+ /* throw new TPSException("TPSProcessor.upgradeApplet: Cannot select newly created applet!",
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ */
+ }
+ }
+
+ protected byte[] getAppletFileData(String appletFilePath) throws IOException, TPSException {
+
+ if (appletFilePath == null) {
+ throw new TPSException("TPSProcessor.getAppletFileData: Invalid applet file name.",
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ }
+
+ byte[] contents = null;
+ try {
+ Path path = Paths.get(appletFilePath);
+ contents = Files.readAllBytes(path);
+
+ } catch (IOException e) {
+ CMS.debug("TPSProcessor.getAppletFileData: IOException " + e);
+ throw e;
+ } catch (Exception e) {
+ CMS.debug("PSProcessor.getAppletFileData: Exception: " + e);
+ throw new TPSException("TPSProcessor.getAppletFileData: Exception: " + e,
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ }
+
+ CMS.debug("TPSProcessor.getAppletFileData: data: " + contents);
+
+ return contents;
+ }
+
+ /**
+ * getAuthentication gets Authentication per configuration
+ *
+ * @param prefix config prefix for tokenType
+ * @param tokenType the tokenType(profile)
+ * @return Authentication
+ */
+ public TPSAuthenticator getAuthentication(String prefix, String tokenType)
+ throws EBaseException {
+ CMS.debug("TPSProcessor.getAuthentication");
+ String auditMsg = null;
+
+ if (prefix.isEmpty() || tokenType.isEmpty()) {
+ auditMsg = "TPSProcessor.getAuthentication: missing parameters: prefix or tokenType";
+ CMS.debug(auditMsg);
+ throw new EBaseException(auditMsg);
+ }
+ IConfigStore configStore = CMS.getConfigStore();
+ String configName = prefix + "." + tokenType + ".auth.id";
+ String authId;
+
+ CMS.debug("TPSProcessor.getAuthentication: getting config: " +
+ configName);
+ authId = configStore.getString(configName);
+ if (authId == null) {
+ auditMsg = "TPSProcessor.getAuthentication: config param not found:" + configName;
+ CMS.debug(auditMsg);
+ throw new EBaseException(auditMsg);
+ }
+
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ TPSAuthenticator authInst =
+ subsystem.getAuthenticationManager().getAuthInstance(authId);
+ String authCredNameConf = "auths.instance." + authId + ".authCredName";
+ CMS.debug("TPSProcessor.getAuthentication: getting config: " +
+ authCredNameConf);
+ String authCredName = configStore.getString(authCredNameConf);
+ if (authCredName == null) {
+ auditMsg = "TPSProcessor.getAuthentication: config param not found:" + authCredNameConf;
+ CMS.debug(auditMsg);
+ throw new EBaseException(auditMsg);
+ }
+ authInst.setAuthCredName(authCredName);
+ return authInst;
+ }
+
+ /**
+ * authenticateUser authenticates a user using specified authentication
+ *
+ * @param op "enrollment", "format", or "pinReset" //TODO: for tokendb activity log
+ * @param userAuth the authenticator
+ * @param userCred IAuthCredentials obtained from a successful requestUserId call
+ * @return IAuthToken information relating to the performed authentication
+ * -- plugin-specific
+ */
+ public IAuthToken authenticateUser(
+ String op,
+ TPSAuthenticator userAuth,
+ IAuthCredentials userCred)
+ throws EBaseException, TPSException {
+ /**
+ * TODO: isExternalReg is not handled until decision made
+ */
+ String auditMsg = null;
+ CMS.debug("TPSProcessor.authenticateUser");
+ if (op.isEmpty() || userAuth == null || userCred == null) {
+ auditMsg = "TPSProcessor.authenticateUser: missing parameter(s): op, userAuth, or userCred";
+ CMS.debug(auditMsg);
+ throw new EBaseException(auditMsg);
+ }
+ IAuthManager auth = userAuth.getAuthManager();
+
+ try {
+ // Authenticate user
+ IAuthToken aToken = auth.authenticate(userCred);
+ if (aToken != null) {
+ CMS.debug("TPSProcessor.authenticateUser: authentication success");
+ return aToken;
+ } else {
+ CMS.debug("TPSProcessor.authenticateUser: authentication failure with aToken null");
+ throw new TPSException("TPS error user authentication failed.",
+ TPSStatus.STATUS_ERROR_LOGIN);
+ }
+ } catch (EBaseException e) {
+ CMS.debug("TPSProcessor.authenticateUser: authentication failure:" + e);
+ throw new TPSException("TPS error user authentication failed.",
+ TPSStatus.STATUS_ERROR_LOGIN);
+ }
+ }
+
+ /**
+ * requestUserId sends message to client to request for user credential
+ * per authentication plugin
+ *
+ * @param op "enrollment", "format", or "pinReset" //TODO: for tokendb activity log
+ * @param cuid token CUID //TODO: for tokendb activity log
+ * @param extensions message extensions
+ * @return IAuthCredentials containing user credential needed for authentication
+ */
+ IAuthCredentials requestUserId(String op, String cuid, TPSAuthenticator auth, Map<String, String> extensions)
+ throws IOException, TPSException, EBaseException {
+ CMS.debug("TPSProcessor.requestUserId");
+ if (op.isEmpty() ||
+ cuid.isEmpty() || auth == null) {
+ CMS.debug("TPSProcessor.requestUserId: missing parameter(s): op, cuid, or auth");
+ throw new EBaseException("TPSProcessor.requestUserId: missing parameter(s): op, cuid, or auth");
+ }
+
+ IAuthCredentials login;
+ if (extensions != null &&
+ extensions.get("extendedLoginRequest") != null) {
+ // default locale will be "en"
+ String locale = extensions.get("locale");
+ if (extensions.get("locale") == null) {
+ locale = "en";
+ }
+ // title
+ String title = auth.getUiTitle(locale);
+ if (title.isEmpty())
+ title = auth.getUiTitle("en");
+ // description
+ String description = auth.getUiDescription(locale);
+ if (description.isEmpty())
+ description = auth.getUiTitle("en");
+ // parameters
+ HashMap<String, AuthUIParameter> authParamSet = auth.getUiParamSet();
+ Set<String> params = new HashSet<String>();
+ for (Map.Entry<String, AuthUIParameter> entry : authParamSet.entrySet()) {
+ params.add(auth.getUiParam(entry.getKey()).toString(locale));
+ CMS.debug("TPSProcessor.requestUserId: for extendedLoginRequest, added param: " +
+ auth.getUiParam(entry.getKey()).toString(locale));
+ }
+
+ login = requestExtendedLogin(0 /* invalid_pw */, 0 /* blocked */,
+ params, title, description, auth);
+ } else {
+ login = requestLogin(0 /* invalid_pw */, 0 /* blocked */, auth);
+ }
+
+ return login;
+ }
+
+ /**
+ * mapCredFromMsgResponse fills up authManager required auth credentials
+ * with mapped values from client
+ * configuration example:
+ *
+ * auths.instance.ldap1.ui.id.UID.credMap.msgCred.extlogin=UID
+ * auths.instance.ldap1.ui.id.UID.credMap.msgCred.login=screen_name
+ * auths.instance.ldap1.ui.id.UID.credMap.authCred=uid
+ *
+ * auths.instance.ldap1.ui.id.PASSWORD.credMap.msgCred.extlogin=PASSWORD
+ * auths.instance.ldap1.ui.id.PASSWORD.credMap.msgCred.login=password
+ * auths.instance.ldap1.ui.id.PASSWORD.credMap.authCred=pwd
+ *
+ * @param response the message response to be mapped
+ * @param auth the authentication for mapping consultation
+ * @return IAuthCredentials auth credential for auth manager
+ */
+ public IAuthCredentials mapCredFromMsgResponse(TPSMessage response, TPSAuthenticator auth, boolean extendedLogin)
+ throws EBaseException {
+ CMS.debug("TPSProcessor.mapCredFromMsgResponse");
+ if (response == null || auth == null) {
+ CMS.debug("TPSProcessor.mapCredFromMsgResponse: missing parameter(s): response or auth");
+ throw new EBaseException("TPSProcessor.mapCredFromMsgResponse: missing parameter(s): response or auth");
+ }
+ IAuthCredentials login =
+ new com.netscape.certsrv.authentication.AuthCredentials();
+
+ String[] requiredCreds = auth.getAuthManager().getRequiredCreds();
+ for (String cred : requiredCreds) {
+ String name = auth.getCredMap(cred, extendedLogin);
+ CMS.debug("TPSProcessor.mapCredFromMsgResponse: cred=" + cred + " &name=" +
+ name);
+ login.set(cred, response.get(name));
+ }
+
+ return login;
+ }
+
+ /**
+ * Requests login ID and password from user.
+ */
+ public IAuthCredentials requestExtendedLogin(int invalidPW, int blocked,
+ Set<String> parameters,
+ String title,
+ String description,
+ TPSAuthenticator auth)
+ throws IOException, TPSException, EBaseException {
+
+ CMS.debug("TPSProcessor.requestExtendedLogin");
+ if (parameters == null || title.isEmpty() ||
+ description.isEmpty() || auth == null) {
+ CMS.debug("TPSProcessor.requestExtendedLogin: missing parameter(s): parameters, title, description, or auth");
+ throw new EBaseException(
+ "TPSProcessor.requestExtendedLogin: missing parameter(s): parameters, title, description, or auth");
+ }
+ ExtendedLoginRequestMsg loginReq =
+ new ExtendedLoginRequestMsg(invalidPW, blocked, parameters, title, description);
+
+ try {
+ session.write(loginReq);
+ } catch (IOException e) {
+ CMS.debug("TPSProcessor.requestExtendedLogin failed WriteMsg: " + e.toString());
+ throw e;
+ }
+ CMS.debug("TPSProcessor.requestExtendedLogin: extendedLoginRequest sent");
+
+ ExtendedLoginResponseMsg loginResp = null;
+ try {
+ loginResp = (ExtendedLoginResponseMsg) session.read();
+ } catch (IOException e) {
+ CMS.debug("TPSProcessor.requestExtendedLogin failed ReadMsg: " + e.toString());
+ throw e;
+ }
+
+ IAuthCredentials login = mapCredFromMsgResponse(loginResp, auth, true /*extendedLogin*/);
+
+ return login;
+ }
+
+ /**
+ * Requests login ID and password from user.
+ */
+ public IAuthCredentials requestLogin(int invalidPW, int blocked,
+ TPSAuthenticator auth)
+ throws IOException, TPSException, EBaseException {
+
+ CMS.debug("TPSProcessor.requestLogin");
+ if (auth == null) {
+ CMS.debug("TPSProcessor.requestLogin: missing parameter(s): parameters, title, description, or auth");
+ throw new EBaseException(
+ "TPSProcessor.requestLogin: missing parameter(s): parameters, title, description, or auth");
+ }
+ LoginRequestMsg loginReq = new LoginRequestMsg(invalidPW, blocked);
+
+ try {
+ session.write(loginReq);
+ } catch (IOException e) {
+ CMS.debug("TPSProcessor.requestLogin failed WriteMsg: " + e.toString());
+ throw e;
+ }
+ CMS.debug("TPSProcessor.requestLogin: loginRequest sent");
+
+ LoginResponseMsg loginResp = null;
+ try {
+ loginResp = (LoginResponseMsg) session.read();
+ } catch (IOException e) {
+ CMS.debug("TPSProcessor.requestLogin failed ReadMsg: " + e.toString());
+ throw e;
+ }
+
+ IAuthCredentials login = mapCredFromMsgResponse(loginResp, auth, false /*not extendedLogin*/);
+ return login;
+ }
+
+ /*
+ * fillTokenRecord -
+ * - retrieves token record from tokendb if it exists, or
+ * - creates a new token record
+ * this in-memory copy of tokenRecord is to be set in the TPSSession
+ */
+ protected void fillTokenRecord(TokenRecord tokenRecord, AppletInfo appletInfo)
+ throws TPSException {
+ String method = "TPSProcessor.fillTokenRecord";
+ CMS.debug(method + ": begins");
+ if (tokenRecord == null || appletInfo == null) {
+ CMS.debug(method + ": params tokenRecord and appletInfo cannot be null");
+ throw new TPSException(
+ method + ": missing parameter(s): parameter appletInfo");
+ }
+
+ byte app_major_version = appletInfo.getAppMajorVersion();
+ byte app_minor_version = appletInfo.getAppMinorVersion();
+ TPSBuffer build_id = null;
+ try {
+ build_id = getAppletVersion();
+ } catch (IOException e) {
+ CMS.debug(method + ": failed getting applet version:" + e + " ... continue");
+ }
+ if (build_id != null) {
+ tokenRecord.setAppletID(Integer.toHexString(app_major_version) + "."
+ + Integer.toHexString(app_minor_version) + "." +
+ build_id.toHexStringPlain());
+ }
+
+ CMS.debug(method + ": ends");
+
+ }
+
+ protected TokenRecord isTokenRecordPresent(AppletInfo appletInfo) throws TPSException {
+
+ if (appletInfo == null) {
+ throw new TPSException("TPSProcessor.isTokenRecordPresent: invalid input data.");
+ }
+
+ CMS.debug("TPSEnrollProcessor.isTokenRecordPresent: " + appletInfo.getCUIDhexString());
+
+ TPSSubsystem tps = (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ TokenRecord tokenRecord = null;
+ try {
+ tokenRecord = tps.tdb.tdbGetTokenEntry(appletInfo.getCUIDhexStringPlain());
+ // now the in memory tokenRecord is replaced by the actual token data
+ CMS.debug("TPSEnrollProcessor.enroll: found token...");
+ } catch (Exception e) {
+ CMS.debug("TPSEnrollProcessor.enroll: token does not exist in tokendb... create one in memory");
+ }
+
+ return tokenRecord;
+ }
+
+ protected String getCAConnectorID() throws TPSException {
+ IConfigStore configStore = CMS.getConfigStore();
+ String id = null;
+
+ String config = "op." + currentTokenOperation + "." + selectedTokenType + ".ca.conn";
+
+ try {
+ id = configStore.getString(config, "ca1");
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.getCAConnectorID: Internal error finding config value.");
+
+ }
+
+ CMS.debug("TPSProcessor.getCAConectorID: returning: " + id);
+
+ return id;
+ }
+
+ /*
+ * revokeCertsAtFormat returns a boolean that tells if config wants to revoke certs on the token during format
+ */
+ protected boolean revokeCertsAtFormat() {
+ String method = "revokeCertsAtFormat";
+ String auditMsg;
+ CMS.debug(method + ": begins");
+
+ IConfigStore configStore = CMS.getConfigStore();
+ String configName = TPSEngine.OP_FORMAT_PREFIX + "." + selectedTokenType + ".revokeCert";
+ boolean revokeCert = false;
+ try {
+ revokeCert = configStore.getBoolean(configName, false);
+ } catch (EBaseException e) {
+ auditMsg = method + ": config not found: " + configName +
+ "; default to false";
+ CMS.debug(auditMsg);
+ }
+ if (!revokeCert) {
+ auditMsg = method + ": revokeCert = false";
+ CMS.debug(auditMsg);
+ }
+ return revokeCert;
+ }
+
+ protected RevocationReason getRevocationReasonAtFormat() {
+ String method = "getRevocationReasonAtFormat";
+ String auditMsg;
+
+ IConfigStore configStore = CMS.getConfigStore();
+ String configName = TPSEngine.OP_FORMAT_PREFIX + "." + selectedTokenType + ".revokeCert.revokeReason";
+ RevocationReason revokeReason = RevocationReason.UNSPECIFIED;
+ try {
+ int revokeReasonInt = configStore.getInteger(configName);
+ revokeReason = RevocationReason.fromInt(revokeReasonInt);
+ } catch (EBaseException e) {
+ auditMsg = method + ": config not found: " + configName +
+ "; default to unspecified";
+ CMS.debug(auditMsg);
+ revokeReason = RevocationReason.UNSPECIFIED;
+ }
+
+ return revokeReason;
+ }
+
+ /*
+ * revokeCertificates revokes certificates on the token specified
+ * @param cuid the cuid of the token to revoke certificates
+ * @return auditMsg captures the audit message
+ * @throws TPSException in case of error
+ *
+ * TODO: maybe make this a callback function later
+ */
+ protected void revokeCertificates(String cuid, RevocationReason revokeReason, String caConnId) throws TPSException {
+ String auditMsg = "";
+ final String method = "TPSProcessor.revokeCertificates";
+
+ if (cuid == null) {
+ auditMsg = "cuid null";
+ CMS.debug(method + ":" + auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_REVOKE_CERTIFICATES_FAILED);
+ }
+ CMS.debug(method + ": begins for cuid:" + cuid);
+ TPSSubsystem tps = (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ boolean isTokenPresent = tps.tdb.isTokenPresent(cuid);
+ if (!isTokenPresent) {
+ auditMsg = method + ": token not found: " + cuid;
+ CMS.debug(auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_REVOKE_CERTIFICATES_FAILED);
+ }
+
+ CARemoteRequestHandler caRH = null;
+ try {
+ caRH = new CARemoteRequestHandler(caConnId);
+ } catch (EBaseException e) {
+ auditMsg = method + ": getting CARemoteRequestHandler failure";
+ CMS.debug(auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_REVOKE_CERTIFICATES_FAILED);
+ }
+ //find all certs belonging to the token
+ ArrayList<TPSCertRecord> certRecords = tps.tdb.tdbGetCertificatesByCUID(cuid);
+
+ CMS.debug(method + ": found " + certRecords.size() + " certs");
+
+ for (TPSCertRecord cert : certRecords) {
+ if (cert.getStatus().equals("revoked")) {
+ // already revoked cert should not be on token any more
+ CMS.debug(method + ": cert " + cert.getSerialNumber()
+ + " already revoked; remove from tokendb and move on");
+ try {
+ tps.certDatabase.removeRecord(cert.getId());
+ } catch (Exception e) {
+ auditMsg = method + ": removeRecord failed";
+ CMS.debug(auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_REVOKE_CERTIFICATES_FAILED);
+ }
+ continue;
+ }
+
+ String origin = cert.getOrigin();
+ if (origin != null && !origin.equals(cuid)) {
+ /*
+ * Raidzilla Bug #57803:
+ * If the certificate is not originally created for this
+ * token, we should not revoke the certificate here.
+ * To figure out if this certificate is originally created
+ * for this token, we check the tokenOrigin attribute.
+ */
+ CMS.debug(method + ": cert " + cert.getSerialNumber()
+ + " originally created for this token: " + origin +
+ " while current token: " + cuid
+ + "; Remove from tokendb and skip the revoke");
+ try {
+ tps.certDatabase.removeRecord(cert.getId());
+ } catch (Exception e) {
+ auditMsg = method + ": removeRecord failed";
+ CMS.debug(auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_REVOKE_CERTIFICATES_FAILED);
+ }
+ continue;
+ }
+ if (origin == null) {
+ // no tokenOrigin, then don't care, keep going
+ CMS.debug(method + ": tokenOrigin is not present in tokendb cert record");
+ }
+
+ // revoke the cert
+ /*
+ * if the certificates are revoked_on_hold, don't do anything because the certificates may
+ * be referenced by more than one token.
+ */
+ if (cert.getStatus().equals("revoked_on_hold")) {
+ CMS.debug(method + ": cert " + cert.getSerialNumber()
+ + " has status revoked_on_hold; remove from tokendb and move on");
+ try {
+ tps.certDatabase.removeRecord(cert.getId());
+ } catch (Exception e) {
+ auditMsg = method + ": removeRecord failed";
+ CMS.debug(auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_REVOKE_CERTIFICATES_FAILED);
+ }
+ continue;
+ }
+
+ String hexSerial = cert.getSerialNumber();
+ if (hexSerial.length() >= 3 && hexSerial.startsWith("0x")) {
+ String serial = hexSerial.substring(2); // skip over the '0x'
+ BigInteger bInt = new BigInteger(serial, 16);
+ String serialStr = bInt.toString();
+ CMS.debug(method + ": found cert hex serial: " + serial +
+ " dec serial:" + serialStr);
+ try {
+ CARevokeCertResponse response =
+ caRH.revokeCertificate(true, serialStr, cert.getCertificate(),
+ revokeReason);
+ CMS.debug(method + ": response status =" + response.getStatus());
+ } catch (EBaseException e) {
+ auditMsg = method + ": revokeCertificate from CA failed:" + e;
+ CMS.debug(auditMsg);
+
+ if (revokeReason == RevocationReason.CERTIFICATE_HOLD) {
+ tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, session.getTokenRecord(),
+ session.getIpAddress(), auditMsg,
+ "failure");
+ } else {
+ tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, session.getTokenRecord(),
+ session.getIpAddress(), auditMsg,
+ "failure");
+ }
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_REVOKE_CERTIFICATES_FAILED);
+ }
+ } else {
+ auditMsg = "mulformed hex serial number :" + hexSerial;
+ CMS.debug(method + ": " + auditMsg);
+ tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, session.getTokenRecord(), session.getIpAddress(),
+ auditMsg,
+ "failure");
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_REVOKE_CERTIFICATES_FAILED);
+ }
+ auditMsg = "Certificate " + hexSerial + " revoked";
+ tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, session.getTokenRecord(), session.getIpAddress(), auditMsg,
+ "success");
+
+ // delete cert from tokendb
+ CMS.debug(method + ": cert " + cert.getSerialNumber()
+ + ": remove from tokendb");
+ try {
+ tps.certDatabase.removeRecord(cert.getId());
+ } catch (Exception e) {
+ auditMsg = "removeRecord failed:" + e;
+ CMS.debug(method + ": " + auditMsg);
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_UPDATE_TOKENDB_FAILED);
+ }
+ continue;
+ }
+ CMS.debug(method + ": done for cuid:" + cuid);
+ }
+
+ protected void format(boolean skipAuth) throws TPSException, IOException {
+
+ String auditMsg = null;
+ String appletVersion = null;
+
+ TPSSubsystem tps = (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+
+ boolean isExternalReg = false;
+ AppletInfo appletInfo = null;
+ TokenRecord tokenRecord = null;
+ try {
+ appletInfo = getAppletInfo();
+ } catch (TPSException e) {
+ auditMsg = e.toString();
+ tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, tokenRecord, session.getIpAddress(), auditMsg,
+ "failure");
+
+ throw e;
+ }
+ appletInfo.setAid(getCardManagerAID());
+
+ CMS.debug("TPSProcessor.format: token cuid: " + appletInfo.getCUIDhexStringPlain());
+ boolean isTokenPresent = false;
+
+ tokenRecord = isTokenRecordPresent(appletInfo);
+
+ if (tokenRecord != null) {
+ CMS.debug("TPSProcessor.format: found token...");
+ isTokenPresent = true;
+ } else {
+ CMS.debug("TPSProcessor.format: token does not exist in tokendb... create one in memory");
+ tokenRecord = new TokenRecord();
+ tokenRecord.setId(appletInfo.getCUIDhexStringPlain());
+ }
+
+ fillTokenRecord(tokenRecord, appletInfo);
+ session.setTokenRecord(tokenRecord);
+
+ String cuid = appletInfo.getCUIDhexString();
+ CMS.debug("TPSProcessor.format: CUID hex string=" + appletInfo.getCUIDhexStringPlain());
+ //tokenRecord.setId(appletInfo.getCUIDhexString(true));
+ String msn = appletInfo.getMSNString();
+
+ byte major_version = appletInfo.getMajorVersion();
+ byte minor_version = appletInfo.getMinorVersion();
+ byte app_major_version = appletInfo.getAppMajorVersion();
+ byte app_minor_version = appletInfo.getAppMinorVersion();
+
+ CMS.debug("TPSProcessor.format: major_version " + major_version + " minor_version: " + minor_version
+ + " app_major_version: " + app_major_version + " app_minor_version: " + app_minor_version);
+
+ String tokenType = "tokenType";
+ String resolverInstName = getResolverInstanceName();
+
+ IAuthCredentials userCred =
+ new com.netscape.certsrv.authentication.AuthCredentials();
+ if (isExternalReg) {
+ //ToDo, do some external Reg stuff along with authentication
+ tokenType = "externalRegAddToToken";
+ } else {
+ CMS.debug("In TPSProcessor.format isExternalReg: OFF");
+ /*
+ * Note: op.format.tokenProfileResolver=none indicates no resolver
+ * plugin used (tokenType resolved perhaps via authentication)
+ */
+
+ try {
+ tokenType = resolveTokenProfile(resolverInstName, cuid, msn, major_version, minor_version);
+ } catch (TPSException e) {
+ auditMsg = e.toString();
+ tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, tokenRecord, session.getIpAddress(), auditMsg,
+ "failure");
+
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+ }
+ CMS.debug("TPSProcessor.format: calculated tokenType: " + tokenType);
+ }
+
+ // isExternalReg : user already authenticated earlier
+ if (!isExternalReg) {
+ // authenticate per profile/tokenType configuration
+ String configName = TPSEngine.OP_FORMAT_PREFIX + "." + tokenType + ".auth.enable";
+ IConfigStore configStore = CMS.getConfigStore();
+ boolean isAuthRequired;
+ try {
+ CMS.debug("TPSProcessor.format: getting config: " + configName);
+ isAuthRequired = configStore.getBoolean(configName, true);
+ } catch (EBaseException e) {
+ CMS.debug("TPSProcessor.format: Internal Error obtaining mandatory config values. Error: " + e);
+ auditMsg = "TPS error getting config values from config store." + e.toString();
+ tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, tokenRecord, session.getIpAddress(), auditMsg,
+ "failure");
+
+ throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+ }
+
+ if (isAuthRequired && !skipAuth) {
+ try {
+ TPSAuthenticator userAuth =
+ getAuthentication(TPSEngine.OP_FORMAT_PREFIX, tokenType);
+ userCred = requestUserId("format", cuid, userAuth, beginMsg.getExtensions());
+ userid = (String) userCred.get(userAuth.getAuthCredName());
+ CMS.debug("TPSProcessor.format: userCred (attempted) userid=" + userid);
+ // initialize userid first for logging purposes in case authentication fails
+ tokenRecord.setUserID(userid);
+ IAuthToken authToken = authenticateUser("format", userAuth, userCred);
+ userid = authToken.getInString("userid");
+ tokenRecord.setUserID(userid);
+ CMS.debug("TPSProcessor.format:: auth token userid=" + userid);
+ // TODO: should check if userid match?
+ } catch (Exception e) {
+ // all exceptions are considered login failure
+ CMS.debug("TPSProcessor.format:: authentication exception thrown: " + e);
+ auditMsg = "authentication failed, status = STATUS_ERROR_LOGIN";
+
+ tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, tokenRecord, session.getIpAddress(), auditMsg,
+ "failure");
+
+ throw new TPSException(auditMsg,
+ TPSStatus.STATUS_ERROR_LOGIN);
+ }
+ } // TODO: if no auth required, should wipe out existing tokenRecord entry data later?
+ }
+
+ /**
+ * TODO:
+ * isExternalReg is not handled beyond this point until decided
+ */
+
+ //Now check provided profile
+
+ checkProfileStateOK();
+
+ if (isTokenPresent) {
+ CMS.debug("TPSProcessor.format: token exists");
+ TokenStatus newState = TokenStatus.UNINITIALIZED;
+ // Check for transition to 0/UNINITIALIZED status.
+
+ if (!tps.engine.isOperationTransitionAllowed(tokenRecord.getTokenStatus(), newState)) {
+ CMS.debug("TPSProcessor.format: token transition disallowed " +
+ tokenRecord.getTokenStatus() +
+ " to " + newState);
+ auditMsg = "Operation for CUID " + appletInfo.getCUIDhexStringPlain() +
+ " Disabled, illegal transition attempted " + tokenRecord.getTokenStatus() +
+ " to " + newState;
+
+ tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, tokenRecord, session.getIpAddress(), auditMsg,
+ "failure");
+
+ throw new TPSException(auditMsg,
+ TPSStatus.STATUS_ERROR_DISABLED_TOKEN);
+ } else {
+ CMS.debug("TPSProcessor.format: token transition allowed " +
+ tokenRecord.getTokenStatus() +
+ " to " + newState);
+ }
+ } else {
+ CMS.debug("TPSProcessor.format: token does not exist");
+
+ checkAllowUnknownToken(TPSEngine.OP_FORMAT_PREFIX);
+ }
+
+ TPSBuffer build_id = getAppletVersion();
+
+ if (build_id == null) {
+ checkAllowNoAppletToken(TPSEngine.OP_FORMAT_PREFIX);
+ } else {
+ appletVersion = Integer.toHexString(app_major_version) + "." + Integer.toHexString(app_minor_version) + "."
+ + build_id.toHexString();
+ }
+
+ String appletRequiredVersion = checkForAppletUpgrade(TPSEngine.OP_FORMAT_PREFIX);
+
+ CMS.debug("TPSProcessor.format: appletVersion found: " + appletVersion + " requiredVersion: "
+ + appletRequiredVersion);
+
+ SecurityLevel secLevel = SecurityLevel.SECURE_MSG_MAC_ENC;
+
+ String tksConnId = getTKSConnectorID();
+
+ upgradeApplet(TPSEngine.OP_FORMAT_PREFIX, appletRequiredVersion, secLevel,
+ beginMsg.getExtensions(), tksConnId,
+ 10, 90);
+ CMS.debug("TPSProcessor.format: Completed applet upgrade.");
+
+ // Add issuer info to the token
+
+ writeIssuerInfoToToken(null);
+
+ if (requiresStatusUpdate()) {
+ statusUpdate(100, "PROGRESS_DONE");
+ }
+
+ // Upgrade Symm Keys if needed
+
+ SecureChannel channel = checkAndUpgradeSymKeys();
+ channel.externalAuthenticate();
+ tokenRecord.setKeyInfo(channel.getKeyInfoData().toHexStringPlain());
+
+ if (isTokenPresent && revokeCertsAtFormat()) {
+ // Revoke certificates on token, if so configured
+ RevocationReason reason = getRevocationReasonAtFormat();
+ String caConnId = getCAConnectorID();
+
+ try {
+ revokeCertificates(tokenRecord.getId(), reason, caConnId);
+ } catch (TPSException te) {
+ // failed revocation; capture message and continue
+ auditMsg = te.getMessage();
+ }
+ }
+
+ // Update Token DB
+ tokenRecord.setStatus("uninitialized");
+ try {
+ tps.tdb.tdbUpdateTokenEntry(tokenRecord);
+ String successMsg = "update token success";
+ tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, tokenRecord, session.getIpAddress(), successMsg,
+ "success");
+ } catch (Exception e) {
+ String failMsg = "update token failure";
+ auditMsg = failMsg + ":" + e.toString();
+ tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, tokenRecord, session.getIpAddress(), failMsg,
+ "failure");
+
+ throw new TPSException(auditMsg);
+ }
+
+ auditMsg = "format operation succeeded";
+
+ tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, tokenRecord, session.getIpAddress(), auditMsg, "success");
+
+ CMS.debug("TPSProcessor.format:: ends");
+
+ }
+
+ protected void writeIssuerInfoToToken(SecureChannel origChannel) throws TPSException, IOException,
+ UnsupportedEncodingException {
+ if (checkIssuerInfoEnabled()) {
+
+ SecurityLevel secLevel = SecurityLevel.SECURE_MSG_MAC_ENC;
+
+ String tksConnId = getTKSConnectorID();
+
+ int defKeyIndex = getChannelDefKeyIndex();
+ int defKeyVersion = getChannelDefKeyVersion();
+
+ SecureChannel channel = null;
+
+ if (origChannel != null) {
+ channel = origChannel;
+ } else {
+
+ channel = setupSecureChannel((byte) defKeyVersion, (byte) defKeyIndex, secLevel, tksConnId);
+ channel.externalAuthenticate();
+
+ }
+
+ String issuer = getIssuerInfoValue();
+
+ // We know this better be ASCII value URL.
+ byte[] issuer_bytes = issuer.getBytes("US-ASCII");
+ TPSBuffer issuerInfoBuff = new TPSBuffer(issuer_bytes);
+
+ channel.setIssuerInfo(issuerInfoBuff);
+
+ }
+ }
+
+ protected String getResolverInstanceName() throws TPSException {
+
+ CMS.debug("TPSProcessor.getResolverInstanceName: entering for operaiton : " + currentTokenOperation);
+ IConfigStore configStore = CMS.getConfigStore();
+ String resolverInstName = null;
+
+ String opPrefix = null;
+ String opDefault = null;
+
+ if (currentTokenOperation.equals(TPSEngine.FORMAT_OP)) {
+ opPrefix = TPSEngine.OP_FORMAT_PREFIX;
+ opDefault = TPSEngine.CFG_DEF_FORMAT_PROFILE_RESOLVER;
+
+ } else if (currentTokenOperation.equals(TPSEngine.ENROLL_OP)) {
+ opDefault = TPSEngine.CFG_DEF_ENROLL_PROFILE_RESOLVER;
+ opPrefix = TPSEngine.OP_ENROLL_PREFIX;
+ } else if (currentTokenOperation.equals(TPSEngine.PIN_RESET_OP)) {
+
+ opDefault = TPSEngine.CFG_DEF_PIN_RESET_PROFILE_RESOLVER;
+ opPrefix = TPSEngine.OP_PIN_RESET_PREFIX;
+ }
+
+ String config = opPrefix +
+ "." + TPSEngine.CFG_PROFILE_RESOLVER;
+
+ CMS.debug("TPSProcessor.getResolverInstanceName: config: " + config);
+ try {
+ resolverInstName = configStore.getString(config, opDefault);
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.getResolverInstanceName: Internal error finding config value.");
+
+ }
+
+ CMS.debug("TPSProcessor.getResolverInstanceName: returning: " + resolverInstName);
+
+ return resolverInstName;
+ }
+
+ /**
+ * @param resolverInstName
+ * @param cuid
+ * @param msn
+ * @param major_version
+ * @param minor_version
+ * @return
+ */
+ protected String resolveTokenProfile(
+ String resolverInstName,
+ String cuid,
+ String msn,
+ byte major_version,
+ byte minor_version)
+ throws TPSException {
+ String tokenType;
+
+ if (!resolverInstName.equals("none") && (selectedTokenType == null)) {
+
+ try {
+ TokenProfileParams pParams = new TokenProfileParams();
+ CMS.debug("In TPSProcessor.resolveTokenProfile : after new TokenProfileParams");
+ pParams.set(TokenProfileParams.PROFILE_PARAM_MAJOR_VERSION,
+ String.valueOf(major_version));
+ pParams.set(TokenProfileParams.PROFILE_PARAM_MINOR_VERSION,
+ String.valueOf(minor_version));
+ pParams.set(TokenProfileParams.PROFILE_PARAM_CUID, cuid);
+ pParams.set(TokenProfileParams.PROFILE_PARAM_MSN, msn);
+ if (beginMsg.getExtensions() != null) {
+ pParams.set(TokenProfileParams.PROFILE_PARAM_EXT_TOKEN_TYPE,
+ beginMsg.getExtensions().get("tokenType"));
+ pParams.set(TokenProfileParams.PROFILE_PARAM_EXT_TOKEN_ATR,
+ beginMsg.getExtensions().get("tokenATR"));
+ }
+ CMS.debug("In TPSProcessor.resolveTokenProfile : after setting TokenProfileParams");
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+ BaseTokenProfileResolver resolverInst =
+ subsystem.getProfileResolverManager().getResolverInstance(resolverInstName);
+ tokenType = resolverInst.getTokenType(pParams);
+ CMS.debug("In TPSProcessor.resolveTokenProfile : profile resolver result: " + tokenType);
+ setSelectedTokenType(tokenType);
+ } catch (EBaseException et) {
+ CMS.debug("In TPSProcessor.resolveTokenProfile exception:" + et);
+ throw new TPSException("TPSProcessor.resolveTokenProfile failed.",
+ TPSStatus.STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND);
+ }
+
+ } else {
+ //Already have a token type, return it
+ tokenType = getSelectedTokenType();
+ }
+
+ return tokenType;
+ }
+
+ protected String getIssuerInfoValue() throws TPSException {
+ IConfigStore configStore = CMS.getConfigStore();
+ String info = null;
+
+ String config = "op." + currentTokenOperation + "." + selectedTokenType + "." + TPSEngine.CFG_ISSUER_INFO_VALUE;
+
+ CMS.debug("TPSProcessor.getIssuerInfoValue: config: " + config);
+ try {
+ info = configStore.getString(config, null);
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.getIssuerInfoValue: Internal error finding config value.");
+
+ }
+
+ if (info == null) {
+ throw new TPSException("TPSProcessor.getIssuerInfoValue: Can't find issuer info value in the config.",
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ }
+
+ CMS.debug("TPSProcessor.getIssuerInfoValue: returning: " + info);
+
+ return info;
+ }
+
+ void checkProfileStateOK() throws TPSException {
+
+ IConfigStore configStore = CMS.getConfigStore();
+
+ String profileConfig = "config.Profiles." + selectedTokenType + ".state";
+ String profileState = null;
+
+ try {
+ profileState = configStore.getString(profileConfig, TPSEngine.CFG_ENABLED);
+ } catch (EBaseException e) {
+ //Default TPSException will return a "contact admin" error code.
+ throw new TPSException(
+ "TPSProcessor.checkProfileStateOK: internal error in getting profile state from config.");
+ }
+
+ if (!profileState.equals(TPSEngine.CFG_ENABLED)) {
+ CMS.debug("TPSProcessor.checkProfileStateOK: profile specifically disabled.");
+ throw new TPSException("TPSProcessor.checkProfileStateOK: profile disabled!");
+ }
+
+ }
+
+ protected boolean checkIssuerInfoEnabled() throws TPSException {
+
+ CMS.debug("TPSProcessor.checkIssuerEnabled entering...");
+
+ IConfigStore configStore = CMS.getConfigStore();
+
+ String issuerEnabledConfig = "op." + currentTokenOperation + "." + selectedTokenType + "."
+ + TPSEngine.CFG_ISSUER_INFO_ENABLE;
+
+ CMS.debug("TPSProcessor.checkIssuerEnabled config to check: " + issuerEnabledConfig);
+
+ boolean issuerInfoEnabled = false;
+
+ try {
+ issuerInfoEnabled = configStore.getBoolean(issuerEnabledConfig, false);
+ } catch (EBaseException e) {
+ //Default TPSException will return a "contact admin" error code.
+ throw new TPSException(
+ "TPSProcessor.checkIssuerInfo: internal error in getting value from config.");
+ }
+
+ CMS.debug("TPSProcessor.checkIssuerEnabled returning: " + issuerInfoEnabled);
+ return issuerInfoEnabled;
+
+ }
+
+ //Obtain value and set class property.
+ protected void checkIsExternalReg() throws TPSException {
+
+ IConfigStore configStore = CMS.getConfigStore();
+ String External_Reg_Cfg = TPSEngine.CFG_EXTERNAL_REG + "." + "enable";
+
+ try {
+ //These defaults are well known, it is safe to use them.
+
+ CMS.debug("In TPS_Processor.checkIsExternalReg.");
+
+ this.isExternalReg = configStore.getBoolean(External_Reg_Cfg, false);
+ CMS.debug("In TPS_Processor.checkIsExternalReg. isExternalReg: " + isExternalReg);
+ } catch (EBaseException e1) {
+ CMS.debug("TPS_Processor.checkIsExternalReg: Internal Error obtaining mandatory config values. Error: "
+ + e1);
+ throw new TPSException("TPS error getting config values from config store.");
+ }
+
+ }
+
+ boolean checkServerSideKeyGen(String connId) throws TPSException {
+
+ boolean result;
+ IConfigStore configStore = CMS.getConfigStore();
+
+ String profileConfig = "conn." + connId + "." + ".serverKeygen";
+
+ try {
+ result = configStore.getBoolean(profileConfig, false);
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor: checkServerSideKeyGen: Internal error obtaining config value!");
+ }
+
+ return result;
+ }
+
+ void checkAllowNoAppletToken(String operation) throws TPSException {
+ boolean allow = true;
+ IConfigStore configStore = CMS.getConfigStore();
+
+ String noAppletConfig = operation + "." + selectedTokenType + "." + TPSEngine.CFG_ALLOW_NO_APPLET;
+
+ try {
+ allow = configStore.getBoolean(noAppletConfig, true);
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.checkAllowNoAppletToken: Internal error getting config param.");
+ }
+
+ if (!allow) {
+ throw new TPSException("TPSProcessor.checkAllowNoAppletToken: token without applet not permitted!",
+ TPSStatus.STATUS_ERROR_CONTACT_ADMIN);
+ }
+
+ }
+
+ boolean checkForAppletUpdateEnabled() throws TPSException {
+ boolean enabled = false;
+
+ IConfigStore configStore = CMS.getConfigStore();
+
+ String appletUpdate = "op." + currentTokenOperation + "." + selectedTokenType + "."
+ + TPSEngine.CFG_UPDATE_APPLET_ENABLE;
+ CMS.debug("TPSProcessor.checkForAppletUpdateEnabled: getting config: " + appletUpdate);
+ try {
+ enabled = configStore.getBoolean(appletUpdate, false);
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "TPSProcessor.checkForAppleUpdateEnabled: Can't find applet Update Enable. Internal error obtaining value.",
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+
+ }
+ CMS.debug("TPSProcessor.checkForAppletUpdateEnabled: returning " + enabled);
+ return enabled;
+ }
+
+ protected String checkForAppletUpgrade(String operation) throws TPSException {
+ String requiredVersion = null;
+ IConfigStore configStore = CMS.getConfigStore();
+
+ String appletRequiredConfig = operation + "." + selectedTokenType + "."
+ + TPSEngine.CFG_APPLET_UPDATE_REQUIRED_VERSION;
+ CMS.debug("TPSProcessor.checkForAppletUpgrade: getting config: " + appletRequiredConfig);
+ try {
+ requiredVersion = configStore.getString(appletRequiredConfig, null);
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "TPSProcessor.checkForAppletUpgrade: Can't find applet required Version. Internal error obtaining version.",
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ }
+
+ if (requiredVersion == null) {
+ throw new TPSException("TPSProcessor.checkForAppletUpgrade: Can't find applet required Version.",
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ }
+
+ CMS.debug("TPSProcessor.checkForAppletUpgrade: returning: " + requiredVersion);
+
+ return requiredVersion;
+ }
+
+ protected void checkAllowUnknownToken(String operation) throws TPSException {
+ boolean allow = true;
+
+ IConfigStore configStore = CMS.getConfigStore();
+
+ String unknownConfig = "op." + operation + "." + TPSEngine.CFG_ALLOW_UNKNOWN_TOKEN;
+
+ try {
+ allow = configStore.getBoolean(unknownConfig, true);
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.checkAllowUnknownToken: Internal error getting config value.");
+ }
+
+ if (allow == false) {
+ throw new TPSException(
+ "TPSProcessor.checkAllowUnknownToken: Unknown tokens not allowed for this operation!",
+ TPSStatus.STATUS_ERROR_TOKEN_DISABLED);
+ }
+
+ }
+
+ protected String getTKSConnectorID() throws TPSException {
+ IConfigStore configStore = CMS.getConfigStore();
+ String id = null;
+
+ String config = "op." + currentTokenOperation + "." + selectedTokenType + ".tks.conn";
+
+ try {
+ id = configStore.getString(config, "tks1");
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.getTKSConnectorID: Internal error finding config value.");
+
+ }
+
+ CMS.debug("TPSProcessor.getTKSConectorID: returning: " + id);
+
+ return id;
+ }
+
+ protected TPSBuffer getNetkeyAID() throws TPSException {
+
+ String NetKeyAID = null;
+ IConfigStore configStore = CMS.getConfigStore();
+ try {
+
+ NetKeyAID = configStore.getString(TPSEngine.CFG_APPLET_NETKEY_INSTANCE_AID,
+ TPSEngine.CFG_DEF_NETKEY_INSTANCE_AID);
+
+ } catch (EBaseException e1) {
+ CMS.debug("TPS_Processor.getNetkeyAID: Internal Error obtaining mandatory config values. Error: " + e1);
+ throw new TPSException("TPS error getting config values from config store.");
+ }
+
+ TPSBuffer ret = new TPSBuffer(NetKeyAID);
+
+ return ret;
+ }
+
+ protected TPSBuffer getNetkeyPAID() throws TPSException {
+
+ String NetKeyPAID = null;
+ IConfigStore configStore = CMS.getConfigStore();
+ try {
+
+ NetKeyPAID = configStore.getString(
+ TPSEngine.CFG_APPLET_NETKEY_FILE_AID, TPSEngine.CFG_DEF_NETKEY_FILE_AID);
+
+ } catch (EBaseException e1) {
+ CMS.debug("TPS_Processor.getNetkeyAID: Internal Error obtaining mandatory config values. Error: " + e1);
+ throw new TPSException("TPS error getting config values from config store.");
+ }
+
+ TPSBuffer ret = new TPSBuffer(NetKeyPAID);
+
+ return ret;
+ }
+
+ protected TPSBuffer getCardManagerAID() throws TPSException {
+
+ String cardMgrAID = null;
+ IConfigStore configStore = CMS.getConfigStore();
+ try {
+
+ cardMgrAID = configStore.getString(TPSEngine.CFG_DEF_CARDMGR_INSTANCE_AID,
+ TPSEngine.CFG_DEF_CARDMGR_INSTANCE_AID);
+
+ } catch (EBaseException e1) {
+ CMS.debug("TPS_Processor.getNetkeyAID: Internal Error obtaining mandatory config values. Error: " + e1);
+ throw new TPSException("TPS error getting config values from config store.");
+ }
+
+ TPSBuffer ret = new TPSBuffer(cardMgrAID);
+
+ return ret;
+ }
+
+ protected String getAppletExtension() throws TPSException {
+ IConfigStore configStore = CMS.getConfigStore();
+ String extension = null;
+ String extensionConfig = TPSEngine.CFG_APPLET_EXTENSION;
+
+ try {
+ extension = configStore.getString(extensionConfig, "ijc");
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.getAppletExtension: Internal error finding config value.");
+
+ }
+
+ CMS.debug("TPSProcessor.getAppletExtension: returning: " + extension);
+
+ return extension;
+ }
+
+ protected String getAppletDirectory(String operation) throws TPSException {
+
+ IConfigStore configStore = CMS.getConfigStore();
+ String directory = null;
+
+ String directoryConfig = operation + "." + selectedTokenType + "." + TPSEngine.CFG_APPLET_DIRECTORY;
+
+ //We need a directory
+ try {
+ directory = configStore.getString(directoryConfig);
+ } catch (EPropertyNotFound e) {
+ throw new TPSException("TPSProcessor.getAppletDirectory: Required config param missing.",
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.getAppletDirectory: Internal error finding config value.",
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ }
+
+ CMS.debug("getAppletDirectory: returning: " + directory);
+ return directory;
+ }
+
+ protected int getChannelBlockSize() throws TPSException {
+ IConfigStore configStore = CMS.getConfigStore();
+ int blockSize = 0;
+ try {
+ blockSize = configStore.getInteger(TPSEngine.CFG_CHANNEL_BLOCK_SIZE, TPSEngine.CFG_CHANNEL_DEF_BLOCK_SIZE);
+
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.getChannelBlockSize: Internal error finding config value: " + e,
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+
+ }
+
+ CMS.debug("TPSProcess.getChannelBlockSize: returning: " + blockSize);
+ return blockSize;
+
+ }
+
+ protected int getChannelInstanceSize() throws TPSException {
+ IConfigStore configStore = CMS.getConfigStore();
+ int instanceSize = 0;
+ try {
+ instanceSize = configStore.getInteger(TPSEngine.CFG_CHANNEL_INSTANCE_SIZE,
+ TPSEngine.CFG_CHANNEL_DEF_INSTANCE_SIZE);
+
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.getChannelInstanceSize: Internal error finding config value: " + e,
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+
+ }
+
+ CMS.debug("TPSProcess.getChannelInstanceSize: returning: " + instanceSize);
+
+ return instanceSize;
+
+ }
+
+ protected int getAppletMemorySize() throws TPSException {
+ IConfigStore configStore = CMS.getConfigStore();
+ int memSize = 0;
+ try {
+ memSize = configStore.getInteger(TPSEngine.CFG_CHANNEL_APPLET_MEMORY_SIZE,
+ TPSEngine.CFG_CHANNEL_DEF_APPLET_MEMORY_SIZE);
+
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.getAppletMemorySize: Internal error finding config value: " + e,
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+
+ }
+ CMS.debug("TPSProcess.getAppletMemorySize: returning: " + memSize);
+
+ return memSize;
+ }
+
+ protected int getChannelDefKeyVersion() throws TPSException {
+ IConfigStore configStore = CMS.getConfigStore();
+ int ver = 0;
+ try {
+ ver = configStore.getInteger(TPSEngine.CFG_CHANNEL_DEFKEY_VERSION, 0x0);
+
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.getChannelDefKeyVersion: Internal error finding config value: " + e,
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+
+ }
+
+ CMS.debug("TPSProcessor.getChannelDefKeyVersion: " + ver);
+
+ return ver;
+
+ }
+
+ protected int getChannelDefKeyIndex() throws TPSException {
+ IConfigStore configStore = CMS.getConfigStore();
+ int index = 0;
+ try {
+ index = configStore.getInteger(TPSEngine.CFG_CHANNEL_DEFKEY_INDEX, 0x0);
+
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.getChannelDefKeyVersion: Internal error finding config value: " + e,
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+
+ }
+
+ CMS.debug("TPSProcessor.getChannelDefKeyIndex: " + index);
+
+ return index;
+
+ }
+
+ protected PK11SymKey getSharedSecretTransportKey(String connId) throws TPSException, NotInitializedException {
+
+ IConfigStore configStore = CMS.getConfigStore();
+ String sharedSecretName = null;
+ try {
+ String configName = "conn." + connId + ".tksSharedSymKeyName";
+ sharedSecretName = configStore.getString(configName, "sharedSecret");
+
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.getSharedSecretTransportKey: Internal error finding config value: "
+ + e,
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+
+ }
+
+ CMS.debug("TPSProcessor.getSharedSecretTransportKey: calculated key name: " + sharedSecretName);
+
+ String symmKeys = null;
+ boolean keyPresent = false;
+ try {
+ symmKeys = SessionKey.ListSymmetricKeys("internal");
+ CMS.debug("TPSProcessor.getSharedSecretTransportKey: symmKeys List: " + symmKeys);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ CMS.debug(e);
+ }
+
+ for (String keyName : symmKeys.split(",")) {
+ if (sharedSecretName.equals(keyName)) {
+ CMS.debug("TPSProcessor.getSharedSecret: shared secret key found!");
+ keyPresent = true;
+ break;
+ }
+
+ }
+
+ if (!keyPresent) {
+ throw new TPSException("TPSProcessor.getSharedSecret: Can't find shared secret!",
+ TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+ }
+
+ // We know for now that shared secret is on this token
+ String tokenName = "Internal Key Storage Token";
+ PK11SymKey sharedSecret = SessionKey.GetSymKeyByName(tokenName, sharedSecretName);
+
+ CMS.debug("TPSProcessor.getSharedSecret: SymKey returns: " + sharedSecret);
+
+ return sharedSecret;
+
+ }
+
+ public boolean getIsExternalReg() {
+ return isExternalReg;
+ }
+
+ public void process(BeginOpMsg beginMsg) throws TPSException, IOException {
+
+ if (beginMsg == null) {
+ throw new TPSException("TPSProcessor.process: invalid input data, not beginMsg provided.",
+ TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+ }
+ setBeginMessage(beginMsg);
+ setCurrentTokenOperation("format");
+ checkIsExternalReg();
+
+ format(false);
+ }
+
+ public void statusUpdate(int status, String info) throws IOException {
+
+ if (!requiresStatusUpdate())
+ return;
+
+ CMS.debug("In TPSProcessor.statusUpdate status: " + status + " info: " + info);
+
+ StatusUpdateRequestMsg statusUpdate = new StatusUpdateRequestMsg(status, info);
+ session.write(statusUpdate);
+
+ //We don't really care about the response, just that we get it.
+
+ session.read();
+
+ }
+
+ public TPSEngine getTPSEngine() {
+ TPSSubsystem subsystem =
+ (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+
+ return subsystem.getEngine();
+
+ }
+
+ // Do the incoming extensions support status update?
+ public boolean requiresStatusUpdate() {
+
+ boolean result = false;
+
+ // We can't get here without a begin message established.
+ String update = getBeginMessage().getExtension(BeginOpMsg.STATUS_UPDATE_EXTENSION_NAME);
+
+ if (update != null && update.equals("true")) {
+ result = true;
+ }
+
+ return result;
+
+ }
+
+ protected AppletInfo getAppletInfo() throws TPSException, IOException {
+ AppletInfo result = null;
+
+ CMS.debug("TPSProcessor.getAppletInfo, entering ...");
+
+ selectCardManager();
+
+ TPSBuffer cplc_data = getCplcData();
+ CMS.debug("cplc_data: " + cplc_data.toString());
+
+ TPSBuffer token_cuid = extractTokenCUID(cplc_data);
+ TPSBuffer token_msn = extractTokenMSN(cplc_data);
+
+ /**
+ * Checks if the netkey has the required applet version.
+ */
+
+ selectCoolKeyApplet();
+
+ TPSBuffer token_status = getStatus();
+
+ byte major_version = 0x0;
+ byte minor_version = 0x0;
+ byte app_major_version = 0x0;
+ byte app_minor_version = 0x0;
+
+ CMS.debug("TPS_Processor.getAppletInfo: status: " + token_status.toHexString());
+ if (token_status.size() >= 4) {
+ major_version = token_status.at(0);
+ minor_version = token_status.at(1);
+ app_major_version = token_status.at(2);
+ app_minor_version = token_status.at(3);
+ }
+
+ int free_mem = 0;
+ int total_mem = 0;
+
+ if (token_status.size() >= 12) {
+ byte tot_high = token_status.at(6);
+ byte tot_low = token_status.at(7);
+
+ byte free_high = token_status.at(10);
+ byte free_low = token_status.at(11);
+
+ total_mem = (tot_high << 8) + tot_low;
+ free_mem = (free_high << 8) + free_low;
+
+ }
+
+ result = new AppletInfo(major_version, minor_version, app_major_version, app_minor_version);
+ result.setCUID(token_cuid);
+ result.setMSN(token_msn);
+ result.setTotalMem(total_mem);
+ result.setFreeMem(free_mem);
+
+ CMS.debug("TPSProcessor.getAppletInfo: cuid: " + result.getCUIDhexString() + " msn: " + result.getMSNString()
+ + " major version: " + result.getMinorVersion() + " minor version: " + result.getMinorVersion()
+ + " App major version: " + result.getAppMajorVersion() + " App minor version: "
+ + result.getAppMinorVersion());
+
+ return result;
+ }
+
+ protected void selectCardManager() throws TPSException, IOException {
+ CMS.debug("TPSProcessor.selectCardManager: entering..");
+ TPSBuffer aidBuf = getCardManagerAID();
+
+ APDUResponse select = selectApplet((byte) 0x04, (byte) 0x00, aidBuf);
+
+ if (!select.checkResult()) {
+ throw new TPSException("TPSProcessor.selectCardManager: Can't selelect the card manager applet!");
+ }
+ }
+
+ protected boolean checkSymmetricKeysEnabled() throws TPSException {
+ boolean result = true;
+
+ IConfigStore configStore = CMS.getConfigStore();
+
+ String symmConfig = "op" + "." + currentTokenOperation + "." + selectedTokenType + "."
+ + TPSEngine.CFG_SYMM_KEY_UPGRADE_ENABLED;
+
+ try {
+ result = configStore.getBoolean(symmConfig, true);
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.checkSymmetricKeysEnabled: Internal error getting config value.");
+ }
+
+ return result;
+ }
+
+ protected int getSymmetricKeysRequiredVersion() throws TPSException {
+ int version = 0;
+ ;
+
+ IConfigStore configStore = CMS.getConfigStore();
+
+ String requiredVersionConfig = "op" + "." + currentTokenOperation + "." + selectedTokenType + "."
+ + "update.symmetricKeys.requiredVersion";
+
+ CMS.debug("TPSProcessor.getSymmetricKeysRequiredVersion: configValue: " + requiredVersionConfig);
+ try {
+ version = configStore.getInteger(requiredVersionConfig, 0x0);
+ } catch (EBaseException e) {
+ throw new TPSException("TPSProcessor.getSymmetricKeysRequired: Internal error getting config value.");
+ }
+
+ CMS.debug("TPSProcessor.getSymmetricKeysRequiredVersion: returning version: " + version);
+
+ return version;
+ }
+
+ protected SecureChannel checkAndUpgradeSymKeys() throws TPSException, IOException {
+
+ /* If the key of the required version is
+ not found, create them.
+
+ This sends a InitializeUpdate request to the token.
+ We tell the token to use whatever it thinks is the
+ default key version (0). It will return the version
+ of the key it actually used later. (This is accessed
+ with GetKeyInfoData below)
+ [ Note: This is not explained very well in the manual
+ The token can have multiple sets of symmetric keys
+ Each set is given a version number, which I think is
+ better thought of as a SLOT. One key slot is populated
+ with a set of keys when the token is manufactured.
+ This is then designated as the default key set version.
+ Later, we will write a new key set with PutKey, and
+ set it to be the new default]
+ */
+
+ SecureChannel channel = null;
+
+ int defKeyVersion = 0;
+ int defKeyIndex = getChannelDefKeyIndex();
+
+ if (checkSymmetricKeysEnabled()) {
+
+ CMS.debug("TPSProcessor.checkAndUpgradeSymKeys: Symm key upgrade enabled.");
+ int requiredVersion = getSymmetricKeysRequiredVersion();
+
+ // try to make a secure channel with the 'requiredVersion' keys
+ // If this fails, we know we will have to attempt an upgrade
+ // of the keys
+
+ boolean failed = false;
+ try {
+
+ channel = setupSecureChannel((byte) requiredVersion, (byte) defKeyIndex,
+ SecurityLevel.SECURE_MSG_MAC_ENC,
+ getTKSConnectorID());
+
+ } catch (TPSException e) {
+
+ CMS.debug("TPSProcessor.checkAndUpgradeSymKeys: failed to create secure channel with required version, we need to upgrade the keys.");
+ failed = true;
+ }
+
+ //If we failed we need to upgrade the keys
+ if (failed == true) {
+
+ selectCardManager();
+
+ channel = setupSecureChannel();
+
+ /* Assemble the Buffer with the version information
+ The second byte is the key offset, which is always 1
+ */
+
+ byte[] nv = { (byte) requiredVersion, 0x01 };
+ TPSBuffer newVersion = new TPSBuffer(nv);
+
+ // GetKeyInfoData will return a buffer which is bytes 11,12 of
+ // the data structure on page 89 of Cyberflex Access Programmer's
+ // Guide
+ // Byte 0 is the key set version.
+ // Byte 1 is the index into that key set
+
+ String connId = getTKSConnectorID();
+ TPSBuffer curKeyInfo = channel.getKeyInfoData();
+ TPSEngine engine = getTPSEngine();
+
+ TPSBuffer keySetData = engine.createKeySetData(newVersion, curKeyInfo,
+ channel.getKeyDiversificationData(), connId);
+
+ CMS.debug("TPSProcessor.checkAndUpgradeSymKeys: new keySetData from TKS: " + keySetData.toHexString());
+
+ byte curVersion = curKeyInfo.at(0);
+ byte curIndex = curKeyInfo.at(1);
+
+ channel.putKeys(curVersion, curIndex, keySetData);
+
+ String curVersionStr = curKeyInfo.toHexString();
+ String newVersionStr = newVersion.toHexString();
+ TPSSession session = getSession();
+ TokenRecord tokenRecord = session.getTokenRecord();
+ tokenRecord.setKeyInfo(newVersion.toHexStringPlain());
+
+ CMS.debug("TPSProcessor.checkAndUpgradeSymKeys: curVersionStr: " + curVersionStr + " newVersionStr: "
+ + newVersionStr);
+
+ selectCoolKeyApplet();
+
+ channel = setupSecureChannel((byte) requiredVersion, (byte) defKeyIndex,
+ SecurityLevel.SECURE_MSG_MAC_ENC,
+ getTKSConnectorID());
+
+ } else {
+ CMS.debug("TPSProcessor.checkAndUpgradeSymeKeys: We are already at the desired key set, returning secure channel.");
+ }
+
+ } else {
+ //Create a standard secure channel with current key set.
+ CMS.debug("TPSProcessor.checkAndUpgradeSymKeys: Key changeover disabled in the configuration.");
+
+ defKeyVersion = getChannelDefKeyVersion();
+
+ channel = setupSecureChannel((byte) defKeyVersion, (byte) defKeyIndex, SecurityLevel.SECURE_MSG_MAC_ENC,
+ getTKSConnectorID());
+
+ }
+
+ CMS.debug("TPSProcessor.checkAndUpdradeSymKeys: Leaving successfully....");
+ return channel;
+ }
+
+ //List objects that may be on a given token
+ //Return null if object void of objects
+
+ protected TPSBuffer listObjects(byte seq) throws TPSException, IOException {
+ TPSBuffer objects = null;
+
+ ListObjectsAPDU listObjects = new ListObjectsAPDU(seq);
+
+ APDUResponse respApdu = handleAPDURequest(listObjects);
+
+ if (!respApdu.checkResult()) {
+ CMS.debug("TPSProcessor.listObjects: Bad response from ListObjects! Token possibly has no objects");
+ return null;
+ }
+
+ objects = respApdu.getData();
+
+ return objects;
+
+ }
+
+ // Request new pin from client
+ protected String requestNewPin(int minLen, int maxLen) throws IOException, TPSException {
+
+ CMS.debug("TPSProcessor.requestNewPin: entering...");
+
+ String newPin = null;
+
+ NewPinRequestMsg new_pin_req = new NewPinRequestMsg(minLen, maxLen);
+
+ session.write(new_pin_req);
+
+ NewPinResponseMsg new_pin_resp = (NewPinResponseMsg) session.read();
+
+ newPin = new_pin_resp.get(NewPinResponseMsg.NEW_PIN_NAME);
+
+ if (newPin.length() < minLen || newPin.length() > maxLen) {
+ throw new TPSException("TPSProcessor.requestNewPin: new pin length outside of length contraints: min: "
+ + minLen + " max: " + maxLen);
+ }
+
+ return newPin;
+ }
+
+ protected String mapPattern(LinkedHashMap<String, String> map, String pattern) throws TPSException {
+
+ //Right now only support one pattern to match within pattern: for instance:
+ // "encryption key for $userid$ , not only the one "$userid$" pattern.
+
+ String result = null;
+
+ if (pattern == null || map == null) {
+ throw new TPSException("TPSProcessor.mapPattern: Illegal input paramters!",
+ TPSStatus.STATUS_ERROR_CONTACT_ADMIN);
+ }
+
+ final char delim = '$';
+ int firstPos = 0;
+ int nextPos = 0;
+ String patternToMap = null;
+ String patternMapped = null;
+
+ firstPos = pattern.indexOf(delim);
+ nextPos = pattern.indexOf(delim, firstPos + 1);
+
+ if ((nextPos - firstPos) <= 1) {
+ return pattern;
+ }
+
+ patternToMap = pattern.substring(firstPos + 1, nextPos);
+
+ CMS.debug("TPSProcessor.mapPattern: patternTo map: " + patternToMap);
+
+ String piece1 = "";
+ if (firstPos >= 1)
+ piece1 = pattern.substring(0, firstPos);
+
+ String piece2 = "";
+ if (nextPos < (pattern.length() - 1))
+ piece2 = pattern.substring(nextPos + 1);
+
+ for (Map.Entry<String, String> entry : map.entrySet()) {
+ String key = entry.getKey();
+
+ String value = entry.getValue();
+ CMS.debug("TPSProcessor.mapPattern: Exposed: key: " + key + " Param: " + value);
+
+ if (key.equals(patternToMap)) {
+ CMS.debug("TPSProcessor.mapPattern: found match: key: " + key + " mapped to: " + value);
+ patternMapped = value;
+ break;
+ }
+
+ }
+
+ result = piece1 + patternMapped + piece2;
+
+ CMS.debug("TPSProcessor.mapPattern: returning: " + result);
+ return result;
+
+ }
+
+ protected String formatCurrentAppletVersion(AppletInfo aInfo) throws TPSException, IOException {
+
+ if (aInfo == null) {
+ throw new TPSException("TPSProcessor.formatCurrentAppletVersion: ", TPSStatus.STATUS_ERROR_CONTACT_ADMIN);
+ }
+
+ TPSBuffer build_id = getAppletVersion();
+ String build_idStr = build_id.toHexStringPlain();
+
+ String finalVersion = aInfo.getAppMajorVersion() + "." + aInfo.getAppMinorVersion() + "." + build_idStr;
+
+ finalVersion = finalVersion.toLowerCase();
+ CMS.debug("TPSProcessor.formatCurrentAppletVersion: returing: " + finalVersion);
+
+ return finalVersion;
+
+ }
+
+ public static void main(String[] args) {
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/profile/BaseTokenProfileResolver.java b/base/tps/src/org/dogtagpki/server/tps/profile/BaseTokenProfileResolver.java
new file mode 100644
index 000000000..c62d1ed2b
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/profile/BaseTokenProfileResolver.java
@@ -0,0 +1,38 @@
+package org.dogtagpki.server.tps.profile;
+
+import org.dogtagpki.tps.main.TPSException;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.IConfigStore;
+
+/**
+ * This class implements the base TPS Profile Resolver instance
+ *
+ * @author cfu
+ */
+public abstract class BaseTokenProfileResolver {
+ protected IConfigStore configStore = null;
+ protected String instanceName = "";
+ protected String prefix = "";
+
+ public BaseTokenProfileResolver() {
+ }
+
+ public void init(String instName) {
+ instanceName = instName;
+ prefix = TokenProfileResolverManager.TOKEN_PROFILE_RESOLVER_CFG +
+ "." + instanceName;
+ configStore = CMS.getConfigStore();
+ }
+
+ public String getName() {
+ return instanceName;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public abstract String getTokenType(TokenProfileParams pPram)
+ throws TPSException;
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/profile/MappingTokenProfileResolver.java b/base/tps/src/org/dogtagpki/server/tps/profile/MappingTokenProfileResolver.java
new file mode 100644
index 000000000..264fba882
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/profile/MappingTokenProfileResolver.java
@@ -0,0 +1,294 @@
+package org.dogtagpki.server.tps.profile;
+
+import org.dogtagpki.server.tps.engine.TPSEngine;
+import org.dogtagpki.tps.main.TPSException;
+import org.dogtagpki.tps.msg.EndOpMsg.TPSStatus;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.EPropertyNotFound;
+
+/**
+ * MappingTokenProfileResolver is a profile resolver plugin that calculates
+ * token type by sorting through a list of filters in mapping
+ */
+public class MappingTokenProfileResolver extends BaseTokenProfileResolver {
+
+ public MappingTokenProfileResolver() {
+ }
+
+ public String getTokenType(TokenProfileParams pParam)
+ throws TPSException {
+
+ String tokenType = null;
+ String mappingOrder = null;
+ int major_version = 0;
+ int minor_version = 0;
+ String cuid = null;
+ // String msn = null;
+ String eTokenType = null;
+ String eTokenATR = null;
+
+ CMS.debug("MappingTokenProfileResolver.getTokenType: starts");
+
+ major_version = pParam.getInt(TokenProfileParams.PROFILE_PARAM_MAJOR_VERSION);
+ CMS.debug("MappingTokenProfileResolver: param major_version =" + major_version);
+
+ minor_version = pParam.getInt(TokenProfileParams.PROFILE_PARAM_MINOR_VERSION);
+ CMS.debug("MappingTokenProfileResolver: param minor_version =" + minor_version);
+
+ cuid = pParam.getString(TokenProfileParams.PROFILE_PARAM_CUID);
+ // msn = (String) pParam.get(TokenProfileParams.PROFILE_PARAM_MSN);
+ // they don't necessarily have extension
+ try {
+ eTokenType = pParam.getString(TokenProfileParams.PROFILE_PARAM_EXT_TOKEN_TYPE);
+ eTokenATR = pParam.getString(TokenProfileParams.PROFILE_PARAM_EXT_TOKEN_ATR);
+ } catch (TPSException e) {
+ CMS.debug("MappingTokenProfileResolver: OK to not have extension. Continue.");
+ }
+
+ CMS.debug("MappingTokenProfileResolver: params retrieved.");
+
+ String configName = prefix + "." + TPSEngine.CFG_PROFILE_MAPPING_ORDER;
+
+ try {
+ CMS.debug("MappingTokenProfileResolver: getting mapping order:" +
+ configName);
+ mappingOrder = configStore.getString(configName);
+ } catch (EPropertyNotFound e) {
+ CMS.debug("MappingTokenProfileResolver: exception:" + e);
+ throw new TPSException(
+ "MappingTokenProfileResolver.getTokenType: Token Type configuration incorrect! Mising mapping order!",
+ TPSStatus.STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND);
+
+ } catch (EBaseException e1) {
+ //The whole feature won't work if this is wrong.
+ CMS.debug("MappingTokenProfileResolver: exception:" + e1);
+ throw new TPSException(
+ "MappingTokenProfileResolver.getTokenType: Internal error obtaining config value.!",
+ TPSStatus.STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND);
+ }
+
+ String targetTokenType = null;
+
+ for (String mappingId : mappingOrder.split(",")) {
+
+ CMS.debug("MappingTokenProfileResolver.getTokenType: mapping: " + mappingId);
+
+ String mappingConfigName = prefix + ".mapping." + mappingId + ".target.tokenType";
+
+ CMS.debug("MappingTokenProfileResolver.getTokenType: mappingConfigName: " + mappingConfigName);
+
+ //We need this to exist.
+ try {
+ targetTokenType = configStore.getString(mappingConfigName);
+ } catch (EPropertyNotFound e) {
+ throw new TPSException(
+ "MappingTokenProfileResolver.getTokenType: Token Type configuration incorrect! No target token type config value found! Config: "
+ + mappingConfigName,
+ TPSStatus.STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND);
+
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "MappingTokenProfileResolver.getTokenType: Internal error obtaining config value. Config: "
+ + mappingConfigName,
+ TPSStatus.STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND);
+ }
+
+ mappingConfigName = prefix + ".mapping." + mappingId + ".filter.tokenType";
+
+ CMS.debug("MappingTokenProfileResolver.getTokenType: mappingConfigName: " + mappingConfigName);
+
+ //For this and remaining cases, it is not automatically an error if we don't get anything back
+ // from the config.
+ try {
+ tokenType = configStore.getString(mappingConfigName, null);
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "MappingTokenProfileResolver.getTokenType: Internal error obtaining config value. Config: "
+ + mappingConfigName,
+ TPSStatus.STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND);
+
+ }
+
+ CMS.debug("MappingTokenProfileResolver.getTokenType: targetTokenType: " + targetTokenType);
+
+ if (tokenType != null && tokenType.length() > 0) {
+
+ if (eTokenType == null) {
+ continue;
+ }
+
+ //String eTokenType = extensions.get("tokenType");
+ //if (eTokenType == null) {
+ // continue;
+ //}
+
+ if (!eTokenType.equals(tokenType)) {
+ continue;
+ }
+ }
+
+ mappingConfigName = prefix + ".mapping." + mappingId + ".filter.tokenATR";
+
+ CMS.debug("MappingTokenProfileResolver.getTokenType: mappingConfigName: " + mappingConfigName);
+
+ String tokenATR = null;
+
+ try {
+ tokenATR = configStore.getString(mappingConfigName, null);
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "MappingTokenProfileResolver.getTokenType: Internal error obtaining config value. Config: "
+ + mappingConfigName,
+ TPSStatus.STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND);
+ }
+
+ CMS.debug("MappingTokenProfileResolver.getTokenType: tokenATR: " + tokenATR);
+
+ if (tokenATR != null && tokenATR.length() > 0) {
+ if (eTokenATR == null) {
+ continue;
+ }
+
+ //String eTokenATR = extensions.get("tokenATR");
+
+ //if (eTokenATR == null) {
+ // continue;
+ //}
+
+ if (!eTokenATR.equals(tokenATR)) {
+ continue;
+ }
+
+ }
+
+ mappingConfigName = prefix + ".mapping." + mappingId + ".filter.tokenCUID.start";
+
+ CMS.debug("MappingTokenProfileResolver.getTokenType: mappingConfigName: " + mappingConfigName);
+
+ String tokenCUIDStart = null;
+
+ try {
+ tokenCUIDStart = configStore.getString(mappingConfigName, null);
+
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "MappingTokenProfileResolver.getTokenType: Internal error obtaining config value. Config: "
+ + mappingConfigName,
+ TPSStatus.STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND);
+ }
+
+ CMS.debug("MappingTokenProfileResolver.getTokenType: tokenCUIDStart: " + tokenCUIDStart);
+
+ if (tokenCUIDStart != null && tokenCUIDStart.length() > 0) {
+ if (cuid == null) {
+ continue;
+ }
+
+ if (tokenCUIDStart.length() != 20) {
+ continue;
+ }
+
+ if (cuid.compareTo(tokenCUIDStart) < 0) {
+ continue;
+ }
+
+ }
+
+ mappingConfigName = prefix + ".mapping." + mappingId + ".filter.tokenCUID.end";
+
+ CMS.debug("MappingTokenProfileResolver.getTokenType: mappingConfigName: " + mappingConfigName);
+
+ String tokenCUIDEnd = null;
+ try {
+ tokenCUIDEnd = configStore.getString(mappingConfigName, null);
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "MappingTokenProfileResolver.getTokenType: Internal error obtaining config value. Config: "
+ + mappingConfigName,
+ TPSStatus.STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND);
+ }
+
+ CMS.debug("MappingTokenProfileResolver.getTokenType: tokenCUIDEnd: " + tokenCUIDEnd);
+
+ if (tokenCUIDEnd != null && tokenCUIDEnd.length() > 0) {
+ if (cuid == null) {
+ continue;
+ }
+
+ if (tokenCUIDEnd.length() != 20) {
+ continue;
+ }
+
+ if (cuid.compareTo(tokenCUIDEnd) > 0) {
+ continue;
+ }
+
+ }
+
+ mappingConfigName = prefix + ".mapping." + mappingId + ".filter.appletMajorVersion";
+
+ CMS.debug("MappingTokenProfileResolver.getTokenType: mappingConfigName: " + mappingConfigName);
+
+ String majorVersion = null;
+ String minorVersion = null;
+
+ try {
+ majorVersion = configStore.getString(mappingConfigName, null);
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "MappingTokenProfileResolver.getTokenType: Internal error obtaining config value. Config: "
+ + mappingConfigName,
+ TPSStatus.STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND);
+ }
+
+ CMS.debug("MappingTokenProfileResolver.getTokenType: majorVersion: " + majorVersion);
+ if (majorVersion != null && majorVersion.length() > 0) {
+
+ int major = Integer.parseInt(majorVersion);
+
+ if (major != major_version) {
+ continue;
+ }
+ }
+
+ mappingConfigName = prefix + ".mapping." + mappingId + ".filter.appletMinorVersion";
+
+ CMS.debug("MappingTokenProfileResolver.getTokenType: mappingConfigName: " + mappingConfigName);
+
+ try {
+ minorVersion = configStore.getString(mappingConfigName, null);
+ } catch (EBaseException e) {
+ throw new TPSException(
+ "MappingTokenProfileResolver.getTokenType: Internal error obtaining config value. Config: "
+ + mappingConfigName,
+ TPSStatus.STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND);
+ }
+ CMS.debug("MappingTokenProfileResolver.getTokenType: minorVersion " + minorVersion);
+
+ if (minorVersion != null && minorVersion.length() > 0) {
+
+ int minor = Integer.parseInt(minorVersion);
+
+ if (minor != minor_version) {
+ continue;
+ }
+ }
+
+ //if we make it this far, we have a token type
+ CMS.debug("MappingTokenProfileResolver.getTokenType: Selected Token type: " + targetTokenType);
+ break;
+ }
+
+ if (targetTokenType == null) {
+ CMS.debug("MappingTokenProfileResolver.getTokenType: end found: " + targetTokenType);
+ throw new TPSException("MappingTokenProfileResolver.getTokenType: Can't find token type!",
+ TPSStatus.STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND);
+ }
+
+ return targetTokenType;
+
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/profile/TokenProfileParams.java b/base/tps/src/org/dogtagpki/server/tps/profile/TokenProfileParams.java
new file mode 100644
index 000000000..d04bc9fb8
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/profile/TokenProfileParams.java
@@ -0,0 +1,145 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps.profile;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.dogtagpki.tps.main.TPSException;
+import org.dogtagpki.tps.msg.EndOpMsg.TPSStatus;
+
+import com.netscape.certsrv.apps.CMS;
+
+/**
+ * A class represents profile params information.
+ * <P>
+ *
+ * @version $Revision$, $Date$
+ */
+public class TokenProfileParams {
+
+ public static final String PROFILE_PARAM_MAJOR_VERSION = "pp_major_version";
+ public static final String PROFILE_PARAM_MINOR_VERSION = "pp_minor_version";
+ public static final String PROFILE_PARAM_CUID = "pp_cuid";
+ public static final String PROFILE_PARAM_MSN = "pp_msn";
+ public static final String PROFILE_PARAM_EXT_TOKEN_TYPE = "pp_ext_tokenType";
+ public static final String PROFILE_PARAM_EXT_TOKEN_ATR = "pp_ext_tokenATR";
+
+ private HashMap<String, String> content = new HashMap<String, String>();
+
+ /**
+ * Constructs a meta information.
+ * <P>
+ */
+ public TokenProfileParams() {
+ }
+
+ /**
+ * Returns a short string describing this certificate attribute.
+ * <P>
+ *
+ * @return information about this certificate attribute.
+ */
+ public String toString() {
+ StringBuffer sb = new StringBuffer("[\n" + " Meta information:\n");
+
+ for (Map.Entry<String, String> entry : content.entrySet()) {
+ String key = entry.getKey();
+
+ sb.append(" " + key + " : " + entry.getValue() + "\n");
+ }
+ sb.append("]\n");
+ return sb.toString();
+ }
+
+ /**
+ * Gets a String attribute value.
+ * <P>
+ *
+ * @param name the name of the attribute to return.
+ */
+ public String getString(String name)
+ throws TPSException {
+ String val = content.get(name);
+ if (val == null) {
+ CMS.debug("TokenProfileParams.getString: param null:"+ name);
+ throw new TPSException (
+ "TokenProfileParams.getString: param null:"+ name,
+ TPSStatus.STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND);
+ }
+ return val;
+ }
+
+ /**
+ * Gets an int attribute value.
+ * <P>
+ *
+ * @param name the name of the attribute to return.
+ */
+ public int getInt(String name)
+ throws TPSException {
+ String val = content.get(name);
+ if (val == null) {
+ CMS.debug("TokenProfileParams.getInt: param null:"+ name);
+ throw new TPSException (
+ "TokenProfileParams.getInt: param null:"+ name,
+ TPSStatus.STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND);
+ }
+ try {
+ int intVal = Integer.parseInt(val);
+ return intVal;
+ } catch (NumberFormatException e) {
+ CMS.debug("TokenProfileParams.getInt: param "+ name + "=" + val + e);
+ throw new TPSException (
+ "TokenProfileParams.getInt: param major_version:"+ e,
+ TPSStatus.STATUS_ERROR_MISCONFIGURATION);
+ }
+ }
+
+ /**
+ * Sets an attribute value.
+ *
+ * @param name the name of the attribute
+ * @param val the attribute value.
+ */
+ public void set(String name, String val) {
+ content.put(name, val);
+ }
+
+ /**
+ * Deletes an attribute value from this AttrSet.
+ * <P>
+ *
+ * @param name the name of the attribute to delete.
+ */
+ public void delete(String name) {
+ content.remove(name);
+ }
+
+ /**
+ * Returns an enumeration of the names of the attributes existing within
+ * this attribute.
+ * <P>
+ *
+ * @return an enumeration of the attribute names.
+ */
+ public Set<String> getElements() {
+ return content.keySet();
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/profile/TokenProfileResolverManager.java b/base/tps/src/org/dogtagpki/server/tps/profile/TokenProfileResolverManager.java
new file mode 100644
index 000000000..b6325fcca
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/profile/TokenProfileResolverManager.java
@@ -0,0 +1,114 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.profile;
+
+import java.util.HashMap;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.registry.IPluginInfo;
+import com.netscape.certsrv.registry.IPluginRegistry;
+
+/**
+ * TokenProfileResolverManager is a class for profile resolver plugin
+ * management
+ *
+ * @author cfu
+ */
+public class TokenProfileResolverManager
+{
+ private static final String TOKEN_PROFILE_RESOLVER_TYPE = "tpsTokenProfileResolver";
+ public static final String PROP_RESOLVER_LIST = "list";
+ public static final String PROP_RESOLVER_CLASS_ID = "class_id";
+
+ protected static final String TOKEN_PROFILE_RESOLVER_CFG = "tokenProfileResolver";
+ protected IPluginRegistry registry = null;
+ protected HashMap<String, BaseTokenProfileResolver> tokenProfileResolvers = null;
+
+ public TokenProfileResolverManager() {
+ tokenProfileResolvers = new HashMap<String, BaseTokenProfileResolver>();
+ }
+
+ /**
+ * initializes all profile resolver plugin instances specified in
+ * <instance-name>/conf/registry.cfg
+ *
+ * configuration e.g.
+ *
+ * registry.cfg:
+ * types=tpsTokenProfileResolver
+ * tpsProfileResolver.ids=mappingTokenProfileResolverImpl
+ * tpsProfileResolver.mappingTokenProfileResolverImpl.class=org.dogtagpki.server.tps.profile.MappingTokenProfileResolver
+ * tpsProfileResolver.mappingTokenProfileResolverImpl.desc=Mapping-based Token profile resolver
+ * tpsProfileResolver.mappingTokenProfileResolverImpl.name=Mapping-based Token profile resolver
+ *
+ * CS.cfg :
+ * registry.file=/var/lib/pki/pki-tomcat/conf/tps/registry.cfg
+ * tokenProfileResolver.list=formatMappingResolver,enrollMappingResolver,pinResetMappingResolver
+ * tokenProfileResolver.formatMappingResolver.class_id=mappingProfileResolverImpl
+ * tokenProfileResolver.formatMappingResolver.[plugin-specific configuration]
+ *
+ * op.format.tokenProfileResolver=formatMappingResolver
+ * ...
+ * op.enroll.tokenProfileResolver=enrollMappingResolver
+ *
+ * Note: "none" indicates no resolver plugin applied
+ * op.format.tokenProfileResolver=none
+ */
+ public void initProfileResolverInstances()
+ throws EBaseException {
+
+ CMS.debug("TokenProfileResolverManager: initProfileResolverInstances(): begins");
+ IConfigStore conf = CMS.getConfigStore();
+ registry = (IPluginRegistry) CMS.getSubsystem(CMS.SUBSYSTEM_REGISTRY);
+ if (registry == null) {
+ CMS.debug("TokenProfileResolverManager: initProfileResolverInstances(): registry null");
+ return;
+ }
+
+ IConfigStore prConf = conf.getSubStore(TOKEN_PROFILE_RESOLVER_CFG);
+ String profileList = prConf.getString(PROP_RESOLVER_LIST, "");
+
+ for (String prInst : profileList.split(",")) {
+ String classID = prConf.getString(prInst + "." + PROP_RESOLVER_CLASS_ID);
+ CMS.debug("TokenProfileResolverManager: initProfileResolverInstances(): initializing classID=" + classID);
+ IPluginInfo resolverInfo =
+ registry.getPluginInfo(TOKEN_PROFILE_RESOLVER_TYPE, classID);
+ String resolverClass = resolverInfo.getClassName();
+ BaseTokenProfileResolver resolver = null;
+ try {
+ resolver = (BaseTokenProfileResolver)
+ Class.forName(resolverClass).newInstance();
+ } catch (Exception e) {
+ // throw Exception
+ CMS.debug("TokenProfileResolverManager: resolver plugin Class.forName " +
+ resolverClass + " " + e.toString());
+ throw new EBaseException(e.toString());
+ }
+ resolver.init(prInst);
+ tokenProfileResolvers.put(prInst, resolver);
+ CMS.debug("TokenProfileResolverManager: initProfileResolverInstances(): resolver instance added: " + prInst);
+ }
+ }
+
+ public BaseTokenProfileResolver getResolverInstance(String name) {
+ return tokenProfileResolvers.get(name);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/rest/ActivityService.java b/base/tps/src/org/dogtagpki/server/tps/rest/ActivityService.java
new file mode 100644
index 000000000..6002e7a94
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/rest/ActivityService.java
@@ -0,0 +1,177 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.rest;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.util.Iterator;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.dogtagpki.server.tps.TPSSubsystem;
+import org.dogtagpki.server.tps.dbs.ActivityDatabase;
+import org.dogtagpki.server.tps.dbs.ActivityRecord;
+import org.jboss.resteasy.plugins.providers.atom.Link;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.BadRequestException;
+import com.netscape.certsrv.base.PKIException;
+import com.netscape.certsrv.logging.ActivityCollection;
+import com.netscape.certsrv.logging.ActivityData;
+import com.netscape.certsrv.logging.ActivityResource;
+import com.netscape.cms.servlet.base.PKIService;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class ActivityService extends PKIService implements ActivityResource {
+
+ @Context
+ private UriInfo uriInfo;
+
+ @Context
+ private HttpHeaders headers;
+
+ @Context
+ private Request request;
+
+ @Context
+ private HttpServletRequest servletRequest;
+
+ public ActivityService() {
+ CMS.debug("ActivityService.<init>()");
+ }
+
+ public ActivityData createActivityData(ActivityRecord activityRecord) {
+
+ ActivityData activityData = new ActivityData();
+ activityData.setID(activityRecord.getId());
+ activityData.setTokenID(activityRecord.getTokenID());
+ activityData.setUserID(activityRecord.getUserID());
+ activityData.setIP(activityRecord.getIP());
+ activityData.setOperation(activityRecord.getOperation());
+ activityData.setResult(activityRecord.getResult());
+ activityData.setMessage(activityRecord.getMessage());
+ activityData.setDate(activityRecord.getDate());
+
+ String activityID = activityRecord.getId();
+ try {
+ activityID = URLEncoder.encode(activityID, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+
+ URI uri = uriInfo.getBaseUriBuilder().path(ActivityResource.class).path("{activityID}").build(activityID);
+ activityData.setLink(new Link("self", uri));
+
+ return activityData;
+ }
+
+ public ActivityRecord createActivityRecord(ActivityData activityData) {
+
+ ActivityRecord activityRecord = new ActivityRecord();
+ activityRecord.setId(activityData.getID());
+ activityRecord.setTokenID(activityData.getTokenID());
+ activityRecord.setUserID(activityData.getUserID());
+ activityRecord.setIP(activityData.getIP());
+ activityRecord.setOperation(activityData.getOperation());
+ activityRecord.setResult(activityData.getResult());
+ activityRecord.setMessage(activityData.getMessage());
+ activityRecord.setDate(activityData.getDate());
+
+ return activityRecord;
+ }
+
+ @Override
+ public Response findActivities(String filter, Integer start, Integer size) {
+
+ CMS.debug("ActivityService.findActivities()");
+
+ if (filter != null && filter.length() < MIN_FILTER_LENGTH) {
+ throw new BadRequestException("Filter is too short.");
+ }
+
+ start = start == null ? 0 : start;
+ size = size == null ? DEFAULT_SIZE : size;
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ActivityDatabase database = subsystem.getActivityDatabase();
+
+ Iterator<ActivityRecord> activities = database.findRecords(filter).iterator();
+
+ ActivityCollection response = new ActivityCollection();
+ int i = 0;
+
+ // skip to the start of the page
+ for ( ; i<start && activities.hasNext(); i++) activities.next();
+
+ // return entries up to the page size
+ for ( ; i<start+size && activities.hasNext(); i++) {
+ response.addEntry(createActivityData(activities.next()));
+ }
+
+ // count the total entries
+ for ( ; activities.hasNext(); i++) activities.next();
+ response.setTotal(i);
+
+ if (start > 0) {
+ URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", Math.max(start-size, 0)).build();
+ response.addLink(new Link("prev", uri));
+ }
+
+ if (start+size < i) {
+ URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", start+size).build();
+ response.addLink(new Link("next", uri));
+ }
+
+ return createOKResponse(response);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response getActivity(String activityID) {
+
+ if (activityID == null) throw new BadRequestException("Activity ID is null.");
+
+ CMS.debug("ActivityService.getActivity(\"" + activityID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ActivityDatabase database = subsystem.getActivityDatabase();
+
+ return createOKResponse(createActivityData(database.getRecord(activityID)));
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/rest/AuthenticatorService.java b/base/tps/src/org/dogtagpki/server/tps/rest/AuthenticatorService.java
new file mode 100644
index 000000000..d862e261d
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/rest/AuthenticatorService.java
@@ -0,0 +1,350 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.rest;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.security.Principal;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.dogtagpki.server.tps.TPSSubsystem;
+import org.dogtagpki.server.tps.config.AuthenticatorDatabase;
+import org.dogtagpki.server.tps.config.AuthenticatorRecord;
+import org.jboss.resteasy.plugins.providers.atom.Link;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.BadRequestException;
+import com.netscape.certsrv.base.ForbiddenException;
+import com.netscape.certsrv.base.PKIException;
+import com.netscape.certsrv.tps.authenticator.AuthenticatorCollection;
+import com.netscape.certsrv.tps.authenticator.AuthenticatorData;
+import com.netscape.certsrv.tps.authenticator.AuthenticatorResource;
+import com.netscape.cms.servlet.base.PKIService;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class AuthenticatorService extends PKIService implements AuthenticatorResource {
+
+ @Context
+ private UriInfo uriInfo;
+
+ @Context
+ private HttpHeaders headers;
+
+ @Context
+ private Request request;
+
+ @Context
+ private HttpServletRequest servletRequest;
+
+ public AuthenticatorService() {
+ CMS.debug("AuthenticatorService.<init>()");
+ }
+
+ public AuthenticatorData createAuthenticatorData(AuthenticatorRecord authenticatorRecord) throws UnsupportedEncodingException {
+
+ String authenticatorID = authenticatorRecord.getID();
+
+ AuthenticatorData authenticatorData = new AuthenticatorData();
+ authenticatorData.setID(authenticatorID);
+ authenticatorData.setStatus(authenticatorRecord.getStatus());
+ authenticatorData.setProperties(authenticatorRecord.getProperties());
+
+ authenticatorID = URLEncoder.encode(authenticatorID, "UTF-8");
+ URI uri = uriInfo.getBaseUriBuilder().path(AuthenticatorResource.class).path("{authenticatorID}").build(authenticatorID);
+ authenticatorData.setLink(new Link("self", uri));
+
+ return authenticatorData;
+ }
+
+ public AuthenticatorRecord createAuthenticatorRecord(AuthenticatorData authenticatorData) {
+
+ AuthenticatorRecord authenticatorRecord = new AuthenticatorRecord();
+ authenticatorRecord.setID(authenticatorData.getID());
+ authenticatorRecord.setStatus(authenticatorData.getStatus());
+ authenticatorRecord.setProperties(authenticatorData.getProperties());
+
+ return authenticatorRecord;
+ }
+
+ @Override
+ public Response findAuthenticators(String filter, Integer start, Integer size) {
+
+ CMS.debug("AuthenticatorService.findAuthenticators()");
+
+ if (filter != null && filter.length() < MIN_FILTER_LENGTH) {
+ throw new BadRequestException("Filter is too short.");
+ }
+
+ start = start == null ? 0 : start;
+ size = size == null ? DEFAULT_SIZE : size;
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ AuthenticatorDatabase database = subsystem.getAuthenticatorDatabase();
+
+ Iterator<AuthenticatorRecord> authenticators = database.findRecords(filter).iterator();
+
+ AuthenticatorCollection response = new AuthenticatorCollection();
+ int i = 0;
+
+ // skip to the start of the page
+ for ( ; i<start && authenticators.hasNext(); i++) authenticators.next();
+
+ // return entries up to the page size
+ for ( ; i<start+size && authenticators.hasNext(); i++) {
+ response.addEntry(createAuthenticatorData(authenticators.next()));
+ }
+
+ // count the total entries
+ for ( ; authenticators.hasNext(); i++) authenticators.next();
+ response.setTotal(i);
+
+ if (start > 0) {
+ URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", Math.max(start-size, 0)).build();
+ response.addLink(new Link("prev", uri));
+ }
+
+ if (start+size < i) {
+ URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", start+size).build();
+ response.addLink(new Link("next", uri));
+ }
+
+ return createOKResponse(response);
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response getAuthenticator(String authenticatorID) {
+
+ if (authenticatorID == null) throw new BadRequestException("Authenticator ID is null.");
+
+ CMS.debug("AuthenticatorService.getAuthenticator(\"" + authenticatorID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ AuthenticatorDatabase database = subsystem.getAuthenticatorDatabase();
+
+ return createOKResponse(createAuthenticatorData(database.getRecord(authenticatorID)));
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response addAuthenticator(AuthenticatorData authenticatorData) {
+
+ if (authenticatorData == null) throw new BadRequestException("Authenticator data is null.");
+
+ CMS.debug("AuthenticatorService.addAuthenticator(\"" + authenticatorData.getID() + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ AuthenticatorDatabase database = subsystem.getAuthenticatorDatabase();
+
+ String status = authenticatorData.getStatus();
+ Principal principal = servletRequest.getUserPrincipal();
+
+ if (status == null || database.requiresApproval() && !database.canApprove(principal)) {
+ // if status is unspecified or user doesn't have rights to approve, the entry is disabled
+ authenticatorData.setStatus("Disabled");
+ }
+
+ database.addRecord(authenticatorData.getID(), createAuthenticatorRecord(authenticatorData));
+ authenticatorData = createAuthenticatorData(database.getRecord(authenticatorData.getID()));
+
+ return createCreatedResponse(authenticatorData, authenticatorData.getLink().getHref());
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response updateAuthenticator(String authenticatorID, AuthenticatorData authenticatorData) {
+
+ if (authenticatorID == null) throw new BadRequestException("Authenticator ID is null.");
+ if (authenticatorData == null) throw new BadRequestException("Authenticator data is null.");
+
+ CMS.debug("AuthenticatorService.updateAuthenticator(\"" + authenticatorID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ AuthenticatorDatabase database = subsystem.getAuthenticatorDatabase();
+
+ AuthenticatorRecord record = database.getRecord(authenticatorID);
+
+ // only disabled authenticator can be updated
+ if (!"Disabled".equals(record.getStatus())) {
+ throw new ForbiddenException("Unable to update authenticator " + authenticatorID);
+ }
+
+ // update status if specified
+ String status = authenticatorData.getStatus();
+ if (status != null && !"Disabled".equals(status)) {
+ if (!"Enabled".equals(status)) {
+ throw new ForbiddenException("Invalid authenticator status: " + status);
+ }
+
+ // if user doesn't have rights, set to pending
+ Principal principal = servletRequest.getUserPrincipal();
+ if (database.requiresApproval() && !database.canApprove(principal)) {
+ status = "Pending_Approval";
+ }
+
+ // enable authenticator
+ record.setStatus(status);
+ }
+
+ // update properties if specified
+ Map<String, String> properties = authenticatorData.getProperties();
+ if (properties != null) {
+ record.setProperties(authenticatorData.getProperties());
+ }
+
+ database.updateRecord(authenticatorID, record);
+
+ authenticatorData = createAuthenticatorData(database.getRecord(authenticatorID));
+
+ return createOKResponse(authenticatorData);
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response changeAuthenticatorStatus(String authenticatorID, String action) {
+
+ if (authenticatorID == null) throw new BadRequestException("Authenticator ID is null.");
+ if (action == null) throw new BadRequestException("Action is null.");
+
+ CMS.debug("AuthenticatorService.changeAuthenticatorStatus(\"" + authenticatorID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ AuthenticatorDatabase database = subsystem.getAuthenticatorDatabase();
+
+ AuthenticatorRecord record = database.getRecord(authenticatorID);
+ String status = record.getStatus();
+
+ if ("Disabled".equals(status)) {
+ if ("enable".equals(action)) {
+ status = "Enabled";
+ } else {
+ throw new BadRequestException("Invalid action: " + action);
+ }
+
+ } else if ("Enabled".equals(status)) {
+ if ("disable".equals(action)) {
+ status = "Disabled";
+ } else {
+ throw new BadRequestException("Invalid action: " + action);
+ }
+
+ } else if ("Pending_Approval".equals(status)) {
+ if ("approve".equals(action)) {
+ status = "Enabled";
+ } else if ("reject".equals(action)) {
+ status = "Disabled";
+ } else {
+ throw new BadRequestException("Invalid action: " + action);
+ }
+
+ } else {
+ throw new PKIException("Invalid authenticator status: " + status);
+ }
+
+ record.setStatus(status);
+ database.updateRecord(authenticatorID, record);
+
+ AuthenticatorData authenticatorData = createAuthenticatorData(database.getRecord(authenticatorID));
+
+ return createOKResponse(authenticatorData);
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response removeAuthenticator(String authenticatorID) {
+
+ if (authenticatorID == null) throw new BadRequestException("Authenticator ID is null.");
+
+ CMS.debug("AuthenticatorService.removeAuthenticator(\"" + authenticatorID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ AuthenticatorDatabase database = subsystem.getAuthenticatorDatabase();
+
+ AuthenticatorRecord record = database.getRecord(authenticatorID);
+ String status = record.getStatus();
+
+ if (!"Disabled".equals(status)) {
+ throw new ForbiddenException("Unable to delete authenticator " + authenticatorID);
+ }
+
+ database.removeRecord(authenticatorID);
+
+ return createNoContentResponse();
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/rest/ConnectorService.java b/base/tps/src/org/dogtagpki/server/tps/rest/ConnectorService.java
new file mode 100644
index 000000000..c281265ef
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/rest/ConnectorService.java
@@ -0,0 +1,350 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.rest;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.security.Principal;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.dogtagpki.server.tps.TPSSubsystem;
+import org.dogtagpki.server.tps.config.ConnectorDatabase;
+import org.dogtagpki.server.tps.config.ConnectorRecord;
+import org.jboss.resteasy.plugins.providers.atom.Link;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.BadRequestException;
+import com.netscape.certsrv.base.ForbiddenException;
+import com.netscape.certsrv.base.PKIException;
+import com.netscape.certsrv.tps.connector.ConnectorCollection;
+import com.netscape.certsrv.tps.connector.ConnectorData;
+import com.netscape.certsrv.tps.connector.ConnectorResource;
+import com.netscape.cms.servlet.base.PKIService;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class ConnectorService extends PKIService implements ConnectorResource {
+
+ @Context
+ private UriInfo uriInfo;
+
+ @Context
+ private HttpHeaders headers;
+
+ @Context
+ private Request request;
+
+ @Context
+ private HttpServletRequest servletRequest;
+
+ public ConnectorService() {
+ CMS.debug("ConnectorService.<init>()");
+ }
+
+ public ConnectorData createConnectorData(ConnectorRecord connectionRecord) throws UnsupportedEncodingException {
+
+ String connectorID = connectionRecord.getID();
+
+ ConnectorData connectorData = new ConnectorData();
+ connectorData.setID(connectorID);
+ connectorData.setStatus(connectionRecord.getStatus());
+ connectorData.setProperties(connectionRecord.getProperties());
+
+ connectorID = URLEncoder.encode(connectorID, "UTF-8");
+ URI uri = uriInfo.getBaseUriBuilder().path(ConnectorResource.class).path("{connectorID}").build(connectorID);
+ connectorData.setLink(new Link("self", uri));
+
+ return connectorData;
+ }
+
+ public ConnectorRecord createConnectorRecord(ConnectorData connectorData) {
+
+ ConnectorRecord connectorRecord = new ConnectorRecord();
+ connectorRecord.setID(connectorData.getID());
+ connectorRecord.setStatus(connectorData.getStatus());
+ connectorRecord.setProperties(connectorData.getProperties());
+
+ return connectorRecord;
+ }
+
+ @Override
+ public Response findConnectors(String filter, Integer start, Integer size) {
+
+ CMS.debug("ConnectorService.findConnectors()");
+
+ if (filter != null && filter.length() < MIN_FILTER_LENGTH) {
+ throw new BadRequestException("Filter is too short.");
+ }
+
+ start = start == null ? 0 : start;
+ size = size == null ? DEFAULT_SIZE : size;
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ConnectorDatabase database = subsystem.getConnectorDatabase();
+
+ Iterator<ConnectorRecord> connections = database.findRecords(filter).iterator();
+
+ ConnectorCollection response = new ConnectorCollection();
+ int i = 0;
+
+ // skip to the start of the page
+ for ( ; i<start && connections.hasNext(); i++) connections.next();
+
+ // return entries up to the page size
+ for ( ; i<start+size && connections.hasNext(); i++) {
+ response.addEntry(createConnectorData(connections.next()));
+ }
+
+ // count the total entries
+ for ( ; connections.hasNext(); i++) connections.next();
+ response.setTotal(i);
+
+ if (start > 0) {
+ URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", Math.max(start-size, 0)).build();
+ response.addLink(new Link("prev", uri));
+ }
+
+ if (start+size < i) {
+ URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", start+size).build();
+ response.addLink(new Link("next", uri));
+ }
+
+ return createOKResponse(response);
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response getConnector(String connectorID) {
+
+ if (connectorID == null) throw new BadRequestException("Connector ID is null.");
+
+ CMS.debug("ConnectorService.getConnector(\"" + connectorID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ConnectorDatabase database = subsystem.getConnectorDatabase();
+
+ return createOKResponse(createConnectorData(database.getRecord(connectorID)));
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response addConnector(ConnectorData connectorData) {
+
+ if (connectorData == null) throw new BadRequestException("Connector data is null.");
+
+ CMS.debug("ConnectorService.addConnector(\"" + connectorData.getID() + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ConnectorDatabase database = subsystem.getConnectorDatabase();
+
+ String status = connectorData.getStatus();
+ Principal principal = servletRequest.getUserPrincipal();
+
+ if (status == null || database.requiresApproval() && !database.canApprove(principal)) {
+ // if status is unspecified or user doesn't have rights to approve, the entry is disabled
+ connectorData.setStatus("Disabled");
+ }
+
+ database.addRecord(connectorData.getID(), createConnectorRecord(connectorData));
+ connectorData = createConnectorData(database.getRecord(connectorData.getID()));
+
+ return createCreatedResponse(connectorData, connectorData.getLink().getHref());
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response updateConnector(String connectorID, ConnectorData connectorData) {
+
+ if (connectorID == null) throw new BadRequestException("Connector ID is null.");
+ if (connectorData == null) throw new BadRequestException("Connector data is null.");
+
+ CMS.debug("ConnectorService.updateConnector(\"" + connectorID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ConnectorDatabase database = subsystem.getConnectorDatabase();
+
+ ConnectorRecord record = database.getRecord(connectorID);
+
+ // only disabled connector can be updated
+ if (!"Disabled".equals(record.getStatus())) {
+ throw new ForbiddenException("Unable to update connector " + connectorID);
+ }
+
+ // update status if specified
+ String status = connectorData.getStatus();
+ if (status != null && !"Disabled".equals(status)) {
+ if (!"Enabled".equals(status)) {
+ throw new ForbiddenException("Invalid connector status: " + status);
+ }
+
+ // if user doesn't have rights, set to pending
+ Principal principal = servletRequest.getUserPrincipal();
+ if (database.requiresApproval() && !database.canApprove(principal)) {
+ status = "Pending_Approval";
+ }
+
+ // enable connector
+ record.setStatus(status);
+ }
+
+ // update properties if specified
+ Map<String, String> properties = connectorData.getProperties();
+ if (properties != null) {
+ record.setProperties(properties);
+ }
+
+ database.updateRecord(connectorID, record);
+
+ connectorData = createConnectorData(database.getRecord(connectorID));
+
+ return createOKResponse(connectorData);
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response changeConnectorStatus(String connectorID, String action) {
+
+ if (connectorID == null) throw new BadRequestException("Connector ID is null.");
+ if (action == null) throw new BadRequestException("Action is null.");
+
+ CMS.debug("ConnectorService.changeConnectorStatus(\"" + connectorID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ConnectorDatabase database = subsystem.getConnectorDatabase();
+
+ ConnectorRecord record = database.getRecord(connectorID);
+ String status = record.getStatus();
+
+ if ("Disabled".equals(status)) {
+ if ("enable".equals(action)) {
+ status = "Enabled";
+ } else {
+ throw new BadRequestException("Invalid action: " + action);
+ }
+
+ } else if ("Enabled".equals(status)) {
+ if ("disable".equals(action)) {
+ status = "Disabled";
+ } else {
+ throw new BadRequestException("Invalid action: " + action);
+ }
+
+ } else if ("Pending_Approval".equals(status)) {
+ if ("approve".equals(action)) {
+ status = "Enabled";
+ } else if ("reject".equals(action)) {
+ status = "Disabled";
+ } else {
+ throw new BadRequestException("Invalid action: " + action);
+ }
+
+ } else {
+ throw new PKIException("Invalid connector status: " + status);
+ }
+
+ record.setStatus(status);
+ database.updateRecord(connectorID, record);
+
+ ConnectorData connectorData = createConnectorData(database.getRecord(connectorID));
+
+ return createOKResponse(connectorData);
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response removeConnector(String connectorID) {
+
+ if (connectorID == null) throw new BadRequestException("Connector ID is null.");
+
+ CMS.debug("ConnectorService.removeConnector(\"" + connectorID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ConnectorDatabase database = subsystem.getConnectorDatabase();
+
+ ConnectorRecord record = database.getRecord(connectorID);
+ String status = record.getStatus();
+
+ if (!"Disabled".equals(status)) {
+ throw new ForbiddenException("Unable to delete connector " + connectorID);
+ }
+
+ database.removeRecord(connectorID);
+
+ return createNoContentResponse();
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/rest/ProfileMappingService.java b/base/tps/src/org/dogtagpki/server/tps/rest/ProfileMappingService.java
new file mode 100644
index 000000000..f3a6f2e38
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/rest/ProfileMappingService.java
@@ -0,0 +1,341 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.rest;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.security.Principal;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.dogtagpki.server.tps.TPSSubsystem;
+import org.dogtagpki.server.tps.config.ProfileMappingDatabase;
+import org.dogtagpki.server.tps.config.ProfileMappingRecord;
+import org.jboss.resteasy.plugins.providers.atom.Link;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.BadRequestException;
+import com.netscape.certsrv.base.ForbiddenException;
+import com.netscape.certsrv.base.PKIException;
+import com.netscape.certsrv.tps.profile.ProfileMappingCollection;
+import com.netscape.certsrv.tps.profile.ProfileMappingData;
+import com.netscape.certsrv.tps.profile.ProfileMappingResource;
+import com.netscape.cms.servlet.base.PKIService;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class ProfileMappingService extends PKIService implements ProfileMappingResource {
+
+ @Context
+ private UriInfo uriInfo;
+
+ @Context
+ private HttpHeaders headers;
+
+ @Context
+ private Request request;
+
+ @Context
+ private HttpServletRequest servletRequest;
+
+ public ProfileMappingService() {
+ CMS.debug("ProfileMappingService.<init>()");
+ }
+
+ public ProfileMappingData createProfileMappingData(ProfileMappingRecord profileMappingRecord) throws UnsupportedEncodingException {
+
+ String profileMappingID = profileMappingRecord.getID();
+
+ ProfileMappingData profileMappingData = new ProfileMappingData();
+ profileMappingData.setID(profileMappingID);
+ profileMappingData.setStatus(profileMappingRecord.getStatus());
+ profileMappingData.setProperties(profileMappingRecord.getProperties());
+
+ profileMappingID = URLEncoder.encode(profileMappingID, "UTF-8");
+ URI uri = uriInfo.getBaseUriBuilder().path(ProfileMappingResource.class).path("{profileMappingID}").build(profileMappingID);
+ profileMappingData.setLink(new Link("self", uri));
+
+ return profileMappingData;
+ }
+
+ public ProfileMappingRecord createProfileMappingRecord(ProfileMappingData profileMappingData) {
+
+ ProfileMappingRecord profileMappingRecord = new ProfileMappingRecord();
+ profileMappingRecord.setID(profileMappingData.getID());
+ profileMappingRecord.setStatus(profileMappingData.getStatus());
+ profileMappingRecord.setProperties(profileMappingData.getProperties());
+
+ return profileMappingRecord;
+ }
+
+ @Override
+ public Response findProfileMappings(String filter, Integer start, Integer size) {
+
+ CMS.debug("ProfileMappingService.findProfileMappings()");
+
+ if (filter != null && filter.length() < MIN_FILTER_LENGTH) {
+ throw new BadRequestException("Filter is too short.");
+ }
+
+ start = start == null ? 0 : start;
+ size = size == null ? DEFAULT_SIZE : size;
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ProfileMappingDatabase database = subsystem.getProfileMappingDatabase();
+
+ Iterator<ProfileMappingRecord> profileMappings = database.findRecords(filter).iterator();
+
+ ProfileMappingCollection response = new ProfileMappingCollection();
+ int i = 0;
+
+ // skip to the start of the page
+ for ( ; i<start && profileMappings.hasNext(); i++) profileMappings.next();
+
+ // return entries up to the page size
+ for ( ; i<start+size && profileMappings.hasNext(); i++) {
+ response.addEntry(createProfileMappingData(profileMappings.next()));
+ }
+
+ // count the total entries
+ for ( ; profileMappings.hasNext(); i++) profileMappings.next();
+ response.setTotal(i);
+
+ if (start > 0) {
+ URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", Math.max(start-size, 0)).build();
+ response.addLink(new Link("prev", uri));
+ }
+
+ if (start+size < i) {
+ URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", start+size).build();
+ response.addLink(new Link("next", uri));
+ }
+
+ return createOKResponse(response);
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response getProfileMapping(String profileMappingID) {
+
+ CMS.debug("ProfileMappingService.getProfileMapping(\"" + profileMappingID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ProfileMappingDatabase database = subsystem.getProfileMappingDatabase();
+
+ return createOKResponse(createProfileMappingData(database.getRecord(profileMappingID)));
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response addProfileMapping(ProfileMappingData profileMappingData) {
+
+ CMS.debug("ProfileMappingService.addProfileMapping(\"" + profileMappingData.getID() + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ProfileMappingDatabase database = subsystem.getProfileMappingDatabase();
+
+ String status = profileMappingData.getStatus();
+ Principal principal = servletRequest.getUserPrincipal();
+
+ if (status == null || database.requiresApproval() && !database.canApprove(principal)) {
+ // if status is unspecified or user doesn't have rights to approve, the entry is disabled
+ profileMappingData.setStatus("Disabled");
+ }
+
+ database.addRecord(profileMappingData.getID(), createProfileMappingRecord(profileMappingData));
+ profileMappingData = createProfileMappingData(database.getRecord(profileMappingData.getID()));
+
+ return createCreatedResponse(profileMappingData, profileMappingData.getLink().getHref());
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response updateProfileMapping(String profileMappingID, ProfileMappingData profileMappingData) {
+
+ CMS.debug("ProfileMappingService.updateProfileMapping(\"" + profileMappingID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ProfileMappingDatabase database = subsystem.getProfileMappingDatabase();
+
+ ProfileMappingRecord record = database.getRecord(profileMappingID);
+
+ // only disabled profile mapping can be updated
+ if (!"Disabled".equals(record.getStatus())) {
+ throw new ForbiddenException("Unable to update profile mapping " + profileMappingID);
+ }
+
+ // update status if specified
+ String status = profileMappingData.getStatus();
+ if (status != null && !"Disabled".equals(status)) {
+ if (!"Enabled".equals(status)) {
+ throw new ForbiddenException("Invalid profile mapping status: " + status);
+ }
+
+ // if user doesn't have rights, set to pending
+ Principal principal = servletRequest.getUserPrincipal();
+ if (database.requiresApproval() && !database.canApprove(principal)) {
+ status = "Pending_Approval";
+ }
+
+ // enable profile mapping
+ record.setStatus(status);
+ }
+
+ // update properties if specified
+ Map<String, String> properties = profileMappingData.getProperties();
+ if (properties != null) {
+ record.setProperties(properties);
+ }
+
+ database.updateRecord(profileMappingID, record);
+
+ profileMappingData = createProfileMappingData(database.getRecord(profileMappingID));
+
+ return createOKResponse(profileMappingData);
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response changeProfileMappingStatus(String profileMappingID, String action) {
+
+ if (profileMappingID == null) throw new BadRequestException("Profile mapping ID is null.");
+ if (action == null) throw new BadRequestException("Action is null.");
+
+ CMS.debug("ProfileMappingService.changeProfileMappingStatus(\"" + profileMappingID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ProfileMappingDatabase database = subsystem.getProfileMappingDatabase();
+
+ ProfileMappingRecord record = database.getRecord(profileMappingID);
+ String status = record.getStatus();
+
+ if ("Disabled".equals(status)) {
+ if ("enable".equals(action)) {
+ status = "Enabled";
+ } else {
+ throw new BadRequestException("Invalid action: " + action);
+ }
+
+ } else if ("Enabled".equals(status)) {
+ if ("disable".equals(action)) {
+ status = "Disabled";
+ } else {
+ throw new BadRequestException("Invalid action: " + action);
+ }
+
+ } else if ("Pending_Approval".equals(status)) {
+ if ("approve".equals(action)) {
+ status = "Enabled";
+ } else if ("reject".equals(action)) {
+ status = "Disabled";
+ } else {
+ throw new BadRequestException("Invalid action: " + action);
+ }
+
+ } else {
+ throw new PKIException("Invalid profile mapping status: " + status);
+ }
+
+ record.setStatus(status);
+ database.updateRecord(profileMappingID, record);
+
+ ProfileMappingData profileMappingData = createProfileMappingData(database.getRecord(profileMappingID));
+
+ return createOKResponse(profileMappingData);
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response removeProfileMapping(String profileMappingID) {
+
+ CMS.debug("ProfileMappingService.removeProfileMapping(\"" + profileMappingID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ProfileMappingDatabase database = subsystem.getProfileMappingDatabase();
+
+ ProfileMappingRecord record = database.getRecord(profileMappingID);
+ String status = record.getStatus();
+
+ if (!"Disabled".equals(status)) {
+ throw new ForbiddenException("Unable to delete profile mapping " + profileMappingID);
+ }
+
+ database.removeRecord(profileMappingID);
+
+ return createNoContentResponse();
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/rest/ProfileService.java b/base/tps/src/org/dogtagpki/server/tps/rest/ProfileService.java
new file mode 100644
index 000000000..e5bfd4663
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/rest/ProfileService.java
@@ -0,0 +1,351 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.rest;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.security.Principal;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.dogtagpki.server.tps.TPSSubsystem;
+import org.dogtagpki.server.tps.config.ProfileDatabase;
+import org.dogtagpki.server.tps.config.ProfileRecord;
+import org.jboss.resteasy.plugins.providers.atom.Link;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.BadRequestException;
+import com.netscape.certsrv.base.ForbiddenException;
+import com.netscape.certsrv.base.PKIException;
+import com.netscape.certsrv.tps.profile.ProfileCollection;
+import com.netscape.certsrv.tps.profile.ProfileData;
+import com.netscape.certsrv.tps.profile.ProfileResource;
+import com.netscape.cms.servlet.base.PKIService;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class ProfileService extends PKIService implements ProfileResource {
+
+ @Context
+ private UriInfo uriInfo;
+
+ @Context
+ private HttpHeaders headers;
+
+ @Context
+ private Request request;
+
+ @Context
+ private HttpServletRequest servletRequest;
+
+ public ProfileService() {
+ CMS.debug("ProfileService.<init>()");
+ }
+
+ public ProfileData createProfileData(ProfileRecord profileRecord) throws UnsupportedEncodingException {
+
+ String profileID = profileRecord.getID();
+
+ ProfileData profileData = new ProfileData();
+ profileData.setID(profileID);
+ profileData.setStatus(profileRecord.getStatus());
+ profileData.setProperties(profileRecord.getProperties());
+
+ profileID = URLEncoder.encode(profileID, "UTF-8");
+ URI uri = uriInfo.getBaseUriBuilder().path(ProfileResource.class).path("{profileID}").build(profileID);
+ profileData.setLink(new Link("self", uri));
+
+ return profileData;
+ }
+
+ public ProfileRecord createProfileRecord(ProfileData profileData) {
+
+ ProfileRecord profileRecord = new ProfileRecord();
+ profileRecord.setID(profileData.getID());
+ profileRecord.setStatus(profileData.getStatus());
+ profileRecord.setProperties(profileData.getProperties());
+
+ return profileRecord;
+ }
+
+ @Override
+ public Response findProfiles(String filter, Integer start, Integer size) {
+
+ CMS.debug("ProfileService.findProfiles()");
+
+ if (filter != null && filter.length() < MIN_FILTER_LENGTH) {
+ throw new BadRequestException("Filter is too short.");
+ }
+
+ start = start == null ? 0 : start;
+ size = size == null ? DEFAULT_SIZE : size;
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ProfileDatabase database = subsystem.getProfileDatabase();
+
+ Iterator<ProfileRecord> profiles = database.findRecords(filter).iterator();
+
+ ProfileCollection response = new ProfileCollection();
+ int i = 0;
+
+ // skip to the start of the page
+ for ( ; i<start && profiles.hasNext(); i++) profiles.next();
+
+ // return entries up to the page size
+ for ( ; i<start+size && profiles.hasNext(); i++) {
+ response.addEntry(createProfileData(profiles.next()));
+ }
+
+ // count the total entries
+ for ( ; profiles.hasNext(); i++) profiles.next();
+ response.setTotal(i);
+
+ if (start > 0) {
+ URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", Math.max(start-size, 0)).build();
+ response.addLink(new Link("prev", uri));
+ }
+
+ if (start+size < i) {
+ URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", start+size).build();
+ response.addLink(new Link("next", uri));
+ }
+
+ return createOKResponse(response);
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response getProfile(String profileID) {
+
+ if (profileID == null) throw new BadRequestException("Profile ID is null.");
+
+ CMS.debug("ProfileService.getProfile(\"" + profileID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ProfileDatabase database = subsystem.getProfileDatabase();
+
+ return createOKResponse(createProfileData(database.getRecord(profileID)));
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response addProfile(ProfileData profileData) {
+
+ if (profileData == null) throw new BadRequestException("Profile data is null.");
+
+ CMS.debug("ProfileService.addProfile(\"" + profileData.getID() + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ProfileDatabase database = subsystem.getProfileDatabase();
+
+ String status = profileData.getStatus();
+ Principal principal = servletRequest.getUserPrincipal();
+
+ if (status == null || database.requiresApproval() && !database.canApprove(principal)) {
+ // if status is unspecified or user doesn't have rights to approve, the entry is disabled
+ profileData.setStatus("Disabled");
+ }
+
+ database.addRecord(profileData.getID(), createProfileRecord(profileData));
+
+ profileData = createProfileData(database.getRecord(profileData.getID()));
+
+ return createCreatedResponse(profileData, profileData.getLink().getHref());
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response updateProfile(String profileID, ProfileData profileData) {
+
+ if (profileID == null) throw new BadRequestException("Profile ID is null.");
+ if (profileData == null) throw new BadRequestException("Profile data is null.");
+
+ CMS.debug("ProfileService.updateProfile(\"" + profileID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ProfileDatabase database = subsystem.getProfileDatabase();
+
+ ProfileRecord record = database.getRecord(profileID);
+
+ // only disabled profile can be updated
+ if (!"Disabled".equals(record.getStatus())) {
+ throw new ForbiddenException("Unable to update profile " + profileID);
+ }
+
+ // update status if specified
+ String status = profileData.getStatus();
+ if (status != null && !"Disabled".equals(status)) {
+ if (!"Enabled".equals(status)) {
+ throw new ForbiddenException("Invalid profile status: " + status);
+ }
+
+ // if user doesn't have rights, set to pending
+ Principal principal = servletRequest.getUserPrincipal();
+ if (database.requiresApproval() && !database.canApprove(principal)) {
+ status = "Pending_Approval";
+ }
+
+ // enable profile
+ record.setStatus(status);
+ }
+
+ // update properties if specified
+ Map<String, String> properties = profileData.getProperties();
+ if (properties != null) {
+ record.setProperties(properties);
+ }
+
+ database.updateRecord(profileID, record);
+
+ profileData = createProfileData(database.getRecord(profileID));
+
+ return createOKResponse(profileData);
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response changeProfileStatus(String profileID, String action) {
+
+ if (profileID == null) throw new BadRequestException("Profile ID is null.");
+ if (action == null) throw new BadRequestException("Action is null.");
+
+ CMS.debug("ProfileService.changeProfileStatus(\"" + profileID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ProfileDatabase database = subsystem.getProfileDatabase();
+
+ ProfileRecord record = database.getRecord(profileID);
+ String status = record.getStatus();
+
+ if ("Disabled".equals(status)) {
+ if ("enable".equals(action)) {
+ status = "Enabled";
+ } else {
+ throw new BadRequestException("Invalid action: " + action);
+ }
+
+ } else if ("Enabled".equals(status)) {
+ if ("disable".equals(action)) {
+ status = "Disabled";
+ } else {
+ throw new BadRequestException("Invalid action: " + action);
+ }
+
+ } else if ("Pending_Approval".equals(status)) {
+ if ("approve".equals(action)) {
+ status = "Enabled";
+ } else if ("reject".equals(action)) {
+ status = "Disabled";
+ } else {
+ throw new BadRequestException("Invalid action: " + action);
+ }
+
+ } else {
+ throw new PKIException("Invalid profile status: " + status);
+ }
+
+ record.setStatus(status);
+ database.updateRecord(profileID, record);
+
+ ProfileData profileData = createProfileData(database.getRecord(profileID));
+
+ return createOKResponse(profileData);
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response removeProfile(String profileID) {
+
+ if (profileID == null) throw new BadRequestException("Profile ID is null.");
+
+ CMS.debug("ProfileService.removeProfile(\"" + profileID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ ProfileDatabase database = subsystem.getProfileDatabase();
+
+ ProfileRecord record = database.getRecord(profileID);
+ String status = record.getStatus();
+
+ if (!"Disabled".equals(status)) {
+ throw new ForbiddenException("Unable to delete profile " + profileID);
+ }
+
+ database.removeRecord(profileID);
+
+ return createNoContentResponse();
+
+ } catch (PKIException e) {
+ throw e;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/rest/TPSApplication.java b/base/tps/src/org/dogtagpki/server/tps/rest/TPSApplication.java
new file mode 100644
index 000000000..70c8afd02
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/rest/TPSApplication.java
@@ -0,0 +1,105 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps.rest;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import javax.ws.rs.core.Application;
+
+import org.dogtagpki.server.rest.ACLInterceptor;
+import org.dogtagpki.server.rest.AccountService;
+import org.dogtagpki.server.rest.AuditService;
+import org.dogtagpki.server.rest.AuthMethodInterceptor;
+import org.dogtagpki.server.rest.GroupService;
+import org.dogtagpki.server.rest.PKIExceptionMapper;
+import org.dogtagpki.server.rest.MessageFormatInterceptor;
+import org.dogtagpki.server.rest.SelfTestService;
+import org.dogtagpki.server.rest.SystemCertService;
+import org.dogtagpki.server.rest.UserService;
+import org.dogtagpki.server.tps.config.ConfigService;
+
+/**
+ * @author Endi S. Dewata <edewata@redhat.com>
+ */
+public class TPSApplication extends Application {
+
+ private Set<Object> singletons = new LinkedHashSet<Object>();
+ private Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
+
+ public TPSApplication() {
+
+ // account
+ classes.add(AccountService.class);
+
+ // audit
+ classes.add(AuditService.class);
+
+ // installer
+ classes.add(TPSInstallerService.class);
+
+ // user and group management
+ classes.add(GroupService.class);
+ classes.add(UserService.class);
+
+ // system certs
+ classes.add(SystemCertService.class);
+
+ // activities
+ classes.add(ActivityService.class);
+
+ // authenticators
+ classes.add(AuthenticatorService.class);
+
+ // certificates
+ classes.add(TPSCertService.class);
+
+ // config
+ classes.add(ConfigService.class);
+
+ // connections
+ classes.add(ConnectorService.class);
+
+ // profiles
+ classes.add(ProfileService.class);
+ classes.add(ProfileMappingService.class);
+
+ // selftests
+ classes.add(SelfTestService.class);
+
+ // tokens
+ classes.add(TokenService.class);
+
+ // exception mapper
+ classes.add(PKIExceptionMapper.class);
+
+ // interceptors
+ singletons.add(new AuthMethodInterceptor());
+ singletons.add(new ACLInterceptor());
+ singletons.add(new MessageFormatInterceptor());
+ }
+
+ public Set<Class<?>> getClasses() {
+ return classes;
+ }
+
+ public Set<Object> getSingletons() {
+ return singletons;
+ }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/rest/TPSCertService.java b/base/tps/src/org/dogtagpki/server/tps/rest/TPSCertService.java
new file mode 100644
index 000000000..75314cd5d
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/rest/TPSCertService.java
@@ -0,0 +1,179 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.rest;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.util.Iterator;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.dogtagpki.server.tps.TPSSubsystem;
+import org.dogtagpki.server.tps.dbs.TPSCertDatabase;
+import org.dogtagpki.server.tps.dbs.TPSCertRecord;
+import org.jboss.resteasy.plugins.providers.atom.Link;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.BadRequestException;
+import com.netscape.certsrv.base.PKIException;
+import com.netscape.certsrv.tps.cert.TPSCertCollection;
+import com.netscape.certsrv.tps.cert.TPSCertData;
+import com.netscape.certsrv.tps.cert.TPSCertResource;
+import com.netscape.cms.servlet.base.PKIService;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class TPSCertService extends PKIService implements TPSCertResource {
+
+ @Context
+ private UriInfo uriInfo;
+
+ @Context
+ private HttpHeaders headers;
+
+ @Context
+ private Request request;
+
+ @Context
+ private HttpServletRequest servletRequest;
+
+ public TPSCertService() {
+ System.out.println("TPSCertService.<init>()");
+ }
+
+ public TPSCertData createCertData(TPSCertRecord certRecord) {
+
+ TPSCertData certData = new TPSCertData();
+ certData.setID(certRecord.getId());
+ certData.setSerialNumber(certRecord.getSerialNumber());
+ certData.setSubject(certRecord.getSubject());
+ certData.setTokenID(certRecord.getTokenID());
+ certData.setKeyType(certRecord.getKeyType());
+ certData.setStatus(certRecord.getStatus());
+ certData.setUserID(certRecord.getUserID());
+ certData.setCreateTime(certRecord.getCreateTime());
+ certData.setModifyTime(certRecord.getModifyTime());
+
+ String certID = certRecord.getId();
+ try {
+ certID = URLEncoder.encode(certID, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+
+ URI uri = uriInfo.getBaseUriBuilder().path(TPSCertResource.class).path("{certID}").build(certID);
+ certData.setLink(new Link("self", uri));
+
+ return certData;
+ }
+
+ public TPSCertRecord createCertRecord(TPSCertData certData) {
+
+ TPSCertRecord certRecord = new TPSCertRecord();
+ certRecord.setId(certData.getID());
+ certRecord.setSerialNumber(certData.getSerialNumber());
+ certRecord.setSubject(certData.getSubject());
+ certRecord.setTokenID(certData.getTokenID());
+ certRecord.setKeyType(certData.getKeyType());
+ certRecord.setStatus(certData.getStatus());
+ certRecord.setUserID(certData.getUserID());
+ certRecord.setCreateTime(certData.getCreateTime());
+ certRecord.setModifyTime(certData.getModifyTime());
+
+ return certRecord;
+ }
+
+ @Override
+ public Response findCerts(String filter, Integer start, Integer size) {
+
+ System.out.println("TPSCertService.findCerts()");
+
+ if (filter != null && filter.length() < MIN_FILTER_LENGTH) {
+ throw new BadRequestException("Filter is too short.");
+ }
+
+ start = start == null ? 0 : start;
+ size = size == null ? DEFAULT_SIZE : size;
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ TPSCertDatabase database = subsystem.getCertDatabase();
+
+ Iterator<TPSCertRecord> activities = database.findRecords(filter).iterator();
+
+ TPSCertCollection response = new TPSCertCollection();
+ int i = 0;
+
+ // skip to the start of the page
+ for ( ; i<start && activities.hasNext(); i++) activities.next();
+
+ // return entries up to the page size
+ for ( ; i<start+size && activities.hasNext(); i++) {
+ response.addEntry(createCertData(activities.next()));
+ }
+
+ // count the total entries
+ for ( ; activities.hasNext(); i++) activities.next();
+ response.setTotal(i);
+
+ if (start > 0) {
+ URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", Math.max(start-size, 0)).build();
+ response.addLink(new Link("prev", uri));
+ }
+
+ if (start+size < i) {
+ URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", start+size).build();
+ response.addLink(new Link("next", uri));
+ }
+
+ return createOKResponse(response);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response getCert(String certID) {
+
+ if (certID == null) throw new BadRequestException("Certificate ID is null.");
+
+ System.out.println("TPSCertService.getCert(\"" + certID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ TPSCertDatabase database = subsystem.getCertDatabase();
+
+ return createOKResponse(createCertData(database.getRecord(certID)));
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/rest/TPSInstallerService.java b/base/tps/src/org/dogtagpki/server/tps/rest/TPSInstallerService.java
new file mode 100644
index 000000000..9c4943b9f
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/rest/TPSInstallerService.java
@@ -0,0 +1,153 @@
+// --- 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) 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package org.dogtagpki.server.tps.rest;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collection;
+
+import org.dogtagpki.server.rest.SystemConfigService;
+import org.dogtagpki.server.tps.installer.TPSInstaller;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.BadRequestException;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.PKIException;
+import com.netscape.certsrv.system.ConfigurationRequest;
+import com.netscape.certsrv.system.SystemCertData;
+import com.netscape.cms.servlet.csadmin.ConfigurationUtils;
+
+/**
+ * @author alee
+ *
+ */
+public class TPSInstallerService extends SystemConfigService {
+
+
+ public TPSInstallerService() throws EBaseException {
+ }
+
+ @Override
+ public void configureSubsystem(ConfigurationRequest request,
+ Collection<String> certList, String token, String domainXML) {
+
+ super.configureSubsystem(request, certList, token, domainXML);
+
+ // get subsystem certificate nickname
+ String nickname = null;
+ for (SystemCertData cert : request.getSystemCerts()) {
+ if (cert.getTag().equals("subsystem")) {
+ nickname = cert.getNickname();
+ break;
+ }
+ }
+
+ if (nickname == null || nickname.isEmpty()) {
+ throw new BadRequestException("No nickname provided for subsystem certificate");
+ }
+
+ // CA Info Panel
+ configureCAConnector(request, nickname);
+
+ // TKS Info Panel
+ configureTKSConnector(request, nickname);
+
+ //DRM Info Panel
+ configureKRAConnector(request, nickname);
+
+ //AuthDBPanel
+ ConfigurationUtils.updateAuthdbInfo(request.getAuthdbBaseDN(),
+ request.getAuthdbHost(), request.getAuthdbPort(),
+ request.getAuthdbSecureConn());
+ }
+
+ public void configureCAConnector(ConfigurationRequest request, String nickname) {
+
+ // TODO: get installer from session
+ TPSInstaller installer = new TPSInstaller();
+ installer.configureCAConnector(request.getCaUri(), nickname);
+ }
+
+ public void configureTKSConnector(ConfigurationRequest request, String nickname) {
+
+ // TODO: get installer from session
+ TPSInstaller installer = new TPSInstaller();
+ installer.configureTKSConnector(request.getTksUri(), nickname);
+ }
+
+ public void configureKRAConnector(ConfigurationRequest request, String nickname) {
+
+ boolean keygen = request.getEnableServerSideKeyGen().equalsIgnoreCase("true");
+
+ // TODO: get installer from session
+ TPSInstaller installer = new TPSInstaller();
+ installer.configureKRAConnector(keygen, request.getKraUri(), nickname);
+ }
+
+ @Override
+ public void configureDatabase(ConfigurationRequest request) {
+
+ super.configureDatabase(request);
+
+ cs.putString("tokendb.activityBaseDN", "ou=Activities," + request.getBaseDN());
+ cs.putString("tokendb.baseDN", "ou=Tokens," + request.getBaseDN());
+ cs.putString("tokendb.certBaseDN", "ou=Certificates," + request.getBaseDN());
+ cs.putString("tokendb.userBaseDN", request.getBaseDN());
+ cs.putString("tokendb.hostport", request.getDsHost() + ":" + request.getDsPort());
+ }
+
+ @Override
+ public void finalizeConfiguration(ConfigurationRequest request) {
+
+ super.finalizeConfiguration(request);
+
+ try {
+ ConfigurationUtils.addProfilesToTPSUser(request.getAdminUID());
+
+ URI secdomainURI = new URI(request.getSecurityDomainUri());
+
+ // register TPS with CA
+ URI caURI = request.getCaUri();
+ ConfigurationUtils.registerUser(secdomainURI, caURI, "ca");
+
+ // register TPS with TKS
+ URI tksURI = request.getTksUri();
+ ConfigurationUtils.registerUser(secdomainURI, tksURI, "tks");
+
+ if (request.getEnableServerSideKeyGen().equalsIgnoreCase("true")) {
+ URI kraURI = request.getKraUri();
+ ConfigurationUtils.registerUser(secdomainURI, kraURI, "kra");
+ String transportCert = ConfigurationUtils.getTransportCert(secdomainURI, kraURI);
+ ConfigurationUtils.exportTransportCert(secdomainURI, tksURI, transportCert);
+ }
+
+ // generate shared secret from the tks
+ ConfigurationUtils.getSharedSecret(
+ tksURI.getHost(),
+ tksURI.getPort(),
+ Boolean.getBoolean(request.getImportSharedSecret()));
+
+ } catch (URISyntaxException e) {
+ throw new BadRequestException("Invalid URI for CA, TKS or KRA");
+
+ } catch (Exception e) {
+ CMS.debug(e);
+ throw new PKIException("Errors in registering TPS to CA, TKS or KRA: " + e);
+ }
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/rest/TokenService.java b/base/tps/src/org/dogtagpki/server/tps/rest/TokenService.java
new file mode 100644
index 000000000..a58447089
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/rest/TokenService.java
@@ -0,0 +1,562 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.rest;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.dogtagpki.server.tps.TPSSubsystem;
+import org.dogtagpki.server.tps.dbs.ActivityDatabase;
+import org.dogtagpki.server.tps.dbs.TokenDatabase;
+import org.dogtagpki.server.tps.dbs.TokenRecord;
+import org.jboss.resteasy.plugins.providers.atom.Link;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.BadRequestException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.PKIException;
+import com.netscape.certsrv.tps.token.TokenCollection;
+import com.netscape.certsrv.tps.token.TokenData;
+import com.netscape.certsrv.tps.token.TokenResource;
+import com.netscape.certsrv.tps.token.TokenStatus;
+import com.netscape.cms.servlet.base.PKIService;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class TokenService extends PKIService implements TokenResource {
+
+ @Context
+ private UriInfo uriInfo;
+
+ @Context
+ private HttpHeaders headers;
+
+ @Context
+ private Request request;
+
+ @Context
+ private HttpServletRequest servletRequest;
+
+ public Map<TokenStatus, Collection<TokenStatus>> transitions = new HashMap<TokenStatus, Collection<TokenStatus>>();
+
+ public TokenService() throws Exception {
+ CMS.debug("TokenService.<init>()");
+ IConfigStore configStore = CMS.getConfigStore();
+
+ // load allowed token state transitions
+ CMS.debug("TokenService: allowed transitions:");
+
+ for (String transition : configStore.getString("tokendb.allowedTransitions").split(",")) {
+ String states[] = transition.split(":");
+ TokenStatus fromState = TokenStatus.fromInt(Integer.valueOf(states[0]));
+ TokenStatus toState = TokenStatus.fromInt(Integer.valueOf(states[1]));
+ CMS.debug("TokenService: - " + fromState + " to " + toState);
+
+ Collection<TokenStatus> nextStates = transitions.get(fromState);
+ if (nextStates == null) {
+ nextStates = new HashSet<TokenStatus>();
+ transitions.put(fromState, nextStates);
+ }
+ nextStates.add(toState);
+ }
+
+ }
+
+ public TokenStatus getTokenStatus(TokenRecord tokenRecord) {
+ String status = tokenRecord.getStatus();
+
+ if ("uninitialized".equals(status)) {
+ return TokenStatus.UNINITIALIZED;
+
+ } else if ("active".equals(status)) {
+ return TokenStatus.ACTIVE;
+
+ } else if ("lost".equals(status)) {
+ String reason = tokenRecord.getReason();
+
+ if ("keyCompromise".equals(reason)) {
+ return TokenStatus.PERM_LOST;
+
+ } else if ("destroyed".equals(reason)) {
+ return TokenStatus.DAMAGED;
+
+ } else if ("onHold".equals(reason)) {
+ return TokenStatus.TEMP_LOST;
+ }
+
+ } else if ("terminated".equals(status)) {
+ return TokenStatus.TERMINATED;
+ }
+
+ return TokenStatus.PERM_LOST;
+ }
+
+ public void setTokenStatus(TokenRecord tokenRecord, TokenStatus tokenState) throws Exception {
+ TPSSubsystem tps = (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+
+ switch (tokenState) {
+ case UNINITIALIZED:
+ tokenRecord.setStatus("uninitialized");
+ tokenRecord.setReason(null);
+ break;
+ case ACTIVE:
+ String origStatus = tokenRecord.getStatus();
+ String origReason = tokenRecord.getReason();
+ if (origStatus.equalsIgnoreCase("lost") &&
+ origReason.equalsIgnoreCase("onHold")) {
+ //unrevoke certs
+ tps.tdb.unRevokeCertsByCUID(tokenRecord.getId());
+ }
+
+ tokenRecord.setStatus("active");
+ tokenRecord.setReason(null);
+ break;
+ case PERM_LOST:
+ case TEMP_LOST_PERM_LOST:
+ tokenRecord.setStatus("lost");
+ tokenRecord.setReason("keyCompromise");
+
+ //revoke certs
+ tps.tdb.revokeCertsByCUID(tokenRecord.getId(), "keyCompromise");
+ break;
+ case DAMAGED:
+ tokenRecord.setStatus("lost");
+ tokenRecord.setReason("destroyed");
+
+ //revoke certs
+ tps.tdb.revokeCertsByCUID(tokenRecord.getId(), "destroyed");
+
+ break;
+ case TEMP_LOST:
+ tokenRecord.setStatus("lost");
+ tokenRecord.setReason("onHold");
+
+ // put certs onHold
+ tps.tdb.revokeCertsByCUID(tokenRecord.getId(), "onHold");
+ break;
+ case TERMINATED:
+ String reason = "keyCompromise";
+ String origStatus2 = tokenRecord.getStatus();
+ String origReason2 = tokenRecord.getReason();
+ // temp token looks at "onHold"
+ if (origStatus2.equalsIgnoreCase("lost") &&
+ origReason2.equalsIgnoreCase("onHold")) {
+ reason = "onHold";
+ }
+ tokenRecord.setStatus("terminated");
+ tokenRecord.setReason(reason);
+
+ //revoke certs
+ tps.tdb.revokeCertsByCUID(tokenRecord.getId(), reason) ;
+ break;
+ default:
+ throw new PKIException("Unsupported token state: " + tokenState);
+ }
+
+ }
+
+ public TokenData createTokenData(TokenRecord tokenRecord) {
+
+ TokenData tokenData = new TokenData();
+ tokenData.setID(tokenRecord.getId());
+ tokenData.setTokenID(tokenRecord.getId());
+ tokenData.setUserID(tokenRecord.getUserID());
+ tokenData.setType(tokenRecord.getType());
+ tokenData.setStatus(getTokenStatus(tokenRecord));
+ tokenData.setAppletID(tokenRecord.getAppletID());
+ tokenData.setKeyInfo(tokenRecord.getKeyInfo());
+ tokenData.setPolicy(tokenRecord.getPolicy());
+ tokenData.setCreateTimestamp(tokenRecord.getCreateTimestamp());
+ tokenData.setModifyTimestamp(tokenRecord.getModifyTimestamp());
+
+ String tokenID = tokenRecord.getId();
+ try {
+ tokenID = URLEncoder.encode(tokenID, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+
+ URI uri = uriInfo.getBaseUriBuilder().path(TokenResource.class).path("{tokenID}").build(tokenID);
+ tokenData.setLink(new Link("self", uri));
+
+ return tokenData;
+ }
+
+ public TokenRecord createTokenRecord(TokenData tokenData) throws Exception {
+
+ TokenRecord tokenRecord = new TokenRecord();
+ tokenRecord.setId(tokenData.getID());
+ tokenRecord.setUserID(tokenData.getUserID());
+ tokenRecord.setType(tokenData.getType());
+ setTokenStatus(tokenRecord, tokenData.getStatus());
+ tokenRecord.setAppletID(tokenData.getAppletID());
+ tokenRecord.setKeyInfo(tokenData.getKeyInfo());
+ tokenRecord.setPolicy(tokenData.getPolicy());
+ tokenRecord.setCreateTimestamp(tokenData.getCreateTimestamp());
+ tokenRecord.setModifyTimestamp(tokenData.getModifyTimestamp());
+
+ return tokenRecord;
+ }
+
+ @Override
+ public Response findTokens(String filter, Integer start, Integer size) {
+
+ CMS.debug("TokenService.findTokens()");
+
+ if (filter != null && filter.length() < MIN_FILTER_LENGTH) {
+ throw new BadRequestException("Filter is too short.");
+ }
+
+ start = start == null ? 0 : start;
+ size = size == null ? DEFAULT_SIZE : size;
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ TokenDatabase database = subsystem.getTokenDatabase();
+
+ Iterator<TokenRecord> tokens = database.findRecords(filter).iterator();
+
+ TokenCollection response = new TokenCollection();
+ int i = 0;
+
+ // skip to the start of the page
+ for ( ; i<start && tokens.hasNext(); i++) tokens.next();
+
+ // return entries up to the page size
+ for ( ; i<start+size && tokens.hasNext(); i++) {
+ response.addEntry(createTokenData(tokens.next()));
+ }
+
+ // count the total entries
+ for ( ; tokens.hasNext(); i++) tokens.next();
+ response.setTotal(i);
+
+ if (start > 0) {
+ URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", Math.max(start-size, 0)).build();
+ response.addLink(new Link("prev", uri));
+ }
+
+ if (start+size < i) {
+ URI uri = uriInfo.getRequestUriBuilder().replaceQueryParam("start", start+size).build();
+ response.addLink(new Link("next", uri));
+ }
+
+ return createOKResponse(response);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response getToken(String tokenID) {
+
+ if (tokenID == null) throw new BadRequestException("Token ID is null.");
+
+ CMS.debug("TokenService.getToken(\"" + tokenID + "\")");
+
+ try {
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ TokenDatabase database = subsystem.getTokenDatabase();
+
+ return createOKResponse(createTokenData(database.getRecord(tokenID)));
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new PKIException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Response addToken(TokenData tokenData) {
+
+ if (tokenData == null) throw new BadRequestException("Token data is null.");
+
+ String tokenID = tokenData.getTokenID();
+ CMS.debug("TokenService.addToken(\"" + tokenID + "\")");
+
+ String remoteUser = servletRequest.getRemoteUser();
+ String ipAddress = servletRequest.getRemoteAddr();
+
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ TokenRecord tokenRecord = null;
+ String msg = "add token";
+
+ try {
+ TokenDatabase database = subsystem.getTokenDatabase();
+
+ // new tokens are uninitialized when created
+ tokenData.setStatus(TokenStatus.UNINITIALIZED);
+
+ tokenRecord = createTokenRecord(tokenData);
+ tokenRecord.setId(tokenID);
+ database.addRecord(tokenID, tokenRecord);
+ subsystem.tdb.tdbActivity(ActivityDatabase.OP_ADD, tokenRecord,
+ ipAddress, msg, "success", remoteUser);
+ tokenData = createTokenData(database.getRecord(tokenID));
+
+ return createCreatedResponse(tokenData, tokenData.getLink().getHref());
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ subsystem.tdb.tdbActivity(ActivityDatabase.OP_ADD, tokenRecord,
+ ipAddress, msg, "failure", remoteUser);
+ msg = msg + ":" + e;
+
+ throw new PKIException(msg);
+ }
+ }
+
+ @Override
+ public Response replaceToken(String tokenID, TokenData tokenData) {
+
+ if (tokenID == null) throw new BadRequestException("Token ID is null.");
+ if (tokenData == null) throw new BadRequestException("Token data is null.");
+
+ CMS.debug("TokenService.replaceToken(\"" + tokenID + "\")");
+
+ String remoteUser = servletRequest.getRemoteUser();
+ String ipAddress = servletRequest.getRemoteAddr();
+
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ TokenRecord tokenRecord = null;
+ String msg = "replace token";
+ try {
+ TokenDatabase database = subsystem.getTokenDatabase();
+
+ tokenRecord = database.getRecord(tokenID);
+ tokenRecord.setUserID(remoteUser);
+ tokenRecord.setType(tokenData.getType());
+ tokenRecord.setAppletID(tokenData.getAppletID());
+ tokenRecord.setKeyInfo(tokenData.getKeyInfo());
+ tokenRecord.setPolicy(tokenData.getPolicy());
+ database.updateRecord(tokenID, tokenRecord);
+ subsystem.tdb.tdbActivity(ActivityDatabase.OP_DO_TOKEN, tokenRecord,
+ ipAddress, msg, "success", remoteUser);
+
+ tokenData = createTokenData(database.getRecord(tokenID));
+
+ return createOKResponse(tokenData);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ subsystem.tdb.tdbActivity(ActivityDatabase.OP_DO_TOKEN, tokenRecord,
+ ipAddress, msg, "failure",
+ remoteUser);
+ msg = msg + ":" + e;
+
+ throw new PKIException(msg);
+ }
+ }
+
+ @Override
+ public Response modifyToken(String tokenID, TokenData tokenData) {
+
+ if (tokenID == null) throw new BadRequestException("Token ID is null.");
+ if (tokenData == null) throw new BadRequestException("Token data is null.");
+
+ CMS.debug("TokenService.modifyToken(\"" + tokenID + "\")");
+
+ String remoteUser = servletRequest.getRemoteUser();
+ String ipAddress = servletRequest.getRemoteAddr();
+
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ TokenRecord tokenRecord = null;
+ String msg = "modify token";
+ try {
+ TokenDatabase database = subsystem.getTokenDatabase();
+
+ // get existing record
+ tokenRecord = database.getRecord(tokenID);
+
+ // update user ID if specified
+ String userID = tokenData.getUserID();
+ if (userID != null) {
+ if (userID.equals("")) { // remove value if empty
+ tokenRecord.setUserID(null);
+ } else { // otherwise replace value
+ tokenRecord.setUserID(userID);
+ }
+ }
+
+ // update type if specified
+ String type = tokenData.getType();
+ if (type != null) {
+ if (type.equals("")) { // remove value if empty
+ tokenRecord.setType(null);
+ } else { // otherwise replace value
+ tokenRecord.setType(type);
+ }
+ }
+
+ // update applet ID if specified
+ String appletID = tokenData.getAppletID();
+ if (appletID != null) {
+ if (appletID.equals("")) { // remove value if empty
+ tokenRecord.setAppletID(null);
+ } else { // otherwise replace value
+ tokenRecord.setAppletID(appletID);
+ }
+ }
+
+ // update key info if specified
+ String keyInfo = tokenData.getKeyInfo();
+ if (keyInfo != null) {
+ if (keyInfo.equals("")) { // remove value if empty
+ tokenRecord.setKeyInfo(null);
+ } else { // otherwise replace value
+ tokenRecord.setKeyInfo(keyInfo);
+ }
+ }
+
+ // update policy if specified
+ String policy = tokenData.getPolicy();
+ if (policy != null) {
+ if (policy.equals("")) { // remove value if empty
+ tokenRecord.setPolicy(null);
+ } else { //otherwise replace value
+ tokenRecord.setPolicy(policy);
+ }
+ }
+
+ database.updateRecord(tokenID, tokenRecord);
+ subsystem.tdb.tdbActivity(ActivityDatabase.OP_DO_TOKEN, tokenRecord,
+ ipAddress, msg, "success", remoteUser);
+
+ tokenData = createTokenData(database.getRecord(tokenID));
+
+ return createOKResponse(tokenData);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ subsystem.tdb.tdbActivity(ActivityDatabase.OP_DO_TOKEN, tokenRecord,
+ ipAddress, msg, "failure",
+ remoteUser);
+ msg = msg + ":" + e;
+
+ throw new PKIException(msg);
+ }
+ }
+
+ @Override
+ public Response changeTokenStatus(String tokenID, TokenStatus tokenStatus) {
+
+ if (tokenID == null) throw new BadRequestException("Token ID is null.");
+ if (tokenStatus == null) throw new BadRequestException("Token state is null.");
+
+ CMS.debug("TokenService.changeTokenStatus(\"" + tokenID + "\", \"" + tokenStatus + "\")");
+
+ String remoteUser = servletRequest.getRemoteUser();
+ String ipAddress = servletRequest.getRemoteAddr();
+
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ TokenRecord tokenRecord = null;
+ String msg = "";
+ try {
+ TokenDatabase database = subsystem.getTokenDatabase();
+
+ tokenRecord = database.getRecord(tokenID);
+ TokenStatus currentTokenStatus = getTokenStatus(tokenRecord);
+ CMS.debug("TokenService.changeTokenStatus(): current status: " + currentTokenStatus);
+ msg = "change token status from " + currentTokenStatus + " to " + tokenStatus;
+
+ // make sure transition is allowed
+ Collection<TokenStatus> nextStatuses = transitions.get(currentTokenStatus);
+ CMS.debug("TokenService.changeTokenStatus(): allowed next statuses: " + nextStatuses);
+ if (nextStatuses == null || !nextStatuses.contains(tokenStatus)) {
+ CMS.debug("TokenService.changeTokenStatus(): next status not allowed: " + tokenStatus);
+ msg = msg + ": Invalid token status transition";
+ subsystem.tdb.tdbActivity(ActivityDatabase.OP_DO_TOKEN, tokenRecord,
+ ipAddress, msg,
+ "failure",
+ remoteUser);
+ throw new BadRequestException(msg);
+ }
+
+ CMS.debug("TokenService.changeTokenStatus(): next status allowed: " + tokenStatus);
+ setTokenStatus(tokenRecord, tokenStatus);
+ database.updateRecord(tokenID, tokenRecord);
+ subsystem.tdb.tdbActivity(ActivityDatabase.OP_DO_TOKEN, tokenRecord,
+ ipAddress, msg, "success",
+ remoteUser);
+
+ TokenData tokenData = createTokenData(database.getRecord(tokenID));
+
+ return createOKResponse(tokenData);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ msg = msg + e;
+ subsystem.tdb.tdbActivity(ActivityDatabase.OP_DO_TOKEN, tokenRecord,
+ ipAddress, msg, "failure",
+ remoteUser);
+
+ throw new PKIException(msg);
+ }
+ }
+
+ @Override
+ public Response removeToken(String tokenID) {
+
+ if (tokenID == null) throw new BadRequestException("Token ID is null.");
+
+ CMS.debug("TokenService.removeToken(\"" + tokenID + "\")");
+
+ String remoteUser = servletRequest.getRemoteUser();
+ String ipAddress = servletRequest.getRemoteAddr();
+
+ TPSSubsystem subsystem = (TPSSubsystem)CMS.getSubsystem(TPSSubsystem.ID);
+ TokenRecord tokenRecord = null;
+ String msg = "remove token";
+ try {
+ TokenDatabase database = subsystem.getTokenDatabase();
+ tokenRecord = database.getRecord(tokenID);
+ database.removeRecord(tokenID);
+ subsystem.tdb.tdbActivity(ActivityDatabase.OP_DELETE, tokenRecord,
+ ipAddress, msg, "success", remoteUser);
+
+ return createNoContentResponse();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ subsystem.tdb.tdbActivity(ActivityDatabase.OP_DELETE, tokenRecord,
+ ipAddress, msg, "failure",
+ remoteUser);
+ msg = msg + ":" + e;
+
+ throw new PKIException(msg);
+ }
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/selftests/TPSPresence.java b/base/tps/src/org/dogtagpki/server/tps/selftests/TPSPresence.java
new file mode 100644
index 000000000..65ac197e7
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/selftests/TPSPresence.java
@@ -0,0 +1,187 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.selftests;
+
+import java.security.PublicKey;
+import java.util.Locale;
+
+import org.dogtagpki.server.tps.TPSSubsystem;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.logging.ILogEventListener;
+import com.netscape.certsrv.selftests.EDuplicateSelfTestException;
+import com.netscape.certsrv.selftests.EInvalidSelfTestException;
+import com.netscape.certsrv.selftests.EMissingSelfTestException;
+import com.netscape.certsrv.selftests.ESelfTestException;
+import com.netscape.certsrv.selftests.ISelfTestSubsystem;
+import com.netscape.cms.selftests.ASelfTest;
+
+/**
+ * This class implements a self test to check for TPS presence.
+ * <P>
+ *
+ * @author alee
+ * @version $Revision$, $Date$
+ */
+public class TPSPresence extends ASelfTest {
+
+ public static final String PROP_TPS_SUB_ID = "TpsSubId";
+ private String tpsSubId = null;
+
+ /**
+ * Initializes this subsystem with the configuration store
+ * associated with this instance name.
+ * <P>
+ *
+ * @param subsystem the associated subsystem
+ * @param instanceName the name of this self test instance
+ * @param parameters configuration store (self test parameters)
+ * @exception EDuplicateSelfTestException subsystem has duplicate name/value
+ * @exception EInvalidSelfTestException subsystem has invalid name/value
+ * @exception EMissingSelfTestException subsystem has missing name/value
+ */
+ public void initSelfTest(ISelfTestSubsystem subsystem, String instanceName,
+ IConfigStore parameters) throws EDuplicateSelfTestException, EInvalidSelfTestException,
+ EMissingSelfTestException {
+ super.initSelfTest(subsystem, instanceName, parameters);
+
+ try {
+ tpsSubId = mConfig.getString(PROP_TPS_SUB_ID);
+ if (tpsSubId != null) {
+ tpsSubId = tpsSubId.trim();
+ } else {
+ mSelfTestSubsystem.log(mSelfTestSubsystem.getSelfTestLogger(),
+ CMS.getLogMessage("SELFTESTS_MISSING_VALUES", getSelfTestName(),
+ mPrefix + "." + PROP_TPS_SUB_ID));
+
+ throw new EMissingSelfTestException(PROP_TPS_SUB_ID);
+ }
+ } catch (EBaseException e) {
+ mSelfTestSubsystem.log(mSelfTestSubsystem.getSelfTestLogger(),
+ CMS.getLogMessage("SELFTESTS_MISSING_NAME", getSelfTestName(),
+ mPrefix + "." + PROP_TPS_SUB_ID));
+
+ throw new EMissingSelfTestException(mPrefix, PROP_TPS_SUB_ID, null);
+ }
+ }
+
+ /**
+ * Notifies this subsystem if it is in execution mode.
+ * <P>
+ *
+ * @exception ESelfTestException failed to start
+ */
+ public void startupSelfTest() throws ESelfTestException {
+ }
+
+ /**
+ * Stops this subsystem. The subsystem may call shutdownSelfTest
+ * anytime after initialization.
+ * <P>
+ */
+ public void shutdownSelfTest() {
+ }
+
+ /**
+ * Returns the name associated with this self test. This method may
+ * return null if the self test has not been initialized.
+ * <P>
+ *
+ * @return instanceName of this self test
+ */
+ public String getSelfTestName() {
+ return super.getSelfTestName();
+ }
+
+ /**
+ * Returns the root configuration storage (self test parameters)
+ * associated with this subsystem.
+ * <P>
+ *
+ * @return configuration store (self test parameters) of this subsystem
+ */
+ public IConfigStore getSelfTestConfigStore() {
+ return super.getSelfTestConfigStore();
+ }
+
+ /**
+ * Retrieves description associated with an individual self test.
+ * This method may return null.
+ * <P>
+ *
+ * @param locale locale of the client that requests the description
+ * @return description of self test
+ */
+ public String getSelfTestDescription(Locale locale) {
+ return CMS.getUserMessage(locale,
+ "CMS_SELFTESTS_TPS_PRESENCE_DESCRIPTION");
+ }
+
+ /**
+ * Execute an individual self test.
+ * <P>
+ *
+ * @param logger specifies logging subsystem
+ * @exception ESelfTestException self test exception
+ */
+ public void runSelfTest(ILogEventListener logger)
+ throws ESelfTestException {
+ String logMessage = null;
+ TPSSubsystem tps = (TPSSubsystem) CMS.getSubsystem(tpsSubId);
+ if (tps == null) {
+ // log that the TPS is not installed
+ logMessage = CMS.getLogMessage("SELFTESTS_TPS_IS_NOT_PRESENT", getSelfTestName());
+ mSelfTestSubsystem.log(logger, logMessage);
+ throw new ESelfTestException(logMessage);
+ }
+
+ // Retrieve the TPS certificate
+ org.mozilla.jss.crypto.X509Certificate tpsCert = null;
+ try {
+ tpsCert = tps.getSubsystemCert();
+ } catch (Exception e) {
+ e.printStackTrace();
+ // cert does not exist or is not yet configured
+ // tpsCert will remain null
+ }
+
+ if (tpsCert == null) {
+ // log that the TPS is not yet initialized
+ logMessage = CMS.getLogMessage("SELFTESTS_TPS_IS_NOT_INITIALIZED",
+ getSelfTestName());
+ mSelfTestSubsystem.log(logger, logMessage);
+ throw new ESelfTestException(logMessage);
+ }
+
+ // Retrieve the TPS certificate public key
+ PublicKey tpsPubKey = tpsCert.getPublicKey();
+ if (tpsPubKey == null) {
+ // log that something is seriously wrong with the TPS
+ logMessage = CMS.getLogMessage("SELFTESTS_TPS_IS_CORRUPT", getSelfTestName());
+ mSelfTestSubsystem.log(logger, logMessage);
+ throw new ESelfTestException(logMessage);
+ }
+
+ // log that the TPS is present
+ logMessage = CMS.getLogMessage("SELFTESTS_TPS_IS_PRESENT", getSelfTestName());
+ mSelfTestSubsystem.log(logger, logMessage);
+ }
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/selftests/TPSValidity.java b/base/tps/src/org/dogtagpki/server/tps/selftests/TPSValidity.java
new file mode 100644
index 000000000..f140d6e7c
--- /dev/null
+++ b/base/tps/src/org/dogtagpki/server/tps/selftests/TPSValidity.java
@@ -0,0 +1,197 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.selftests;
+
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.util.Locale;
+
+import netscape.security.x509.X509CertImpl;
+
+import org.dogtagpki.server.tps.TPSSubsystem;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.logging.ILogEventListener;
+import com.netscape.certsrv.selftests.EDuplicateSelfTestException;
+import com.netscape.certsrv.selftests.EInvalidSelfTestException;
+import com.netscape.certsrv.selftests.EMissingSelfTestException;
+import com.netscape.certsrv.selftests.ESelfTestException;
+import com.netscape.certsrv.selftests.ISelfTestSubsystem;
+import com.netscape.cms.selftests.ASelfTest;
+
+/**
+ * This class implements a self test to check the validity of the TPS.
+ * <P>
+ *
+ * @author alee
+ * @version $Revision$, $Date$
+ */
+public class TPSValidity extends ASelfTest {
+
+ // parameter information
+ public static final String PROP_TPS_SUB_ID = "TpsSubId";
+ private String tpsSubId = null;
+
+ /**
+ * Initializes this subsystem with the configuration store
+ * associated with this instance name.
+ * <P>
+ *
+ * @param subsystem the associated subsystem
+ * @param instanceName the name of this self test instance
+ * @param parameters configuration store (self test parameters)
+ * @exception EDuplicateSelfTestException subsystem has duplicate name/value
+ * @exception EInvalidSelfTestException subsystem has invalid name/value
+ * @exception EMissingSelfTestException subsystem has missing name/value
+ */
+ public void initSelfTest(ISelfTestSubsystem subsystem, String instanceName,
+ IConfigStore parameters) throws EDuplicateSelfTestException,
+ EInvalidSelfTestException, EMissingSelfTestException {
+ super.initSelfTest(subsystem, instanceName, parameters);
+
+ try {
+ tpsSubId = mConfig.getString(PROP_TPS_SUB_ID);
+ if (tpsSubId != null) {
+ tpsSubId = tpsSubId.trim();
+ } else {
+ mSelfTestSubsystem.log(mSelfTestSubsystem.getSelfTestLogger(),
+ CMS.getLogMessage("SELFTESTS_MISSING_VALUES", getSelfTestName(),
+ mPrefix + "." + PROP_TPS_SUB_ID));
+
+ throw new EMissingSelfTestException(PROP_TPS_SUB_ID);
+ }
+ } catch (EBaseException e) {
+ mSelfTestSubsystem.log(mSelfTestSubsystem.getSelfTestLogger(),
+ CMS.getLogMessage("SELFTESTS_MISSING_NAME", getSelfTestName(),
+ mPrefix + "." + PROP_TPS_SUB_ID));
+
+ throw new EMissingSelfTestException(mPrefix, PROP_TPS_SUB_ID, null);
+ }
+ }
+
+ /**
+ * Notifies this subsystem if it is in execution mode.
+ * <P>
+ *
+ * @exception ESelfTestException failed to start
+ */
+ public void startupSelfTest() throws ESelfTestException {
+ }
+
+ /**
+ * Stops this subsystem. The subsystem may call shutdownSelfTest
+ * anytime after initialization.
+ * <P>
+ */
+ public void shutdownSelfTest() {
+ }
+
+ /**
+ * Returns the name associated with this self test. This method may
+ * return null if the self test has not been intialized.
+ * <P>
+ *
+ * @return instanceName of this self test
+ */
+ public String getSelfTestName() {
+ return super.getSelfTestName();
+ }
+
+ /**
+ * Returns the root configuration storage (self test parameters)
+ * associated with this subsystem.
+ * <P>
+ *
+ * @return configuration store (self test parameters) of this subsystem
+ */
+ public IConfigStore getSelfTestConfigStore() {
+ return super.getSelfTestConfigStore();
+ }
+
+ /**
+ * Retrieves description associated with an individual self test.
+ * This method may return null.
+ * <P>
+ *
+ * @param locale locale of the client that requests the description
+ * @return description of self test
+ */
+ public String getSelfTestDescription(Locale locale) {
+ return CMS.getUserMessage(locale,
+ "CMS_SELFTESTS_TPS_VALIDITY_DESCRIPTION");
+ }
+
+ /**
+ * Execute an individual self test.
+ * <P>
+ *
+ * @param logger specifies logging subsystem
+ * @exception ESelfTestException self test exception
+ */
+ public void runSelfTest(ILogEventListener logger)
+ throws ESelfTestException {
+ String logMessage = null;
+ TPSSubsystem tps = (TPSSubsystem) CMS.getSubsystem(tpsSubId);
+
+ if (tps == null) {
+ // log that the TPS is not installed
+ logMessage = CMS.getLogMessage("SELFTESTS_TPS_IS_NOT_PRESENT", getSelfTestName());
+ mSelfTestSubsystem.log(logger, logMessage);
+ throw new ESelfTestException(logMessage);
+ }
+
+ // Retrieve the TPS subsystem certificate
+ X509CertImpl tpsCert = null;
+ try {
+ tpsCert = new X509CertImpl(tps.getSubsystemCert().getEncoded());
+ } catch (Exception e) {
+ // certificate is not present or has not been configured
+ // tpsCert will remain null
+ }
+
+ if (tpsCert == null) {
+ // log that the TPS is not yet initialized
+ logMessage = CMS.getLogMessage("SELFTESTS_TPS_IS_NOT_INITIALIZED",
+ getSelfTestName());
+ mSelfTestSubsystem.log(logger, logMessage);
+ throw new ESelfTestException(logMessage);
+ }
+
+ // Check the TPS validity period
+ try {
+ tpsCert.checkValidity();
+ } catch (CertificateNotYetValidException e) {
+ // log that the TPS is not yet valid
+ logMessage = CMS.getLogMessage("SELFTESTS_TPS_IS_NOT_YET_VALID", getSelfTestName());
+ mSelfTestSubsystem.log(logger, logMessage);
+ throw new ESelfTestException(logMessage);
+ } catch (CertificateExpiredException e) {
+ // log that the TPS is expired
+ logMessage = CMS.getLogMessage("SELFTESTS_TPS_IS_EXPIRED", getSelfTestName());
+ mSelfTestSubsystem.log(logger, logMessage);
+ throw new ESelfTestException(logMessage);
+ }
+
+ // log that the TPS is valid
+ logMessage = CMS.getLogMessage("SELFTESTS_TPS_IS_VALID", getSelfTestName());
+ mSelfTestSubsystem.log(logger, logMessage);
+ }
+}
diff --git a/base/tps/src/pki-tps.mf b/base/tps/src/pki-tps.mf
new file mode 100644
index 000000000..d77fe8fa9
--- /dev/null
+++ b/base/tps/src/pki-tps.mf
@@ -0,0 +1,3 @@
+Name: pki-tps
+Specification-Version: ${APPLICATION_VERSION}
+Implementation-Version: ${VERSION}