// --- 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.CryptoStore;
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;
/**
* Tool for creating CMC full request
*
*
* @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.
*
* @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");
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 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 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