summaryrefslogtreecommitdiffstats
path: root/base/java-tools/src/com/netscape
diff options
context:
space:
mode:
authorEndi Sukma Dewata <edewata@redhat.com>2012-03-24 02:27:47 -0500
committerEndi Sukma Dewata <edewata@redhat.com>2012-03-26 11:43:54 -0500
commit621d9e5c413e561293d7484b93882d985b3fe15f (patch)
tree638f3d75761c121d9a8fb50b52a12a6686c5ac5c /base/java-tools/src/com/netscape
parent40d3643b8d91886bf210aa27f711731c81a11e49 (diff)
downloadpki-621d9e5c413e561293d7484b93882d985b3fe15f.tar.gz
pki-621d9e5c413e561293d7484b93882d985b3fe15f.tar.xz
pki-621d9e5c413e561293d7484b93882d985b3fe15f.zip
Removed unnecessary pki folder.
Previously the source code was located inside a pki folder. This folder was created during svn migration and is no longer needed. This folder has now been removed and the contents have been moved up one level. Ticket #131
Diffstat (limited to 'base/java-tools/src/com/netscape')
-rw-r--r--base/java-tools/src/com/netscape/cmstools/AtoB.java146
-rw-r--r--base/java-tools/src/com/netscape/cmstools/AuditVerify.java334
-rw-r--r--base/java-tools/src/com/netscape/cmstools/BtoA.java119
-rw-r--r--base/java-tools/src/com/netscape/cmstools/CMCEnroll.java467
-rw-r--r--base/java-tools/src/com/netscape/cmstools/CMCRequest.java1129
-rw-r--r--base/java-tools/src/com/netscape/cmstools/CMCResponse.java234
-rw-r--r--base/java-tools/src/com/netscape/cmstools/CMCRevoke.java426
-rw-r--r--base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java620
-rw-r--r--base/java-tools/src/com/netscape/cmstools/DRMTool.cfg160
-rw-r--r--base/java-tools/src/com/netscape/cmstools/DRMTool.java5120
-rw-r--r--base/java-tools/src/com/netscape/cmstools/ExtJoiner.java104
-rw-r--r--base/java-tools/src/com/netscape/cmstools/GenExtKeyUsage.java100
-rw-r--r--base/java-tools/src/com/netscape/cmstools/GenIssuerAltNameExt.java141
-rw-r--r--base/java-tools/src/com/netscape/cmstools/GenSubjectAltNameExt.java141
-rw-r--r--base/java-tools/src/com/netscape/cmstools/HttpClient.java403
-rw-r--r--base/java-tools/src/com/netscape/cmstools/OCSPClient.java276
-rw-r--r--base/java-tools/src/com/netscape/cmstools/PKCS10Client.java249
-rw-r--r--base/java-tools/src/com/netscape/cmstools/PKCS12Export.java301
-rw-r--r--base/java-tools/src/com/netscape/cmstools/PasswordCache.java870
-rw-r--r--base/java-tools/src/com/netscape/cmstools/PrettyPrintCert.java248
-rw-r--r--base/java-tools/src/com/netscape/cmstools/PrettyPrintCrl.java212
-rw-r--r--base/java-tools/src/com/netscape/cmstools/TestCRLSigning.java115
-rw-r--r--base/java-tools/src/com/netscape/cmstools/TokenInfo.java75
23 files changed, 11990 insertions, 0 deletions
diff --git a/base/java-tools/src/com/netscape/cmstools/AtoB.java b/base/java-tools/src/com/netscape/cmstools/AtoB.java
new file mode 100644
index 000000000..48301e492
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/AtoB.java
@@ -0,0 +1,146 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * The AtoB class is a utility program designed to "translate" an ASCII
+ * BASE 64 encoded blob into a BINARY BASE 64 encoded blob. It assumes
+ * that the name of a data file is passed to the program via the command line,
+ * and that the contents contain a blob encoded in an ASCII BASE 64
+ * format. Note that the data file may contain an optional "-----BEGIN" header
+ * and/or an optional "-----END" trailer.
+ *
+ * <P>
+ * The program may be invoked as follows:
+ *
+ * <PRE>
+ *
+ * AtoB &lt;input filename&gt; &lt;output filename&gt;
+ *
+ * NOTE: &lt;input filename&gt; must contain an ASCII
+ * BASE 64 encoded blob
+ *
+ * &lt;output filename&gt; contains a BINARY
+ * BASE 64 encoded blob
+ * </PRE>
+ *
+ * @version $Revision$, $Date$
+ */
+public class AtoB {
+ // Define constants
+ public static final int ARGC = 2;
+ public static final String HEADER = "-----BEGIN";
+ public static final String TRAILER = "-----END";
+
+ public static void main(String argv[]) {
+
+ BufferedReader inputBlob = null;
+ String asciiBASE64BlobChunk = new String();
+ String asciiBASE64Blob = new String();
+ byte binaryBASE64Blob[] = null;
+ FileOutputStream outputBlob = null;
+
+ // (1) Check that two arguments were submitted to the program
+ if (argv.length != ARGC) {
+ System.out.println("Usage: AtoB " +
+ "<input filename> " +
+ "<output filename>");
+ return;
+ }
+
+ // (2) Create a DataInputStream() object to the BASE 64
+ // encoded blob contained within the file
+ // specified on the command line
+ try {
+ inputBlob = new BufferedReader(new InputStreamReader(
+ new BufferedInputStream(
+ new FileInputStream(
+ argv[0]))));
+ } catch (FileNotFoundException e) {
+ System.out.println("AtoB(): can''t find file " +
+ argv[0] + ":\n" + e);
+ return;
+ }
+
+ // (3) Read the entire contents of the specified BASE 64 encoded
+ // blob into a String() object throwing away any
+ // headers beginning with HEADER and any trailers beginning
+ // with TRAILER
+ try {
+ while ((asciiBASE64BlobChunk = inputBlob.readLine()) != null) {
+ if (!(asciiBASE64BlobChunk.startsWith(HEADER)) &&
+ !(asciiBASE64BlobChunk.startsWith(TRAILER))) {
+ asciiBASE64Blob += asciiBASE64BlobChunk.trim();
+ }
+ }
+ } catch (IOException e) {
+ System.out.println("AtoB(): Unexpected BASE64 " +
+ "encoded error encountered in readLine():\n" +
+ e);
+ }
+
+ // (4) Close the DataInputStream() object
+ try {
+ inputBlob.close();
+ } catch (IOException e) {
+ System.out.println("AtoB(): Unexpected BASE64 " +
+ "encoded error encountered in close():\n" + e);
+ }
+
+ // (5) Decode the ASCII BASE 64 blob enclosed in the
+ // String() object into a BINARY BASE 64 byte[] object
+
+ binaryBASE64Blob = Utils.base64decode(asciiBASE64Blob);
+
+ // (6) Finally, print the actual AtoB blob to the
+ // specified output file
+ try {
+ outputBlob = new FileOutputStream(argv[1]);
+ } catch (IOException e) {
+ System.out.println("AtoB(): unable to open file " +
+ argv[1] + " for writing:\n" + e);
+ return;
+ }
+
+ try {
+ outputBlob.write(binaryBASE64Blob);
+ } catch (IOException e) {
+ System.out.println("AtoB(): I/O error " +
+ "encountered during write():\n" +
+ e);
+ }
+
+ try {
+ outputBlob.close();
+ } catch (IOException e) {
+ System.out.println("AtoB(): Unexpected error " +
+ "encountered while attempting to close() " +
+ argv[1] + ":\n" + e);
+ }
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/AuditVerify.java b/base/java-tools/src/com/netscape/cmstools/AuditVerify.java
new file mode 100644
index 000000000..fb23e89fd
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/AuditVerify.java
@@ -0,0 +1,334 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import netscape.security.x509.X509CertImpl;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.crypto.ObjectNotFoundException;
+import org.mozilla.jss.crypto.X509Certificate;
+
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * Tool for verifying signed audit logs
+ *
+ * @version $Revision$, $Date$
+ */
+public class AuditVerify {
+
+ private static void usage() {
+ System.out
+ .println("Usage: AuditVerify -d <dbdir> -n <signing certificate nickname> -a <log list file> [-P <cert/key db prefix>] [-v]");
+ System.exit(1);
+ }
+
+ public static final String CRYPTO_PROVIDER = "Mozilla-JSS";
+
+ public static byte[] base64decode(String input) throws Exception {
+ return Utils.base64decode(input);
+ }
+
+ // We always sign 0x0a as the line separator, regardless of what
+ // line separator characters are used in the log file. This helps
+ // signature verification be platform-independent.
+ private static final byte LINE_SEP_BYTE = 0x0a;
+
+ private static void output(int linenum, String mesg) throws IOException {
+ System.out.println("Line " + linenum + ": " + mesg);
+ }
+
+ private static void writeFile(String curfileName) {
+ System.out.println("======\nFile: " + curfileName + "\n======");
+ }
+
+ private static void writeSigStatus(int linenum, String sigStartFile,
+ int sigStartLine, String sigStopFile, int sigStopLine, String mesg)
+ throws IOException {
+ output(linenum, mesg + ": signature of " + sigStartFile + ":" +
+ sigStartLine + " to " + sigStopFile + ":" + sigStopLine);
+ }
+
+ private static class PrefixFilter implements FilenameFilter {
+ private String prefix;
+
+ public PrefixFilter(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public boolean accept(File dir, String name) {
+ // look for <prefix>cert* in this directory
+ return (name.indexOf(prefix + "cert") != -1);
+ }
+ }
+
+ public static boolean validPrefix(String configDir, String prefix)
+ throws IOException {
+ File dir = new File(configDir);
+ if (!dir.isDirectory()) {
+ System.out.println("ERROR: \"" + dir + "\" is not a directory");
+ usage();
+ }
+
+ String matchingFiles[] = dir.list(new PrefixFilter(prefix));
+
+ // prefix may be valid if at least one file matched the pattern
+ return (matchingFiles.length > 0);
+ }
+
+ public static boolean isSigningCert(X509CertImpl cert) {
+ boolean[] keyUsage = null;
+
+ try {
+ keyUsage = cert.getKeyUsage();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return (keyUsage == null) ? false : keyUsage[0];
+ }
+
+ public static void main(String args[]) {
+ try {
+
+ String dbdir = null;
+ String logListFile = null;
+ String signerNick = null;
+ String prefix = null;
+ boolean verbose = false;
+
+ for (int i = 0; i < args.length; ++i) {
+ if (args[i].equals("-d")) {
+ if (++i >= args.length)
+ usage();
+ dbdir = args[i];
+ } else if (args[i].equals("-a")) {
+ if (++i >= args.length)
+ usage();
+ logListFile = args[i];
+ } else if (args[i].equals("-n")) {
+ if (++i >= args.length)
+ usage();
+ signerNick = args[i];
+ } else if (args[i].equals("-P")) {
+ if (++i >= args.length)
+ usage();
+ prefix = args[i];
+ } else if (args[i].equals("-v")) {
+ verbose = true;
+ } else {
+ System.out.println("Unrecognized argument(" + i + "): "
+ + args[i]);
+ usage();
+ }
+ }
+ if (dbdir == null || logListFile == null || signerNick == null) {
+ System.out.println("Argument omitted");
+ usage();
+ }
+
+ // get list of log files
+ Vector<String> logFiles = new Vector<String>();
+ BufferedReader r = new BufferedReader(new FileReader(logListFile));
+ String listLine;
+ while ((listLine = r.readLine()) != null) {
+ StringTokenizer tok = new StringTokenizer(listLine, ",");
+ while (tok.hasMoreElements()) {
+ logFiles.addElement(((String) tok.nextElement()).trim());
+ }
+ }
+ if (logFiles.size() == 0) {
+ System.out.println("Error: no log files listed in " + logListFile);
+ System.exit(1);
+ }
+
+ // initialize crypto stuff
+ if (prefix == null) {
+ if (!validPrefix(dbdir, "")) {
+ System.out.println("ERROR: \"" + dbdir +
+ "\" does not contain any security databases");
+ usage();
+ }
+ CryptoManager.initialize(dbdir);
+ } else {
+ if (!validPrefix(dbdir, prefix)) {
+ System.out.println("ERROR: \"" + prefix +
+ "\" is not a valid prefix");
+ usage();
+ }
+ CryptoManager.initialize(
+ new CryptoManager.InitializationValues(dbdir, prefix, prefix,
+ "secmod.db")
+ );
+ }
+ CryptoManager cm = CryptoManager.getInstance();
+ X509Certificate signerCert = cm.findCertByNickname(signerNick);
+
+ X509CertImpl cert_i = null;
+ if (signerCert != null) {
+ byte[] signerCert_b = signerCert.getEncoded();
+ cert_i = new X509CertImpl(signerCert_b);
+ } else {
+ System.out.println("ERROR: signing certificate not found");
+ System.exit(1);
+ }
+
+ // verify signer's certificate
+ // not checking validity because we want to allow verifying old logs
+ //
+ if (!isSigningCert(cert_i)) {
+ System.out.println("info: signing certificate is not a signing certificate");
+ System.exit(1);
+ }
+
+ PublicKey pubk = signerCert.getPublicKey();
+ String sigAlgorithm = null;
+ if (pubk instanceof RSAPublicKey) {
+ sigAlgorithm = "SHA-256/RSA";
+ } else if (pubk instanceof DSAPublicKey) {
+ sigAlgorithm = "SHA-256/DSA";
+ } else {
+ System.out.println("Error: unknown key type: " +
+ pubk.getAlgorithm());
+ System.exit(1);
+ }
+ Signature sig = Signature.getInstance(sigAlgorithm, CRYPTO_PROVIDER);
+ sig.initVerify(pubk);
+
+ int goodSigCount = 0;
+ int badSigCount = 0;
+
+ int lastFileWritten = -1;
+
+ int sigStartLine = 1;
+ int sigStopLine = 1;
+ String sigStartFile = (String) logFiles.elementAt(0);
+ String sigStopFile = null;
+ int signedLines = 1;
+
+ for (int curfile = 0; curfile < logFiles.size(); ++curfile) {
+ String curfileName = (String) logFiles.elementAt(curfile);
+ BufferedReader br = new BufferedReader(new FileReader(curfileName));
+
+ if (verbose) {
+ writeFile(curfileName);
+ lastFileWritten = curfile;
+ }
+
+ String curLine;
+ int linenum = 0;
+ while ((curLine = br.readLine()) != null) {
+ ++linenum;
+ if (curLine.indexOf("AUDIT_LOG_SIGNING") != -1) {
+ if (curfile == 0 && linenum == 1) {
+ // Ignore the first signature of the first file,
+ // since it signs data we don't have access to.
+ if (verbose) {
+ output(linenum,
+ "Ignoring first signature of log series");
+ }
+ } else {
+ int sigStart = curLine.indexOf("sig: ") + 5;
+ if (sigStart < 5) {
+ output(linenum, "INVALID SIGNATURE");
+ ++badSigCount;
+ } else {
+ byte[] logSig =
+ base64decode(curLine.substring(sigStart));
+
+ // verify the signature
+ if (sig.verify(logSig)) {
+ // signature verifies correctly
+ if (verbose) {
+ writeSigStatus(linenum, sigStartFile,
+ sigStartLine, sigStopFile, sigStopLine,
+ "verification succeeded");
+ }
+ ++goodSigCount;
+ } else {
+ if (lastFileWritten < curfile) {
+ writeFile(curfileName);
+ lastFileWritten = curfile;
+ }
+ writeSigStatus(linenum, sigStartFile,
+ sigStartLine, sigStopFile, sigStopLine,
+ "VERIFICATION FAILED");
+ ++badSigCount;
+ }
+ }
+ sig.initVerify(pubk);
+ signedLines = 0;
+ sigStartLine = linenum;
+ sigStartFile = curfileName;
+ }
+ }
+
+ byte[] lineBytes = curLine.getBytes("UTF-8");
+ sig.update(lineBytes);
+ sig.update(LINE_SEP_BYTE);
+ ++signedLines;
+ sigStopLine = linenum;
+ sigStopFile = curfileName;
+ }
+
+ }
+
+ // Make sure there were no unsigned log entries at the end.
+ // The first signed line is the previous signature, but anything
+ // more than that is data.
+ if (signedLines > 1) {
+ System.out.println(
+ "ERROR: log entries after " + sigStartFile
+ + ":" + sigStartLine + " are UNSIGNED");
+ badSigCount++;
+ }
+
+ System.out.println("\nVerification process complete.");
+ System.out.println("Valid signatures: " + goodSigCount);
+ System.out.println("Invalid signatures: " + badSigCount);
+
+ if (badSigCount > 0) {
+ System.exit(2);
+ } else {
+ System.exit(0);
+ }
+
+ } catch (FileNotFoundException fnfe) {
+ System.out.println(fnfe);
+ } catch (ObjectNotFoundException onfe) {
+ System.out.println("ERROR: certificate not found");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ System.out.println("Verification process FAILED.");
+ System.exit(1);
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/BtoA.java b/base/java-tools/src/com/netscape/cmstools/BtoA.java
new file mode 100644
index 000000000..4c2e5c22a
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/BtoA.java
@@ -0,0 +1,119 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * The BtoA class is a utility program designed to "translate" a BINARY
+ * BASE 64 encoded blob into an ASCII BASE 64 encoded blob. It assumes
+ * that the name of a data file is passed to the program via the command line,
+ * and that the contents contain a blob encoded in a BINARY BASE 64
+ * format.
+ *
+ * <P>
+ * The program may be invoked as follows:
+ *
+ * <PRE>
+ *
+ * BtoA &lt;input filename&gt; &lt;output filename&gt;
+ *
+ * NOTE: &lt;input filename&gt; must contain a BINARY
+ * BASE 64 encoded blob
+ *
+ * &lt;output filename&gt; contains an ASCII
+ * BASE 64 encoded blob
+ * </PRE>
+ *
+ * @version $Revision$, $Date$
+ */
+public class BtoA {
+ // Define constants
+ public static final int ARGC = 2;
+
+ public static void main(String argv[]) {
+
+ FileInputStream inputBlob = null;
+ FileOutputStream outputBlob = null;
+
+ // (1) Check that two arguments were submitted to the program
+ if (argv.length != ARGC) {
+ System.out.println("Usage: BtoA " +
+ "<input filename> " +
+ "<output filename>");
+ return;
+ }
+
+ // (2) Create a DataInputStream() object to the BASE 64
+ // encoded blob contained within the file
+ // specified on the command line
+ try {
+ inputBlob = new FileInputStream(argv[0]);
+ } catch (FileNotFoundException e) {
+ System.out.println("BtoA(): can''t find file " +
+ argv[0] + ":\n" + e);
+ return;
+ }
+
+ // (3) Create a FileOutputStream() object to the BASE 64
+ // specified output file
+ try {
+ outputBlob = new FileOutputStream(argv[1]);
+ } catch (IOException e) {
+ System.out.println("BtoA(): unable to open file " +
+ argv[1] + " for writing:\n" + e);
+ return;
+ }
+
+ // (4) Convert the BINARY BASE 64 blob into an ASCII BASE 64 blob
+
+ try {
+ byte data[] = new byte[inputBlob.available()];
+ inputBlob.read(data);
+ String out = Utils.base64encode(data);
+ outputBlob.write(out.getBytes());
+ } catch (IOException e) {
+ System.out.println("BtoA(): Unexpected BASE64 " +
+ "encoded error encountered:\n" +
+ e);
+ }
+
+ // (5) Close the DataInputStream() object
+ try {
+ inputBlob.close();
+ } catch (IOException e) {
+ System.out.println("BtoA(): Unexpected input error " +
+ "encountered while attempting to close() " +
+ argv[0] + ":\n" + e);
+ }
+
+ // (6) Close the FileOutputStream() object
+ try {
+ outputBlob.close();
+ } catch (IOException e) {
+ System.out.println("BtoA(): Unexpected output error " +
+ "encountered while attempting to close() " +
+ argv[1] + ":\n" + e);
+ }
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/CMCEnroll.java b/base/java-tools/src/com/netscape/cmstools/CMCEnroll.java
new file mode 100644
index 000000000..e2e51a29d
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/CMCEnroll.java
@@ -0,0 +1,467 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
+import java.util.Date;
+
+import netscape.security.pkcs.PKCS10;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.X509CertImpl;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.asn1.ANY;
+import org.mozilla.jss.asn1.INTEGER;
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.SET;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.DigestAlgorithm;
+import org.mozilla.jss.crypto.ObjectNotFoundException;
+import org.mozilla.jss.crypto.SignatureAlgorithm;
+import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.pkcs10.CertificationRequest;
+import org.mozilla.jss.pkix.cmc.PKIData;
+import org.mozilla.jss.pkix.cmc.TaggedAttribute;
+import org.mozilla.jss.pkix.cmc.TaggedCertificationRequest;
+import org.mozilla.jss.pkix.cmc.TaggedRequest;
+import org.mozilla.jss.pkix.cms.ContentInfo;
+import org.mozilla.jss.pkix.cms.EncapsulatedContentInfo;
+import org.mozilla.jss.pkix.cms.IssuerAndSerialNumber;
+import org.mozilla.jss.pkix.cms.SignedData;
+import org.mozilla.jss.pkix.cms.SignerIdentifier;
+import org.mozilla.jss.pkix.cms.SignerInfo;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+import org.mozilla.jss.pkix.primitive.Name;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * Tool for signing PKCS #10 , return CMC enrollment request
+ *
+ * <P>
+ *
+ * @version $Revision$, $Date$
+ */
+public class CMCEnroll {
+
+ public static final String PR_REQUEST_CMC = "CMC";
+ public static final String PR_REQUEST_PKCS10 = "PKCS10";
+
+ public static final int ARGC = 4;
+ private static final String CERTDB = "cert8.db";
+ private static final String KEYDB = "key3.db";
+ public static final String HEADER = "-----BEGIN NEW CERTIFICATE REQUEST-----";
+ public static final String TRAILER = "-----END NEW CERTIFICATE REQUEST-----";
+
+ void cleanArgs(String[] s) {
+
+ }
+
+ public static X509Certificate getCertificate(String tokenname,
+ String nickname) throws Exception {
+ CryptoManager manager = CryptoManager.getInstance();
+ CryptoToken token = null;
+
+ if (tokenname.equals("internal")) {
+ token = manager.getInternalKeyStorageToken();
+ } else {
+ token = manager.getTokenByName(tokenname);
+ }
+ StringBuffer certname = new StringBuffer();
+
+ if (!token.equals(manager.getInternalKeyStorageToken())) {
+ certname.append(tokenname);
+ certname.append(":");
+ }
+ certname.append(nickname);
+ try {
+ return manager.findCertByNickname(certname.toString());
+ } catch (ObjectNotFoundException e) {
+ throw new IOException("Signing Certificate not found");
+ }
+ }
+
+ public static java.security.PrivateKey getPrivateKey(String tokenname, String nickname)
+ throws Exception {
+
+ X509Certificate cert = getCertificate(tokenname, nickname);
+
+ return CryptoManager.getInstance().findPrivKeyByCert(cert);
+ }
+
+ /**
+ * getCMCBlob create and return the enrollent request.
+ * <P>
+ *
+ * @param signerCert the certificate of the authorized signer of the CMC revocation request.
+ * @param manager the crypto manger.
+ * @param nValue the nickname of the certificate inside the token.
+ * @param rValue request PKCS#10 file name.
+ * @return the CMC revocation request encoded in base64
+ */
+ static String getCMCBlob(X509Certificate signerCert, CryptoManager manager, String nValue, String rValue) {
+
+ String asciiBASE64Blob = rValue; // input pkcs10 blob
+ String tokenname = "internal";
+
+ try {
+
+ java.security.PrivateKey privKey = null;
+ PKCS10 pkcs = null;
+ SignerIdentifier si = null;
+ ContentInfo fullEnrollmentReq = null;
+
+ try {
+ byte[] decodedBytes = Utils.base64decode(asciiBASE64Blob);
+
+ pkcs = new PKCS10(decodedBytes);
+ } catch (IOException e) {
+ throw new IOException("Internal Error - " + e.toString());
+ } catch (SignatureException e) {
+ throw new IOException("Internal Error - " + e.toString());
+ } catch (NoSuchAlgorithmException e) {
+ throw new IOException("Internal Error - " + e.toString());
+ }
+
+ BigInteger serialno = signerCert.getSerialNumber();
+ byte[] certB = signerCert.getEncoded();
+ X509CertImpl impl = new X509CertImpl(certB);
+ X500Name issuerName = (X500Name) impl.getIssuerDN();
+ byte[] issuerByte = issuerName.getEncoded();
+ ByteArrayInputStream istream = new ByteArrayInputStream(issuerByte);
+
+ Name issuer = (Name) Name.getTemplate().decode(istream);
+ IssuerAndSerialNumber ias = new IssuerAndSerialNumber(issuer, new INTEGER(serialno.toString()));
+
+ si = new SignerIdentifier(SignerIdentifier.ISSUER_AND_SERIALNUMBER, ias, null);
+ privKey = getPrivateKey(tokenname, nValue);
+
+ // create CMC req
+ // transfer pkcs10 to jss class
+ int bpid = 1;
+ ByteArrayInputStream crInputStream = new ByteArrayInputStream(pkcs.toByteArray());
+ CertificationRequest cr = (CertificationRequest) CertificationRequest.getTemplate().decode(crInputStream);
+
+ TaggedCertificationRequest tcr = new
+ TaggedCertificationRequest(new
+ INTEGER(bpid++), cr);
+ TaggedRequest trq = new
+ TaggedRequest(TaggedRequest.PKCS10, tcr,
+ null);
+
+ SEQUENCE reqSequence = new SEQUENCE();
+
+ reqSequence.addElement(trq);
+
+ // Add some control sequence
+ // Verisign has transactionID,senderNonce
+ SEQUENCE controlSeq = new SEQUENCE();
+
+ Date date = new Date();
+ String salt = "lala123" + date.toString();
+ byte[] dig;
+
+ try {
+ MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1");
+
+ dig = SHA1Digest.digest(salt.getBytes());
+ } catch (NoSuchAlgorithmException ex) {
+ dig = salt.getBytes();
+ }
+
+ String sn = Utils.base64encode(dig);
+
+ TaggedAttribute senderNonce = new TaggedAttribute(new
+ INTEGER(bpid++),
+ OBJECT_IDENTIFIER.id_cmc_senderNonce,
+ new OCTET_STRING(sn.getBytes()));
+
+ controlSeq.addElement(senderNonce);
+
+ // Verisign recommend transactionId be MD5 hash of publicKey
+ byte[] transId;
+
+ try {
+ MessageDigest MD5Digest = MessageDigest.getInstance("MD5");
+
+ transId = MD5Digest.digest(pkcs.getSubjectPublicKeyInfo().getKey());
+ } catch (Exception ex) {
+ transId = salt.getBytes();
+ }
+
+ TaggedAttribute transactionId = new TaggedAttribute(new
+ INTEGER(bpid++),
+ OBJECT_IDENTIFIER.id_cmc_transactionId,
+ new INTEGER(1, transId));
+
+ controlSeq.addElement(transactionId);
+
+ PKIData pkidata = new PKIData(controlSeq, reqSequence, new SEQUENCE(), new SEQUENCE());
+
+ EncapsulatedContentInfo ci = new
+ EncapsulatedContentInfo(OBJECT_IDENTIFIER.id_cct_PKIData,
+ pkidata);
+ // SHA1 is the default digest Alg for now.
+ DigestAlgorithm digestAlg = null;
+ SignatureAlgorithm signAlg = SignatureAlgorithm.RSASignatureWithSHA1Digest;
+ org.mozilla.jss.crypto.PrivateKey.Type signingKeyType =
+ ((org.mozilla.jss.crypto.PrivateKey) privKey).getType();
+
+ if (signingKeyType.equals(org.mozilla.jss.crypto.PrivateKey.Type.DSA))
+ signAlg = SignatureAlgorithm.DSASignatureWithSHA1Digest;
+ MessageDigest SHADigest = null;
+ byte[] digest = null;
+
+ try {
+ SHADigest = MessageDigest.getInstance("SHA1");
+ digestAlg = DigestAlgorithm.SHA1;
+
+ ByteArrayOutputStream ostream = new ByteArrayOutputStream();
+
+ pkidata.encode((OutputStream) ostream);
+ digest = SHADigest.digest(ostream.toByteArray());
+ } catch (NoSuchAlgorithmException e) {
+ }
+ SignerInfo signInfo = new
+ SignerInfo(si, null, null, OBJECT_IDENTIFIER.id_cct_PKIData, digest, signAlg,
+ (org.mozilla.jss.crypto.PrivateKey) privKey);
+ SET signInfos = new SET();
+
+ signInfos.addElement(signInfo);
+
+ SET digestAlgs = new SET();
+
+ if (digestAlg != null) {
+ AlgorithmIdentifier ai = new AlgorithmIdentifier(digestAlg.toOID(), null);
+
+ digestAlgs.addElement(ai);
+ }
+
+ org.mozilla.jss.crypto.X509Certificate[] agentChain = manager.buildCertificateChain(signerCert);
+ SET certs = new SET();
+
+ for (int i = 0; i < agentChain.length; i++) {
+ ANY cert = new ANY(agentChain[i].getEncoded());
+
+ certs.addElement(cert);
+ }
+ SignedData req = new SignedData(digestAlgs, ci, certs, null, signInfos);
+
+ fullEnrollmentReq = new
+ ContentInfo(req);
+
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(bs);
+
+ // format is PR_REQUEST_CMC
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ fullEnrollmentReq.encode(os);
+ ps.print(Utils.base64encode(os.toByteArray()));
+ //fullEnrollmentReq.print(ps); // no header/trailer
+ asciiBASE64Blob = bs.toString();
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ return asciiBASE64Blob;
+ }
+
+ /** Creates a new instance of CMCEnroll */
+ public static void main(String[] s) {
+
+ String dValue = null, nValue = null, rValue = null, pValue = null;
+ FileOutputStream outputBlob = null;
+
+ // default path is "."
+ String mPath = ".";
+ // default prefix is ""
+ String mPrefix = "";
+
+ boolean bWrongParam = false;
+
+ // (1) Check that two arguments were submitted to the program
+ if (s.length != (ARGC * 2)) {
+ System.out.println("Wrong number of parameters:" + s.length);
+ System.out.println("Usage: CMCEnroll " +
+ "-d <dir to cert8.db, key3.db> " +
+ "-n <nickname> " +
+ "-r <request PKCS#10 file name> " +
+ "-p <password>"
+ );
+ bWrongParam = true;
+ } else {
+ int length;
+ int i;
+
+ length = s.length;
+ for (i = 0; i < length; i++) {
+ if (s[i].equals("-d")) {
+ dValue = s[i + 1];
+ } else if (s[i].equals("-n")) {
+ nValue = s[i + 1];
+ } else if (s[i].equals("-r")) {
+ rValue = s[i + 1];
+ } else if (s[i].equals("-p")) {
+ pValue = s[i + 1];
+ }
+ if (s[i].equals(""))
+ bWrongParam = true;
+
+ }
+
+ if (dValue == null || nValue == null || rValue == null || pValue == null)
+ bWrongParam = true;
+ else if (dValue.length() == 0 || nValue.length() == 0 || rValue.length() == 0 ||
+ pValue.length() == 0)
+ bWrongParam = true;
+ if (bWrongParam == true) {
+ System.out.println("Usage: CMCEnroll " +
+ "-d <dir to cert8.db, key3.db> " +
+ "-n <nickname> " +
+ "-r <request PKCS#10 file name> " +
+ "-p <password>"
+ );
+ System.exit(0);
+ }
+
+ try {
+ // initialize CryptoManager
+ mPath = dValue;
+ System.out.println("cert/key prefix = " + mPrefix);
+ System.out.println("path = " + mPath);
+ CryptoManager.InitializationValues vals =
+ new CryptoManager.InitializationValues(mPath, mPrefix,
+ mPrefix, "secmod.db");
+
+ CryptoManager.initialize(vals);
+
+ CryptoManager cm = CryptoManager.getInstance();
+ CryptoToken token = cm.getInternalKeyStorageToken();
+ Password pass = new Password(pValue.toCharArray());
+
+ token.login(pass);
+ X509Certificate signerCert = null;
+
+ signerCert = cm.findCertByNickname(nValue);
+
+ BufferedReader inputBlob = null;
+
+ try {
+ inputBlob = new BufferedReader(new InputStreamReader(
+ new BufferedInputStream(
+ new FileInputStream(
+ rValue))));
+ } catch (FileNotFoundException e) {
+ System.out.println("CMCEnroll: can''t find file " +
+ rValue + ":\n" + e);
+ return;
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ // (3) Read the entire contents of the specified BASE 64 encoded
+ // blob into a String() object throwing away any
+ // headers beginning with HEADER and any trailers beginning
+ // with TRAILER
+ String asciiBASE64BlobChunk = new String();
+ String asciiBASE64Blob = new String();
+
+ try {
+ while ((asciiBASE64BlobChunk = inputBlob.readLine()) != null) {
+ if (!(asciiBASE64BlobChunk.startsWith(HEADER)) &&
+ !(asciiBASE64BlobChunk.startsWith(TRAILER))) {
+ asciiBASE64Blob += asciiBASE64BlobChunk.trim();
+ }
+ }
+ } catch (IOException e) {
+ System.out.println("CMCEnroll: Unexpected BASE64 " +
+ "encoded error encountered in readLine():\n" +
+ e);
+ }
+ // (4) Close the DataInputStream() object
+ try {
+ inputBlob.close();
+ } catch (IOException e) {
+ System.out.println("CMCEnroll(): Unexpected BASE64 " +
+ "encoded error encountered in close():\n" + e);
+ }
+
+ asciiBASE64Blob = getCMCBlob(signerCert, cm, nValue, asciiBASE64Blob);
+ // (5) Decode the ASCII BASE 64 blob enclosed in the
+ // String() object into a BINARY BASE 64 byte[] object
+
+ @SuppressWarnings("unused")
+ byte binaryBASE64Blob[] =
+ Utils.base64decode(asciiBASE64Blob); // check for errors
+
+ // (6) Finally, print the actual CMCEnroll blob to the
+ // specified output file
+ try {
+ outputBlob = new FileOutputStream(rValue + ".out");
+ } catch (IOException e) {
+ System.out.println("CMCEnroll: unable to open file " +
+ rValue + ".out" + " for writing:\n" + e);
+ return;
+ }
+
+ System.out.println(HEADER);
+ System.out.println(asciiBASE64Blob + TRAILER);
+ try {
+ asciiBASE64Blob = HEADER + "\n" + asciiBASE64Blob + TRAILER;
+ outputBlob.write(asciiBASE64Blob.getBytes());
+ } catch (IOException e) {
+ System.out.println("CMCEnroll: I/O error " +
+ "encountered during write():\n" +
+ e);
+ }
+
+ try {
+ outputBlob.close();
+ } catch (IOException e) {
+ System.out.println("CMCEnroll: Unexpected error " +
+ "encountered while attempting to close() " +
+ "\n" + e);
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ return;
+ }
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/CMCRequest.java b/base/java-tools/src/com/netscape/cmstools/CMCRequest.java
new file mode 100644
index 000000000..591361149
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/CMCRequest.java
@@ -0,0 +1,1129 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
+import java.util.Date;
+import java.util.StringTokenizer;
+
+import netscape.security.pkcs.PKCS10;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.X509CertImpl;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.asn1.ANY;
+import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.BIT_STRING;
+import org.mozilla.jss.asn1.ENUMERATED;
+import org.mozilla.jss.asn1.GeneralizedTime;
+import org.mozilla.jss.asn1.INTEGER;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.SET;
+import org.mozilla.jss.asn1.UTF8String;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.DigestAlgorithm;
+import org.mozilla.jss.crypto.ObjectNotFoundException;
+import org.mozilla.jss.crypto.SignatureAlgorithm;
+import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.pkcs10.CertificationRequest;
+import org.mozilla.jss.pkix.cmc.CMCCertId;
+import org.mozilla.jss.pkix.cmc.GetCert;
+import org.mozilla.jss.pkix.cmc.LraPopWitness;
+import org.mozilla.jss.pkix.cmc.OtherMsg;
+import org.mozilla.jss.pkix.cmc.PKIData;
+import org.mozilla.jss.pkix.cmc.TaggedAttribute;
+import org.mozilla.jss.pkix.cmc.TaggedCertificationRequest;
+import org.mozilla.jss.pkix.cmc.TaggedRequest;
+import org.mozilla.jss.pkix.cmmf.RevRequest;
+import org.mozilla.jss.pkix.cms.ContentInfo;
+import org.mozilla.jss.pkix.cms.EncapsulatedContentInfo;
+import org.mozilla.jss.pkix.cms.IssuerAndSerialNumber;
+import org.mozilla.jss.pkix.cms.SignedData;
+import org.mozilla.jss.pkix.cms.SignerIdentifier;
+import org.mozilla.jss.pkix.cms.SignerInfo;
+import org.mozilla.jss.pkix.crmf.CertReqMsg;
+import org.mozilla.jss.pkix.crmf.CertRequest;
+import org.mozilla.jss.pkix.crmf.CertTemplate;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+import org.mozilla.jss.pkix.primitive.Name;
+import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.cmsutil.util.HMACDigest;
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * Tool for creating CMC full request
+ *
+ * <P>
+ *
+ * @version $Revision$, $Date$
+ *
+ */
+public class CMCRequest {
+
+ public static final String PR_REQUEST_CMC = "CMC";
+ public static final String PR_REQUEST_CRMF = "CRMF";
+
+ public static final int ARGC = 1;
+ private static final String CERTDB = "cert8.db";
+ private static final String KEYDB = "key3.db";
+ public static final String HEADER = "-----BEGIN NEW CERTIFICATE REQUEST-----";
+ public static final String TRAILER = "-----END NEW CERTIFICATE REQUEST-----";
+
+ void cleanArgs(String[] s) {
+
+ }
+
+ public static X509Certificate getCertificate(String tokenname,
+ String nickname) throws Exception {
+ CryptoManager manager = CryptoManager.getInstance();
+ CryptoToken token = null;
+
+ if (tokenname.equals("internal")) {
+ token = manager.getInternalKeyStorageToken();
+ } else {
+ token = manager.getTokenByName(tokenname);
+ }
+ StringBuffer certname = new StringBuffer();
+
+ if (!token.equals(manager.getInternalKeyStorageToken())) {
+ certname.append(tokenname);
+ certname.append(":");
+ }
+ certname.append(nickname);
+ try {
+ return manager.findCertByNickname(certname.toString());
+ } catch (ObjectNotFoundException e) {
+ throw new IOException("Signing Certificate not found");
+ }
+ }
+
+ public static java.security.PrivateKey getPrivateKey(String tokenname, String nickname)
+ throws Exception {
+
+ X509Certificate cert = getCertificate(tokenname, nickname);
+
+ return CryptoManager.getInstance().findPrivKeyByCert(cert);
+ }
+
+ /**
+ * getCMCBlob create and return the enrollent request.
+ * <P>
+ *
+ * @param signerCert the certificate of the authorized signer of the CMC revocation request.
+ * @param nickname the nickname of the certificate inside the token.
+ * @param rValue CRMF/PKCS10 request.
+ * @param format either crmf or pkcs10
+ * @return the CMC enrollment request encoded in base64
+ */
+ static ContentInfo getCMCBlob(X509Certificate signerCert, String nickname,
+ String[] rValue, String format, CryptoManager manager, String transactionMgtEnable,
+ String transactionMgtId, String identityProofEnable, String identityProofSharedSecret,
+ SEQUENCE controlSeq, SEQUENCE otherMsgSeq, int bpid) {
+
+ String tokenname = "internal";
+
+ ContentInfo fullEnrollmentReq = null;
+ try {
+ java.security.PrivateKey privKey = null;
+ SignerIdentifier si = null;
+
+ BigInteger serialno = signerCert.getSerialNumber();
+ byte[] certB = signerCert.getEncoded();
+ X509CertImpl impl = new X509CertImpl(certB);
+ X500Name issuerName = (X500Name) impl.getIssuerDN();
+ byte[] issuerByte = issuerName.getEncoded();
+ ByteArrayInputStream istream = new ByteArrayInputStream(issuerByte);
+
+ Name issuer = (Name) Name.getTemplate().decode(istream);
+ IssuerAndSerialNumber ias = new IssuerAndSerialNumber(
+ issuer, new INTEGER(serialno.toString()));
+
+ si = new SignerIdentifier(
+ SignerIdentifier.ISSUER_AND_SERIALNUMBER, ias, null);
+ privKey = getPrivateKey(tokenname, nickname);
+
+ TaggedRequest trq = null;
+ PKCS10 pkcs = null;
+ CertReqMsg certReqMsg = null;
+
+ // create CMC req
+ SEQUENCE reqSequence = new SEQUENCE();
+ try {
+ for (int k = 0; k < rValue.length; k++) {
+ String asciiBASE64Blob = rValue[k];
+ byte[] decodedBytes = Utils.base64decode(asciiBASE64Blob);
+
+ if (format.equals("crmf")) {
+ ByteArrayInputStream reqBlob =
+ new ByteArrayInputStream(decodedBytes);
+ SEQUENCE crmfMsgs = null;
+ try {
+ crmfMsgs = (SEQUENCE) new SEQUENCE.OF_Template(new
+ CertReqMsg.Template()).decode(reqBlob);
+ } catch (InvalidBERException ee) {
+ System.out.println("This is not a crmf request. Or this request has an error.");
+ System.exit(1);
+ }
+ certReqMsg = (CertReqMsg) crmfMsgs.elementAt(0);
+ trq = new TaggedRequest(TaggedRequest.CRMF, null,
+ certReqMsg);
+ } else if (format.equals("pkcs10")) {
+ try {
+ pkcs = new PKCS10(decodedBytes);
+ } catch (IllegalArgumentException e) {
+ System.out.println("This is not a PKCS10 request.");
+ System.exit(1);
+ }
+ ByteArrayInputStream crInputStream = new ByteArrayInputStream(
+ pkcs.toByteArray());
+ CertificationRequest cr = (CertificationRequest)
+ CertificationRequest.getTemplate().decode(crInputStream);
+ TaggedCertificationRequest tcr = new TaggedCertificationRequest(
+ new INTEGER(bpid++), cr);
+ trq = new
+ TaggedRequest(TaggedRequest.PKCS10, tcr, null);
+ } else {
+ System.out.println("Unrecognized request format: " + format);
+ System.exit(1);
+ }
+ reqSequence.addElement(trq);
+ }
+ } catch (IOException e) {
+ throw new IOException("Internal Error - " + e.toString());
+ } catch (SignatureException e) {
+ throw new IOException("Internal Error - " + e.toString());
+ } catch (NoSuchAlgorithmException e) {
+ throw new IOException("Internal Error - " + e.toString());
+ }
+
+ if (transactionMgtEnable.equals("true"))
+ bpid = addTransactionAttr(bpid, controlSeq, transactionMgtId, format,
+ pkcs, certReqMsg);
+
+ if (identityProofEnable.equals("true"))
+ bpid = addIdentityProofAttr(bpid, controlSeq, reqSequence,
+ identityProofSharedSecret);
+
+ PKIData pkidata = new PKIData(controlSeq, reqSequence, new SEQUENCE(), otherMsgSeq);
+
+ EncapsulatedContentInfo ci = new
+ EncapsulatedContentInfo(OBJECT_IDENTIFIER.id_cct_PKIData, pkidata);
+ // SHA1 is the default digest Alg for now.
+ DigestAlgorithm digestAlg = null;
+ SignatureAlgorithm signAlg = SignatureAlgorithm.RSASignatureWithSHA1Digest;
+ org.mozilla.jss.crypto.PrivateKey.Type signingKeyType =
+ ((org.mozilla.jss.crypto.PrivateKey) privKey).getType();
+
+ if (signingKeyType.equals(org.mozilla.jss.crypto.PrivateKey.Type.DSA))
+ signAlg = SignatureAlgorithm.DSASignatureWithSHA1Digest;
+ MessageDigest SHADigest = null;
+
+ byte[] digest = null;
+ try {
+ SHADigest = MessageDigest.getInstance("SHA1");
+ digestAlg = DigestAlgorithm.SHA1;
+
+ ByteArrayOutputStream ostream = new ByteArrayOutputStream();
+
+ pkidata.encode((OutputStream) ostream);
+ digest = SHADigest.digest(ostream.toByteArray());
+ } catch (NoSuchAlgorithmException e) {
+ }
+ SignerInfo signInfo = new
+ SignerInfo(si, null, null, OBJECT_IDENTIFIER.id_cct_PKIData, digest, signAlg,
+ (org.mozilla.jss.crypto.PrivateKey) privKey);
+ SET signInfos = new SET();
+ signInfos.addElement(signInfo);
+
+ SET digestAlgs = new SET();
+
+ if (digestAlg != null) {
+ AlgorithmIdentifier ai = new AlgorithmIdentifier(digestAlg.toOID(), null);
+ digestAlgs.addElement(ai);
+ }
+
+ org.mozilla.jss.crypto.X509Certificate[] agentChain = manager.buildCertificateChain(signerCert);
+ SET certs = new SET();
+
+ for (int i = 0; i < agentChain.length; i++) {
+ ANY cert = new ANY(agentChain[i].getEncoded());
+ certs.addElement(cert);
+ }
+ SignedData req = new SignedData(digestAlgs, ci, certs, null, signInfos);
+ fullEnrollmentReq = new ContentInfo(req);
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(bs);
+
+ if (fullEnrollmentReq != null) {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ fullEnrollmentReq.encode(os);
+ ps.print(Utils.base64encode(os.toByteArray()));
+ }
+ String asciiBASE64Blob = bs.toString();
+
+ System.out.println("");
+ System.out.println("The CMC enrollment request in base-64 encoded format:");
+ System.out.println("");
+ System.out.println(asciiBASE64Blob);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ return fullEnrollmentReq;
+ }
+
+ static void printUsage() {
+ System.out.println("");
+ System.out.println("Usage: CMCRequest <configuration file>");
+ System.out.println("For example, CMCRequest CMCRequest.cfg");
+ System.out.println("");
+ System.out.println("The configuration file should look like as follows:");
+ System.out.println("");
+ System.out.println("#numRequests: Total number of PKCS10 requests or CRMF requests.");
+ System.out.println("numRequests=1");
+ System.out.println("");
+ System.out.println("#input: full path for the PKCS10 request or CRMF request,");
+ System.out.println("#the content must be in Base-64 encoded format");
+ System.out.println("#Multiple files are supported. They must be separated by space.");
+ System.out.println("input=crmf1");
+ System.out.println("");
+ System.out.println("#output: full path for the CMC request in binary format");
+ System.out.println("output=/u/doc/cmcReq");
+ System.out.println("");
+ System.out.println("#nickname: nickname for agent certificate which will be used");
+ System.out.println("#to sign the CMC full request.");
+ System.out.println("nickname=CMS Agent Certificate");
+ System.out.println("");
+ System.out.println("#dbdir: directory for cert8.db, key3.db and secmod.db");
+ System.out.println("dbdir=/u/smith/.netscape");
+ System.out.println("");
+ System.out.println("#password: password for cert8.db which stores the agent");
+ System.out.println("#certificate");
+ System.out.println("password=pass");
+ System.out.println("");
+ System.out.println("#format: request format, either pkcs10 or crmf");
+ System.out.println("format=crmf");
+ System.out.println("");
+ System.out.println("#confirmCertAcceptance.enable: if true, then the request will");
+ System.out.println("#contain this control. Otherwise, false.");
+ System.out.println("confirmCertAcceptance.enable=true");
+ System.out.println("");
+ System.out.println("#confirmCertAcceptance.serial: The serial number for");
+ System.out.println("#confirmCertAcceptance control");
+ System.out.println("confirmCertAcceptance.serial=3");
+ System.out.println("");
+ System.out.println("#confirmCertAcceptance.issuer: The issuer name for");
+ System.out.println("#confirmCertAcceptance control");
+ System.out.println("confirmCertAcceptance.issuer=cn=Certificate Manager,c=us");
+ System.out.println("");
+ System.out.println("#getCert.enable: if true, then the request will contain this");
+ System.out.println("#control. Otherwise, false.");
+ System.out.println("getCert.enable=true");
+ System.out.println("");
+ System.out.println("#getCert.serial: The serial number for getCert control");
+ System.out.println("getCert.serial=3");
+ System.out.println("");
+ System.out.println("#getCert.issuer: The issuer name for getCert control");
+ System.out.println("getCert.issuer=cn=Certificate Manager,c=us");
+ System.out.println("");
+ System.out.println("#dataReturn.enable: if true, then the request will contain");
+ System.out.println("#this control. Otherwise, false.");
+ System.out.println("dataReturn.enable=true");
+ System.out.println("");
+ System.out.println("#dataReturn.data: data contained in the control.");
+ System.out.println("dataReturn.data=test");
+ System.out.println("");
+ System.out.println("#transactionMgt.enable: if true, then the request will contain");
+ System.out.println("#this control. Otherwise, false.");
+ System.out.println("transactionMgt.enable=true");
+ System.out.println("");
+ System.out.println("#transactionMgt.id: transaction identifier. Verisign recommend");
+ System.out.println("#transactionId to be MD5 hash of publicKey.");
+ System.out.println("transactionMgt.id=");
+ System.out.println("");
+ System.out.println("#senderNonce.enable: if true, then the request will contain this");
+ System.out.println("#control. Otherwise, false.");
+ System.out.println("senderNonce.enable=true");
+ System.out.println("");
+ System.out.println("#senderNonce.id: sender nonce");
+ System.out.println("senderNonce.id=");
+ System.out.println("");
+ System.out.println("#revRequest.enable: if true, then the request will contain this");
+ System.out.println("#control. Otherwise, false.");
+ System.out.println("revRequest.enable=true");
+ System.out.println("");
+ System.out.println("#revRequest.nickname: The nickname for the revoke certificate");
+ System.out.println("revRequest.nickname=newuser's 102504a ID");
+ System.out.println("");
+ System.out.println("#revRequest.issuer: The issuer name for the certificate being");
+ System.out.println("#revoked.");
+ System.out.println("revRequest.issuer=cn=Certificate Manager,c=us");
+ System.out.println("");
+ System.out.println("#revRequest.serial: The serial number for the certificate being");
+ System.out.println("#revoked.");
+ System.out.println("revRequest.serial=61");
+ System.out.println("");
+ System.out.println("#revRequest.reason: The reason for revoking this certificate: ");
+ System.out.println("# unspecified, keyCompromise, caCompromise,");
+ System.out.println("# affiliationChanged, superseded, cessationOfOperation,");
+ System.out.println("# certificateHold, removeFromCRL");
+ System.out.println("revRequest.reason=unspecified");
+ System.out.println("");
+ System.out.println("#revRequest.sharedSecret: The sharedSecret");
+ System.out.println("revRequest.sharedSecret=");
+ System.out.println("");
+ System.out.println("#revRequest.comment: The human readable comment");
+ System.out.println("revRequest.comment=");
+ System.out.println("");
+ System.out.println("#revRequest.invalidityDatePresent: if true, the current time will be the");
+ System.out.println("# invalidityDate. If false, no invalidityDate");
+ System.out.println("# is present.");
+ System.out.println("revRequest.invalidityDatePresent=false");
+ System.out.println("");
+ System.out.println("#identityProof.enable: if true, then the request will contain");
+ System.out.println("#this control. Otherwise, false.");
+ System.out.println("identityProof.enable=true");
+ System.out.println("");
+ System.out.println("#identityProof.sharedSecret: Shared Secret");
+ System.out.println("identityProof.sharedSecret=testing");
+ System.out.println("");
+ System.out.println("#popLinkWitness.enable: if true, then the request will contain");
+ System.out.println("#this control. Otherwise, false.");
+ System.out.println("#If you want to test this control, make sure to use CRMFPopClient ");
+ System.out.println("# to generate the CRMF request which will include the ");
+ System.out.println("#idPOPLinkWitness attribute in the controls section of the ");
+ System.out.println("#CertRequest structure.");
+ System.out.println("popLinkWitness.enable=false");
+ System.out.println("");
+ System.out.println("#LraPopWitness.enable: if true, then the request will contain this");
+ System.out.println("#control. Otherwise, false.");
+ System.out.println("LraPopWitness.enable=true");
+ System.out.println("");
+ System.out.println("#LraPopWitness.bodyPartIDs: List of body part IDs");
+ System.out.println("#Each id is separated by space.");
+ System.out.println("LraPopWitness.bodyPartIDs=1");
+ System.exit(1);
+ }
+
+ private static int addLraPopWitnessAttr(int bpid, SEQUENCE seq, String bodyPartIDs) {
+ StringTokenizer tokenizer = new StringTokenizer(bodyPartIDs, " ");
+ SEQUENCE bodyList = new SEQUENCE();
+ while (tokenizer.hasMoreTokens()) {
+ String s = (String) tokenizer.nextToken();
+ bodyList.addElement(new INTEGER(s));
+ }
+ LraPopWitness lra = new LraPopWitness(new INTEGER(0), bodyList);
+ TaggedAttribute cont = new TaggedAttribute(new
+ INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_lraPOPWitness, lra);
+ System.out.println("Successfully create LRA POP witness control. bpid = " + (bpid - 1));
+ System.out.println("");
+ seq.addElement(cont);
+ return bpid;
+ }
+
+ private static int addConfirmCertAttr(int bpid, SEQUENCE seq, String confirmCertIssuer,
+ String confirmCertSerial) {
+ try {
+ INTEGER serial = new INTEGER(confirmCertSerial);
+ X500Name issuername = new X500Name(confirmCertIssuer);
+ byte[] issuerbyte = issuername.getEncoded();
+ ANY issuern = new ANY(issuerbyte);
+ CMCCertId cmcCertId = new CMCCertId(issuern, serial, null);
+ TaggedAttribute cmcCertIdControl = new TaggedAttribute(new
+ INTEGER(bpid++),
+ OBJECT_IDENTIFIER.id_cmc_idConfirmCertAcceptance, cmcCertId);
+ System.out.println("Successfully create confirm certificate acceptance control. bpid = " + (bpid - 1));
+ System.out.println("");
+ seq.addElement(cmcCertIdControl);
+ } catch (Exception e) {
+ System.out.println("Error in creating confirm certificate acceptance control. Check the parameters.");
+ System.exit(1);
+ }
+ return bpid;
+ }
+
+ private static ENUMERATED toCRLReason(String str) {
+ if (str.equalsIgnoreCase("unspecified")) {
+ return RevRequest.unspecified;
+ } else if (str.equalsIgnoreCase("keyCompromise")) {
+ return RevRequest.keyCompromise;
+ } else if (str.equalsIgnoreCase("caCompromise")) {
+ return RevRequest.cACompromise;
+ } else if (str.equalsIgnoreCase("affiliationChanged")) {
+ return RevRequest.affiliationChanged;
+ } else if (str.equalsIgnoreCase("superseded")) {
+ return RevRequest.superseded;
+ } else if (str.equalsIgnoreCase("cessationOfOperation")) {
+ return RevRequest.cessationOfOperation;
+ } else if (str.equalsIgnoreCase("certificateHold")) {
+ return RevRequest.certificateHold;
+ } else if (str.equalsIgnoreCase("removeFromCRL")) {
+ return RevRequest.removeFromCRL;
+ }
+
+ System.out.println("Unrecognized CRL reason");
+ System.exit(1);
+
+ return RevRequest.unspecified;
+ }
+
+ private static int addIdentityProofAttr(int bpid, SEQUENCE seq, SEQUENCE reqSequence,
+ String sharedSecret) {
+ byte[] b = ASN1Util.encode(reqSequence);
+ byte[] key = null;
+ byte[] finalDigest = null;
+ try {
+ MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1");
+ key = SHA1Digest.digest(sharedSecret.getBytes());
+ } catch (NoSuchAlgorithmException ex) {
+ System.out.println("CMCRequest::addIdentityProofAttr() - "
+ + "No such algorithm!");
+ return -1;
+ }
+
+ try {
+ MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1");
+ HMACDigest hmacDigest = new HMACDigest(SHA1Digest, key);
+ hmacDigest.update(b);
+ finalDigest = hmacDigest.digest();
+ } catch (NoSuchAlgorithmException ex) {
+ }
+
+ TaggedAttribute identityProof = new TaggedAttribute(new
+ INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_identityProof,
+ new OCTET_STRING(finalDigest));
+ seq.addElement(identityProof);
+ System.out.println("Identity Proof control: ");
+ System.out.print(" Value: ");
+ for (int i = 0; i < finalDigest.length; i++) {
+ System.out.print(finalDigest[i] + " ");
+ }
+ System.out.println("");
+ System.out.println("Successfully create identityProof control. bpid = " + (bpid - 1));
+ System.out.println("");
+ return bpid;
+ }
+
+ private static int addRevRequestAttr(int bpid, SEQUENCE seq, SEQUENCE otherMsgSeq, String nickname,
+ String revRequestIssuer, String revRequestSerial, String revRequestReason,
+ String revRequestSharedSecret, String revRequestComment, String invalidityDatePresent,
+ CryptoManager manager) {
+ try {
+ if (nickname.length() <= 0) {
+ System.out.println("The nickname for the certificate being revoked is null");
+ System.exit(1);
+ }
+ String nickname1 = nickname;
+ UTF8String comment = null;
+ OCTET_STRING sharedSecret = null;
+ GeneralizedTime d = null;
+ X500Name subjectname = new X500Name(revRequestIssuer);
+ INTEGER snumber = new INTEGER(revRequestSerial);
+ ENUMERATED reason = toCRLReason(revRequestReason);
+ if (revRequestSharedSecret.length() > 0)
+ sharedSecret = new OCTET_STRING(revRequestSharedSecret.getBytes());
+ if (revRequestComment.length() > 0)
+ comment = new UTF8String(revRequestComment);
+ if (invalidityDatePresent.equals("true"))
+ d = new GeneralizedTime(new Date());
+ RevRequest revRequest =
+ new RevRequest(new ANY(subjectname.getEncoded()), snumber,
+ reason, d, sharedSecret, comment);
+ int revokeBpid = bpid;
+ TaggedAttribute revRequestControl = new TaggedAttribute(
+ new INTEGER(bpid++),
+ OBJECT_IDENTIFIER.id_cmc_revokeRequest, revRequest);
+ seq.addElement(revRequestControl);
+
+ if (sharedSecret != null) {
+ System.out.println("Successfully create revRequest control. bpid = " + (bpid - 1));
+ System.out.println("");
+ return bpid;
+ }
+
+ EncapsulatedContentInfo revokeContent = new EncapsulatedContentInfo(
+ OBJECT_IDENTIFIER.id_cct_PKIData, revRequestControl);
+ DigestAlgorithm digestAlg1 = null;
+ SignatureAlgorithm signAlg1 = SignatureAlgorithm.RSASignatureWithSHA1Digest;
+ java.security.PrivateKey revokePrivKey = null;
+ X509Certificate revokeCert = null;
+ try {
+ revokeCert = manager.findCertByNickname(nickname1);
+ } catch (ObjectNotFoundException e) {
+ System.out.println("Certificate not found: " + nickname1);
+ System.exit(1);
+ }
+ revokePrivKey = manager.findPrivKeyByCert(revokeCert);
+ org.mozilla.jss.crypto.PrivateKey.Type signingKeyType1 =
+ ((org.mozilla.jss.crypto.PrivateKey) revokePrivKey).getType();
+ if (signingKeyType1.equals(org.mozilla.jss.crypto.PrivateKey.Type.DSA))
+ signAlg1 = SignatureAlgorithm.DSASignatureWithSHA1Digest;
+
+ MessageDigest rSHADigest = null;
+ byte[] rdigest = null;
+ try {
+ rSHADigest = MessageDigest.getInstance("SHA1");
+ digestAlg1 = DigestAlgorithm.SHA1;
+
+ ByteArrayOutputStream ostream = new ByteArrayOutputStream();
+
+ revRequestControl.encode((OutputStream) ostream);
+ rdigest = rSHADigest.digest(ostream.toByteArray());
+ } catch (NoSuchAlgorithmException e) {
+ }
+
+ ByteArrayInputStream bistream =
+ new ByteArrayInputStream(subjectname.getEncoded());
+ Name iname = (Name) Name.getTemplate().decode(bistream);
+ IssuerAndSerialNumber ias1 = new IssuerAndSerialNumber(iname, snumber);
+
+ SignerIdentifier rsi = new SignerIdentifier(
+ SignerIdentifier.ISSUER_AND_SERIALNUMBER, ias1, null);
+
+ SignerInfo signInfo1 = new SignerInfo(rsi, null, null,
+ OBJECT_IDENTIFIER.id_cct_PKIData, rdigest, signAlg1,
+ (org.mozilla.jss.crypto.PrivateKey) revokePrivKey);
+
+ SET signInfos1 = new SET();
+ signInfos1.addElement(signInfo1);
+ SET digestAlgs1 = new SET();
+ if (digestAlg1 != null) {
+ AlgorithmIdentifier ai1 = new AlgorithmIdentifier(digestAlg1.toOID(), null);
+ digestAlgs1.addElement(ai1);
+ }
+
+ org.mozilla.jss.crypto.X509Certificate[] revokeCertChain =
+ manager.buildCertificateChain(revokeCert);
+ SET certs1 = new SET();
+ for (int i = 0; i < revokeCertChain.length; i++) {
+ ANY cert1 = new ANY(revokeCertChain[i].getEncoded());
+ certs1.addElement(cert1);
+ }
+
+ SignedData sData = new SignedData(digestAlgs1, revokeContent, certs1, null, signInfos1);
+ OBJECT_IDENTIFIER signedDataOID = new OBJECT_IDENTIFIER("1.2.840.113549.1.7.2");
+ ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
+ sData.encode(bos1);
+ OtherMsg otherMsg = new OtherMsg(new INTEGER(revokeBpid), signedDataOID, new ANY(bos1.toByteArray()));
+ otherMsgSeq.addElement(otherMsg);
+ System.out.println("Successfully create revRequest control. bpid = " + (bpid - 1));
+ System.out.println("");
+ } catch (Exception e) {
+ System.out.println("Error in creating revRequest control. Check the parameters.");
+ System.exit(1);
+ }
+
+ return bpid;
+ }
+
+ private static int addGetCertAttr(int bpid, SEQUENCE seq, String issuer, String serial) {
+ try {
+ INTEGER serialno = new INTEGER(serial);
+ X500Name issuername = new X500Name(issuer);
+ byte[] issuerbyte = issuername.getEncoded();
+ ANY issuern = new ANY(issuerbyte);
+ GetCert getCert = new GetCert(issuern, serialno);
+ TaggedAttribute getCertControl = new TaggedAttribute(new
+ INTEGER(bpid++),
+ OBJECT_IDENTIFIER.id_cmc_getCert, getCert);
+ System.out.println("Successfully create get certificate control. bpid = " + (bpid - 1));
+ System.out.println("");
+ seq.addElement(getCertControl);
+ } catch (Exception e) {
+ System.out.println("Error in creating get certificate control. Check the parameters.");
+ System.exit(1);
+ }
+
+ return bpid;
+ }
+
+ private static int addDataReturnAttr(int bpid, SEQUENCE seq, String str) {
+ try {
+ byte bvalue[] = str.getBytes();
+ System.out.println("Data Return Control: ");
+ String ss = " Value: ";
+ for (int m = 0; m < bvalue.length; m++) {
+ ss = ss + bvalue[m] + " ";
+ }
+ System.out.println(ss);
+ OCTET_STRING s = new OCTET_STRING(bvalue);
+ TaggedAttribute dataReturnControl = new TaggedAttribute(new
+ INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_dataReturn, s);
+ seq.addElement(dataReturnControl);
+ System.out.println("Successfully create data return control. bpid = " + (bpid - 1));
+ System.out.println("");
+ } catch (Exception e) {
+ System.out.println("Error in creating data return control. Check the parameters.");
+ System.exit(1);
+ }
+
+ return bpid;
+ }
+
+ private static int addTransactionAttr(int bpid, SEQUENCE seq, String id, String format,
+ PKCS10 pkcs, CertReqMsg certReqMsg) {
+ byte[] transId = null;
+ Date date = new Date();
+ String salt = "lala123" + date.toString();
+ if (id == null || id.equals("")) {
+ try {
+ MessageDigest MD5Digest = MessageDigest.getInstance("MD5");
+ if (format.equals("crmf")) {
+ CertRequest certreq = certReqMsg.getCertReq();
+ CertTemplate certTemplate = certreq.getCertTemplate();
+ SubjectPublicKeyInfo pkinfo = certTemplate.getPublicKey();
+ BIT_STRING bitString = pkinfo.getSubjectPublicKey();
+ byte[] b = bitString.getBits();
+ transId = MD5Digest.digest(b);
+ } else if (format.equals("pkcs10")) {
+ transId = MD5Digest.digest(pkcs.getSubjectPublicKeyInfo().getKey());
+ }
+ } catch (Exception ex) {
+ transId = salt.getBytes();
+ }
+ } else {
+ transId = id.getBytes();
+ }
+
+ if (transId == null) {
+ System.out.println("CMCRequest::addTransactionAttr() - "
+ + "transId is null!");
+ return -1;
+ }
+
+ INTEGER ii = new INTEGER(1, transId);
+ TaggedAttribute transactionId = new TaggedAttribute(new
+ INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_transactionId, ii);
+ System.out.println("Transaction ID control: ");
+ System.out.println(" Value: " + ii.toString());
+ System.out.println("Successfully create transaction management control. bpid = " + (bpid - 1));
+ System.out.println("");
+
+ seq.addElement(transactionId);
+
+ return bpid;
+ }
+
+ private static int addSenderNonceAttr(int bpid, SEQUENCE seq, String nonce) {
+ byte[] dig;
+ String sn = nonce;
+ if (nonce == null || nonce.equals("")) {
+ // Verisign has transactionID,senderNonce
+ Date date = new Date();
+ String salt = "lala123" + date.toString();
+
+ try {
+ MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1");
+
+ dig = SHA1Digest.digest(salt.getBytes());
+ } catch (NoSuchAlgorithmException ex) {
+ dig = salt.getBytes();
+ }
+
+ sn = Utils.base64encode(dig);
+ }
+ byte bb[] = sn.getBytes();
+ System.out.println("SenderNonce control: ");
+ String ss = " Value: ";
+ for (int m = 0; m < bb.length; m++) {
+ ss = ss + bb[m] + " ";
+ }
+ System.out.println(ss);
+ TaggedAttribute senderNonce = new TaggedAttribute(new
+ INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_senderNonce,
+ new OCTET_STRING(sn.getBytes()));
+ System.out.println("Successfully create sender nonce control. bpid = " + (bpid - 1));
+ System.out.println("");
+ seq.addElement(senderNonce);
+ return bpid;
+ }
+
+ private static int addPopLinkWitnessAttr(int bpid, SEQUENCE controlSeq) {
+ byte[] seed =
+ { 0x10, 0x53, 0x42, 0x24, 0x1a, 0x2a, 0x35, 0x3c,
+ 0x7a, 0x52, 0x54, 0x56, 0x71, 0x65, 0x66, 0x4c,
+ 0x51, 0x34, 0x35, 0x23, 0x3c, 0x42, 0x43, 0x45,
+ 0x61, 0x4f, 0x6e, 0x43, 0x1e, 0x2a, 0x2b, 0x31,
+ 0x32, 0x34, 0x35, 0x36, 0x55, 0x51, 0x48, 0x14,
+ 0x16, 0x29, 0x41, 0x42, 0x43, 0x7b, 0x63, 0x44,
+ 0x6a, 0x12, 0x6b, 0x3c, 0x4c, 0x3f, 0x00, 0x14,
+ 0x51, 0x61, 0x15, 0x22, 0x23, 0x5f, 0x5e, 0x69 };
+
+ TaggedAttribute idPOPLinkRandom = new TaggedAttribute(new
+ INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_idPOPLinkRandom,
+ new OCTET_STRING(seed));
+ controlSeq.addElement(idPOPLinkRandom);
+ System.out.println("Successfully create PopLinkWitness control. bpid = " + (bpid - 1));
+ System.out.println("");
+ return bpid;
+ }
+
+ public static void main(String[] s) {
+ String numRequests = null;
+ String dbdir = null, nickname = null;
+ String ifilename = null, ofilename = null, password = null, format = null;
+ String confirmCertEnable = "false", confirmCertIssuer = null, confirmCertSerial = null;
+ String getCertEnable = "false", getCertIssuer = null, getCertSerial = null;
+ String dataReturnEnable = "false", dataReturnData = null;
+ String transactionMgtEnable = "false", transactionMgtId = null;
+ String senderNonceEnable = "false", senderNonce = null;
+ String revCertNickname = "";
+ String revRequestEnable = "false", revRequestIssuer = null, revRequestSerial = null;
+ String revRequestReason = null, revRequestSharedSecret = null, revRequestComment = null;
+ String revRequestInvalidityDatePresent = "false";
+ String identityProofEnable = "false", identityProofSharedSecret = null;
+ String popLinkWitnessEnable = "false";
+ String bodyPartIDs = null, lraPopWitnessEnable = "false";
+
+ System.out.println("");
+
+ // Check that the correct # of arguments were submitted to the program
+ if (s.length != (ARGC)) {
+ System.out.println("Wrong number of parameters:" + s.length);
+ printUsage();
+ }
+
+ String configFile = s[0];
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new InputStreamReader(
+ new BufferedInputStream(
+ new FileInputStream(
+ configFile))));
+ } catch (FileNotFoundException e) {
+ System.out.println("CMCRequest: can't find configuration file: " + configFile);
+ printUsage();
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ try {
+ String str = "";
+ while ((str = reader.readLine()) != null) {
+ str = str.trim();
+ if (!str.startsWith("#") && str.length() > 0) {
+ int index = str.indexOf("=");
+ String name = "";
+ String val = "";
+ if (index == -1) {
+ System.out.println("Error in configuration file: " + str);
+ System.exit(1);
+ }
+ name = str.substring(0, index);
+ if (index != str.length() - 1)
+ val = str.substring(index + 1);
+
+ if (name.equals("format")) {
+ format = val;
+ } else if (name.equals("dbdir")) {
+ dbdir = val;
+ } else if (name.equals("nickname")) {
+ nickname = val;
+ } else if (name.equals("password")) {
+ password = val;
+ } else if (name.equals("output")) {
+ ofilename = val;
+ } else if (name.equals("input")) {
+ ifilename = val;
+ } else if (name.equals("confirmCertAcceptance.serial")) {
+ confirmCertSerial = val;
+ } else if (name.equals("confirmCertAcceptance.issuer")) {
+ confirmCertIssuer = val;
+ } else if (name.equals("confirmCertAcceptance.enable")) {
+ confirmCertEnable = val;
+ } else if (name.equals("getCert.enable")) {
+ getCertEnable = val;
+ } else if (name.equals("getCert.issuer")) {
+ getCertIssuer = val;
+ } else if (name.equals("getCert.serial")) {
+ getCertSerial = val;
+ } else if (name.equals("dataReturn.enable")) {
+ dataReturnEnable = val;
+ } else if (name.equals("dataReturn.data")) {
+ dataReturnData = val;
+ } else if (name.equals("transactionMgt.enable")) {
+ transactionMgtEnable = val;
+ } else if (name.equals("transactionMgt.id")) {
+ transactionMgtId = val;
+ } else if (name.equals("senderNonce.enable")) {
+ senderNonceEnable = val;
+ } else if (name.equals("senderNonce")) {
+ senderNonce = val;
+ } else if (name.equals("revRequest.enable")) {
+ revRequestEnable = val;
+ } else if (name.equals("revRequest.issuer")) {
+ revRequestIssuer = val;
+ } else if (name.equals("revRequest.serial")) {
+ revRequestSerial = val;
+ } else if (name.equals("revRequest.reason")) {
+ revRequestReason = val;
+ } else if (name.equals("revRequest.sharedSecret")) {
+ revRequestSharedSecret = val;
+ } else if (name.equals("revRequest.comment")) {
+ revRequestComment = val;
+ } else if (name.equals("revRequest.invalidityDatePresent")) {
+ revRequestInvalidityDatePresent = val;
+ } else if (name.equals("revRequest.nickname")) {
+ revCertNickname = val;
+ } else if (name.equals("identityProof.enable")) {
+ identityProofEnable = val;
+ } else if (name.equals("identityProof.sharedSecret")) {
+ identityProofSharedSecret = val;
+ } else if (name.equals("popLinkWitness.enable")) {
+ popLinkWitnessEnable = val;
+ } else if (name.equals("LraPopWitness.enable")) {
+ lraPopWitnessEnable = val;
+ } else if (name.equals("LraPopWitness.bodyPartIDs")) {
+ bodyPartIDs = val;
+ } else if (name.equals("numRequests")) {
+ numRequests = val;
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ printUsage();
+ }
+
+ if (ifilename == null) {
+ System.out.println("Missing input filename for PKCS10 or CRMF.");
+ printUsage();
+ }
+
+ int num = 0;
+ if (numRequests == null) {
+ System.out.println("Missing numRequests.");
+ printUsage();
+ } else {
+ try {
+ num = Integer.parseInt(numRequests);
+ } catch (Exception ee) {
+ System.out.println("numRequests must be integer");
+ System.exit(1);
+ }
+ }
+
+ StringTokenizer tokenizer = new StringTokenizer(ifilename, " ");
+ String[] ifiles = new String[num];
+ for (int i = 0; i < num; i++) {
+ String ss = (String) tokenizer.nextToken();
+ ifiles[i] = ss;
+ if (ss == null) {
+ System.out.println("Missing input file for the request.");
+ System.exit(1);
+ }
+ }
+
+ if (ofilename == null) {
+ System.out.println("Missing output filename for the CMC request.");
+ printUsage();
+ }
+
+ if (format == null) {
+ System.out.println("Missing format.");
+ printUsage();
+ }
+
+ if (password == null) {
+ System.out.println("Missing password.");
+ printUsage();
+ }
+
+ if (nickname == null) {
+ System.out.println("Missing nickname.");
+ printUsage();
+ }
+
+ try {
+ // initialize CryptoManager
+ if (dbdir == null)
+ dbdir = ".";
+ String mPrefix = "";
+ System.out.println("cert/key prefix = " + mPrefix);
+ System.out.println("path = " + dbdir);
+ CryptoManager.InitializationValues vals =
+ new CryptoManager.InitializationValues(dbdir, mPrefix,
+ mPrefix, "secmod.db");
+
+ CryptoManager.initialize(vals);
+ CryptoManager cm = CryptoManager.getInstance();
+ CryptoToken token = cm.getInternalKeyStorageToken();
+ Password pass = new Password(password.toCharArray());
+
+ token.login(pass);
+ X509Certificate signerCert = null;
+
+ signerCert = cm.findCertByNickname(nickname);
+
+ String[] requests = new String[num];
+ for (int i = 0; i < num; i++) {
+ BufferedReader inputBlob = null;
+ try {
+ inputBlob = new BufferedReader(new InputStreamReader(
+ new BufferedInputStream(new FileInputStream(ifiles[i]))));
+ } catch (FileNotFoundException e) {
+ System.out.println("CMCRequest: can't find file " +
+ ifiles[i] + ":\n" + e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ // (3) Read the entire contents of the specified BASE 64 encoded
+ // blob into a String() object throwing away any
+ // headers beginning with HEADER and any trailers beginning
+ // with TRAILER
+ String asciiBASE64BlobChunk = new String();
+ String asciiBASE64Blob = new String();
+
+ try {
+ while ((asciiBASE64BlobChunk = inputBlob.readLine()) != null) {
+ if (!(asciiBASE64BlobChunk.startsWith(HEADER)) &&
+ !(asciiBASE64BlobChunk.startsWith(TRAILER))) {
+ asciiBASE64Blob += asciiBASE64BlobChunk.trim();
+ }
+ }
+ requests[i] = asciiBASE64Blob;
+ } catch (IOException e) {
+ System.out.println("CMCRequest: Unexpected BASE64 " +
+ "encoded error encountered in readLine():\n" +
+ e);
+ }
+ // (4) Close the DataInputStream() object
+ try {
+ inputBlob.close();
+ } catch (IOException e) {
+ System.out.println("CMCRequest(): Unexpected BASE64 " +
+ "encoded error encountered in close():\n" + e);
+ }
+ }
+
+ SEQUENCE controlSeq = new SEQUENCE();
+ int bpid = 1;
+ if (confirmCertEnable.equalsIgnoreCase("true")) {
+ if (confirmCertIssuer.length() == 0 || confirmCertSerial.length() == 0) {
+ System.out.println("Illegal parameters for confirm certificate acceptance control");
+ printUsage();
+ System.exit(1);
+ }
+ bpid = addConfirmCertAttr(bpid, controlSeq, confirmCertIssuer, confirmCertSerial);
+ }
+
+ if (lraPopWitnessEnable.equalsIgnoreCase("true")) {
+ if (bodyPartIDs.length() == 0) {
+ System.out.println("Illegal parameters for Lra Pop Witness control");
+ printUsage();
+ System.exit(1);
+ }
+
+ bpid = addLraPopWitnessAttr(bpid, controlSeq, bodyPartIDs);
+ }
+
+ if (getCertEnable.equalsIgnoreCase("true")) {
+ if (getCertIssuer.length() == 0 || getCertSerial.length() == 0) {
+ System.out.println("Illegal parameters for get certificate control");
+ printUsage();
+ System.exit(1);
+ }
+
+ bpid = addGetCertAttr(bpid, controlSeq, getCertIssuer, getCertSerial);
+ }
+
+ if (dataReturnEnable.equalsIgnoreCase("true")) {
+ if (dataReturnData.length() == 0) {
+ System.out.println("Illegal parameters for data return control");
+ printUsage();
+ System.exit(1);
+ }
+
+ bpid = addDataReturnAttr(bpid, controlSeq, dataReturnData);
+ }
+
+ if (senderNonceEnable.equalsIgnoreCase("true"))
+ bpid = addSenderNonceAttr(bpid, controlSeq, senderNonce);
+
+ if (popLinkWitnessEnable.equalsIgnoreCase("true"))
+ bpid = addPopLinkWitnessAttr(bpid, controlSeq);
+
+ SEQUENCE otherMsgSeq = new SEQUENCE();
+ if (revRequestEnable.equalsIgnoreCase("true")) {
+ if (revRequestIssuer.length() == 0 || revRequestSerial.length() == 0 ||
+ revRequestReason.length() == 0) {
+ System.out.println("Illegal parameters for revRequest control");
+ printUsage();
+ System.exit(1);
+ }
+
+ bpid = addRevRequestAttr(bpid, controlSeq, otherMsgSeq, revCertNickname,
+ revRequestIssuer, revRequestSerial, revRequestReason, revRequestSharedSecret,
+ revRequestComment, revRequestInvalidityDatePresent, cm);
+ }
+
+ ContentInfo cmcblob = getCMCBlob(signerCert, nickname, requests, format,
+ cm, transactionMgtEnable, transactionMgtId, identityProofEnable,
+ identityProofSharedSecret, controlSeq, otherMsgSeq, bpid);
+
+ // (6) Finally, print the actual CMC blob to the
+ // specified output file
+ FileOutputStream os = null;
+ try {
+ os = new FileOutputStream(ofilename);
+ cmcblob.encode(os);
+ System.out.println("");
+ System.out.println("");
+ System.out.println("The CMC enrollment request in binary format is stored in " +
+ ofilename + ".");
+ } catch (IOException e) {
+ System.out.println("CMCRequest: unable to open file " + ofilename +
+ " for writing:\n" + e);
+ }
+
+ try {
+ os.close();
+ } catch (IOException e) {
+ System.out.println("CMCRequest: Unexpected error " +
+ "encountered while attempting to close() " +
+ "\n" + e);
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/CMCResponse.java b/base/java-tools/src/com/netscape/cmstools/CMCResponse.java
new file mode 100644
index 000000000..4d68dd151
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/CMCResponse.java
@@ -0,0 +1,234 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+import netscape.security.util.CertPrettyPrint;
+import netscape.security.x509.X509CertImpl;
+
+import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.INTEGER;
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.SET;
+import org.mozilla.jss.pkix.cert.Certificate;
+import org.mozilla.jss.pkix.cmc.CMCStatusInfo;
+import org.mozilla.jss.pkix.cmc.OtherInfo;
+import org.mozilla.jss.pkix.cmc.PendInfo;
+import org.mozilla.jss.pkix.cmc.ResponseBody;
+import org.mozilla.jss.pkix.cmc.TaggedAttribute;
+import org.mozilla.jss.pkix.cms.EncapsulatedContentInfo;
+
+/**
+ * Tool for parsing a CMC response
+ *
+ * <P>
+ *
+ * @version $Revision$, $Date$
+ *
+ */
+public class CMCResponse {
+
+ public CMCResponse() {
+ }
+
+ public static void printOutput(String path, String filename) {
+ byte[] bb = new byte[10000];
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(filename);
+ while (fis.available() > 0)
+ fis.read(bb, 0, 10000);
+ } catch (Exception e) {
+ System.out.println("Error reading the response. Exception: " + e.toString());
+ System.exit(1);
+ }
+
+ try {
+ ByteArrayInputStream bis = new ByteArrayInputStream(bb);
+ org.mozilla.jss.pkix.cms.ContentInfo cii = (org.mozilla.jss.pkix.cms.ContentInfo)
+ org.mozilla.jss.pkix.cms.ContentInfo.getTemplate().decode(bis);
+
+ org.mozilla.jss.pkix.cms.SignedData cmcFullResp =
+ (org.mozilla.jss.pkix.cms.SignedData) cii.getInterpretedContent();
+
+ String content = "";
+ if (cmcFullResp.hasCertificates()) {
+ SET certs = cmcFullResp.getCertificates();
+ int numCerts = certs.size();
+
+ for (int i = 0; i < numCerts; i++) {
+ Certificate cert = (Certificate) certs.elementAt(i);
+ X509CertImpl certImpl = new X509CertImpl(ASN1Util.encode(cert));
+ CertPrettyPrint print = new CertPrettyPrint(certImpl);
+ content += print.toString(Locale.getDefault());
+ }
+ }
+
+ System.out.println("Certificates: ");
+ System.out.println(content);
+ System.out.println("");
+ EncapsulatedContentInfo ci = cmcFullResp.getContentInfo();
+ OBJECT_IDENTIFIER id = ci.getContentType();
+ OBJECT_IDENTIFIER dataid = new OBJECT_IDENTIFIER("1.2.840.113549.1.7.1");
+ if (!id.equals(OBJECT_IDENTIFIER.id_cct_PKIResponse) && !id.equals(dataid)) {
+ System.out.println("Invalid CMC Response Format");
+ }
+
+ if (!ci.hasContent())
+ return;
+
+ OCTET_STRING content1 = ci.getContent();
+ ByteArrayInputStream bbis = new ByteArrayInputStream(content1.toByteArray());
+ ResponseBody responseBody = (ResponseBody) (new ResponseBody.Template()).decode(bbis);
+ SEQUENCE controlSequence = responseBody.getControlSequence();
+
+ int numControls = controlSequence.size();
+ System.out.println("Number of controls is " + numControls);
+
+ for (int i = 0; i < numControls; i++) {
+ TaggedAttribute taggedAttr = (TaggedAttribute) controlSequence.elementAt(i);
+ OBJECT_IDENTIFIER type = taggedAttr.getType();
+
+ if (type.equals(OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo)) {
+ System.out.println("Control #" + i + ": CMCStatusInfo");
+ System.out.println(" OID: " + type.toString());
+ SET sts = taggedAttr.getValues();
+ int numSts = sts.size();
+ for (int j = 0; j < numSts; j++) {
+ CMCStatusInfo cst = (CMCStatusInfo) ASN1Util.decode(CMCStatusInfo.getTemplate(),
+ ASN1Util.encode(sts.elementAt(j)));
+ SEQUENCE seq = cst.getBodyList();
+
+ String s = " BodyList: ";
+ for (int k = 0; k < seq.size(); k++) {
+ INTEGER n = (INTEGER) seq.elementAt(k);
+ s = s + n.toString() + " ";
+ }
+ System.out.println(s);
+ int st = cst.getStatus();
+ if (st != CMCStatusInfo.SUCCESS && st != CMCStatusInfo.CONFIRM_REQUIRED) {
+ String stString = cst.getStatusString();
+ if (stString != null)
+ System.out.println(" Status String: " + stString);
+ OtherInfo oi = cst.getOtherInfo();
+ OtherInfo.Type t = oi.getType();
+ if (t == OtherInfo.FAIL)
+ System.out.println(" OtherInfo type: FAIL");
+ else if (t == OtherInfo.PEND) {
+ System.out.println(" OtherInfo type: PEND");
+ PendInfo pi = oi.getPendInfo();
+ if (pi.getPendTime() != null) {
+ String datePattern = "dd/MMM/yyyy:HH:mm:ss z";
+ SimpleDateFormat dateFormat = new SimpleDateFormat(datePattern);
+ Date d = pi.getPendTime().toDate();
+ System.out.println(" Date: " + dateFormat.format(d));
+ }
+ }
+ } else if (st == CMCStatusInfo.SUCCESS) {
+ System.out.println(" Status: SUCCESS");
+ }
+ }
+ } else if (type.equals(OBJECT_IDENTIFIER.id_cmc_transactionId)) {
+ System.out.println("Control #" + i + ": CMC Transaction Id");
+ System.out.println(" OID: " + type.toString());
+ SET transIds = taggedAttr.getValues();
+ INTEGER num = (INTEGER) (ASN1Util.decode(INTEGER.getTemplate(),
+ ASN1Util.encode(transIds.elementAt(0))));
+ System.out.println(" INTEGER: " + num);
+ } else if (type.equals(OBJECT_IDENTIFIER.id_cmc_recipientNonce)) {
+ System.out.println("Control #" + i + ": CMC Recipient Nonce");
+ System.out.println(" OID: " + type.toString());
+ SET recipientN = taggedAttr.getValues();
+ OCTET_STRING str =
+ (OCTET_STRING) (ASN1Util.decode(OCTET_STRING.getTemplate(),
+ ASN1Util.encode(recipientN.elementAt(0))));
+ byte b[] = str.toByteArray();
+ String s = " Value: ";
+ for (int m = 0; m < b.length; m++) {
+ s = s + b[m] + " ";
+ }
+ System.out.println(s);
+ } else if (type.equals(OBJECT_IDENTIFIER.id_cmc_senderNonce)) {
+ System.out.println("Control #" + i + ": CMC Sender Nonce");
+ System.out.println(" OID: " + type.toString());
+ SET senderN = taggedAttr.getValues();
+ OCTET_STRING str =
+ (OCTET_STRING) (ASN1Util.decode(OCTET_STRING.getTemplate(),
+ ASN1Util.encode(senderN.elementAt(0))));
+ byte b[] = str.toByteArray();
+ String s = " Value: ";
+ for (int m = 0; m < b.length; m++) {
+ s = s + b[m] + " ";
+ }
+ System.out.println(s);
+ } else if (type.equals(OBJECT_IDENTIFIER.id_cmc_dataReturn)) {
+ System.out.println("Control #" + i + ": CMC Data Return");
+ System.out.println(" OID: " + type.toString());
+ SET dataReturn = taggedAttr.getValues();
+ OCTET_STRING str =
+ (OCTET_STRING) (ASN1Util.decode(OCTET_STRING.getTemplate(),
+ ASN1Util.encode(dataReturn.elementAt(0))));
+ byte b[] = str.toByteArray();
+ String s = " Value: ";
+ for (int m = 0; m < b.length; m++) {
+ s = s + b[m] + " ";
+ }
+ System.out.println(s);
+ }
+ }
+ } catch (Exception e) {
+ System.out.println("Error found in the response. Exception: " + e.toString());
+ System.exit(1);
+
+ }
+ }
+
+ private static void printUsage() {
+ System.out.println("");
+ System.out.println(
+ "Usage: CMCResponse -d <pathname for cert8.db> -i <pathname for CMC response in binary format> ");
+ }
+
+ public static void main(String args[]) {
+ String filename = null, path = null;
+ if (args.length != 4) {
+ printUsage();
+ System.exit(1);
+ }
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("-d"))
+ path = args[i + 1];
+ else if (args[i].equals("-i"))
+ filename = args[i + 1];
+ }
+
+ if (filename == null || path == null) {
+ printUsage();
+ System.exit(1);
+ }
+ printOutput(path, filename);
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/CMCRevoke.java b/base/java-tools/src/com/netscape/cmstools/CMCRevoke.java
new file mode 100644
index 000000000..f29984713
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/CMCRevoke.java
@@ -0,0 +1,426 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Date;
+
+import netscape.security.x509.X500Name;
+import netscape.security.x509.X509CertImpl;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.NoSuchTokenException;
+import org.mozilla.jss.asn1.ANY;
+import org.mozilla.jss.asn1.ENUMERATED;
+import org.mozilla.jss.asn1.INTEGER;
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.SET;
+import org.mozilla.jss.asn1.UTF8String;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.DigestAlgorithm;
+import org.mozilla.jss.crypto.ObjectNotFoundException;
+import org.mozilla.jss.crypto.SignatureAlgorithm;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.pkix.cmc.PKIData;
+import org.mozilla.jss.pkix.cmc.TaggedAttribute;
+import org.mozilla.jss.pkix.cms.ContentInfo;
+import org.mozilla.jss.pkix.cms.EncapsulatedContentInfo;
+import org.mozilla.jss.pkix.cms.IssuerAndSerialNumber;
+import org.mozilla.jss.pkix.cms.SignedData;
+import org.mozilla.jss.pkix.cms.SignerIdentifier;
+import org.mozilla.jss.pkix.cms.SignerInfo;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+import org.mozilla.jss.pkix.primitive.Name;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * Tool for signing a CMC revocation request with an agent's certificate.
+ *
+ * <P>
+ *
+ * @version $Revision$, $Date$
+ */
+public class CMCRevoke {
+ public static final int ARGC = 7;
+ private static final String CERTDB = "cert8.db";
+ private static final String KEYDB = "key3.db";
+ public static final String HEADER = "-----BEGIN NEW CERTIFICATE REQUEST-----";
+ public static final String TRAILER = "-----END NEW CERTIFICATE REQUEST-----";
+ static String dValue = null, nValue = null, iValue = null, sValue = null, mValue = null, hValue = null,
+ cValue = null;
+
+ public static final String CMS_BASE_CA_SIGNINGCERT_NOT_FOUND = "CA signing certificate not found";
+ public static final String PR_INTERNAL_TOKEN_NAME = "internal";
+ public static final String PR_REQUEST_CMC = "CMC";
+
+ static String cleanArgs(String s) {
+ if (s.startsWith("\"") && s.endsWith("\""))
+ return s.substring(1, s.length() - 2);
+ else if (s.startsWith("\'") && s.endsWith("\'"))
+ return new String(s.substring(1, s.length() - 2));
+ else
+ return s;
+ }
+
+ /**
+ * Creates a new instance of CMCRevoke.
+ */
+ public static void main(String[] s) {
+
+ // default path is "."
+ String mPath = ".";
+ // default prefix is ""
+ String mPrefix = "";
+
+ boolean bWrongParam = false;
+
+ // (1) Check that two arguments were submitted to the program
+ if (s.length != (ARGC) && s.length != (ARGC - 1)) {
+
+ bWrongParam = true;
+ System.out.println("Wrong number of parameters:" + s.length);
+ System.out.println("Usage: CMCRevoke " +
+ "-d<dir to cert8.db, key3.db> " +
+ "-n<nickname> " +
+ "-i<issuerName> " +
+ "-s<serialName> " +
+ "-m<reason to revoke> " +
+ "-h<password to db> " +
+ "-c<comment> ");
+ for (int i = 0; i < s.length; i++) {
+ System.out.println(i + ":" + s[i]);
+ }
+ } else {
+ int length;
+ int i;
+
+ length = s.length;
+ for (i = 0; i < length; i++) {
+ if (s[i].startsWith("-d")) {
+ dValue = cleanArgs(s[i].substring(2));
+ } else if (s[i].startsWith("-n")) {
+ nValue = cleanArgs(s[i].substring(2));
+ } else if (s[i].startsWith("-i")) {
+ iValue = cleanArgs(s[i].substring(2));
+ } else if (s[i].startsWith("-s")) {
+ sValue = cleanArgs(s[i].substring(2));
+ } else if (s[i].startsWith("-m")) {
+ mValue = cleanArgs(s[i].substring(2));
+ } else if (s[i].startsWith("-h")) {
+ hValue = cleanArgs(s[i].substring(2));
+ } else if (s[i].startsWith("-c")) {
+ cValue = cleanArgs(s[i].substring(2));
+ }
+
+ }
+ // optional parameter
+ if (cValue == null)
+ cValue = new String();
+ if (dValue == null
+ || nValue == null || iValue == null || sValue == null || mValue == null || hValue == null)
+ bWrongParam = true;
+ else if (dValue.length() == 0 || nValue.length() == 0 || iValue.length() == 0 ||
+ sValue.length() == 0 || mValue.length() == 0 || hValue.length() == 0)
+ bWrongParam = true;
+
+ if (bWrongParam == true) {
+ System.out.println("Usage: CMCRevoke " +
+ "-d<dir to cert8.db, key3.db> " +
+ "-n<nickname> " +
+ "-i<issuerName> " +
+ "-s<serialName> " +
+ "-m<reason to revoke> " +
+ "-h<password to db> " +
+ "-c<comment> ");
+ for (i = 0; i < s.length; i++) {
+ System.out.println(i + ":" + s[i]);
+ }
+ System.exit(0);
+ }
+
+ try {
+ // initialize CryptoManager
+ mPath = dValue;
+ System.out.println("cert/key prefix = " + mPrefix);
+ System.out.println("path = " + mPath);
+ CryptoManager.InitializationValues vals =
+ new CryptoManager.InitializationValues(mPath, mPrefix, mPrefix, "secmod.db");
+
+ CryptoManager.initialize(vals);
+
+ CryptoManager cm = CryptoManager.getInstance();
+ CryptoToken token = cm.getInternalKeyStorageToken();
+ Password pass = new Password(hValue.toCharArray());
+
+ token.login(pass);
+ X509Certificate signerCert = null;
+
+ signerCert = cm.findCertByNickname(nValue);
+ String outBlob = createRevokeReq(signerCert, cm, nValue);
+
+ printCMCRevokeRequest(outBlob);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ return;
+ }
+ }
+
+ /**
+ * printout CMC revoke request in Base64 encoding to a file CMCRevoke.out
+ * <P>
+ *
+ * @param asciiBASE64Blob the ascii string of the request
+ */
+ static void printCMCRevokeRequest(String asciiBASE64Blob) {
+
+ // (6) Finally, print the actual CMCSigning blob to the
+ // specified output file
+ FileOutputStream outputBlob = null;
+
+ try {
+ outputBlob = new FileOutputStream("CMCRevoke.out");
+ } catch (IOException e) {
+ System.out.println("CMCSigning: unable to open file CMCRevoke.out for writing:\n" + e);
+ return;
+ }
+
+ System.out.println(HEADER);
+ System.out.println(asciiBASE64Blob + TRAILER);
+ try {
+ asciiBASE64Blob = HEADER + "\n" + asciiBASE64Blob + TRAILER;
+ outputBlob.write(asciiBASE64Blob.getBytes());
+ } catch (IOException e) {
+ System.out.println("CMCSigning: I/O error " +
+ "encountered during write():\n" +
+ e);
+ }
+
+ try {
+ outputBlob.close();
+ } catch (IOException e) {
+ System.out.println("CMCSigning: Unexpected error " +
+ "encountered while attempting to close() " +
+ "\n" + e);
+ }
+ }
+
+ /**
+ * getCertificate find the certicate inside the token by its nickname.
+ * <P>
+ *
+ * @param manager the CrytoManager
+ * @param tokenname the name of the token. it's set to "internal".
+ * @param nickname the nickname of the certificate inside the token.
+ * @return the X509Certificate.
+ */
+ public static X509Certificate getCertificate(CryptoManager manager, String tokenname,
+ String nickname) throws NoSuchTokenException,
+ Exception, TokenException {
+ CryptoToken token = null;
+
+ if (tokenname.equals(PR_INTERNAL_TOKEN_NAME)) {
+ token = manager.getInternalKeyStorageToken();
+ } else {
+ token = manager.getTokenByName(tokenname);
+ }
+ StringBuffer certname = new StringBuffer();
+
+ if (!token.equals(manager.getInternalKeyStorageToken())) {
+ certname.append(tokenname);
+ certname.append(":");
+ }
+ certname.append(nickname);
+ try {
+ return manager.findCertByNickname(certname.toString());
+ } catch (ObjectNotFoundException e) {
+ throw new Exception(CMS_BASE_CA_SIGNINGCERT_NOT_FOUND);
+ }
+ }
+
+ /**
+ * createRevokeReq create and return the revocation request.
+ * <P>
+ *
+ * @param signerCert the certificate of the authorized signer of the CMC revocation request.
+ * @param manager the crypto manger.
+ * @param nValue the nickname of the certificate inside the token.
+ * @return the CMC revocation request encoded in base64
+ */
+ static String createRevokeReq(X509Certificate signerCert, CryptoManager manager, String nValue) {
+
+ java.security.PrivateKey privKey = null;
+ SignerIdentifier si = null;
+ ContentInfo fullEnrollmentReq = null;
+ String tokenname = "internal";
+ String asciiBASE64Blob = new String();
+
+ try {
+
+ BigInteger serialno = signerCert.getSerialNumber();
+ byte[] certB = signerCert.getEncoded();
+ X509CertImpl impl = new X509CertImpl(certB);
+ X500Name issuerName = (X500Name) impl.getIssuerDN();
+ byte[] issuerByte = issuerName.getEncoded();
+ ByteArrayInputStream istream = new ByteArrayInputStream(issuerByte);
+
+ Name issuer = (Name) Name.getTemplate().decode(istream);
+ IssuerAndSerialNumber ias = new IssuerAndSerialNumber(issuer, new INTEGER(serialno.toString()));
+
+ si = new SignerIdentifier(SignerIdentifier.ISSUER_AND_SERIALNUMBER, ias, null);
+ X509Certificate cert = getCertificate(manager, tokenname, nValue);
+
+ privKey = manager.findPrivKeyByCert(cert);
+
+ if (privKey == null) {
+ System.out.println("CMCRevoke::createRevokeReq() - " +
+ "privKey is null!");
+ return "";
+ }
+
+ int bpid = 1;
+ // Add some control sequence
+ // Verisign has transactionID,senderNonce
+ SEQUENCE controlSeq = new SEQUENCE();
+
+ Date date = new Date();
+ String salt = "lala123" + date.toString();
+ byte[] dig;
+
+ try {
+ MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1");
+
+ dig = SHA1Digest.digest(salt.getBytes());
+ } catch (NoSuchAlgorithmException ex) {
+ dig = salt.getBytes();
+ }
+ String sn = Utils.base64encode(dig);
+
+ TaggedAttribute senderNonce =
+ new TaggedAttribute(new INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_senderNonce,
+ new OCTET_STRING(sn.getBytes()));
+
+ controlSeq.addElement(senderNonce);
+
+ Name subjectName = new Name();
+
+ subjectName.addCommonName(iValue);
+ org.mozilla.jss.pkix.cmmf.RevRequest lRevokeRequest =
+ new org.mozilla.jss.pkix.cmmf.RevRequest(new ANY((new X500Name(iValue)).getEncoded()),
+ new INTEGER(sValue),
+ //org.mozilla.jss.pkix.cmmf.RevRequest.unspecified,
+ new ENUMERATED((new Integer(mValue)).longValue()),
+ //new GeneralizedTime(new Date(lValue)),
+ new OCTET_STRING(hValue.getBytes()),
+ new UTF8String(cValue.toCharArray()));
+ //byte[] encoded = ASN1Util.encode(lRevokeRequest);
+ //org.mozilla.jss.asn1.ASN1Template template = new org.mozilla.jss.pkix.cmmf.RevRequest.Template();
+ //org.mozilla.jss.pkix.cmmf.RevRequest revRequest = (org.mozilla.jss.pkix.cmmf.RevRequest)
+ // template.decode(new java.io.ByteArrayInputStream(
+ // encoded));
+
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ //lRevokeRequest.encode(os); // khai
+ TaggedAttribute revokeRequestTag =
+ new TaggedAttribute(new INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_revokeRequest,
+ lRevokeRequest);
+
+ controlSeq.addElement(revokeRequestTag);
+ PKIData pkidata = new PKIData(controlSeq, new SEQUENCE(), new SEQUENCE(), new SEQUENCE());
+
+ EncapsulatedContentInfo ci = new EncapsulatedContentInfo(OBJECT_IDENTIFIER.id_cct_PKIData, pkidata);
+ // SHA1 is the default digest Alg for now.
+ DigestAlgorithm digestAlg = null;
+ SignatureAlgorithm signAlg = SignatureAlgorithm.RSASignatureWithSHA1Digest;
+ org.mozilla.jss.crypto.PrivateKey.Type signingKeyType =
+ ((org.mozilla.jss.crypto.PrivateKey) privKey).getType();
+
+ if (signingKeyType.equals(org.mozilla.jss.crypto.PrivateKey.Type.DSA))
+ signAlg = SignatureAlgorithm.DSASignatureWithSHA1Digest;
+ MessageDigest SHADigest = null;
+ byte[] digest = null;
+
+ try {
+ SHADigest = MessageDigest.getInstance("SHA1");
+ digestAlg = DigestAlgorithm.SHA1;
+
+ ByteArrayOutputStream ostream = new ByteArrayOutputStream();
+
+ pkidata.encode((OutputStream) ostream);
+ digest = SHADigest.digest(ostream.toByteArray());
+ } catch (NoSuchAlgorithmException e) {
+ }
+ SignerInfo signInfo = new SignerInfo(si, null, null, OBJECT_IDENTIFIER.id_cct_PKIData, digest, signAlg,
+ (org.mozilla.jss.crypto.PrivateKey) privKey);
+ SET signInfos = new SET();
+
+ signInfos.addElement(signInfo);
+
+ SET digestAlgs = new SET();
+
+ if (digestAlg != null) {
+ AlgorithmIdentifier ai = new AlgorithmIdentifier(digestAlg.toOID(), null);
+
+ digestAlgs.addElement(ai);
+ }
+
+ org.mozilla.jss.crypto.X509Certificate[] agentChain = manager.buildCertificateChain(signerCert);
+ SET certs = new SET();
+
+ for (int i = 0; i < agentChain.length; i++) {
+ ANY certificate = new ANY(agentChain[i].getEncoded());
+
+ certs.addElement(certificate);
+ }
+ SignedData req = new SignedData(digestAlgs, ci, certs, null, signInfos);
+
+ fullEnrollmentReq = new ContentInfo(req);
+
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(bs);
+
+ if (fullEnrollmentReq != null) {
+ // format is PR_REQUEST_CMC
+ fullEnrollmentReq.encode(os);
+ ps.print(Utils.base64encode(os.toByteArray()));
+ ////fullEnrollmentReq.print(ps); // no header/trailer
+ }
+
+ asciiBASE64Blob = bs.toString();
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ return asciiBASE64Blob;
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
new file mode 100644
index 000000000..c1d463cdb
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
@@ -0,0 +1,620 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLEncoder;
+import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import netscape.security.x509.X500Name;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.BIT_STRING;
+import org.mozilla.jss.asn1.INTEGER;
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.PrintableString;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.KeyGenAlgorithm;
+import org.mozilla.jss.crypto.KeyGenerator;
+import org.mozilla.jss.crypto.KeyPairAlgorithm;
+import org.mozilla.jss.crypto.KeyPairGenerator;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapper;
+import org.mozilla.jss.crypto.Signature;
+import org.mozilla.jss.crypto.SignatureAlgorithm;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.pkix.crmf.CertReqMsg;
+import org.mozilla.jss.pkix.crmf.CertRequest;
+import org.mozilla.jss.pkix.crmf.CertTemplate;
+import org.mozilla.jss.pkix.crmf.EncryptedKey;
+import org.mozilla.jss.pkix.crmf.EncryptedValue;
+import org.mozilla.jss.pkix.crmf.PKIArchiveOptions;
+import org.mozilla.jss.pkix.crmf.POPOSigningKey;
+import org.mozilla.jss.pkix.crmf.ProofOfPossession;
+import org.mozilla.jss.pkix.primitive.AVA;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+import org.mozilla.jss.pkix.primitive.Name;
+import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.cmsutil.util.HMACDigest;
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * A command-line utility used to generate a Certificate Request Message
+ * Format (CRMF) request with proof of possesion (POP).
+ *
+ * Usage:
+ *
+ * <pre>
+ * CRMFPopClient TOKEN_PWD
+ * PROFILE_NAME HOST PORT USER_NAME REQUESTOR_NAME
+ * POP_OPTION
+ * SUBJECT_DN [OUTPUT_CERT_REQ]
+ *
+ * --- or ---
+ *
+ * CRMFPopClient TOKEN_PWD
+ * POP_OPTION
+ * OUTPUT_CERT_REQ SUBJECT_DN
+ *
+ *
+ * where POP_OPTION can be [POP_SUCCESS or POP_FAIL or POP_NONE]
+ * </pre>
+ * <p>
+ * Examples:
+ *
+ * <pre>
+ * CRMFPopClient password123
+ * caEncUserCert host.example.com 1026 MyUid MyUid
+ * [POP_SUCCESS or POP_FAIL or POP_NONE]
+ * CN=MyTest,C=US,UID=MyUid
+ *
+ * --- or ---
+ *
+ * CRMFPopClient password123
+ * caEncUserCert host.example.com 1026 joe joe
+ * [POP_SUCCESS or POP_FAIL or POP_NONE]
+ * CN=MyTest,C=US,UID=MyUid OUTPUT_CERT_REQ
+ *
+ * --- or ---
+ *
+ * CRMFPopClient password123
+ * [POP_SUCCESS or POP_FAIL or POP_NONE]
+ * OUTPUT_CERT_REQ CN=MyTest,C=US,UID=MyUid
+ * </pre>
+ * <p>
+ *
+ * <pre>
+ * IMPORTANT: The file "transport.txt" needs to be created to contain the
+ * transport certificate in its base64 encoded format. This
+ * file should consist of one line containing a single certificate
+ * in base64 encoded format with the header and footer removed.
+ * </pre>
+ * <p>
+ *
+ * @version $Revision$, $Date$
+ */
+public class CRMFPopClient {
+
+ private static void usage() {
+ System.out.println("");
+ System.out.println("Description: A command-line utility used to generate a");
+ System.out.println(" Certificate Request Message Format (CRMF)");
+ System.out.println(" request with proof of possesion (POP).\n\n");
+ System.out.println("Usage:");
+ System.out.println("");
+ System.out.println(" CRMFPopClient TOKEN_PWD");
+ System.out.println(" PROFILE_NAME HOST PORT USER_NAME REQUESTOR_NAME");
+ System.out.println(" POP_OPTION");
+ System.out.println(" SUBJECT_DN [OUTPUT_CERT_REQ] \n");
+ System.out.println(" --- or ---\n");
+ System.out.println(" CRMFPopClient TOKEN_PWD");
+ System.out.println(" POP_OPTION");
+ System.out.println(" OUTPUT_CERT_REQ SUBJECT_DN\n\n");
+ System.out.println(" where POP_OPTION can be [POP_SUCCESS or POP_FAIL or POP_NONE]\n\n");
+ System.out.println("Examples:");
+ System.out.println("");
+ System.out.println(" CRMFPopClient password123");
+ System.out.println(" caEncUserCert host.example.com 1026 MyUid MyUid");
+ System.out.println(" [POP_SUCCESS or POP_FAIL or POP_NONE]");
+ System.out.println(" CN=MyTest,C=US,UID=MyUid\n");
+ System.out.println(" --- or ---\n");
+ System.out.println(" CRMFPopClient password123");
+ System.out.println(" caEncUserCert host.example.com 1026 MyUid myUid");
+ System.out.println(" [POP_SUCCESS or POP_FAIL or POP_NONE]");
+ System.out.println(" CN=MyTest,C=US,UID=MyUid OUTPUT_CERT_REQ\n");
+ System.out.println(" --- or ---\n");
+ System.out.println(" CRMFPopClient password123");
+ System.out.println(" [POP_SUCCESS or POP_FAIL or POP_NONE]");
+ System.out.println(" OUTPUT_CERT_REQ CN=MyTest,C=US,UID=MyUid");
+ System.out.println("\n");
+ System.out.println("IMPORTANT: The file \"transport.txt\" needs to be created to contain the");
+ System.out.println(" transport certificate in its base64 encoded format. This");
+ System.out.println(" file should consist of one line containing a single certificate");
+ System.out.println(" in base64 encoded format with the header and footer removed.\n");
+ }
+
+ private static int getRealArgsLength(String args[]) {
+
+ int len = args.length;
+
+ String curArg = "";
+ int finalLen = len;
+
+ for (int i = 0; i < len; i++) {
+
+ curArg = args[i];
+ // System.out.println("arg[" + i + "] " + curArg);
+
+ if (curArg == null || curArg.equalsIgnoreCase("")) {
+ finalLen--;
+ }
+
+ }
+
+ //System.out.println("getRealArgsLength: returning " + finalLen);
+
+ if (finalLen < 0)
+ finalLen = 0;
+
+ return finalLen;
+
+ }
+
+ public static void main(String args[]) {
+
+ int argsLen = getRealArgsLength(args);
+
+ // System.out.println("args length " + argsLen);
+
+ System.out.println("\n\nProof Of Possession Utility....");
+ System.out.println("");
+
+ if (argsLen == 0 || (argsLen != 8 && argsLen != 9 && argsLen != 10 && argsLen != 4)) {
+ usage();
+ return;
+ }
+
+ String DB_DIR = "./";
+ String TOKEN_PWD = args[0];
+ int KEY_LEN = 1024;
+
+ int PORT = 0;
+ String USER_NAME = null;
+ String REQUESTOR_NAME = null;
+ String PROFILE_NAME = null;
+
+ String HOST = null;
+ String SUBJ_DN = null;
+
+ if (argsLen >= 8) {
+ PROFILE_NAME = args[1];
+ HOST = args[2];
+
+ PORT = Integer.parseInt(args[3]);
+
+ USER_NAME = args[4];
+ REQUESTOR_NAME = args[5];
+
+ SUBJ_DN = args[7];
+
+ }
+
+ String POP_OPTION = null;
+ String OUTPUT_CERT_REQ = null;
+
+ if (argsLen == 4)
+ POP_OPTION = args[1];
+ else
+ POP_OPTION = args[6];
+
+ int doServerHit = 1;
+
+ if (argsLen >= 9) {
+ OUTPUT_CERT_REQ = args[8];
+ }
+
+ if (argsLen == 4) {
+ doServerHit = 0;
+ OUTPUT_CERT_REQ = args[2];
+ SUBJ_DN = args[3];
+ }
+
+ int dont_do_pop = 0;
+
+ if (POP_OPTION.equals("POP_NONE")) {
+ dont_do_pop = 1;
+ }
+
+ URL url = null;
+ URLConnection conn = null;
+ InputStream is = null;
+ BufferedReader reader = null;
+ KeyPair pair = null;
+
+ boolean foundTransport = false;
+ String transportCert = null;
+ try {
+ BufferedReader br = new BufferedReader(new FileReader("./transport.txt"));
+ transportCert = br.readLine();
+ foundTransport = true;
+ } catch (Exception e) {
+ System.out.println("ERROR: cannot find ./transport.txt, so no key archival");
+
+ return;
+ }
+
+ try {
+ CryptoManager.initialize(DB_DIR);
+ } catch (Exception e) {
+ // it is ok if it is already initialized
+ System.out.println("INITIALIZATION ERROR: " + e.toString());
+ // return;
+ }
+
+ try {
+ CryptoManager manager = CryptoManager.getInstance();
+ String token_pwd = TOKEN_PWD;
+ CryptoToken token = manager.getInternalKeyStorageToken();
+ Password password = new Password(token_pwd.toCharArray());
+ try {
+ token.login(password);
+ } catch (Exception e) {
+ //System.out.println("login Exception: " + e.toString());
+ if (!token.isLoggedIn()) {
+ token.initPassword(password, password);
+ }
+ }
+
+ System.out.println("."); //"done with cryptomanager");
+
+ KeyPairGenerator kg = token.getKeyPairGenerator(
+ KeyPairAlgorithm.RSA);
+ kg.initialize(KEY_LEN);
+
+ String profileName = PROFILE_NAME;
+ pair = kg.genKeyPair();
+
+ System.out.println("."); //key pair generated");
+
+ // wrap private key
+ byte transport[] = Utils.base64decode(transportCert);
+
+ X509Certificate tcert = manager.importCACertPackage(transport);
+
+ byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+
+ KeyGenerator kg1 = token.getKeyGenerator(KeyGenAlgorithm.DES3);
+ SymmetricKey sk = kg1.generate();
+
+ System.out.println("."); //before KeyWrapper");
+
+ // wrap private key using session
+ KeyWrapper wrapper1 =
+ token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
+
+ System.out.println("."); //key wrapper created");
+
+ wrapper1.initWrap(sk, new IVParameterSpec(iv));
+
+ System.out.println("."); //key wrapper inited");
+ byte key_data[] = wrapper1.wrap((org.mozilla.jss.crypto.PrivateKey) pair.getPrivate());
+
+ System.out.println("."); //key wrapper wrapped");
+
+ // wrap session using transport
+ KeyWrapper rsaWrap = token.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+
+ System.out.println("."); //got rsaWrapper");
+
+ rsaWrap.initWrap(tcert.getPublicKey(), null);
+
+ System.out.println("."); //rsaWrap inited");
+
+ byte session_data[] = rsaWrap.wrap(sk);
+
+ System.out.println("."); //rsaWrapped");
+
+ try {
+ // create CRMF
+ CertTemplate certTemplate = new CertTemplate();
+ certTemplate.setVersion(new INTEGER(2));
+
+ Name n1 = getJssName(SUBJ_DN);
+
+ Name n = new Name();
+
+ n.addCommonName("Me");
+ n.addCountryName("US");
+ n.addElement(new AVA(new OBJECT_IDENTIFIER("0.9.2342.19200300.100.1.1"), new PrintableString("MyUid")));
+
+ if (n1 != null)
+ certTemplate.setSubject(n1);
+ else
+ certTemplate.setSubject(n);
+
+ certTemplate.setPublicKey(new SubjectPublicKeyInfo(pair.getPublic()));
+ // set extension
+ AlgorithmIdentifier algS =
+ new AlgorithmIdentifier(new OBJECT_IDENTIFIER("1.2.840.113549.3.7"), new OCTET_STRING(iv));
+ EncryptedValue encValue =
+ new EncryptedValue(null, algS, new BIT_STRING(session_data, 0), null, null, new BIT_STRING(
+ key_data, 0));
+ EncryptedKey key = new EncryptedKey(encValue);
+ PKIArchiveOptions opt = new PKIArchiveOptions(key);
+ SEQUENCE seq = new SEQUENCE();
+ if (foundTransport) {
+ seq.addElement(new AVA(new OBJECT_IDENTIFIER("1.3.6.1.5.5.7.5.1.4"), opt));
+ }
+
+ // Add idPOPLinkWitness control
+ String secretValue = "testing";
+ byte[] key1 = null;
+ byte[] finalDigest = null;
+ try {
+ MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1");
+ key1 = SHA1Digest.digest(secretValue.getBytes());
+ } catch (NoSuchAlgorithmException ex) {
+ }
+
+ /* Example of adding the POP link witness control to CRMF */
+ byte[] b =
+ { 0x10, 0x53, 0x42, 0x24, 0x1a, 0x2a, 0x35, 0x3c,
+ 0x7a, 0x52, 0x54, 0x56, 0x71, 0x65, 0x66, 0x4c,
+ 0x51, 0x34, 0x35, 0x23, 0x3c, 0x42, 0x43, 0x45,
+ 0x61, 0x4f, 0x6e, 0x43, 0x1e, 0x2a, 0x2b, 0x31,
+ 0x32, 0x34, 0x35, 0x36, 0x55, 0x51, 0x48, 0x14,
+ 0x16, 0x29, 0x41, 0x42, 0x43, 0x7b, 0x63, 0x44,
+ 0x6a, 0x12, 0x6b, 0x3c, 0x4c, 0x3f, 0x00, 0x14,
+ 0x51, 0x61, 0x15, 0x22, 0x23, 0x5f, 0x5e, 0x69 };
+
+ try {
+ MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1");
+ HMACDigest hmacDigest = new HMACDigest(SHA1Digest, key1);
+ hmacDigest.update(b);
+ finalDigest = hmacDigest.digest();
+ } catch (NoSuchAlgorithmException ex) {
+ }
+
+ OCTET_STRING ostr = new OCTET_STRING(finalDigest);
+ seq.addElement(new AVA(OBJECT_IDENTIFIER.id_cmc_idPOPLinkWitness, ostr));
+ CertRequest certReq = new CertRequest(new INTEGER(1), certTemplate, seq);
+
+ System.out.println("."); //CertRequest created");
+
+ ByteArrayOutputStream bo = new ByteArrayOutputStream();
+ certReq.encode(bo);
+ byte[] toBeVerified = bo.toByteArray();
+
+ byte signature[];
+
+ System.out.println("."); //CertRequest encoded");
+
+ Signature signer = token.getSignatureContext(
+ SignatureAlgorithm.RSASignatureWithMD5Digest);
+
+ System.out.println("."); //signer created");
+
+ signer.initSign((org.mozilla.jss.crypto.PrivateKey) pair.getPrivate());
+
+ System.out.println("."); //signer inited");
+
+ System.out.println("."); //FAIL_OR_SUCC " + FAIL_OR_SUCC);
+
+ if (POP_OPTION.equals("POP_SUCCESS")) {
+ System.out.println("Generating Legal POP Data.....");
+ signer.update(toBeVerified);
+ } else if (POP_OPTION.equals("POP_FAIL")) {
+ System.out.println("Generating Illegal POP Data.....");
+ signer.update(iv);
+ } else if (dont_do_pop == 1) {
+ System.out.println("Generating NO POP Data.....");
+ }
+
+ System.out.println("."); //signer updated");
+
+ CertReqMsg crmfMsg = null;
+
+ if (dont_do_pop == 0) {
+ signature = signer.sign();
+
+ System.out.println("Signature completed...");
+ System.out.println("");
+
+ AlgorithmIdentifier algID =
+ new AlgorithmIdentifier(SignatureAlgorithm.RSASignatureWithMD5Digest.toOID(), null);
+ POPOSigningKey popoKey = new POPOSigningKey(null, algID, new BIT_STRING(signature, 0));
+
+ ProofOfPossession pop = ProofOfPossession.createSignature(popoKey);
+
+ crmfMsg = new CertReqMsg(certReq, pop, null);
+
+ } else {
+ crmfMsg = new CertReqMsg(certReq, null, null);
+
+ }
+
+ //crmfMsg.verify();
+
+ SEQUENCE s1 = new SEQUENCE();
+ s1.addElement(crmfMsg);
+ byte encoded[] = ASN1Util.encode(s1);
+
+ String Req1 = Utils.base64encode(encoded);
+
+ if (OUTPUT_CERT_REQ != null) {
+ System.out.println("Generated Cert Request: ...... ");
+ System.out.println("");
+
+ System.out.println(Req1);
+ System.out.println("");
+ System.out.println("End Request:");
+
+ if (doServerHit == 0)
+ return;
+ }
+
+ String Req = URLEncoder.encode(Req1, "UTF-8");
+
+ // post PKCS10
+
+ url =
+ new URL("http://"
+ + HOST + ":" + PORT + "/ca/ee/ca/profileSubmit?cert_request_type=crmf&cert_request="
+ + Req + "&renewal=false&uid=" + USER_NAME + "&xmlOutput=false&&profileId="
+ + profileName + "&sn_uid=" + USER_NAME + "&SubId=profile&requestor_name="
+ + REQUESTOR_NAME);
+ //System.out.println("Posting " + url);
+
+ System.out.println("");
+ System.out.println("Server Response.....");
+ System.out.println("--------------------");
+ System.out.println("");
+
+ conn = url.openConnection();
+ is = conn.getInputStream();
+ reader = new BufferedReader(new InputStreamReader(is));
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ System.out.println(line);
+ if (line.equals("CMS Enroll Request Success")) {
+ System.out.println("Enrollment Successful: ......");
+ System.out.println("");
+ }
+ } /* while */
+
+ } catch (Exception e) {
+ System.out.println("WARNING: " + e.toString());
+ e.printStackTrace();
+ }
+ } catch (Exception e) {
+ System.out.println("ERROR: " + e.toString());
+ e.printStackTrace();
+ }
+ }
+
+ static Name getJssName(String dn) {
+
+ X500Name x5Name = null;
+
+ try {
+ x5Name = new X500Name(dn);
+
+ } catch (IOException e) {
+
+ System.out.println("Illegal Subject Name: " + dn + " Error: " + e.toString());
+ System.out.println("Filling in default Subject Name......");
+ return null;
+ }
+
+ Name ret = new Name();
+
+ netscape.security.x509.RDN[] names = null;
+
+ names = x5Name.getNames();
+
+ int nameLen = x5Name.getNamesLength();
+
+ // System.out.println("x5Name len: " + nameLen);
+
+ netscape.security.x509.RDN cur = null;
+
+ for (int i = 0; i < nameLen; i++) {
+ cur = names[i];
+
+ String rdnStr = cur.toString();
+
+ String[] split = rdnStr.split("=");
+
+ if (split.length != 2)
+ continue;
+
+ try {
+
+ if (split[0].equals("UID")) {
+
+ ret.addElement(new AVA(new OBJECT_IDENTIFIER("0.9.2342.19200300.100.1.1"), new PrintableString(
+ split[1])));
+ // System.out.println("UID found : " + split[1]);
+
+ }
+
+ if (split[0].equals("C")) {
+ ret.addCountryName(split[1]);
+ // System.out.println("C found : " + split[1]);
+ continue;
+
+ }
+
+ if (split[0].equals("CN")) {
+ ret.addCommonName(split[1]);
+ // System.out.println("CN found : " + split[1]);
+ continue;
+ }
+
+ if (split[0].equals("L")) {
+ ret.addLocalityName(split[1]);
+ // System.out.println("L found : " + split[1]);
+ continue;
+ }
+
+ if (split[0].equals("O")) {
+ ret.addOrganizationName(split[1]);
+ // System.out.println("O found : " + split[1]);
+ continue;
+ }
+
+ if (split[0].equals("ST")) {
+ ret.addStateOrProvinceName(split[1]);
+ // System.out.println("ST found : " + split[1]);
+ continue;
+ }
+
+ if (split[0].equals("OU")) {
+ ret.addOrganizationalUnitName(split[1]);
+ // System.out.println("OU found : " + split[1]);
+ continue;
+ }
+ } catch (Exception e) {
+ System.out.println("Error constructing RDN: " + rdnStr + " Error: " + e.toString());
+
+ continue;
+ }
+
+ }
+
+ return ret;
+
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/DRMTool.cfg b/base/java-tools/src/com/netscape/cmstools/DRMTool.cfg
new file mode 100644
index 000000000..b43441e19
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/DRMTool.cfg
@@ -0,0 +1,160 @@
+drmtool.ldif.caEnrollmentRequest._000=########################################
+drmtool.ldif.caEnrollmentRequest._001=## DRM CA Enrollment Request ##
+drmtool.ldif.caEnrollmentRequest._002=########################################
+drmtool.ldif.caEnrollmentRequest._003=## ##
+drmtool.ldif.caEnrollmentRequest._004=## NEVER allow 'DRMTOOL' the ability ##
+drmtool.ldif.caEnrollmentRequest._005=## to change the CA 'naming context' ##
+drmtool.ldif.caEnrollmentRequest._006=## data in the following fields: ##
+drmtool.ldif.caEnrollmentRequest._007=## ##
+drmtool.ldif.caEnrollmentRequest._008=## extdata-auth--005ftoken;uid ##
+drmtool.ldif.caEnrollmentRequest._009=## extdata-auth--005ftoken;userid ##
+drmtool.ldif.caEnrollmentRequest._010=## extdata-updatedby ##
+drmtool.ldif.caEnrollmentRequest._011=## ##
+drmtool.ldif.caEnrollmentRequest._012=## NEVER allow 'DRMTOOL' the ability ##
+drmtool.ldif.caEnrollmentRequest._013=## to change CA 'numeric' data in ##
+drmtool.ldif.caEnrollmentRequest._014=## the following fields: ##
+drmtool.ldif.caEnrollmentRequest._015=## ##
+drmtool.ldif.caEnrollmentRequest._016=## extdata-requestId ##
+drmtool.ldif.caEnrollmentRequest._017=## ##
+drmtool.ldif.caEnrollmentRequest._018=########################################
+drmtool.ldif.caEnrollmentRequest.cn=true
+drmtool.ldif.caEnrollmentRequest.dateOfModify=true
+drmtool.ldif.caEnrollmentRequest.dn=true
+drmtool.ldif.caEnrollmentRequest.extdata.keyRecord=true
+drmtool.ldif.caEnrollmentRequest.extdata.requestNotes=true
+drmtool.ldif.caEnrollmentRequest.requestId=true
+drmtool.ldif.caKeyRecord._000=#########################################
+drmtool.ldif.caKeyRecord._001=## DRM CA Key Record ##
+drmtool.ldif.caKeyRecord._002=#########################################
+drmtool.ldif.caKeyRecord._003=## ##
+drmtool.ldif.caKeyRecord._004=## NEVER allow 'DRMTOOL' the ability ##
+drmtool.ldif.caKeyRecord._005=## to change the CA 'naming context' ##
+drmtool.ldif.caKeyRecord._006=## data in the following fields: ##
+drmtool.ldif.caKeyRecord._007=## ##
+drmtool.ldif.caKeyRecord._008=## archivedBy ##
+drmtool.ldif.caKeyRecord._009=## ##
+drmtool.ldif.caKeyRecord._010=#########################################
+drmtool.ldif.caKeyRecord.cn=true
+drmtool.ldif.caKeyRecord.dateOfModify=true
+drmtool.ldif.caKeyRecord.dn=true
+drmtool.ldif.caKeyRecord.privateKeyData=true
+drmtool.ldif.caKeyRecord.serialno=true
+drmtool.ldif.namingContext._000=############################################
+drmtool.ldif.namingContext._001=## DRM Naming Context Fields ##
+drmtool.ldif.namingContext._002=############################################
+drmtool.ldif.namingContext._003=## ##
+drmtool.ldif.namingContext._004=## NEVER allow 'DRMTOOL' the ability to ##
+drmtool.ldif.namingContext._005=## change the CA 'naming context' data ##
+drmtool.ldif.namingContext._006=## in the following 'non-KeyRecord / ##
+drmtool.ldif.namingContext._007=## non-Request' fields (as these records ##
+drmtool.ldif.namingContext._008=## should be removed via the option to ##
+drmtool.ldif.namingContext._009=## process requests and key records only ##
+drmtool.ldif.namingContext._010=## if this is a DRM migration): ##
+drmtool.ldif.namingContext._011=## ##
+drmtool.ldif.namingContext._012=## cn ##
+drmtool.ldif.namingContext._013=## sn ##
+drmtool.ldif.namingContext._014=## uid ##
+drmtool.ldif.namingContext._015=## uniqueMember ##
+drmtool.ldif.namingContext._016=## ##
+drmtool.ldif.namingContext._017=## NEVER allow 'DRMTOOL' the ability to ##
+drmtool.ldif.namingContext._018=## change the DRM 'naming context' data ##
+drmtool.ldif.namingContext._019=## in the following 'non-KeyRecord / ##
+drmtool.ldif.namingContext._020=## non-Request' fields (as these records ##
+drmtool.ldif.namingContext._021=## should be removed via the option to ##
+drmtool.ldif.namingContext._022=## process requests and key records only ##
+drmtool.ldif.namingContext._023=## if this is a DRM migration): ##
+drmtool.ldif.namingContext._024=## ##
+drmtool.ldif.namingContext._025=## dc ##
+drmtool.ldif.namingContext._026=## dn ##
+drmtool.ldif.namingContext._027=## uniqueMember ##
+drmtool.ldif.namingContext._028=## ##
+drmtool.ldif.namingContext._029=## NEVER allow 'DRMTOOL' the ability to ##
+drmtool.ldif.namingContext._030=## change the TPS 'naming context' data ##
+drmtool.ldif.namingContext._031=## in the following 'non-KeyRecord / ##
+drmtool.ldif.namingContext._032=## non-Request' fields (as these records ##
+drmtool.ldif.namingContext._033=## should be removed via the option to ##
+drmtool.ldif.namingContext._034=## process requests and key records only ##
+drmtool.ldif.namingContext._035=## if this is a DRM migration): ##
+drmtool.ldif.namingContext._036=## ##
+drmtool.ldif.namingContext._037=## uid ##
+drmtool.ldif.namingContext._038=## uniqueMember ##
+drmtool.ldif.namingContext._039=## ##
+drmtool.ldif.namingContext._040=## If '-source_naming_context ##
+drmtool.ldif.namingContext._041=## <original source DRM naming context>' ##
+drmtool.ldif.namingContext._042=## and '-target_naming_context ##
+drmtool.ldif.namingContext._043=## <renamed target DRM naming context>' ##
+drmtool.ldif.namingContext._044=## options are specified, ALWAYS ##
+drmtool.ldif.namingContext._045=## require 'DRMTOOL' to change the ##
+drmtool.ldif.namingContext._046=## DRM 'naming context' data in ALL of ##
+drmtool.ldif.namingContext._047=## the following fields in EACH of the ##
+drmtool.ldif.namingContext._048=## following types of records: ##
+drmtool.ldif.namingContext._049=## ##
+drmtool.ldif.namingContext._050=## caEnrollmentRequest: ##
+drmtool.ldif.namingContext._051=## ##
+drmtool.ldif.namingContext._052=## dn ##
+drmtool.ldif.namingContext._053=## extdata-auth--005ftoken;user ##
+drmtool.ldif.namingContext._054=## extdata-auth--005ftoken;userdn ##
+drmtool.ldif.namingContext._055=## ##
+drmtool.ldif.namingContext._056=## caKeyRecord: ##
+drmtool.ldif.namingContext._057=## ##
+drmtool.ldif.namingContext._058=## dn ##
+drmtool.ldif.namingContext._059=## ##
+drmtool.ldif.namingContext._060=## recoveryRequest: ##
+drmtool.ldif.namingContext._061=## ##
+drmtool.ldif.namingContext._062=## dn ##
+drmtool.ldif.namingContext._063=## ##
+drmtool.ldif.namingContext._064=## tpsKeyRecord: ##
+drmtool.ldif.namingContext._065=## ##
+drmtool.ldif.namingContext._066=## dn ##
+drmtool.ldif.namingContext._067=## ##
+drmtool.ldif.namingContext._068=## tpsNetkeyKeygenRequest: ##
+drmtool.ldif.namingContext._069=## ##
+drmtool.ldif.namingContext._070=## dn ##
+drmtool.ldif.namingContext._071=## ##
+drmtool.ldif.namingContext._072=############################################
+drmtool.ldif.recoveryRequest._000=#####################################
+drmtool.ldif.recoveryRequest._001=## DRM CA / TPS Recovery Request ##
+drmtool.ldif.recoveryRequest._002=#####################################
+drmtool.ldif.recoveryRequest.cn=true
+drmtool.ldif.recoveryRequest.dateOfModify=true
+drmtool.ldif.recoveryRequest.dn=true
+drmtool.ldif.recoveryRequest.extdata.requestId=true
+drmtool.ldif.recoveryRequest.extdata.requestNotes=true
+drmtool.ldif.recoveryRequest.extdata.serialnumber=true
+drmtool.ldif.recoveryRequest.requestId=true
+drmtool.ldif.tpsKeyRecord._000=#########################################
+drmtool.ldif.tpsKeyRecord._001=## DRM TPS Key Record ##
+drmtool.ldif.tpsKeyRecord._002=#########################################
+drmtool.ldif.tpsKeyRecord._003=## ##
+drmtool.ldif.tpsKeyRecord._004=## NEVER allow 'DRMTOOL' the ability ##
+drmtool.ldif.tpsKeyRecord._005=## to change the TPS 'naming context' ##
+drmtool.ldif.tpsKeyRecord._006=## data in the following fields: ##
+drmtool.ldif.tpsKeyRecord._007=## ##
+drmtool.ldif.tpsKeyRecord._008=## archivedBy ##
+drmtool.ldif.tpsKeyRecord._009=## ##
+drmtool.ldif.tpsKeyRecord._010=#########################################
+drmtool.ldif.tpsKeyRecord.cn=true
+drmtool.ldif.tpsKeyRecord.dateOfModify=true
+drmtool.ldif.tpsKeyRecord.dn=true
+drmtool.ldif.tpsKeyRecord.privateKeyData=true
+drmtool.ldif.tpsKeyRecord.serialno=true
+drmtool.ldif.tpsNetkeyKeygenRequest._000=#####################################
+drmtool.ldif.tpsNetkeyKeygenRequest._001=## DRM TPS Netkey Keygen Request ##
+drmtool.ldif.tpsNetkeyKeygenRequest._002=#####################################
+drmtool.ldif.tpsNetkeyKeygenRequest._003=## ##
+drmtool.ldif.tpsNetkeyKeygenRequest._004=## NEVER allow 'DRMTOOL' the ##
+drmtool.ldif.tpsNetkeyKeygenRequest._005=## ability to change the ##
+drmtool.ldif.tpsNetkeyKeygenRequest._006=## TPS 'naming context' data in ##
+drmtool.ldif.tpsNetkeyKeygenRequest._007=## the following fields: ##
+drmtool.ldif.tpsNetkeyKeygenRequest._008=## ##
+drmtool.ldif.tpsNetkeyKeygenRequest._009=## extdata-updatedby ##
+drmtool.ldif.tpsNetkeyKeygenRequest._010=## ##
+drmtool.ldif.tpsNetkeyKeygenRequest._011=#####################################
+drmtool.ldif.tpsNetkeyKeygenRequest.cn=true
+drmtool.ldif.tpsNetkeyKeygenRequest.dateOfModify=true
+drmtool.ldif.tpsNetkeyKeygenRequest.dn=true
+drmtool.ldif.tpsNetkeyKeygenRequest.extdata.keyRecord=true
+drmtool.ldif.tpsNetkeyKeygenRequest.extdata.requestId=true
+drmtool.ldif.tpsNetkeyKeygenRequest.extdata.requestNotes=true
+drmtool.ldif.tpsNetkeyKeygenRequest.requestId=true
+
diff --git a/base/java-tools/src/com/netscape/cmstools/DRMTool.java b/base/java-tools/src/com/netscape/cmstools/DRMTool.java
new file mode 100644
index 000000000..e2fd2c538
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/DRMTool.java
@@ -0,0 +1,5120 @@
+// --- 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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.cert.CertificateException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.regex.PatternSyntaxException;
+
+import netscape.security.provider.RSAPublicKey;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.x509.X509CertImpl;
+
+import org.mozilla.jss.CertDatabaseException;
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.KeyDatabaseException;
+import org.mozilla.jss.crypto.AlreadyInitializedException;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.InvalidKeyFormatException;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapper;
+import org.mozilla.jss.crypto.ObjectNotFoundException;
+import org.mozilla.jss.crypto.PrivateKey;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.TokenCertificate;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.pkcs11.PK11PubKey;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * The DRMTool class is a utility program designed to operate on an LDIF file
+ * to perform one or more of the following tasks:
+ *
+ * <PRE>
+ * (A) Use a new storage key (e. g. - a 2048-bit key to replace a
+ * 1024-bit key) to rewrap the existing triple DES symmetric key
+ * that was used to wrap a user's private key.
+ *
+ * STARTING INVENTORY:
+ *
+ * (1) a DRMTOOL configuration file containing DRM LDIF record
+ * types and the processing status of their associated fields
+ *
+ * (2) an LDIF file containing 'exported' DRM data
+ * (referred to as the "source" DRM)
+ *
+ * NOTE: If this LDIF file contains data that was originally
+ * from a DRM instance that was prior to RHCS 8, it
+ * must have previously undergone the appropriate
+ * migration steps.
+ *
+ * (3) the NSS security databases (e. g. - cert8.db, key3.db,
+ * and secmod.db) associated with the data contained in
+ * the source LDIF file
+ *
+ * NOTE: If the storage key was located on an HSM, then the
+ * HSM must be available to the machine on which the
+ * DRMTool is being executed (since the RSA private
+ * storage key is required for unwrapping the
+ * symmetric triple DES key). Additionally, a
+ * password may be required to unlock access to
+ * this key (e. g. - which may be located in
+ * the source DRM's 'password.conf' file).
+ *
+ * (4) a file containing the ASCII BASE-64 storage certificate
+ * from the DRM instance for which the output LDIF file is
+ * intended (referred to as the "target")
+ *
+ * ENDING INVENTORY:
+ *
+ * (1) all items listed in the STARTING INVENTORY (unchanged)
+ *
+ * (2) a log file containing information suitable for audit
+ * purposes
+ *
+ * (3) an LDIF file containing the revised data suitable for
+ * 'import' into a new DRM (referred to as the "target" DRM)
+ *
+ * DRMTool PARAMETERS:
+ *
+ * (1) the name of the DRMTOOL configuration file containing
+ * DRM LDIF record types and the processing status of their
+ * associated fields
+ *
+ * (2) the name of the input LDIF file containing data which was
+ * 'exported' from the source DRM instance
+ *
+ * (3) the name of the output LDIF file intended to contain the
+ * revised data suitable for 'import' to a target DRM instance
+ *
+ * (4) the name of the log file that may be used for auditing
+ * purposes
+ *
+ * (5) the path to the security databases that were used by
+ * the source DRM instance
+ *
+ * (6) the name of the token that was used by
+ * the source DRM instance
+ *
+ * (7) the name of the storage certificate that was used by
+ * the source DRM instance
+ *
+ * (8) the name of the file containing the ASCII BASE-64 storage
+ * certificate from the target DRM instance for which the
+ * output LDIF file is intended
+ *
+ * (9) OPTIONALLY, the name of a file which ONLY contains the
+ * password needed to access the source DRM instance's
+ * security databases
+ *
+ * (10) OPTIONALLY, choose to change the specified source DRM naming
+ * context to the specified target DRM naming context
+ *
+ * (11) OPTIONALLY, choose to ONLY process CA enrollment requests,
+ * CA recovery requests, CA key records, TPS netkeyKeygen
+ * enrollment requests, TPS recovery requests, and
+ * TPS key records
+ *
+ * DATA FIELDS AFFECTED (using default config file values):
+ *
+ * (1) CA DRM enrollment request
+ *
+ * (a) dateOfModify
+ * (b) extdata-requestnotes
+ *
+ * (2) CA DRM key record
+ *
+ * (a) dateOfModify
+ * (b) privateKeyData
+ *
+ * (3) CA DRM recovery request
+ *
+ * (a) dateOfModify
+ * (b) extdata-requestnotes (NEW)
+ *
+ * (4) TPS DRM netkeyKeygen (enrollment) request
+ *
+ * (a) dateOfModify
+ * (b) extdata-requestnotes (NEW)
+ *
+ * (5) TPS DRM key record
+ *
+ * (a) dateOfModify
+ * (b) privateKeyData
+ *
+ * (6) TPS DRM recovery request
+ *
+ * (a) dateOfModify
+ * (b) extdata-requestnotes (NEW)
+ *
+ * (B) Specify an ID offset to append to existing numeric data
+ * (e. g. - to renumber data for use in DRM consolidation efforts).
+ *
+ * STARTING INVENTORY:
+ *
+ * (1) a DRMTOOL configuration file containing DRM LDIF record
+ * types and the processing status of their associated fields
+ *
+ * (2) an LDIF file containing 'exported' DRM data
+ * (referred to as the "source" DRM)
+ *
+ * NOTE: If this LDIF file contains data that was originally
+ * from a DRM instance that was prior to RHCS 8, it
+ * must have previously undergone the appropriate
+ * migration steps.
+ *
+ * ENDING INVENTORY:
+ *
+ * (1) all items listed in the STARTING INVENTORY (unchanged)
+ *
+ * (2) a log file containing information suitable for audit
+ * purposes
+ *
+ * (3) an LDIF file containing the revised data suitable for
+ * 'import' into a new DRM (referred to as the "target" DRM)
+ *
+ * DRMTool PARAMETERS:
+ *
+ * (1) the name of the DRMTOOL configuration file containing
+ * DRM LDIF record types and the processing status of their
+ * associated fields
+ *
+ * (2) the name of the input LDIF file containing data which was
+ * 'exported' from the source DRM instance
+ *
+ * (3) the name of the output LDIF file intended to contain the
+ * revised data suitable for 'import' to a target DRM instance
+ *
+ * (4) the name of the log file that may be used for auditing
+ * purposes
+ *
+ * (5) a large numeric ID offset (mask) to be appended to existing
+ * numeric data in the source DRM instance's LDIF file
+ *
+ * (6) OPTIONALLY, choose to change the specified source DRM naming
+ * context to the specified target DRM naming context
+ *
+ * (7) OPTIONALLY, choose to ONLY process CA enrollment requests,
+ * CA recovery requests, CA key records, TPS netkeyKeygen
+ * enrollment requests, TPS recovery requests, and
+ * TPS key records
+ *
+ * DATA FIELDS AFFECTED (using default config file values):
+ *
+ * (1) CA DRM enrollment request
+ *
+ * (a) cn
+ * (b) dateOfModify
+ * (c) extdata-keyrecord
+ * (d) extdata-requestnotes
+ * (e) requestId
+ *
+ * (2) CA DRM key record
+ *
+ * (a) cn
+ * (b) dateOfModify
+ * (c) serialno
+ *
+ * (3) CA DRM recovery request
+ *
+ * (a) cn
+ * (b) dateOfModify
+ * (c) extdata-requestid
+ * (d) extdata-requestnotes (NEW)
+ * (e) extdata-serialnumber
+ * (f) requestId
+ *
+ * (4) TPS DRM netkeyKeygen (enrollment) request
+ *
+ * (a) cn
+ * (b) dateOfModify
+ * (c) extdata-keyrecord
+ * (d) extdata-requestid
+ * (e) extdata-requestnotes (NEW)
+ * (f) requestId
+ *
+ * (5) TPS DRM key record
+ *
+ * (a) cn
+ * (b) dateOfModify
+ * (c) serialno
+ *
+ * (6) TPS DRM recovery request
+ *
+ * (a) cn
+ * (b) dateOfModify
+ * (c) extdata-requestid
+ * (d) extdata-requestnotes (NEW)
+ * (e) extdata-serialnumber
+ * (f) requestId
+ *
+ * (C) Specify an ID offset to be removed from existing numeric data
+ * (e. g. - to undo renumbering used in DRM consolidation efforts).
+ *
+ * STARTING INVENTORY:
+ *
+ * (1) a DRMTOOL configuration file containing DRM LDIF record
+ * types and the processing status of their associated fields
+ *
+ * (2) an LDIF file containing 'exported' DRM data
+ * (referred to as the "source" DRM)
+ *
+ * NOTE: If this LDIF file contains data that was originally
+ * from a DRM instance that was prior to RHCS 8, it
+ * must have previously undergone the appropriate
+ * migration steps.
+ *
+ * ENDING INVENTORY:
+ *
+ * (1) all items listed in the STARTING INVENTORY (unchanged)
+ *
+ * (2) a log file containing information suitable for audit
+ * purposes
+ *
+ * (3) an LDIF file containing the revised data suitable for
+ * 'import' into a new DRM (referred to as the "target" DRM)
+ *
+ * DRMTool PARAMETERS:
+ *
+ * (1) the name of the DRMTOOL configuration file containing
+ * DRM LDIF record types and the processing status of their
+ * associated fields
+ *
+ * (2) the name of the input LDIF file containing data which was
+ * 'exported' from the source DRM instance
+ *
+ * (3) the name of the output LDIF file intended to contain the
+ * revised data suitable for 'import' to a target DRM instance
+ *
+ * (4) the name of the log file that may be used for auditing
+ * purposes
+ *
+ * (5) a large numeric ID offset (mask) to be removed from existing
+ * numeric data in the source DRM instance's LDIF file
+ *
+ * (6) OPTIONALLY, choose to change the specified source DRM naming
+ * context to the specified target DRM naming context
+ *
+ * (7) OPTIONALLY, choose to ONLY process CA enrollment requests,
+ * CA recovery requests, CA key records, TPS netkeyKeygen
+ * enrollment requests, TPS recovery requests, and
+ * TPS key records
+ *
+ * DATA FIELDS AFFECTED (using default config file values):
+ *
+ * (1) CA DRM enrollment request
+ *
+ * (a) cn
+ * (b) dateOfModify
+ * (c) extdata-keyrecord
+ * (d) extdata-requestnotes
+ * (e) requestId
+ *
+ * (2) CA DRM key record
+ *
+ * (a) cn
+ * (b) dateOfModify
+ * (c) serialno
+ *
+ * (3) CA DRM recovery request
+ *
+ * (a) cn
+ * (b) dateOfModify
+ * (c) extdata-requestid
+ * (d) extdata-requestnotes (NEW)
+ * (e) extdata-serialnumber
+ * (f) requestId
+ *
+ * (4) TPS DRM netkeyKeygen (enrollment) request
+ *
+ * (a) cn
+ * (b) dateOfModify
+ * (c) extdata-keyrecord
+ * (d) extdata-requestid
+ * (e) extdata-requestnotes (NEW)
+ * (f) requestId
+ *
+ * (5) TPS DRM key record
+ *
+ * (a) cn
+ * (b) dateOfModify
+ * (c) serialno
+ *
+ * (6) TPS DRM recovery request
+ *
+ * (a) cn
+ * (b) dateOfModify
+ * (c) extdata-requestid
+ * (d) extdata-requestnotes (NEW)
+ * (e) extdata-serialnumber
+ * (f) requestId
+ *
+ * </PRE>
+ *
+ * <P>
+ * DRMTool may be invoked as follows:
+ *
+ * <PRE>
+ *
+ * DRMTool
+ * -drmtool_config_file &lt;path + drmtool config file&gt;
+ * -source_ldif_file &lt;path + source ldif file&gt;
+ * -target_ldif_file &lt;path + target ldif file&gt;
+ * -log_file &lt;path + log file&gt;
+ * [-source_pki_security_database_path &lt;path to PKI source database&gt;]
+ * [-source_storage_token_name '&lt;source token&gt;']
+ * [-source_storage_certificate_nickname '&lt;source nickname&gt;']
+ * [-target_storage_certificate_file &lt;path to target certificate file&gt;]
+ * [-source_pki_security_database_pwdfile &lt;path to PKI password file&gt;]
+ * [-append_id_offset &lt;numeric offset&gt;]
+ * [-remove_id_offset &lt;numeric offset&gt;]
+ * [-source_drm_naming_context '&lt;original source DRM naming context&gt;']
+ * [-target_drm_naming_context '&lt;renamed target DRM naming context&gt;']
+ * [-process_requests_and_key_records_only]
+ *
+ * where the following options are 'Mandatory':
+ *
+ * -drmtool_config_file &lt;path + drmtool config file&gt;
+ * -source_ldif_file &lt;path + source ldif file&gt;
+ * -target_ldif_file &lt;path + target ldif file&gt;
+ * -log_file &lt;path + log file&gt;
+ *
+ * AND at least ONE of the following are a 'Mandatory' set of options:
+ *
+ * (a) options for using a new storage key for rewrapping:
+ *
+ * [-source_pki_security_database_path
+ * &lt;path to PKI source database&gt;]
+ * [-source_storage_token_name '&lt;source token&gt;']
+ * [-source_storage_certificate_nickname '&lt;source nickname&gt;']
+ * [-target_storage_certificate_file
+ * &lt;path to target certificate file&gt;]
+ *
+ * AND OPTIONALLY, specify the name of a file which ONLY contains
+ * the password needed to access the source DRM instance's
+ * security databases:
+ *
+ * [-source_pki_security_database_pwdfile
+ * &lt;path to PKI password file&gt;]
+ *
+ * AND OPTIONALLY, rename source DRM naming context --> target
+ * DRM naming context:
+ *
+ * [-source_drm_naming_context '&lt;source DRM naming context&gt;']
+ * [-target_drm_naming_context '&lt;target DRM naming context&gt;']
+ *
+ * AND OPTIONALLY, process requests and key records ONLY:
+ *
+ * [-process_requests_and_key_records_only]
+ *
+ * (b) option for appending the specified numeric ID offset
+ * to existing numerical data:
+ *
+ * [-append_id_offset &lt;numeric offset&gt;]
+ *
+ * AND OPTIONALLY, rename source DRM naming context --> target
+ * DRM naming context:
+ *
+ * [-source_drm_naming_context '&lt;source DRM naming context&gt;']
+ * [-target_drm_naming_context '&lt;target DRM naming context&gt;']
+ *
+ * AND OPTIONALLY, process requests and key records ONLY:
+ *
+ * [-process_requests_and_key_records_only]
+ *
+ * (c) option for removing the specified numeric ID offset
+ * from existing numerical data:
+ *
+ * AND OPTIONALLY, rename source DRM naming context --> target
+ * DRM naming context:
+ *
+ * [-source_drm_naming_context '&lt;source DRM naming context&gt;']
+ * [-target_drm_naming_context '&lt;target DRM naming context&gt;']
+ *
+ * [-remove_id_offset &lt;numeric offset&gt;]
+ *
+ * AND OPTIONALLY, process requests and key records ONLY:
+ *
+ * [-process_requests_and_key_records_only]
+ *
+ * (d) (a) rewrap AND (b) append ID offset
+ * [AND OPTIONALLY, rename source DRM naming context --> target
+ * DRM naming context]
+ * [AND OPTIONALLY process requests and key records ONLY]
+ *
+ * (e) (a) rewrap AND (c) remove ID offset
+ * [AND OPTIONALLY, rename source DRM naming context --> target
+ * DRM naming context]
+ * [AND OPTIONALLY process requests and key records ONLY]
+ *
+ * NOTE: Options (b) and (c) are mutually exclusive!
+ *
+ * </PRE>
+ *
+ * @author mharmsen
+ * @version $Revision$, $Date$
+ */
+public class DRMTool {
+ /*************/
+ /* Constants */
+ /*************/
+
+ // Constants: Miscellaneous
+ private static final boolean FAILURE = false;
+ private static final boolean SUCCESS = true;
+ private static final String COLON = ":";
+ private static final String COMMA = ",";
+ private static final String DOT = ".";
+ private static final String EQUAL_SIGN = "=";
+ private static final String HASH = "#";
+ private static final String LEFT_BRACE = "[";
+ private static final String NEWLINE = "\n";
+ private static final String PLUS = "+";
+ private static final String RIGHT_BRACE = "]";
+ private static final String SPACE = " ";
+ private static final String TIC = "'";
+
+ // Constants: Calendar
+ private static final String DATE_OF_MODIFY_PATTERN = "yyyyMMddHHmmss'Z'";
+ private static final String LOGGING_DATE_PATTERN = "dd/MMM/yyyy:HH:mm:ss z";
+
+ // Constants: PKCS #11 Information
+ private static final String INTERNAL_TOKEN = "Internal Key Storage Token";
+
+ // Constants: Command-line Options
+ private static final int ID_OFFSET_NAME_VALUE_PAIRS = 1;
+ private static final int PWDFILE_NAME_VALUE_PAIRS = 1;
+ private static final int NAMING_CONTEXT_NAME_VALUE_PAIRS = 2;
+ private static final int MANDATORY_NAME_VALUE_PAIRS = 4;
+ private static final int REWRAP_NAME_VALUE_PAIRS = 4;
+ private static final int ID_OFFSET_ARGS = 10;
+ private static final int REWRAP_ARGS = 16;
+ private static final int REWRAP_AND_ID_OFFSET_ARGS = 18;
+
+ // Constants: Command-line Options (Mandatory)
+ private static final String DRM_TOOL = "DRMTool";
+
+ private static final String DRMTOOL_CFG_FILE = "-drmtool_config_file";
+
+ private static final String DRMTOOL_CFG_DESCRIPTION = " <complete path to the drmtool config file"
+ + NEWLINE
+ + " "
+ + " ending with the drmtool config file name>";
+
+ private static final String DRMTOOL_CFG_FILE_EXAMPLE = DRMTOOL_CFG_FILE
+ + " "
+ + "/usr/share/pki/java-tools/DRMTool.cfg";
+
+ private static final String SOURCE_LDIF_FILE = "-source_ldif_file";
+
+ private static final String SOURCE_LDIF_DESCRIPTION = " <complete path to the source LDIF input file"
+ + NEWLINE
+ + " "
+ + " ending with the source LDIF file name>";
+
+ private static final String SOURCE_LDIF_FILE_EXAMPLE = SOURCE_LDIF_FILE
+ + " "
+ + "/export/pki/source.ldif";
+
+ private static final String TARGET_LDIF_FILE = "-target_ldif_file";
+
+ private static final String TARGET_LDIF_DESCRIPTION = " <complete path to the target LDIF output file"
+ + NEWLINE
+ + " "
+ + " ending with the target LDIF file name>";
+
+ private static final String TARGET_LDIF_FILE_EXAMPLE = TARGET_LDIF_FILE
+ + " "
+ + "/export/pki/target.ldif";
+
+ private static final String LOG_FILE = "-log_file";
+
+ private static final String LOG_DESCRIPTION = " <complete path to the log file"
+ + NEWLINE
+ + " "
+ + " ending with the log file name>";
+
+ private static final String LOG_FILE_EXAMPLE = LOG_FILE
+ + " "
+ + "/export/pki/DRMTool.log";
+
+ // Constants: Command-line Options (Rewrap)
+ private static final String SOURCE_NSS_DB_PATH = "-source_pki_security_database_path";
+
+ private static final String SOURCE_NSS_DB_DESCRIPTION = " <complete path to the "
+ + "source security databases"
+ + NEWLINE
+ + " "
+ + " used by data in the source LDIF file>";
+
+ private static final String SOURCE_NSS_DB_PATH_EXAMPLE = SOURCE_NSS_DB_PATH
+ + " "
+ + "/export/pki";
+
+ private static final String SOURCE_STORAGE_TOKEN_NAME = "-source_storage_token_name";
+
+ private static final String SOURCE_STORAGE_TOKEN_DESCRIPTION = " <name of the token containing "
+ + "the source storage token>";
+
+ private static final String SOURCE_STORAGE_TOKEN_NAME_EXAMPLE = SOURCE_STORAGE_TOKEN_NAME
+ + " "
+ + TIC
+ + "Internal Key Storage Token"
+ + TIC;
+
+ private static final String SOURCE_STORAGE_CERT_NICKNAME = "-source_storage_certificate_nickname";
+
+ private static final String SOURCE_STORAGE_CERT_NICKNAME_DESCRIPTION = " <nickname of the source "
+ + "storage certificate>";
+
+ private static final String SOURCE_STORAGE_CERT_NICKNAME_EXAMPLE = SOURCE_STORAGE_CERT_NICKNAME
+ + " "
+ + TIC
+ + "storageCert cert-pki-kra"
+ + TIC;
+
+ private static final String TARGET_STORAGE_CERTIFICATE_FILE = "-target_storage_certificate_file";
+
+ private static final String TARGET_STORAGE_CERTIFICATE_DESCRIPTION = " <complete path to the target "
+ + "storage certificate file"
+ + NEWLINE
+ + " "
+ + " ending with the target "
+ + "storage certificate file name;"
+ + NEWLINE
+ + " "
+ + " the target storage "
+ + "certificate is stored in"
+ + NEWLINE
+ + " "
+ + " an ASCII format between a "
+ + "header and footer>";
+
+ private static final String TARGET_STORAGE_CERTIFICATE_FILE_EXAMPLE = TARGET_STORAGE_CERTIFICATE_FILE
+ + " "
+ + "/export/pki/target_storage.cert";
+
+ private static final String SOURCE_NSS_DB_PWDFILE = "-source_pki_security_database_pwdfile";
+
+ private static final String SOURCE_NSS_DB_PWDFILE_DESCRIPTION = " <complete path to the password "
+ + "file which ONLY contains the"
+ + NEWLINE
+ + " "
+ + " password used to access the "
+ + "source security databases>";
+
+ private static final String SOURCE_NSS_DB_PWDFILE_EXAMPLE = SOURCE_NSS_DB_PWDFILE
+ + " "
+ + "/export/pki/pwdfile";
+
+ // Constants: Command-line Options (ID Offset)
+ private static final String APPEND_ID_OFFSET = "-append_id_offset";
+
+ private static final String APPEND_ID_OFFSET_DESCRIPTION = " <ID offset that is appended to "
+ + "each record's source ID>";
+
+ private static final String APPEND_ID_OFFSET_EXAMPLE = APPEND_ID_OFFSET
+ + " "
+ + "100000000000";
+
+ private static final String REMOVE_ID_OFFSET = "-remove_id_offset";
+
+ private static final String REMOVE_ID_OFFSET_DESCRIPTION = " <ID offset that is removed from "
+ + "each record's source ID>";
+
+ private static final String REMOVE_ID_OFFSET_EXAMPLE = REMOVE_ID_OFFSET
+ + " "
+ + "100000000000";
+
+ // Constants: Command-line Options
+ private static final String SOURCE_DRM_NAMING_CONTEXT = "-source_drm_naming_context";
+
+ private static final String SOURCE_DRM_NAMING_CONTEXT_DESCRIPTION = " <source DRM naming context>";
+
+ private static final String SOURCE_DRM_NAMING_CONTEXT_EXAMPLE = SOURCE_DRM_NAMING_CONTEXT
+ + " "
+ + TIC
+ + "alpha.example.com-pki-kra"
+ + TIC;
+
+ private static final String TARGET_DRM_NAMING_CONTEXT = "-target_drm_naming_context";
+
+ private static final String TARGET_DRM_NAMING_CONTEXT_DESCRIPTION = " <target DRM naming context>";
+
+ private static final String TARGET_DRM_NAMING_CONTEXT_EXAMPLE = TARGET_DRM_NAMING_CONTEXT
+ + " "
+ + TIC
+ + "omega.example.com-pki-kra"
+ + TIC;
+
+ private static final String PROCESS_REQUESTS_AND_KEY_RECORDS_ONLY =
+ "-process_requests_and_key_records_only";
+
+ // Constants: DRMTOOL Config File
+ private static final String DRMTOOL_CFG_PREFIX = "drmtool.ldif";
+ private static final String DRMTOOL_CFG_ENROLLMENT = "caEnrollmentRequest";
+ private static final String DRMTOOL_CFG_CA_KEY_RECORD = "caKeyRecord";
+ private static final String DRMTOOL_CFG_RECOVERY = "recoveryRequest";
+ private static final String DRMTOOL_CFG_TPS_KEY_RECORD = "tpsKeyRecord";
+ private static final String DRMTOOL_CFG_KEYGEN = "tpsNetkeyKeygenRequest";
+
+ // Constants: DRMTOOL Config File (DRM CA Enrollment Request Fields)
+ private static final String DRMTOOL_CFG_ENROLLMENT_CN = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_ENROLLMENT
+ + DOT
+ + "cn";
+ private static final String DRMTOOL_CFG_ENROLLMENT_DATE_OF_MODIFY = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_ENROLLMENT
+ + DOT
+ + "dateOfModify";
+ private static final String DRMTOOL_CFG_ENROLLMENT_DN = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_ENROLLMENT
+ + DOT
+ + "dn";
+ private static final String DRMTOOL_CFG_ENROLLMENT_EXTDATA_KEY_RECORD = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_ENROLLMENT
+ + DOT
+ + "extdata.keyRecord";
+ private static final String DRMTOOL_CFG_ENROLLMENT_EXTDATA_REQUEST_NOTES = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_ENROLLMENT
+ + DOT
+ + "extdata.requestNotes";
+ private static final String DRMTOOL_CFG_ENROLLMENT_REQUEST_ID = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_ENROLLMENT
+ + DOT
+ + "requestId";
+
+ // Constants: DRMTOOL Config File (DRM CA Key Record Fields)
+ private static final String DRMTOOL_CFG_CA_KEY_RECORD_CN = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_CA_KEY_RECORD
+ + DOT
+ + "cn";
+ private static final String DRMTOOL_CFG_CA_KEY_RECORD_DATE_OF_MODIFY = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_CA_KEY_RECORD
+ + DOT
+ + "dateOfModify";
+ private static final String DRMTOOL_CFG_CA_KEY_RECORD_DN = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_ENROLLMENT
+ + DOT
+ + "dn";
+ private static final String DRMTOOL_CFG_CA_KEY_RECORD_PRIVATE_KEY_DATA = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_CA_KEY_RECORD
+ + DOT
+ + "privateKeyData";
+ private static final String DRMTOOL_CFG_CA_KEY_RECORD_SERIAL_NO = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_CA_KEY_RECORD
+ + DOT
+ + "serialno";
+
+ // Constants: DRMTOOL Config File (DRM CA / TPS Recovery Request Fields)
+ private static final String DRMTOOL_CFG_RECOVERY_CN = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_RECOVERY
+ + DOT
+ + "cn";
+ private static final String DRMTOOL_CFG_RECOVERY_DATE_OF_MODIFY = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_RECOVERY
+ + DOT
+ + "dateOfModify";
+ private static final String DRMTOOL_CFG_RECOVERY_DN = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_RECOVERY
+ + DOT
+ + "dn";
+ private static final String DRMTOOL_CFG_RECOVERY_EXTDATA_REQUEST_ID = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_RECOVERY
+ + DOT
+ + "extdata.requestId";
+ private static final String DRMTOOL_CFG_RECOVERY_EXTDATA_REQUEST_NOTES = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_RECOVERY
+ + DOT
+ + "extdata.requestNotes";
+ private static final String DRMTOOL_CFG_RECOVERY_EXTDATA_SERIAL_NUMBER = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_RECOVERY
+ + DOT
+ + "extdata.serialnumber";
+ private static final String DRMTOOL_CFG_RECOVERY_REQUEST_ID = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_RECOVERY
+ + DOT
+ + "requestId";
+
+ // Constants: DRMTOOL Config File (DRM TPS Key Record Fields)
+ private static final String DRMTOOL_CFG_TPS_KEY_RECORD_CN = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_TPS_KEY_RECORD
+ + DOT
+ + "cn";
+ private static final String DRMTOOL_CFG_TPS_KEY_RECORD_DATE_OF_MODIFY = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_TPS_KEY_RECORD
+ + DOT
+ + "dateOfModify";
+ private static final String DRMTOOL_CFG_TPS_KEY_RECORD_DN = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_TPS_KEY_RECORD
+ + DOT
+ + "dn";
+ private static final String DRMTOOL_CFG_TPS_KEY_RECORD_PRIVATE_KEY_DATA = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_TPS_KEY_RECORD
+ + DOT
+ + "privateKeyData";
+ private static final String DRMTOOL_CFG_TPS_KEY_RECORD_SERIAL_NO = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_TPS_KEY_RECORD
+ + DOT
+ + "serialno";
+
+ // Constants: DRMTOOL Config File (DRM TPS Netkey Keygen Request Fields)
+ private static final String DRMTOOL_CFG_KEYGEN_CN = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_KEYGEN
+ + DOT
+ + "cn";
+ private static final String DRMTOOL_CFG_KEYGEN_DATE_OF_MODIFY = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_KEYGEN
+ + DOT
+ + "dateOfModify";
+ private static final String DRMTOOL_CFG_KEYGEN_DN = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_KEYGEN
+ + DOT
+ + "dn";
+ private static final String DRMTOOL_CFG_KEYGEN_EXTDATA_KEY_RECORD = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_KEYGEN
+ + DOT
+ + "extdata.keyRecord";
+ private static final String DRMTOOL_CFG_KEYGEN_EXTDATA_REQUEST_ID = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_KEYGEN
+ + DOT
+ + "extdata.requestId";
+ private static final String DRMTOOL_CFG_KEYGEN_EXTDATA_REQUEST_NOTES = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_KEYGEN
+ + DOT
+ + "extdata.requestNotes";
+ private static final String DRMTOOL_CFG_KEYGEN_REQUEST_ID = DRMTOOL_CFG_PREFIX
+ + DOT
+ + DRMTOOL_CFG_KEYGEN
+ + DOT
+ + "requestId";
+
+ // Constants: Target Certificate Information
+ private static final String HEADER = "-----BEGIN";
+ private static final String TRAILER = "-----END";
+ private static final String X509_INFO = "x509.INFO";
+
+ // Constants: DRM LDIF Record Fields
+ private static final String DRM_LDIF_ARCHIVED_BY = "archivedBy:";
+ private static final String DRM_LDIF_CN = "cn:";
+ private static final String DRM_LDIF_DATE_OF_MODIFY = "dateOfModify:";
+ private static final String DRM_LDIF_DN = "dn:";
+ private static final String DRM_LDIF_DN_EMBEDDED_CN_DATA = "dn: cn";
+ private static final String DRM_LDIF_EXTDATA_AUTH_TOKEN_USER = "extdata-auth--005ftoken;user:";
+ private static final String DRM_LDIF_EXTDATA_AUTH_TOKEN_USER_DN = "extdata-auth--005ftoken;userdn:";
+ private static final String DRM_LDIF_EXTDATA_KEY_RECORD = "extdata-keyrecord:";
+ private static final String DRM_LDIF_EXTDATA_REQUEST_ID = "extdata-requestid:";
+ private static final String DRM_LDIF_EXTDATA_REQUEST_NOTES = "extdata-requestnotes:";
+ private static final String DRM_LDIF_EXTDATA_REQUEST_TYPE = "extdata-requesttype:";
+ private static final String DRM_LDIF_EXTDATA_SERIAL_NUMBER = "extdata-serialnumber:";
+ private static final String DRM_LDIF_PRIVATE_KEY_DATA = "privateKeyData::";
+ private static final String DRM_LDIF_REQUEST_ID = "requestId:";
+ private static final String DRM_LDIF_REQUEST_TYPE = "requestType:";
+ private static final String DRM_LDIF_SERIAL_NO = "serialno:";
+
+ // Constants: DRM LDIF Record Values
+ private static final int INITIAL_LDIF_RECORD_CAPACITY = 0;
+ private static final int EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH = 56;
+ private static final int PRIVATE_KEY_DATA_FIRST_LINE_DATA_LENGTH = 60;
+ private static final String DRM_LDIF_RECORD = "Generic";
+ private static final String DRM_LDIF_CA_KEY_RECORD = "CA";
+ private static final String DRM_LDIF_ENROLLMENT = "enrollment";
+ private static final String DRM_LDIF_KEYGEN = "netkeyKeygen";
+ private static final String DRM_LDIF_RECOVERY = "recovery";
+ private static final String DRM_LDIF_TPS_KEY_RECORD = "TPS";
+
+ // Constants: DRM LDIF Record Messages
+ private static final String DRM_LDIF_REWRAP_MESSAGE = "REWRAPPED the '"
+ + "existing DES3 "
+ + "symmetric "
+ + "session key"
+ + "' with the '";
+ private static final String DRM_LDIF_RSA_MESSAGE = "-bit RSA public key' "
+ + "obtained from the "
+ + "target storage "
+ + "certificate";
+ private static final String DRM_LDIF_USED_PWDFILE_MESSAGE =
+ "USED source PKI security database "
+ + "password file";
+ private static final String DRM_LDIF_APPENDED_ID_OFFSET_MESSAGE =
+ "APPENDED ID offset";
+ private static final String DRM_LDIF_REMOVED_ID_OFFSET_MESSAGE =
+ "REMOVED ID offset";
+ private static final String DRM_LDIF_SOURCE_NAME_CONTEXT_MESSAGE =
+ "RENAMED source DRM naming context '";
+ private static final String DRM_LDIF_TARGET_NAME_CONTEXT_MESSAGE =
+ "' to target DRM naming context '";
+ private static final String DRM_LDIF_PROCESS_REQUESTS_AND_KEY_RECORDS_ONLY_MESSAGE =
+ "PROCESSED requests and key records ONLY!";
+
+ /*************/
+ /* Variables */
+ /*************/
+
+ // Variables: Calendar
+ private static String mDateOfModify = null;
+
+ // Variables: Command-Line Options
+ private static boolean mMandatoryFlag = false;
+ private static boolean mRewrapFlag = false;
+ private static boolean mPwdfileFlag = false;
+ private static boolean mAppendIdOffsetFlag = false;
+ private static boolean mRemoveIdOffsetFlag = false;
+ private static boolean mDrmNamingContextsFlag = false;
+ private static boolean mProcessRequestsAndKeyRecordsOnlyFlag = false;
+ private static int mMandatoryNameValuePairs = 0;
+ private static int mRewrapNameValuePairs = 0;
+ private static int mPKISecurityDatabasePwdfileNameValuePairs = 0;
+ private static int mAppendIdOffsetNameValuePairs = 0;
+ private static int mRemoveIdOffsetNameValuePairs = 0;
+ private static int mDrmNamingContextNameValuePairs = 0;
+
+ // Variables: Command-Line Values (Mandatory)
+ private static String mDrmtoolCfgFilename = null;
+ private static String mSourceLdifFilename = null;
+ private static String mTargetLdifFilename = null;
+ private static String mLogFilename = null;
+
+ // Variables: Command-Line Values (Rewrap)
+ private static String mSourcePKISecurityDatabasePath = null;
+ private static String mSourceStorageTokenName = null;
+ private static String mSourceStorageCertNickname = null;
+ private static String mTargetStorageCertificateFilename = null;
+
+ // Variables: Command-Line Values (Rewrap Password File)
+ private static String mSourcePKISecurityDatabasePwdfile = null;
+
+ // Variables: Command-Line Values (ID Offset)
+ private static BigInteger mAppendIdOffset = null;
+ private static BigInteger mRemoveIdOffset = null;
+
+ // Variables: Command-Line Values (DRM Naming Contexts)
+ private static String mSourceDrmNamingContext = null;
+ private static String mTargetDrmNamingContext = null;
+
+ // Variables: DRMTOOL Config File Parameters of Interest
+ private static Hashtable<String, Boolean> drmtoolCfg = null;
+
+ // Variables: DRMTOOL LDIF File Parameters of Interest
+ private static Vector<String> record = null;
+ private static Iterator<String> ldif_record = null;
+
+ // Variables: Logging
+ private static boolean mDebug = false; // set 'true' for debug messages
+ private static PrintWriter logger = null;
+ private static String current_date_and_time = null;
+
+ // Variables: PKCS #11 Information
+ private static CryptoToken mSourceToken = null;
+ private static X509Certificate mUnwrapCert = null;
+ private static PrivateKey mUnwrapPrivateKey = null;
+ private static PublicKey mWrapPublicKey = null;
+ private static int mPublicKeySize = 0;
+
+ // Variables: DRM LDIF Record Messages
+ private static String mSourcePKISecurityDatabasePwdfileMessage = null;
+ private static String mDrmNamingContextMessage = null;
+ private static String mProcessRequestsAndKeyRecordsOnlyMessage = null;
+
+ /********************/
+ /* Calendar Methods */
+ /********************/
+
+ /**
+ * This method is used to get the current date and time.
+ * <P>
+ *
+ * @param pattern string containing desired format of date and time
+ * @return a formatted string containing the current date and time
+ */
+ private static String now(String pattern) {
+ Calendar cal = Calendar.getInstance();
+ SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+ return sdf.format(cal.getTime());
+ }
+
+ /*****************/
+ /* Usage Methods */
+ /*****************/
+
+ /**
+ * This method prints out the proper command-line usage required to
+ * execute DRMTool.
+ */
+ private static void printUsage() {
+ System.out.println("Usage: "
+ + DRM_TOOL
+ + NEWLINE
+ + " "
+ + DRMTOOL_CFG_FILE
+ + NEWLINE
+ + " "
+ + DRMTOOL_CFG_DESCRIPTION
+ + NEWLINE
+ + " "
+ + SOURCE_LDIF_FILE
+ + NEWLINE
+ + " "
+ + SOURCE_LDIF_DESCRIPTION
+ + NEWLINE
+ + " "
+ + TARGET_LDIF_FILE
+ + NEWLINE
+ + " "
+ + TARGET_LDIF_DESCRIPTION
+ + NEWLINE
+ + " "
+ + LOG_FILE
+ + NEWLINE
+ + " "
+ + LOG_DESCRIPTION
+ + NEWLINE
+ + " "
+ + "["
+ + SOURCE_NSS_DB_PATH
+ + NEWLINE
+ + " "
+ + SOURCE_NSS_DB_DESCRIPTION
+ + "]"
+ + NEWLINE
+ + " "
+ + "["
+ + SOURCE_STORAGE_TOKEN_NAME
+ + NEWLINE
+ + " "
+ + SOURCE_STORAGE_TOKEN_DESCRIPTION
+ + "]"
+ + NEWLINE
+ + " "
+ + "["
+ + SOURCE_STORAGE_CERT_NICKNAME
+ + NEWLINE
+ + " "
+ + SOURCE_STORAGE_CERT_NICKNAME_DESCRIPTION
+ + "]"
+ + NEWLINE
+ + " "
+ + "["
+ + TARGET_STORAGE_CERTIFICATE_FILE
+ + NEWLINE
+ + " "
+ + TARGET_STORAGE_CERTIFICATE_DESCRIPTION
+ + "]"
+ + NEWLINE
+ + " "
+ + "["
+ + SOURCE_NSS_DB_PWDFILE
+ + NEWLINE
+ + " "
+ + SOURCE_NSS_DB_PWDFILE_DESCRIPTION
+ + "]"
+ + NEWLINE
+ + " "
+ + "["
+ + APPEND_ID_OFFSET
+ + NEWLINE
+ + " "
+ + APPEND_ID_OFFSET_DESCRIPTION
+ + "]"
+ + NEWLINE
+ + " "
+ + "["
+ + REMOVE_ID_OFFSET
+ + NEWLINE
+ + " "
+ + REMOVE_ID_OFFSET_DESCRIPTION
+ + "]"
+ + NEWLINE
+ + " "
+ + "["
+ + SOURCE_DRM_NAMING_CONTEXT
+ + NEWLINE
+ + " "
+ + SOURCE_DRM_NAMING_CONTEXT_DESCRIPTION
+ + "]"
+ + NEWLINE
+ + " "
+ + "["
+ + TARGET_DRM_NAMING_CONTEXT
+ + NEWLINE
+ + " "
+ + TARGET_DRM_NAMING_CONTEXT_DESCRIPTION
+ + "]"
+ + NEWLINE
+ + " "
+ + "["
+ + PROCESS_REQUESTS_AND_KEY_RECORDS_ONLY
+ + "]"
+ + NEWLINE);
+
+ System.out.println("Example of 'Rewrap and Append ID Offset':"
+ + NEWLINE
+ + NEWLINE
+ + " "
+ + DRM_TOOL
+ + NEWLINE
+ + " "
+ + DRMTOOL_CFG_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_LDIF_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + TARGET_LDIF_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + LOG_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_NSS_DB_PATH_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_STORAGE_TOKEN_NAME_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_STORAGE_CERT_NICKNAME_EXAMPLE
+ + NEWLINE
+ + " "
+ + TARGET_STORAGE_CERTIFICATE_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_NSS_DB_PWDFILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + APPEND_ID_OFFSET_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_DRM_NAMING_CONTEXT_EXAMPLE
+ + NEWLINE
+ + " "
+ + TARGET_DRM_NAMING_CONTEXT_EXAMPLE
+ + NEWLINE
+ + " "
+ + PROCESS_REQUESTS_AND_KEY_RECORDS_ONLY
+ + NEWLINE);
+
+ System.out.println("Example of 'Rewrap and Remove ID Offset':"
+ + NEWLINE
+ + NEWLINE
+ + " "
+ + DRM_TOOL
+ + NEWLINE
+ + " "
+ + DRMTOOL_CFG_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_LDIF_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + TARGET_LDIF_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + LOG_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_NSS_DB_PATH_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_STORAGE_TOKEN_NAME_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_STORAGE_CERT_NICKNAME_EXAMPLE
+ + NEWLINE
+ + " "
+ + TARGET_STORAGE_CERTIFICATE_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_NSS_DB_PWDFILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + REMOVE_ID_OFFSET_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_DRM_NAMING_CONTEXT_EXAMPLE
+ + NEWLINE
+ + " "
+ + TARGET_DRM_NAMING_CONTEXT_EXAMPLE
+ + NEWLINE
+ + " "
+ + PROCESS_REQUESTS_AND_KEY_RECORDS_ONLY
+ + NEWLINE);
+
+ System.out.println("Example of 'Rewrap':"
+ + NEWLINE
+ + NEWLINE
+ + " "
+ + DRM_TOOL
+ + NEWLINE
+ + " "
+ + DRMTOOL_CFG_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_LDIF_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + TARGET_LDIF_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + LOG_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_NSS_DB_PATH_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_STORAGE_TOKEN_NAME_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_STORAGE_CERT_NICKNAME_EXAMPLE
+ + NEWLINE
+ + " "
+ + TARGET_STORAGE_CERTIFICATE_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_NSS_DB_PWDFILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_DRM_NAMING_CONTEXT_EXAMPLE
+ + NEWLINE
+ + " "
+ + TARGET_DRM_NAMING_CONTEXT_EXAMPLE
+ + NEWLINE
+ + " "
+ + PROCESS_REQUESTS_AND_KEY_RECORDS_ONLY
+ + NEWLINE);
+
+ System.out.println("Example of 'Append ID Offset':"
+ + NEWLINE
+ + NEWLINE
+ + " "
+ + DRM_TOOL
+ + NEWLINE
+ + " "
+ + DRMTOOL_CFG_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_LDIF_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + TARGET_LDIF_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + LOG_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + APPEND_ID_OFFSET_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_DRM_NAMING_CONTEXT_EXAMPLE
+ + NEWLINE
+ + " "
+ + TARGET_DRM_NAMING_CONTEXT_EXAMPLE
+ + NEWLINE
+ + " "
+ + PROCESS_REQUESTS_AND_KEY_RECORDS_ONLY
+ + NEWLINE);
+
+ System.out.println("Example of 'Remove ID Offset':"
+ + NEWLINE
+ + NEWLINE
+ + " "
+ + DRM_TOOL
+ + NEWLINE
+ + " "
+ + DRMTOOL_CFG_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_LDIF_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + TARGET_LDIF_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + LOG_FILE_EXAMPLE
+ + NEWLINE
+ + " "
+ + REMOVE_ID_OFFSET_EXAMPLE
+ + NEWLINE
+ + " "
+ + SOURCE_DRM_NAMING_CONTEXT_EXAMPLE
+ + NEWLINE
+ + " "
+ + TARGET_DRM_NAMING_CONTEXT_EXAMPLE
+ + NEWLINE
+ + " "
+ + PROCESS_REQUESTS_AND_KEY_RECORDS_ONLY
+ + NEWLINE);
+ }
+
+ /*******************/
+ /* Logging Methods */
+ /*******************/
+
+ /**
+ * This method opens a new log file for writing.
+ * <P>
+ *
+ * @param logfile string containing the name of the log file to be opened
+ */
+ private static void open_log(String logfile) {
+ try {
+ logger = new PrintWriter(
+ new BufferedWriter(
+ new FileWriter(logfile)));
+ } catch (IOException eFile) {
+ System.err.println("ERROR: Unable to open file '"
+ + logfile
+ + "' for writing: '"
+ + eFile.toString()
+ + "'"
+ + NEWLINE);
+ System.exit(0);
+ }
+ }
+
+ /**
+ * This method closes the specified log file.
+ * <P>
+ *
+ * @param logfile string containing the name of the log file to be closed
+ */
+ private static void close_log(String logfile) {
+ logger.close();
+ }
+
+ /**
+ * This method writes the specified message to the log file, and also
+ * to 'stderr' if the boolean flag is set to 'true'.
+ * <P>
+ *
+ * @param msg string containing the message to be written to the log file
+ * @param stderr boolean which also writes the message to 'stderr' if 'true'
+ */
+ private static void log(String msg, boolean stderr) {
+ current_date_and_time = now(LOGGING_DATE_PATTERN);
+ if (stderr) {
+ System.err.println(msg);
+ }
+ logger.write("["
+ + current_date_and_time
+ + "]: "
+ + msg);
+ logger.flush();
+ }
+
+ /*********************************************/
+ /* PKCS #11: Rewrap RSA Storage Key Methods */
+ /*********************************************/
+
+ /**
+ * Helper method to determine if two arrays contain the same values.
+ *
+ * This method is based upon code from 'com.netscape.kra.StorageKeyUnit'.
+ * <P>
+ *
+ * @param bytes first array of bytes
+ * @param ints second array of bytes
+ * @return true if the two arrays are identical
+ */
+ private static boolean arraysEqual(byte[] bytes, byte[] ints) {
+ if (bytes == null || ints == null) {
+ return false;
+ }
+
+ if (bytes.length != ints.length) {
+ return false;
+ }
+
+ for (int i = 0; i < bytes.length; i++) {
+ if (bytes[i] != ints[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * This method is used to obtain the private RSA storage key from
+ * the "source" DRM instance's security databases.
+ *
+ * This method is based upon code from 'com.netscape.kra.StorageKeyUnit'.
+ * <P>
+ *
+ * @return the private RSA storage key from the "source" DRM
+ */
+ private static PrivateKey getPrivateKey() {
+ try {
+ PrivateKey pk[] = mSourceToken.getCryptoStore().getPrivateKeys();
+
+ for (int i = 0; i < pk.length; i++) {
+ if (arraysEqual(pk[i].getUniqueID(),
+ ((TokenCertificate)
+ mUnwrapCert).getUniqueID())) {
+ return pk[i];
+ }
+ }
+ } catch (TokenException exToken) {
+ log("ERROR: Getting private key - "
+ + "TokenException: '"
+ + exToken.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+
+ return null;
+ }
+
+ /**
+ * This method gets the public key from the certificate stored
+ * in the "target" DRM storage certificate file. It also obtains
+ * the keysize of this RSA key.
+ *
+ * This method is based upon code from
+ * 'com.netscape.cmstools.PrettyPrintCert'.
+ * <P>
+ *
+ * @return the public RSA storage key from the "target" DRM
+ */
+ private static PublicKey getPublicKey() {
+ BufferedReader inputCert = null;
+ String encodedBASE64CertChunk = new String();
+ String encodedBASE64Cert = new String();
+ byte decodedBASE64Cert[] = null;
+ X509CertImpl cert = null;
+ PublicKey key = null;
+ RSAPublicKey rsakey = null;
+
+ // Create a DataInputStream() object to the BASE 64
+ // encoded certificate contained within the file
+ // specified on the command line
+ try {
+ inputCert = new BufferedReader(
+ new InputStreamReader(
+ new BufferedInputStream(
+ new FileInputStream(
+ mTargetStorageCertificateFilename
+ ))));
+ } catch (FileNotFoundException exWrapFileNotFound) {
+ log("ERROR: No target storage "
+ + "certificate file named '"
+ + mTargetStorageCertificateFilename
+ + "' exists! FileNotFoundException: '"
+ + exWrapFileNotFound.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+
+ // Read the entire contents of the specified BASE 64 encoded
+ // certificate into a String() object throwing away any
+ // headers beginning with HEADER and any trailers beginning
+ // with TRAILER
+ try {
+ while ((encodedBASE64CertChunk = inputCert.readLine()) != null) {
+ if (!(encodedBASE64CertChunk.startsWith(HEADER)) &&
+ !(encodedBASE64CertChunk.startsWith(TRAILER))) {
+ encodedBASE64Cert += encodedBASE64CertChunk.trim();
+ }
+ }
+ } catch (IOException exWrapReadLineIO) {
+ log("ERROR: Unexpected BASE64 "
+ + "encoded error encountered while reading '"
+ + mTargetStorageCertificateFilename
+ + "'! IOException: '"
+ + exWrapReadLineIO.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+
+ // Close the DataInputStream() object
+ try {
+ inputCert.close();
+ } catch (IOException exWrapCloseIO) {
+ log("ERROR: Unexpected BASE64 "
+ + "encoded error encountered in closing '"
+ + mTargetStorageCertificateFilename
+ + "'! IOException: '"
+ + exWrapCloseIO.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+
+ // Decode the ASCII BASE 64 certificate enclosed in the
+ // String() object into a BINARY BASE 64 byte[] object
+ decodedBASE64Cert = Utils.base64decode(
+ encodedBASE64Cert);
+
+ // Create an X509CertImpl() object from
+ // the BINARY BASE 64 byte[] object
+ try {
+ cert = new X509CertImpl(decodedBASE64Cert);
+ } catch (CertificateException exWrapCertificate) {
+ log("ERROR: Error encountered "
+ + "in parsing certificate in '"
+ + mTargetStorageCertificateFilename
+ + "' CertificateException: '"
+ + exWrapCertificate.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+
+ // Extract the Public Key
+ key = cert.getPublicKey();
+ if (key == null) {
+ log("ERROR: Unable to extract public key "
+ + "from certificate that was stored in '"
+ + mTargetStorageCertificateFilename
+ + "'."
+ + NEWLINE, true);
+ System.exit(0);
+ }
+
+ // Convert this X.509 public key --> RSA public key
+ try {
+ rsakey = new RSAPublicKey(key.getEncoded());
+ } catch (InvalidKeyException exInvalidKey) {
+ log("ERROR: Converting X.509 public key --> RSA public key - "
+ + "InvalidKeyException: '"
+ + exInvalidKey.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+
+ // Obtain the Public Key's keysize
+ mPublicKeySize = rsakey.getKeySize();
+
+ return key;
+ }
+
+ /**
+ * This method is used to obtain the private RSA storage key
+ * from the "source" DRM instance's security databases and
+ * the public RSA storage key from the certificate stored in
+ * the "target" DRM storage certificate file.
+ * <P>
+ *
+ * @return true if successfully able to obtain both keys
+ */
+ private static boolean obtain_RSA_rewrapping_keys() {
+ CryptoManager cm = null;
+
+ // Initialize the source security databases
+ try {
+ log("Initializing source PKI security databases in '"
+ + mSourcePKISecurityDatabasePath + "'."
+ + NEWLINE, true);
+
+ CryptoManager.initialize(mSourcePKISecurityDatabasePath);
+ } catch (KeyDatabaseException exKey) {
+ log("ERROR: source_pki_security_database_path='"
+ + mSourcePKISecurityDatabasePath
+ + "' KeyDatabaseException: '"
+ + exKey.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ } catch (CertDatabaseException exCert) {
+ log("ERROR: source_pki_security_database_path='"
+ + mSourcePKISecurityDatabasePath
+ + "' CertDatabaseException: '"
+ + exCert.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ } catch (AlreadyInitializedException exAlreadyInitialized) {
+ log("ERROR: source_pki_security_database_path='"
+ + mSourcePKISecurityDatabasePath
+ + "' AlreadyInitializedException: '"
+ + exAlreadyInitialized.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ } catch (GeneralSecurityException exSecurity) {
+ log("ERROR: source_pki_security_database_path='"
+ + mSourcePKISecurityDatabasePath
+ + "' GeneralSecurityException: '"
+ + exSecurity.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+
+ // Retrieve the source storage token by its name
+ try {
+ log("Retrieving token from CryptoManager."
+ + NEWLINE, true);
+ cm = CryptoManager.getInstance();
+
+ log("Retrieving source storage token called '"
+ + mSourceStorageTokenName
+ + "'."
+ + NEWLINE, true);
+
+ if (mSourceStorageTokenName.equals(INTERNAL_TOKEN)) {
+ mSourceToken = cm.getInternalKeyStorageToken();
+ } else {
+ mSourceToken = cm.getTokenByName(mSourceStorageTokenName);
+ }
+
+ if (mSourceToken == null) {
+ return FAILURE;
+ }
+
+ if (mPwdfileFlag) {
+ BufferedReader in = null;
+ String pwd = null;
+ Password mPwd = null;
+
+ try {
+ in = new BufferedReader(
+ new FileReader(
+ mSourcePKISecurityDatabasePwdfile));
+ pwd = in.readLine();
+
+ mPwd = new Password(pwd.toCharArray());
+
+ mSourceToken.login(mPwd);
+ } catch (Exception exReadPwd) {
+ log("ERROR: Failed to read the keydb password from "
+ + "the file '"
+ + mSourcePKISecurityDatabasePwdfile
+ + "'. Exception: '"
+ + exReadPwd.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+ }
+ } catch (Exception exUninitialized) {
+ log("ERROR: Uninitialized CryptoManager - '"
+ + exUninitialized.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+
+ // Retrieve the source storage cert by its nickname
+ try {
+ if (mSourceStorageTokenName.equals(INTERNAL_TOKEN)) {
+ log("Retrieving source storage cert with nickname of '"
+ + mSourceStorageCertNickname
+ + "'."
+ + NEWLINE, true);
+
+ mUnwrapCert = cm.findCertByNickname(mSourceStorageCertNickname
+ );
+ } else {
+ log("Retrieving source storage cert with nickname of '"
+ + mSourceStorageTokenName
+ + ":"
+ + mSourceStorageCertNickname
+ + "'. "
+ + NEWLINE, true);
+ mUnwrapCert = cm.findCertByNickname(mSourceStorageTokenName
+ + ":"
+ + mSourceStorageCertNickname
+ );
+ }
+
+ if (mUnwrapCert == null) {
+ return FAILURE;
+ }
+ } catch (ObjectNotFoundException exUnwrapObjectNotFound) {
+ if (mSourceStorageTokenName.equals(INTERNAL_TOKEN)) {
+ log("ERROR: No internal "
+ + "source storage cert named '"
+ + mSourceStorageCertNickname
+ + "' exists! ObjectNotFoundException: '"
+ + exUnwrapObjectNotFound.toString()
+ + "'"
+ + NEWLINE, true);
+ } else {
+ log("ERROR: No "
+ + "source storage cert named '"
+ + mSourceStorageTokenName
+ + ":"
+ + mSourceStorageCertNickname
+ + "' exists! ObjectNotFoundException: '"
+ + exUnwrapObjectNotFound
+ + "'"
+ + NEWLINE, true);
+ }
+ System.exit(0);
+ } catch (TokenException exUnwrapToken) {
+ if (mSourceStorageTokenName.equals(INTERNAL_TOKEN)) {
+ log("ERROR: No internal "
+ + "source storage cert named '"
+ + mSourceStorageCertNickname
+ + "' exists! TokenException: '"
+ + exUnwrapToken.toString()
+ + "'"
+ + NEWLINE, true);
+ } else {
+ log("ERROR: No "
+ + "source storage cert named '"
+ + mSourceStorageTokenName
+ + ":"
+ + mSourceStorageCertNickname
+ + "' exists! TokenException: '"
+ + exUnwrapToken
+ + "'"
+ + NEWLINE, true);
+ }
+ System.exit(0);
+ }
+
+ // Extract the private key from the source storage token
+ log("BEGIN: Obtaining the private key from "
+ + "the source storage token . . ."
+ + NEWLINE, true);
+
+ mUnwrapPrivateKey = getPrivateKey();
+
+ if (mUnwrapPrivateKey == null) {
+ log("ERROR: Failed extracting "
+ + "private key from the source storage token."
+ + NEWLINE, true);
+ System.exit(0);
+ }
+
+ log("FINISHED: Obtaining the private key from "
+ + "the source storage token."
+ + NEWLINE, true);
+
+ // Extract the public key from the target storage certificate
+ try {
+ log("BEGIN: Obtaining the public key from "
+ + "the target storage certificate . . ."
+ + NEWLINE, true);
+
+ mWrapPublicKey = (PublicKey)
+ (PK11PubKey.fromSPKI(
+ getPublicKey().getEncoded()));
+
+ if (mWrapPublicKey == null) {
+ log("ERROR: Failed extracting "
+ + "public key from target storage certificate stored in '"
+ + mTargetStorageCertificateFilename
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+
+ log("FINISHED: Obtaining the public key from "
+ + "the target storage certificate."
+ + NEWLINE, true);
+ } catch (InvalidKeyFormatException exInvalidPublicKey) {
+ log("ERROR: Failed extracting "
+ + "public key from target storage certificate stored in '"
+ + mTargetStorageCertificateFilename
+ + "' InvalidKeyFormatException '"
+ + exInvalidPublicKey.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+
+ return SUCCESS;
+ }
+
+ /**
+ * This method basically rewraps the "wrappedKeyData" by implementiing
+ * "mStorageUnit.decryptInternalPrivate( byte wrappedKeyData[] )" and
+ * "mStorageUnit.encryptInternalPrivate( byte priKey[] )", where
+ * "wrappedKeyData" uses the following structure:
+ *
+ * SEQUENCE {
+ * encryptedSession OCTET STRING,
+ * encryptedPrivate OCTET STRING
+ * }
+ *
+ * This method is based upon code from
+ * 'com.netscape.kra.EncryptionUnit'.
+ * <P>
+ *
+ * @return a byte[] containing the rewrappedKeyData
+ */
+ private static byte[] rewrap_wrapped_key_data(byte[] wrappedKeyData)
+ throws Exception {
+ DerValue val = null;
+ DerInputStream in = null;
+ DerValue dSession = null;
+ byte source_session[] = null;
+ DerValue dPri = null;
+ byte pri[] = null;
+ KeyWrapper source_rsaWrap = null;
+ SymmetricKey sk = null;
+ KeyWrapper target_rsaWrap = null;
+ byte target_session[] = null;
+ DerOutputStream tmp = null;
+ DerOutputStream out = null;
+ byte[] rewrappedKeyData = null;
+
+ // public byte[]
+ // mStorageUnit.decryptInternalPrivate( byte wrappedKeyData[] );
+ // throws EBaseException
+ try {
+ val = new DerValue(wrappedKeyData);
+ in = val.data;
+ dSession = in.getDerValue();
+ source_session = dSession.getOctetString();
+ dPri = in.getDerValue();
+ pri = dPri.getOctetString();
+ source_rsaWrap = mSourceToken.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+ source_rsaWrap.initUnwrap(mUnwrapPrivateKey, null);
+ sk = source_rsaWrap.unwrapSymmetric(source_session,
+ SymmetricKey.DES3,
+ SymmetricKey.Usage.DECRYPT,
+ 0);
+ if (mDebug) {
+ log("DEBUG: sk = '"
+ + Utils.base64encode(sk.getEncoded())
+ + "' length = '"
+ + sk.getEncoded().length
+ + "'"
+ + NEWLINE, false);
+ log("DEBUG: pri = '"
+ + Utils.base64encode(pri)
+ + "' length = '"
+ + pri.length
+ + "'"
+ + NEWLINE, false);
+ }
+ } catch (IOException exUnwrapIO) {
+ log("ERROR: Unwrapping key data - "
+ + "IOException: '"
+ + exUnwrapIO.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ } catch (NoSuchAlgorithmException exUnwrapAlgorithm) {
+ log("ERROR: Unwrapping key data - "
+ + "NoSuchAlgorithmException: '"
+ + exUnwrapAlgorithm.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ } catch (TokenException exUnwrapToken) {
+ log("ERROR: Unwrapping key data - "
+ + "TokenException: '"
+ + exUnwrapToken.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ } catch (InvalidKeyException exUnwrapInvalidKey) {
+ log("ERROR: Unwrapping key data - "
+ + "InvalidKeyException: '"
+ + exUnwrapInvalidKey.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ } catch (InvalidAlgorithmParameterException exUnwrapInvalidAlgorithm) {
+ log("ERROR: Unwrapping key data - "
+ + "InvalidAlgorithmParameterException: '"
+ + exUnwrapInvalidAlgorithm.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ } catch (IllegalStateException exUnwrapState) {
+ log("ERROR: Unwrapping key data - "
+ + "InvalidStateException: '"
+ + exUnwrapState.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+
+ // public byte[]
+ // mStorageUnit.encryptInternalPrivate( byte priKey[] )
+ // throws EBaseException
+ try {
+ // Use "mSourceToken" to get "KeyWrapAlgorithm.RSA"
+ target_rsaWrap = mSourceToken.getKeyWrapper(
+ KeyWrapAlgorithm.RSA);
+ target_rsaWrap.initWrap(mWrapPublicKey, null);
+ target_session = target_rsaWrap.wrap(sk);
+
+ tmp = new DerOutputStream();
+ out = new DerOutputStream();
+
+ tmp.putOctetString(target_session);
+ tmp.putOctetString(pri);
+ out.write(DerValue.tag_Sequence, tmp);
+
+ rewrappedKeyData = out.toByteArray();
+ } catch (NoSuchAlgorithmException exWrapAlgorithm) {
+ log("ERROR: Wrapping key data - "
+ + "NoSuchAlgorithmException: '"
+ + exWrapAlgorithm.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ } catch (TokenException exWrapToken) {
+ log("ERROR: Wrapping key data - "
+ + "TokenException: '"
+ + exWrapToken.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ } catch (InvalidKeyException exWrapInvalidKey) {
+ log("ERROR: Wrapping key data - "
+ + "InvalidKeyException: '"
+ + exWrapInvalidKey.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ } catch (InvalidAlgorithmParameterException exWrapInvalidAlgorithm) {
+ log("ERROR: Wrapping key data - "
+ + "InvalidAlgorithmParameterException: '"
+ + exWrapInvalidAlgorithm.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ } catch (IllegalStateException exWrapState) {
+ log("ERROR: Wrapping key data - "
+ + "InvalidStateException: '"
+ + exWrapState.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ } catch (IOException exWrapIO) {
+ log("ERROR: Wrapping key data - "
+ + "IOException: '"
+ + exWrapIO.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+
+ return rewrappedKeyData;
+ }
+
+ /**
+ * Helper method used to remove all EOLs ('\n' and '\r')
+ * from the passed in string.
+ * <P>
+ *
+ * @param data consisting of a string containing EOLs
+ * @return a string consisting of a string with no EOLs
+ */
+ private static String stripEOL(String data) {
+ StringBuffer buffer = new StringBuffer();
+ String revised_data = null;
+
+ for (int i = 0; i < data.length(); i++) {
+ if ((data.charAt(i) != '\n') &&
+ (data.charAt(i) != '\r')) {
+ buffer.append(data.charAt(i));
+ }
+ }
+
+ revised_data = buffer.toString();
+
+ return revised_data;
+ }
+
+ /**
+ * Helper method used to format a string containing unformatted data
+ * into a string containing formatted data suitable as an entry for
+ * an LDIF file.
+ * <P>
+ *
+ * @param length the length of the first line of data
+ * @param data a string containing unformatted data
+ * @return formatted data consisting of data formatted for an LDIF record
+ * suitable for an LDIF file
+ */
+ private static String format_ldif_data(int length, String data) {
+ String revised_data = "";
+
+ if (data.length() > length) {
+ // process first line
+ for (int i = 0; i < length; i++) {
+ revised_data += data.charAt(i);
+ }
+
+ // terminate first line
+ revised_data += '\n';
+
+ // process remaining lines
+ int j = 0;
+ for (int i = length; i < data.length(); i++) {
+ if (j == 0) {
+ revised_data += ' ';
+ }
+
+ revised_data += data.charAt(i);
+
+ j++;
+
+ if (j == 76) {
+ revised_data += '\n';
+ j = 0;
+ }
+ }
+ }
+
+ return revised_data.replaceAll("\\s+$", "");
+ }
+
+ /*********************/
+ /* ID Offset Methods */
+ /*********************/
+
+ /**
+ * Helper method which converts an "indexed" BigInteger into
+ * its String representation.
+ *
+ * <PRE>
+ *
+ * NOTE: Indexed data means that the numeric data
+ * is stored with a prepended length
+ * (e. g. - record '73' is stored as '0273').
+ *
+ * Indexed data is currently limited to '99' digits
+ * (an index of '00' is invalid). See
+ * 'com.netscape.cmscore.dbs.BigIntegerMapper.java'
+ * for details.
+ *
+ * </PRE>
+ *
+ * This method is based upon code from
+ * 'com.netscape.cmscore.dbs.BigIntegerMapper'.
+ * <P>
+ *
+ * @param i an "indexed " BigInteger
+ * @return the string representation of the "indexed" BigInteger
+ */
+ private static String BigIntegerToDB(BigInteger i) {
+ int len = i.toString().length();
+ String ret = null;
+
+ if (len < 10) {
+ ret = "0" + Integer.toString(len) + i.toString();
+ } else {
+ ret = Integer.toString(len) + i.toString();
+ }
+ return ret;
+ }
+
+ /**
+ * Helper method which converts the string representation of an
+ * "indexed" integer into a BigInteger.
+ *
+ * <PRE>
+ * NOTE: Indexed data means that the numeric data
+ * is stored with a prepended length
+ * (e. g. - record '73' is stored as '0273').
+ *
+ * Indexed data is currently limited to '99' digits
+ * (an index of '00' is invalid). See
+ * 'com.netscape.cmscore.dbs.BigIntegerMapper.java'
+ * for details.
+ * </PRE>
+ *
+ * This method is based upon code from
+ * 'com.netscape.cmscore.dbs.BigIntegerMapper'.
+ * <P>
+ *
+ * @param i the string representation of the "indexed" integer
+ * @return an "indexed " BigInteger
+ */
+ private static BigInteger BigIntegerFromDB(String i) {
+ String s = i.substring(2);
+
+ // possibly check length
+ return new BigInteger(s);
+ }
+
+ /**
+ * This method accepts an "attribute", its "delimiter", a string
+ * representation of numeric data, and a flag indicating whether
+ * or not the string representation is "indexed".
+ *
+ * An "attribute" consists of one of the following values:
+ *
+ * <PRE>
+ * DRM_LDIF_CN = "cn:";
+ * DRM_LDIF_DN_EMBEDDED_CN_DATA = "dn: cn";
+ * DRM_LDIF_EXTDATA_KEY_RECORD = "extdata-keyrecord:";
+ * DRM_LDIF_EXTDATA_REQUEST_ID = "extdata-requestid:";
+ * DRM_LDIF_EXTDATA_SERIAL_NUMBER = "extdata-serialnumber:";
+ * DRM_LDIF_REQUEST_ID = "requestId:";
+ * DRM_LDIF_SERIAL_NO = "serialno:";
+ *
+ *
+ * NOTE: Indexed data means that the numeric data
+ * is stored with a prepended length
+ * (e. g. - record '73' is stored as '0273').
+ *
+ * Indexed data is currently limited to '99' digits
+ * (an index of '00' is invalid). See
+ * 'com.netscape.cmscore.dbs.BigIntegerMapper.java'
+ * for details.
+ * </PRE>
+ *
+ * <P>
+ *
+ * @param attribute the string representation of the "name"
+ * @param delimiter the separator between the attribute and its contents
+ * @param source_line the string containing the "name" and "value"
+ * @param indexed boolean flag indicating if the "value" is "indexed"
+ * @return a revised line containing the "name" and "value" with the
+ * specified ID offset applied as a "mask" to the "value"
+ */
+ private static String compose_numeric_line(String attribute,
+ String delimiter,
+ String source_line,
+ boolean indexed) {
+ String target_line = null;
+ String data = null;
+ String revised_data = null;
+ BigInteger value = null;
+
+ // Since both "-append_id_offset" and "-remove_id_offset" are OPTIONAL
+ // parameters, first check to see if either has been selected
+ if (!mAppendIdOffsetFlag &&
+ !mRemoveIdOffsetFlag) {
+ return source_line;
+ }
+
+ try {
+ // extract the data
+ data = source_line.substring(attribute.length() + 1).trim();
+
+ // skip values which are non-numeric
+ if (!data.matches("[0-9]++")) {
+ // set the target_line to the unchanged source_line
+ target_line = source_line;
+
+ // log this information
+ log("Skipped changing non-numeric line '"
+ + source_line
+ + "'."
+ + NEWLINE, false);
+ } else {
+ // if indexed, first strip the index from the data
+ if (indexed) {
+ // NOTE: Indexed data means that the numeric data
+ // is stored with a prepended length
+ // (e. g. - record '73' is stored as '0273').
+ //
+ // Indexed data is currently limited to '99' digits
+ // (an index of '00' is invalid). See
+ // 'com.netscape.cmscore.dbs.BigIntegerMapper.java'
+ // for details.
+ value = BigIntegerFromDB(data);
+ } else {
+ value = new BigInteger(data);
+ }
+
+ // compare the specified target ID offset
+ // with the actual value of the attribute
+ if (mAppendIdOffsetFlag) {
+ if (mAppendIdOffset.compareTo(value) == 1) {
+ // add the target ID offset to this value
+ if (indexed) {
+ revised_data = BigIntegerToDB(
+ value.add(mAppendIdOffset)
+ ).toString();
+ } else {
+ revised_data = value.add(
+ mAppendIdOffset).toString();
+ }
+ } else {
+ log("ERROR: attribute='"
+ + attribute
+ + "' is greater than the specified "
+ + "append_id_offset='"
+ + mAppendIdOffset.toString()
+ + "'!"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+ } else if (mRemoveIdOffsetFlag) {
+ if (mRemoveIdOffset.compareTo(value) <= 0) {
+ // subtract the target ID offset to this value
+ if (indexed) {
+ revised_data = BigIntegerToDB(
+ value.subtract(mRemoveIdOffset)
+ ).toString();
+ } else {
+ revised_data = value.subtract(mRemoveIdOffset
+ ).toString();
+ }
+ } else {
+ log("ERROR: attribute='"
+ + attribute
+ + "' is less than the specified "
+ + "remove_id_offset='"
+ + mRemoveIdOffset.toString()
+ + "'!"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+ }
+
+ // set the target_line to the revised data
+ target_line = attribute + delimiter + revised_data;
+
+ // log this information
+ log("Changed numeric data '"
+ + data
+ + "' to '"
+ + revised_data
+ + "'."
+ + NEWLINE, false);
+ }
+ } catch (IndexOutOfBoundsException exBounds) {
+ log("ERROR: source_line='"
+ + source_line
+ + "' IndexOutOfBoundsException: '"
+ + exBounds.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ } catch (PatternSyntaxException exPattern) {
+ log("ERROR: data='"
+ + data
+ + "' PatternSyntaxException: '"
+ + exPattern.toString()
+ + "'"
+ + NEWLINE, true);
+ System.exit(0);
+ }
+
+ return target_line;
+ }
+
+ /***********************/
+ /* LDIF Parser Methods */
+ /***********************/
+
+ /**
+ * Helper method which composes the output line for DRM_LDIF_CN.
+ * <P>
+ *
+ * @param record_type the string representation of the input record type
+ * @param line the string representation of the input line
+ * @return the composed output line
+ */
+ private static String output_cn(String record_type,
+ String line) {
+ String output = null;
+
+ if (record_type.equals(DRM_LDIF_ENROLLMENT)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_ENROLLMENT_CN)) {
+ output = compose_numeric_line(DRM_LDIF_CN,
+ SPACE,
+ line,
+ false);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_CA_KEY_RECORD)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_CA_KEY_RECORD_CN)) {
+ output = compose_numeric_line(DRM_LDIF_CN,
+ SPACE,
+ line,
+ false);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_RECOVERY)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_RECOVERY_CN)) {
+ output = compose_numeric_line(DRM_LDIF_CN,
+ SPACE,
+ line,
+ false);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_TPS_KEY_RECORD)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_TPS_KEY_RECORD_CN)) {
+ output = compose_numeric_line(DRM_LDIF_CN,
+ SPACE,
+ line,
+ false);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_KEYGEN)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_KEYGEN_CN)) {
+ output = compose_numeric_line(DRM_LDIF_CN,
+ SPACE,
+ line,
+ false);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_RECORD)) {
+ // Non-Request / Non-Key Record:
+ // Pass through the original
+ // 'cn' line UNCHANGED
+ // so that it is ALWAYS written
+ output = line;
+ } else {
+ log("ERROR: Mismatched record field='"
+ + DRM_LDIF_CN
+ + "' for record type='"
+ + record_type
+ + "'!"
+ + NEWLINE, true);
+ }
+
+ return output;
+ }
+
+ /**
+ * Helper method which composes the output line for DRM_LDIF_DATE_OF_MODIFY.
+ * <P>
+ *
+ * @param record_type the string representation of the input record type
+ * @param line the string representation of the input line
+ * @return the composed output line
+ */
+ private static String output_date_of_modify(String record_type,
+ String line) {
+ String output = null;
+
+ if (record_type.equals(DRM_LDIF_ENROLLMENT)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_ENROLLMENT_DATE_OF_MODIFY)) {
+ output = DRM_LDIF_DATE_OF_MODIFY
+ + SPACE
+ + mDateOfModify;
+
+ log("Changed '"
+ + line
+ + "' to '"
+ + output
+ + "'."
+ + NEWLINE, false);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_CA_KEY_RECORD)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_CA_KEY_RECORD_DATE_OF_MODIFY)) {
+ output = DRM_LDIF_DATE_OF_MODIFY
+ + SPACE
+ + mDateOfModify;
+
+ log("Changed '"
+ + line
+ + "' to '"
+ + output
+ + "'."
+ + NEWLINE, false);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_RECOVERY)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_RECOVERY_DATE_OF_MODIFY)) {
+ output = DRM_LDIF_DATE_OF_MODIFY
+ + SPACE
+ + mDateOfModify;
+
+ log("Changed '"
+ + line
+ + "' to '"
+ + output
+ + "'."
+ + NEWLINE, false);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_TPS_KEY_RECORD)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_TPS_KEY_RECORD_DATE_OF_MODIFY)) {
+ output = DRM_LDIF_DATE_OF_MODIFY
+ + SPACE
+ + mDateOfModify;
+
+ log("Changed '"
+ + line
+ + "' to '"
+ + output
+ + "'."
+ + NEWLINE, false);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_KEYGEN)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_KEYGEN_DATE_OF_MODIFY)) {
+ output = DRM_LDIF_DATE_OF_MODIFY
+ + SPACE
+ + mDateOfModify;
+
+ log("Changed '"
+ + line
+ + "' to '"
+ + output
+ + "'."
+ + NEWLINE, false);
+ } else {
+ output = line;
+ }
+ } else {
+ log("ERROR: Mismatched record field='"
+ + DRM_LDIF_DATE_OF_MODIFY
+ + "' for record type='"
+ + record_type
+ + "'!"
+ + NEWLINE, true);
+ }
+
+ return output;
+ }
+
+ /**
+ * Helper method which composes the output line for DRM_LDIF_DN.
+ * <P>
+ *
+ * @param record_type the string representation of the input record type
+ * @param line the string representation of the input line
+ * @return the composed output line
+ */
+ private static String output_dn(String record_type,
+ String line) {
+ String embedded_cn_data[] = null;
+ String embedded_cn_output = null;
+ String input = null;
+ String output = null;
+
+ try {
+ if (record_type.equals(DRM_LDIF_ENROLLMENT)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_ENROLLMENT_DN)) {
+
+ // First check for an embedded "cn=<value>"
+ // name-value pair
+ if (line.startsWith(DRM_LDIF_DN_EMBEDDED_CN_DATA)) {
+ // At this point, always extract
+ // the embedded "cn=<value>" name-value pair
+ // which will ALWAYS be the first
+ // portion of the "dn: " attribute
+ embedded_cn_data = line.split(COMMA, 2);
+
+ embedded_cn_output = compose_numeric_line(
+ DRM_LDIF_DN_EMBEDDED_CN_DATA,
+ EQUAL_SIGN,
+ embedded_cn_data[0],
+ false);
+
+ input = embedded_cn_output
+ + COMMA
+ + embedded_cn_data[1];
+ } else {
+ input = line;
+ }
+
+ // Since "-source_drm_naming_context", and
+ // "-target_drm_naming_context" are OPTIONAL
+ // parameters, ONLY process this portion of the field
+ // if both of these options have been selected
+ if (mDrmNamingContextsFlag) {
+ output = input.replace(mSourceDrmNamingContext,
+ mTargetDrmNamingContext);
+ } else {
+ output = input;
+ }
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_CA_KEY_RECORD)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_CA_KEY_RECORD_DN)) {
+
+ // First check for an embedded "cn=<value>"
+ // name-value pair
+ if (line.startsWith(DRM_LDIF_DN_EMBEDDED_CN_DATA)) {
+ // At this point, always extract
+ // the embedded "cn=<value>" name-value pair
+ // which will ALWAYS be the first
+ // portion of the "dn: " attribute
+ embedded_cn_data = line.split(COMMA, 2);
+
+ embedded_cn_output = compose_numeric_line(
+ DRM_LDIF_DN_EMBEDDED_CN_DATA,
+ EQUAL_SIGN,
+ embedded_cn_data[0],
+ false);
+
+ input = embedded_cn_output
+ + COMMA
+ + embedded_cn_data[1];
+ } else {
+ input = line;
+ }
+
+ // Since "-source_drm_naming_context", and
+ // "-target_drm_naming_context" are OPTIONAL
+ // parameters, ONLY process this portion of the field
+ // if both of these options have been selected
+ if (mDrmNamingContextsFlag) {
+ output = input.replace(mSourceDrmNamingContext,
+ mTargetDrmNamingContext);
+ } else {
+ output = input;
+ }
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_RECOVERY)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_RECOVERY_DN)) {
+
+ // First check for an embedded "cn=<value>"
+ // name-value pair
+ if (line.startsWith(DRM_LDIF_DN_EMBEDDED_CN_DATA)) {
+ // At this point, always extract
+ // the embedded "cn=<value>" name-value pair
+ // which will ALWAYS be the first
+ // portion of the "dn: " attribute
+ embedded_cn_data = line.split(COMMA, 2);
+
+ embedded_cn_output = compose_numeric_line(
+ DRM_LDIF_DN_EMBEDDED_CN_DATA,
+ EQUAL_SIGN,
+ embedded_cn_data[0],
+ false);
+
+ input = embedded_cn_output
+ + COMMA
+ + embedded_cn_data[1];
+ } else {
+ input = line;
+ }
+
+ // Since "-source_drm_naming_context", and
+ // "-target_drm_naming_context" are OPTIONAL
+ // parameters, ONLY process this portion of the field
+ // if both of these options have been selected
+ if (mDrmNamingContextsFlag) {
+ output = input.replace(mSourceDrmNamingContext,
+ mTargetDrmNamingContext);
+ } else {
+ output = input;
+ }
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_TPS_KEY_RECORD)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_TPS_KEY_RECORD_DN)) {
+
+ // First check for an embedded "cn=<value>"
+ // name-value pair
+ if (line.startsWith(DRM_LDIF_DN_EMBEDDED_CN_DATA)) {
+ // At this point, always extract
+ // the embedded "cn=<value>" name-value pair
+ // which will ALWAYS be the first
+ // portion of the "dn: " attribute
+ embedded_cn_data = line.split(COMMA, 2);
+
+ embedded_cn_output = compose_numeric_line(
+ DRM_LDIF_DN_EMBEDDED_CN_DATA,
+ EQUAL_SIGN,
+ embedded_cn_data[0],
+ false);
+
+ input = embedded_cn_output
+ + COMMA
+ + embedded_cn_data[1];
+ } else {
+ input = line;
+ }
+
+ // Since "-source_drm_naming_context", and
+ // "-target_drm_naming_context" are OPTIONAL
+ // parameters, ONLY process this portion of the field
+ // if both of these options have been selected
+ if (mDrmNamingContextsFlag) {
+ output = input.replace(mSourceDrmNamingContext,
+ mTargetDrmNamingContext);
+ } else {
+ output = input;
+ }
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_KEYGEN)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_KEYGEN_DN)) {
+
+ // First check for an embedded "cn=<value>"
+ // name-value pair
+ if (line.startsWith(DRM_LDIF_DN_EMBEDDED_CN_DATA)) {
+ // At this point, always extract
+ // the embedded "cn=<value>" name-value pair
+ // which will ALWAYS be the first
+ // portion of the "dn: " attribute
+ embedded_cn_data = line.split(COMMA, 2);
+
+ embedded_cn_output = compose_numeric_line(
+ DRM_LDIF_DN_EMBEDDED_CN_DATA,
+ EQUAL_SIGN,
+ embedded_cn_data[0],
+ false);
+
+ input = embedded_cn_output
+ + COMMA
+ + embedded_cn_data[1];
+ } else {
+ input = line;
+ }
+
+ // Since "-source_drm_naming_context", and
+ // "-target_drm_naming_context" are OPTIONAL
+ // parameters, ONLY process this portion of the field
+ // if both of these options have been selected
+ if (mDrmNamingContextsFlag) {
+ output = input.replace(mSourceDrmNamingContext,
+ mTargetDrmNamingContext);
+ } else {
+ output = input;
+ }
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_RECORD)) {
+ // Non-Request / Non-Key Record:
+ // Pass through the original
+ // 'dn' line UNCHANGED
+ // so that it is ALWAYS written
+ output = line;
+ } else {
+ log("ERROR: Mismatched record field='"
+ + DRM_LDIF_DN
+ + "' for record type='"
+ + record_type
+ + "'!"
+ + NEWLINE, true);
+ }
+ } catch (PatternSyntaxException exDnEmbeddedCnNameValuePattern) {
+ log("ERROR: line='"
+ + line
+ + "' PatternSyntaxException: '"
+ + exDnEmbeddedCnNameValuePattern.toString()
+ + "'"
+ + NEWLINE, true);
+ } catch (NullPointerException exNullPointerException) {
+ log("ERROR: Unable to replace source DRM naming context '"
+ + mSourceDrmNamingContext
+ + "' with target DRM naming context '"
+ + mTargetDrmNamingContext
+ + "' NullPointerException: '"
+ + exNullPointerException.toString()
+ + "'"
+ + NEWLINE, true);
+ }
+
+ return output;
+ }
+
+ /**
+ * Helper method which composes the output line for
+ * DRM_LDIF_EXTDATA_KEY_RECORD.
+ * <P>
+ *
+ * @param record_type the string representation of the input record type
+ * @param line the string representation of the input line
+ * @return the composed output line
+ */
+ private static String output_extdata_key_record(String record_type,
+ String line) {
+ String output = null;
+
+ if (record_type.equals(DRM_LDIF_ENROLLMENT)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_ENROLLMENT_EXTDATA_KEY_RECORD)) {
+ output = compose_numeric_line(DRM_LDIF_EXTDATA_KEY_RECORD,
+ SPACE,
+ line,
+ false);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_KEYGEN)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_KEYGEN_EXTDATA_KEY_RECORD)) {
+ output = compose_numeric_line(DRM_LDIF_EXTDATA_KEY_RECORD,
+ SPACE,
+ line,
+ false);
+ } else {
+ output = line;
+ }
+ } else {
+ log("ERROR: Mismatched record field='"
+ + DRM_LDIF_EXTDATA_KEY_RECORD
+ + "' for record type='"
+ + record_type
+ + "'!"
+ + NEWLINE, true);
+ }
+
+ return output;
+ }
+
+ /**
+ * Helper method which composes the output line for
+ * DRM_LDIF_EXTDATA_REQUEST_ID.
+ * <P>
+ *
+ * @param record_type the string representation of the input record type
+ * @param line the string representation of the input line
+ * @return the composed output line
+ */
+ private static String output_extdata_request_id(String record_type,
+ String line) {
+ String output = null;
+
+ if (record_type.equals(DRM_LDIF_ENROLLMENT)) {
+ // ALWAYS pass-through "extdata-requestId" for
+ // DRM_LDIF_ENROLLMENT records UNCHANGED because the
+ // value in this field is associated with the issuing CA!
+ output = line;
+ } else if (record_type.equals(DRM_LDIF_RECOVERY)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_RECOVERY_EXTDATA_REQUEST_ID)) {
+ output = compose_numeric_line(DRM_LDIF_EXTDATA_REQUEST_ID,
+ SPACE,
+ line,
+ false);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_KEYGEN)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_KEYGEN_EXTDATA_REQUEST_ID)) {
+ output = compose_numeric_line(DRM_LDIF_EXTDATA_REQUEST_ID,
+ SPACE,
+ line,
+ false);
+ } else {
+ output = line;
+ }
+ } else {
+ log("ERROR: Mismatched record field='"
+ + DRM_LDIF_EXTDATA_REQUEST_ID
+ + "' for record type='"
+ + record_type
+ + "'!"
+ + NEWLINE, true);
+ }
+
+ return output;
+ }
+
+ /**
+ * Helper method which composes the output line for
+ * DRM_LDIF_EXTDATA_REQUEST_NOTES.
+ * <P>
+ *
+ * @param record_type the string representation of the input record type
+ * @param line the string representation of the input line
+ * @return the composed output line
+ */
+ private static String output_extdata_request_notes(String record_type,
+ String line) {
+ String input = null;
+ String data = null;
+ String unformatted_data = null;
+ String output = null;
+ String next_line = null;
+
+ // extract the data
+ if (line.length() > DRM_LDIF_EXTDATA_REQUEST_NOTES.length()) {
+ input = line.substring(
+ DRM_LDIF_EXTDATA_REQUEST_NOTES.length() + 1
+ ).trim();
+ } else {
+ input = line.substring(
+ DRM_LDIF_EXTDATA_REQUEST_NOTES.length()
+ ).trim();
+ }
+
+ while ((line = ldif_record.next()) != null) {
+ if (line.startsWith(SPACE)) {
+ // Do NOT use "trim()";
+ // remove single leading space and
+ // trailing carriage returns and newlines ONLY!
+ input += line.replaceFirst(" ", "").replace('\r', '\0').replace('\n', '\0');
+ } else {
+ next_line = line;
+ break;
+ }
+ }
+
+ if (record_type.equals(DRM_LDIF_ENROLLMENT)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_ENROLLMENT_EXTDATA_REQUEST_NOTES)) {
+ // write out a revised 'extdata-requestnotes' line
+ if (mRewrapFlag && mAppendIdOffsetFlag) {
+ data = input
+ + SPACE
+ + LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REWRAP_MESSAGE
+ + mPublicKeySize
+ + DRM_LDIF_RSA_MESSAGE
+ + mSourcePKISecurityDatabasePwdfileMessage
+ + SPACE
+ + PLUS + SPACE
+ + DRM_LDIF_APPENDED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mAppendIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mRewrapFlag && mRemoveIdOffsetFlag) {
+ data = input
+ + SPACE
+ + LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REWRAP_MESSAGE
+ + mPublicKeySize
+ + DRM_LDIF_RSA_MESSAGE
+ + mSourcePKISecurityDatabasePwdfileMessage
+ + SPACE
+ + PLUS + SPACE
+ + DRM_LDIF_REMOVED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mRemoveIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mRewrapFlag) {
+ data = input
+ + SPACE
+ + LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REWRAP_MESSAGE
+ + mPublicKeySize
+ + DRM_LDIF_RSA_MESSAGE
+ + mSourcePKISecurityDatabasePwdfileMessage
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mAppendIdOffsetFlag) {
+ data = input
+ + SPACE
+ + LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_APPENDED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mAppendIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mRemoveIdOffsetFlag) {
+ data = input
+ + SPACE
+ + LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REMOVED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mRemoveIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ }
+
+ // log this information
+ log("Changed:"
+ + NEWLINE
+ + TIC
+ + DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ input)
+ + TIC
+ + NEWLINE
+ + "--->"
+ + NEWLINE
+ + TIC
+ + output
+ + TIC
+ + NEWLINE, false);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_RECOVERY)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_RECOVERY_EXTDATA_REQUEST_NOTES)) {
+ // write out a revised 'extdata-requestnotes' line
+ if (mRewrapFlag && mAppendIdOffsetFlag) {
+ data = input
+ + SPACE
+ + LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REWRAP_MESSAGE
+ + mPublicKeySize
+ + DRM_LDIF_RSA_MESSAGE
+ + mSourcePKISecurityDatabasePwdfileMessage
+ + SPACE
+ + PLUS + SPACE
+ + DRM_LDIF_APPENDED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mAppendIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mRewrapFlag && mRemoveIdOffsetFlag) {
+ data = input
+ + SPACE
+ + LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REWRAP_MESSAGE
+ + mPublicKeySize
+ + DRM_LDIF_RSA_MESSAGE
+ + mSourcePKISecurityDatabasePwdfileMessage
+ + SPACE
+ + PLUS + SPACE
+ + DRM_LDIF_REMOVED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mRemoveIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mRewrapFlag) {
+ data = input
+ + SPACE
+ + LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REWRAP_MESSAGE
+ + mPublicKeySize
+ + DRM_LDIF_RSA_MESSAGE
+ + mSourcePKISecurityDatabasePwdfileMessage
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mAppendIdOffsetFlag) {
+ data = input
+ + SPACE
+ + LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_APPENDED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mAppendIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mRemoveIdOffsetFlag) {
+ data = input
+ + SPACE
+ + LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REMOVED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mRemoveIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ }
+
+ // log this information
+ log("Changed:"
+ + NEWLINE
+ + TIC
+ + DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ input)
+ + TIC
+ + NEWLINE
+ + "--->"
+ + NEWLINE
+ + TIC
+ + output
+ + TIC
+ + NEWLINE, false);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_KEYGEN)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_KEYGEN_EXTDATA_REQUEST_NOTES)) {
+ // write out a revised 'extdata-requestnotes' line
+ if (mRewrapFlag && mAppendIdOffsetFlag) {
+ data = input
+ + SPACE
+ + LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REWRAP_MESSAGE
+ + mPublicKeySize
+ + DRM_LDIF_RSA_MESSAGE
+ + mSourcePKISecurityDatabasePwdfileMessage
+ + SPACE
+ + PLUS + SPACE
+ + DRM_LDIF_APPENDED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mAppendIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mRewrapFlag && mRemoveIdOffsetFlag) {
+ data = input
+ + SPACE
+ + LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REWRAP_MESSAGE
+ + mPublicKeySize
+ + DRM_LDIF_RSA_MESSAGE
+ + mSourcePKISecurityDatabasePwdfileMessage
+ + SPACE
+ + PLUS + SPACE
+ + DRM_LDIF_REMOVED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mRemoveIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mRewrapFlag) {
+ data = input
+ + SPACE
+ + LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REWRAP_MESSAGE
+ + mPublicKeySize
+ + DRM_LDIF_RSA_MESSAGE
+ + mSourcePKISecurityDatabasePwdfileMessage
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mAppendIdOffsetFlag) {
+ data = input
+ + SPACE
+ + LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_APPENDED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mAppendIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mRemoveIdOffsetFlag) {
+ data = input
+ + SPACE
+ + LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REMOVED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mRemoveIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ }
+
+ // log this information
+ log("Changed:"
+ + NEWLINE
+ + TIC
+ + DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ input)
+ + TIC
+ + NEWLINE
+ + "--->"
+ + NEWLINE
+ + TIC
+ + output
+ + TIC
+ + NEWLINE, false);
+ } else {
+ output = line;
+ }
+ } else {
+ log("ERROR: Mismatched record field='"
+ + DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + "' for record type='"
+ + record_type
+ + "'!"
+ + NEWLINE, true);
+ }
+
+ if (output != null) {
+ output += NEWLINE + next_line;
+ }
+
+ return output;
+ }
+
+ /**
+ * Helper method which composes the output line for
+ * DRM_LDIF_EXTDATA_REQUEST_NOTES.
+ * <P>
+ *
+ * @param record_type the string representation of the input record type
+ * @param previous_line the string representation of the previous input line
+ * @param writer the PrintWriter used to output this new LDIF line
+ * @return the composed output line
+ */
+ private static void create_extdata_request_notes(String record_type,
+ String previous_line,
+ PrintWriter writer) {
+ String data = null;
+ String unformatted_data = null;
+ String output = null;
+
+ if (record_type.equals(DRM_LDIF_RECOVERY)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_RECOVERY_EXTDATA_REQUEST_NOTES)) {
+ if (!previous_line.startsWith(DRM_LDIF_EXTDATA_REQUEST_NOTES)) {
+ // write out the missing 'extdata-requestnotes' line
+ if (mRewrapFlag && mAppendIdOffsetFlag) {
+ data = LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REWRAP_MESSAGE
+ + mPublicKeySize
+ + DRM_LDIF_RSA_MESSAGE
+ + mSourcePKISecurityDatabasePwdfileMessage
+ + SPACE
+ + PLUS + SPACE
+ + DRM_LDIF_APPENDED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mAppendIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mRewrapFlag && mRemoveIdOffsetFlag) {
+ data = LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REWRAP_MESSAGE
+ + mPublicKeySize
+ + DRM_LDIF_RSA_MESSAGE
+ + mSourcePKISecurityDatabasePwdfileMessage
+ + SPACE
+ + PLUS + SPACE
+ + DRM_LDIF_REMOVED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mRemoveIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mRewrapFlag) {
+ data = LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REWRAP_MESSAGE
+ + mPublicKeySize
+ + DRM_LDIF_RSA_MESSAGE
+ + mSourcePKISecurityDatabasePwdfileMessage
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mAppendIdOffsetFlag) {
+ data = LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_APPENDED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mAppendIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mRemoveIdOffsetFlag) {
+ data = LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REMOVED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mRemoveIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ }
+
+ // log this information
+ log("Created:"
+ + NEWLINE
+ + TIC
+ + output
+ + TIC
+ + NEWLINE, false);
+
+ // Write out this revised line
+ // and flush the buffer
+ writer.write(output + NEWLINE);
+ writer.flush();
+ System.out.print(".");
+ }
+ }
+ } else if (record_type.equals(DRM_LDIF_KEYGEN)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_KEYGEN_EXTDATA_REQUEST_NOTES)) {
+ if (!previous_line.startsWith(DRM_LDIF_EXTDATA_REQUEST_NOTES)) {
+ // write out the missing 'extdata-requestnotes' line
+ if (mRewrapFlag && mAppendIdOffsetFlag) {
+ data = LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REWRAP_MESSAGE
+ + mPublicKeySize
+ + DRM_LDIF_RSA_MESSAGE
+ + mSourcePKISecurityDatabasePwdfileMessage
+ + SPACE
+ + PLUS + SPACE
+ + DRM_LDIF_APPENDED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mAppendIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mRewrapFlag && mRemoveIdOffsetFlag) {
+ data = LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REWRAP_MESSAGE
+ + mPublicKeySize
+ + DRM_LDIF_RSA_MESSAGE
+ + mSourcePKISecurityDatabasePwdfileMessage
+ + SPACE
+ + PLUS + SPACE
+ + DRM_LDIF_REMOVED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mRemoveIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mRewrapFlag) {
+ data = LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REWRAP_MESSAGE
+ + mPublicKeySize
+ + DRM_LDIF_RSA_MESSAGE
+ + mSourcePKISecurityDatabasePwdfileMessage
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mAppendIdOffsetFlag) {
+ data = LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_APPENDED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mAppendIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ } else if (mRemoveIdOffsetFlag) {
+ data = LEFT_BRACE
+ + mDateOfModify
+ + RIGHT_BRACE
+ + COLON + SPACE
+ + DRM_LDIF_REMOVED_ID_OFFSET_MESSAGE
+ + SPACE
+ + TIC
+ + mRemoveIdOffset.toString()
+ + TIC
+ + mDrmNamingContextMessage
+ + mProcessRequestsAndKeyRecordsOnlyMessage;
+
+ // Unformat the data
+ unformatted_data = stripEOL(data);
+
+ // Format the unformatted_data
+ // to match the desired LDIF format
+ output = DRM_LDIF_EXTDATA_REQUEST_NOTES
+ + SPACE
+ + format_ldif_data(
+ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+ }
+
+ // log this information
+ log("Created:"
+ + NEWLINE
+ + TIC
+ + output
+ + TIC
+ + NEWLINE, false);
+
+ // Write out this revised line
+ // and flush the buffer
+ writer.write(output + NEWLINE);
+ writer.flush();
+ System.out.print(".");
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper method which composes the output line for
+ * DRM_LDIF_EXTDATA_SERIAL_NUMBER.
+ * <P>
+ *
+ * @param record_type the string representation of the input record type
+ * @param line the string representation of the input line
+ * @return the composed output line
+ */
+ private static String output_extdata_serial_number(String record_type,
+ String line) {
+ String output = null;
+
+ if (record_type.equals(DRM_LDIF_RECOVERY)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_RECOVERY_EXTDATA_SERIAL_NUMBER)) {
+ output = compose_numeric_line(DRM_LDIF_EXTDATA_SERIAL_NUMBER,
+ SPACE,
+ line,
+ false);
+ } else {
+ output = line;
+ }
+ } else {
+ log("ERROR: Mismatched record field='"
+ + DRM_LDIF_EXTDATA_SERIAL_NUMBER
+ + "' for record type='"
+ + record_type
+ + "'!"
+ + NEWLINE, true);
+ }
+
+ return output;
+ }
+
+ /**
+ * Helper method which composes the output line for
+ * DRM_LDIF_PRIVATE_KEY_DATA.
+ * <P>
+ *
+ * @param record_type the string representation of the input record type
+ * @param line the string representation of the input line
+ * @return the composed output line
+ */
+ private static String output_private_key_data(String record_type,
+ String line) {
+ byte source_wrappedKeyData[] = null;
+ byte target_wrappedKeyData[] = null;
+ String data = null;
+ String revised_data = null;
+ String unformatted_data = null;
+ String formatted_data = null;
+ String output = null;
+
+ try {
+ if (record_type.equals(DRM_LDIF_CA_KEY_RECORD)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_CA_KEY_RECORD_PRIVATE_KEY_DATA)) {
+ // Since "-source_pki_security_database_path",
+ // "-source_storage_token_name",
+ // "-source_storage_certificate_nickname", and
+ // "-target_storage_certificate_file" are OPTIONAL
+ // parameters, ONLY process this field if all of
+ // these options have been selected
+ if (mRewrapFlag) {
+ // extract the data
+ data = line.substring(
+ DRM_LDIF_PRIVATE_KEY_DATA.length() + 1
+ ).trim();
+
+ while ((line = ldif_record.next()) != null) {
+ if (line.startsWith(SPACE)) {
+ data += line.trim();
+ } else {
+ break;
+ }
+ }
+
+ // Decode the ASCII BASE 64 certificate
+ // enclosed in the String() object
+ // into a BINARY BASE 64 byte[] object
+ source_wrappedKeyData =
+ Utils.base64decode(data);
+
+ // rewrap the source wrapped private key data
+ target_wrappedKeyData = rewrap_wrapped_key_data(
+ source_wrappedKeyData);
+
+ // Encode the BINARY BASE 64 byte[] object
+ // into an ASCII BASE 64 certificate
+ // enclosed in a String() object
+ revised_data = Utils.base64encode(
+ target_wrappedKeyData);
+
+ // Unformat the ASCII BASE 64 certificate
+ // for the log file
+ unformatted_data = stripEOL(revised_data);
+
+ // Format the ASCII BASE 64 certificate
+ // to match the desired LDIF format
+ formatted_data = format_ldif_data(
+ PRIVATE_KEY_DATA_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+
+ // construct a revised 'privateKeyData' line
+ output = DRM_LDIF_PRIVATE_KEY_DATA
+ + SPACE
+ + formatted_data
+ + NEWLINE
+ + line;
+
+ // log this information
+ log("Changed 'privateKeyData' from:"
+ + NEWLINE
+ + TIC
+ + data
+ + TIC
+ + NEWLINE
+ + " to:"
+ + NEWLINE
+ + TIC
+ + unformatted_data
+ + TIC
+ + NEWLINE, false);
+ } else {
+ output = line;
+ }
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_TPS_KEY_RECORD)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_TPS_KEY_RECORD_PRIVATE_KEY_DATA)) {
+ // Since "-source_pki_security_database_path",
+ // "-source_storage_token_name",
+ // "-source_storage_certificate_nickname", and
+ // "-target_storage_certificate_file" are OPTIONAL
+ // parameters, ONLY process this field if all of
+ // these options have been selected
+ if (mRewrapFlag) {
+ // extract the data
+ data = line.substring(
+ DRM_LDIF_PRIVATE_KEY_DATA.length() + 1
+ ).trim();
+
+ while ((line = ldif_record.next()) != null) {
+ if (line.startsWith(SPACE)) {
+ data += line.trim();
+ } else {
+ break;
+ }
+ }
+
+ // Decode the ASCII BASE 64 certificate
+ // enclosed in the String() object
+ // into a BINARY BASE 64 byte[] object
+ source_wrappedKeyData =
+ Utils.base64decode(data);
+
+ // rewrap the source wrapped private key data
+ target_wrappedKeyData = rewrap_wrapped_key_data(
+ source_wrappedKeyData);
+
+ // Encode the BINARY BASE 64 byte[] object
+ // into an ASCII BASE 64 certificate
+ // enclosed in a String() object
+ revised_data = Utils.base64encode(
+ target_wrappedKeyData);
+
+ // Unformat the ASCII BASE 64 certificate
+ // for the log file
+ unformatted_data = stripEOL(revised_data);
+
+ // Format the ASCII BASE 64 certificate
+ // to match the desired LDIF format
+ formatted_data = format_ldif_data(
+ PRIVATE_KEY_DATA_FIRST_LINE_DATA_LENGTH,
+ unformatted_data);
+
+ // construct a revised 'privateKeyData' line
+ output = DRM_LDIF_PRIVATE_KEY_DATA
+ + SPACE
+ + formatted_data
+ + NEWLINE
+ + line;
+
+ // log this information
+ log("Changed 'privateKeyData' from:"
+ + NEWLINE
+ + TIC
+ + data
+ + TIC
+ + NEWLINE
+ + " to:"
+ + NEWLINE
+ + TIC
+ + unformatted_data
+ + TIC
+ + NEWLINE, false);
+ } else {
+ output = line;
+ }
+ } else {
+ output = line;
+ }
+ } else {
+ log("ERROR: Mismatched record field='"
+ + DRM_LDIF_PRIVATE_KEY_DATA
+ + "' for record type='"
+ + record_type
+ + "'!"
+ + NEWLINE, true);
+ }
+ } catch (Exception exRewrap) {
+ log("ERROR: Unable to rewrap BINARY BASE 64 data. "
+ + "Exception: '"
+ + exRewrap.toString()
+ + "'"
+ + NEWLINE, true);
+ }
+
+ return output;
+ }
+
+ /**
+ * Helper method which composes the output line for DRM_LDIF_REQUEST_ID.
+ * <P>
+ *
+ * @param record_type the string representation of the input record type
+ * @param line the string representation of the input line
+ * @return the composed output line
+ */
+ private static String output_request_id(String record_type,
+ String line) {
+ String output = null;
+
+ if (record_type.equals(DRM_LDIF_ENROLLMENT)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_ENROLLMENT_REQUEST_ID)) {
+ output = compose_numeric_line(DRM_LDIF_REQUEST_ID,
+ SPACE,
+ line,
+ true);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_RECOVERY)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_RECOVERY_REQUEST_ID)) {
+ output = compose_numeric_line(DRM_LDIF_REQUEST_ID,
+ SPACE,
+ line,
+ true);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_KEYGEN)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_KEYGEN_REQUEST_ID)) {
+ output = compose_numeric_line(DRM_LDIF_REQUEST_ID,
+ SPACE,
+ line,
+ true);
+ } else {
+ output = line;
+ }
+ } else {
+ log("ERROR: Mismatched record field='"
+ + DRM_LDIF_REQUEST_ID
+ + "' for record type='"
+ + record_type
+ + "'!"
+ + NEWLINE, true);
+ }
+
+ return output;
+ }
+
+ /**
+ * Helper method which composes the output line for DRM_LDIF_SERIAL_NO.
+ * <P>
+ *
+ * @param record_type the string representation of the input record type
+ * @param line the string representation of the input line
+ * @return the composed output line
+ */
+ private static String output_serial_no(String record_type,
+ String line) {
+ String output = null;
+
+ if (record_type.equals(DRM_LDIF_CA_KEY_RECORD)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_CA_KEY_RECORD_SERIAL_NO)) {
+ output = compose_numeric_line(DRM_LDIF_SERIAL_NO,
+ SPACE,
+ line,
+ true);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_TPS_KEY_RECORD)) {
+ if (drmtoolCfg.get(DRMTOOL_CFG_TPS_KEY_RECORD_SERIAL_NO)) {
+ output = compose_numeric_line(DRM_LDIF_SERIAL_NO,
+ SPACE,
+ line,
+ true);
+ } else {
+ output = line;
+ }
+ } else if (record_type.equals(DRM_LDIF_RECORD)) {
+ // Non-Request / Non-Key Record:
+ // Pass through the original
+ // 'serialno' line UNCHANGED
+ // so that it is ALWAYS written
+ output = line;
+ } else {
+ log("ERROR: Mismatched record field='"
+ + DRM_LDIF_SERIAL_NO
+ + "' for record type='"
+ + record_type
+ + "'!"
+ + NEWLINE, true);
+ }
+
+ return output;
+ }
+
+ /**
+ * Helper method which composes the output line for
+ * DRM_LDIF_EXTDATA_AUTH_TOKEN_USER.
+ * <P>
+ *
+ * @param record_type the string representation of the input record type
+ * @param line the string representation of the input line
+ * @return the composed output line
+ */
+ private static String output_extdata_auth_token_user(String record_type,
+ String line) {
+ String output = null;
+
+ try {
+ if (record_type.equals(DRM_LDIF_ENROLLMENT)) {
+ // Since "-source_drm_naming_context", and
+ // "-target_drm_naming_context" are OPTIONAL
+ // parameters, ONLY process this field if both of
+ // these options have been selected
+ if (mDrmNamingContextsFlag) {
+ output = line.replace(mSourceDrmNamingContext,
+ mTargetDrmNamingContext);
+ } else {
+ output = line;
+ }
+ } else {
+ log("ERROR: Mismatched record field='"
+ + DRM_LDIF_EXTDATA_AUTH_TOKEN_USER
+ + "' for record type='"
+ + record_type
+ + "'!"
+ + NEWLINE, true);
+ }
+ } catch (NullPointerException exNullPointerException) {
+ log("ERROR: Unable to replace source DRM naming context '"
+ + mSourceDrmNamingContext
+ + "' with target DRM naming context '"
+ + mTargetDrmNamingContext
+ + "' NullPointerException: '"
+ + exNullPointerException.toString()
+ + "'"
+ + NEWLINE, true);
+ }
+
+ return output;
+ }
+
+ /**
+ * Helper method which composes the output line for
+ * DRM_LDIF_EXTDATA_AUTH_TOKEN_USER_DN.
+ * <P>
+ *
+ * @param record_type the string representation of the input record type
+ * @param line the string representation of the input line
+ * @return the composed output line
+ */
+ private static String output_extdata_auth_token_user_dn(String record_type,
+ String line) {
+ String output = null;
+
+ try {
+ if (record_type.equals(DRM_LDIF_ENROLLMENT)) {
+ // Since "-source_drm_naming_context", and
+ // "-target_drm_naming_context" are OPTIONAL
+ // parameters, ONLY process this field if both of
+ // these options have been selected
+ if (mDrmNamingContextsFlag) {
+ output = line.replace(mSourceDrmNamingContext,
+ mTargetDrmNamingContext);
+ } else {
+ output = line;
+ }
+ } else {
+ log("ERROR: Mismatched record field='"
+ + DRM_LDIF_EXTDATA_AUTH_TOKEN_USER_DN
+ + "' for record type='"
+ + record_type
+ + "'!"
+ + NEWLINE, true);
+ }
+ } catch (NullPointerException exNullPointerException) {
+ log("ERROR: Unable to replace source DRM naming context '"
+ + mSourceDrmNamingContext
+ + "' with target DRM naming context '"
+ + mTargetDrmNamingContext
+ + "' NullPointerException: '"
+ + exNullPointerException.toString()
+ + "'"
+ + NEWLINE, true);
+ }
+
+ return output;
+ }
+
+ /**
+ * This method performs the actual parsing of the "source" LDIF file
+ * and produces the "target" LDIF file.
+ * <P>
+ *
+ * @return true if the "target" LDIF file is successfully created
+ */
+ private static boolean convert_source_ldif_to_target_ldif() {
+ boolean success = false;
+ BufferedReader reader = null;
+ PrintWriter writer = null;
+ String input = null;
+ String line = null;
+ String previous_line = null;
+ String output = null;
+ String data = null;
+ String record_type = null;
+
+ if (mRewrapFlag) {
+ success = obtain_RSA_rewrapping_keys();
+ if (!success) {
+ return FAILURE;
+ }
+ }
+
+ // Create a vector for LDIF input
+ record = new Vector<String>(INITIAL_LDIF_RECORD_CAPACITY);
+
+ // Process each line in the source LDIF file
+ // and store it in the target LDIF file
+ try {
+ // Open source LDIF file for reading
+ reader = new BufferedReader(
+ new FileReader(mSourceLdifFilename));
+
+ // Open target LDIF file for writing
+ writer = new PrintWriter(
+ new BufferedWriter(
+ new FileWriter(mTargetLdifFilename)));
+
+ System.out.print("PROCESSING: ");
+ while ((input = reader.readLine()) != null) {
+ // Read in a record from the source LDIF file and
+ // add this line of input into the record vector
+ success = record.add(input);
+ if (!success) {
+ return FAILURE;
+ }
+
+ // Check for the end of an LDIF record
+ if (!input.equals("")) {
+ // Check to see if input line identifies the record type
+ if (input.startsWith(DRM_LDIF_REQUEST_TYPE)) {
+ // set the record type:
+ //
+ // * DRM_LDIF_ENROLLMENT
+ // * DRM_LDIF_KEYGEN
+ // * DRM_LDIF_RECOVERY
+ //
+ record_type = input.substring(
+ DRM_LDIF_REQUEST_TYPE.length() + 1
+ ).trim();
+ if (!record_type.equals(DRM_LDIF_ENROLLMENT) &&
+ !record_type.equals(DRM_LDIF_KEYGEN) &&
+ !record_type.equals(DRM_LDIF_RECOVERY)) {
+ log("ERROR: Unknown LDIF record type='"
+ + record_type
+ + "'!"
+ + NEWLINE, true);
+ return FAILURE;
+ }
+ } else if (input.startsWith(DRM_LDIF_ARCHIVED_BY)) {
+ // extract the data
+ data = input.substring(
+ DRM_LDIF_ARCHIVED_BY.length() + 1
+ ).trim();
+
+ // set the record type:
+ //
+ // * DRM_LDIF_CA_KEY_RECORD
+ // * DRM_LDIF_TPS_KEY_RECORD
+ //
+ if (data.startsWith(DRM_LDIF_TPS_KEY_RECORD)) {
+ record_type = DRM_LDIF_TPS_KEY_RECORD;
+ } else if (data.startsWith(DRM_LDIF_CA_KEY_RECORD)) {
+ record_type = DRM_LDIF_CA_KEY_RECORD;
+ } else {
+ log("ERROR: Unable to determine LDIF record type "
+ + "from data='"
+ + data
+ + "'!"
+ + NEWLINE, true);
+ return FAILURE;
+ }
+ }
+
+ // continue adding input lines into this record
+ continue;
+ }
+
+ // If record type is unset, then this record is neither
+ // an LDIF request record nor an LDIF key record; check
+ // to see if it needs to be written out to the target
+ // LDIF file or thrown away.
+ if ((record_type == null) &&
+ mProcessRequestsAndKeyRecordsOnlyFlag) {
+ // Mark each removed record with an 'x'
+ System.out.print("x");
+
+ // log this information
+ log("INFO: Throwing away an LDIF record which is "
+ + "neither a Request nor a Key Record!"
+ + NEWLINE, false);
+
+ // clear this LDIF record from the record vector
+ record.clear();
+
+ // NOTE: there is no need to reset the record type
+
+ // begin adding input lines into a new record
+ continue;
+ } else if (record_type == null) {
+ // Set record type to specify a "generic" LDIF record
+ record_type = DRM_LDIF_RECORD;
+ }
+
+ ldif_record = record.iterator();
+
+ // Process each line of the record:
+ // * If LDIF Record Type for this line is 'valid'
+ // * If DRMTOOL Configuration File Parameter is 'true'
+ // * Process this data
+ // * Else If DRMTOOL Configuration File Parameter is 'false'
+ // * Pass through this data unchanged
+ // * Else If LDIF Record Type for this line is 'invalid'
+ // * Log error and leave method returning 'false'
+ while (ldif_record.hasNext()) {
+
+ line = ldif_record.next();
+
+ if (line.startsWith(DRM_LDIF_CN)) {
+ output = output_cn(record_type, line);
+ if (output == null) {
+ return FAILURE;
+ }
+ } else if (line.startsWith(DRM_LDIF_DATE_OF_MODIFY)) {
+ output = output_date_of_modify(record_type, line);
+ if (output == null) {
+ return FAILURE;
+ }
+ } else if (line.startsWith(DRM_LDIF_DN)) {
+ output = output_dn(record_type, line);
+ if (output == null) {
+ return FAILURE;
+ }
+ } else if (line.startsWith(DRM_LDIF_EXTDATA_KEY_RECORD)) {
+ output = output_extdata_key_record(record_type,
+ line);
+ if (output == null) {
+ return FAILURE;
+ }
+ } else if (line.startsWith(DRM_LDIF_EXTDATA_REQUEST_ID)) {
+ output = output_extdata_request_id(record_type,
+ line);
+ if (output == null) {
+ return FAILURE;
+ }
+ } else if (line.startsWith(DRM_LDIF_EXTDATA_REQUEST_NOTES)) {
+ output = output_extdata_request_notes(record_type,
+ line);
+ if (output == null) {
+ return FAILURE;
+ }
+ } else if (line.startsWith(DRM_LDIF_EXTDATA_REQUEST_TYPE)) {
+ // if one is not already present,
+ // compose and write out the missing
+ // 'extdata_requestnotes' line
+ create_extdata_request_notes(record_type,
+ previous_line,
+ writer);
+
+ // ALWAYS pass through the original
+ // 'extdata-requesttype' line UNCHANGED
+ // so that it is ALWAYS written
+ output = line;
+ } else if (line.startsWith(DRM_LDIF_EXTDATA_SERIAL_NUMBER)) {
+ output = output_extdata_serial_number(record_type,
+ line);
+ if (output == null) {
+ return FAILURE;
+ }
+ } else if (line.startsWith(DRM_LDIF_PRIVATE_KEY_DATA)) {
+ output = output_private_key_data(record_type,
+ line);
+ if (output == null) {
+ return FAILURE;
+ }
+ } else if (line.startsWith(DRM_LDIF_REQUEST_ID)) {
+ output = output_request_id(record_type, line);
+ if (output == null) {
+ return FAILURE;
+ }
+ } else if (line.startsWith(DRM_LDIF_SERIAL_NO)) {
+ output = output_serial_no(record_type, line);
+ if (output == null) {
+ return FAILURE;
+ }
+ } else if (previous_line != null &&
+ previous_line.startsWith(
+ DRM_LDIF_EXTDATA_AUTH_TOKEN_USER)) {
+ output = output_extdata_auth_token_user(record_type,
+ line);
+ if (output == null) {
+ return FAILURE;
+ }
+ } else if (previous_line != null &&
+ previous_line.startsWith(
+ DRM_LDIF_EXTDATA_AUTH_TOKEN_USER_DN)) {
+ output = output_extdata_auth_token_user_dn(record_type,
+ line);
+ if (output == null) {
+ return FAILURE;
+ }
+ } else {
+ // Pass through line unchanged
+ output = line;
+ }
+
+ // Always save a copy of this line
+ previous_line = output;
+
+ // Always write out the output line and flush the buffer
+ writer.write(output + NEWLINE);
+ writer.flush();
+ System.out.print(".");
+ }
+ // Mark the end of the LDIF record
+ System.out.print("!");
+
+ // clear this LDIF record from the record vector
+ record.clear();
+ }
+ System.out.println(" FINISHED." + NEWLINE);
+ } catch (IOException exIO) {
+ log("ERROR: line='"
+ + line
+ + "' OR output='"
+ + output
+ + "' IOException: '"
+ + exIO.toString()
+ + "'"
+ + NEWLINE, true);
+ return FAILURE;
+ }
+
+ return SUCCESS;
+ }
+
+ /**************************************/
+ /* DRMTOOL Config File Parser Methods */
+ /**************************************/
+
+ /**
+ * This method performs the actual parsing of the DRMTOOL config file
+ * and initializes how the DRM Record Fields should be processed.
+ * <P>
+ *
+ * @return true if the DRMTOOL config file is successfully processed
+ */
+ private static boolean process_drmtool_config_file() {
+ BufferedReader reader = null;
+ String line = null;
+ String name_value_pair[] = null;
+ String name = null;
+ Boolean value = null;
+
+ // Process each line containing a name/value pair
+ // in the DRMTOOL config file
+ try {
+ // Open DRMTOOL config file for reading
+ reader = new BufferedReader(
+ new FileReader(mDrmtoolCfgFilename));
+
+ // Create a hashtable for relevant name/value pairs
+ drmtoolCfg = new Hashtable<String, Boolean>();
+
+ System.out.print("PROCESSING DRMTOOL CONFIG FILE: ");
+ while ((line = reader.readLine()) != null) {
+ if (line.startsWith(DRMTOOL_CFG_PREFIX)) {
+ // obtain "name=value" pair
+ name_value_pair = line.split(EQUAL_SIGN);
+
+ // obtain "name"
+ name = name_value_pair[0];
+
+ // compute "boolean" value
+ if (name_value_pair[1].equals("true")) {
+ value = Boolean.TRUE;
+ } else {
+ value = Boolean.FALSE;
+ }
+
+ // store relevant DRM LDIF fields for processing
+ if (name.equals(DRMTOOL_CFG_ENROLLMENT_CN)
+ || name.equals(DRMTOOL_CFG_ENROLLMENT_DATE_OF_MODIFY)
+ || name.equals(DRMTOOL_CFG_ENROLLMENT_DN)
+ || name.equals(DRMTOOL_CFG_ENROLLMENT_EXTDATA_KEY_RECORD)
+ || name.equals(DRMTOOL_CFG_ENROLLMENT_EXTDATA_REQUEST_NOTES)
+ || name.equals(DRMTOOL_CFG_ENROLLMENT_REQUEST_ID)
+ || name.equals(DRMTOOL_CFG_CA_KEY_RECORD_CN)
+ || name.equals(DRMTOOL_CFG_CA_KEY_RECORD_DATE_OF_MODIFY)
+ || name.equals(DRMTOOL_CFG_CA_KEY_RECORD_DN)
+ || name.equals(DRMTOOL_CFG_CA_KEY_RECORD_PRIVATE_KEY_DATA)
+ || name.equals(DRMTOOL_CFG_CA_KEY_RECORD_SERIAL_NO)
+ || name.equals(DRMTOOL_CFG_RECOVERY_CN)
+ || name.equals(DRMTOOL_CFG_RECOVERY_DATE_OF_MODIFY)
+ || name.equals(DRMTOOL_CFG_RECOVERY_DN)
+ || name.equals(DRMTOOL_CFG_RECOVERY_EXTDATA_REQUEST_ID)
+ || name.equals(DRMTOOL_CFG_RECOVERY_EXTDATA_REQUEST_NOTES)
+ || name.equals(DRMTOOL_CFG_RECOVERY_EXTDATA_SERIAL_NUMBER)
+ || name.equals(DRMTOOL_CFG_RECOVERY_REQUEST_ID)
+ || name.equals(DRMTOOL_CFG_TPS_KEY_RECORD_CN)
+ || name.equals(DRMTOOL_CFG_TPS_KEY_RECORD_DATE_OF_MODIFY)
+ || name.equals(DRMTOOL_CFG_TPS_KEY_RECORD_DN)
+ || name.equals(DRMTOOL_CFG_TPS_KEY_RECORD_PRIVATE_KEY_DATA)
+ || name.equals(DRMTOOL_CFG_TPS_KEY_RECORD_SERIAL_NO)
+ || name.equals(DRMTOOL_CFG_KEYGEN_CN)
+ || name.equals(DRMTOOL_CFG_KEYGEN_DATE_OF_MODIFY)
+ || name.equals(DRMTOOL_CFG_KEYGEN_DN)
+ || name.equals(DRMTOOL_CFG_KEYGEN_EXTDATA_KEY_RECORD)
+ || name.equals(DRMTOOL_CFG_KEYGEN_EXTDATA_REQUEST_ID)
+ || name.equals(DRMTOOL_CFG_KEYGEN_EXTDATA_REQUEST_NOTES)
+ || name.equals(DRMTOOL_CFG_KEYGEN_REQUEST_ID)) {
+ drmtoolCfg.put(name, value);
+ System.out.print(".");
+ }
+ }
+ }
+ System.out.println(" FINISHED." + NEWLINE);
+ } catch (FileNotFoundException exDrmtoolCfgFileNotFound) {
+ log("ERROR: No DRMTOOL config file named '"
+ + mDrmtoolCfgFilename
+ + "' exists! FileNotFoundException: '"
+ + exDrmtoolCfgFileNotFound.toString()
+ + "'"
+ + NEWLINE, true);
+ return FAILURE;
+ } catch (IOException exDrmtoolCfgIO) {
+ log("ERROR: line='"
+ + line
+ + "' IOException: '"
+ + exDrmtoolCfgIO.toString()
+ + "'"
+ + NEWLINE, true);
+ return FAILURE;
+ } catch (PatternSyntaxException exDrmtoolCfgNameValuePattern) {
+ log("ERROR: line='"
+ + line
+ + "' PatternSyntaxException: '"
+ + exDrmtoolCfgNameValuePattern.toString()
+ + "'"
+ + NEWLINE, true);
+ return FAILURE;
+ }
+
+ return SUCCESS;
+ }
+
+ /************/
+ /* DRM Tool */
+ /************/
+
+ /**
+ * The main DRMTool method.
+ * <P>
+ *
+ * @param args DRMTool options
+ */
+ public static void main(String[] args) {
+ // Variables
+ String append_id_offset = null;
+ String remove_id_offset = null;
+ String process_drm_naming_context_fields = null;
+ String process_requests_and_key_records_only = null;
+ String use_PKI_security_database_pwdfile = null;
+ File cfgFile = null;
+ File sourceFile = null;
+ File sourceDBPath = null;
+ File sourceDBPwdfile = null;
+ File targetStorageCertFile = null;
+ File targetFile = null;
+ File logFile = null;
+ boolean success = false;
+
+ // Get current date and time
+ mDateOfModify = now(DATE_OF_MODIFY_PATTERN);
+
+ // Check that the correct number of arguments were
+ // submitted to the program
+ if ((args.length != ID_OFFSET_ARGS) &&
+ (args.length != (ID_OFFSET_ARGS + 1)) &&
+ (args.length != (ID_OFFSET_ARGS + 4)) &&
+ (args.length != (ID_OFFSET_ARGS + 5)) &&
+ (args.length != REWRAP_ARGS) &&
+ (args.length != (REWRAP_ARGS + 1)) &&
+ (args.length != (REWRAP_ARGS + 2)) &&
+ (args.length != (REWRAP_ARGS + 3)) &&
+ (args.length != (REWRAP_ARGS + 4)) &&
+ (args.length != (REWRAP_ARGS + 5)) &&
+ (args.length != (REWRAP_ARGS + 6)) &&
+ (args.length != (REWRAP_ARGS + 7)) &&
+ (args.length != REWRAP_AND_ID_OFFSET_ARGS) &&
+ (args.length != (REWRAP_AND_ID_OFFSET_ARGS + 1)) &&
+ (args.length != (REWRAP_AND_ID_OFFSET_ARGS + 2)) &&
+ (args.length != (REWRAP_AND_ID_OFFSET_ARGS + 3)) &&
+ (args.length != (REWRAP_AND_ID_OFFSET_ARGS + 4)) &&
+ (args.length != (REWRAP_AND_ID_OFFSET_ARGS + 5)) &&
+ (args.length != (REWRAP_AND_ID_OFFSET_ARGS + 6)) &&
+ (args.length != (REWRAP_AND_ID_OFFSET_ARGS + 7))) {
+ System.err.println("ERROR: Incorrect number of arguments!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ }
+
+ // Process command-line arguments
+ for (int i = 0; i < args.length; i += 2) {
+ if (args[i].equals(DRMTOOL_CFG_FILE)) {
+ mDrmtoolCfgFilename = args[i + 1];
+ mMandatoryNameValuePairs++;
+ } else if (args[i].equals(SOURCE_LDIF_FILE)) {
+ mSourceLdifFilename = args[i + 1];
+ mMandatoryNameValuePairs++;
+ } else if (args[i].equals(TARGET_LDIF_FILE)) {
+ mTargetLdifFilename = args[i + 1];
+ mMandatoryNameValuePairs++;
+ } else if (args[i].equals(LOG_FILE)) {
+ mLogFilename = args[i + 1];
+ mMandatoryNameValuePairs++;
+ } else if (args[i].equals(SOURCE_NSS_DB_PATH)) {
+ mSourcePKISecurityDatabasePath = args[i + 1];
+ mRewrapNameValuePairs++;
+ } else if (args[i].equals(SOURCE_STORAGE_TOKEN_NAME)) {
+ mSourceStorageTokenName = args[i + 1];
+ mRewrapNameValuePairs++;
+ } else if (args[i].equals(SOURCE_STORAGE_CERT_NICKNAME)) {
+ mSourceStorageCertNickname = args[i + 1];
+ mRewrapNameValuePairs++;
+ } else if (args[i].equals(TARGET_STORAGE_CERTIFICATE_FILE)) {
+ mTargetStorageCertificateFilename = args[i + 1];
+ mRewrapNameValuePairs++;
+ } else if (args[i].equals(SOURCE_NSS_DB_PWDFILE)) {
+ mSourcePKISecurityDatabasePwdfile = args[i + 1];
+ mPKISecurityDatabasePwdfileNameValuePairs++;
+ } else if (args[i].equals(APPEND_ID_OFFSET)) {
+ append_id_offset = args[i + 1];
+ mAppendIdOffsetNameValuePairs++;
+ } else if (args[i].equals(REMOVE_ID_OFFSET)) {
+ remove_id_offset = args[i + 1];
+ mRemoveIdOffsetNameValuePairs++;
+ } else if (args[i].equals(SOURCE_DRM_NAMING_CONTEXT)) {
+ mSourceDrmNamingContext = args[i + 1];
+ mDrmNamingContextNameValuePairs++;
+ } else if (args[i].equals(TARGET_DRM_NAMING_CONTEXT)) {
+ mTargetDrmNamingContext = args[i + 1];
+ mDrmNamingContextNameValuePairs++;
+ } else if (args[i].equals(PROCESS_REQUESTS_AND_KEY_RECORDS_ONLY)) {
+ mProcessRequestsAndKeyRecordsOnlyFlag = true;
+ i -= 1;
+ } else {
+ System.err.println("ERROR: Unknown argument '"
+ + args[i]
+ + "'!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ }
+ }
+
+ // Verify that correct number of valid mandatory
+ // arguments were submitted to the program
+ if (mMandatoryNameValuePairs != MANDATORY_NAME_VALUE_PAIRS ||
+ mDrmtoolCfgFilename == null ||
+ mDrmtoolCfgFilename.length() == 0 ||
+ mSourceLdifFilename == null ||
+ mSourceLdifFilename.length() == 0 ||
+ mTargetLdifFilename == null ||
+ mTargetLdifFilename.length() == 0 ||
+ mLogFilename == null ||
+ mLogFilename.length() == 0) {
+ System.err.println("ERROR: Missing mandatory arguments!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ } else {
+ // Check for a valid DRMTOOL config file
+ cfgFile = new File(mDrmtoolCfgFilename);
+ if (!cfgFile.exists() ||
+ !cfgFile.isFile() ||
+ (cfgFile.length() == 0)) {
+ System.err.println("ERROR: '"
+ + mDrmtoolCfgFilename
+ + "' does NOT exist, is NOT a file, "
+ + "or is empty!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ }
+
+ // Check for a valid source LDIF file
+ sourceFile = new File(mSourceLdifFilename);
+ if (!sourceFile.exists() ||
+ !sourceFile.isFile() ||
+ (sourceFile.length() == 0)) {
+ System.err.println("ERROR: '"
+ + mSourceLdifFilename
+ + "' does NOT exist, is NOT a file, "
+ + "or is empty!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ }
+
+ // Check that the target LDIF file does NOT exist
+ targetFile = new File(mTargetLdifFilename);
+ if (targetFile.exists()) {
+ System.err.println("ERROR: '"
+ + mTargetLdifFilename
+ + "' ALREADY exists!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ }
+
+ // Check that the log file does NOT exist
+ logFile = new File(mLogFilename);
+ if (logFile.exists()) {
+ System.err.println("ERROR: '"
+ + mLogFilename
+ + "' ALREADY exists!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ }
+
+ // Mark the 'Mandatory' flag true
+ mMandatoryFlag = true;
+ }
+
+ // Check to see that if the 'Rewrap' command-line options were
+ // specified, that they are all present and accounted for
+ if (mRewrapNameValuePairs > 0) {
+ if (mRewrapNameValuePairs != REWRAP_NAME_VALUE_PAIRS ||
+ mSourcePKISecurityDatabasePath == null ||
+ mSourcePKISecurityDatabasePath.length() == 0 ||
+ mSourceStorageTokenName == null ||
+ mSourceStorageTokenName.length() == 0 ||
+ mSourceStorageCertNickname == null ||
+ mSourceStorageCertNickname.length() == 0 ||
+ mTargetStorageCertificateFilename == null ||
+ mTargetStorageCertificateFilename.length() == 0) {
+ System.err.println("ERROR: Missing 'Rewrap' arguments!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ } else {
+ // Check for a valid path to the PKI security databases
+ sourceDBPath = new File(mSourcePKISecurityDatabasePath);
+ if (!sourceDBPath.exists() ||
+ !sourceDBPath.isDirectory()) {
+ System.err.println("ERROR: '"
+ + mSourcePKISecurityDatabasePath
+ + "' does NOT exist or "
+ + "'is NOT a directory!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ }
+
+ // Check for a valid target storage certificate file
+ targetStorageCertFile = new File(
+ mTargetStorageCertificateFilename);
+ if (!targetStorageCertFile.exists() ||
+ !targetStorageCertFile.isFile() ||
+ (targetStorageCertFile.length() == 0)) {
+ System.err.println("ERROR: '"
+ + mTargetStorageCertificateFilename
+ + "' does NOT exist, is NOT a file, "
+ + "or is empty!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ }
+
+ // Mark the 'Rewrap' flag true
+ mRewrapFlag = true;
+ }
+ }
+
+ // Check to see that BOTH append 'ID Offset' command-line options
+ // and remove 'ID Offset' command-line options were NOT specified
+ // since these two command-line options are mutually exclusive!
+ if ((mAppendIdOffsetNameValuePairs > 0) &&
+ (mRemoveIdOffsetNameValuePairs > 0)) {
+ System.err.println("ERROR: The 'append ID Offset' option "
+ + "and the 'remove ID Offset' option are "
+ + "mutually exclusive!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ }
+
+ // Check to see that if the 'append ID Offset' command-line options
+ // were specified, that they are all present and accounted for
+ if (mAppendIdOffsetNameValuePairs > 0) {
+ if (mAppendIdOffsetNameValuePairs == ID_OFFSET_NAME_VALUE_PAIRS &&
+ append_id_offset != null &&
+ append_id_offset.length() != 0) {
+ try {
+ if (!append_id_offset.matches("[0-9]++")) {
+ System.err.println("ERROR: '"
+ + append_id_offset
+ + "' contains non-numeric "
+ + "characters!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ } else {
+ mAppendIdOffset = new BigInteger(
+ append_id_offset);
+
+ // Mark the 'append ID Offset' flag true
+ mAppendIdOffsetFlag = true;
+ }
+ } catch (PatternSyntaxException exAppendPattern) {
+ System.err.println("ERROR: append_id_offset='"
+ + append_id_offset
+ + "' PatternSyntaxException: '"
+ + exAppendPattern.toString()
+ + "'"
+ + NEWLINE);
+ System.exit(0);
+ }
+ } else {
+ System.err.println("ERROR: Missing "
+ + "'append ID Offset' arguments!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ }
+ }
+
+ // Check to see that if the 'remove ID Offset' command-line options
+ // were specified, that they are all present and accounted for
+ if (mRemoveIdOffsetNameValuePairs > 0) {
+ if (mRemoveIdOffsetNameValuePairs == ID_OFFSET_NAME_VALUE_PAIRS &&
+ remove_id_offset != null &&
+ remove_id_offset.length() != 0) {
+ try {
+ if (!remove_id_offset.matches("[0-9]++")) {
+ System.err.println("ERROR: '"
+ + remove_id_offset
+ + "' contains non-numeric "
+ + "characters!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ } else {
+ mRemoveIdOffset = new BigInteger(
+ remove_id_offset);
+
+ // Mark the 'remove ID Offset' flag true
+ mRemoveIdOffsetFlag = true;
+ }
+ } catch (PatternSyntaxException exRemovePattern) {
+ System.err.println("ERROR: remove_id_offset='"
+ + remove_id_offset
+ + "' PatternSyntaxException: '"
+ + exRemovePattern.toString()
+ + "'"
+ + NEWLINE);
+ System.exit(0);
+ }
+ } else {
+ System.err.println("ERROR: Missing "
+ + "'remove ID Offset' arguments!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ }
+ }
+
+ // Make certain that at least one of the "Rewrap", "Append ID Offset",
+ // or "Remove ID Offset" options has been specified
+ if (!mRewrapFlag &&
+ !mAppendIdOffsetFlag &&
+ !mRemoveIdOffsetFlag) {
+ System.err.println("ERROR: At least one of the 'rewrap', "
+ + "'append ID Offset', or 'remove ID Offset' "
+ + "options MUST be specified!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ }
+
+ // Check to see that if the OPTIONAL
+ // 'PKI Security Database Password File'
+ // command-line options were specified,
+ // that they are all present and accounted for
+ if (mPKISecurityDatabasePwdfileNameValuePairs > 0) {
+ if (mPKISecurityDatabasePwdfileNameValuePairs !=
+ PWDFILE_NAME_VALUE_PAIRS ||
+ mSourcePKISecurityDatabasePwdfile == null ||
+ mSourcePKISecurityDatabasePwdfile.length() == 0) {
+ System.err.println("ERROR: Missing 'Password File' "
+ + "arguments!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ } else {
+ if (mRewrapFlag) {
+ // Check for a valid source PKI
+ // security database password file
+ sourceDBPwdfile = new
+ File(mSourcePKISecurityDatabasePwdfile);
+ if (!sourceDBPwdfile.exists() ||
+ !sourceDBPwdfile.isFile() ||
+ (sourceDBPwdfile.length() == 0)) {
+ System.err.println("ERROR: '"
+ + mSourcePKISecurityDatabasePwdfile
+ + "' does NOT exist, is NOT a file, "
+ + "or is empty!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ }
+
+ use_PKI_security_database_pwdfile = SPACE
+ + SOURCE_NSS_DB_PWDFILE
+ + SPACE
+ + TIC
+ + mSourcePKISecurityDatabasePwdfile
+ + TIC;
+
+ mSourcePKISecurityDatabasePwdfileMessage = SPACE
+ + PLUS
+ + SPACE
+ + DRM_LDIF_USED_PWDFILE_MESSAGE;
+
+ // Mark the 'Password File' flag true
+ mPwdfileFlag = true;
+ } else {
+ System.err.println("ERROR: The "
+ + TIC
+ + SOURCE_NSS_DB_PWDFILE
+ + TIC
+ + " option is ONLY valid when "
+ + "performing rewrapping."
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ }
+ }
+ } else {
+ use_PKI_security_database_pwdfile = "";
+ mSourcePKISecurityDatabasePwdfileMessage = "";
+ }
+
+ // Check to see that if the OPTIONAL 'DRM Naming Context' command-line
+ // options were specified, that they are all present and accounted for
+ if (mDrmNamingContextNameValuePairs > 0) {
+ if (mDrmNamingContextNameValuePairs !=
+ NAMING_CONTEXT_NAME_VALUE_PAIRS ||
+ mSourceDrmNamingContext == null ||
+ mSourceDrmNamingContext.length() == 0 ||
+ mTargetDrmNamingContext == null ||
+ mTargetDrmNamingContext.length() == 0) {
+ System.err.println("ERROR: Both 'source DRM naming context' "
+ + "and 'target DRM naming context' "
+ + "options MUST be specified!"
+ + NEWLINE);
+ printUsage();
+ System.exit(0);
+ } else {
+ process_drm_naming_context_fields = SPACE
+ + SOURCE_DRM_NAMING_CONTEXT
+ + SPACE
+ + TIC
+ + mSourceDrmNamingContext
+ + TIC
+ + SPACE
+ + TARGET_DRM_NAMING_CONTEXT
+ + SPACE
+ + TIC
+ + mTargetDrmNamingContext
+ + TIC;
+
+ mDrmNamingContextMessage = SPACE
+ + PLUS
+ + SPACE
+ + DRM_LDIF_SOURCE_NAME_CONTEXT_MESSAGE
+ + mSourceDrmNamingContext
+ + DRM_LDIF_TARGET_NAME_CONTEXT_MESSAGE
+ + mTargetDrmNamingContext
+ + TIC;
+
+ // Mark the 'DRM Naming Contexts' flag true
+ mDrmNamingContextsFlag = true;
+ }
+ } else {
+ process_drm_naming_context_fields = "";
+ mDrmNamingContextMessage = "";
+ }
+
+ // Check for OPTIONAL "Process Requests and Key Records ONLY" option
+ if (mProcessRequestsAndKeyRecordsOnlyFlag) {
+ process_requests_and_key_records_only = SPACE
+ + PROCESS_REQUESTS_AND_KEY_RECORDS_ONLY;
+ mProcessRequestsAndKeyRecordsOnlyMessage = SPACE + PLUS + SPACE +
+ DRM_LDIF_PROCESS_REQUESTS_AND_KEY_RECORDS_ONLY_MESSAGE;
+ } else {
+ process_requests_and_key_records_only = "";
+ mProcessRequestsAndKeyRecordsOnlyMessage = "";
+ }
+
+ // Enable logging process . . .
+ open_log(mLogFilename);
+
+ // Begin logging progress . . .
+ if (mRewrapFlag && mAppendIdOffsetFlag) {
+ log("BEGIN \""
+ + DRM_TOOL + SPACE
+ + DRMTOOL_CFG_FILE + SPACE
+ + mDrmtoolCfgFilename + SPACE
+ + SOURCE_LDIF_FILE + SPACE
+ + mSourceLdifFilename + SPACE
+ + TARGET_LDIF_FILE + SPACE
+ + mTargetLdifFilename + SPACE
+ + LOG_FILE + SPACE
+ + mLogFilename + SPACE
+ + SOURCE_NSS_DB_PATH + SPACE
+ + mSourcePKISecurityDatabasePath + SPACE
+ + SOURCE_STORAGE_TOKEN_NAME + SPACE
+ + TIC + mSourceStorageTokenName + TIC + SPACE
+ + SOURCE_STORAGE_CERT_NICKNAME + SPACE
+ + TIC + mSourceStorageCertNickname + TIC + SPACE
+ + TARGET_STORAGE_CERTIFICATE_FILE + SPACE
+ + mTargetStorageCertificateFilename + SPACE
+ + use_PKI_security_database_pwdfile
+ + APPEND_ID_OFFSET + SPACE
+ + append_id_offset
+ + process_drm_naming_context_fields
+ + process_requests_and_key_records_only
+ + "\" . . ."
+ + NEWLINE, true);
+ } else if (mRewrapFlag && mRemoveIdOffsetFlag) {
+ log("BEGIN \""
+ + DRM_TOOL + SPACE
+ + DRMTOOL_CFG_FILE + SPACE
+ + mDrmtoolCfgFilename + SPACE
+ + SOURCE_LDIF_FILE + SPACE
+ + mSourceLdifFilename + SPACE
+ + TARGET_LDIF_FILE + SPACE
+ + mTargetLdifFilename + SPACE
+ + LOG_FILE + SPACE
+ + mLogFilename + SPACE
+ + SOURCE_NSS_DB_PATH + SPACE
+ + mSourcePKISecurityDatabasePath + SPACE
+ + SOURCE_STORAGE_TOKEN_NAME + SPACE
+ + TIC + mSourceStorageTokenName + TIC + SPACE
+ + SOURCE_STORAGE_CERT_NICKNAME + SPACE
+ + TIC + mSourceStorageCertNickname + TIC + SPACE
+ + TARGET_STORAGE_CERTIFICATE_FILE + SPACE
+ + mTargetStorageCertificateFilename + SPACE
+ + use_PKI_security_database_pwdfile
+ + REMOVE_ID_OFFSET + SPACE
+ + remove_id_offset
+ + process_drm_naming_context_fields
+ + process_requests_and_key_records_only
+ + "\" . . ."
+ + NEWLINE, true);
+ } else if (mRewrapFlag) {
+ log("BEGIN \""
+ + DRM_TOOL + SPACE
+ + DRMTOOL_CFG_FILE + SPACE
+ + mDrmtoolCfgFilename + SPACE
+ + SOURCE_LDIF_FILE + SPACE
+ + mSourceLdifFilename + SPACE
+ + TARGET_LDIF_FILE + SPACE
+ + mTargetLdifFilename + SPACE
+ + LOG_FILE + SPACE
+ + mLogFilename + SPACE
+ + SOURCE_NSS_DB_PATH + SPACE
+ + mSourcePKISecurityDatabasePath + SPACE
+ + SOURCE_STORAGE_TOKEN_NAME + SPACE
+ + TIC + mSourceStorageTokenName + TIC + SPACE
+ + SOURCE_STORAGE_CERT_NICKNAME + SPACE
+ + TIC + mSourceStorageCertNickname + TIC + SPACE
+ + TARGET_STORAGE_CERTIFICATE_FILE + SPACE
+ + mTargetStorageCertificateFilename
+ + use_PKI_security_database_pwdfile
+ + process_drm_naming_context_fields
+ + process_requests_and_key_records_only
+ + "\" . . ."
+ + NEWLINE, true);
+ } else if (mAppendIdOffsetFlag) {
+ log("BEGIN \""
+ + DRM_TOOL + SPACE
+ + DRMTOOL_CFG_FILE + SPACE
+ + mDrmtoolCfgFilename + SPACE
+ + SOURCE_LDIF_FILE + SPACE
+ + mSourceLdifFilename + SPACE
+ + TARGET_LDIF_FILE + SPACE
+ + mTargetLdifFilename + SPACE
+ + LOG_FILE + SPACE
+ + mLogFilename + SPACE
+ + APPEND_ID_OFFSET + SPACE
+ + append_id_offset
+ + process_drm_naming_context_fields
+ + process_requests_and_key_records_only
+ + "\" . . ."
+ + NEWLINE, true);
+ } else if (mRemoveIdOffsetFlag) {
+ log("BEGIN \""
+ + DRM_TOOL + SPACE
+ + DRMTOOL_CFG_FILE + SPACE
+ + mDrmtoolCfgFilename + SPACE
+ + SOURCE_LDIF_FILE + SPACE
+ + mSourceLdifFilename + SPACE
+ + TARGET_LDIF_FILE + SPACE
+ + mTargetLdifFilename + SPACE
+ + LOG_FILE + SPACE
+ + mLogFilename + SPACE
+ + REMOVE_ID_OFFSET + SPACE
+ + remove_id_offset
+ + process_drm_naming_context_fields
+ + process_requests_and_key_records_only
+ + "\" . . ."
+ + NEWLINE, true);
+ }
+
+ // Process the DRMTOOL config file
+ success = process_drmtool_config_file();
+ if (!success) {
+ log("FAILED processing drmtool config file!"
+ + NEWLINE, true);
+ } else {
+ log("SUCCESSFULLY processed drmtool config file!"
+ + NEWLINE, true);
+
+ // Convert the source LDIF file to a target LDIF file
+ success = convert_source_ldif_to_target_ldif();
+ if (!success) {
+ log("FAILED converting source LDIF file --> target LDIF file!"
+ + NEWLINE, true);
+ } else {
+ log("SUCCESSFULLY converted source LDIF file --> "
+ + "target LDIF file!"
+ + NEWLINE, true);
+ }
+ }
+
+ // Finish logging progress
+ if (mRewrapFlag && mAppendIdOffsetFlag) {
+ log("FINISHED \""
+ + DRM_TOOL + SPACE
+ + DRMTOOL_CFG_FILE + SPACE
+ + mDrmtoolCfgFilename + SPACE
+ + SOURCE_LDIF_FILE + SPACE
+ + mSourceLdifFilename + SPACE
+ + TARGET_LDIF_FILE + SPACE
+ + mTargetLdifFilename + SPACE
+ + LOG_FILE + SPACE
+ + mLogFilename + SPACE
+ + SOURCE_NSS_DB_PATH + SPACE
+ + mSourcePKISecurityDatabasePath + SPACE
+ + SOURCE_STORAGE_TOKEN_NAME + SPACE
+ + TIC + mSourceStorageTokenName + TIC + SPACE
+ + SOURCE_STORAGE_CERT_NICKNAME + SPACE
+ + TIC + mSourceStorageCertNickname + TIC + SPACE
+ + TARGET_STORAGE_CERTIFICATE_FILE + SPACE
+ + mTargetStorageCertificateFilename + SPACE
+ + use_PKI_security_database_pwdfile
+ + APPEND_ID_OFFSET + SPACE
+ + append_id_offset
+ + process_drm_naming_context_fields
+ + process_requests_and_key_records_only
+ + "\"."
+ + NEWLINE, true);
+ } else if (mRewrapFlag && mRemoveIdOffsetFlag) {
+ log("FINISHED \""
+ + DRM_TOOL + SPACE
+ + DRMTOOL_CFG_FILE + SPACE
+ + mDrmtoolCfgFilename + SPACE
+ + SOURCE_LDIF_FILE + SPACE
+ + mSourceLdifFilename + SPACE
+ + TARGET_LDIF_FILE + SPACE
+ + mTargetLdifFilename + SPACE
+ + LOG_FILE + SPACE
+ + mLogFilename + SPACE
+ + SOURCE_NSS_DB_PATH + SPACE
+ + mSourcePKISecurityDatabasePath + SPACE
+ + SOURCE_STORAGE_TOKEN_NAME + SPACE
+ + TIC + mSourceStorageTokenName + TIC + SPACE
+ + SOURCE_STORAGE_CERT_NICKNAME + SPACE
+ + TIC + mSourceStorageCertNickname + TIC + SPACE
+ + TARGET_STORAGE_CERTIFICATE_FILE + SPACE
+ + mTargetStorageCertificateFilename + SPACE
+ + use_PKI_security_database_pwdfile
+ + REMOVE_ID_OFFSET + SPACE
+ + remove_id_offset
+ + process_drm_naming_context_fields
+ + process_requests_and_key_records_only
+ + "\"."
+ + NEWLINE, true);
+ } else if (mRewrapFlag) {
+ log("FINISHED \""
+ + DRM_TOOL + SPACE
+ + DRMTOOL_CFG_FILE + SPACE
+ + mDrmtoolCfgFilename + SPACE
+ + SOURCE_LDIF_FILE + SPACE
+ + mSourceLdifFilename + SPACE
+ + TARGET_LDIF_FILE + SPACE
+ + mTargetLdifFilename + SPACE
+ + LOG_FILE + SPACE
+ + mLogFilename + SPACE
+ + SOURCE_NSS_DB_PATH + SPACE
+ + mSourcePKISecurityDatabasePath + SPACE
+ + SOURCE_STORAGE_TOKEN_NAME + SPACE
+ + TIC + mSourceStorageTokenName + TIC + SPACE
+ + SOURCE_STORAGE_CERT_NICKNAME + SPACE
+ + TIC + mSourceStorageCertNickname + TIC + SPACE
+ + TARGET_STORAGE_CERTIFICATE_FILE + SPACE
+ + mTargetStorageCertificateFilename
+ + use_PKI_security_database_pwdfile
+ + process_drm_naming_context_fields
+ + process_requests_and_key_records_only
+ + "\"."
+ + NEWLINE, true);
+ } else if (mAppendIdOffsetFlag) {
+ log("FINISHED \""
+ + DRM_TOOL + SPACE
+ + DRMTOOL_CFG_FILE + SPACE
+ + mDrmtoolCfgFilename + SPACE
+ + SOURCE_LDIF_FILE + SPACE
+ + mSourceLdifFilename + SPACE
+ + TARGET_LDIF_FILE + SPACE
+ + mTargetLdifFilename + SPACE
+ + LOG_FILE + SPACE
+ + mLogFilename + SPACE
+ + APPEND_ID_OFFSET + SPACE
+ + append_id_offset
+ + process_drm_naming_context_fields
+ + process_requests_and_key_records_only
+ + "\"."
+ + NEWLINE, true);
+ } else if (mRemoveIdOffsetFlag) {
+ log("FINISHED \""
+ + DRM_TOOL + SPACE
+ + DRMTOOL_CFG_FILE + SPACE
+ + mDrmtoolCfgFilename + SPACE
+ + SOURCE_LDIF_FILE + SPACE
+ + mSourceLdifFilename + SPACE
+ + TARGET_LDIF_FILE + SPACE
+ + mTargetLdifFilename + SPACE
+ + LOG_FILE + SPACE
+ + mLogFilename + SPACE
+ + REMOVE_ID_OFFSET + SPACE
+ + remove_id_offset
+ + process_drm_naming_context_fields
+ + process_requests_and_key_records_only
+ + "\"."
+ + NEWLINE, true);
+ }
+
+ // Shutdown logging process
+ close_log(mLogFilename);
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/ExtJoiner.java b/base/java-tools/src/com/netscape/cmstools/ExtJoiner.java
new file mode 100644
index 000000000..48f180add
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/ExtJoiner.java
@@ -0,0 +1,104 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import com.netscape.cmsutil.util.Utils;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+
+/**
+ * This program joins a sequence of extensions together
+ * so that the final output can be used in configuration
+ * wizard for specifing extra extensions in default
+ * certificates (i.e. CA certificate, SSL certificate).
+ *
+ * Usage:
+ *
+ * <pre>
+ * ExtJoiner \
+ * &lt;ext_file0&gt; &lt;ext_file1&gt; ... &lt;ext_fileN&gt;
+ *
+ * where,
+ * &lt;ext_file&gt; is a file that has the base64
+ * encoded DER encoding of an X509 Extension
+ *
+ * ExtensionSequence ::= SEQUENCE OF Extension;
+ *
+ * 0 30 142: SEQUENCE {
+ * 3 30 69: SEQUENCE {
+ * 5 06 3: OBJECT IDENTIFIER issuerAltName (2 5 29 18)
+ * 10 04 62: OCTET STRING
+ * : 30 3C 82 01 61 82 01 61 A4 10 30 0E 31 0C 30 0A
+ * : 06 03 55 04 03 13 03 64 73 61 87 04 01 01 01 01
+ * : 86 01 61 81 14 74 68 6F 6D 61 73 6B 40 6E 65 74
+ * : 73 63 61 70 65 2E 63 6F 6D 88 03 29 01 01
+ * : }
+ * 74 30 69: SEQUENCE {
+ * 76 06 3: OBJECT IDENTIFIER subjectAltName (2 5 29 17)
+ * 81 04 62: OCTET STRING
+ * : 30 3C 82 01 61 82 01 61 A4 10 30 0E 31 0C 30 0A
+ * : 06 03 55 04 03 13 03 64 73 61 87 04 01 01 01 01
+ * : 86 01 61 81 14 74 68 6F 6D 61 73 6B 40 6E 65 74
+ * : 73 63 61 70 65 2E 63 6F 6D 88 03 29 01 01
+ * : }
+ * : }
+ * </pre>
+ *
+ * @version $Revision$, $Date$
+ */
+public class ExtJoiner {
+
+ public static void main(String args[]) {
+ try {
+ if (args.length == 0) {
+ System.out.println("Usage: ExtJoiner <ext_file0> <ext_file1> ... <ext_fileN>");
+ System.exit(0);
+ }
+ DerValue exts[] = new DerValue[args.length];
+
+ for (int i = 0; i < args.length; i++) {
+ byte data[] = getFileData(args[i]);
+
+ exts[i] = new DerValue(data);
+ }
+ DerOutputStream out = new DerOutputStream();
+
+ out.putSequence(exts);
+ System.out.println(Utils.base64encode(out.toByteArray()));
+ } catch (IOException e) {
+ System.out.println(e.toString());
+ }
+ }
+
+ public static byte[] getFileData(String fileName)
+ throws IOException {
+ FileInputStream fis = new FileInputStream(fileName);
+
+ byte data[] = new byte[fis.available()];
+ try {
+ fis.read(data);
+ } finally {
+ fis.close();
+ }
+ return Utils.base64decode(new String(data));
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/GenExtKeyUsage.java b/base/java-tools/src/com/netscape/cmstools/GenExtKeyUsage.java
new file mode 100644
index 000000000..35072aae3
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/GenExtKeyUsage.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) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.util.Vector;
+
+import com.netscape.cmsutil.util.Utils;
+
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.Extension;
+
+/**
+ * Generates a DER-encoded Extended Key Usage extension.
+ * The first parameter is the criticality of the extension, true or false.
+ * The OIDs to be included in the extension are passed as command-line
+ * arguments. The OIDs are described in RFC 2459. For example,
+ * the OID for code signing is 1.3.6.1.5.5.7.3.3.
+ *
+ * @version $Revision$, $Date$
+ */
+public class GenExtKeyUsage {
+
+ public static void main(String[] args) {
+ try {
+ if (args.length < 2) {
+ System.out.println("Usage: GenExtKeyUsage [true|false] <OID> ...");
+ System.exit(-1);
+ }
+
+ boolean critical = false;
+
+ if (args[0].equalsIgnoreCase("true")) {
+ critical = true;
+ } else if (args[0].equalsIgnoreCase("false")) {
+ critical = false;
+ } else {
+ System.out.println("Usage: GenExtKeyUsage [true|false] <OID> ...");
+ System.exit(-1);
+ }
+
+ // Generate vector of object identifiers from command line
+ Vector<ObjectIdentifier> oids = new Vector<ObjectIdentifier>();
+
+ for (int i = 1; i < args.length; i++) {
+ ObjectIdentifier oid = new ObjectIdentifier(args[i]);
+
+ oids.addElement(oid);
+ }
+
+ // encode all the object identifiers to the DerOutputStream
+ DerOutputStream contents = new DerOutputStream();
+
+ for (int i = 0; i < oids.size(); i++) {
+ contents.putOID(oids.elementAt(i));
+ }
+
+ // stuff the object identifiers into a SEQUENCE
+ DerOutputStream seq = new DerOutputStream();
+
+ seq.write(DerValue.tag_Sequence, contents);
+
+ // encode the SEQUENCE in an octet string
+ DerOutputStream octetString = new DerOutputStream();
+
+ octetString.putOctetString(seq.toByteArray());
+
+ // Construct an extension
+ ObjectIdentifier extKeyUsageOID = new ObjectIdentifier("2.5.29.37");
+ Extension extn = new Extension(extKeyUsageOID, critical,
+ octetString.toByteArray());
+ DerOutputStream extdos = new DerOutputStream();
+
+ extn.encode(extdos);
+
+ // BASE64 encode the whole thing and write it to stdout
+
+ System.out.println(Utils.base64encode(extdos.toByteArray()));
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/GenIssuerAltNameExt.java b/base/java-tools/src/com/netscape/cmstools/GenIssuerAltNameExt.java
new file mode 100644
index 000000000..5c905278f
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/GenIssuerAltNameExt.java
@@ -0,0 +1,141 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.ByteArrayOutputStream;
+import java.net.InetAddress;
+
+import com.netscape.cmsutil.util.Utils;
+
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.DNSName;
+import netscape.security.x509.GeneralNameInterface;
+import netscape.security.x509.GeneralNames;
+import netscape.security.x509.IPAddressName;
+import netscape.security.x509.IssuerAlternativeNameExtension;
+import netscape.security.x509.OIDName;
+import netscape.security.x509.RFC822Name;
+import netscape.security.x509.URIName;
+import netscape.security.x509.X500Name;
+
+/**
+ * This program generates an issuer alternative name extension
+ * in base-64 encoding. The encoding output can be used with
+ * the configuration wizard.
+ *
+ * Usage:
+ *
+ * <pre>
+ * GenIssuerAltNameExt \
+ * &lt;general_type0&gt; &lt;general_name0&gt; ... &lt;general_typeN&gt; &lt;general_nameN&gt;
+ *
+ * where,
+ * &lt;general_type&gt; can be one of the following string:
+ * DNSName
+ * EDIPartyName
+ * IPAddressName
+ * URIName
+ * RFC822Name
+ * OIDName
+ * X500Name
+ * &lt;general_name&gt; is string
+ * </pre>
+ *
+ * @version $Revision$, $Date$
+ */
+public class GenIssuerAltNameExt {
+
+ public static void main(String args[]) {
+ try {
+ if ((args.length == 0) || (args.length % 2 != 0)) {
+ doUsage();
+ System.exit(0);
+ }
+ GeneralNames gns = new GeneralNames();
+
+ for (int i = 0; i < args.length; i += 2) {
+ GeneralNameInterface gni =
+ buildGeneralNameInterface(
+ args[i], args[i + 1]);
+
+ gns.addElement(gni);
+ }
+
+ IssuerAlternativeNameExtension sane =
+ new IssuerAlternativeNameExtension(gns);
+
+ output(sane);
+ } catch (Exception e) {
+ System.out.println(e.toString());
+ }
+ }
+
+ public static void output(IssuerAlternativeNameExtension ext)
+ throws Exception {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ ext.encode(os);
+
+ System.out.println(
+ Utils.base64encode(os.toByteArray())
+ );
+ }
+
+ public static void doUsage() {
+ System.out.println();
+ System.out.println(
+ "Usage: GenIssuerAltNameExt <general_type0> <general_name0> ... <general_typeN> <general_nameN>");
+ System.out.println("where,");
+ System.out.println("<general_type> can be one of the following string:");
+ System.out.println("\tDNSName");
+ System.out.println("\tEDIPartyName");
+ System.out.println("\tIPAddressName");
+ System.out.println("\tURIName");
+ System.out.println("\tRFC822Name");
+ System.out.println("\tOIDName");
+ System.out.println("\tX500Name");
+ System.out.println("<general_name> is a string");
+ }
+
+ public static GeneralNameInterface buildGeneralNameInterface(
+ String type, String value) throws Exception {
+ if (type.equals("DNSName")) {
+ return new DNSName(value);
+ } else if (type.equals("EDIPartyName")) {
+ return new DNSName(value);
+ } else if (type.equals("IPAddressName")) {
+ InetAddress addr = InetAddress.getByName(value);
+
+ return new IPAddressName(addr.getAddress());
+ } else if (type.equals("URIName")) {
+ return new URIName(value);
+ } else if (type.equals("OIDName")) {
+ return new OIDName(new ObjectIdentifier(value));
+ } else if (type.equals("RFC822Name")) {
+ return new RFC822Name(value);
+ } else if (type.equals("X500Name")) {
+ return new X500Name(value);
+ } else {
+ System.out.println("Error: unknown general_type " +
+ type);
+ doUsage();
+ System.exit(0);
+ return null;
+ }
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/GenSubjectAltNameExt.java b/base/java-tools/src/com/netscape/cmstools/GenSubjectAltNameExt.java
new file mode 100644
index 000000000..35e07f772
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/GenSubjectAltNameExt.java
@@ -0,0 +1,141 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.ByteArrayOutputStream;
+import java.net.InetAddress;
+
+import com.netscape.cmsutil.util.Utils;
+
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.DNSName;
+import netscape.security.x509.GeneralNameInterface;
+import netscape.security.x509.GeneralNames;
+import netscape.security.x509.IPAddressName;
+import netscape.security.x509.OIDName;
+import netscape.security.x509.RFC822Name;
+import netscape.security.x509.SubjectAlternativeNameExtension;
+import netscape.security.x509.URIName;
+import netscape.security.x509.X500Name;
+
+/**
+ * This program generates an subject alternative name extension
+ * in base-64 encoding. The encoding output can be used with
+ * the configuration wizard.
+ *
+ * Usage:
+ *
+ * <pre>
+ * GenSubjectAltNameExt \
+ * &lt;general_type0&gt; &lt;general_name0&gt; ... &lt;general_typeN&gt; &lt;general_nameN&gt;
+ *
+ * where,
+ * &lt;general_type&gt; can be one of the following string:
+ * DNSName
+ * EDIPartyName
+ * IPAddressName
+ * URIName
+ * RFC822Name
+ * OIDName
+ * X500Name
+ * &lt;general_name&gt; is string
+ * </pre>
+ *
+ * @version $Revision$, $Date$
+ */
+public class GenSubjectAltNameExt {
+
+ public static void main(String args[]) {
+ try {
+ if ((args.length == 0) || (args.length % 2 != 0)) {
+ doUsage();
+ System.exit(0);
+ }
+ GeneralNames gns = new GeneralNames();
+
+ for (int i = 0; i < args.length; i += 2) {
+ GeneralNameInterface gni =
+ buildGeneralNameInterface(
+ args[i], args[i + 1]);
+
+ gns.addElement(gni);
+ }
+
+ SubjectAlternativeNameExtension sane =
+ new SubjectAlternativeNameExtension(gns);
+
+ output(sane);
+ } catch (Exception e) {
+ System.out.println(e.toString());
+ }
+ }
+
+ public static void output(SubjectAlternativeNameExtension ext)
+ throws Exception {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ ext.encode(os);
+
+ System.out.println(
+ Utils.base64encode(os.toByteArray())
+ );
+ }
+
+ public static void doUsage() {
+ System.out.println();
+ System.out
+ .println("Usage: GenSubjectAltNameExt <general_type0> <general_name0> ... <general_typeN> <general_nameN>");
+ System.out.println("where,");
+ System.out.println("<general_type> can be one of the following string:");
+ System.out.println("\tDNSName");
+ System.out.println("\tEDIPartyName");
+ System.out.println("\tIPAddressName");
+ System.out.println("\tURIName");
+ System.out.println("\tRFC822Name");
+ System.out.println("\tOIDName");
+ System.out.println("\tX500Name");
+ System.out.println("<general_name> is a string");
+ }
+
+ public static GeneralNameInterface buildGeneralNameInterface(
+ String type, String value) throws Exception {
+ if (type.equals("DNSName")) {
+ return new DNSName(value);
+ } else if (type.equals("EDIPartyName")) {
+ return new DNSName(value);
+ } else if (type.equals("IPAddressName")) {
+ InetAddress addr = InetAddress.getByName(value);
+
+ return new IPAddressName(addr.getAddress());
+ } else if (type.equals("URIName")) {
+ return new URIName(value);
+ } else if (type.equals("OIDName")) {
+ return new OIDName(new ObjectIdentifier(value));
+ } else if (type.equals("RFC822Name")) {
+ return new RFC822Name(value);
+ } else if (type.equals("X500Name")) {
+ return new X500Name(value);
+ } else {
+ System.out.println("Error: unknown general_type " +
+ type);
+ doUsage();
+ System.exit(0);
+ return null;
+ }
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/HttpClient.java b/base/java-tools/src/com/netscape/cmstools/HttpClient.java
new file mode 100644
index 000000000..c8817b52f
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/HttpClient.java
@@ -0,0 +1,403 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.StringTokenizer;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.ssl.SSLHandshakeCompletedEvent;
+import org.mozilla.jss.ssl.SSLHandshakeCompletedListener;
+import org.mozilla.jss.ssl.SSLSocket;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * This class implements a CMC Enroll client for testing.
+ *
+ * @version $Revision$, $Date$
+ */
+public class HttpClient {
+ private String _host = null;
+ private int _port = 0;
+ private boolean _secure = false;
+
+ public static final int ARGC = 1;
+ static final int cipherSuites[] = {
+ SSLSocket.SSL3_RSA_WITH_RC4_128_MD5,
+ SSLSocket.SSL3_RSA_WITH_3DES_EDE_CBC_SHA,
+ SSLSocket.SSL3_RSA_WITH_DES_CBC_SHA,
+ SSLSocket.SSL3_RSA_EXPORT_WITH_RC4_40_MD5,
+ SSLSocket.SSL3_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
+ SSLSocket.SSL3_RSA_WITH_NULL_MD5,
+ 0
+ };
+
+ public HttpClient(String host, int port, String secure)
+ throws Exception {
+ _host = host;
+ _port = port;
+ if (secure.equals("true"))
+ _secure = true;
+ }
+
+ public static byte[] getBytesFromFile(String filename) throws IOException {
+ File file = new File(filename);
+ FileInputStream is = new FileInputStream(file);
+
+ long length = file.length();
+
+ if (length > Integer.MAX_VALUE) {
+ throw new IOException("Input file " + filename +
+ " is too large. Must be smaller than " + Integer.MAX_VALUE);
+ }
+
+ byte[] bytes = new byte[(int) length];
+
+ int offset = 0;
+ int numRead = 0;
+ while (offset < bytes.length
+ && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
+ offset += numRead;
+ }
+
+ if (offset < bytes.length) {
+ throw new IOException("Could not completely read file " + filename);
+ }
+
+ is.close();
+ return bytes;
+ }
+
+ public void send(String ifilename, String ofilename, String dbdir,
+ String nickname, String password, String servlet, String clientmode)
+ throws Exception {
+ byte[] b = getBytesFromFile(ifilename);
+
+ System.out.println("Total number of bytes read = " + b.length);
+
+ DataOutputStream dos = null;
+ InputStream is = null;
+ if (_secure) {
+ try {
+ CryptoManager.InitializationValues vals =
+ new CryptoManager.InitializationValues(dbdir, "", "", "secmod.db");
+ CryptoManager.initialize(vals);
+ SSLSocket socket = new SSLSocket(_host, _port);
+ int i;
+
+ for (i = SSLSocket.SSL2_RC4_128_WITH_MD5; i <= SSLSocket.SSL2_RC2_128_CBC_EXPORT40_WITH_MD5; ++i) {
+ try {
+ socket.setCipherPreference(i, true);
+ } catch (SocketException e) {
+ }
+ }
+ //skip SSL_EN_IDEA_128_EDE3_CBC_WITH_MD5
+ for (i = SSLSocket.SSL2_DES_64_CBC_WITH_MD5; i <= SSLSocket.SSL2_DES_192_EDE3_CBC_WITH_MD5; ++i) {
+ try {
+ socket.setCipherPreference(i, true);
+ } catch (SocketException e) {
+ }
+ }
+ for (i = 0; cipherSuites[i] != 0; ++i) {
+ try {
+ socket.setCipherPreference(cipherSuites[i], true);
+ } catch (SocketException e) {
+ }
+ }
+ SSLHandshakeCompletedListener listener = new ClientHandshakeCB(this);
+ socket.addHandshakeCompletedListener(listener);
+
+ if (clientmode != null && clientmode.equals("true")) {
+ CryptoManager cm = CryptoManager.getInstance();
+ CryptoToken token = cm.getInternalKeyStorageToken();
+ Password pass = new Password(password.toCharArray());
+ token.login(pass);
+ X509Certificate cert = cm.findCertByNickname(nickname);
+ if (cert == null)
+ System.out.println("client cert is null");
+ else
+ System.out.println("client cert is not null");
+ socket.setUseClientMode(true);
+ socket.setClientCertNickname(nickname);
+ }
+
+ socket.forceHandshake();
+ dos = new DataOutputStream(socket.getOutputStream());
+ is = socket.getInputStream();
+ } catch (Exception e) {
+ System.out.println("Exception: " + e.toString());
+ return;
+ }
+ } else {
+ Socket socket = new Socket(_host, _port);
+ dos = new DataOutputStream(socket.getOutputStream());
+ is = socket.getInputStream();
+ }
+
+ // send request
+ if (servlet == null) {
+ System.out.println("Missing servlet name.");
+ printUsage();
+ } else {
+ String s = "POST " + servlet + " HTTP/1.0\r\n";
+ dos.writeBytes(s);
+ }
+ dos.writeBytes("Content-length: " + b.length + "\r\n");
+ dos.writeBytes("\r\n");
+ dos.write(b);
+ dos.flush();
+
+ FileOutputStream fof = new FileOutputStream(ofilename);
+ boolean startSaving = false;
+ int sum = 0;
+ boolean hack = false;
+ try {
+ while (true) {
+ int r = is.read();
+ if (r == -1)
+ break;
+ if (r == 10) {
+ sum++;
+ }
+ if (sum == 6) {
+ startSaving = true;
+ continue;
+ }
+ if (startSaving) {
+ if (hack) {
+ fof.write(r);
+ }
+ if (hack == false) {
+ hack = true;
+ }
+ }
+ }
+ } catch (IOException e) {
+ }
+ fof.close();
+
+ byte[] bout = getBytesFromFile(ofilename);
+ System.out.println("Total number of bytes read = " + bout.length);
+
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(bs);
+ ps.print(Utils.base64encode(bout));
+ System.out.println(bs.toString());
+
+ System.out.println("");
+ System.out.println("The response in binary format is stored in " + ofilename);
+ System.out.println("");
+ }
+
+ static void printUsage() {
+ System.out.println("");
+ System.out.println("Usage: HttpClient <configuration file>");
+ System.out.println("For example, HttpClient HttpClient.cfg");
+ System.out.println("");
+ System.out.println("The configuration file should look like as follows:");
+ System.out.println("");
+ System.out.println("#host: host name for the http server");
+ System.out.println("host=host1.a.com");
+ System.out.println("");
+ System.out.println("#port: port number");
+ System.out.println("port=1025");
+ System.out.println("");
+ System.out.println("#secure: true for secure connection, false for nonsecure connection");
+ System.out.println("secure=false");
+ System.out.println("");
+ System.out.println("#input: full path for the enrollment request, the content must be in binary format");
+ System.out.println("input=/u/doc/cmcReqCRMFBin");
+ System.out.println("");
+ System.out.println("#output: full path for the response in binary format");
+ System.out.println("output=/u/doc/cmcResp");
+ System.out.println("");
+ System.out.println("#dbdir: directory for cert8.db, key3.db and secmod.db");
+ System.out.println("#This parameter will be ignored if secure=false");
+ System.out.println("dbdir=/u/smith/.netscape");
+ System.out.println("");
+ System.out.println("#clientmode: true for client authentication, false for no client authentication");
+ System.out.println("#This parameter will be ignored if secure=false");
+ System.out.println("clientmode=false");
+ System.out.println("");
+ System.out.println("#password: password for cert8.db");
+ System.out.println("#This parameter will be ignored if secure=false and clientauth=false");
+ System.out.println("password=");
+ System.out.println("");
+ System.out.println("#nickname: nickname for client certificate");
+ System.out.println("#This parameter will be ignored if clientmode=false");
+ System.out.println("nickname=");
+ System.out.println("");
+ System.out.println("#servlet: servlet name");
+ System.out.println("servlet=/ca/profileSubmitCMCFull");
+ System.out.println("");
+ System.exit(0);
+ }
+
+ public static void main(String args[]) {
+ String host = null, portstr = null, secure = null, dbdir = null, nickname = null;
+ String password = null, ofilename = null, ifilename = null;
+ String servlet = null;
+ String clientmode = null;
+
+ System.out.println("");
+
+ // Check that the correct # of arguments were submitted to the program
+ if (args.length != (ARGC)) {
+ System.out.println("Wrong number of parameters:" + args.length);
+ printUsage();
+ }
+
+ String configFile = args[0];
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new InputStreamReader(
+ new BufferedInputStream(
+ new FileInputStream(configFile))));
+ } catch (FileNotFoundException e) {
+ System.out.println("HttpClient: can't find configuration file: " + configFile);
+ printUsage();
+ System.exit(1);
+ } catch (Exception e) {
+ e.printStackTrace();
+ printUsage();
+ return;
+ }
+
+ try {
+ String str = "";
+ while ((str = reader.readLine()) != null) {
+ str = str.trim();
+ if (!str.startsWith("#") && str.length() > 0) {
+ StringTokenizer tokenizer = new StringTokenizer(str, "=");
+ if (tokenizer.hasMoreTokens()) {
+ String name = tokenizer.nextToken();
+ String val = null;
+ if (tokenizer.countTokens() > 0)
+ val = tokenizer.nextToken();
+ if (name.equals("host")) {
+ host = val;
+ } else if (name.equals("port")) {
+ portstr = val;
+ } else if (name.equals("secure")) {
+ secure = val;
+ } else if (name.equals("dbdir")) {
+ dbdir = val;
+ } else if (name.equals("nickname")) {
+ nickname = val;
+ } else if (name.equals("password")) {
+ password = val;
+ } else if (name.equals("output")) {
+ ofilename = val;
+ } else if (name.equals("input")) {
+ ifilename = val;
+ } else if (name.equals("clientmode")) {
+ clientmode = val;
+ } else if (name.equals("servlet")) {
+ servlet = val;
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ printUsage();
+ }
+
+ if (host == null) {
+ System.out.println("Missing host name.");
+ printUsage();
+ }
+
+ if (portstr == null) {
+ System.out.println("Missing port number.");
+ printUsage();
+ }
+
+ if (servlet == null) {
+ System.out.println("Missing servlet name.");
+ printUsage();
+ }
+
+ if (ifilename == null) {
+ System.out.println("Missing input filename for the enrollment request.");
+ printUsage();
+ }
+
+ if (ofilename == null) {
+ System.out.println("Missing output filename for the response.");
+ printUsage();
+ }
+
+ int port = Integer.parseInt(portstr);
+
+ if (secure != null && secure.equals("true")) {
+ if (dbdir == null) {
+ System.out.println("Missing directory name for the cert7.db.");
+ printUsage();
+ }
+
+ if (clientmode != null && clientmode.equals("true")) {
+ if (password == null) {
+ System.out.println("Missing password for the cert7.db.");
+ printUsage();
+ }
+ if (nickname == null) {
+ System.out.println("Missing nickname for the client certificate");
+ printUsage();
+ }
+ }
+ }
+
+ try {
+ HttpClient client =
+ new HttpClient(host, port, secure);
+ client.send(ifilename, ofilename, dbdir, nickname, password, servlet, clientmode);
+ } catch (Exception e) {
+ System.out.println("Error: " + e.toString());
+ }
+ }
+
+ class ClientHandshakeCB implements SSLHandshakeCompletedListener {
+ Object sc;
+
+ public ClientHandshakeCB(Object sc) {
+ this.sc = sc;
+ }
+
+ public void handshakeCompleted(SSLHandshakeCompletedEvent event) {
+ System.out.println("handshake happened");
+ }
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/OCSPClient.java b/base/java-tools/src/com/netscape/cmstools/OCSPClient.java
new file mode 100644
index 000000000..5b9abe495
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/OCSPClient.java
@@ -0,0 +1,276 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+import java.security.MessageDigest;
+
+import netscape.security.x509.X500Name;
+import netscape.security.x509.X509CertImpl;
+import netscape.security.x509.X509Key;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.asn1.INTEGER;
+import org.mozilla.jss.asn1.NULL;
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+
+import com.netscape.cmsutil.ocsp.BasicOCSPResponse;
+import com.netscape.cmsutil.ocsp.CertID;
+import com.netscape.cmsutil.ocsp.CertStatus;
+import com.netscape.cmsutil.ocsp.GoodInfo;
+import com.netscape.cmsutil.ocsp.OCSPRequest;
+import com.netscape.cmsutil.ocsp.OCSPResponse;
+import com.netscape.cmsutil.ocsp.Request;
+import com.netscape.cmsutil.ocsp.ResponseBytes;
+import com.netscape.cmsutil.ocsp.ResponseData;
+import com.netscape.cmsutil.ocsp.RevokedInfo;
+import com.netscape.cmsutil.ocsp.SingleResponse;
+import com.netscape.cmsutil.ocsp.TBSRequest;
+import com.netscape.cmsutil.ocsp.UnknownInfo;
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * This class implements a OCSP client for testing.
+ *
+ * @version $Revision$, $Date$
+ */
+public class OCSPClient {
+ private String _host = null;
+ private int _port = 0;
+
+ public OCSPClient(String host, int port, String dbdir)
+ throws Exception {
+ _host = host;
+ _port = port;
+ CryptoManager.initialize(dbdir);
+ }
+
+ public void send(String uri, String nickname, int serialno, String output)
+ throws Exception {
+ CryptoManager manager = CryptoManager.getInstance();
+ X509Certificate caCert = manager.findCertByNickname(nickname);
+ OCSPRequest request = getOCSPRequest(caCert, serialno);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ request.encode(os);
+ byte request_data[] = os.toByteArray();
+ sendOCSPRequest(uri, _host, _port, request_data, output);
+ }
+
+ public void sendRequestData(String uri, String nickname, byte request_data[], String output)
+ throws Exception {
+ sendOCSPRequest(uri, _host, _port, request_data, output);
+ }
+
+ public OCSPRequest getOCSPRequest(X509Certificate caCert, int serialno)
+ throws Exception {
+ MessageDigest md = MessageDigest.getInstance("SHA");
+
+ // calculate issuer key hash
+ X509CertImpl x509Cert = new X509CertImpl(caCert.getEncoded());
+ X509Key x509key = (X509Key) x509Cert.getPublicKey();
+ byte issuerKeyHash[] = md.digest(x509key.getKey());
+
+ // calculate name hash
+ X500Name name = (X500Name) x509Cert.getSubjectDN();
+ byte issuerNameHash[] = md.digest(name.getEncoded());
+ // constructing the OCSP request
+ CertID certid = new CertID(
+ new AlgorithmIdentifier(
+ new OBJECT_IDENTIFIER("1.3.14.3.2.26"), new NULL()),
+ new OCTET_STRING(issuerNameHash),
+ new OCTET_STRING(issuerKeyHash),
+ new INTEGER(serialno));
+ Request request = new Request(certid, null);
+ SEQUENCE requestList = new SEQUENCE();
+ requestList.addElement(request);
+ TBSRequest tbsRequest = new TBSRequest(null, null, requestList, null);
+ return new OCSPRequest(tbsRequest, null);
+ }
+
+ public void sendOCSPRequest(String uri, String host, int port,
+ byte request_data[], String output) throws Exception {
+ Socket socket = new Socket(host, port);
+
+ // send request
+ System.out.println("URI: " + uri);
+
+ DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
+ dos.writeBytes("POST " + uri + " HTTP/1.0\r\n");
+ dos.writeBytes("Content-length: " + request_data.length + "\r\n");
+ dos.writeBytes("\r\n");
+ dos.write(request_data);
+ dos.flush();
+
+ System.out.println("Data Length: " + request_data.length);
+ System.out.println("Data: " + Utils.base64encode(request_data));
+
+ InputStream iiss = socket.getInputStream();
+ FileOutputStream fof = new FileOutputStream(output);
+ boolean startSaving = false;
+ int sum = 0;
+ boolean hack = false;
+ try {
+ while (true) {
+ int r = iiss.read();
+ if (r == -1)
+ break;
+ if (r == 10) {
+ sum++;
+ }
+ if (sum == 6) {
+ startSaving = true;
+ continue;
+ }
+ if (startSaving) {
+ if (hack) {
+ fof.write(r);
+ }
+ if (hack == false) {
+ hack = true;
+ }
+ }
+ } // while
+ } catch (IOException e) {
+ }
+ fof.close();
+
+ // parse OCSPResponse
+ BufferedInputStream fis =
+ new BufferedInputStream(
+ new FileInputStream(output));
+ OCSPResponse resp = (OCSPResponse)
+ OCSPResponse.getTemplate().decode(fis);
+ ResponseBytes bytes = resp.getResponseBytes();
+ BasicOCSPResponse basic = (BasicOCSPResponse)
+ BasicOCSPResponse.getTemplate().decode(
+ new ByteArrayInputStream(bytes.getResponse().toByteArray()));
+ ResponseData rd = basic.getResponseData();
+ for (int i = 0; i < rd.getResponseCount(); i++) {
+ SingleResponse rd1 = rd.getResponseAt(i);
+ System.out.println("CertID.serialNumber=" +
+ rd1.getCertID().getSerialNumber());
+ CertStatus status1 = rd1.getCertStatus();
+ if (status1 instanceof GoodInfo) {
+ System.out.println("CertStatus=Good");
+ }
+ if (status1 instanceof UnknownInfo) {
+ System.out.println("CertStatus=Unknown");
+ }
+ if (status1 instanceof RevokedInfo) {
+ System.out.println("CertStatus=Revoked");
+ }
+ }
+ }
+
+ public static void printUsage() {
+ System.out.println("Usage: OCSPClient " +
+ "<host> <port> <dbdir> <nickname> <serialno_or_filename> <output> <times>");
+ System.out.println(" <host> = OCSP server hostname");
+ System.out.println(" <port> = OCSP server port number");
+ System.out.println(" <dbdir> = Certificate Database Directory");
+ System.out.println(" <nickname> = Nickname of CA Certificate");
+ System.out.println(
+ " <serialno_or_filename> = Serial Number Being Checked, Or Name of file that contains the request");
+ System.out.println(" <output> = Filename of Response in DER encoding");
+ System.out.println(" <times> = Submit Request Multiple Times");
+ System.out.println(" [<uri>] = OCSP Service URI (i.e. /ocsp/ee/ocsp)");
+ }
+
+ public static void main(String args[]) {
+ if (args.length != 7 && args.length != 8) {
+ System.out.println("ERROR: Invalid number of arguments - got "
+ + args.length + " expected 7!");
+ for (int i = 0; i < args.length; i++) {
+ System.out.println("arg[" + i + "]=" + args[i]);
+ }
+ printUsage();
+ System.exit(0);
+ }
+
+ String host = args[0];
+ int port = -1;
+ try {
+ port = Integer.parseInt(args[1]);
+ } catch (Exception e) {
+ System.out.println("Error: Invalid Port Number");
+ printUsage();
+ System.exit(0);
+ }
+ String dbdir = args[2];
+ String nickname = args[3];
+ int serialno = -1;
+ byte data[] = null;
+ try {
+ serialno = Integer.parseInt(args[4]);
+ } catch (Exception e) {
+ try {
+ System.out.println("Warning: Serial Number not found. It may be a filename.");
+ /* it could be a file name */
+ FileInputStream fis = new FileInputStream(args[4]);
+ System.out.println("File Size: " + fis.available());
+ data = new byte[fis.available()];
+ fis.read(data);
+ } catch (Exception e1) {
+ System.out.println("Error: Invalid Serial Number or File Name");
+ printUsage();
+ System.exit(0);
+ }
+ }
+ String output = args[5];
+ int times = 1;
+ try {
+ times = Integer.parseInt(args[6]);
+ } catch (Exception e) {
+ System.out.println("Error: Invalid Times");
+ printUsage();
+ System.exit(0);
+ }
+ String uri = "/ocsp/ee/ocsp";
+ if (args.length > 7) {
+ uri = args[7];
+ }
+ try {
+ OCSPClient client =
+ new OCSPClient(host, port, dbdir);
+ for (int i = 0; i < times; i++) {
+ if (data != null) {
+ client.sendRequestData(uri, nickname, data, output);
+ } else {
+ client.send(uri, nickname, serialno, output);
+ }
+ }
+ System.out.println("Success: Output " + output);
+ } catch (Exception e) {
+ System.out.println("Error: " + e.toString());
+ printUsage();
+ System.exit(0);
+ }
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/PKCS10Client.java b/base/java-tools/src/com/netscape/cmstools/PKCS10Client.java
new file mode 100644
index 000000000..7cd50a37a
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/PKCS10Client.java
@@ -0,0 +1,249 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.security.KeyPair;
+import java.security.MessageDigest;
+
+import netscape.security.x509.X500Name;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.asn1.INTEGER;
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.PrintableString;
+import org.mozilla.jss.asn1.SET;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.KeyPairAlgorithm;
+import org.mozilla.jss.crypto.KeyPairGenerator;
+import org.mozilla.jss.crypto.SignatureAlgorithm;
+import org.mozilla.jss.pkcs10.CertificationRequest;
+import org.mozilla.jss.pkcs10.CertificationRequestInfo;
+import org.mozilla.jss.pkix.primitive.AVA;
+import org.mozilla.jss.pkix.primitive.Attribute;
+import org.mozilla.jss.pkix.primitive.Name;
+import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.cmsutil.util.HMACDigest;
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * Generates a 1024-bit RSA key pair in the security database, constructs a
+ * PKCS#10 certificate request with the public key, and outputs the request
+ * to a file.
+ * <p>
+ * PKCS #10 is a certification request syntax standard defined by RSA. A CA may support multiple types of certificate
+ * requests. The Certificate System CA supports KEYGEN, PKCS#10, CRMF, and CMC.
+ * <p>
+ * To get a certificate from the CA, the certificate request needs to be submitted to and approved by a CA agent. Once
+ * approved, a certificate is created for the request, and certificate attributes, such as extensions, are populated
+ * according to certificate profiles.
+ * <p>
+ *
+ * @version $Revision$, $Date$
+ */
+public class PKCS10Client {
+
+ private static void printUsage() {
+ System.out.println(
+ "Usage: PKCS10Client -p <certdb password> -d <location of certdb> -o <output file which saves the base64 PKCS10> -s <subjectDN>\n");
+ }
+
+ public static void main(String args[]) {
+ String dbdir = null, ofilename = null, password = null, subjectName = null;
+
+ if (args.length != 8) {
+ printUsage();
+ System.exit(1);
+ }
+
+ for (int i = 0; i < args.length; i++) {
+ String name = args[i];
+ if (name.equals("-p")) {
+ password = args[i + 1];
+ } else if (name.equals("-d")) {
+ dbdir = args[i + 1];
+ } else if (name.equals("-o")) {
+ ofilename = args[i + 1];
+ } else if (name.equals("-s")) {
+ subjectName = args[i + 1];
+ }
+ }
+
+ if (password == null || ofilename == null || subjectName == null) {
+ System.out.println("Illegal input parameters.");
+ printUsage();
+ System.exit(1);
+ }
+
+ if (dbdir == null)
+ dbdir = ".";
+
+ try {
+ String mPrefix = "";
+ CryptoManager.InitializationValues vals =
+ new CryptoManager.InitializationValues(dbdir, mPrefix,
+ mPrefix, "secmod.db");
+
+ CryptoManager.initialize(vals);
+ CryptoManager cm = CryptoManager.getInstance();
+ CryptoToken token = cm.getInternalKeyStorageToken();
+ Password pass = new Password(password.toCharArray());
+
+ token.login(pass);
+ KeyPairGenerator kg = token.getKeyPairGenerator(KeyPairAlgorithm.RSA);
+ kg.initialize(1024);
+ KeyPair pair = kg.genKeyPair();
+
+ // Add idPOPLinkWitness control
+ String secretValue = "testing";
+ byte[] key1 = null;
+ byte[] finalDigest = null;
+ MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1");
+ key1 = SHA1Digest.digest(secretValue.getBytes());
+
+ /* seed */
+ byte[] b =
+ { 0x10, 0x53, 0x42, 0x24, 0x1a, 0x2a, 0x35, 0x3c,
+ 0x7a, 0x52, 0x54, 0x56, 0x71, 0x65, 0x66, 0x4c,
+ 0x51, 0x34, 0x35, 0x23, 0x3c, 0x42, 0x43, 0x45,
+ 0x61, 0x4f, 0x6e, 0x43, 0x1e, 0x2a, 0x2b, 0x31,
+ 0x32, 0x34, 0x35, 0x36, 0x55, 0x51, 0x48, 0x14,
+ 0x16, 0x29, 0x41, 0x42, 0x43, 0x7b, 0x63, 0x44,
+ 0x6a, 0x12, 0x6b, 0x3c, 0x4c, 0x3f, 0x00, 0x14,
+ 0x51, 0x61, 0x15, 0x22, 0x23, 0x5f, 0x5e, 0x69 };
+
+ HMACDigest hmacDigest = new HMACDigest(SHA1Digest, key1);
+ hmacDigest.update(b);
+ finalDigest = hmacDigest.digest();
+
+ OCTET_STRING ostr = new OCTET_STRING(finalDigest);
+ Attribute attr = new Attribute(OBJECT_IDENTIFIER.id_cmc_idPOPLinkWitness, ostr);
+
+ SET attributes = new SET();
+ attributes.addElement(attr);
+ Name n = getJssName(subjectName);
+ SubjectPublicKeyInfo subjectPub = new SubjectPublicKeyInfo(pair.getPublic());
+ CertificationRequestInfo certReqInfo =
+ new CertificationRequestInfo(new INTEGER(0), n, subjectPub, attributes);
+ CertificationRequest certRequest = new CertificationRequest(certReqInfo,
+ pair.getPrivate(), SignatureAlgorithm.RSASignatureWithMD5Digest);
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ certRequest.encode(bos);
+ byte[] bb = bos.toByteArray();
+
+ String b64E = Utils.base64encode(bb);
+
+ System.out.println("");
+ System.out.println(b64E);
+ System.out.println("");
+
+ PrintStream ps = null;
+ ps = new PrintStream(new FileOutputStream(ofilename));
+ ps.println(b64E);
+ ps.flush();
+ ps.close();
+ } catch (Exception e) {
+ }
+ }
+
+ static Name getJssName(String dn) {
+
+ X500Name x5Name = null;
+
+ try {
+ x5Name = new X500Name(dn);
+ } catch (IOException e) {
+
+ System.out.println("Illegal Subject Name: " + dn + " Error: " + e.toString());
+ System.out.println("Filling in default Subject Name......");
+ return null;
+ }
+
+ Name ret = new Name();
+ netscape.security.x509.RDN[] names = null;
+ names = x5Name.getNames();
+ int nameLen = x5Name.getNamesLength();
+
+ netscape.security.x509.RDN cur = null;
+
+ for (int i = 0; i < nameLen; i++) {
+ cur = names[i];
+ String rdnStr = cur.toString();
+ String[] split = rdnStr.split("=");
+
+ if (split.length != 2)
+ continue;
+
+ try {
+ if (split[0].equals("UID")) {
+ ret.addElement(new AVA(new OBJECT_IDENTIFIER("0.9.2342.19200300.100.1.1"), new PrintableString(
+ split[1])));
+ // System.out.println("UID found : " + split[1]);
+ }
+
+ if (split[0].equals("C")) {
+ ret.addCountryName(split[1]);
+ // System.out.println("C found : " + split[1]);
+ continue;
+ }
+
+ if (split[0].equals("CN")) {
+ ret.addCommonName(split[1]);
+ // System.out.println("CN found : " + split[1]);
+ continue;
+ }
+
+ if (split[0].equals("L")) {
+ ret.addLocalityName(split[1]);
+ // System.out.println("L found : " + split[1]);
+ continue;
+ }
+
+ if (split[0].equals("O")) {
+ ret.addOrganizationName(split[1]);
+ // System.out.println("O found : " + split[1]);
+ continue;
+ }
+
+ if (split[0].equals("ST")) {
+ ret.addStateOrProvinceName(split[1]);
+ // System.out.println("ST found : " + split[1]);
+ continue;
+ }
+
+ if (split[0].equals("OU")) {
+ ret.addOrganizationalUnitName(split[1]);
+ // System.out.println("OU found : " + split[1]);
+ continue;
+ }
+ } catch (Exception e) {
+ System.out.println("Error constructing RDN: " + rdnStr + " Error: " + e.toString());
+ continue;
+ }
+ }
+
+ return ret;
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/PKCS12Export.java b/base/java-tools/src/com/netscape/cmstools/PKCS12Export.java
new file mode 100644
index 000000000..8d8e858f2
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/PKCS12Export.java
@@ -0,0 +1,301 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.security.MessageDigest;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.BMPString;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.SET;
+import org.mozilla.jss.crypto.Cipher;
+import org.mozilla.jss.crypto.CryptoStore;
+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.KeyGenerator;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapper;
+import org.mozilla.jss.crypto.PBEAlgorithm;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.pkcs12.AuthenticatedSafes;
+import org.mozilla.jss.pkcs12.CertBag;
+import org.mozilla.jss.pkcs12.PFX;
+import org.mozilla.jss.pkcs12.PasswordConverter;
+import org.mozilla.jss.pkcs12.SafeBag;
+import org.mozilla.jss.pkix.primitive.EncryptedPrivateKeyInfo;
+import org.mozilla.jss.pkix.primitive.PrivateKeyInfo;
+import org.mozilla.jss.util.Password;
+
+/**
+ * Tool for creating PKCS12 file
+ *
+ * <P>
+ *
+ * @version $Revision$, $Date$
+ *
+ */
+public class PKCS12Export {
+
+ private static boolean debugMode = false;
+
+ private static void debug(String s) {
+ if (debugMode)
+ System.out.println("PKCS12Export debug: " + s);
+ }
+
+ private static void printUsage() {
+ System.out.println(
+ "Usage: PKCS12Export -d <cert/key db directory> -p <file containing password for keydb> -w <file containing pkcs12 password> -o <output file for pkcs12>");
+ System.out.println("");
+ System.out.println("If you want to turn on debug, do the following:");
+ System.out.println(
+ "Usage: PKCS12Export -debug -d <cert/key db directory> -p <file containing password for keydb> -w <file containing pkcs12 password> -o <output file for pkcs12>");
+ }
+
+ private static byte[] getEncodedKey(org.mozilla.jss.crypto.PrivateKey pkey) {
+ try {
+ CryptoManager cm = CryptoManager.getInstance();
+ CryptoToken token = cm.getInternalKeyStorageToken();
+ KeyGenerator kg = token.getKeyGenerator(KeyGenAlgorithm.DES3);
+ SymmetricKey sk = kg.generate();
+ KeyWrapper wrapper = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
+ byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+ IVParameterSpec param = new IVParameterSpec(iv);
+ wrapper.initWrap(sk, param);
+ byte[] enckey = wrapper.wrap(pkey);
+ Cipher c = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
+ c.initDecrypt(sk, param);
+ byte[] recovered = c.doFinal(enckey);
+ return recovered;
+ } catch (Exception e) {
+ debug("PKCS12Export getEncodedKey: Exception=" + e.toString());
+ System.exit(1);
+ }
+
+ return null;
+ }
+
+ private static void addKeyBag(org.mozilla.jss.crypto.PrivateKey pkey, X509Certificate x509cert,
+ Password pass, byte[] localKeyId, SEQUENCE safeContents) {
+ try {
+ PasswordConverter passConverter = new PasswordConverter();
+ byte salt[] = { 0x01, 0x01, 0x01, 0x01 };
+ byte[] priData = getEncodedKey(pkey);
+
+ PrivateKeyInfo pki = (PrivateKeyInfo)
+ ASN1Util.decode(PrivateKeyInfo.getTemplate(), priData);
+ ASN1Value key = EncryptedPrivateKeyInfo.createPBE(
+ PBEAlgorithm.PBE_SHA1_DES3_CBC,
+ pass, salt, 1, passConverter, pki);
+ SET keyAttrs = createBagAttrs(
+ x509cert.getSubjectDN().toString(), localKeyId);
+ SafeBag keyBag = new SafeBag(SafeBag.PKCS8_SHROUDED_KEY_BAG,
+ key, keyAttrs);
+ safeContents.addElement(keyBag);
+ } catch (Exception e) {
+ debug("PKCS12Export addKeyBag: Exception=" + e.toString());
+ System.exit(1);
+ }
+ }
+
+ private static byte[] addCertBag(X509Certificate x509cert, String nickname,
+ SEQUENCE safeContents) throws IOException {
+ byte[] localKeyId = null;
+ try {
+ ASN1Value cert = new OCTET_STRING(x509cert.getEncoded());
+ localKeyId = createLocalKeyId(x509cert);
+ SET certAttrs = null;
+ if (nickname != null)
+ certAttrs = createBagAttrs(nickname, localKeyId);
+ SafeBag certBag = new SafeBag(SafeBag.CERT_BAG,
+ new CertBag(CertBag.X509_CERT_TYPE, cert), certAttrs);
+ safeContents.addElement(certBag);
+ } catch (Exception e) {
+ debug("PKCS12Export addCertBag: " + e.toString());
+ System.exit(1);
+ }
+
+ return localKeyId;
+ }
+
+ private static byte[] createLocalKeyId(X509Certificate cert) {
+ try {
+ // SHA1 hash of the X509Cert der encoding
+ byte certDer[] = cert.getEncoded();
+
+ MessageDigest md = MessageDigest.getInstance("SHA");
+
+ md.update(certDer);
+ return md.digest();
+ } catch (Exception e) {
+ debug("PKCS12Export createLocalKeyId: Exception: " + e.toString());
+ System.exit(1);
+ }
+
+ return null;
+ }
+
+ private static SET createBagAttrs(String nickName, byte localKeyId[])
+ throws IOException {
+ try {
+ SET attrs = new SET();
+ SEQUENCE nickNameAttr = new SEQUENCE();
+
+ nickNameAttr.addElement(SafeBag.FRIENDLY_NAME);
+ SET nickNameSet = new SET();
+
+ nickNameSet.addElement(new BMPString(nickName));
+ nickNameAttr.addElement(nickNameSet);
+ attrs.addElement(nickNameAttr);
+ SEQUENCE localKeyAttr = new SEQUENCE();
+
+ localKeyAttr.addElement(SafeBag.LOCAL_KEY_ID);
+ SET localKeySet = new SET();
+
+ localKeySet.addElement(new OCTET_STRING(localKeyId));
+ localKeyAttr.addElement(localKeySet);
+ attrs.addElement(localKeyAttr);
+ return attrs;
+ } catch (Exception e) {
+ debug("PKCS12Export createBagAttrs: Exception=" + e.toString());
+ System.exit(1);
+ }
+
+ return null;
+ }
+
+ public static void main(String args[]) {
+ if (args.length < 8) {
+ printUsage();
+ System.exit(1);
+ }
+
+ String pwdfile = null;
+ String dir = null;
+ String pk12pwdfile = null;
+ String pk12output = null;
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("-d")) {
+ dir = args[i + 1];
+ } else if (args[i].equals("-p")) {
+ pwdfile = args[i + 1];
+ } else if (args[i].equals("-s")) {
+ // snickname = args[i + 1];
+ } else if (args[i].equals("-w")) {
+ pk12pwdfile = args[i + 1];
+ } else if (args[i].equals("-o")) {
+ pk12output = args[i + 1];
+ } else if (args[i].equals("-debug")) {
+ debugMode = true;
+ }
+ }
+
+ debug("The directory for certdb/keydb is " + dir);
+ debug("The password file for keydb is " + pwdfile);
+
+ // get password
+ String pwd = null;
+ try {
+ BufferedReader in = new BufferedReader(new FileReader(pwdfile));
+ pwd = in.readLine();
+ } catch (Exception e) {
+ debug("Failed to read the keydb password from the file. Exception: " + e.toString());
+ System.exit(1);
+ }
+
+ String pk12pwd = null;
+ try {
+ BufferedReader in = new BufferedReader(new FileReader(pk12pwdfile));
+ pk12pwd = in.readLine();
+ } catch (Exception e) {
+ debug("Failed to read the keydb password from the file. Exception: " + e.toString());
+ System.exit(1);
+ }
+
+ CryptoManager cm = null;
+ try {
+ CryptoManager.InitializationValues vals =
+ new CryptoManager.InitializationValues(dir, "", "", "secmod.db");
+ CryptoManager.initialize(vals);
+ cm = CryptoManager.getInstance();
+ } catch (Exception e) {
+ debug("Failed to initialize the certdb.");
+ System.exit(1);
+ }
+
+ SEQUENCE encSafeContents = new SEQUENCE();
+ SEQUENCE safeContents = new SEQUENCE();
+ try {
+ CryptoToken token = cm.getInternalKeyStorageToken();
+ Password pass = new Password(pwd.toCharArray());
+ token.login(pass);
+ CryptoStore store = token.getCryptoStore();
+ X509Certificate[] certs = store.getCertificates();
+ debug("Number of user certificates = " + certs.length);
+ Password pass12 = new Password(pk12pwd.toCharArray());
+ for (int i = 0; i < certs.length; i++) {
+ String nickname = certs[i].getNickname();
+ debug("Certificate nickname = " + nickname);
+ org.mozilla.jss.crypto.PrivateKey prikey = null;
+ try {
+ prikey = cm.findPrivKeyByCert(certs[i]);
+ } catch (Exception e) {
+ debug("PKCS12Export Exception: " + e.toString());
+ }
+
+ if (prikey == null) {
+ debug("Private key is null");
+ addCertBag(certs[i], null, safeContents);
+ } else {
+ debug("Private key is not null");
+ byte localKeyId[] =
+ addCertBag(certs[i], nickname, safeContents);
+ addKeyBag(prikey, certs[i], pass12, localKeyId, encSafeContents);
+ }
+ }
+
+ AuthenticatedSafes authSafes = new AuthenticatedSafes();
+ authSafes.addSafeContents(safeContents);
+ authSafes.addSafeContents(encSafeContents);
+ PFX pfx = new PFX(authSafes);
+ pfx.computeMacData(pass12, null, 5);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ pfx.encode(bos);
+ FileOutputStream fos = new FileOutputStream(pk12output);
+ fos.write(bos.toByteArray());
+ fos.flush();
+ fos.close();
+ pass.clear();
+ pass12.clear();
+ } catch (Exception e) {
+ debug("PKCS12Export Exception: " + e.toString());
+ System.exit(1);
+ }
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/PasswordCache.java b/base/java-tools/src/com/netscape/cmstools/PasswordCache.java
new file mode 100644
index 000000000..ba7fb72a4
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/PasswordCache.java
@@ -0,0 +1,870 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.SecretDecoderRing.Decryptor;
+import org.mozilla.jss.SecretDecoderRing.Encryptor;
+import org.mozilla.jss.SecretDecoderRing.KeyManager;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.util.Base64OutputStream;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * Tool for interacting with the PWcache
+ *
+ * @version $Revision$, $Date$
+ */
+
+public class PasswordCache {
+
+ /* These are the tags that identify various passwords
+ * They should probably be converted instances of some
+ * class so that we can expose an API to add additional
+ * TAG's for use if I want to add a password for use
+ * with my own authenticaion module
+ */
+ public static final String PROP_PWC_NICKNAME = "sso_key";
+ public static final String PW_TAG_INTERNAL_LDAP_DB = "Internal LDAP Database";
+ private static final String WRONG_NUM_ARGS = "Error: wrong number of arguments";
+ private static final String CERTDB = "cert8.db";
+ private static final String KEYDB = "key3.db";
+
+ private static void usage() {
+ System.out.println(
+ "This tool has to be run from the same directory where pwcache.db file resides, normally <cms instance>/config directory, unless the file's full path is specified in the -c option..\nUsage: PasswordCache <SSO_PASSWORD> <-d cert/key db directory> <-h tokenName> <-P cert/key db prefix> <-c pwcache.db_file_full_path> <-k file containing Base64EncodedKeyID> <COMMAND> ...");
+ System.out.println(" commands:");
+ System.out.println(" 'add <password_name> <password>'");
+ System.out.println(" 'change <password_name> <password>'");
+ System.out.println(" 'delete <password_name>'");
+ System.out.println(" 'rekey'");
+ System.out.println(" 'list'");
+ System.out.println(
+ "\nExample:\n\tPasswordCache thePassword1 -d /usr/netscape/servers/cms/alias -P cert-instance1-machine1- -c pwcache.db -k keyidFile list");
+ System.exit(1);
+ }
+
+ private static boolean debugMode = false;
+
+ public PasswordCache() {
+ }
+
+ private static void debug(String s) {
+ if (debugMode == true)
+ System.out.println("PasswordCache debug: " + s);
+ }
+
+ /**
+ * clean up an argv by removing the trailing, empty arguments
+ *
+ * This is necessary to support the script wrapper which calls the
+ * tool with arguments in quotes such as:
+ * "$1" "$2"
+ * if $2 is not specified, the empty arg "" gets passed, which causes
+ * an error in the arg-count checking code.
+ */
+ private static String[] cleanArgs(String[] s) {
+ int length;
+ int i;
+
+ length = s.length;
+ debug("before cleanArgs argv length =" + length);
+
+ for (i = length - 1; i >= 0; i--) {
+ if (s[i].equals("")) {
+ length--;
+ } else {
+ break;
+ }
+ }
+
+ String[] new_av = new String[length];
+ for (i = 0; i < length; i++) {
+ new_av[i] = s[i];
+ debug("arg " + i + " is " + new_av[i]);
+ }
+ debug("after cleanArgs argv length =" + length);
+
+ return new_av;
+ }
+
+ public static byte[] base64Decode(String s) throws IOException {
+ byte[] d = Utils.base64decode(s);
+ return d;
+ }
+
+ public static String base64Encode(byte[] bytes) throws IOException {
+ // All this streaming is lame, but Base64OutputStream needs a
+ // PrintStream
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ Base64OutputStream b64 = new Base64OutputStream(new
+ PrintStream(new
+ FilterOutputStream(output)
+ )
+ );
+
+ b64.write(bytes);
+ b64.flush();
+
+ // This is internationally safe because Base64 chars are
+ // contained within 8859_1
+ return output.toString("8859_1");
+ }
+
+ public static void main(String[] av) {
+ // default path is "."
+ String mPath = ".";
+ String mTokenName = null;
+ // default prefix is ""
+ String mPrefix = "";
+ String mKeyIdString = null;
+ byte[] mKeyId = null;
+ String mCacheFile = "pwcache.db";
+
+ String pwdPath = null;
+ String instancePath = null;
+ String instanceName = null;
+
+ String[] argv = cleanArgs(av);
+
+ if (argv.length < 2) {
+ usage();
+ }
+
+ String pw = argv[0];
+
+ char[] testpw = pw.toCharArray();
+ Password pass = new Password(testpw);
+
+ String command = "";
+ String aTag = "";
+ String aPasswd = "";
+
+ int i = 0;
+ for (i = 1; i < argv.length; ++i) {
+ if (argv[i].equals("-d")) {
+ if (++i >= argv.length)
+ usage();
+ mPath = argv[i];
+ } else if (argv[i].equals("-h")) {
+ if (++i >= argv.length)
+ usage();
+ mTokenName = argv[i];
+ } else if (argv[i].equals("-P")) {
+ if (++i >= argv.length)
+ usage();
+ mPrefix = argv[i];
+ } else if (argv[i].equals("-c")) {
+ if (++i >= argv.length)
+ usage();
+ mCacheFile = argv[i];
+ } else if (argv[i].equals("-k")) {
+ if (++i >= argv.length)
+ usage();
+ String keyFile = argv[i];
+ try {
+ BufferedReader r = new BufferedReader(new FileReader(keyFile));
+ mKeyIdString = r.readLine();
+ } catch (Exception e) {
+ System.out.println("Error: " + e.toString());
+ System.exit(1);
+ }
+
+ if (mKeyIdString != null) {
+ try {
+ mKeyId = base64Decode(mKeyIdString);
+ debug("base64Decode of key id string successful");
+ } catch (IOException e) {
+ System.out.println("base64Decode of key id string failed");
+ System.exit(1);
+ }
+ }
+ } else {
+ command = argv[i++];
+ debug("command = " + command);
+
+ if ((command.equals("add")) ||
+ (command.equals("change"))) {
+ aTag = argv[i++];
+ aPasswd = argv[i];
+ debug("command is " + command + " " + aTag + ":" + aPasswd);
+ } else if (command.equals("delete")) {
+ aTag = argv[i];
+ } else if (command.equals("list")) {
+ } else if (command.equals("rekey")) {
+ }
+ break;
+ }
+ }
+
+ try {
+ // initialize CryptoManager
+ System.out.println("cert/key prefix = " + mPrefix);
+ System.out.println("cert/key db path = " + mPath);
+ System.out.println("password cache file = " + mCacheFile);
+
+ CryptoManager.InitializationValues vals =
+ new CryptoManager.InitializationValues(mPath, mPrefix,
+ mPrefix, "secmod.db");
+
+ CryptoManager.initialize(vals);
+
+ CryptoManager cm = CryptoManager.getInstance();
+ CryptoToken token = null;
+ if (mTokenName == null) {
+ token = cm.getInternalKeyStorageToken();
+ System.out.println("token name = internal");
+ } else {
+ token = cm.getTokenByName(mTokenName);
+ System.out.println("token name = " + mTokenName);
+ }
+
+ token.login(pass);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ // generating new key
+ if (command.equals("rekey")) {
+ System.out.println("generating new key...");
+ PWsdrCache cache = null;
+ try {
+ // compose instance name
+ File passwordCacheDB = new File(mCacheFile);
+ pwdPath = passwordCacheDB.getAbsolutePath();
+ int beginIndex = pwdPath.lastIndexOf("cert-");
+ instancePath = pwdPath.substring(beginIndex);
+ int endIndex = 0;
+ endIndex = instancePath.lastIndexOf("config");
+ instanceName = instancePath.substring(0, (endIndex - 1));
+
+ cache = new PWsdrCache(mCacheFile, mTokenName, null, true);
+ cache.deleteUniqueNamedKey(PROP_PWC_NICKNAME
+ + " "
+ + instanceName);
+ byte[] newKeyId = cache.generateSDRKeyWithNickName(
+ PROP_PWC_NICKNAME
+ + " "
+ + instanceName);
+ if (newKeyId != null) {
+ String newKeyIDString = base64Encode(newKeyId);
+ System.out.println("key generated successfully with key id = " +
+ newKeyIDString);
+ System.out.println("Save the VALUE portion of this key id in a local file,");
+ System.out.println("and under variable \"pwcKeyid\" in CS.cfg !!");
+ System.out.println("If you have not already done so,");
+ System.out.println("remove the old pwcache.db and use this local file to add passwords.");
+ // job is done
+ System.exit(0);
+ } else {
+ System.out.println("key expected to be generated but wasn't");
+ System.exit(1);
+ }
+ } catch (Exception e) {
+ System.out.println(e.toString());
+ System.exit(1);
+ }
+ }
+
+ PWsdrCache cache = null;
+ try {
+ cache = new PWsdrCache(mCacheFile, mTokenName, mKeyId, true);
+ } catch (Exception e) {
+ System.out.println(e.toString());
+ System.exit(1);
+ }
+
+ if ((command.equals("add")) || (command.equals("change"))) {
+ // current key id must be specified
+ if (mKeyId == null) {
+ System.out.println("operation failed: no key id specified");
+ System.exit(1);
+ }
+
+ try {
+ System.out.println("adding " + aTag + ":" + aPasswd);
+ cache.addEntry(aTag, aPasswd);
+ } catch (Exception e) {
+ System.out.println("--failed--" + e.toString());
+ }
+ } else if (command.equals("list")) {
+ cache.pprint();
+ } else if (command.equals("delete")) {
+ // current key id must be specified
+ if (mKeyId == null) {
+ System.out.println("operation failed: no key id specified");
+ System.exit(1);
+ }
+
+ try {
+ cache.deleteEntry(aTag);
+ } catch (Exception e) {
+ System.out.println("User not found");
+ }
+ } else {
+ System.out.println("Illegal command: " + command);
+ System.exit(1);
+ }
+ }
+}
+
+/*
+ * A class for managing passwords in the SDR password cache
+ *
+ * @author Christina Fu
+ * @version $Revision$, $Date$
+ */
+class PWsdrCache {
+
+ public static final String PROP_PWC_NICKNAME = "sso_key";
+
+ private String mPWcachedb = null;
+ private byte[] mKeyID = null;
+ private String mTokenName = null;
+ private CryptoToken mToken = null;
+
+ // mTool tells if this is called from the PasswordCache tool
+ private boolean mIsTool = false;
+
+ // for PasswordCache tool (isTool == true)
+ public PWsdrCache(String pwCache, String pwcTokenname, byte[] keyId,
+ boolean isTool) throws Exception {
+ mPWcachedb = pwCache;
+ mIsTool = isTool;
+ mTokenName = pwcTokenname;
+ CryptoManager cm = null;
+
+ if (keyId != null) {
+ mKeyID = keyId;
+ }
+
+ cm = CryptoManager.getInstance();
+ if (mTokenName != null) {
+ mToken = cm.getTokenByName(mTokenName);
+ debug("PWsdrCache: mToken = " + mTokenName);
+ } else {
+ mToken = cm.getInternalKeyStorageToken();
+ debug("PWsdrCache: mToken = internal");
+ }
+ }
+
+ public byte[] getKeyId() {
+ return mKeyID;
+ }
+
+ public String getTokenName() {
+ return mTokenName;
+ }
+
+ public void deleteUniqueNamedKey(String nickName)
+ throws Exception {
+ KeyManager km = new KeyManager(mToken);
+ km.deleteUniqueNamedKey(nickName);
+ }
+
+ public byte[] generateSDRKey() throws Exception {
+ return generateSDRKeyWithNickName(PROP_PWC_NICKNAME);
+ }
+
+ public byte[] generateSDRKeyWithNickName(String nickName)
+ throws Exception {
+ try {
+ if (mIsTool == true) {
+ // generate SDR key
+ KeyManager km = new KeyManager(mToken);
+ try {
+ // Bugscape Bug #54838: Due to the CMS cloning feature,
+ // we must check for the presence of
+ // a uniquely named symmetric key
+ // prior to making an attempt to
+ // generate it!
+ //
+ if (!(km.uniqueNamedKeyExists(nickName))) {
+ mKeyID = km.generateUniqueNamedKey(nickName);
+ debug("PWsdrCache: SDR key generated");
+ }
+ } catch (TokenException e) {
+ log(0, "generateSDRKey() failed on " + e.toString());
+ throw e;
+ }
+ }
+ } catch (Exception e) {
+ log(0, e.toString());
+ throw e;
+ }
+ return mKeyID;
+ }
+
+ public void addEntry(String tag, String pwd) throws IOException {
+ addEntry(tag, pwd, (Hashtable<String, String>) null);
+ }
+
+ /*
+ * Store passwd in pwcache.
+ */
+ public void addEntry(Hashtable<String, String> ht) throws IOException {
+ addEntry((String) null, (String) null, ht);
+ }
+
+ /*
+ * add passwd in pwcache.
+ */
+ public void addEntry(String tag, String pwd, Hashtable<String, String> tagPwds) throws IOException {
+ System.out.println("PWsdrCache: in addEntry");
+ String stringToAdd = null;
+ String bufs = null;
+
+ if (tagPwds == null) {
+ stringToAdd = tag + ":" + pwd + "\n";
+ } else {
+ Enumeration<String> enum1 = tagPwds.keys();
+
+ while (enum1.hasMoreElements()) {
+ tag = enum1.nextElement();
+ pwd = tagPwds.get(tag);
+ debug("password tag: " + tag + " stored in " + mPWcachedb);
+
+ if (stringToAdd == null) {
+ stringToAdd = tag + ":" + pwd + "\n";
+ } else {
+ stringToAdd += tag + ":" + pwd + "\n";
+ }
+ }
+ }
+
+ String dcrypts = readPWcache();
+ System.out.println("PWsdrCache: after readPWcache()");
+ if (dcrypts != null) {
+ // converts to Hashtable, replace if tag exists, add
+ // if tag doesn't exist
+ Hashtable<String, String> ht = string2Hashtable(dcrypts);
+
+ if (ht.containsKey(tag) == false) {
+ debug("adding new tag: " + tag);
+ ht.put(tag, pwd);
+ } else {
+ debug("replacing tag: " + tag);
+ ht.put(tag, pwd);
+ }
+ bufs = hashtable2String(ht);
+ } else {
+ debug("adding new tag: " + tag);
+ bufs = stringToAdd;
+ }
+
+ // write update to cache
+ writePWcache(bufs);
+ }
+
+ /*
+ * delete passwd in pwcache.
+ */
+ public void deleteEntry(String tag) throws IOException {
+ String bufs = null;
+
+ String dcrypts = readPWcache();
+
+ if (dcrypts != null) {
+ // converts to Hashtable, replace if tag exists, add
+ // if tag doesn't exist
+ Hashtable<String, String> ht = string2Hashtable(dcrypts);
+
+ if (ht.containsKey(tag) == false) {
+ debug("tag: " + tag + " does not exist");
+ return;
+ } else {
+ debug("deleting tag: " + tag);
+ ht.remove(tag);
+ }
+ bufs = hashtable2String(ht);
+ } else {
+ debug("password cache contains no tags");
+ return;
+ }
+
+ // write update to cache
+ writePWcache(bufs);
+ }
+
+ /*
+ * reads and decrypts the pwcache.db content
+ */
+ public String readPWcache() throws IOException {
+ debug("about to read password cache");
+ String dcrypts = null;
+ if (mToken == null) {
+ debug("mToken is null");
+ throw new IOException("token must be specified");
+ }
+
+ Decryptor sdr = new Decryptor(mToken);
+
+ // not used, but could used for debugging
+ int totalRead = 0;
+ FileInputStream inputs = null;
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ try {
+ // for SDR -> read, decrypt, append, and write
+ inputs = new FileInputStream(mPWcachedb);
+ byte[] readbuf = new byte[2048]; // for now
+ int numRead = 0;
+
+ while ((numRead = inputs.read(readbuf)) != -1) {
+ bos.write(readbuf, 0, numRead);
+ totalRead += numRead;
+ }
+ inputs.close();
+ } catch (FileNotFoundException e) {
+ System.out.println("Failed for file " + mPWcachedb + " " + e.toString());
+ throw new IOException(e.toString() + ": " + mPWcachedb);
+ } catch (IOException e) {
+ System.out.println("Failed for file " + mPWcachedb + " " + e.toString());
+ throw new IOException(e.toString() + ": " + mPWcachedb);
+ }
+
+ if (totalRead > 0) {
+ try {
+ // decrypt it first to append
+ byte[] dcryptb = sdr.decrypt(bos.toByteArray());
+
+ dcrypts = new String(dcryptb, "UTF-8");
+ } catch (TokenException e) {
+ System.out.println("password cache decrypto failed " + e.toString());
+ e.printStackTrace();
+ throw new IOException("password cache decrypt failed");
+ } catch (UnsupportedEncodingException e) {
+ System.out.println("password cache decrypto failed " + e.toString());
+ e.printStackTrace();
+ throw new IOException("password cache decrypt failed");
+ } catch (Exception e) {
+ System.out.println("password cache decrypto failed " + e.toString());
+ e.printStackTrace();
+ throw new IOException("password cache decrypt failed");
+ }
+ }
+
+ return dcrypts;
+ }
+
+ /*
+ * encrypts and writes the whole String buf into pwcache.db
+ */
+ public void writePWcache(String bufs) throws IOException {
+
+ try {
+ Encryptor sdr = new Encryptor(mToken, mKeyID,
+ Encryptor.DEFAULT_ENCRYPTION_ALG);
+
+ byte[] writebuf = null;
+
+ try {
+ // now encrypt it again
+ writebuf = sdr.encrypt(bufs.getBytes("UTF-8"));
+ } catch (Exception e) {
+ System.out.println("password cache encrypt failed " + e.toString());
+ e.printStackTrace();
+ throw new IOException("password cache encrypt failed");
+ }
+
+ File tmpPWcache = new File(mPWcachedb + ".tmp");
+
+ if (tmpPWcache.exists()) {
+ // it wasn't removed?
+ tmpPWcache.delete();
+ }
+ FileOutputStream outstream = new FileOutputStream(mPWcachedb + ".tmp");
+
+ outstream.write(writebuf);
+ outstream.close();
+
+ // Make certain that this temporary file has
+ // the correct permissions.
+ if (!isNT()) {
+ exec("chmod 00660 " + tmpPWcache.getAbsolutePath());
+ }
+
+ File origFile = new File(mPWcachedb);
+
+ try {
+ // Always remove any pre-existing target file
+ if (origFile.exists()) {
+ origFile.delete();
+ }
+
+ if (isNT()) {
+ // NT is very picky on the path
+ exec("copy " +
+ tmpPWcache.getAbsolutePath().replace('/', '\\') + " " +
+ origFile.getAbsolutePath().replace('/', '\\'));
+ } else {
+ // Create a copy of the temporary file which
+ // preserves the temporary file's permissions.
+ exec("cp -p " + tmpPWcache.getAbsolutePath() + " " +
+ origFile.getAbsolutePath());
+ }
+
+ // Remove the temporary file if and only if
+ // the "rename" was successful.
+ if (origFile.exists()) {
+ tmpPWcache.delete();
+
+ // Make certain that the final file has
+ // the correct permissions.
+ if (!isNT()) {
+ exec("chmod 00660 " + origFile.getAbsolutePath());
+ }
+
+ // report success
+ debug("Renaming operation completed for " + mPWcachedb);
+ } else {
+ // report failure and exit
+ debug("Renaming operation failed for " + mPWcachedb);
+ System.exit(1);
+ }
+ } catch (IOException exx) {
+ System.out.println("sdrPWcache: Error " + exx.toString());
+ throw new IOException(exx.toString() + ": " + mPWcachedb);
+ }
+ } catch (FileNotFoundException e) {
+ System.out.println("sdrPWcache: Error " + e.toString());
+ throw new IOException(e.toString() + ": " + mPWcachedb);
+ } catch (IOException e) {
+ System.out.println("Failed for file " + mPWcachedb + " " + e.toString());
+ throw new IOException(e.toString() + ": " + mPWcachedb);
+ } catch (Exception e) {
+ System.out.println("sdrPWcache: Error " + e.toString());
+ throw new IOException(e.toString());
+ }
+ }
+
+ public String hashtable2String(Hashtable<String, String> ht) {
+ Enumeration<String> enum1 = ht.keys();
+ String returnString = null;
+
+ while (enum1.hasMoreElements()) {
+ String tag = enum1.nextElement();
+ String pwd = ht.get(tag);
+
+ if (returnString == null) {
+ returnString = tag + ":" + pwd + "\n";
+ } else {
+ returnString += tag + ":" + pwd + "\n";
+ }
+ }
+ return returnString;
+ }
+
+ public Hashtable<String, String> string2Hashtable(String cache) {
+ Hashtable<String, String> ht = new Hashtable<String, String>();
+
+ // first, break into lines
+ StringTokenizer st = new StringTokenizer(cache, "\n");
+
+ while (st.hasMoreTokens()) {
+ String line = (String) st.nextToken();
+ // break into tag:password format for each line
+ int colonIdx = line.indexOf(":");
+
+ if (colonIdx != -1) {
+ String tag = line.substring(0, colonIdx);
+ String passwd = line.substring(colonIdx + 1,
+ line.length());
+
+ ht.put(tag.trim(), passwd.trim());
+ } else {
+ //invalid format...log or throw...later
+ }
+ }
+ return ht;
+ }
+
+ /*
+ * get password from cache. This one supplies cache file name
+ */
+ public Password getEntry(String fileName, String tag) {
+ mPWcachedb = fileName;
+ return getEntry(tag);
+ }
+
+ /*
+ * if tag found with pwd, return it
+ * if tag not found, return null, which will cause it to give up
+ */
+ public Password getEntry(String tag) {
+ Hashtable<String, String> pwTable = null;
+ String pw = null;
+
+ debug("in getEntry, tag=" + tag);
+
+ if (mPWcachedb == null) {
+ debug("mPWcachedb file path name is not initialized");
+ return null;
+ }
+
+ String dcrypts = null;
+
+ try {
+ dcrypts = readPWcache();
+ } catch (IOException e) {
+ System.out.println("dfailed readPWcache() " + e.toString());
+ return null;
+ }
+
+ if (dcrypts != null) {
+ // parse the cache
+ String cache = dcrypts;
+
+ // this is created and destroyed at each use
+ pwTable = string2Hashtable(cache);
+ debug("in getEntry, pw cache parsed");
+ pw = (String) pwTable.get(tag);
+ }
+
+ if (pw != null) {
+ debug("getEntry gotten password for " + tag);
+ return new Password(pw.toCharArray());
+ } else {
+ System.out.println("getEntry did not get password for tag " + tag);
+ return null;
+ }
+ }
+
+ //copied from IOUtil.java
+ /**
+ * Checks if this is NT.
+ */
+ public static boolean isNT() {
+ return ((File.separator).equals("\\"));
+ }
+
+ public static boolean exec(String cmd) throws IOException {
+ try {
+ String cmds[] = null;
+
+ if (isNT()) {
+ // NT
+ cmds = new String[3];
+ cmds[0] = "cmd";
+ cmds[1] = "/c";
+ cmds[2] = cmd;
+ } else {
+ // UNIX
+ cmds = new String[3];
+ cmds[0] = "/bin/sh";
+ cmds[1] = "-c";
+ cmds[2] = cmd;
+ }
+ Process process = Runtime.getRuntime().exec(cmds);
+
+ process.waitFor();
+
+ if (process.exitValue() == 0) {
+
+ /**
+ * pOut = new BufferedReader(
+ * new InputStreamReader(process.getInputStream()));
+ * while ((l = pOut.readLine()) != null) {
+ * System.out.println(l);
+ * }
+ **/
+ return true;
+ } else {
+
+ /**
+ * pOut = new BufferedReader(
+ * new InputStreamReader(process.getErrorStream()));
+ * l = null;
+ * while ((l = pOut.readLine()) != null) {
+ * System.out.println(l);
+ * }
+ **/
+ return false;
+ }
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ public void debug(String msg) {
+ System.out.println(msg);
+ }
+
+ public void log(int level, String msg) {
+ System.out.println(msg);
+ }
+
+ /*
+ * list passwds in pwcache.
+ */
+ public boolean pprint() {
+ String dcrypts = null;
+
+ try {
+ dcrypts = readPWcache();
+ } catch (IOException e) {
+ System.out.println("failed readPWcache() " + e.toString());
+ return false;
+ }
+
+ debug("----- Password Cache Content -----");
+
+ if (dcrypts != null) {
+ // first, break into lines
+ StringTokenizer st = new StringTokenizer(dcrypts, "\n");
+
+ while (st.hasMoreTokens()) {
+ String line = (String) st.nextToken();
+ // break into tag:password format for each line
+ int colonIdx = line.indexOf(":");
+
+ if (colonIdx != -1) {
+ String tag = line.substring(0, colonIdx);
+ String passwd = line.substring(colonIdx + 1,
+ line.length());
+
+ debug(tag.trim() +
+ " : " + passwd.trim());
+ } else {
+ //invalid format...log or throw...later
+ debug("invalid format");
+ }
+ }
+ } // else print nothing
+ return true;
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/PrettyPrintCert.java b/base/java-tools/src/com/netscape/cmstools/PrettyPrintCert.java
new file mode 100644
index 000000000..382c4e312
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/PrettyPrintCert.java
@@ -0,0 +1,248 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.security.cert.CertificateException;
+import java.util.Locale;
+
+import com.netscape.cmsutil.util.Utils;
+
+import netscape.security.util.CertPrettyPrint;
+import netscape.security.x509.CertificateSubjectName;
+import netscape.security.x509.RDN;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.X509CertImpl;
+import netscape.security.x509.X509CertInfo;
+
+/**
+ * The PrettyPrintCert class is a utility program designed to "pretty print"
+ * a certificate. It assumes that the name of a data file is passed to the
+ * program via the command line, and that the contents contain a certificate
+ * encoded in an ASCII BASE 64 format. Note that the data file may contain
+ * an optional "-----BEGIN" header and/or an optional "-----END" trailer.
+ *
+ * <P>
+ * The program may be invoked as follows:
+ *
+ * <PRE>
+ *
+ * PrettyPrintCert &lt;input filename&gt; [output filename]
+ *
+ * NOTE: &lt;input filename&gt; must contain an ASCII
+ * BASE 64 encoded certificate
+ *
+ * &lt;output filename&gt; contains a certificate displayed
+ * in a "pretty print" ASCII format
+ * </PRE>
+ *
+ * @version $Revision$, $Date$
+ */
+
+public class PrettyPrintCert {
+ // Define constants
+ public static final int ARGC = 2;
+ public static final String HEADER = "-----BEGIN";
+ public static final String TRAILER = "-----END";
+
+ public static void usageAndExit() {
+ System.out.println("Usage: PrettyPrintCert " +
+ "[options] " +
+ "<input filename> " +
+ "[output filename]");
+ System.out.println("\n options: ");
+ System.out.println(" -simpleinfo : prints limited cert info in easy to parse format");
+ System.exit(0);
+ }
+
+ public static void main(String argv[]) {
+
+ BufferedReader inputCert = null;
+ String encodedBASE64CertChunk = new String();
+ String encodedBASE64Cert = new String();
+ byte decodedBASE64Cert[] = null;
+ X509CertImpl cert = null;
+ Locale aLocale = null;
+ CertPrettyPrint certDetails = null;
+ String pp = new String();
+ FileOutputStream outputCert = null;
+ boolean mSimpleInfo = false;
+ String inputfile = null;
+ String outputfile = null;
+
+ // parse arguments
+
+ for (int i = 0; i < argv.length; i++) {
+
+ // deal with empty arguments passed in by script
+ if (argv[i].equals("")) {
+ continue;
+ }
+
+ // parse options
+ if (argv[i].charAt(0) == '-') {
+ if (argv[i].equals("-simpleinfo")) {
+ mSimpleInfo = true;
+ continue;
+ } else {
+ System.out.println("Illegal option: " + argv[i]);
+ usageAndExit();
+ }
+ }
+
+ // deal with filename
+
+ if (inputfile == null) {
+ inputfile = argv[i];
+ continue;
+ }
+
+ if (outputfile == null) {
+ outputfile = argv[i];
+ continue;
+ }
+
+ System.out.println("Error - Too many arguments");
+ System.exit(0);
+ }
+
+ if (inputfile == null) {
+ usageAndExit();
+ }
+
+ // (2) Create a DataInputStream() object to the BASE 64
+ // encoded certificate contained within the file
+ // specified on the command line
+ try {
+ inputCert = new BufferedReader(new InputStreamReader(
+ new BufferedInputStream(
+ new FileInputStream(
+ inputfile))));
+ } catch (FileNotFoundException e) {
+ System.out.println("PrettyPrintCert: can't find file " +
+ inputfile + ":\n" + e);
+ return;
+ }
+
+ // (3) Read the entire contents of the specified BASE 64 encoded
+ // certificate into a String() object throwing away any
+ // headers beginning with HEADER and any trailers beginning
+ // with TRAILER
+ try {
+ while ((encodedBASE64CertChunk = inputCert.readLine()) != null) {
+ if (!(encodedBASE64CertChunk.startsWith(HEADER)) &&
+ !(encodedBASE64CertChunk.startsWith(TRAILER))) {
+ encodedBASE64Cert += encodedBASE64CertChunk.trim();
+ }
+ }
+ } catch (IOException e) {
+ System.out.println("PrettyPrintCert: Unexpected BASE64 " +
+ "encoded error encountered in readLine():\n" +
+ e);
+ }
+
+ // (4) Close the DataInputStream() object
+ try {
+ inputCert.close();
+ } catch (IOException e) {
+ System.out.println("PrettyPrintCert: Unexpected BASE64 " +
+ "encoded error encountered in close():\n" + e);
+ }
+
+ // (5) Decode the ASCII BASE 64 certificate enclosed in the
+ // String() object into a BINARY BASE 64 byte[] object
+
+ decodedBASE64Cert = Utils.base64decode(encodedBASE64Cert);
+
+ // (6) Create an X509CertImpl() object from the BINARY BASE 64
+ // byte[] object
+ try {
+ cert = new X509CertImpl(decodedBASE64Cert);
+ } catch (CertificateException e) {
+ System.out.println("PrettyPrintCert: Error encountered " +
+ "on parsing certificate :\n" + e);
+ }
+
+ if (mSimpleInfo) {
+ try {
+ X509CertInfo certinfo = (X509CertInfo) cert.get("x509.INFO");
+
+ CertificateSubjectName csn = (CertificateSubjectName)
+ certinfo.get(X509CertInfo.SUBJECT);
+
+ X500Name dname = (X500Name) csn.get(CertificateSubjectName.DN_NAME);
+
+ pp = "";
+ RDN[] rdns = dname.getNames();
+
+ for (int i = rdns.length - 1; i >= 0; i--) {
+ pp = pp + rdns[i] + "\n";
+ }
+
+ } catch (Exception e) {
+ System.out.println("ERROR");
+ e.printStackTrace();
+ }
+ } else {
+ // (7) For this utility, always specify the default Locale
+ aLocale = Locale.getDefault();
+
+ // (8) Create a CertPrettyPrint() object
+ certDetails = new CertPrettyPrint(cert);
+
+ // (9) Convert the CertPrettyPrint() object into a String() object
+ pp = certDetails.toString(aLocale);
+ }
+
+ // (10) Finally, "pretty print" the actual certificate to the console
+ // unless an output file has been specified
+ if (outputfile == null) {
+ System.out.println(pp);
+ } else {
+ try {
+ outputCert = new FileOutputStream(outputfile);
+ } catch (Exception e) {
+ System.out.println("PrettyPrintCert: unable to open file " +
+ argv[1] + " for writing:\n" + e);
+ return;
+ }
+
+ try {
+ outputCert.write(pp.getBytes());
+ } catch (IOException e) {
+ System.out.println("PrettyPrintCert: Unexpected error " +
+ "encountered while attempting to write() " +
+ outputfile + ":\n" + e);
+ }
+
+ try {
+ outputCert.close();
+ } catch (IOException e) {
+ System.out.println("PrettyPrintCert: Unexpected error " +
+ "encountered while attempting to close() " +
+ outputfile + ":\n" + e);
+ }
+ }
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/PrettyPrintCrl.java b/base/java-tools/src/com/netscape/cmstools/PrettyPrintCrl.java
new file mode 100644
index 000000000..8801b2423
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/PrettyPrintCrl.java
@@ -0,0 +1,212 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateException;
+import java.util.Locale;
+
+import com.netscape.cmsutil.util.Utils;
+
+import netscape.security.util.CrlPrettyPrint;
+import netscape.security.x509.DeltaCRLIndicatorExtension;
+import netscape.security.x509.HoldInstructionExtension;
+import netscape.security.x509.InvalidityDateExtension;
+import netscape.security.x509.IssuingDistributionPointExtension;
+import netscape.security.x509.OIDMap;
+import netscape.security.x509.X509CRLImpl;
+import netscape.security.x509.X509ExtensionException;
+
+/**
+ * The PrettyPrintCrl class is a utility program designed to "pretty print"
+ * a CRL. It assumes that the name of a data file is passed to the
+ * program via the command line, and that the contents contain a CRL
+ * encoded in an ASCII BASE 64 format. Note that the data file may contain
+ * an optional "-----BEGIN" header and/or an optional "-----END" trailer.
+ *
+ * <P>
+ * The program may be invoked as follows:
+ *
+ * <PRE>
+ *
+ * PrettyPrintCrl &lt;input filename&gt; [output filename]
+ *
+ * NOTE: &lt;input filename&gt; must contain an ASCII
+ * BASE 64 encoded CRL
+ *
+ * &lt;output filename&gt; contains a CRL displayed
+ * in a "pretty print" ASCII format
+ * </PRE>
+ *
+ * @version $Revision$, $Date$
+ */
+
+public class PrettyPrintCrl {
+ // Define constants
+ public static final int ARGC = 2;
+ public static final String HEADER = "-----BEGIN";
+ public static final String TRAILER = "-----END";
+
+ public static void main(String argv[]) {
+
+ BufferedReader inputCrl = null;
+ String encodedBASE64CrlChunk = new String();
+ String encodedBASE64Crl = new String();
+ byte decodedBASE64Crl[] = null;
+ X509CRLImpl crl = null;
+ Locale aLocale = null;
+ CrlPrettyPrint CrlDetails = null;
+ String pp = new String();
+ FileOutputStream outputCrl = null;
+
+ // (1) Check that at least one argument was submitted to the program
+ if ((argv.length < 1) || (argv.length > ARGC)) {
+ System.out.println("Usage: PrettyPrintCrl " +
+ "<input filename> " +
+ "[output filename]");
+ return;
+ }
+
+ try {
+ OIDMap.addAttribute(DeltaCRLIndicatorExtension.class.getName(),
+ DeltaCRLIndicatorExtension.OID,
+ DeltaCRLIndicatorExtension.NAME);
+ } catch (CertificateException e) {
+ }
+ try {
+ OIDMap.addAttribute(HoldInstructionExtension.class.getName(),
+ HoldInstructionExtension.OID,
+ HoldInstructionExtension.NAME);
+ } catch (CertificateException e) {
+ }
+ try {
+ OIDMap.addAttribute(InvalidityDateExtension.class.getName(),
+ InvalidityDateExtension.OID,
+ InvalidityDateExtension.NAME);
+ } catch (CertificateException e) {
+ }
+ try {
+ OIDMap.addAttribute(IssuingDistributionPointExtension.class.getName(),
+ IssuingDistributionPointExtension.OID,
+ IssuingDistributionPointExtension.NAME);
+ } catch (CertificateException e) {
+ }
+
+ // (2) Create a DataInputStream() object to the BASE 64
+ // encoded CRL contained within the file
+ // specified on the command line
+ try {
+ inputCrl = new BufferedReader(new InputStreamReader(
+ new BufferedInputStream(
+ new FileInputStream(
+ argv[0]))));
+ } catch (FileNotFoundException e) {
+ System.out.println("PrettyPrintCrl(): can''t find file " +
+ argv[0] + ":\n" + e);
+ return;
+ }
+
+ // (3) Read the entire contents of the specified BASE 64 encoded
+ // CRL into a String() object throwing away any
+ // headers beginning with HEADER and any trailers beginning
+ // with TRAILER
+ try {
+ while ((encodedBASE64CrlChunk = inputCrl.readLine()) != null) {
+ if (!(encodedBASE64CrlChunk.startsWith(HEADER)) &&
+ !(encodedBASE64CrlChunk.startsWith(TRAILER))) {
+ encodedBASE64Crl += encodedBASE64CrlChunk.trim();
+ }
+ }
+ } catch (IOException e) {
+ System.out.println("PrettyPrintCrl(): Unexpected BASE64 " +
+ "encoded error encountered in readLine():\n" +
+ e);
+ }
+
+ // (4) Close the DataInputStream() object
+ try {
+ inputCrl.close();
+ } catch (IOException e) {
+ System.out.println("PrettyPrintCrl(): Unexpected BASE64 " +
+ "encoded error encountered in close():\n" + e);
+ }
+
+ // (5) Decode the ASCII BASE 64 CRL enclosed in the
+ // String() object into a BINARY BASE 64 byte[] object
+
+ decodedBASE64Crl = Utils.base64decode(encodedBASE64Crl);
+
+ // (6) Create an X509CRLImpl() object from the BINARY BASE 64
+ // byte[] object
+ try {
+ crl = new X509CRLImpl(decodedBASE64Crl);
+ } catch (CRLException e) {
+ System.out.println("PrettyPrintCrl(): Error encountered " +
+ "on parsing and initialization errors:\n" + e);
+ } catch (X509ExtensionException e) {
+ System.out.println("PrettyPrintCrl(): Error encountered " +
+ "on parsing and initialization errors:\n" + e);
+ }
+
+ // (7) For this utility, always specify the default Locale
+ aLocale = Locale.getDefault();
+
+ // (8) Create a CrlPrettyPrint() object
+ CrlDetails = new CrlPrettyPrint(crl);
+
+ // (9) Convert the CrlPrettyPrint() object into a String() object
+ pp = CrlDetails.toString(aLocale);
+
+ // (10) Finally, "pretty print" the actual CRL to the console
+ // unless an output file has been specified
+ if (argv.length != ARGC) {
+ System.out.println(pp);
+ } else {
+ try {
+ outputCrl = new FileOutputStream(argv[1]);
+ } catch (IOException e) {
+ System.out.println("PrettyPrintCrl(): unable to open file " +
+ argv[1] + " for writing:\n" + e);
+ return;
+ }
+
+ try {
+ outputCrl.write(pp.getBytes());
+ } catch (IOException e) {
+ System.out.println("PrettyPrintCrl(): I/O error " +
+ "encountered during write():\n" +
+ e);
+ }
+
+ try {
+ outputCrl.close();
+ } catch (IOException e) {
+ System.out.println("PrettyPrintCrl(): Unexpected error " +
+ "encountered while attempting to close() " +
+ argv[1] + ":\n" + e);
+ }
+ }
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/TestCRLSigning.java b/base/java-tools/src/com/netscape/cmstools/TestCRLSigning.java
new file mode 100644
index 000000000..369010abf
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/TestCRLSigning.java
@@ -0,0 +1,115 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.util.Date;
+import java.util.Hashtable;
+
+import netscape.security.x509.RevokedCertImpl;
+import netscape.security.x509.RevokedCertificate;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.X509CRLImpl;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.KeyPairAlgorithm;
+import org.mozilla.jss.crypto.KeyPairGenerator;
+import org.mozilla.jss.util.Password;
+
+/**
+ * Tool used to test out signing a CRL
+ *
+ * <p>
+ *
+ * @version $Revision$ Date: $
+ */
+public class TestCRLSigning {
+ public static void printUsage() {
+ System.out.println("Command <dbdir> <numreovked> <keysize> <tokenname> <tokenpwd>");
+ }
+
+ public static void main(String args[]) throws Exception {
+ String dir = args[0];
+ String num = args[1];
+ String keysize = args[2];
+ String tokenname = args[3];
+ String tokenpwd = args[4];
+
+ // initialize JSS
+ CryptoManager cm = null;
+ CryptoManager.InitializationValues vals =
+ new CryptoManager.InitializationValues(dir, "", "", "secmod.db");
+ CryptoManager.initialize(vals);
+ cm = CryptoManager.getInstance();
+
+ // Login to token
+ CryptoToken token = null;
+ if (tokenname.equals("internal")) {
+ token = cm.getInternalKeyStorageToken();
+ } else {
+ token = cm.getTokenByName(tokenname);
+ }
+ Password pass = new Password(tokenpwd.toCharArray());
+ token.login(pass);
+
+ // generate key pair
+ KeyPairGenerator g = token.getKeyPairGenerator(KeyPairAlgorithm.RSA);
+ g.initialize(Integer.parseInt(keysize));
+ KeyPair pair = g.genKeyPair();
+
+ // generate revoked certificates
+ long startPutting = System.currentTimeMillis();
+ Date curDate = new Date();
+ Hashtable<BigInteger, RevokedCertificate> badCerts = new Hashtable<BigInteger, RevokedCertificate>();
+ int n = Integer.parseInt(num);
+ for (int i = 0; i < n; i++) {
+ badCerts.put(new BigInteger(Integer.toString(i)),
+ new RevokedCertImpl(new BigInteger(Integer.toString(i)), curDate));
+ }
+ long endPutting = System.currentTimeMillis();
+
+ long startConstructing = System.currentTimeMillis();
+ X509CRLImpl crl = new X509CRLImpl(
+ new X500Name("CN=Signer"),
+ null,
+ curDate,
+ curDate,
+ badCerts,
+ null);
+ long endConstructing = System.currentTimeMillis();
+
+ System.out.println("Start signing");
+ long startSigning = System.currentTimeMillis();
+ crl.sign(pair.getPrivate(), "SHA1withRSA");
+ long endSigning = System.currentTimeMillis();
+ System.out.println("Done signing");
+
+ long startData = System.currentTimeMillis();
+ byte data[] = crl.getTBSCertList();
+ long endData = System.currentTimeMillis();
+
+ System.out.println("Summary:");
+ System.out.println("Insertion time (ms): " + Long.toString(endPutting - startPutting));
+ System.out.println("Construction time (ms): " + Long.toString(endConstructing - startConstructing));
+ System.out.println("Signing time (ms): " + Long.toString(endSigning - startSigning));
+ System.out.println("Data time (ms): " + Long.toString(endData - startData));
+ System.out.println("Data size (bytes): " + Long.toString(data.length));
+ }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/TokenInfo.java b/base/java-tools/src/com/netscape/cmstools/TokenInfo.java
new file mode 100644
index 000000000..fc3d13b42
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/TokenInfo.java
@@ -0,0 +1,75 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmstools;
+
+import java.util.Enumeration;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.pkcs11.PK11Module;
+
+/**
+ * Tool used to determine which external hardware tokens are visible to the
+ * Certificate System subsystem. This can be used to diagnose whether problems
+ * using tokens are related to the Certificate System being unable to detect it.
+ *
+ * <p>
+ *
+ * @version $Revision$ Date: $
+ */
+public class TokenInfo {
+
+ /**
+ * Creates a new instance of CMCRevoke.
+ */
+ public static void main(String[] args) {
+ try {
+ if (args.length != 1) {
+ System.out.println("Usage: TokenInfo <alias directory>");
+ System.exit(0);
+ }
+ System.out.println("Database Path: " + args[0]);
+
+ CryptoManager.InitializationValues vals =
+ new CryptoManager.InitializationValues(args[0],
+ "", "", "secmod.db");
+
+ CryptoManager.initialize(vals);
+
+ CryptoManager cm = CryptoManager.getInstance();
+ @SuppressWarnings("unchecked")
+ Enumeration<PK11Module> modules = cm.getModules();
+ while (modules.hasMoreElements()) {
+ PK11Module m = modules.nextElement();
+ System.out.println("Found external module '" + m.getName() + "'");
+ }
+ @SuppressWarnings("unchecked")
+ Enumeration<CryptoToken> tokens = cm.getExternalTokens();
+
+ while (tokens.hasMoreElements()) {
+ CryptoToken t = tokens.nextElement();
+ System.out.println("Found external token '" + t.getName() + "'");
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ }
+}