summaryrefslogtreecommitdiffstats
path: root/base/kra/functional/src/com/netscape/cms
diff options
context:
space:
mode:
Diffstat (limited to 'base/kra/functional/src/com/netscape/cms')
-rw-r--r--base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java266
-rw-r--r--base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java503
-rw-r--r--base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java222
3 files changed, 991 insertions, 0 deletions
diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java
new file mode 100644
index 000000000..651873b20
--- /dev/null
+++ b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java
@@ -0,0 +1,266 @@
+package com.netscape.cms.servlet.test;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.Socket;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+
+import org.apache.commons.httpclient.ConnectTimeoutException;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.params.HttpConnectionParams;
+import org.apache.commons.httpclient.protocol.Protocol;
+import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
+import org.jboss.resteasy.client.ClientExecutor;
+import org.jboss.resteasy.client.ClientResponse;
+import org.jboss.resteasy.client.ProxyFactory;
+import com.netscape.certsrv.dbs.keydb.KeyId;
+import com.netscape.certsrv.request.RequestId;
+import org.jboss.resteasy.client.core.executors.ApacheHttpClientExecutor;
+import com.netscape.cms.servlet.admin.SystemCertificateResource;
+import com.netscape.cms.servlet.cert.model.CertificateData;
+import com.netscape.cms.servlet.key.KeyResource;
+import com.netscape.cms.servlet.key.KeysResource;
+import com.netscape.cms.servlet.key.model.KeyData;
+import com.netscape.cms.servlet.key.model.KeyDataInfo;
+import com.netscape.cms.servlet.key.model.KeyDataInfos;
+import com.netscape.cms.servlet.request.KeyRequestResource;
+import com.netscape.cms.servlet.request.KeyRequestsResource;
+import com.netscape.cms.servlet.request.model.ArchivalRequestData;
+import com.netscape.cms.servlet.request.model.KeyRequestInfo;
+import com.netscape.cms.servlet.request.model.KeyRequestInfos;
+import com.netscape.cms.servlet.request.model.RecoveryRequestData;
+import com.netscape.cmsutil.util.Utils;
+
+import org.mozilla.jss.ssl.SSLCertificateApprovalCallback;
+import org.mozilla.jss.ssl.SSLClientCertificateSelectionCallback;
+import org.mozilla.jss.ssl.SSLSocket;
+
+public class DRMRestClient {
+
+ // Callback to approve or deny returned SSL server certs
+ // Right now, simply approve the cert.
+ // ToDO: Look into taking this JSS http client code and move it into
+ // its own class to be used by possible future clients.
+ private class ServerCertApprovalCB implements SSLCertificateApprovalCallback {
+
+ public boolean approve(org.mozilla.jss.crypto.X509Certificate servercert,
+ SSLCertificateApprovalCallback.ValidityStatus status) {
+
+ //For now lets just accept the server cert. This is a test tool, being
+ // pointed at a well know kra instance.
+
+
+ if (servercert != null) {
+ System.out.println("Peer cert details: " +
+ "\n subject: " + servercert.getSubjectDN().toString() +
+ "\n issuer: " + servercert.getIssuerDN().toString() +
+ "\n serial: " + servercert.getSerialNumber().toString()
+ );
+ }
+
+ SSLCertificateApprovalCallback.ValidityItem item;
+
+ Enumeration<?> errors = status.getReasons();
+ int i = 0;
+ while (errors.hasMoreElements()) {
+ i++;
+ item = (SSLCertificateApprovalCallback.ValidityItem) errors.nextElement();
+ System.out.println("item " + i +
+ " reason=" + item.getReason() +
+ " depth=" + item.getDepth());
+
+ int reason = item.getReason();
+
+ if (reason ==
+ SSLCertificateApprovalCallback.ValidityStatus.UNTRUSTED_ISSUER ||
+ reason == SSLCertificateApprovalCallback.ValidityStatus.BAD_CERT_DOMAIN) {
+
+ //Allow these two since we haven't necessarily installed the CA cert for trust
+ // and we are choosing "localhost" as the host for this client.
+
+ return true;
+
+ }
+ }
+
+ //For other errors return false
+
+ return false;
+ }
+ }
+
+ private class JSSProtocolSocketFactory implements ProtocolSocketFactory {
+
+ @Override
+ public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
+
+ SSLSocket sock = createJSSSocket(host,port, null, 0, null);
+ return (Socket) sock;
+ }
+
+ @Override
+ public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException,
+ UnknownHostException {
+
+ SSLSocket sock = createJSSSocket(host,port, clientHost, clientPort, null);
+ return (Socket) sock;
+ }
+
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params)
+ throws IOException, UnknownHostException, ConnectTimeoutException {
+
+ SSLSocket sock = createJSSSocket(host, port, localAddress, localPort, null);
+ return (Socket) sock;
+ }
+ }
+
+ private SSLSocket createJSSSocket(String host, int port, InetAddress localAddress,
+ int localPort, SSLClientCertificateSelectionCallback clientCertSelectionCallback)
+ throws IOException, UnknownHostException, ConnectTimeoutException {
+
+ SSLSocket sock = new SSLSocket(InetAddress.getByName(host),
+ port,
+ localAddress,
+ localPort,
+ new ServerCertApprovalCB(),
+ null);
+
+ if(sock != null && clientCertNickname != null) {
+ sock.setClientCertNickname(clientCertNickname);
+ }
+
+ return sock;
+
+ }
+ private KeyResource keyClient;
+ private KeysResource keysClient;
+ private KeyRequestsResource keyRequestsClient;
+ private KeyRequestResource keyRequestClient;
+ private SystemCertificateResource systemCertClient;
+
+ private String clientCertNickname = null;
+
+ public DRMRestClient(String baseUri, String clientCertNick) throws MalformedURLException {
+
+ // For SSL we are assuming the caller has already intialized JSS and has
+ // a valid CryptoManager and CryptoToken
+ // optional clientCertNickname is provided for use if required.
+
+
+ URL url = new URL(baseUri);
+
+ String protocol = url.getProtocol();
+ int port = url.getPort();
+
+ clientCertNickname = null;
+ if(protocol != null && protocol.equals("https")) {
+ if (clientCertNick != null) {
+ clientCertNickname = clientCertNick;
+ }
+
+ Protocol.registerProtocol("https",
+ new Protocol(protocol, new JSSProtocolSocketFactory(), port));
+ }
+
+ HttpClient httpclient = new HttpClient();
+ ClientExecutor executor = new ApacheHttpClientExecutor(httpclient);
+
+ systemCertClient = ProxyFactory.create(SystemCertificateResource.class, baseUri, executor);
+ keyRequestsClient = ProxyFactory.create(KeyRequestsResource.class, baseUri, executor);
+ keyRequestClient = ProxyFactory.create(KeyRequestResource.class, baseUri, executor);
+ keysClient = ProxyFactory.create(KeysResource.class, baseUri, executor);
+ keyClient = ProxyFactory.create(KeyResource.class, baseUri, executor);
+ }
+
+ public String getTransportCert() {
+ @SuppressWarnings("unchecked")
+ ClientResponse<CertificateData> response = (ClientResponse<CertificateData>) systemCertClient.getTransportCert();
+ CertificateData certData = response.getEntity();
+ String transportCert = certData.getB64();
+ return transportCert;
+ }
+
+ public Collection<KeyRequestInfo> listRequests(String requestState, String requestType) {
+ KeyRequestInfos infos = keyRequestsClient.listRequests(
+ requestState, requestType, null, new RequestId(0), 100, 100, 10
+ );
+ Collection<KeyRequestInfo> list = infos.getRequests();
+ return list;
+ }
+
+ public KeyRequestInfo archiveSecurityData(byte[] encoded, String clientId, String dataType) {
+ // create archival request
+ ArchivalRequestData data = new ArchivalRequestData();
+ String req1 = Utils.base64encode(encoded);
+ data.setWrappedPrivateData(req1);
+ data.setClientId(clientId);
+ data.setDataType(dataType);
+
+ KeyRequestInfo info = keyRequestClient.archiveKey(data);
+ return info;
+ }
+
+ public KeyDataInfo getKeyData(String clientId, String status) {
+ KeyDataInfos infos = keysClient.listKeys(clientId, status, 100, 10);
+ Collection<KeyDataInfo> list = infos.getKeyInfos();
+ Iterator<KeyDataInfo> iter = list.iterator();
+
+ while (iter.hasNext()) {
+ KeyDataInfo info = iter.next();
+ if (info != null) {
+ // return the first one
+ return info;
+ }
+ }
+ return null;
+ }
+
+ public KeyRequestInfo requestRecovery(KeyId keyId, byte[] rpwd, byte[] rkey, byte[] nonceData) {
+ // create recovery request
+ RecoveryRequestData data = new RecoveryRequestData();
+ data.setKeyId(keyId);
+ if (rpwd != null) {
+ data.setSessionWrappedPassphrase(Utils.base64encode(rpwd));
+ }
+ if (rkey != null) {
+ data.setTransWrappedSessionKey(Utils.base64encode(rkey));
+ }
+
+ if (nonceData != null) {
+ data.setNonceData(Utils.base64encode(nonceData));
+ }
+
+ KeyRequestInfo info = keyRequestClient.recoverKey(data);
+ return info;
+ }
+
+ public void approveRecovery(RequestId recoveryId) {
+ keyRequestClient.approveRequest(recoveryId);
+ }
+
+ public KeyData retrieveKey(KeyId keyId, RequestId requestId, byte[] rpwd, byte[] rkey, byte[] nonceData) {
+ // create recovery request
+ RecoveryRequestData data = new RecoveryRequestData();
+ data.setKeyId(keyId);
+ data.setRequestId(requestId);
+ if (rkey != null) {
+ data.setTransWrappedSessionKey(Utils.base64encode(rkey));
+ }
+ if (rpwd != null) {
+ data.setSessionWrappedPassphrase(Utils.base64encode(rpwd));
+ }
+
+ if (nonceData != null) {
+ data.setNonceData(Utils.base64encode(nonceData));
+ }
+
+ KeyData key = keyClient.retrieveKey(data);
+ return key;
+ }
+}
diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
new file mode 100644
index 000000000..8d83247b8
--- /dev/null
+++ b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
@@ -0,0 +1,503 @@
+// --- 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) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.servlet.test;
+
+import java.net.MalformedURLException;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Random;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.crypto.AlreadyInitializedException;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.KeyGenAlgorithm;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.util.Password;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.PosixParser;
+
+import com.netscape.certsrv.dbs.keydb.KeyId;
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.cms.servlet.base.CMSResourceService;
+import com.netscape.cms.servlet.key.model.KeyData;
+import com.netscape.cms.servlet.key.model.KeyDataInfo;
+import com.netscape.cms.servlet.request.KeyRequestResource;
+import com.netscape.cms.servlet.request.model.KeyRequestInfo;
+import com.netscape.cmsutil.crypto.CryptoUtil;
+import com.netscape.cmsutil.util.Utils;
+
+public class DRMTest {
+
+ public static void usage(Options options) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp("DRMTest", options);
+ System.exit(1);
+ }
+
+ public static void main(String args[]) {
+ String host = null;
+ String port = null;
+ String token_pwd = null;
+ String db_dir = "./";
+ String protocol = "http";
+ String clientCertNickname = "KRA Administrator of Instance pki-kra's SjcRedhat Domain ID";
+
+ // parse command line arguments
+ Options options = new Options();
+ options.addOption("h", true, "Hostname of the DRM");
+ options.addOption("p", true, "Port of the DRM");
+ options.addOption("w", true, "Token password");
+ options.addOption("d", true, "Directory for tokendb");
+ options.addOption("s", true, "Attempt Optional Secure SSL connection");
+ options.addOption("c", true, "Optional SSL Client cert Nickname");
+
+ try {
+ CommandLineParser parser = new PosixParser();
+ CommandLine cmd = parser.parse(options, args);
+
+ if (cmd.hasOption("h")) {
+ host = cmd.getOptionValue("h");
+ } else {
+ System.err.println("Error: no hostname provided.");
+ usage(options);
+ }
+
+ if (cmd.hasOption("p")) {
+ port = cmd.getOptionValue("p");
+ } else {
+ System.err.println("Error: no port provided");
+ usage(options);
+ }
+
+ if (cmd.hasOption("w")) {
+ token_pwd = cmd.getOptionValue("w");
+ } else {
+ System.err.println("Error: no token password provided");
+ usage(options);
+ }
+
+ if (cmd.hasOption("d")) {
+ db_dir = cmd.getOptionValue("d");
+ }
+
+ if (cmd.hasOption("s")) {
+ if(cmd.getOptionValue("s") != null && cmd.getOptionValue("s").equals("true")) {
+ protocol = "https";
+ }
+ }
+
+ if (cmd.hasOption("c")) {
+ String nick = cmd.getOptionValue("c");
+
+ if (nick != null && protocol.equals("https")) {
+ clientCertNickname = nick;
+ }
+ }
+
+ } catch (ParseException e) {
+ System.err.println("Error in parsing command line options: " + e.getMessage());
+ usage(options);
+ }
+
+ // used for crypto operations
+ byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+ IVParameterSpec ivps = null;
+ IVParameterSpec ivps_server = null;
+
+ try {
+ ivps = genIV(8);
+ } catch (Exception e) {
+ log("Can't generate initialization vector use default: " + e.toString());
+ ivps = new IVParameterSpec(iv);
+ }
+
+ CryptoManager manager = null;
+ CryptoToken token = null;
+
+ // used for wrapping to send data to DRM
+ String transportCert = null;
+
+ // Data to be archived
+ SymmetricKey vek = null;
+ String passphrase = null;
+
+ // Session keys and passphrases for recovery
+ SymmetricKey recoveryKey = null;
+ byte[] wrappedRecoveryKey = null;
+ String recoveryPassphrase = null;
+ byte[] wrappedRecoveryPassphrase = null;
+
+ // retrieved data (should match archived data)
+ String wrappedRecoveredKey = null;
+ String recoveredKey = null;
+
+ // various ids used in recovery/archival operations
+ KeyId keyId = null;
+ String clientId = null;
+ RequestId recoveryRequestId = null;
+
+ // Variables for data structures from calls
+ KeyRequestInfo requestInfo = null;
+ KeyData keyData = null;
+ KeyDataInfo keyInfo = null;
+
+ // Initialize token
+ try {
+ CryptoManager.initialize(db_dir);
+ } catch (AlreadyInitializedException e) {
+ // it is ok if it is already initialized
+ } catch (Exception e) {
+ log("INITIALIZATION ERROR: " + e.toString());
+ System.exit(1);
+ }
+
+ // log into token
+ try {
+ manager = CryptoManager.getInstance();
+ token = manager.getInternalKeyStorageToken();
+ Password password = new Password(token_pwd.toCharArray());
+ try {
+ token.login(password);
+ } catch (Exception e) {
+ log("login Exception: " + e.toString());
+ if (!token.isLoggedIn()) {
+ token.initPassword(password, password);
+ }
+ }
+ } catch (Exception e) {
+ log("Exception in logging into token:" + e.toString());
+ }
+
+ // Set base URI and get client
+
+
+ String baseUri = protocol + "://" + host + ":" + port + "/kra/pki";
+ DRMRestClient client;
+ try {
+ client = new DRMRestClient(baseUri, clientCertNickname);
+ } catch (MalformedURLException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ return;
+ }
+
+ // Test 1: Get transport certificate from DRM
+ transportCert = client.getTransportCert();
+ transportCert = transportCert.substring(CMSResourceService.HEADER.length(),
+ transportCert.indexOf(CMSResourceService.TRAILER));
+
+ log("Transport Cert retrieved from DRM: " + transportCert);
+
+ // Test 2: Get list of completed key archival requests
+ log("\n\nList of completed archival requests");
+ Collection<KeyRequestInfo> list = client.listRequests("complete", "securityDataEnrollment");
+ if (list == null) {
+ log("No requests found");
+ } else {
+ Iterator<KeyRequestInfo> iter = list.iterator();
+ while (iter.hasNext()) {
+ KeyRequestInfo info = iter.next();
+ printRequestInfo(info);
+ }
+ }
+
+ // Test 3: Get list of key recovery requests
+ log("\n\nList of completed recovery requests");
+ Collection<KeyRequestInfo> list2 = client.listRequests("complete", "securityDataRecovery");
+ if (list2 == null) {
+ log("No requests found");
+ } else {
+ Iterator<KeyRequestInfo> iter2 = list2.iterator();
+ while (iter2.hasNext()) {
+ KeyRequestInfo info = iter2.next();
+ printRequestInfo(info);
+ }
+ }
+
+ // Test 4: Generate and archive a symmetric key
+ log("Archiving symmetric key");
+ clientId = "UUID: 123-45-6789 VEK " + Calendar.getInstance().getTime().toString();
+ try {
+ vek = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+ byte[] encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, vek, null,
+ KeyGenAlgorithm.DES3, ivps);
+
+ KeyRequestInfo info = client.archiveSecurityData(encoded, clientId, KeyRequestResource.SYMMETRIC_KEY_TYPE);
+ log("Archival Results:");
+ printRequestInfo(info);
+ keyId = info.getKeyId();
+ } catch (Exception e) {
+ log("Exception in archiving symmetric key:" + e.getMessage());
+ e.printStackTrace();
+ }
+
+ //Test 5: Get keyId for active key with client ID
+
+ log("Getting key ID for symmetric key");
+ keyInfo = client.getKeyData(clientId, "active");
+ KeyId keyId2 = keyInfo.getKeyId();
+ if (keyId2 == null) {
+ log("No archived key found");
+ } else {
+ log("Archived Key found: " + keyId);
+ }
+
+ if (!keyId.equals(keyId2)) {
+ log("Error: key ids from search and archival do not match");
+ } else {
+ log("Success: keyids from search and archival match.");
+ }
+
+ // Test 6: Submit a recovery request for the symmetric key using a session key
+ log("Submitting a recovery request for the symmetric key using session key");
+ try {
+ recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+ wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
+ KeyRequestInfo info = client.requestRecovery(keyId, null, wrappedRecoveryKey, ivps.getIV());
+ recoveryRequestId = info.getRequestId();
+ } catch (Exception e) {
+ log("Exception in recovering symmetric key using session key: " + e.getMessage());
+ }
+
+ // Test 7: Approve recovery
+ log("Approving recovery request: " + recoveryRequestId);
+ client.approveRecovery(recoveryRequestId);
+
+ // Test 8: Get key
+ log("Getting key: " + keyId);
+
+ keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, ivps.getIV());
+ wrappedRecoveredKey = keyData.getWrappedPrivateData();
+
+ ivps_server = new IVParameterSpec(Utils.base64decode(keyData.getNonceData()));
+ try {
+ recoveredKey = CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server,
+ Utils.base64decode(wrappedRecoveredKey),
+ recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD);
+ } catch (Exception e) {
+ log("Exception in unwrapping key: " + e.toString());
+ e.printStackTrace();
+ }
+
+ if (!recoveredKey.equals(Utils.base64encode(vek.getEncoded()))) {
+ log("Error: recovered and archived keys do not match!");
+ } else {
+ log("Success: recoverd and archived keys match!");
+ }
+
+ // Test 9: Submit a recovery request for the symmetric key using a passphrase
+ log("Submitting a recovery request for the symmetric key using a passphrase");
+ recoveryPassphrase = "Gimme me keys please";
+
+ try {
+ recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+ wrappedRecoveryPassphrase = CryptoUtil.wrapPassphrase(token, recoveryPassphrase, ivps, recoveryKey,
+ EncryptionAlgorithm.DES3_CBC_PAD);
+ wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
+
+ requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
+ recoveryRequestId = requestInfo.getRequestId();
+ } catch (Exception e) {
+ log("Exception in recovering symmetric key using passphrase" + e.toString());
+ e.printStackTrace();
+ }
+
+ //Test 10: Approve recovery
+ log("Approving recovery request: " + recoveryRequestId);
+ client.approveRecovery(recoveryRequestId);
+
+ // Test 11: Get key
+ log("Getting key: " + keyId);
+ keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
+ wrappedRecoveredKey = keyData.getWrappedPrivateData();
+
+ try {
+ recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
+ } catch (Exception e) {
+ log("Error: unable to unwrap key using passphrase");
+ e.printStackTrace();
+ }
+
+ if (recoveredKey == null || !recoveredKey.equals(Utils.base64encode(vek.getEncoded()))) {
+ log("Error: recovered and archived keys do not match!");
+ } else {
+ log("Success: recovered and archived keys do match!");
+ }
+
+
+ passphrase = "secret12345";
+ // Test 12: Generate and archive a passphrase
+ clientId = "UUID: 123-45-6789 RKEK " + Calendar.getInstance().getTime().toString();
+ try {
+ byte[] encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, null, passphrase,
+ KeyGenAlgorithm.DES3, ivps);
+ requestInfo = client.archiveSecurityData(encoded, clientId, KeyRequestResource.PASS_PHRASE_TYPE);
+ log("Archival Results:");
+ printRequestInfo(requestInfo);
+ keyId = requestInfo.getKeyId();
+ } catch (Exception e) {
+ log("Exception in archiving symmetric key:" + e.toString());
+ e.printStackTrace();
+ }
+
+ //Test 13: Get keyId for active passphrase with client ID
+ log("Getting key ID for passphrase");
+ keyInfo = client.getKeyData(clientId, "active");
+ keyId2 = keyInfo.getKeyId();
+ if (keyId2 == null) {
+ log("No archived key found");
+ } else {
+ log("Archived Key found: " + keyId);
+ }
+
+ if (!keyId.equals(keyId2)) {
+ log("Error: key ids from search and archival do not match");
+ } else {
+ log("Success: key ids from search and archival do match!");
+ }
+
+ // Test 14: Submit a recovery request for the passphrase using a session key
+ log("Submitting a recovery request for the passphrase using session key");
+ recoveryKey = null;
+ recoveryRequestId = null;
+ wrappedRecoveryKey = null;
+ try {
+ recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+ wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
+ wrappedRecoveryPassphrase = CryptoUtil.wrapPassphrase(token, recoveryPassphrase, ivps, recoveryKey,
+ EncryptionAlgorithm.DES3_CBC_PAD);
+ requestInfo = client.requestRecovery(keyId, null, wrappedRecoveryKey, ivps.getIV());
+ recoveryRequestId = requestInfo.getRequestId();
+ } catch (Exception e) {
+ log("Exception in recovering passphrase using session key: " + e.getMessage());
+ }
+
+ // Test 15: Approve recovery
+ log("Approving recovery request: " + recoveryRequestId);
+ client.approveRecovery(recoveryRequestId);
+
+ // Test 16: Get key
+ log("Getting passphrase: " + keyId);
+
+ keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, ivps.getIV());
+ wrappedRecoveredKey = keyData.getWrappedPrivateData();
+ ivps_server = new IVParameterSpec( Utils.base64decode(keyData.getNonceData()));
+ try {
+ recoveredKey = CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server,
+ Utils.base64decode(wrappedRecoveredKey),
+ recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD);
+ recoveredKey = new String(Utils.base64decode(recoveredKey), "UTF-8");
+ } catch (Exception e) {
+ log("Exception in unwrapping key: " + e.toString());
+ e.printStackTrace();
+ }
+
+ if (recoveredKey == null || !recoveredKey.equals(passphrase)) {
+ log("Error: recovered and archived passphrases do not match!");
+ } else {
+ log("Success: recovered and archived passphrases do match!");
+ }
+
+ // Test 17: Submit a recovery request for the passphrase using a passphrase
+ log("Submitting a recovery request for the passphrase using a passphrase");
+ requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
+ recoveryRequestId = requestInfo.getRequestId();
+
+ //Test 18: Approve recovery
+ log("Approving recovery request: " + recoveryRequestId);
+ client.approveRecovery(recoveryRequestId);
+
+ // Test 19: Get key
+ log("Getting passphrase: " + keyId);
+ keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
+ wrappedRecoveredKey = keyData.getWrappedPrivateData();
+ try {
+ recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
+ recoveredKey = new String(Utils.base64decode(recoveredKey), "UTF-8");
+ } catch (Exception e) {
+ log("Error: cannot unwrap key using passphrase");
+ e.printStackTrace();
+ }
+
+ if (recoveredKey == null || !recoveredKey.equals(passphrase)) {
+ log("Error: recovered and archived passphrases do not match!");
+ } else {
+ log("Success: recovered and archived passphrases do match!");
+ }
+
+ // Test 20: Submit a recovery request for the passphrase using a passphrase
+ //Wait until retrieving key before sending input data.
+
+ log("Submitting a recovery request for the passphrase using a passphrase, wait till end to provide recovery data.");
+ requestInfo = client.requestRecovery(keyId, null, null, null);
+ recoveryRequestId = requestInfo.getRequestId();
+
+ //Test 21: Approve recovery
+ log("Approving recovery request: " + recoveryRequestId);
+ client.approveRecovery(recoveryRequestId);
+
+ // Test 22: Get key
+ log("Getting passphrase: " + keyId);
+ keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
+ wrappedRecoveredKey = keyData.getWrappedPrivateData();
+ try {
+ recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
+ recoveredKey = new String(Utils.base64decode(recoveredKey), "UTF-8");
+ } catch (Exception e) {
+ log("Error: Can't unwrap recovered key using passphrase");
+ e.printStackTrace();
+ }
+
+ if (recoveredKey == null || !recoveredKey.equals(passphrase)) {
+ log("Error: recovered and archived passphrases do not match!");
+ } else {
+ log("Success: recovered and archived passphrases do match!");
+ }
+ }
+
+ private static void log(String string) {
+ // TODO Auto-generated method stub
+ System.out.println(string);
+ }
+
+ private static void printRequestInfo(KeyRequestInfo info) {
+ log("KeyRequestURL: " + info.getRequestURL());
+ log("Key URL: " + info.getKeyURL());
+ log("Status: " + info.getRequestStatus());
+ log("Type: " + info.getRequestType());
+ }
+
+ //Use this when we actually create random initialization vectors
+ private static IVParameterSpec genIV(int blockSize) throws Exception {
+ // generate an IV
+ byte[] iv = new byte[blockSize];
+
+ Random rnd = new Random();
+ rnd.nextBytes(iv);
+
+ return new IVParameterSpec(iv);
+ }
+}
diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java b/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java
new file mode 100644
index 000000000..604430b57
--- /dev/null
+++ b/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java
@@ -0,0 +1,222 @@
+package com.netscape.cms.servlet.test;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.CharConversionException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateEncodingException;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.PosixParser;
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.crypto.AlreadyInitializedException;
+import org.mozilla.jss.crypto.BadPaddingException;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.IllegalBlockSizeException;
+import org.mozilla.jss.crypto.KeyGenAlgorithm;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.SymmetricKey.NotExtractableException;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.cmsutil.crypto.CryptoUtil;
+import com.netscape.cmsutil.util.Utils;
+
+@SuppressWarnings("deprecation")
+public class GeneratePKIArchiveOptions {
+
+ public static void usage(Options options) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp("GeneratePKIArchiveOptions", options);
+ System.exit(1);
+ }
+
+ private static void log(String string) {
+ // TODO Auto-generated method stub
+ System.out.println(string);
+ }
+
+ // read in byte array
+ // we must do this somewhere?
+ public static byte[] read(String fname) throws IOException {
+ File file = new File(fname);
+ byte[] result = new byte[(int) file.length()];
+ InputStream input = null;
+ try {
+ int totalBytesRead = 0;
+ input = new BufferedInputStream(new FileInputStream(file));
+ while (totalBytesRead < result.length) {
+ int bytesRemaining = result.length - totalBytesRead;
+ //input.read() returns -1, 0, or more :
+ int bytesRead = input.read(result, totalBytesRead, bytesRemaining);
+ if (bytesRead > 0) {
+ totalBytesRead = totalBytesRead + bytesRead;
+ }
+ }
+ } catch (Exception e) {
+ throw new IOException(e);
+ } finally {
+ if (input != null) {
+ input.close();
+ }
+ }
+
+ return result;
+ }
+
+ public static void write(byte[] aInput, String outFile) throws IOException {
+ OutputStream output = null;
+ try {
+ output = new BufferedOutputStream(new FileOutputStream(outFile));
+ output.write(aInput);
+ } catch (Exception e) {
+ throw new IOException(e);
+ } finally {
+ if (output != null) {
+ output.close();
+ }
+ }
+ }
+
+ private static void write_file(String data, String outFile) throws IOException {
+ FileWriter fstream = new FileWriter(outFile);
+ BufferedWriter out = new BufferedWriter(fstream);
+ out.write(data);
+ //Close the output stream
+ out.close();
+ }
+
+ public static void main(String args[]) throws InvalidKeyException, CertificateEncodingException,
+ CharConversionException, NoSuchAlgorithmException, InvalidAlgorithmParameterException,
+ IllegalStateException, TokenException, IOException, IllegalBlockSizeException, BadPaddingException,
+ InvalidBERException, NotExtractableException {
+ String token_pwd = null;
+ String db_dir = "./";
+ String out_file = "./options.out";
+ String transport_file = "./transport.crt";
+ String key_file = "./symkey.out";
+ String passphrase = null;
+ boolean passphraseMode = false;
+
+ // parse command line arguments
+ Options options = new Options();
+ options.addOption("w", true, "Token password (required)");
+ options.addOption("d", true, "Directory for tokendb");
+ options.addOption("p", true, "Passphrase");
+ options.addOption("t", true, "File with transport cert");
+ options.addOption("o", true, "Output file");
+ options.addOption("k", true, "Key file");
+
+ try {
+ CommandLineParser parser = new PosixParser();
+ CommandLine cmd = parser.parse(options, args);
+
+ if (cmd.hasOption("p")) {
+ passphrase = cmd.getOptionValue("p");
+ passphraseMode = true;
+ }
+
+ if (cmd.hasOption("o")) {
+ out_file = cmd.getOptionValue("o");
+ }
+
+ if (cmd.hasOption("k")) {
+ key_file = cmd.getOptionValue("k");
+ }
+
+ if (cmd.hasOption("t")) {
+ transport_file = cmd.getOptionValue("t");
+ }
+
+ if (cmd.hasOption("w")) {
+ token_pwd = cmd.getOptionValue("w");
+ } else {
+ System.err.println("Error: no token password provided");
+ usage(options);
+ }
+
+ if (cmd.hasOption("d")) {
+ db_dir = cmd.getOptionValue("d");
+ }
+
+ } catch (ParseException e) {
+ System.err.println("Error in parsing command line options: " + e.getMessage());
+ usage(options);
+ }
+
+ // used for crypto operations
+ byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+ IVParameterSpec ivps = new IVParameterSpec(iv);
+ CryptoManager manager = null;
+ CryptoToken token = null;
+
+ // used for wrapping to send data to DRM
+ byte[] tcert = read(transport_file);
+ String transportCert = Utils.base64encode(tcert);
+
+ // Initialize token
+ try {
+ CryptoManager.initialize(db_dir);
+ } catch (AlreadyInitializedException e) {
+ // it is ok if it is already initialized
+ } catch (Exception e) {
+ log("INITIALIZATION ERROR: " + e.toString());
+ System.exit(1);
+ }
+
+ // log into token
+ try {
+ manager = CryptoManager.getInstance();
+ token = manager.getInternalKeyStorageToken();
+ Password password = new Password(token_pwd.toCharArray());
+ try {
+ token.login(password);
+ } catch (Exception e) {
+ log("login Exception: " + e.toString());
+ if (!token.isLoggedIn()) {
+ token.initPassword(password, password);
+ }
+ }
+ } catch (Exception e) {
+ log("Exception in logging into token:" + e.toString());
+ }
+
+ // Data to be archived
+ SymmetricKey vek = null;
+ if (!passphraseMode) {
+ vek = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+ // store vek in file
+ write_file(Utils.base64encode(vek.getKeyData()), key_file);
+ }
+
+ byte[] encoded = null;
+
+ if (passphraseMode) {
+ encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, null, passphrase,
+ KeyGenAlgorithm.DES3, ivps);
+ } else {
+ encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, vek, null,
+ KeyGenAlgorithm.DES3, ivps);
+ }
+
+ // write encoded to file
+ write_file(Utils.base64encode(encoded), out_file);
+
+ }
+}