summaryrefslogtreecommitdiffstats
path: root/base/java-tools/src/com/netscape/cmstools/CMCRevoke.java
diff options
context:
space:
mode:
Diffstat (limited to 'base/java-tools/src/com/netscape/cmstools/CMCRevoke.java')
-rw-r--r--base/java-tools/src/com/netscape/cmstools/CMCRevoke.java426
1 files changed, 426 insertions, 0 deletions
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;
+ }
+}