diff options
Diffstat (limited to 'base/common/src/com/netscape/cms/servlet/processors')
6 files changed, 1601 insertions, 0 deletions
diff --git a/base/common/src/com/netscape/cms/servlet/processors/CMCProcessor.java b/base/common/src/com/netscape/cms/servlet/processors/CMCProcessor.java new file mode 100644 index 000000000..53c13510d --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/processors/CMCProcessor.java @@ -0,0 +1,433 @@ +// --- 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.cms.servlet.processors; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.PublicKey; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Hashtable; + +import netscape.security.pkcs.PKCS10; +import netscape.security.x509.CertificateX509Key; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; +import netscape.security.x509.X509Key; + +import org.mozilla.jss.asn1.ANY; +import org.mozilla.jss.asn1.ASN1Util; +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.crypto.DigestAlgorithm; +import org.mozilla.jss.crypto.PrivateKey; +import org.mozilla.jss.pkcs10.CertificationRequest; +import org.mozilla.jss.pkcs11.PK11PubKey; +import org.mozilla.jss.pkix.cert.Certificate; +import org.mozilla.jss.pkix.cert.CertificateInfo; +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.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.crmf.CertReqMsg; +import org.mozilla.jss.pkix.crmf.CertRequest; +import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier; +import org.mozilla.jss.pkix.primitive.Name; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Process CMC messages according to RFC 2797 + * See http://www.ietf.org/rfc/rfc2797.txt + * + * @version $Revision$, $Date$ + */ +public class CMCProcessor extends PKIProcessor { + + private boolean enforcePop = false; + + public CMCProcessor() { + super(); + } + + public CMCProcessor(CMSRequest cmsReq, CMSServlet servlet, boolean doEnforcePop) { + + super(cmsReq, servlet); + enforcePop = doEnforcePop; + + } + + public void process(CMSRequest cmsReq) + throws EBaseException { + } + + public void fillCertInfo( + String protocolString, X509CertInfo certInfo, + IAuthToken authToken, IArgBlock httpParams) + throws EBaseException { + } + + public X509CertInfo[] fillCertInfoArray( + String protocolString, IAuthToken authToken, IArgBlock httpParams, IRequest req) + throws EBaseException { + + CMS.debug("CMCProcessor: In CMCProcessor.fillCertInfoArray!"); + String cmc = protocolString; + + try { + byte[] cmcBlob = CMS.AtoB(cmc); + ByteArrayInputStream cmcBlobIn = + new ByteArrayInputStream(cmcBlob); + + org.mozilla.jss.pkix.cms.ContentInfo cmcReq = (org.mozilla.jss.pkix.cms.ContentInfo) + org.mozilla.jss.pkix.cms.ContentInfo.getTemplate().decode(cmcBlobIn); + + if (!cmcReq.getContentType().equals(org.mozilla.jss.pkix.cms.ContentInfo.SIGNED_DATA) + || !cmcReq.hasContent()) + throw new ECMSGWException(CMS.getUserMessage("CMS_GW_NO_CMC_CONTENT")); + + SignedData cmcFullReq = (SignedData) + cmcReq.getInterpretedContent(); + + EncapsulatedContentInfo ci = cmcFullReq.getContentInfo(); + + OBJECT_IDENTIFIER id = ci.getContentType(); + + if (!id.equals(OBJECT_IDENTIFIER.id_cct_PKIData) || !ci.hasContent()) { + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_NO_PKIDATA")); + } + OCTET_STRING content = ci.getContent(); + + ByteArrayInputStream s = new ByteArrayInputStream(content.toByteArray()); + PKIData pkiData = (PKIData) (new PKIData.Template()).decode(s); + + SEQUENCE reqSequence = pkiData.getReqSequence(); + + int numReqs = reqSequence.size(); + X509CertInfo[] certInfoArray = new X509CertInfo[numReqs]; + String[] reqIdArray = new String[numReqs]; + + for (int i = 0; i < numReqs; i++) { + // decode message. + TaggedRequest taggedRequest = (TaggedRequest) reqSequence.elementAt(i); + + TaggedRequest.Type type = taggedRequest.getType(); + + if (type.equals(TaggedRequest.PKCS10)) { + TaggedCertificationRequest tcr = taggedRequest.getTcr(); + int p10Id = tcr.getBodyPartID().intValue(); + + reqIdArray[i] = String.valueOf(p10Id); + + CertificationRequest p10 = + tcr.getCertificationRequest(); + + // transfer to sun class + ByteArrayOutputStream ostream = new ByteArrayOutputStream(); + + p10.encode(ostream); + + PKCS10Processor pkcs10Processor = new PKCS10Processor(mRequest, mServlet); + + try { + PKCS10 pkcs10 = new PKCS10(ostream.toByteArray()); + //xxx do we need to do anything else? + X509CertInfo certInfo = CMS.getDefaultX509CertInfo(); + + pkcs10Processor.fillCertInfo(pkcs10, certInfo, authToken, httpParams); + + /* fillPKCS10(pkcs10,certInfo, + authToken, httpParams); + */ + + certInfoArray[i] = certInfo; + } catch (Exception e) { + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_PKCS10_ERROR", e.toString())); + } + } else if (type.equals(TaggedRequest.CRMF)) { + + CRMFProcessor crmfProc = new CRMFProcessor(mRequest, mServlet, enforcePop); + + CertReqMsg crm = taggedRequest.getCrm(); + CertRequest certReq = crm.getCertReq(); + + INTEGER certReqId = certReq.getCertReqId(); + int srcId = certReqId.intValue(); + + reqIdArray[i] = String.valueOf(srcId); + + certInfoArray[i] = crmfProc.processIndividualRequest(crm, authToken, httpParams); + + } else { + throw new ECMSGWException(CMS.getUserMessage("CMS_GW_NO_CMC_CONTENT")); + } + } + + // verify the signerInfo + SET dais = cmcFullReq.getDigestAlgorithmIdentifiers(); + int numDig = dais.size(); + Hashtable<String, byte[]> digs = new Hashtable<String, byte[]>(); + + for (int i = 0; i < numDig; i++) { + AlgorithmIdentifier dai = + (AlgorithmIdentifier) dais.elementAt(i); + String name = + DigestAlgorithm.fromOID(dai.getOID()).toString(); + + MessageDigest md = + MessageDigest.getInstance(name); + + byte[] digest = md.digest(content.toByteArray()); + + digs.put(name, digest); + } + + SET sis = cmcFullReq.getSignerInfos(); + int numSis = sis.size(); + + for (int i = 0; i < numSis; i++) { + org.mozilla.jss.pkix.cms.SignerInfo si = + (org.mozilla.jss.pkix.cms.SignerInfo) + sis.elementAt(i); + + String name = si.getDigestAlgorithm().toString(); + byte[] digest = (byte[]) digs.get(name); + + if (digest == null) { + MessageDigest md = MessageDigest.getInstance(name); + ByteArrayOutputStream ostream = new ByteArrayOutputStream(); + + pkiData.encode((OutputStream) ostream); + digest = md.digest(ostream.toByteArray()); + + } + + SignerIdentifier sid = si.getSignerIdentifier(); + + if (sid.getType().equals(SignerIdentifier.ISSUER_AND_SERIALNUMBER)) { + IssuerAndSerialNumber issuerAndSerialNumber = sid.getIssuerAndSerialNumber(); + // find from the certs in the signedData + X509Certificate cert = null; + + if (cmcFullReq.hasCertificates()) { + SET certs = cmcFullReq.getCertificates(); + int numCerts = certs.size(); + + for (int j = 0; j < numCerts; j++) { + Certificate certJss = + (Certificate) certs.elementAt(j); + CertificateInfo certI = + certJss.getInfo(); + Name issuer = certI.getIssuer(); + byte[] issuerB = ASN1Util.encode(issuer); + + INTEGER sn = certI.getSerialNumber(); + + if (new String(issuerB).equals(new + String(ASN1Util.encode(issuerAndSerialNumber.getIssuer()))) + && sn.toString().equals(issuerAndSerialNumber.getSerialNumber().toString())) { + ByteArrayOutputStream os = new + ByteArrayOutputStream(); + + certJss.encode(os); + cert = new X509CertImpl(os.toByteArray()); + // xxx validate the cert length + + } + } + + } + // find from internaldb if it's ca. (ra does not have that.) + // find from internaldb usrgrp info + + if (cert == null) { + // find from certDB + si.verify(digest, id); + } else { + PublicKey signKey = cert.getPublicKey(); + PrivateKey.Type keyType = null; + String alg = signKey.getAlgorithm(); + + if (alg.equals("RSA")) { + keyType = PrivateKey.RSA; + } else if (alg.equals("DSA")) { + keyType = PrivateKey.DSA; + } else { + } + PK11PubKey pubK = + PK11PubKey.fromRaw(keyType, + ((X509Key) signKey).getKey()); + + si.verify(digest, id, pubK); + } + + } else { + OCTET_STRING ski = sid.getSubjectKeyIdentifier(); + // find the publicKey using ski + int j = 0; + PublicKey signKey = null; + + while (signKey == null && j < numReqs) { + X509Key subjectKeyInfo = + (X509Key) ((CertificateX509Key) certInfoArray[j].get(X509CertInfo.KEY)) + .get(CertificateX509Key.KEY); + MessageDigest md = MessageDigest.getInstance("SHA-1"); + + md.update(subjectKeyInfo.getEncoded()); + byte[] skib = md.digest(); + + if (new String(skib).equals(new String(ski.toByteArray()))) { + signKey = subjectKeyInfo; + } + j++; + } + if (signKey == null) { + throw new ECMSGWException(CMS.getUserMessage("CMS_GW_CMC_ERROR", + "SubjectKeyIdentifier in SignerInfo does not match any publicKey in the request.")); + } else { + PrivateKey.Type keyType = null; + String alg = signKey.getAlgorithm(); + + if (alg.equals("RSA")) { + keyType = PrivateKey.RSA; + } else if (alg.equals("DSA")) { + keyType = PrivateKey.DSA; + } else { + } + PK11PubKey pubK = PK11PubKey.fromRaw( + keyType, + ((X509Key) signKey).getKey()); + + si.verify(digest, id, pubK); + } + } + } + // end verify signerInfo + + // Get control sequence + // verisign has transactionId, senderNonce, regInfo + // identification, identityproof + SEQUENCE controls = pkiData.getControlSequence(); + int numControls = controls.size(); + + for (int i = 0; i < numControls; i++) { + TaggedAttribute control = + (TaggedAttribute) controls.elementAt(i); + OBJECT_IDENTIFIER type = control.getType(); + SET values = control.getValues(); + int numVals = values.size(); + + if (type.equals(OBJECT_IDENTIFIER.id_cmc_transactionId)) { + String[] vals = null; + + if (numVals > 0) + vals = new String[numVals]; + for (int j = 0; j < numVals; j++) { + ANY val = (ANY) + values.elementAt(j); + INTEGER transId = (INTEGER) ((ANY) val).decodeWith( + INTEGER.getTemplate()); + + if (transId != null) { + vals[j] = transId.toString(); + } + } + if (vals != null) + req.setExtData(IRequest.CMC_TRANSID, vals); + } else if (type.equals(OBJECT_IDENTIFIER.id_cmc_senderNonce)) { + String[] vals = null; + + if (numVals > 0) + vals = new String[numVals]; + for (int j = 0; j < numVals; j++) { + ANY val = (ANY) + values.elementAt(j); + OCTET_STRING nonce = (OCTET_STRING) + ((ANY) val).decodeWith(OCTET_STRING.getTemplate()); + + if (nonce != null) { + vals[j] = new String(nonce.toByteArray()); + } + } + if (vals != null) + req.setExtData(IRequest.CMC_SENDERNONCE, vals); + + } else if (type.equals(OBJECT_IDENTIFIER.id_cmc_regInfo)) { + // what can we do here + // for verisign, we just debug.print() + } else if (type.equals(OBJECT_IDENTIFIER.id_cmc_identification)) { + // what can we do here + // for verisign, we just debug.print() + } else if (type.equals(OBJECT_IDENTIFIER.id_cmc_identityProof)) { + // what can we do here + // for verisign, we just debug.print() + } + } + + req.setExtData(IRequest.CMC_REQIDS, reqIdArray); + return certInfoArray; + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_CMC_TO_CERTINFO_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_CMC_TO_CERTINFO_ERROR")); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_CMC_TO_CERTINFO_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_CMC_TO_CERTINFO_ERROR")); + } catch (InvalidBERException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_CMC_TO_CERTINFO_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_CMC_TO_CERTINFO_ERROR")); + } catch (InvalidKeyException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_CMC_TO_CERTINFO_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_CMC_TO_CERTINFO_ERROR")); + } catch (Exception e) { + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_CMC_ERROR", e.toString())); + } + + } + +} diff --git a/base/common/src/com/netscape/cms/servlet/processors/CRMFProcessor.java b/base/common/src/com/netscape/cms/servlet/processors/CRMFProcessor.java new file mode 100644 index 000000000..2d2f1430e --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/processors/CRMFProcessor.java @@ -0,0 +1,372 @@ +// --- 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.cms.servlet.processors; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.cert.CertificateException; + +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateSubjectName; +import netscape.security.x509.CertificateValidity; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.CertificateX509Key; +import netscape.security.x509.Extension; +import netscape.security.x509.X500Name; +import netscape.security.x509.X509CertInfo; +import netscape.security.x509.X509Key; + +import org.mozilla.jss.asn1.INTEGER; +import org.mozilla.jss.asn1.InvalidBERException; +import org.mozilla.jss.asn1.SEQUENCE; +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.ProofOfPossession; +import org.mozilla.jss.pkix.primitive.Name; +import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.AuthToken; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Process CRMF requests, according to RFC 2511 + * See http://www.ietf.org/rfc/rfc2511.txt + * + * @version $Revision$, $Date$ + */ +public class CRMFProcessor extends PKIProcessor { + + private CMSRequest mRequest; + + private boolean enforcePop = false; + + private final static String LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION = + "LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION_2"; + + public CRMFProcessor() { + super(); + } + + public CRMFProcessor(CMSRequest cmsReq, CMSServlet servlet, boolean doEnforcePop) { + super(cmsReq, servlet); + + enforcePop = doEnforcePop; + mRequest = cmsReq; + } + + public void process(CMSRequest cmsReq) + throws EBaseException { + } + + /** + * Verify Proof of Possession (POP) + * <P> + * + * <ul> + * <li>signed.audit LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION used when proof of possession is checked during + * certificate enrollment + * </ul> + * + * @param certReqMsg the certificate request message + * @exception EBaseException an error has occurred + */ + private void verifyPOP(CertReqMsg certReqMsg) + throws EBaseException { + String auditMessage = null; + String auditSubjectID = auditSubjectID(); + + try { + CMS.debug("CRMFProcessor: verifyPOP"); + + if (certReqMsg.hasPop()) { + ProofOfPossession pop = certReqMsg.getPop(); + + ProofOfPossession.Type popType = pop.getType(); + + if (popType == ProofOfPossession.SIGNATURE) { + CMS.debug("CRMFProcessor: Request has pop."); + try { + certReqMsg.verify(); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION, + auditSubjectID, + ILogger.SUCCESS); + + audit(auditMessage); + } catch (Exception e) { + CMS.debug("CRMFProcessor: Failed POP verify!"); + + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_POP_VERIFY")); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION, + auditSubjectID, + ILogger.FAILURE); + + audit(auditMessage); + + throw new ECMSGWException( + CMS.getLogMessage("CMSGW_ERROR_POP_VERIFY")); + } + } + } else { + if (enforcePop == true) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_NO_POP")); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION, + auditSubjectID, + ILogger.FAILURE); + + audit(auditMessage); + + throw new ECMSGWException( + CMS.getLogMessage("CMSGW_ERROR_NO_POP")); + } + } + } catch (EBaseException eAudit1) { + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_PROOF_OF_POSSESSION, + auditSubjectID, + ILogger.FAILURE); + + audit(auditMessage); + } + } + + public X509CertInfo processIndividualRequest(CertReqMsg certReqMsg, IAuthToken authToken, IArgBlock httpParams) + throws EBaseException { + CMS.debug("CRMFProcessor::processIndividualRequest!"); + + try { + + verifyPOP(certReqMsg); + + CertRequest certReq = certReqMsg.getCertReq(); + + CertTemplate certTemplate = certReq.getCertTemplate(); + X509CertInfo certInfo = CMS.getDefaultX509CertInfo(); + + // get key + SubjectPublicKeyInfo spki = certTemplate.getPublicKey(); + ByteArrayOutputStream keyout = new ByteArrayOutputStream(); + + spki.encode(keyout); + byte[] keybytes = keyout.toByteArray(); + X509Key key = new X509Key(); + + key.decode(keybytes); + certInfo.set(X509CertInfo.KEY, new CertificateX509Key(key)); + + // field suggested notBefore and notAfter in CRMF + // Tech Support #383184 + if (certTemplate.getNotBefore() != null || certTemplate.getNotAfter() != null) { + CertificateValidity certValidity = + new CertificateValidity(certTemplate.getNotBefore(), certTemplate.getNotAfter()); + + certInfo.set(X509CertInfo.VALIDITY, certValidity); + } + + if (certTemplate.hasSubject()) { + Name subjectdn = certTemplate.getSubject(); + ByteArrayOutputStream subjectEncStream = + new ByteArrayOutputStream(); + + subjectdn.encode(subjectEncStream); + byte[] subjectEnc = subjectEncStream.toByteArray(); + X500Name subject = new X500Name(subjectEnc); + + certInfo.set(X509CertInfo.SUBJECT, + new CertificateSubjectName(subject)); + } else if (authToken == null || + authToken.getInString(AuthToken.TOKEN_CERT_SUBJECT) == null) { + // No subject name - error! + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_SUBJECT_NAME_FROM_AUTHTOKEN")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_MISSING_SUBJECT_NAME_FROM_AUTHTOKEN")); + } + + // get extensions + CertificateExtensions extensions = null; + + try { + extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + } catch (CertificateException e) { + extensions = null; + } catch (IOException e) { + extensions = null; + } + if (certTemplate.hasExtensions()) { + // put each extension from CRMF into CertInfo. + // index by extension name, consistent with + // CertificateExtensions.parseExtension() method. + if (extensions == null) + extensions = new CertificateExtensions(); + int numexts = certTemplate.numExtensions(); + + for (int j = 0; j < numexts; j++) { + org.mozilla.jss.pkix.cert.Extension jssext = + certTemplate.extensionAt(j); + boolean isCritical = jssext.getCritical(); + org.mozilla.jss.asn1.OBJECT_IDENTIFIER jssoid = + jssext.getExtnId(); + long[] numbers = jssoid.getNumbers(); + int[] oidNumbers = new int[numbers.length]; + + for (int k = numbers.length - 1; k >= 0; k--) { + oidNumbers[k] = (int) numbers[k]; + } + ObjectIdentifier oid = + new ObjectIdentifier(oidNumbers); + org.mozilla.jss.asn1.OCTET_STRING jssvalue = + jssext.getExtnValue(); + ByteArrayOutputStream jssvalueout = + new ByteArrayOutputStream(); + + jssvalue.encode(jssvalueout); + byte[] extValue = jssvalueout.toByteArray(); + + Extension ext = + new Extension(oid, isCritical, extValue); + + extensions.parseExtension(ext); + } + + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + + } + + // Added a new configuration parameter + // eeGateway.Enrollment.authTokenOverride=[true|false] + // By default, it is set to true. In most + // of the case, administrator would want + // to have the control of the subject name + // formulation. + // -- CRMFfillCert + if (authToken != null && + authToken.getInString(AuthToken.TOKEN_CERT_SUBJECT) != null) { + // if authenticated override subect name, validity and + // extensions if any from authtoken. + fillCertInfoFromAuthToken(certInfo, authToken); + } + + // SPECIAL CASE: + // if it is adminEnroll servlet, get the validity + // from the http parameters. + if (mServletId.equals(PKIProcessor.ADMIN_ENROLL_SERVLET_ID)) { + fillValidityFromForm(certInfo, httpParams); + } + + return certInfo; + + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_CRMF_TO_CERTINFO_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_CRMF_TO_CERTINFO_ERROR")); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_CRMF_TO_CERTINFO_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_CRMF_TO_CERTINFO_ERROR")); + } /* catch (InvalidBERException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_CRMF_TO_CERTINFO_1",e.toString())); + throw new ECMSGWException( + CMSGWResources.ERROR_CRMF_TO_CERTINFO); + } */catch (InvalidKeyException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_CRMF_TO_CERTINFO_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_CRMF_TO_CERTINFO_ERROR")); + } + + } + + public X509CertInfo[] fillCertInfoArray( + String protocolString, IAuthToken authToken, IArgBlock httpParams, IRequest req) + throws EBaseException { + + CMS.debug("CRMFProcessor.fillCertInfoArray!"); + + String crmf = protocolString; + + try { + byte[] crmfBlob = CMS.AtoB(crmf); + ByteArrayInputStream crmfBlobIn = + new ByteArrayInputStream(crmfBlob); + + SEQUENCE crmfMsgs = (SEQUENCE) + new SEQUENCE.OF_Template(new CertReqMsg.Template()).decode(crmfBlobIn); + + int nummsgs = crmfMsgs.size(); + X509CertInfo[] certInfoArray = new X509CertInfo[nummsgs]; + + for (int i = 0; i < nummsgs; i++) { + // decode message. + CertReqMsg certReqMsg = (CertReqMsg) crmfMsgs.elementAt(i); + + CertRequest certReq = certReqMsg.getCertReq(); + INTEGER certReqId = certReq.getCertReqId(); + int srcId = certReqId.intValue(); + + req.setExtData(IRequest.CRMF_REQID, String.valueOf(srcId)); + + certInfoArray[i] = processIndividualRequest(certReqMsg, authToken, httpParams); + + } + + //do_testbed_hack(nummsgs, certInfoArray, httpParams); + + return certInfoArray; + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_CRMF_TO_CERTINFO_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_CRMF_TO_CERTINFO_ERROR")); + } catch (InvalidBERException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_CRMF_TO_CERTINFO_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_CRMF_TO_CERTINFO_ERROR")); + } + } +} diff --git a/base/common/src/com/netscape/cms/servlet/processors/IPKIProcessor.java b/base/common/src/com/netscape/cms/servlet/processors/IPKIProcessor.java new file mode 100644 index 000000000..9139f888c --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/processors/IPKIProcessor.java @@ -0,0 +1,33 @@ +// --- 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.cms.servlet.processors; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.cms.servlet.common.CMSRequest; + +/** + * This represents the request parser. + * + * @version $Revision$, $Date$ + */ +public interface IPKIProcessor { + + public void process(CMSRequest cmsReq) + throws EBaseException; + +} diff --git a/base/common/src/com/netscape/cms/servlet/processors/KeyGenProcessor.java b/base/common/src/com/netscape/cms/servlet/processors/KeyGenProcessor.java new file mode 100644 index 000000000..cfe9754a8 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/processors/KeyGenProcessor.java @@ -0,0 +1,120 @@ +// --- 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.cms.servlet.processors; + +import java.io.IOException; +import java.security.cert.CertificateException; + +import netscape.security.x509.CertificateX509Key; +import netscape.security.x509.X509CertInfo; +import netscape.security.x509.X509Key; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.AuthToken; +import com.netscape.certsrv.authentication.IAuthSubsystem; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.KeyGenInfo; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * KeyGenProcess parses Certificate request matching the + * KEYGEN tag format used by Netscape Communicator 4.x + * + * @version $Revision$, $Date$ + */ +public class KeyGenProcessor extends PKIProcessor { + + public KeyGenProcessor() { + super(); + } + + public KeyGenProcessor(CMSRequest cmsReq, CMSServlet servlet) { + super(cmsReq, servlet); + + } + + public void process(CMSRequest cmsReq) + throws EBaseException { + } + + public void fillCertInfo( + String protocolString, X509CertInfo certInfo, + IAuthToken authToken, IArgBlock httpParams) + throws EBaseException { + + CMS.debug("KeyGenProcessor: fillCertInfo"); + + if (mServlet == null) { + return; + } + + KeyGenInfo keyGenInfo = httpParams.getValueAsKeyGenInfo( + PKIProcessor.SUBJECT_KEYGEN_INFO, null); + + // fill key + X509Key key = null; + + key = keyGenInfo.getSPKI(); + if (key == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_MISSING_KEY_IN_KEYGENINFO")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_MISSING_KEY_IN_KEYGENINFO")); + } + try { + certInfo.set(X509CertInfo.KEY, new CertificateX509Key(key)); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + "Could not set key into certInfo from keygen. Error " + e); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_KEY_FROM_KEYGEN_FAILED", e.toString())); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAILED_SET_KEY_FROM_KEYGEN_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_KEY_FROM_KEYGEN_FAILED", e.toString())); + } + + String authMgr = mServlet.getAuthMgr(); + + // if not authenticated, fill subject name, validity & extensions + // from authtoken. + if (authToken == null) { + fillCertInfoFromForm(certInfo, httpParams); + } else { + if (authToken.getInString(AuthToken.TOKEN_CERT_SUBJECT) == null) { + // allow special case for agent gateway in admin enroll + // and bulk issuance. + if (!authMgr.equals(IAuthSubsystem.CERTUSERDB_AUTHMGR_ID) && + !authMgr.equals(IAuthSubsystem.PASSWDUSERDB_AUTHMGR_ID)) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_SUBJECT_NAME_FROM_AUTHTOKEN")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_MISSING_SUBJECT_NAME_FROM_AUTHTOKEN")); + } + fillCertInfoFromForm(certInfo, httpParams); + } else { + fillCertInfoFromAuthToken(certInfo, authToken); + } + } + } +} diff --git a/base/common/src/com/netscape/cms/servlet/processors/PKCS10Processor.java b/base/common/src/com/netscape/cms/servlet/processors/PKCS10Processor.java new file mode 100644 index 000000000..dad4b64ab --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/processors/PKCS10Processor.java @@ -0,0 +1,287 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cms.servlet.processors; + +import java.io.IOException; +import java.security.cert.CertificateException; + +import netscape.security.pkcs.PKCS10; +import netscape.security.pkcs.PKCS10Attribute; +import netscape.security.pkcs.PKCS10Attributes; +import netscape.security.pkcs.PKCS9Attribute; +import netscape.security.util.DerInputStream; +import netscape.security.util.DerOutputStream; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateSubjectName; +import netscape.security.x509.CertificateX509Key; +import netscape.security.x509.Extensions; +import netscape.security.x509.X500Name; +import netscape.security.x509.X509CertInfo; +import netscape.security.x509.X509Key; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.AuthToken; +import com.netscape.certsrv.authentication.IAuthSubsystem; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * PKCS10Processor process Certificate Requests in + * PKCS10 format, as defined here: + * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-10/index.html + * + * @version $Revision$, $Date$ + */ +public class PKCS10Processor extends PKIProcessor { + + private PKCS10 mPkcs10 = null; + + private final String USE_INTERNAL_PKCS10 = "internal"; + + public PKCS10Processor() { + + super(); + } + + public PKCS10Processor(CMSRequest cmsReq, CMSServlet servlet) { + super(cmsReq, servlet); + + } + + public void process(CMSRequest cmsReq) + throws EBaseException { + } + + public void fillCertInfo( + PKCS10 pkcs10, X509CertInfo certInfo, + IAuthToken authToken, IArgBlock httpParams) + throws EBaseException { + + mPkcs10 = pkcs10; + + fillCertInfo(USE_INTERNAL_PKCS10, certInfo, authToken, httpParams); + + } + + public void fillCertInfo( + String protocolString, X509CertInfo certInfo, + IAuthToken authToken, IArgBlock httpParams) + throws EBaseException { + + PKCS10 p10 = null; + + CMS.debug("PKCS10Processor:fillCertInfo"); + + if (protocolString == null) { + p10 = getPKCS10(httpParams); + } else if (protocolString.equals(USE_INTERNAL_PKCS10)) { + p10 = mPkcs10; + } else { + CMS.debug("PKCS10Processor::fillCertInfo() - p10 is null!"); + throw new EBaseException("p10 is null"); + } + + if (mServlet == null) { + EBaseException ex = new ECMSGWException("Servlet property of PKCS10Processor is null."); + + throw ex; + + } + + // fill key + X509Key key = p10.getSubjectPublicKeyInfo(); + + if (key == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_MISSING_KEY_IN_P10")); + throw new ECMSGWException(CMS.getUserMessage("CMS_GW_MISSING_KEY_IN_P10")); + } + CertificateX509Key certKey = new CertificateX509Key(key); + + try { + certInfo.set(X509CertInfo.KEY, certKey); + } catch (CertificateException e) { + EBaseException ex = new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_KEY_FROM_P10_FAILED", e.toString())); + + log(ILogger.LL_FAILURE, ex.toString()); + throw ex; + } catch (IOException e) { + EBaseException ex = new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_KEY_FROM_P10_FAILED", e.toString())); + + log(ILogger.LL_FAILURE, ex.toString()); + throw ex; + } + + X500Name subject = p10.getSubjectName(); + + if (subject != null) { + try { + certInfo.set(X509CertInfo.SUBJECT, + new CertificateSubjectName(subject)); + log(ILogger.LL_INFO, + "Setting subject name " + subject + " from p10."); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAILED_SET_SUBJECT_FROM_P10", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_SUBJECT_FROM_P10_FAILED", e.toString())); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAILED_SET_SUBJECT_FROM_P10", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_SUBJECT_FROM_P10_FAILED", e.toString())); + } catch (Exception e) { + // if anything bad happens in X500 name parsing, + // this will catch it. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAILED_SET_SUBJECT_FROM_P10", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_SUBJECT_FROM_P10_FAILED", e.toString())); + } + } else if (authToken == null || + authToken.getInString(AuthToken.TOKEN_CERT_SUBJECT) == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_SUBJECT_IN_P10")); + throw new ECMSGWException(CMS.getUserMessage("CMS_GW_MISSING_SUBJECT_IN_P10")); + } + + // fill extensions from pkcs 10 attributes if any. + // other pkcs10 attributes are not recognized. + // ExtensionReq ::= SEQUENCE OF Extension + // ExtensionReq {pkcs-9 14}. + try { + PKCS10Attributes p10Attrs = p10.getAttributes(); + + if (p10Attrs != null) { + PKCS10Attribute p10Attr = (PKCS10Attribute) + (p10Attrs.getAttribute(CertificateExtensions.NAME)); + + if (p10Attr != null && p10Attr.getAttributeId().equals( + PKCS9Attribute.EXTENSION_REQUEST_OID)) { + Extensions exts0 = (Extensions) + (p10Attr.getAttributeValue()); + DerOutputStream extOut = new DerOutputStream(); + + exts0.encode(extOut); + byte[] extB = extOut.toByteArray(); + DerInputStream extIn = new DerInputStream(extB); + CertificateExtensions exts = new CertificateExtensions(extIn); + + if (exts != null) { + certInfo.set(X509CertInfo.EXTENSIONS, exts); + } + } + } + CMS.debug( + "PKCS10Processor: Seted cert extensions from pkcs10. "); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAILED_SET_EXTENSIONS_FROM_P10", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_KEY_FROM_P10_FAILED", e.toString())); + + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAILED_SET_EXTENSIONS_FROM_P10", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_KEY_FROM_P10_FAILED", e.toString())); + } catch (Exception e) { + // if anything bad happens in extensions parsing, + // this will catch it. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAILED_SET_EXTENSIONS_FROM_P10", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_KEY_FROM_P10_FAILED", e.toString())); + } + + // override pkcs10 attributes with authtoken attributes + // like subject name, validity and extensions if any. + // adminEnroll is an exception + String authMgr = mServlet.getAuthMgr(); + + if (authToken != null && + authToken.getInString(AuthToken.TOKEN_CERT_SUBJECT) != null && + !(authMgr.equals(IAuthSubsystem.PASSWDUSERDB_AUTHMGR_ID))) { + fillCertInfoFromAuthToken(certInfo, authToken); + } + + // SPECIAL CASE: + // if it is adminEnroll servlet, get the validity + // from the http parameters. + if (mServletId.equals(PKIProcessor.ADMIN_ENROLL_SERVLET_ID)) { + fillValidityFromForm(certInfo, httpParams); + } + + } + + private PKCS10 getPKCS10(IArgBlock httpParams) + throws EBaseException { + + PKCS10 pkcs10 = null; + + String certType = null; + + // support Enterprise 3.5.1 server where CERT_TYPE=csrCertType + // instead of certType + certType = httpParams.getValueAsString(PKIProcessor.OLD_CERT_TYPE, null); + if (certType == null) { + certType = httpParams.getValueAsString(PKIProcessor.CERT_TYPE, "client"); + } else { + // some policies may rely on the fact that + // CERT_TYPE is set. So for 3.5.1 or eariler + // we need to set CERT_TYPE but not here. + } + if (certType.equals("client")) { + // coming from MSIE + String p10b64 = httpParams.getValueAsString(PKIProcessor.PKCS10_REQUEST, null); + + if (p10b64 != null) { + try { + byte[] bytes = CMS.AtoB(p10b64); + + pkcs10 = new PKCS10(bytes); + } catch (Exception e) { + // ok, if the above fails, it could + // be a PKCS10 with header + pkcs10 = httpParams.getValueAsPKCS10(PKIProcessor.PKCS10_REQUEST, false, null); + // e.printStackTrace(); + } + } + + //pkcs10 = httpParams.getValuePKCS10(PKCS10_REQUEST, null); + + } else { + try { + // coming from server cut & paste blob. + pkcs10 = httpParams.getValueAsPKCS10(PKIProcessor.PKCS10_REQUEST, false, null); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + return pkcs10; + + } + +} diff --git a/base/common/src/com/netscape/cms/servlet/processors/PKIProcessor.java b/base/common/src/com/netscape/cms/servlet/processors/PKIProcessor.java new file mode 100644 index 000000000..5b78bb42a --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/processors/PKIProcessor.java @@ -0,0 +1,356 @@ +// --- 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.cms.servlet.processors; + +import java.io.IOException; +import java.security.cert.CertificateException; +import java.util.Date; + +import javax.servlet.http.HttpServletRequest; + +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateSubjectName; +import netscape.security.x509.CertificateValidity; +import netscape.security.x509.X500Name; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.AuthToken; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.SessionContext; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Process Certificate Requests + * + * @version $Revision$, $Date$ + */ +public class PKIProcessor implements IPKIProcessor { + + public final static String ADMIN_ENROLL_SERVLET_ID = "caadminEnroll"; + public static final String SUBJECT_NAME = "subject"; + public static final String OLD_CERT_TYPE = "csrCertType"; + public static final String CERT_TYPE = "certType"; + public static final String PKCS10_REQUEST = "pkcs10Request"; + public static final String SUBJECT_KEYGEN_INFO = "subjectKeyGenInfo"; + + protected CMSRequest mRequest = null; + + protected HttpServletRequest httpReq = null; + protected String mServletId = null; + protected CMSServlet mServlet = null; + + protected ILogger mSignedAuditLogger = CMS.getSignedAuditLogger(); + + public PKIProcessor() { + } + + public PKIProcessor(CMSRequest cmsReq, CMSServlet servlet) { + mRequest = cmsReq; + + mServlet = servlet; + + if (mServlet == null || mRequest == null) { + return; + } + + mServletId = servlet.getId(); + + } + + public void process(CMSRequest cmsReq) + throws EBaseException { + } + + protected void fillCertInfo( + String protocolString, X509CertInfo certInfo, + IAuthToken authToken, IArgBlock httpParams) + throws EBaseException { + } + + protected X509CertInfo[] fillCertInfoArray( + String protocolString, IAuthToken authToken, IArgBlock httpParams, IRequest req) + throws EBaseException { + return null; + } + + /** + * fill subject name, validity, extensions from authoken if any, + * overriding what was in pkcs10. + * fill subject name, extensions from http input if not authenticated. + * requests not authenticated will need to be approved by an agent. + */ + public static void fillCertInfoFromAuthToken( + X509CertInfo certInfo, IAuthToken authToken) + throws EBaseException { + // override subject, validity and extensions from auth token + // CA determines algorithm, version and issuer. + // take key from keygen, cmc, pkcs10 or crmf. + + CMS.debug("PKIProcessor: fillCertInfoFromAuthToken"); + // subject name. + try { + String subjectname = + authToken.getInString(AuthToken.TOKEN_CERT_SUBJECT); + + if (subjectname != null) { + CertificateSubjectName certSubject = (CertificateSubjectName) + new CertificateSubjectName(new X500Name(subjectname)); + + certInfo.set(X509CertInfo.SUBJECT, certSubject); + log(ILogger.LL_INFO, + "cert subject set to " + certSubject + " from authtoken"); + } + } catch (CertificateException e) { + log(ILogger.LL_WARN, + CMS.getLogMessage("CMSGW_ERROR_SET_SUBJECT_NAME_1", + e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_SUBJECT_NAME_ERROR")); + } catch (IOException e) { + log(ILogger.LL_WARN, + CMS.getLogMessage("CMSGW_ERROR_SET_SUBJECT_NAME", + e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_SUBJECT_NAME_ERROR")); + } + + // validity + try { + CertificateValidity validity = null; + Date notBefore = + authToken.getInDate(AuthToken.TOKEN_CERT_NOTBEFORE); + Date notAfter = + authToken.getInDate(AuthToken.TOKEN_CERT_NOTAFTER); + + if (notBefore != null && notAfter != null) { + validity = new CertificateValidity(notBefore, notAfter); + certInfo.set(X509CertInfo.VALIDITY, validity); + log(ILogger.LL_INFO, + "cert validity set to " + validity + " from authtoken"); + } + } catch (CertificateException e) { + log(ILogger.LL_WARN, + CMS.getLogMessage("CMSGW_ERROR_SET_VALIDITY_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_VALIDITY_ERROR")); + } catch (IOException e) { + log(ILogger.LL_WARN, + CMS.getLogMessage("CMSGW_ERROR_SET_VALIDITY_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_VALIDITY_ERROR")); + } + + // extensions + try { + CertificateExtensions extensions = + authToken.getInCertExts(X509CertInfo.EXTENSIONS); + + if (extensions != null) { + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + log(ILogger.LL_INFO, "cert extensions set from authtoken"); + } + } catch (CertificateException e) { + log(ILogger.LL_WARN, + CMS.getLogMessage("CMSGW_ERROR_SET_EXTENSIONS_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_EXTENSIONS_ERROR")); + } catch (IOException e) { + log(ILogger.LL_WARN, + CMS.getLogMessage("CMSGW_ERROR_SET_EXTENSIONS_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_EXTENSIONS_ERROR")); + } + } + + /** + * fill subject name, extension from form. + * this is done for unauthenticated requests. + * unauthenticated requests must be approved by agents so these will + * all be seen by and agent. + */ + public static void fillCertInfoFromForm( + X509CertInfo certInfo, IArgBlock httpParams) + throws EBaseException { + + CMS.debug("PKIProcessor: fillCertInfoFromForm"); + // subject name. + try { + String subject = httpParams.getValueAsString(PKIProcessor.SUBJECT_NAME, null); + + if (subject == null) { + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_MISSING_SUBJECT_FROM_FORM")); + } + + X500Name x500name = new X500Name(subject); + + certInfo.set( + X509CertInfo.SUBJECT, new CertificateSubjectName(x500name)); + + fillValidityFromForm(certInfo, httpParams); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_SET_SUBJECT_NAME_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_SUBJECT_NAME_ERROR")); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_SET_SUBJECT_NAME_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_SUBJECT_NAME_ERROR")); + } catch (IllegalArgumentException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_SET_SUBJECT_NAME_1", e.toString())); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_REQ_ILLEGAL_CHARACTERS")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_CONVERT_DN_TO_X500NAME_ERROR")); + } + + // requested extensions. + // let polcies form extensions from http input. + } + + public static void fillValidityFromForm( + X509CertInfo certInfo, IArgBlock httpParams) + throws EBaseException { + CMS.debug("PKIProcessor: fillValidityFromForm!"); + try { + String notValidBeforeStr = httpParams.getValueAsString("notValidBefore", null); + String notValidAfterStr = httpParams.getValueAsString("notValidAfter", null); + + if (notValidBeforeStr != null && notValidAfterStr != null) { + long notValidBefore = 0; + long notValidAfter = 0; + + try { + notValidBefore = Long.parseLong(notValidBeforeStr); + } catch (NumberFormatException e) { + } + try { + notValidAfter = Long.parseLong(notValidAfterStr); + } catch (NumberFormatException e) { + } + + if (notValidBefore > 0 && notValidAfter > 0) { + CertificateValidity validity = null; + Date notBefore = new Date(notValidBefore); + Date notAfter = new Date(notValidAfter); + + if (notBefore != null && notAfter != null) { + validity = new CertificateValidity(notBefore, notAfter); + certInfo.set(X509CertInfo.VALIDITY, validity); + log(ILogger.LL_INFO, + "cert validity set to " + validity + " from authtoken"); + } + } + } + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_SET_SUBJECT_NAME_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_SUBJECT_NAME_ERROR")); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_SET_SUBJECT_NAME_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_SUBJECT_NAME_ERROR")); + } + } + + /** + * log according to authority category. + */ + public static void log(int event, int level, String msg) { + CMS.getLogger().log(event, ILogger.S_OTHER, level, + "PKIProcessor " + ": " + msg); + } + + public static void log(int level, String msg) { + CMS.getLogger().log(ILogger.EV_SYSTEM, ILogger.S_OTHER, level, + "PKIProcessor " + ": " + msg); + } + + /** + * Signed Audit Log + * + * This method is inherited by all extended "CMSServlet"s, + * and is called to store messages to the signed audit log. + * <P> + * + * @param msg signed audit log message + */ + protected void audit(String msg) { + // in this case, do NOT strip preceding/trailing whitespace + // from passed-in String parameters + + if (mSignedAuditLogger == null) { + return; + } + + mSignedAuditLogger.log(ILogger.EV_SIGNED_AUDIT, + null, + ILogger.S_SIGNED_AUDIT, + ILogger.LL_SECURITY, + msg); + } + + /** + * Signed Audit Log Subject ID + * + * This method is inherited by all extended "CMSServlet"s, + * and is called to obtain the "SubjectID" for + * a signed audit log message. + * <P> + * + * @return id string containing the signed audit log message SubjectID + */ + protected String auditSubjectID() { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String subjectID = null; + + // Initialize subjectID + SessionContext auditContext = SessionContext.getExistingContext(); + + if (auditContext != null) { + subjectID = (String) + auditContext.get(SessionContext.USER_ID); + + if (subjectID != null) { + subjectID = subjectID.trim(); + } else { + subjectID = ILogger.NONROLEUSER; + } + } else { + subjectID = ILogger.UNIDENTIFIED; + } + + return subjectID; + } +} |