From 621d9e5c413e561293d7484b93882d985b3fe15f Mon Sep 17 00:00:00 2001 From: Endi Sukma Dewata Date: Sat, 24 Mar 2012 02:27:47 -0500 Subject: 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 --- .../cms/servlet/cert/CMCRevReqServlet.java | 1056 ++++++++++ .../servlet/cert/ChallengeRevocationServlet1.java | 716 +++++++ .../netscape/cms/servlet/cert/CloneRedirect.java | 142 ++ .../netscape/cms/servlet/cert/DirAuthServlet.java | 241 +++ .../cms/servlet/cert/DisableEnrollResult.java | 173 ++ .../netscape/cms/servlet/cert/DisplayBySerial.java | 488 +++++ .../com/netscape/cms/servlet/cert/DisplayCRL.java | 481 +++++ .../cms/servlet/cert/DisplayHashUserEnroll.java | 227 +++ .../com/netscape/cms/servlet/cert/DoRevoke.java | 1221 +++++++++++ .../com/netscape/cms/servlet/cert/DoRevokeTPS.java | 940 +++++++++ .../com/netscape/cms/servlet/cert/DoUnrevoke.java | 671 ++++++ .../netscape/cms/servlet/cert/DoUnrevokeTPS.java | 618 ++++++ .../cms/servlet/cert/EnableEnrollResult.java | 184 ++ .../netscape/cms/servlet/cert/EnrollServlet.java | 1768 ++++++++++++++++ .../com/netscape/cms/servlet/cert/GetBySerial.java | 296 +++ .../com/netscape/cms/servlet/cert/GetCAChain.java | 407 ++++ .../src/com/netscape/cms/servlet/cert/GetCRL.java | 467 +++++ .../cms/servlet/cert/GetCertFromRequest.java | 350 ++++ .../netscape/cms/servlet/cert/GetEnableStatus.java | 173 ++ .../src/com/netscape/cms/servlet/cert/GetInfo.java | 377 ++++ .../cms/servlet/cert/HashEnrollServlet.java | 1241 ++++++++++++ .../servlet/cert/ImportCertsTemplateFiller.java | 381 ++++ .../com/netscape/cms/servlet/cert/ListCerts.java | 672 ++++++ .../src/com/netscape/cms/servlet/cert/Monitor.java | 407 ++++ .../netscape/cms/servlet/cert/ReasonToRevoke.java | 287 +++ .../cms/servlet/cert/RemoteAuthConfig.java | 624 ++++++ .../netscape/cms/servlet/cert/RenewalServlet.java | 523 +++++ .../cms/servlet/cert/RevocationServlet.java | 392 ++++ .../cert/RevocationSuccessTemplateFiller.java | 97 + .../com/netscape/cms/servlet/cert/SrchCerts.java | 762 +++++++ .../com/netscape/cms/servlet/cert/UpdateCRL.java | 530 +++++ .../com/netscape/cms/servlet/cert/UpdateDir.java | 747 +++++++ .../cms/servlet/cert/model/CertificateData.java | 53 + .../cms/servlet/cert/scep/CRSEnrollment.java | 2135 ++++++++++++++++++++ .../cms/servlet/cert/scep/ChallengePassword.java | 141 ++ .../cms/servlet/cert/scep/ExtensionsRequested.java | 176 ++ 36 files changed, 20164 insertions(+) create mode 100644 base/common/src/com/netscape/cms/servlet/cert/CMCRevReqServlet.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/ChallengeRevocationServlet1.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/CloneRedirect.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/DirAuthServlet.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/DisableEnrollResult.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/DisplayBySerial.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/DisplayCRL.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/DisplayHashUserEnroll.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/DoRevoke.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/DoRevokeTPS.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/DoUnrevoke.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/DoUnrevokeTPS.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/EnableEnrollResult.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/EnrollServlet.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/GetBySerial.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/GetCAChain.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/GetCRL.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/GetCertFromRequest.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/GetEnableStatus.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/GetInfo.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/HashEnrollServlet.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/ImportCertsTemplateFiller.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/ListCerts.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/Monitor.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/ReasonToRevoke.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/RemoteAuthConfig.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/RenewalServlet.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/RevocationServlet.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/RevocationSuccessTemplateFiller.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/SrchCerts.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/UpdateCRL.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/UpdateDir.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/model/CertificateData.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/scep/CRSEnrollment.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/scep/ChallengePassword.java create mode 100644 base/common/src/com/netscape/cms/servlet/cert/scep/ExtensionsRequested.java (limited to 'base/common/src/com/netscape/cms/servlet/cert') diff --git a/base/common/src/com/netscape/cms/servlet/cert/CMCRevReqServlet.java b/base/common/src/com/netscape/cms/servlet/cert/CMCRevReqServlet.java new file mode 100644 index 000000000..5af09ad0d --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/CMCRevReqServlet.java @@ -0,0 +1,1056 @@ +// --- 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.cert; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.CertificateException; +import java.util.Date; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.CRLReasonExtension; +import netscape.security.x509.InvalidityDateExtension; +import netscape.security.x509.RevocationReason; +import netscape.security.x509.RevokedCertImpl; +import netscape.security.x509.X509CertImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.AuthToken; +import com.netscape.certsrv.authentication.EMissingCredential; +import com.netscape.certsrv.authentication.IAuthManager; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authority.ICertAuthority; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertRecordList; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.logging.AuditFormat; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.publish.IPublisherProcessor; +import com.netscape.certsrv.ra.IRegistrationAuthority; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.RequestId; +import com.netscape.certsrv.request.RequestStatus; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; +import com.netscape.cmsutil.util.Utils; + +/** + * Revoke a certificate with a CMC-formatted revocation request + * + * @version $Revision$, $Date$ + */ +public class CMCRevReqServlet extends CMSServlet { + /** + * + */ + private static final long serialVersionUID = 4731070386698127770L; + public final static String GETCERTS_FOR_CHALLENGE_REQUEST = "getCertsForChallenge"; + public static final String TOKEN_CERT_SERIAL = "certSerialToRevoke"; + // revocation templates. + private final static String TPL_FILE = "revocationResult.template"; + public static final String CRED_CMC = "cmcRequest"; + + private ICertificateRepository mCertDB = null; + private String mFormPath = null; + private IRequestQueue mQueue = null; + private IPublisherProcessor mPublisherProcessor = null; + private String mRequestID = null; + private final static String REVOKE = "revoke"; + private final static String ON_HOLD = "on-hold"; + private final static int ON_HOLD_REASON = 6; + private final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST = + "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_5"; + private final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED = + "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED_7"; + + // http params + public static final String SERIAL_NO = TOKEN_CERT_SERIAL; + public static final String REASON_CODE = "reasonCode"; + public static final String CHALLENGE_PHRASE = "challengePhrase"; + + // request attributes + public static final String SERIALNO_ARRAY = "serialNoArray"; + + public CMCRevReqServlet() { + super(); + } + + /** + * initialize the servlet. + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + + super.init(sc); + + String authorityId = mAuthority.getId(); + + mFormPath = "/" + authorityId + "/" + TPL_FILE; + + mTemplates.remove(CMSRequest.SUCCESS); + if (mAuthority instanceof ICertificateAuthority) { + mCertDB = ((ICertificateAuthority) mAuthority).getCertificateRepository(); + } + + if (mAuthority instanceof ICertAuthority) { + mPublisherProcessor = ((ICertAuthority) mAuthority).getPublisherProcessor(); + } + mQueue = mAuthority.getRequestQueue(); + if (mOutputTemplatePath != null) + mFormPath = mOutputTemplatePath; + } + + /** + * Process the HTTP request. + * + * + * + * @param cmsReq the object holding the request and response information + */ + protected void process(CMSRequest cmsReq) throws EBaseException { + + String cmcAgentSerialNumber = null; + IArgBlock httpParams = cmsReq.getHttpParams(); + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + CMS.debug("**** mFormPath = " + mFormPath); + try { + form = getTemplate(mFormPath, req, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock ctx = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, ctx); + + String cmc = (String) httpParams.get(CRED_CMC); + if (cmc == null) { + throw new EMissingCredential( + CMS.getUserMessage("CMS_AUTHENTICATION_NULL_CREDENTIAL", CRED_CMC)); + } + + IAuthToken authToken = authenticate(cmsReq); + + AuthzToken authzToken = null; + try { + authzToken = authorize(mAclMethod, authToken, mAuthzResourceName, "revoke"); + } catch (Exception e) { + // do nothing for now + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + //IAuthToken authToken = getAuthToken(cmsReq); + //Object subject = authToken.get(CMCAuth.TOKEN_CERT_SERIAL); + //Object uid = authToken.get("uid"); + //=========================== + String authMgr = AuditFormat.NOAUTH; + BigInteger[] serialNoArray = null; + + if (authToken != null) { + serialNoArray = authToken.getInBigIntegerArray(TOKEN_CERT_SERIAL); + } + + Integer reasonCode = Integer.valueOf(0); + if (authToken != null) { + reasonCode = authToken.getInInteger(REASON_CODE); + } + + String comments = ""; + Date invalidityDate = null; + String revokeAll = null; + int verifiedRecordCount = 0; + int totalRecordCount = 0; + + if (serialNoArray != null) { + totalRecordCount = serialNoArray.length; + verifiedRecordCount = serialNoArray.length; + } + + X509CertImpl[] certs = null; + + //for audit log. + String initiative = null; + + if (mAuthMgr != null && mAuthMgr.equals("CMCAuth")) { + // request is from agent + if (authToken != null) { + authMgr = authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME); + String agentID = authToken.getInString("userid"); + + initiative = AuditFormat.FROMAGENT + " agentID: " + agentID + + " authenticated by " + authMgr; + } + } else { + initiative = AuditFormat.FROMUSER; + } + + if ((serialNoArray != null) && (serialNoArray.length > 0)) { + if (mAuthority instanceof ICertificateAuthority) { + certs = new X509CertImpl[serialNoArray.length]; + + for (int i = 0; i < serialNoArray.length; i++) { + certs[i] = + ((ICertificateAuthority) mAuthority).getCertificateRepository().getX509Certificate( + serialNoArray[i]); + } + + } else if (mAuthority instanceof IRegistrationAuthority) { + IRequest getCertsChallengeReq = null; + + getCertsChallengeReq = mQueue.newRequest( + GETCERTS_FOR_CHALLENGE_REQUEST); + getCertsChallengeReq.setExtData(SERIALNO_ARRAY, serialNoArray); + mQueue.processRequest(getCertsChallengeReq); + RequestStatus status = getCertsChallengeReq.getRequestStatus(); + + if (status == RequestStatus.COMPLETE) { + certs = getCertsChallengeReq.getExtDataInCertArray(IRequest.OLD_CERTS); + header.addStringValue("request", getCertsChallengeReq.getRequestId().toString()); + mRequestID = getCertsChallengeReq.getRequestId().toString(); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("ADMIN_SRVLT_FAIL_GET_CERT_CHALL_PWRD")); + } + } + + header.addIntegerValue("totalRecordCount", serialNoArray.length); + header.addIntegerValue("verifiedRecordCount", serialNoArray.length); + + for (int i = 0; i < serialNoArray.length; i++) { + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addBigIntegerValue("serialNumber", + serialNoArray[i], 16); + rarg.addStringValue("subject", + certs[i].getSubjectDN().toString()); + rarg.addLongValue("validNotBefore", + certs[i].getNotBefore().getTime() / 1000); + rarg.addLongValue("validNotAfter", + certs[i].getNotAfter().getTime() / 1000); + //argSet.addRepeatRecord(rarg); + } + + revokeAll = "(|(certRecordId=" + serialNoArray[0].toString() + "))"; + cmcAgentSerialNumber = authToken.getInString(IAuthManager.CRED_SSL_CLIENT_CERT); + process(argSet, header, reasonCode.intValue(), invalidityDate, initiative, req, resp, + verifiedRecordCount, revokeAll, totalRecordCount, + comments, locale[0], cmcAgentSerialNumber); + + } else { + header.addIntegerValue("totalRecordCount", 0); + header.addIntegerValue("verifiedRecordCount", 0); + } + + try { + ServletOutputStream out = resp.getOutputStream(); + + if ((serialNoArray == null) || (serialNoArray.length == 0)) { + cmsReq.setStatus(CMSRequest.ERROR); + EBaseException ee = new EBaseException("No matched certificate is found"); + + cmsReq.setError(ee); + } else { + String xmlOutput = req.getParameter("xml"); + if (xmlOutput != null && xmlOutput.equals("true")) { + outputXML(resp, argSet); + } else { + resp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_ERR_STREAM_TEMPLATE", e.toString())); + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + } + } + + /** + * Process cert status change request using the Certificate Management + * protocol using CMS (CMC) + *

+ * + * (Certificate Request - an "EE" cert status change request) + *

+ * + * (Certificate Request Processed - an "EE" cert status change request) + *

+ * + *

+ * + * @param argSet CMS template parameters + * @param header argument block + * @param reason revocation reason (0 - Unspecified, 1 - Key compromised, + * 2 - CA key compromised; should not be used, 3 - Affiliation changed, + * 4 - Certificate superceded, 5 - Cessation of operation, or + * 6 - Certificate is on hold) + * @param invalidityDate certificate validity date + * @param initiative string containing the audit format + * @param req HTTP servlet request + * @param resp HTTP servlet response + * @param verifiedRecordCount number of verified records + * @param revokeAll string containing information on all of the + * certificates to be revoked + * @param totalRecordCount total number of records (verified and unverified) + * @param comments string containing certificate comments + * @param locale the system locale + * @exception EBaseException an error has occurred + */ + private void process(CMSTemplateParams argSet, IArgBlock header, + int reason, Date invalidityDate, + String initiative, + HttpServletRequest req, + HttpServletResponse resp, + int verifiedRecordCount, + String revokeAll, + int totalRecordCount, + String comments, + Locale locale, String cmcAgentSerialNumber) + throws EBaseException { + String eeSerialNumber = null; + if (cmcAgentSerialNumber != null) { + eeSerialNumber = cmcAgentSerialNumber; + } else { + X509CertImpl sslCert = (X509CertImpl) getSSLClientCertificate(req); + if (sslCert != null) { + eeSerialNumber = sslCert.getSerialNumber().toString(); + } + } + + boolean auditRequest = true; + String auditMessage = null; + String auditSubjectID = auditSubjectID(); + String auditRequesterID = auditRequesterID(req); + String auditSerialNumber = auditSerialNumber(eeSerialNumber); + String auditRequestType = auditRequestType(reason); + String auditApprovalStatus = ILogger.SIGNED_AUDIT_EMPTY_VALUE; + String auditReasonNum = String.valueOf(reason); + + try { + int count = 0; + Vector oldCertsV = new Vector(); + Vector revCertImplsV = new Vector(); + + // Construct a CRL reason code extension. + RevocationReason revReason = RevocationReason.fromInt(reason); + CRLReasonExtension crlReasonExtn = new CRLReasonExtension(revReason); + + // Construct a CRL invalidity date extension. + InvalidityDateExtension invalidityDateExtn = null; + + if (invalidityDate != null) { + invalidityDateExtn = new InvalidityDateExtension(invalidityDate); + } + + // Construct a CRL extension for this request. + CRLExtensions entryExtn = new CRLExtensions(); + + if (crlReasonExtn != null) { + entryExtn.set(crlReasonExtn.getName(), crlReasonExtn); + } + if (invalidityDateExtn != null) { + entryExtn.set(invalidityDateExtn.getName(), invalidityDateExtn); + } + + if (mAuthority instanceof ICertificateAuthority) { + ICertRecordList list = (ICertRecordList) mCertDB.findCertRecordsInList( + revokeAll, null, totalRecordCount); + Enumeration e = list.getCertRecords(0, totalRecordCount - 1); + + while (e != null && e.hasMoreElements()) { + ICertRecord rec = e.nextElement(); + X509CertImpl cert = rec.getCertificate(); + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addBigIntegerValue("serialNumber", + cert.getSerialNumber(), 16); + + if (rec.getStatus().equals(ICertRecord.STATUS_REVOKED)) { + rarg.addStringValue("error", "Certificate " + + cert.getSerialNumber().toString() + + " is already revoked."); + } else { + oldCertsV.addElement(cert); + + RevokedCertImpl revCertImpl = + new RevokedCertImpl(cert.getSerialNumber(), + CMS.getCurrentDate(), entryExtn); + + revCertImplsV.addElement(revCertImpl); + count++; + rarg.addStringValue("error", null); + } + argSet.addRepeatRecord(rarg); + } + + } else if (mAuthority instanceof IRegistrationAuthority) { + String reqIdStr = null; + + if (mRequestID != null && mRequestID.length() > 0) + reqIdStr = mRequestID; + Vector serialNumbers = new Vector(); + + if (revokeAll != null && revokeAll.length() > 0) { + for (int i = revokeAll.indexOf('='); i < revokeAll.length() && i > -1; i = + revokeAll.indexOf('=', i)) { + if (i > -1) { + i++; + while (i < revokeAll.length() && revokeAll.charAt(i) == ' ') { + i++; + } + String legalDigits = "0123456789"; + int j = i; + + while (j < revokeAll.length() && + legalDigits.indexOf(revokeAll.charAt(j)) != -1) { + j++; + } + if (j > i) { + serialNumbers.addElement(revokeAll.substring(i, j)); + } + } + } + } + if (reqIdStr != null && reqIdStr.length() > 0 && serialNumbers.size() > 0) { + IRequest certReq = mRequestQueue.findRequest(new RequestId(reqIdStr)); + X509CertImpl[] certs = certReq.getExtDataInCertArray(IRequest.OLD_CERTS); + + for (int i = 0; i < certs.length; i++) { + boolean addToList = false; + + for (int j = 0; j < serialNumbers.size(); j++) { + if (certs[i].getSerialNumber().toString().equals( + (String) serialNumbers.elementAt(j))) { + addToList = true; + break; + } + } + if (addToList) { + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addBigIntegerValue("serialNumber", + certs[i].getSerialNumber(), 16); + oldCertsV.addElement(certs[i]); + + RevokedCertImpl revCertImpl = + new RevokedCertImpl(certs[i].getSerialNumber(), + CMS.getCurrentDate(), entryExtn); + + revCertImplsV.addElement(revCertImpl); + count++; + rarg.addStringValue("error", null); + argSet.addRepeatRecord(rarg); + } + } + } else { + String b64eCert = req.getParameter("b64eCertificate"); + + if (b64eCert != null) { + byte[] certBytes = Utils.base64decode(b64eCert); + X509CertImpl cert = new X509CertImpl(certBytes); + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addBigIntegerValue("serialNumber", + cert.getSerialNumber(), 16); + oldCertsV.addElement(cert); + + RevokedCertImpl revCertImpl = + new RevokedCertImpl(cert.getSerialNumber(), + CMS.getCurrentDate(), entryExtn); + + revCertImplsV.addElement(revCertImpl); + count++; + rarg.addStringValue("error", null); + argSet.addRepeatRecord(rarg); + } + } + } + + header.addIntegerValue("totalRecordCount", count); + + X509CertImpl[] oldCerts = new X509CertImpl[count]; + RevokedCertImpl[] revCertImpls = new RevokedCertImpl[count]; + + for (int i = 0; i < count; i++) { + oldCerts[i] = (X509CertImpl) oldCertsV.elementAt(i); + revCertImpls[i] = (RevokedCertImpl) revCertImplsV.elementAt(i); + } + + IRequest revReq = + mQueue.newRequest(IRequest.REVOCATION_REQUEST); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + + revReq.setExtData(IRequest.CERT_INFO, revCertImpls); + revReq.setExtData(IRequest.REQ_TYPE, IRequest.REVOCATION_REQUEST); + revReq.setExtData(IRequest.REQUESTOR_TYPE, IRequest.REQUESTOR_AGENT); + revReq.setExtData(IRequest.REVOKED_REASON, reason); + revReq.setExtData(IRequest.OLD_CERTS, oldCerts); + if (comments != null) { + revReq.setExtData(IRequest.REQUESTOR_COMMENTS, comments); + } + + // change audit processing from "REQUEST" to "REQUEST_PROCESSED" + // to distinguish which type of signed audit log message to save + // as a failure outcome in case an exception occurs + auditRequest = false; + + mQueue.processRequest(revReq); + + // retrieve the request status + auditApprovalStatus = revReq.getRequestStatus().toString(); + + RequestStatus stat = revReq.getRequestStatus(); + + if (stat == RequestStatus.COMPLETE) { + // audit log the error + Integer result = revReq.getExtDataInInteger(IRequest.RESULT); + + if (result.equals(IRequest.RES_ERROR)) { + String[] svcErrors = + revReq.getExtDataInStringArray(IRequest.SVCERRORS); + + if (svcErrors != null && svcErrors.length > 0) { + for (int i = 0; i < svcErrors.length; i++) { + String err = svcErrors[i]; + + if (err != null) { + //cmsReq.setErrorDescription(err); + for (int j = 0; j < count; j++) { + if (oldCerts[j] != null) { + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOREVOKEFORMAT, + new Object[] { + revReq.getRequestId(), + initiative, + "completed with error: " + + err, + oldCerts[j].getSubjectDN(), + oldCerts[j].getSerialNumber().toString(16), + RevocationReason.fromInt(reason).toString() } + ); + } + } + } + } + } + return; + } + + // audit log the success. + for (int j = 0; j < count; j++) { + if (oldCerts[j] != null) { + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOREVOKEFORMAT, + new Object[] { + revReq.getRequestId(), + initiative, + "completed", + oldCerts[j].getSubjectDN(), + oldCerts[j].getSerialNumber().toString(16), + RevocationReason.fromInt(reason).toString() } + ); + } + } + + header.addStringValue("revoked", "yes"); + + Integer updateCRLResult = + revReq.getExtDataInInteger(IRequest.CRL_UPDATE_STATUS); + + if (updateCRLResult != null) { + header.addStringValue("updateCRL", "yes"); + if (updateCRLResult.equals(IRequest.RES_SUCCESS)) { + header.addStringValue("updateCRLSuccess", "yes"); + } else { + header.addStringValue("updateCRLSuccess", "no"); + String crlError = + revReq.getExtDataInString(IRequest.CRL_UPDATE_ERROR); + + if (crlError != null) + header.addStringValue("updateCRLError", + crlError); + } + // let known crl publishing status too. + Integer publishCRLResult = + revReq.getExtDataInInteger(IRequest.CRL_PUBLISH_STATUS); + + if (publishCRLResult != null) { + if (publishCRLResult.equals(IRequest.RES_SUCCESS)) { + header.addStringValue("publishCRLSuccess", "yes"); + } else { + header.addStringValue("publishCRLSuccess", "no"); + String publError = + revReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR); + + if (publError != null) + header.addStringValue("publishCRLError", + publError); + } + } + } + if (mAuthority instanceof ICertificateAuthority) { + // let known update and publish status of all crls. + Enumeration otherCRLs = + ((ICertificateAuthority) mAuthority).getCRLIssuingPoints(); + + while (otherCRLs.hasMoreElements()) { + ICRLIssuingPoint crl = (ICRLIssuingPoint) + otherCRLs.nextElement(); + String crlId = crl.getId(); + + if (crlId.equals(ICertificateAuthority.PROP_MASTER_CRL)) + continue; + String updateStatusStr = crl.getCrlUpdateStatusStr(); + Integer updateResult = revReq.getExtDataInInteger(updateStatusStr); + + if (updateResult != null) { + if (updateResult.equals(IRequest.RES_SUCCESS)) { + CMS.debug("CMCRevReqServlet: " + CMS.getLogMessage("ADMIN_SRVLT_ADDING_HEADER", + updateStatusStr)); + header.addStringValue(updateStatusStr, "yes"); + } else { + String updateErrorStr = crl.getCrlUpdateErrorStr(); + + CMS.debug("CMCRevReqServlet: " + CMS.getLogMessage("ADMIN_SRVLT_ADDING_HEADER_NO", + updateStatusStr)); + header.addStringValue(updateStatusStr, "no"); + String error = + revReq.getExtDataInString(updateErrorStr); + + if (error != null) + header.addStringValue(updateErrorStr, + error); + } + String publishStatusStr = crl.getCrlPublishStatusStr(); + Integer publishResult = + revReq.getExtDataInInteger(publishStatusStr); + + if (publishResult == null) + continue; + if (publishResult.equals(IRequest.RES_SUCCESS)) { + header.addStringValue(publishStatusStr, "yes"); + } else { + String publishErrorStr = + crl.getCrlPublishErrorStr(); + + header.addStringValue(publishStatusStr, "no"); + String error = + revReq.getExtDataInString(publishErrorStr); + + if (error != null) + header.addStringValue( + publishErrorStr, error); + } + } + } + } + + if (mPublisherProcessor != null && mPublisherProcessor.ldapEnabled()) { + header.addStringValue("dirEnabled", "yes"); + Integer[] ldapPublishStatus = + revReq.getExtDataInIntegerArray("ldapPublishStatus"); + int certsToUpdate = 0; + int certsUpdated = 0; + + if (ldapPublishStatus != null) { + certsToUpdate = ldapPublishStatus.length; + for (int i = 0; i < certsToUpdate; i++) { + if (ldapPublishStatus[i] == IRequest.RES_SUCCESS) { + certsUpdated++; + } + } + } + header.addIntegerValue("certsUpdated", certsUpdated); + header.addIntegerValue("certsToUpdate", certsToUpdate); + + // add crl publishing status. + String publError = + revReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR); + + if (publError != null) { + header.addStringValue("crlPublishError", + publError); + } + } else { + header.addStringValue("dirEnabled", "no"); + } + header.addStringValue("error", null); + + } else if (stat == RequestStatus.PENDING) { + header.addStringValue("error", "Request Pending"); + header.addStringValue("revoked", "pending"); + // audit log the pending + for (int j = 0; j < count; j++) { + if (oldCerts[j] != null) { + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOREVOKEFORMAT, + new Object[] { + revReq.getRequestId(), + initiative, + "pending", + oldCerts[j].getSubjectDN(), + oldCerts[j].getSerialNumber().toString(16), + RevocationReason.fromInt(reason).toString() } + ); + } + } + + } else { + Vector errors = revReq.getExtDataInStringVector(IRequest.ERRORS); + StringBuffer errorStr = new StringBuffer(); + + if (errors != null && errors.size() > 0) { + for (int ii = 0; ii < errors.size(); ii++) { + errorStr.append(errors.elementAt(ii)); + ; + } + } + header.addStringValue("error", errorStr.toString()); + header.addStringValue("revoked", "no"); + // audit log the error + for (int j = 0; j < count; j++) { + if (oldCerts[j] != null) { + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOREVOKEFORMAT, + new Object[] { + revReq.getRequestId(), + initiative, + stat.toString(), + oldCerts[j].getSubjectDN(), + oldCerts[j].getSerialNumber().toString(16), + RevocationReason.fromInt(reason).toString() } + ); + } + } + } + + // store a message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals(RequestStatus.COMPLETE_STRING)) + || (auditApprovalStatus.equals(RequestStatus.REJECTED_STRING)) + || (auditApprovalStatus.equals(RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + + } catch (CertificateException e) { + if (auditRequest) { + // store a "CERT_STATUS_CHANGE_REQUEST" failure + // message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + } else { + // store a "CERT_STATUS_CHANGE_REQUEST_PROCESSED" failure + // message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals(RequestStatus.COMPLETE_STRING)) + || (auditApprovalStatus.equals(RequestStatus.REJECTED_STRING)) + || (auditApprovalStatus.equals(RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + } + + log(ILogger.LL_FAILURE, "error " + e); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, "error " + e); + + if (auditRequest) { + // store a "CERT_STATUS_CHANGE_REQUEST" failure + // message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + } else { + // store a "CERT_STATUS_CHANGE_REQUEST_PROCESSED" failure + // message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals(RequestStatus.COMPLETE_STRING)) + || (auditApprovalStatus.equals(RequestStatus.REJECTED_STRING)) + || (auditApprovalStatus.equals(RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + } + + throw e; + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED", e.toString())); + + if (auditRequest) { + // store a "CERT_STATUS_CHANGE_REQUEST" failure + // message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + } else { + // store a "CERT_STATUS_CHANGE_REQUEST_PROCESSED" failure + // message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals(RequestStatus.COMPLETE_STRING)) + || (auditApprovalStatus.equals(RequestStatus.REJECTED_STRING)) + || (auditApprovalStatus.equals(RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + } + + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED")); + } catch (Exception e) { + if (auditRequest) { + // store a "CERT_STATUS_CHANGE_REQUEST" failure + // message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + } else { + // store a "CERT_STATUS_CHANGE_REQUEST_PROCESSED" failure + // message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals(RequestStatus.COMPLETE_STRING)) + || (auditApprovalStatus.equals(RequestStatus.REJECTED_STRING)) + || (auditApprovalStatus.equals(RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + } + + e.printStackTrace(); + } + + return; + } + + /** + * Signed Audit Log Requester ID + * + * This method is called to obtain the "RequesterID" for + * a signed audit log message. + *

+ * + * @param req HTTP request + * @return id string containing the signed audit log message RequesterID + */ + private String auditRequesterID(HttpServletRequest req) { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String requesterID = null; + + // Obtain the requesterID + requesterID = req.getParameter("requestId"); + + if (requesterID != null) { + requesterID = requesterID.trim(); + } else { + requesterID = ILogger.UNIDENTIFIED; + } + + return requesterID; + } + + /** + * Signed Audit Log Serial Number + * + * This method is called to obtain the serial number of the certificate + * whose status is to be changed for a signed audit log message. + *

+ * + * @param eeSerialNumber a string containing the un-normalized serialNumber + * @return id string containing the signed audit log message RequesterID + */ + private String auditSerialNumber(String eeSerialNumber) { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String serialNumber = null; + + // Normalize the serialNumber + if (eeSerialNumber != null) { + serialNumber = eeSerialNumber.trim(); + + // convert it to hexadecimal + serialNumber = "0x" + + Integer.toHexString( + Integer.valueOf(serialNumber).intValue()); + } else { + serialNumber = ILogger.SIGNED_AUDIT_EMPTY_VALUE; + } + + return serialNumber; + } + + /** + * Signed Audit Log Request Type + * + * This method is called to obtain the "Request Type" for + * a signed audit log message. + *

+ * + * @param reason an integer denoting the revocation reason + * @return string containing REVOKE or ON_HOLD + */ + private String auditRequestType(int reason) { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String requestType = null; + + // Determine the revocation type based upon the revocation reason + if (reason == ON_HOLD_REASON) { + requestType = ON_HOLD; + } else { + requestType = REVOKE; + } + + return requestType; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/ChallengeRevocationServlet1.java b/base/common/src/com/netscape/cms/servlet/cert/ChallengeRevocationServlet1.java new file mode 100644 index 000000000..f056047cc --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/ChallengeRevocationServlet1.java @@ -0,0 +1,716 @@ +// --- 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.cert; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.CertificateException; +import java.util.Date; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.CRLReasonExtension; +import netscape.security.x509.InvalidityDateExtension; +import netscape.security.x509.RevocationReason; +import netscape.security.x509.RevokedCertImpl; +import netscape.security.x509.X509CertImpl; + +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.authority.ICertAuthority; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertRecordList; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.logging.AuditFormat; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.publish.IPublisherProcessor; +import com.netscape.certsrv.ra.IRegistrationAuthority; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.RequestId; +import com.netscape.certsrv.request.RequestStatus; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; +import com.netscape.cmsutil.util.Utils; + +/** + * Takes the certificate info (serial number) and optional challenge phrase, creates a + * revocation request and submits it to the authority subsystem for processing + * + * @version $Revision$, $Date$ + */ +public class ChallengeRevocationServlet1 extends CMSServlet { + /** + * + */ + private static final long serialVersionUID = 1253319999546210407L; + public final static String GETCERTS_FOR_CHALLENGE_REQUEST = "getCertsForChallenge"; + public static final String TOKEN_CERT_SERIAL = "certSerialToRevoke"; + // revocation templates. + private final static String TPL_FILE = "revocationResult.template"; + + private ICertificateRepository mCertDB = null; + private String mFormPath = null; + private IRequestQueue mQueue = null; + private IPublisherProcessor mPublisherProcessor = null; + private String mRequestID = null; + + // http params + public static final String SERIAL_NO = TOKEN_CERT_SERIAL; + public static final String REASON_CODE = "reasonCode"; + public static final String CHALLENGE_PHRASE = "challengePhrase"; + + // request attributes + public static final String SERIALNO_ARRAY = "serialNoArray"; + + public ChallengeRevocationServlet1() { + super(); + } + + /** + * Initialize the servlet. This servlet uses the file + * revocationResult.template for the response + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + + String authorityId = mAuthority.getId(); + + mFormPath = "/" + authorityId + "/" + TPL_FILE; + + mTemplates.remove(CMSRequest.SUCCESS); + if (mAuthority instanceof ICertificateAuthority) { + mCertDB = ((ICertificateAuthority) mAuthority).getCertificateRepository(); + } + + if (mAuthority instanceof ICertAuthority) { + mPublisherProcessor = ((ICertAuthority) mAuthority).getPublisherProcessor(); + } + mQueue = mAuthority.getRequestQueue(); + } + + /** + * Process the HTTP request. + *

    + *
  • http.param REASON_CODE the revocation reason + *
  • http.param b64eCertificate the base-64 encoded certificate to revoke + *
+ * + * @param cmsReq the object holding the request and response information + */ + protected void process(CMSRequest cmsReq) + throws EBaseException { + IArgBlock httpParams = cmsReq.getHttpParams(); + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, req, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock ctx = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, ctx); + + // for audit log + IAuthToken authToken = authenticate(cmsReq); + String authMgr = AuditFormat.NOAUTH; + + BigInteger[] serialNoArray = null; + + if (authToken != null) { + serialNoArray = authToken.getInBigIntegerArray(SERIAL_NO); + } + // set revocation reason, default to unspecified if not set. + int reasonCode = + httpParams.getValueAsInt(REASON_CODE, 0); + // header.addIntegerValue("reason", reasonCode); + + String comments = req.getParameter(IRequest.REQUESTOR_COMMENTS); + Date invalidityDate = null; + String revokeAll = null; + int totalRecordCount = (serialNoArray != null) ? serialNoArray.length : 0; + int verifiedRecordCount = (serialNoArray != null) ? serialNoArray.length : 0; + + X509CertImpl[] certs = null; + + //for audit log. + String initiative = null; + + if (mAuthMgr != null && mAuthMgr.equals(IAuthSubsystem.CERTUSERDB_AUTHMGR_ID)) { + // request is from agent + if (authToken != null) { + authMgr = authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME); + String agentID = authToken.getInString("userid"); + + initiative = AuditFormat.FROMAGENT + " agentID: " + agentID + + " authenticated by " + authMgr; + } + } else { + initiative = AuditFormat.FROMUSER; + } + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "revoke"); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + if (serialNoArray != null && serialNoArray.length > 0) { + if (mAuthority instanceof ICertificateAuthority) { + certs = new X509CertImpl[serialNoArray.length]; + + for (int i = 0; i < serialNoArray.length; i++) { + certs[i] = + ((ICertificateAuthority) mAuthority).getCertificateRepository().getX509Certificate( + serialNoArray[i]); + } + + } else if (mAuthority instanceof IRegistrationAuthority) { + IRequest getCertsChallengeReq = null; + + getCertsChallengeReq = mQueue.newRequest( + GETCERTS_FOR_CHALLENGE_REQUEST); + getCertsChallengeReq.setExtData(SERIALNO_ARRAY, serialNoArray); + mQueue.processRequest(getCertsChallengeReq); + RequestStatus status = getCertsChallengeReq.getRequestStatus(); + + if (status == RequestStatus.COMPLETE) { + certs = getCertsChallengeReq.getExtDataInCertArray(IRequest.OLD_CERTS); + header.addStringValue("request", getCertsChallengeReq.getRequestId().toString()); + mRequestID = getCertsChallengeReq.getRequestId().toString(); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("ADMIN_SRVLT_FAIL_GET_CERT_CHALL_PWRD")); + } + } + + header.addIntegerValue("totalRecordCount", serialNoArray.length); + header.addIntegerValue("verifiedRecordCount", serialNoArray.length); + + for (int i = 0; i < serialNoArray.length; i++) { + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addBigIntegerValue("serialNumber", + serialNoArray[i], 16); + rarg.addStringValue("subject", + certs[i].getSubjectDN().toString()); + rarg.addLongValue("validNotBefore", + certs[i].getNotBefore().getTime() / 1000); + rarg.addLongValue("validNotAfter", + certs[i].getNotAfter().getTime() / 1000); + //argSet.addRepeatRecord(rarg); + } + + revokeAll = "(|(certRecordId=" + serialNoArray[0].toString() + "))"; + process(argSet, header, reasonCode, invalidityDate, initiative, req, resp, + verifiedRecordCount, revokeAll, totalRecordCount, + comments, locale[0]); + } else { + header.addIntegerValue("totalRecordCount", 0); + header.addIntegerValue("verifiedRecordCount", 0); + } + + try { + ServletOutputStream out = resp.getOutputStream(); + + if (serialNoArray == null) { + CMS.debug("ChallengeRevcationServlet1::process() - " + + " serialNoArray is null!"); + EBaseException ee = new EBaseException("No matched certificate is found"); + + cmsReq.setError(ee); + return; + } + + if (serialNoArray.length == 0) { + cmsReq.setStatus(CMSRequest.ERROR); + EBaseException ee = new EBaseException("No matched certificate is found"); + + cmsReq.setError(ee); + } else { + String xmlOutput = req.getParameter("xml"); + if (xmlOutput != null && xmlOutput.equals("true")) { + outputXML(resp, argSet); + } else { + resp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_ERR_STREAM_TEMPLATE", e.toString())); + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + } + } + + private void process(CMSTemplateParams argSet, IArgBlock header, + int reason, Date invalidityDate, + String initiative, + HttpServletRequest req, + HttpServletResponse resp, + int verifiedRecordCount, + String revokeAll, + int totalRecordCount, + String comments, + Locale locale) + throws EBaseException { + try { + int count = 0; + Vector oldCertsV = new Vector(); + Vector revCertImplsV = new Vector(); + + // Construct a CRL reason code extension. + RevocationReason revReason = RevocationReason.fromInt(reason); + CRLReasonExtension crlReasonExtn = new CRLReasonExtension(revReason); + + // Construct a CRL invalidity date extension. + InvalidityDateExtension invalidityDateExtn = null; + + if (invalidityDate != null) { + invalidityDateExtn = new InvalidityDateExtension(invalidityDate); + } + + // Construct a CRL extension for this request. + CRLExtensions entryExtn = new CRLExtensions(); + + if (crlReasonExtn != null) { + entryExtn.set(crlReasonExtn.getName(), crlReasonExtn); + } + if (invalidityDateExtn != null) { + entryExtn.set(invalidityDateExtn.getName(), invalidityDateExtn); + } + + if (mAuthority instanceof ICertificateAuthority) { + ICertRecordList list = (ICertRecordList) mCertDB.findCertRecordsInList( + revokeAll, null, totalRecordCount); + Enumeration e = list.getCertRecords(0, totalRecordCount - 1); + + while (e != null && e.hasMoreElements()) { + ICertRecord rec = e.nextElement(); + X509CertImpl cert = rec.getCertificate(); + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addBigIntegerValue("serialNumber", + cert.getSerialNumber(), 16); + + if (rec.getStatus().equals(ICertRecord.STATUS_REVOKED)) { + rarg.addStringValue("error", "Certificate " + + cert.getSerialNumber().toString() + + " is already revoked."); + } else { + oldCertsV.addElement(cert); + + RevokedCertImpl revCertImpl = + new RevokedCertImpl(cert.getSerialNumber(), + CMS.getCurrentDate(), entryExtn); + + revCertImplsV.addElement(revCertImpl); + count++; + rarg.addStringValue("error", null); + } + argSet.addRepeatRecord(rarg); + } + + } else if (mAuthority instanceof IRegistrationAuthority) { + String reqIdStr = null; + + if (mRequestID != null && mRequestID.length() > 0) + reqIdStr = mRequestID; + Vector serialNumbers = new Vector(); + + if (revokeAll != null && revokeAll.length() > 0) { + for (int i = revokeAll.indexOf('='); i < revokeAll.length() && i > -1; + i = revokeAll.indexOf('=', i)) { + if (i > -1) { + i++; + while (i < revokeAll.length() && revokeAll.charAt(i) == ' ') { + i++; + } + String legalDigits = "0123456789"; + int j = i; + + while (j < revokeAll.length() && + legalDigits.indexOf(revokeAll.charAt(j)) != -1) { + j++; + } + if (j > i) { + serialNumbers.addElement(revokeAll.substring(i, j)); + } + } + } + } + if (reqIdStr != null && reqIdStr.length() > 0 && serialNumbers.size() > 0) { + IRequest certReq = mRequestQueue.findRequest(new RequestId(reqIdStr)); + X509CertImpl[] certs = certReq.getExtDataInCertArray(IRequest.OLD_CERTS); + + for (int i = 0; i < certs.length; i++) { + boolean addToList = false; + + for (int j = 0; j < serialNumbers.size(); j++) { + if (certs[i].getSerialNumber().toString().equals( + (String) serialNumbers.elementAt(j))) { + addToList = true; + break; + } + } + if (addToList) { + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addBigIntegerValue("serialNumber", + certs[i].getSerialNumber(), 16); + oldCertsV.addElement(certs[i]); + + RevokedCertImpl revCertImpl = + new RevokedCertImpl(certs[i].getSerialNumber(), + CMS.getCurrentDate(), entryExtn); + + revCertImplsV.addElement(revCertImpl); + count++; + rarg.addStringValue("error", null); + argSet.addRepeatRecord(rarg); + } + } + } else { + String b64eCert = req.getParameter("b64eCertificate"); + + if (b64eCert != null) { + byte[] certBytes = Utils.base64decode(b64eCert); + X509CertImpl cert = new X509CertImpl(certBytes); + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addBigIntegerValue("serialNumber", + cert.getSerialNumber(), 16); + oldCertsV.addElement(cert); + + RevokedCertImpl revCertImpl = + new RevokedCertImpl(cert.getSerialNumber(), + CMS.getCurrentDate(), entryExtn); + + revCertImplsV.addElement(revCertImpl); + count++; + rarg.addStringValue("error", null); + argSet.addRepeatRecord(rarg); + } + } + } + + header.addIntegerValue("totalRecordCount", count); + + X509CertImpl[] oldCerts = new X509CertImpl[count]; + RevokedCertImpl[] revCertImpls = new RevokedCertImpl[count]; + + for (int i = 0; i < count; i++) { + oldCerts[i] = (X509CertImpl) oldCertsV.elementAt(i); + revCertImpls[i] = (RevokedCertImpl) revCertImplsV.elementAt(i); + } + + IRequest revReq = + mQueue.newRequest(IRequest.REVOCATION_REQUEST); + + revReq.setExtData(IRequest.CERT_INFO, revCertImpls); + revReq.setExtData(IRequest.REQ_TYPE, IRequest.REVOCATION_REQUEST); + revReq.setExtData(IRequest.REQUESTOR_TYPE, IRequest.REQUESTOR_AGENT); + + revReq.setExtData(IRequest.OLD_CERTS, oldCerts); + if (comments != null) { + revReq.setExtData(IRequest.REQUESTOR_COMMENTS, comments); + } + + mQueue.processRequest(revReq); + RequestStatus stat = revReq.getRequestStatus(); + + if (stat == RequestStatus.COMPLETE) { + // audit log the error + Integer result = revReq.getExtDataInInteger(IRequest.RESULT); + + if (result.equals(IRequest.RES_ERROR)) { + String[] svcErrors = + revReq.getExtDataInStringArray(IRequest.SVCERRORS); + + if (svcErrors != null && svcErrors.length > 0) { + for (int i = 0; i < svcErrors.length; i++) { + String err = svcErrors[i]; + + if (err != null) { + //cmsReq.setErrorDescription(err); + for (int j = 0; j < count; j++) { + if (oldCerts[j] != null) { + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOREVOKEFORMAT, + new Object[] { + revReq.getRequestId(), + initiative, + "completed with error: " + + err, + oldCerts[j].getSubjectDN(), + oldCerts[j].getSerialNumber().toString(16), + RevocationReason.fromInt(reason).toString() } + ); + } + } + } + } + } + return; + } + + // audit log the success. + for (int j = 0; j < count; j++) { + if (oldCerts[j] != null) { + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOREVOKEFORMAT, + new Object[] { + revReq.getRequestId(), + initiative, + "completed", + oldCerts[j].getSubjectDN(), + oldCerts[j].getSerialNumber().toString(16), + RevocationReason.fromInt(reason).toString() } + ); + } + } + + header.addStringValue("revoked", "yes"); + + Integer updateCRLResult = + revReq.getExtDataInInteger(IRequest.CRL_UPDATE_STATUS); + + if (updateCRLResult != null) { + header.addStringValue("updateCRL", "yes"); + if (updateCRLResult.equals(IRequest.RES_SUCCESS)) { + header.addStringValue("updateCRLSuccess", "yes"); + } else { + header.addStringValue("updateCRLSuccess", "no"); + String crlError = + revReq.getExtDataInString(IRequest.CRL_UPDATE_ERROR); + + if (crlError != null) + header.addStringValue("updateCRLError", + crlError); + } + // let known crl publishing status too. + Integer publishCRLResult = + revReq.getExtDataInInteger(IRequest.CRL_PUBLISH_STATUS); + + if (publishCRLResult != null) { + if (publishCRLResult.equals(IRequest.RES_SUCCESS)) { + header.addStringValue("publishCRLSuccess", "yes"); + } else { + header.addStringValue("publishCRLSuccess", "no"); + String publError = + revReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR); + + if (publError != null) + header.addStringValue("publishCRLError", + publError); + } + } + } + if (mAuthority instanceof ICertificateAuthority) { + // let known update and publish status of all crls. + Enumeration otherCRLs = + ((ICertificateAuthority) mAuthority).getCRLIssuingPoints(); + + while (otherCRLs.hasMoreElements()) { + ICRLIssuingPoint crl = (ICRLIssuingPoint) + otherCRLs.nextElement(); + String crlId = crl.getId(); + + if (crlId.equals(ICertificateAuthority.PROP_MASTER_CRL)) + continue; + String updateStatusStr = crl.getCrlUpdateStatusStr(); + Integer updateResult = revReq.getExtDataInInteger(updateStatusStr); + + if (updateResult != null) { + if (updateResult.equals(IRequest.RES_SUCCESS)) { + CMS.debug("ChallengeRevcationServlet1: " + + CMS.getLogMessage("ADMIN_SRVLT_ADDING_HEADER", + updateStatusStr)); + header.addStringValue(updateStatusStr, "yes"); + } else { + String updateErrorStr = crl.getCrlUpdateErrorStr(); + + CMS.debug("ChallengeRevcationServlet1: " + + CMS.getLogMessage("ADMIN_SRVLT_ADDING_HEADER_NO", + updateStatusStr)); + header.addStringValue(updateStatusStr, "no"); + String error = + revReq.getExtDataInString(updateErrorStr); + + if (error != null) + header.addStringValue(updateErrorStr, + error); + } + String publishStatusStr = crl.getCrlPublishStatusStr(); + Integer publishResult = + revReq.getExtDataInInteger(publishStatusStr); + + if (publishResult == null) + continue; + if (publishResult.equals(IRequest.RES_SUCCESS)) { + header.addStringValue(publishStatusStr, "yes"); + } else { + String publishErrorStr = + crl.getCrlPublishErrorStr(); + + header.addStringValue(publishStatusStr, "no"); + String error = + revReq.getExtDataInString(publishErrorStr); + + if (error != null) + header.addStringValue( + publishErrorStr, error); + } + } + } + } + + if (mPublisherProcessor != null && mPublisherProcessor.ldapEnabled()) { + header.addStringValue("dirEnabled", "yes"); + Integer[] ldapPublishStatus = + revReq.getExtDataInIntegerArray("ldapPublishStatus"); + int certsToUpdate = 0; + int certsUpdated = 0; + + if (ldapPublishStatus != null) { + certsToUpdate = ldapPublishStatus.length; + for (int i = 0; i < certsToUpdate; i++) { + if (ldapPublishStatus[i] == IRequest.RES_SUCCESS) { + certsUpdated++; + } + } + } + header.addIntegerValue("certsUpdated", certsUpdated); + header.addIntegerValue("certsToUpdate", certsToUpdate); + + // add crl publishing status. + String publError = + revReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR); + + if (publError != null) { + header.addStringValue("crlPublishError", + publError); + } + } else { + header.addStringValue("dirEnabled", "no"); + } + header.addStringValue("error", null); + + } else if (stat == RequestStatus.PENDING) { + header.addStringValue("error", "Request Pending"); + header.addStringValue("revoked", "pending"); + // audit log the pending + for (int j = 0; j < count; j++) { + if (oldCerts[j] != null) { + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOREVOKEFORMAT, + new Object[] { + revReq.getRequestId(), + initiative, + "pending", + oldCerts[j].getSubjectDN(), + oldCerts[j].getSerialNumber().toString(16), + RevocationReason.fromInt(reason).toString() } + ); + } + } + + } else { + Vector errors = revReq.getExtDataInStringVector(IRequest.ERRORS); + StringBuffer errorStr = new StringBuffer(); + + if (errors != null && errors.size() > 0) { + for (int ii = 0; ii < errors.size(); ii++) { + errorStr.append(errors.elementAt(ii)); + } + } + header.addStringValue("error", errorStr.toString()); + header.addStringValue("revoked", "no"); + // audit log the error + for (int j = 0; j < count; j++) { + if (oldCerts[j] != null) { + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOREVOKEFORMAT, + new Object[] { + revReq.getRequestId(), + initiative, + stat.toString(), + oldCerts[j].getSubjectDN(), + oldCerts[j].getSerialNumber().toString(16), + RevocationReason.fromInt(reason).toString() } + ); + } + } + } + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, "error " + e); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, "error " + e); + throw e; + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED", e.toString())); + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED")); + } catch (Exception e) { + e.printStackTrace(); + } + + return; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/CloneRedirect.java b/base/common/src/com/netscape/cms/servlet/cert/CloneRedirect.java new file mode 100644 index 000000000..d17fd959b --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/CloneRedirect.java @@ -0,0 +1,142 @@ +// --- 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.cert; + +import java.io.IOException; +import java.util.Locale; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.ca.ICertificateAuthority; +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.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Redirect a request to the Master. This servlet is used in + * a clone when a requested service (such as CRL) is not available. + * It redirects the user to the master. + * + * @version $Revision$, $Date$ + */ +public class CloneRedirect extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = 3217967115281965166L; + private final static String PROP_REDIRECT_URL = "masterURL"; + private final static String TPL_FILE = "cloneRedirect.template"; + + private String mNewUrl = null; + private String mFormPath = null; + + private ICertificateAuthority mCA = null; + + /** + * Constructs CloneRedirect servlet. + */ + public CloneRedirect() { + super(); + + } + + /** + * Initialize the servlet. + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + + if (mAuthority instanceof ICertificateAuthority) { + mCA = (ICertificateAuthority) mAuthority; + IConfigStore authConfig = mCA.getConfigStore(); + + if (authConfig != null) { + try { + mNewUrl = authConfig.getString(PROP_REDIRECT_URL, + "*** master URL unavailable, check your configuration ***"); + } catch (EBaseException e) { + // do nothing + } + } + } + + if (mAuthority instanceof ICertificateAuthority) + mCA = (ICertificateAuthority) mAuthority; + + // override success to do output with our own template. + mTemplates.remove(CMSRequest.SUCCESS); + } + + /** + * Serves HTTP request. + */ + public void process(CMSRequest cmsReq) throws EBaseException { + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, req, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + throw new ECMSGWException( + CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + } + + CMS.debug("CloneRedirect: " + CMS.getLogMessage("ADMIN_SRVLT_ADD_MASTER_URL", mNewUrl)); + header.addStringValue("masterURL", mNewUrl); + try { + ServletOutputStream out = resp.getOutputStream(); + + String xmlOutput = req.getParameter("xml"); + if (xmlOutput != null && xmlOutput.equals("true")) { + outputXML(resp, argSet); + } else { + resp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_ERR_STREAM_TEMPLATE", e.toString())); + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + } + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/DirAuthServlet.java b/base/common/src/com/netscape/cms/servlet/cert/DirAuthServlet.java new file mode 100644 index 000000000..ced92ba85 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/DirAuthServlet.java @@ -0,0 +1,241 @@ +// --- 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.cert; + +import java.io.IOException; +import java.util.Date; +import java.util.Locale; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthManager; +import com.netscape.certsrv.authentication.IAuthSubsystem; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.ra.IRegistrationAuthority; +import com.netscape.cms.authentication.HashAuthentication; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * 'Face-to-face' certificate enrollment. + * + * @version $Revision$, $Date$ + */ +public class DirAuthServlet extends CMSServlet { + /** + * + */ + private static final long serialVersionUID = 3906057586972768401L; + private final static String TPL_FILE = "/ra/hashEnrollmentSubmit.template"; + private final static String TPL_ERROR_FILE = "/ra/GenErrorHashDirEnroll.template"; + private String mFormPath = null; + + public DirAuthServlet() { + super(); + } + + /** + * initialize the servlet. + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + try { + mFormPath = sc.getInitParameter( + PROP_SUCCESS_TEMPLATE); + if (mFormPath == null) + mFormPath = TPL_FILE; + } catch (Exception e) { + } + + mTemplates.remove(CMSRequest.SUCCESS); + } + + /** + * Process the HTTP request. This servlet reads configuration information + * from the hashDirEnrollment configuration substore + * + * @param cmsReq the object holding the request and response information + */ + protected void process(CMSRequest cmsReq) + throws EBaseException { + HttpServletRequest httpReq = cmsReq.getHttpReq(); + HttpServletResponse httpResp = cmsReq.getHttpResp(); + + String reqHost = httpReq.getRemoteHost(); + + // Construct an ArgBlock + IArgBlock args = cmsReq.getHttpParams(); + + if (!(mAuthority instanceof IRegistrationAuthority)) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("ADMIN_SRVLT_CA_FROM_RA_NOT_IMP")); + cmsReq.setError(new ECMSGWException( + CMS.getLogMessage("CMSGW_NOT_YET_IMPLEMENTED"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, httpReq, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + cmsReq.setError(new ECMSGWException( + CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + IAuthToken authToken = authenticate(cmsReq); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "submit"); + } catch (Exception e) { + // do nothing for now + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + IConfigStore configStore = CMS.getConfigStore(); + String val = configStore.getString("hashDirEnrollment.name"); + IAuthSubsystem authSS = (IAuthSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_AUTH); + IAuthManager authMgr = authSS.get(val); + HashAuthentication mgr = (HashAuthentication) authMgr; + + Date date = new Date(); + long currTime = date.getTime(); + long timeout = mgr.getTimeout(reqHost); + long lastlogin = mgr.getLastLogin(reqHost); + long diff = currTime - lastlogin; + + boolean enable = mgr.isEnable(reqHost); + + if (!enable) { + printError(cmsReq, "0"); + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } + if (lastlogin == 0) + mgr.setLastLogin(reqHost, currTime); + else if (diff > timeout) { + mgr.disable(reqHost); + printError(cmsReq, "2"); + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } + + mgr.setLastLogin(reqHost, currTime); + + String uid = args.getValueAsString("uid"); + long pageid = mgr.getPageID(); + String pageID = pageid + ""; + + mgr.addAuthToken(pageID, authToken); + + header.addStringValue("pageID", pageID); + header.addStringValue("uid", uid); + header.addStringValue("fingerprint", mgr.hashFingerprint(reqHost, pageID, uid)); + header.addStringValue("hostname", reqHost); + + try { + ServletOutputStream out = httpResp.getOutputStream(); + + httpResp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_ERR_STREAM_TEMPLATE", e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE"))); + cmsReq.setStatus(CMSRequest.ERROR); + } + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } + + private void printError(CMSRequest cmsReq, String errorCode) + throws EBaseException { + HttpServletRequest httpReq = cmsReq.getHttpReq(); + HttpServletResponse httpResp = cmsReq.getHttpResp(); + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + mTemplates.remove(CMSRequest.SUCCESS); + header.addStringValue("authority", "Registration Manager"); + header.addStringValue("errorCode", errorCode); + String formPath = TPL_ERROR_FILE; + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(formPath, httpReq, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_ERR_GET_TEMPLATE", formPath, e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + try { + ServletOutputStream out = httpResp.getOutputStream(); + + httpResp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_ERR_STREAM_TEMPLATE", e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE"))); + cmsReq.setStatus(CMSRequest.ERROR); + } + } + +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/DisableEnrollResult.java b/base/common/src/com/netscape/cms/servlet/cert/DisableEnrollResult.java new file mode 100644 index 000000000..a5cdc98e8 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/DisableEnrollResult.java @@ -0,0 +1,173 @@ +// --- 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.cert; + +import java.io.IOException; +import java.security.cert.X509Certificate; +import java.util.Locale; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthManager; +import com.netscape.certsrv.authentication.IAuthSubsystem; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.ra.IRegistrationAuthority; +import com.netscape.cms.authentication.HashAuthentication; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * For Face-to-face enrollment, disable EE enrollment feature + * + * @version $Revision$, $Date$ + * @see com.netscape.cms.servlet.cert.EnableEnrollResult + */ +public class DisableEnrollResult extends CMSServlet { + /** + * + */ + private static final long serialVersionUID = 4307655310299723974L; + private final static String TPL_FILE = "enableEnrollResult.template"; + private String mFormPath = null; + + public DisableEnrollResult() { + super(); + } + + /** + * Initializes the servlet. + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + // coming from agent + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + + mTemplates.remove(CMSRequest.SUCCESS); + } + + protected CMSRequest newCMSRequest() { + return new CMSRequest(); + } + + /** + * Services the request + */ + protected void process(CMSRequest cmsReq) + throws EBaseException { + HttpServletRequest httpReq = cmsReq.getHttpReq(); + HttpServletResponse httpResp = cmsReq.getHttpResp(); + + IAuthToken token = authenticate(cmsReq); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, token, + mAuthzResourceName, "disable"); + } catch (Exception e) { + // do nothing for now + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + X509Certificate sslClientCert = null; + + sslClientCert = getSSLClientCertificate(httpReq); + String dn = (String) sslClientCert.getSubjectDN().toString(); + + // Construct an ArgBlock + IArgBlock args = cmsReq.getHttpParams(); + + if (!(mAuthority instanceof IRegistrationAuthority)) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("ADMIN_SRVLT_CA_FROM_RA_NOT_IMP")); + cmsReq.setError(new ECMSGWException( + CMS.getLogMessage("CMSGW_NOT_YET_IMPLEMENTED"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, httpReq, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_ERR_GET_TEMPLATE", mFormPath, e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + IConfigStore configStore = CMS.getConfigStore(); + String val = configStore.getString("hashDirEnrollment.name"); + IAuthSubsystem authSS = (IAuthSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_AUTH); + IAuthManager authMgr = authSS.get(val); + HashAuthentication mgr = (HashAuthentication) authMgr; + + String host = args.getValueAsString("hosts", null); + String name = mgr.getAgentName(host); + + if (name == null) { + header.addStringValue("code", "2"); + } else if (name.equals(dn)) { + mgr.disable(host); + header.addStringValue("code", "2"); + } else { + header.addStringValue("code", "3"); + } + + try { + ServletOutputStream out = httpResp.getOutputStream(); + + httpResp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_ERR_STREAM_TEMPLATE", e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + } + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } + +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/DisplayBySerial.java b/base/common/src/com/netscape/cms/servlet/cert/DisplayBySerial.java new file mode 100644 index 000000000..5a1e4ed65 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/DisplayBySerial.java @@ -0,0 +1,488 @@ +// --- 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.cert; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.Enumeration; +import java.util.Locale; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.extensions.NSCertTypeExtension; +import netscape.security.pkcs.ContentInfo; +import netscape.security.pkcs.PKCS7; +import netscape.security.pkcs.SignerInfo; +import netscape.security.x509.AlgorithmId; +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.CRLReasonExtension; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.Extension; +import netscape.security.x509.KeyUsageExtension; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authority.ICertAuthority; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.ICertPrettyPrint; +import com.netscape.certsrv.base.MetaInfo; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.EDBRecordNotFoundException; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.dbs.certdb.IRevocationInfo; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.RequestId; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; +import com.netscape.cmsutil.util.Utils; + +/** + * Display detailed information about a certificate + * + * The template 'displayBySerial.template' is used to + * render the response for this servlet. + * + * @version $Revision$, $Date$ + */ +public class DisplayBySerial extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = -4143700762995036597L; + private final static String INFO = "DisplayBySerial"; + private final static String TPL_FILE1 = "displayBySerial.template"; + private final static BigInteger MINUS_ONE = new BigInteger("-1"); + + private ICertificateRepository mCertDB = null; + private String mForm1Path = null; + private X509Certificate mCACerts[] = null; + + /** + * Constructs DisplayBySerial servlet. + */ + public DisplayBySerial() { + super(); + } + + /** + * initialize the servlet. + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + if (mAuthority instanceof ICertificateAuthority) { + mCertDB = ((ICertificateAuthority) mAuthority).getCertificateRepository(); + } + try { + mCACerts = ((ICertAuthority) mAuthority).getCACertChain().getChain(); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CA_CHAIN_NOT_AVAILABLE")); + } + // coming from ee + mForm1Path = "/" + mAuthority.getId() + "/" + TPL_FILE1; + + if (mOutputTemplatePath != null) + mForm1Path = mOutputTemplatePath; + + // override success and error templates to null - + // handle templates locally. + mTemplates.remove(CMSRequest.SUCCESS); + } + + /** + * Serves HTTP request. The format of this request is as follows: + *
    + *
  • http.param serialNumber Decimal serial number of certificate to display (or hex if serialNumber preceded by + * 0x) + *
+ */ + public void process(CMSRequest cmsReq) throws EBaseException { + BigInteger serialNumber = MINUS_ONE; + EBaseException error = null; + String certType[] = new String[1]; + + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "read"); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + serialNumber = getSerialNumber(req); + getCertRecord(serialNumber, certType); //throw exception on error + + if (certType[0].equalsIgnoreCase("x509")) { + form = getTemplate(mForm1Path, req, locale); + } + } catch (NumberFormatException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("BASE_INVALID_NUMBER_FORMAT_1", String.valueOf(serialNumber))); + + error = new ECMSGWException(CMS.getLogMessage("BASE_INVALID_NUMBER_FORMAT")); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", mForm1Path, e.toString())); + throw new ECMSGWException( + CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + } catch (EDBRecordNotFoundException e) { + throw new ECMSGWException( + CMS.getLogMessage("CMSGW_CERT_SERIAL_NOT_FOUND_1", "0x" + serialNumber.toString(16))); + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + try { + if (serialNumber.compareTo(MINUS_ONE) > 0) { + process(argSet, header, serialNumber, + req, resp, locale[0]); + } else { + error = new ECMSGWException( + CMS.getLogMessage("CMSGW_INVALID_SERIAL_NUMBER")); + } + } catch (EBaseException e) { + error = e; + } + + try { + ServletOutputStream out = resp.getOutputStream(); + + if (error == null) { + String xmlOutput = req.getParameter("xml"); + if (xmlOutput != null && xmlOutput.equals("true")) { + outputXML(resp, argSet); + } else { + resp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } + } else { + cmsReq.setStatus(CMSRequest.ERROR); + cmsReq.setError(error); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_BAD_SERV_OUT_STREAM", e.toString())); + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + } + + } + + /** + * Display information about a particular certificate + */ + private void process(CMSTemplateParams argSet, IArgBlock header, + BigInteger seq, HttpServletRequest req, + HttpServletResponse resp, + Locale locale) + throws EBaseException { + String certType[] = new String[1]; + + try { + getCertRecord(seq, certType); // throw exception on error + + if (certType[0].equalsIgnoreCase("x509")) { + processX509(argSet, header, seq, req, resp, locale); + return; + } + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_DISP_BY_SERIAL", e.toString())); + throw e; + } + + return; + } + + private void processX509(CMSTemplateParams argSet, IArgBlock header, + BigInteger seq, HttpServletRequest req, + HttpServletResponse resp, + Locale locale) + throws EBaseException { + try { + ICertRecord rec = (ICertRecord) mCertDB.readCertificateRecord(seq); + if (rec == null) { + CMS.debug("DisplayBySerial: failed to read record"); + throw new ECMSGWException( + CMS.getLogMessage("CMSGW_ERROR_ENCODING_ISSUED_CERT")); + } + X509CertImpl cert = rec.getCertificate(); + if (cert == null) { + CMS.debug("DisplayBySerial: no certificate in record"); + throw new ECMSGWException( + CMS.getLogMessage("CMSGW_ERROR_ENCODING_ISSUED_CERT")); + } + + try { + X509CertInfo info = (X509CertInfo) cert.get(X509CertImpl.NAME + "." + X509CertImpl.INFO); + if (info == null) { + CMS.debug("DisplayBySerial: no info found"); + throw new ECMSGWException( + CMS.getLogMessage("CMSGW_ERROR_ENCODING_ISSUED_CERT")); + } + CertificateExtensions extensions = (CertificateExtensions) info.get(X509CertInfo.EXTENSIONS); + + boolean emailCert = false; + + if (extensions != null) { + for (int i = 0; i < extensions.size(); i++) { + Extension ext = (Extension) extensions.elementAt(i); + + if (ext instanceof NSCertTypeExtension) { + NSCertTypeExtension type = (NSCertTypeExtension) ext; + + if (((Boolean) type.get(NSCertTypeExtension.EMAIL)).booleanValue()) + emailCert = true; + } + if (ext instanceof KeyUsageExtension) { + KeyUsageExtension usage = + (KeyUsageExtension) ext; + + try { + if (((Boolean) usage.get(KeyUsageExtension.DIGITAL_SIGNATURE)).booleanValue() || + ((Boolean) usage.get(KeyUsageExtension.DATA_ENCIPHERMENT)).booleanValue()) + emailCert = true; + } catch (ArrayIndexOutOfBoundsException e) { + // bug356108: + // In case there is only DIGITAL_SIGNATURE, + // don't report error + } + } + } + } + header.addBooleanValue("emailCert", emailCert); + + boolean noCertImport = true; + MetaInfo metaInfo = (MetaInfo) rec.get(ICertRecord.ATTR_META_INFO); + + if (metaInfo != null) { + String rid = (String) metaInfo.get(ICertRecord.META_REQUEST_ID); + + if (rid != null && mAuthority instanceof ICertificateAuthority) { + IRequest r = + ((ICertificateAuthority) mAuthority).getRequestQueue().findRequest(new RequestId(rid)); + String certType = r.getExtDataInString(IRequest.HTTP_PARAMS, IRequest.CERT_TYPE); + + if (certType != null && certType.equals(IRequest.CLIENT_CERT)) { + noCertImport = false; + } + } + } + header.addBooleanValue("noCertImport", noCertImport); + + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_PARSING_EXTENS", e.toString())); + } + + IRevocationInfo revocationInfo = rec.getRevocationInfo(); + + if (revocationInfo != null) { + CRLExtensions crlExts = revocationInfo.getCRLEntryExtensions(); + + if (crlExts != null) { + Enumeration enumx = crlExts.getElements(); + int reason = 0; + + while (enumx.hasMoreElements()) { + Extension ext = (Extension) enumx.nextElement(); + + if (ext instanceof CRLReasonExtension) { + reason = ((CRLReasonExtension) ext).getReason().toInt(); + } + } + header.addIntegerValue("revocationReason", reason); + } + } + + ICertPrettyPrint certDetails = CMS.getCertPrettyPrint(cert); + + header.addStringValue("certPrettyPrint", + certDetails.toString(locale)); + + /* + String scheme = req.getScheme(); + if (scheme.equals("http") && connectionIsSSL(req)) + scheme = "https"; + String requestURI = req.getRequestURI(); + int i = requestURI.indexOf('?'); + String newRequestURI = + (i > -1)? requestURI.substring(0, i): requestURI; + header.addStringValue("serviceURL", scheme +"://"+ + req.getServerName() + ":"+ + req.getServerPort() + newRequestURI); + */ + header.addStringValue("authorityid", mAuthority.getId()); + + String certFingerprints = ""; + + try { + certFingerprints = CMS.getFingerPrints(cert); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_DIGESTING_CERT", e.toString())); + } + if (certFingerprints.length() > 0) + header.addStringValue("certFingerprint", certFingerprints); + + byte[] ba = cert.getEncoded(); + // Do base 64 encoding + + header.addStringValue("certChainBase64", Utils.base64encode(ba)); + header.addStringValue("serialNumber", seq.toString(16)); + + /* + String userAgent = req.getHeader("user-agent"); + String agent = + (userAgent != null)? UserInfo.getUserAgent(userAgent): ""; + */ + // Now formulate a PKCS#7 blob + X509CertImpl[] certsInChain = new X509CertImpl[1]; + ; + if (mCACerts != null) { + for (int i = 0; i < mCACerts.length; i++) { + if (cert.equals(mCACerts[i])) { + certsInChain = new + X509CertImpl[mCACerts.length]; + break; + } + certsInChain = new X509CertImpl[mCACerts.length + 1]; + } + } + + // Set the EE cert + certsInChain[0] = cert; + + // Set the Ca certificate chain + if (mCACerts != null) { + for (int i = 0; i < mCACerts.length; i++) { + if (!cert.equals(mCACerts[i])) + certsInChain[i + 1] = (X509CertImpl) mCACerts[i]; + } + } + + // Wrap the chain into a degenerate P7 object + String p7Str; + + try { + PKCS7 p7 = new PKCS7(new AlgorithmId[0], + new ContentInfo(new byte[0]), + certsInChain, + new SignerInfo[0]); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + p7.encodeSignedData(bos, false); + byte[] p7Bytes = bos.toByteArray(); + + p7Str = Utils.base64encode(p7Bytes); + header.addStringValue("pkcs7ChainBase64", p7Str); + } catch (Exception e) { + //p7Str = "PKCS#7 B64 Encoding error - " + e.toString() + //+ "; Please contact your administrator"; + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_FORMING_PKCS7_1", e.toString())); + throw new ECMSGWException( + CMS.getLogMessage("CMSGW_ERROR_FORMING_PKCS7")); + } + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("MSGW_ERR_DISP_BY_SERIAL", e.toString())); + throw e; + } catch (CertificateEncodingException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_ENCODE_CERT", e.toString())); + throw new ECMSGWException( + CMS.getLogMessage("CMSGW_ERROR_ENCODING_ISSUED_CERT")); + } + + return; + } + + private ICertRecord getCertRecord(BigInteger seq, String certtype[]) + throws EBaseException { + ICertRecord rec = null; + + try { + rec = (ICertRecord) mCertDB.readCertificateRecord(seq); + X509CertImpl x509cert = rec.getCertificate(); + + if (x509cert != null) { + certtype[0] = "x509"; + return rec; + } + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_DISP_BY_SERIAL", e.toString())); + throw e; + } + + return rec; + } + + private BigInteger getSerialNumber(HttpServletRequest req) + throws NumberFormatException { + String serialNumString = req.getParameter("serialNumber"); + + if (serialNumString != null) { + serialNumString = serialNumString.trim(); + if (serialNumString.startsWith("0x") || serialNumString.startsWith("0X")) { + return new BigInteger(serialNumString.substring(2), 16); + } else { + return new BigInteger(serialNumString); + } + } else { + throw new NumberFormatException(); + } + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/DisplayCRL.java b/base/common/src/com/netscape/cms/servlet/cert/DisplayCRL.java new file mode 100644 index 000000000..ad503272a --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/DisplayCRL.java @@ -0,0 +1,481 @@ +// --- 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.cert; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.CRLException; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.X509CRLImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.ICRLPrettyPrint; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.crldb.ICRLIssuingPointRecord; +import com.netscape.certsrv.dbs.crldb.ICRLRepository; +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.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; +import com.netscape.cmsutil.util.Utils; + +/** + * Decode the CRL and display it to the requester. + * + * @version $Revision$, $Date$ + */ +public class DisplayCRL extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = 1152016798229054027L; + private final static String INFO = "DisplayCRL"; + private final static String TPL_FILE = "displayCRL.template"; + //private final static String E_TPL_FILE = "error.template"; + //private final static String OUT_ERROR = "errorDetails"; + + private String mFormPath = null; + private ICertificateAuthority mCA = null; + + /** + * Constructs DisplayCRL servlet. + */ + public DisplayCRL() { + super(); + } + + /** + * Initialize the servlet. This servlet uses the 'displayCRL.template' file to + * to render the response to the client. + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + if (mAuthority instanceof ICertificateAuthority) { + mCA = (ICertificateAuthority) mAuthority; + } + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + + if (mOutputTemplatePath != null) + mFormPath = mOutputTemplatePath; + + mTemplates.remove(CMSRequest.SUCCESS); + } + + /** + * Process the HTTP request + *
    + *
  • http.param crlIssuingPoint number + *
  • http.param crlDisplayType entireCRL or crlHeader or base64Encoded or deltaCRL + *
  • http.param pageStart which page to start displaying from + *
  • http.param pageSize number of entries to show per page + *
+ * + * @param cmsReq the Request to service. + */ + public void process(CMSRequest cmsReq) throws EBaseException { + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "read"); + } catch (Exception e) { + // do nothing for now + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, req, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE_1", mFormPath, e.toString())); + throw new ECMSGWException( + CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + // Note error is covered in the same template as success. + + String crlIssuingPointId = req.getParameter("crlIssuingPoint"); + + process(argSet, header, req, resp, crlIssuingPointId, + locale[0]); + + try { + ServletOutputStream out = resp.getOutputStream(); + + String xmlOutput = req.getParameter("xml"); + if (xmlOutput != null && xmlOutput.equals("true")) { + outputXML(resp, argSet); + } else { + resp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_BAD_SERV_OUT_STREAM", e.toString())); + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + } + } + + /** + * Display information about a particular CRL. + */ + private void process(CMSTemplateParams argSet, IArgBlock header, + HttpServletRequest req, + HttpServletResponse resp, + String crlIssuingPointId, + Locale locale) { + ICRLIssuingPoint crlIP = null; + X509CRLImpl crl = null; + boolean clonedCA = false; + boolean isCRLCacheEnabled = false; + String masterHost = null; + String masterPort = null; + Vector ipNames = null; + String ipId = crlIssuingPointId; + ICRLRepository crlRepository = mCA.getCRLRepository(); + + try { + masterHost = CMS.getConfigStore().getString("master.ca.agent.host", ""); + masterPort = CMS.getConfigStore().getString("master.ca.agent.port", ""); + if (masterHost != null && masterHost.length() > 0 && + masterPort != null && masterPort.length() > 0) { + clonedCA = true; + ipNames = crlRepository.getIssuingPointsNames(); + } + } catch (EBaseException e) { + } + + if (clonedCA) { + if (crlIssuingPointId != null) { + if (ipNames != null && ipNames.size() > 0) { + int i; + for (i = 0; i < ipNames.size(); i++) { + String ipName = ipNames.elementAt(i); + if (crlIssuingPointId.equals(ipName)) { + break; + } + } + if (i >= ipNames.size()) + crlIssuingPointId = null; + } else { + crlIssuingPointId = null; + } + } + } else { + if (crlIssuingPointId != null) { + Enumeration ips = mCA.getCRLIssuingPoints(); + + while (ips.hasMoreElements()) { + ICRLIssuingPoint ip = ips.nextElement(); + + if (crlIssuingPointId.equals(ip.getId())) { + crlIP = ip; + isCRLCacheEnabled = ip.isCRLCacheEnabled(); + break; + } + if (!ips.hasMoreElements()) + crlIssuingPointId = null; + } + } + } + if (crlIssuingPointId == null) { + header.addStringValue("error", + "Request to unspecified or non-existing CRL issuing point: " + ipId); + return; + } + + ICRLIssuingPointRecord crlRecord = null; + + String crlDisplayType = req.getParameter("crlDisplayType"); + + if (crlDisplayType == null) + crlDisplayType = "cachedCRL"; + header.addStringValue("crlDisplayType", crlDisplayType); + + try { + crlRecord = + (ICRLIssuingPointRecord) mCA.getCRLRepository().readCRLIssuingPointRecord(crlIssuingPointId); + } catch (EBaseException e) { + header.addStringValue("error", e.toString(locale)); + return; + } + if (crlRecord == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CRL_NOT_YET_UPDATED_1", crlIssuingPointId)); + header.addStringValue("error", + new ECMSGWException(CMS.getUserMessage(locale, "CMS_GW_CRL_NOT_YET_UPDATED")).toString()); + return; + } + + header.addStringValue("crlIssuingPoint", crlIssuingPointId); + if (crlDisplayType.equals("deltaCRL")) { + if (clonedCA) { + header.addStringValue("crlNumber", crlRecord.getDeltaCRLNumber().toString()); + } else { + header.addStringValue("crlNumber", crlIP.getDeltaCRLNumber().toString()); + } + } else { + if (clonedCA) { + header.addStringValue("crlNumber", crlRecord.getCRLNumber().toString()); + } else { + header.addStringValue("crlNumber", crlIP.getCRLNumber().toString()); + } + } + long lCRLSize = crlRecord.getCRLSize().longValue(); + header.addLongValue("crlSize", lCRLSize); + + if (crlIP != null) { + header.addStringValue("crlDescription", crlIP.getDescription()); + } + + if (!crlDisplayType.equals("cachedCRL")) { + byte[] crlbytes = crlRecord.getCRL(); + + if (crlbytes == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CRL_NOT_YET_UPDATED_1", crlIssuingPointId)); + header.addStringValue("error", + new ECMSGWException(CMS.getUserMessage(locale, "CMS_GW_CRL_NOT_YET_UPDATED")).toString()); + return; + } + + try { + if (crlDisplayType.equals("crlHeader")) { + crl = new X509CRLImpl(crlbytes, false); + } else { + crl = new X509CRLImpl(crlbytes); + } + + } catch (Exception e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERR_DECODE_CRL", e.toString())); + header.addStringValue("error", + new ECMSGWException(CMS.getUserMessage(locale, "CMS_GW_DECODE_CRL_FAILED")).toString()); + } + } + + if (crl != null || (isCRLCacheEnabled && crlDisplayType.equals("cachedCRL"))) { + if (crlDisplayType.equals("entireCRL") || crlDisplayType.equals("cachedCRL")) { + ICRLPrettyPrint crlDetails = null; + if (crlDisplayType.equals("entireCRL")) { + crlDetails = CMS.getCRLPrettyPrint(crl); + } else { + crlDetails = CMS.getCRLCachePrettyPrint(crlIP); + } + + String pageStart = req.getParameter("pageStart"); + String pageSize = req.getParameter("pageSize"); + + if (pageStart != null && pageSize != null) { + long lPageStart = new Long(pageStart).longValue(); + long lPageSize = new Long(pageSize).longValue(); + + if (lPageStart < 1) + lPageStart = 1; + // if (lPageStart + lPageSize - lCRLSize > 1) + // lPageStart = lCRLSize - lPageSize + 1; + + header.addStringValue( + "crlPrettyPrint", crlDetails.toString(locale, + lCRLSize, lPageStart, lPageSize)); + header.addLongValue("pageStart", lPageStart); + header.addLongValue("pageSize", lPageSize); + } else { + header.addStringValue( + "crlPrettyPrint", crlDetails.toString(locale)); + } + } else if (crlDisplayType.equals("crlHeader")) { + ICRLPrettyPrint crlDetails = CMS.getCRLPrettyPrint(crl); + + header.addStringValue( + "crlPrettyPrint", crlDetails.toString(locale, lCRLSize, 0, 0)); + } else if (crlDisplayType.equals("base64Encoded")) { + try { + byte[] ba = crl.getEncoded(); + String crlBase64Encoded = Utils.base64encode(ba); + int length = crlBase64Encoded.length(); + int i = 0; + int j = 0; + int n = 1; + + while (i < length) { + int k = crlBase64Encoded.indexOf('\n', i); + + if (n < 100 && k > -1) { + n++; + i = k + 1; + if (i >= length) { + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addStringValue("crlBase64Encoded", crlBase64Encoded.substring(j, k)); + argSet.addRepeatRecord(rarg); + } + } else { + n = 1; + IArgBlock rarg = CMS.createArgBlock(); + + if (k > -1) { + rarg.addStringValue("crlBase64Encoded", crlBase64Encoded.substring(j, k)); + i = k + 1; + j = i; + } else { + rarg.addStringValue("crlBase64Encoded", crlBase64Encoded.substring(j, length)); + i = length; + } + argSet.addRepeatRecord(rarg); + } + } + } catch (CRLException e) { + } + } else if (crlDisplayType.equals("deltaCRL")) { + if ((clonedCA && crlRecord.getDeltaCRLSize() != null && + crlRecord.getDeltaCRLSize().longValue() > -1) || + (crlIP != null && crlIP.isDeltaCRLEnabled())) { + byte[] deltaCRLBytes = crlRecord.getDeltaCRL(); + + if (deltaCRLBytes == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_NO_DELTA_CRL", crlIssuingPointId)); + header.addStringValue("error", "Delta CRL is not available"); + } else { + X509CRLImpl deltaCRL = null; + + try { + deltaCRL = new X509CRLImpl(deltaCRLBytes); + } catch (Exception e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERR_DECODE_DELTA_CRL", e.toString())); + header.addStringValue("error", + new ECMSGWException(CMS.getUserMessage(locale, "CMS_GW_DECODE_CRL_FAILED")) + .toString()); + } + if (deltaCRL != null) { + BigInteger crlNumber = crlRecord.getCRLNumber(); + BigInteger deltaNumber = crlRecord.getDeltaCRLNumber(); + if ((clonedCA && crlNumber != null && deltaNumber != null && + deltaNumber.compareTo(crlNumber) >= 0) || + (crlIP != null && crlIP.isThisCurrentDeltaCRL(deltaCRL))) { + + header.addIntegerValue("deltaCRLSize", + deltaCRL.getNumberOfRevokedCertificates()); + + ICRLPrettyPrint crlDetails = CMS.getCRLPrettyPrint(deltaCRL); + + header.addStringValue( + "crlPrettyPrint", crlDetails.toString(locale, 0, 0, 0)); + + try { + byte[] ba = deltaCRL.getEncoded(); + String crlBase64Encoded = Utils.base64encode(ba); + int length = crlBase64Encoded.length(); + int i = 0; + int j = 0; + int n = 1; + + while (i < length) { + int k = crlBase64Encoded.indexOf('\n', i); + + if (n < 100 && k > -1) { + n++; + i = k + 1; + if (i >= length) { + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addStringValue("crlBase64Encoded", + crlBase64Encoded.substring(j, k)); + argSet.addRepeatRecord(rarg); + } + } else { + n = 1; + IArgBlock rarg = CMS.createArgBlock(); + + if (k > -1) { + rarg.addStringValue("crlBase64Encoded", + crlBase64Encoded.substring(j, k)); + i = k + 1; + j = i; + } else { + rarg.addStringValue("crlBase64Encoded", + crlBase64Encoded.substring(j, length)); + i = length; + } + argSet.addRepeatRecord(rarg); + } + } + } catch (CRLException e) { + } + } else { + header.addStringValue("error", "Current Delta CRL is not available."); + } + } + } + } else { + header.addStringValue("error", "Delta CRL is not enabled for " + + crlIssuingPointId + + " issuing point"); + } + } + + } else if (!isCRLCacheEnabled && crlDisplayType.equals("cachedCRL")) { + header.addStringValue("error", + CMS.getUserMessage(locale, "CMS_GW_CRL_CACHE_IS_NOT_ENABLED", crlIssuingPointId)); + header.addStringValue("crlPrettyPrint", + CMS.getUserMessage(locale, "CMS_GW_CRL_CACHE_IS_NOT_ENABLED", crlIssuingPointId)); + } else { + header.addStringValue("error", + new ECMSGWException(CMS.getUserMessage(locale, "CMS_GW_DECODE_CRL_FAILED")).toString()); + header.addStringValue("crlPrettyPrint", + new ECMSGWException(CMS.getUserMessage(locale, "CMS_GW_DECODE_CRL_FAILED")).toString()); + } + return; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/DisplayHashUserEnroll.java b/base/common/src/com/netscape/cms/servlet/cert/DisplayHashUserEnroll.java new file mode 100644 index 000000000..99082d4c5 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/DisplayHashUserEnroll.java @@ -0,0 +1,227 @@ +// --- 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.cert; + +import java.io.IOException; +import java.util.Date; +import java.util.Locale; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthManager; +import com.netscape.certsrv.authentication.IAuthSubsystem; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.ra.IRegistrationAuthority; +import com.netscape.cms.authentication.HashAuthentication; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Servlet to report the status, ie, the agent-initiated user + * enrollment is enabled or disabled. + * + * @version $Revision$, $Date$ + */ +public class DisplayHashUserEnroll extends CMSServlet { + /** + * + */ + private static final long serialVersionUID = -7063912475278810362L; + private final static String TPL_FILE = "/ra/hashDirUserEnroll.template"; + private final static String TPL_ERROR_FILE = "/ra/GenErrorHashDirEnroll.template"; + private String mFormPath = null; + + public DisplayHashUserEnroll() { + super(); + } + + /** + * Initializes the servlet. + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + + try { + mFormPath = sc.getInitParameter( + PROP_SUCCESS_TEMPLATE); + if (mFormPath == null) + mFormPath = TPL_FILE; + } catch (Exception e) { + } + + mTemplates.remove(CMSRequest.SUCCESS); + } + + protected CMSRequest newCMSRequest() { + return new CMSRequest(); + } + + /** + * Services the request + */ + protected void process(CMSRequest cmsReq) + throws EBaseException { + HttpServletRequest httpReq = cmsReq.getHttpReq(); + HttpServletResponse httpResp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "read"); + } catch (Exception e) { + // do nothing for now + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + String reqHost = httpReq.getRemoteHost(); + + if (!(mAuthority instanceof IRegistrationAuthority)) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("ADMIN_SRVLT_ERR_GET_TEMPLATE")); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_NOT_YET_IMPLEMENTED"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + IConfigStore configStore = CMS.getConfigStore(); + String val = configStore.getString("hashDirEnrollment.name"); + IAuthSubsystem authSS = (IAuthSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_AUTH); + IAuthManager authMgr = authSS.get(val); + HashAuthentication mgr = (HashAuthentication) authMgr; + boolean isEnable = mgr.isEnable(reqHost); + + if (!isEnable) { + printError(cmsReq, "0"); + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } + + Date date = new Date(); + long currTime = date.getTime(); + long timeout = mgr.getTimeout(reqHost); + long lastlogin = mgr.getLastLogin(reqHost); + long diff = currTime - lastlogin; + + if (lastlogin == 0) + mgr.setLastLogin(reqHost, currTime); + else if (diff > timeout) { + mgr.disable(reqHost); + printError(cmsReq, "2"); + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } + + mgr.setLastLogin(reqHost, currTime); + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, httpReq, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_ERR_GET_TEMPLATE", mFormPath, e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + try { + ServletOutputStream out = httpResp.getOutputStream(); + + httpResp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_OUT_STREAM_TEMPLATE", e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + } + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } + + private void printError(CMSRequest cmsReq, String errorCode) + throws EBaseException { + HttpServletRequest httpReq = cmsReq.getHttpReq(); + HttpServletResponse httpResp = cmsReq.getHttpResp(); + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + mTemplates.remove(CMSRequest.SUCCESS); + header.addStringValue("authority", "Registration Manager"); + header.addStringValue("errorCode", errorCode); + String formPath = TPL_ERROR_FILE; + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(formPath, httpReq, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_ERR_GET_TEMPLATE", formPath, e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + try { + ServletOutputStream out = httpResp.getOutputStream(); + + httpResp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_BAD_SERV_OUT_STREAM", "", e.toString())); + + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + } + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/DoRevoke.java b/base/common/src/com/netscape/cms/servlet/cert/DoRevoke.java new file mode 100644 index 000000000..1594c5323 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/DoRevoke.java @@ -0,0 +1,1221 @@ +// --- 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.cert; + +import java.io.IOException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Vector; +import java.math.BigInteger; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.CRLReasonExtension; +import netscape.security.x509.InvalidityDateExtension; +import netscape.security.x509.RevocationReason; +import netscape.security.x509.RevokedCertImpl; +import netscape.security.x509.X509CertImpl; + +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.authority.ICertAuthority; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.Nonces; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.logging.AuditFormat; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.publish.IPublisherProcessor; +import com.netscape.certsrv.ra.IRegistrationAuthority; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.RequestId; +import com.netscape.certsrv.request.RequestStatus; +import com.netscape.certsrv.usrgrp.Certificates; +import com.netscape.certsrv.usrgrp.ICertUserLocator; +import com.netscape.certsrv.usrgrp.IUGSubsystem; +import com.netscape.certsrv.usrgrp.IUser; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Revoke a Certificate + * + * @version $Revision$, $Date$ + */ +public class DoRevoke extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = 1693115906265904238L; + private final static String INFO = "DoRevoke"; + private final static String TPL_FILE = "revocationResult.template"; + + private ICertificateRepository mCertDB = null; + private String mFormPath = null; + private IRequestQueue mQueue = null; + private IPublisherProcessor mPublisherProcessor = null; + private Nonces mNonces = null; + private int mTimeLimits = 30; /* in seconds */ + private IUGSubsystem mUG = null; + private ICertUserLocator mUL = null; + + private final static String REVOKE = "revoke"; + private final static String ON_HOLD = "on-hold"; + private final static int ON_HOLD_REASON = 6; + private final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST = + "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_5"; + private final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED = + "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED_7"; + + public DoRevoke() { + super(); + } + + /** + * initialize the servlet. This servlet uses the template + * file "revocationResult.template" to render the result + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + + mUG = (IUGSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_UG); + mUL = mUG.getCertUserLocator(); + + if (mAuthority instanceof ICertificateAuthority) { + mCertDB = ((ICertificateAuthority) mAuthority).getCertificateRepository(); + if (((ICertificateAuthority) mAuthority).noncesEnabled()) { + mNonces = ((ICertificateAuthority) mAuthority).getNonces(); + } + } + if (mAuthority instanceof ICertAuthority) { + mPublisherProcessor = ((ICertAuthority) mAuthority).getPublisherProcessor(); + } + mQueue = mAuthority.getRequestQueue(); + + mTemplates.remove(CMSRequest.SUCCESS); + if (mOutputTemplatePath != null) + mFormPath = mOutputTemplatePath; + + /* Server-Side time limit */ + try { + mTimeLimits = Integer.parseInt(sc.getInitParameter("timeLimits")); + } catch (Exception e) { + /* do nothing, just use the default if integer parsing failed */ + } + } + + /** + * Serves HTTP request. The http parameters used by this request are as follows: + * + *
+     * serialNumber Serial number of certificate to revoke (in HEX)
+     * revocationReason Revocation reason (Described below)
+     * totalRecordCount [number]
+     * verifiedRecordCount [number]
+     * invalidityDate [number of seconds in Jan 1,1970]
+     * 
+     * 
+ * + * revocationReason can be one of these values: + * + *
+     * 0 = Unspecified   (default)
+     * 1 = Key compromised
+     * 2 = CA key compromised
+     * 3 = Affiliation changed
+     * 4 = Certificate superseded
+     * 5 = Cessation of operation
+     * 6 = Certificate is on hold
+     * 
+ */ + public void process(CMSRequest cmsReq) throws EBaseException { + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + + String revokeAll = null; + int totalRecordCount = -1; + int verifiedRecordCount = -1; + EBaseException error = null; + int reason = -1; + boolean authorized = true; + Date invalidityDate = null; + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, req, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", mFormPath, e.toString())); + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock ctx = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, ctx); + + try { + if (req.getParameter("revocationReason") != null) { + reason = Integer.parseInt(req.getParameter( + "revocationReason")); + } + if (req.getParameter("totalRecordCount") != null) { + totalRecordCount = Integer.parseInt(req.getParameter( + "totalRecordCount")); + } + if (req.getParameter("verifiedRecordCount") != null) { + verifiedRecordCount = Integer.parseInt( + req.getParameter( + "verifiedRecordCount")); + } + if (req.getParameter("invalidityDate") != null) { + long l = Long.parseLong(req.getParameter( + "invalidityDate")); + + if (l > 0) { + invalidityDate = new Date(l); + } + } + revokeAll = req.getParameter("revokeAll"); + + if (mNonces != null) { + boolean nonceVerified = false; + boolean skipNonceVerification = false; + + X509Certificate cert2 = getSSLClientCertificate(req); + if (cert2 != null) { + X509Certificate certChain[] = new X509Certificate[1]; + certChain[0] = cert2; + IUser user = null; + try { + user = (IUser) mUL.locateUser(new Certificates(certChain)); + } catch (Exception e) { + CMS.debug("DoRevoke: Failed to map certificate '" + + cert2.getSubjectDN().getName() + "' to user."); + } + if (mUG.isMemberOf(user, "Subsystem Group")) { + skipNonceVerification = true; + } + } + + String nonceStr = req.getParameter("nonce"); + if (nonceStr != null) { + long nonce = Long.parseLong(nonceStr.trim()); + X509Certificate cert1 = mNonces.getCertificate(nonce); + if (cert1 == null) { + CMS.debug("DoRevoke: Unknown nonce"); + } else if (cert1 != null && cert2 != null && cert1.equals(cert2)) { + nonceVerified = true; + mNonces.removeNonce(nonce); + } + } else { + CMS.debug("DoRevoke: Missing nonce"); + } + CMS.debug("DoRevoke: nonceVerified=" + nonceVerified); + CMS.debug("DoRevoke: skipNonceVerification=" + skipNonceVerification); + if ((!nonceVerified) && (!skipNonceVerification)) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + } + + String comments = req.getParameter(IRequest.REQUESTOR_COMMENTS); + String eeSubjectDN = null; + String eeSerialNumber = null; + + //for audit log. + String initiative = null; + + String authMgr = AuditFormat.NOAUTH; + + authToken = authenticate(req); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "revoke"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + if (mAuthMgr != null && mAuthMgr.equals(IAuthSubsystem.CERTUSERDB_AUTHMGR_ID)) { + if (authToken != null) { + + String serialNumber = req.getParameter("serialNumber"); + getSSLClientCertificate(req); // throw exception on error + + if (serialNumber != null) { + eeSerialNumber = serialNumber; + } + + authMgr = authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME); + String agentID = authToken.getInString("userid"); + + initiative = AuditFormat.FROMAGENT + " agentID: " + agentID + + " authenticated by " + authMgr; + } + } else { + // request is fromUser. + initiative = AuditFormat.FROMUSER; + + String serialNumber = req.getParameter("serialNumber"); + X509CertImpl sslCert = (X509CertImpl) getSSLClientCertificate(req); + + if (serialNumber == null || sslCert == null || + !(serialNumber.equals(sslCert.getSerialNumber().toString(16)))) { + authorized = false; + } else { + eeSubjectDN = sslCert.getSubjectDN().toString(); + eeSerialNumber = sslCert.getSerialNumber().toString(); + } + + } + + if (authorized) { + process(argSet, header, reason, invalidityDate, initiative, + req, resp, verifiedRecordCount, revokeAll, + totalRecordCount, eeSerialNumber, eeSubjectDN, + comments, locale[0]); + } + + } catch (NumberFormatException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("BASE_INVALID_NUMBER_FORMAT")); + error = new EBaseException(CMS.getLogMessage("BASE_INVALID_NUMBER_FORMAT")); + } catch (EBaseException e) { + error = e; + } + + /* + catch (Exception e) { + noError = false; + header.addStringValue(OUT_ERROR, + MessageFormatter.getLocalizedString( + errorlocale[0], + BaseResources.class.getName(), + BaseResources.INTERNAL_ERROR_1, + e.toString())); + } + */ + + try { + ServletOutputStream out = resp.getOutputStream(); + + if (error == null && authorized) { + String xmlOutput = req.getParameter("xml"); + if (xmlOutput != null && xmlOutput.equals("true")) { + outputXML(resp, argSet); + } else { + resp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } + } else if (!authorized) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + } else { + cmsReq.setStatus(CMSRequest.ERROR); + cmsReq.setError(error); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_OUT_STREAM_TEMPLATE", e.toString())); + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + } + } + + /** + * Process cert status change request + *

+ * + * (Certificate Request - either an "agent" cert status change request, or an "EE" cert status change request) + *

+ * + * (Certificate Request Processed - either an "agent" cert status change request, or an "EE" cert status change + * request) + *

+ * + *

    + *
  • signed.audit LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST used when a cert status change request (e. g. - + * "revocation") is made (before approval process) + *
  • signed.audit LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED used when a certificate status is + * changed (revoked, expired, on-hold, off-hold) + *
+ * + * @param argSet CMS template parameters + * @param header argument block + * @param reason revocation reason (0 - Unspecified, 1 - Key compromised, + * 2 - CA key compromised; should not be used, 3 - Affiliation changed, + * 4 - Certificate superceded, 5 - Cessation of operation, or + * 6 - Certificate is on hold) + * @param invalidityDate certificate validity date + * @param initiative string containing the audit format + * @param req HTTP servlet request + * @param resp HTTP servlet response + * @param verifiedRecordCount number of verified records + * @param revokeAll string containing information on all of the + * certificates to be revoked + * @param totalRecordCount total number of records (verified and unverified) + * @param eeSerialNumber string containing the end-entity certificate + * serial number + * @param eeSubjectDN string containing the end-entity certificate subject + * distinguished name (DN) + * @param comments string containing certificate comments + * @param locale the system locale + * @exception EBaseException an error has occurred + */ + private void process(CMSTemplateParams argSet, IArgBlock header, + int reason, Date invalidityDate, + String initiative, + HttpServletRequest req, + HttpServletResponse resp, + int verifiedRecordCount, + String revokeAll, + int totalRecordCount, + String eeSerialNumber, + String eeSubjectDN, + String comments, + Locale locale) + throws EBaseException { + boolean auditRequest = true; + String auditMessage = null; + String auditSubjectID = auditSubjectID(); + String auditRequesterID = auditRequesterID(req); + String auditSerialNumber = auditSerialNumber(eeSerialNumber); + String auditRequestType = auditRequestType(reason); + String auditApprovalStatus = ILogger.SIGNED_AUDIT_EMPTY_VALUE; + String auditReasonNum = String.valueOf(reason); + + CMS.debug("DoRevoke: eeSerialNumber: " + eeSerialNumber + " auditSerialNumber: " + auditSerialNumber); + long startTime = CMS.getCurrentDate().getTime(); + + try { + int count = 0; + Vector oldCertsV = new Vector(); + Vector revCertImplsV = new Vector(); + + // Construct a CRL reason code extension. + RevocationReason revReason = RevocationReason.fromInt(reason); + CRLReasonExtension crlReasonExtn = new CRLReasonExtension(revReason); + + // Construct a CRL invalidity date extension. + InvalidityDateExtension invalidityDateExtn = null; + + if (invalidityDate != null) { + invalidityDateExtn = new InvalidityDateExtension(invalidityDate); + } + + // Construct a CRL extension for this request. + CRLExtensions entryExtn = new CRLExtensions(); + + if (crlReasonExtn != null) { + entryExtn.set(crlReasonExtn.getName(), crlReasonExtn); + } + if (invalidityDateExtn != null) { + entryExtn.set(invalidityDateExtn.getName(), invalidityDateExtn); + } + + if (mAuthority instanceof ICertificateAuthority) { + + Enumeration e = mCertDB.searchCertificates(revokeAll, + totalRecordCount, mTimeLimits); + + while (e != null && e.hasMoreElements()) { + ICertRecord rec = e.nextElement(); + + if (rec == null) + continue; + X509CertImpl xcert = rec.getCertificate(); + IArgBlock rarg = CMS.createArgBlock(); + + // we do not want to revoke the CA certificate accidentially + if (xcert != null && isSystemCertificate(xcert.getSerialNumber())) { + CMS.debug("DoRevoke: skipped revocation request for system certificate " + + xcert.getSerialNumber()); + continue; + } + + if (xcert != null) { + rarg.addStringValue("serialNumber", + xcert.getSerialNumber().toString(16)); + + if (eeSerialNumber != null && + (eeSerialNumber.equals(xcert.getSerialNumber().toString())) && + rec.getStatus().equals(ICertRecord.STATUS_REVOKED)) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CA_CERTIFICATE_ALREADY_REVOKED_1", xcert.getSerialNumber() + .toString(16))); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + + throw new ECMSGWException(CMS.getLogMessage("CMSGW_UNAUTHORIZED")); + } else if (rec.getStatus().equals(ICertRecord.STATUS_REVOKED)) { + rarg.addStringValue("error", "Certificate 0x" + + xcert.getSerialNumber().toString(16) + + " is already revoked."); + } else if (eeSubjectDN != null && + (!eeSubjectDN.equals(xcert.getSubjectDN().toString()))) { + rarg.addStringValue("error", "Certificate 0x" + + xcert.getSerialNumber().toString(16) + + " belongs to different subject."); + } else { + oldCertsV.addElement(xcert); + + RevokedCertImpl revCertImpl = + new RevokedCertImpl(xcert.getSerialNumber(), + CMS.getCurrentDate(), entryExtn); + + revCertImplsV.addElement(revCertImpl); + count++; + rarg.addStringValue("error", null); + } + argSet.addRepeatRecord(rarg); + } + } + + } else if (mAuthority instanceof IRegistrationAuthority) { + String reqIdStr = req.getParameter("requestId"); + Vector serialNumbers = new Vector(); + + if (revokeAll != null && revokeAll.length() > 0) { + for (int i = revokeAll.indexOf('='); i < revokeAll.length() && i > -1; + i = revokeAll.indexOf('=', i)) { + if (i > -1) { + i++; + while (i < revokeAll.length() && revokeAll.charAt(i) == ' ') { + i++; + } + // xxxx decimal serial number? + String legalDigits = "0123456789"; + int j = i; + + while (j < revokeAll.length() && legalDigits.indexOf(revokeAll.charAt(j)) != -1) { + j++; + } + if (j > i) { + serialNumbers.addElement(revokeAll.substring(i, j)); + } + } + } + } + if (reqIdStr != null && reqIdStr.length() > 0 && serialNumbers.size() > 0) { + IRequest certReq = mRequestQueue.findRequest(new RequestId(reqIdStr)); + X509CertImpl[] certs = certReq.getExtDataInCertArray(IRequest.OLD_CERTS); + boolean authorized = false; + + for (int i = 0; i < certs.length; i++) { + boolean addToList = false; + + for (int j = 0; j < serialNumbers.size(); j++) { + //xxxxx serial number in decimal? + if (certs[i].getSerialNumber().toString().equals((String) serialNumbers.elementAt(j)) && + eeSubjectDN != null && eeSubjectDN.equals(certs[i].getSubjectDN().toString())) { + addToList = true; + break; + } + } + if (eeSerialNumber != null && + eeSerialNumber.equals(certs[i].getSerialNumber().toString())) { + authorized = true; + } + if (addToList) { + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addStringValue("serialNumber", + certs[i].getSerialNumber().toString(16)); + oldCertsV.addElement(certs[i]); + + RevokedCertImpl revCertImpl = + new RevokedCertImpl(certs[i].getSerialNumber(), + CMS.getCurrentDate(), entryExtn); + + revCertImplsV.addElement(revCertImpl); + count++; + rarg.addStringValue("error", null); + argSet.addRepeatRecord(rarg); + } + } + if (!authorized) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_REQ_AUTH_REVOKED_CERT")); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + + throw new ECMSGWException(CMS.getLogMessage("CMSGW_UNAUTHORIZED")); + } + } else { + String b64eCert = req.getParameter("b64eCertificate"); + + if (b64eCert != null) { + // BASE64Decoder decoder = new BASE64Decoder(); + // byte[] certBytes = decoder.decodeBuffer(b64eCert); + byte[] certBytes = CMS.AtoB(b64eCert); + X509CertImpl cert = new X509CertImpl(certBytes); + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addStringValue("serialNumber", + cert.getSerialNumber().toString(16)); + oldCertsV.addElement(cert); + + RevokedCertImpl revCertImpl = + new RevokedCertImpl(cert.getSerialNumber(), + CMS.getCurrentDate(), entryExtn); + + revCertImplsV.addElement(revCertImpl); + count++; + rarg.addStringValue("error", null); + argSet.addRepeatRecord(rarg); + } + } + } + if (count == 0) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_REV_CERTS_ZERO")); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + + throw new ECMSGWException(CMS.getLogMessage("CMSGW_REVOCATION_ERROR_CERT_NOT_FOUND")); + } + + header.addIntegerValue("totalRecordCount", count); + + X509CertImpl[] oldCerts = new X509CertImpl[count]; + //Certificate[] oldCerts = new Certificate[count]; + RevokedCertImpl[] revCertImpls = new RevokedCertImpl[count]; + + for (int i = 0; i < count; i++) { + oldCerts[i] = (X509CertImpl) oldCertsV.elementAt(i); + revCertImpls[i] = (RevokedCertImpl) revCertImplsV.elementAt(i); + } + + IRequest revReq = + mQueue.newRequest(IRequest.REVOCATION_REQUEST); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + + revReq.setExtData(IRequest.CERT_INFO, revCertImpls); + revReq.setExtData(IRequest.REQ_TYPE, IRequest.REVOCATION_REQUEST); + if (initiative.equals(AuditFormat.FROMUSER)) + revReq.setExtData(IRequest.REQUESTOR_TYPE, IRequest.REQUESTOR_EE); + else + revReq.setExtData(IRequest.REQUESTOR_TYPE, IRequest.REQUESTOR_AGENT); + revReq.setExtData(IRequest.OLD_CERTS, oldCerts); + if (comments != null) { + revReq.setExtData(IRequest.REQUESTOR_COMMENTS, comments); + } + revReq.setExtData(IRequest.REVOKED_REASON, + Integer.valueOf(reason)); + + // change audit processing from "REQUEST" to "REQUEST_PROCESSED" + // to distinguish which type of signed audit log message to save + // as a failure outcome in case an exception occurs + auditRequest = false; + + mQueue.processRequest(revReq); + + // retrieve the request status + auditApprovalStatus = revReq.getRequestStatus().toString(); + + RequestStatus stat = revReq.getRequestStatus(); + String type = revReq.getRequestType(); + + // The SVC_PENDING check has been added for the Cloned CA request + // that is meant for the Master CA. From Clone's point of view + // the request is complete + if ((stat == RequestStatus.COMPLETE) + || ((type.equals(IRequest.CLA_CERT4CRL_REQUEST)) && (stat == RequestStatus.SVC_PENDING))) { + // audit log the error + Integer result = revReq.getExtDataInInteger(IRequest.RESULT); + + if (result.equals(IRequest.RES_ERROR)) { + String[] svcErrors = + revReq.getExtDataInStringArray(IRequest.SVCERRORS); + + if (svcErrors != null && svcErrors.length > 0) { + for (int i = 0; i < svcErrors.length; i++) { + String err = svcErrors[i]; + + if (err != null) { + //cmsReq.setErrorDescription(err); + for (int j = 0; j < count; j++) { + if (oldCerts[j] instanceof X509CertImpl) { + X509CertImpl cert = (X509CertImpl) oldCerts[j]; + + if (oldCerts[j] != null) { + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOREVOKEFORMAT, + new Object[] { + revReq.getRequestId(), + initiative, + "completed with error: " + + err, + cert.getSubjectDN(), + cert.getSerialNumber().toString(16), + RevocationReason.fromInt(reason).toString() } + ); + } + } + } + } + } + } + + // store a message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals( + RequestStatus.COMPLETE_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.REJECTED_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + + return; + } + + long endTime = CMS.getCurrentDate().getTime(); + + // audit log the success. + for (int j = 0; j < count; j++) { + if (oldCerts[j] != null) { + if (oldCerts[j] instanceof X509CertImpl) { + X509CertImpl cert = (X509CertImpl) oldCerts[j]; + + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOREVOKEFORMAT, + new Object[] { + revReq.getRequestId(), + initiative, + "completed", + cert.getSubjectDN(), + cert.getSerialNumber().toString(16), + RevocationReason.fromInt(reason).toString() + + " time: " + (endTime - startTime) } + ); + } + } + } + + header.addStringValue("revoked", "yes"); + + Integer updateCRLResult = + revReq.getExtDataInInteger(IRequest.CRL_UPDATE_STATUS); + + if (updateCRLResult != null) { + header.addStringValue("updateCRL", "yes"); + if (updateCRLResult.equals(IRequest.RES_SUCCESS)) { + header.addStringValue("updateCRLSuccess", "yes"); + } else { + header.addStringValue("updateCRLSuccess", "no"); + String crlError = + revReq.getExtDataInString(IRequest.CRL_UPDATE_ERROR); + + if (crlError != null) + header.addStringValue("updateCRLError", + crlError); + } + // let known crl publishing status too. + Integer publishCRLResult = + revReq.getExtDataInInteger(IRequest.CRL_PUBLISH_STATUS); + + if (publishCRLResult != null) { + if (publishCRLResult.equals(IRequest.RES_SUCCESS)) { + header.addStringValue("publishCRLSuccess", "yes"); + } else { + header.addStringValue("publishCRLSuccess", "no"); + String publError = + revReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR); + + if (publError != null) + header.addStringValue("publishCRLError", + publError); + } + } + } + + if (mAuthority instanceof ICertificateAuthority) { + // let known update and publish status of all crls. + Enumeration otherCRLs = + ((ICertificateAuthority) mAuthority).getCRLIssuingPoints(); + + while (otherCRLs.hasMoreElements()) { + ICRLIssuingPoint crl = (ICRLIssuingPoint) + otherCRLs.nextElement(); + String crlId = crl.getId(); + + if (crlId.equals(ICertificateAuthority.PROP_MASTER_CRL)) + continue; + String updateStatusStr = crl.getCrlUpdateStatusStr(); + Integer updateResult = revReq.getExtDataInInteger(updateStatusStr); + + if (updateResult != null) { + if (updateResult.equals(IRequest.RES_SUCCESS)) { + CMS.debug("DoRevoke: " + + CMS.getLogMessage("ADMIN_SRVLT_ADDING_HEADER", updateStatusStr)); + header.addStringValue(updateStatusStr, "yes"); + } else { + String updateErrorStr = crl.getCrlUpdateErrorStr(); + + CMS.debug("DoRevoke: " + CMS.getLogMessage("ADMIN_SRVLT_ADDING_HEADER_NO", + updateStatusStr)); + header.addStringValue(updateStatusStr, "no"); + String error = + revReq.getExtDataInString(updateErrorStr); + + if (error != null) + header.addStringValue(updateErrorStr, + error); + } + String publishStatusStr = crl.getCrlPublishStatusStr(); + Integer publishResult = + revReq.getExtDataInInteger(publishStatusStr); + + if (publishResult == null) + continue; + if (publishResult.equals(IRequest.RES_SUCCESS)) { + header.addStringValue(publishStatusStr, "yes"); + } else { + String publishErrorStr = + crl.getCrlPublishErrorStr(); + + header.addStringValue(publishStatusStr, "no"); + String error = + revReq.getExtDataInString(publishErrorStr); + + if (error != null) + header.addStringValue( + publishErrorStr, error); + } + } + } + } + + if (mPublisherProcessor != null && mPublisherProcessor.ldapEnabled()) { + header.addStringValue("dirEnabled", "yes"); + Integer[] ldapPublishStatus = + revReq.getExtDataInIntegerArray("ldapPublishStatus"); + int certsToUpdate = 0; + int certsUpdated = 0; + + if (ldapPublishStatus != null) { + certsToUpdate = ldapPublishStatus.length; + for (int i = 0; i < certsToUpdate; i++) { + if (ldapPublishStatus[i] == IRequest.RES_SUCCESS) { + certsUpdated++; + } + } + } + header.addIntegerValue("certsUpdated", certsUpdated); + header.addIntegerValue("certsToUpdate", certsToUpdate); + + // add crl publishing status. + String publError = + revReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR); + + if (publError != null) { + header.addStringValue("crlPublishError", + publError); + } + } else { + header.addStringValue("dirEnabled", "no"); + } + header.addStringValue("error", null); + + } else { + if (stat == RequestStatus.PENDING || stat == RequestStatus.REJECTED) { + header.addStringValue("revoked", stat.toString()); + } else { + header.addStringValue("revoked", "no"); + } + Vector errors = revReq.getExtDataInStringVector(IRequest.ERRORS); + if (errors != null) { + StringBuffer errInfo = new StringBuffer(); + for (int i = 0; i < errors.size(); i++) { + errInfo.append(errors.elementAt(i)); + errInfo.append("\n"); + } + header.addStringValue("error", errInfo.toString()); + + } else if (stat == RequestStatus.PENDING) { + header.addStringValue("error", "Request Pending"); + } else { + header.addStringValue("error", null); + } + + // audit log the pending, revoked and rest + for (int j = 0; j < count; j++) { + if (oldCerts[j] != null) { + if (oldCerts[j] instanceof X509CertImpl) { + X509CertImpl cert = (X509CertImpl) oldCerts[j]; + + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOREVOKEFORMAT, + new Object[] { + revReq.getRequestId(), + initiative, + stat.toString(), + cert.getSubjectDN(), + cert.getSerialNumber().toString(16), + RevocationReason.fromInt(reason).toString() } + ); + } + } + } + } + + // store a message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals(RequestStatus.COMPLETE_STRING)) + || (auditApprovalStatus.equals(RequestStatus.REJECTED_STRING)) + || (auditApprovalStatus.equals(RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + + } catch (CertificateException e) { + if (auditRequest) { + // store a "CERT_STATUS_CHANGE_REQUEST" failure + // message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + } else { + // store a "CERT_STATUS_CHANGE_REQUEST_PROCESSED" failure + // message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals( + RequestStatus.COMPLETE_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.REJECTED_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + } + + log(ILogger.LL_FAILURE, "error " + e); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, "error " + e); + + if (auditRequest) { + // store a "CERT_STATUS_CHANGE_REQUEST" failure + // message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + } else { + // store a "CERT_STATUS_CHANGE_REQUEST_PROCESSED" failure + // message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals( + RequestStatus.COMPLETE_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.REJECTED_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + } + + throw e; + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED_1", e.toString())); + + if (auditRequest) { + // store a "CERT_STATUS_CHANGE_REQUEST" failure + // message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + } else { + // store a "CERT_STATUS_CHANGE_REQUEST_PROCESSED" failure + // message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals( + RequestStatus.COMPLETE_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.REJECTED_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + } + + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED")); + } + + return; + } + + /** + * Signed Audit Log Requester ID + * + * This method is called to obtain the "RequesterID" for + * a signed audit log message. + *

+ * + * @param req HTTP request + * @return id string containing the signed audit log message RequesterID + */ + private String auditRequesterID(HttpServletRequest req) { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String requesterID = null; + + // Obtain the requesterID + requesterID = req.getParameter("requestId"); + + if (requesterID != null) { + requesterID = requesterID.trim(); + } else { + requesterID = ILogger.UNIDENTIFIED; + } + + return requesterID; + } + + /** + * Signed Audit Log Serial Number + * + * This method is called to obtain the serial number of the certificate + * whose status is to be changed for a signed audit log message. + *

+ * + * @param eeSerialNumber a string containing the un-normalized serialNumber + * @return id string containing the signed audit log message RequesterID + */ + private String auditSerialNumber(String eeSerialNumber) { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String serialNumber = null; + + // Normalize the serialNumber + if (eeSerialNumber != null) { + serialNumber = eeSerialNumber.trim(); + + // find out if the value is hex or decimal + + BigInteger value = BigInteger.ONE.negate(); + + //try int + try { + value = new BigInteger(serialNumber, 10); + } catch (NumberFormatException e) { + } + + //try hex + if (value.compareTo(BigInteger.ONE.negate()) == 0) { + try { + value = new BigInteger(serialNumber, 16); + } catch (NumberFormatException e) { + } + } + // give up if it isn't hex or dec + if (value.compareTo(BigInteger.ONE.negate()) == 0) { + throw new NumberFormatException(); + } + + // convert it to hexadecimal + serialNumber = "0x" + value.toString(16); + } else { + serialNumber = ILogger.SIGNED_AUDIT_EMPTY_VALUE; + } + + return serialNumber; + } + + /** + * Signed Audit Log Request Type + * + * This method is called to obtain the "Request Type" for + * a signed audit log message. + *

+ * + * @param reason an integer denoting the revocation reason + * @return string containing REVOKE or ON_HOLD + */ + private String auditRequestType(int reason) { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String requestType = null; + + // Determine the revocation type based upon the revocation reason + if (reason == ON_HOLD_REASON) { + requestType = ON_HOLD; + } else { + requestType = REVOKE; + } + + return requestType; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/DoRevokeTPS.java b/base/common/src/com/netscape/cms/servlet/cert/DoRevokeTPS.java new file mode 100644 index 000000000..c4603dd51 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/DoRevokeTPS.java @@ -0,0 +1,940 @@ +// --- 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.cert; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Date; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Vector; +import java.math.BigInteger; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.CRLReasonExtension; +import netscape.security.x509.InvalidityDateExtension; +import netscape.security.x509.RevocationReason; +import netscape.security.x509.RevokedCertImpl; +import netscape.security.x509.X509CertImpl; + +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.authority.ICertAuthority; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.logging.AuditFormat; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.publish.IPublisherProcessor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.RequestStatus; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Revoke a Certificate + * + * @version $Revision$, $Date$ + */ +public class DoRevokeTPS extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = -2980600514636454836L; + private final static String INFO = "DoRevoke"; + private final static String TPL_FILE = "revocationResult.template"; + + private ICertificateRepository mCertDB = null; + private String mFormPath = null; + private IRequestQueue mQueue = null; + private IPublisherProcessor mPublisherProcessor = null; + private String errorString = "error="; + private String o_status = "status=0"; + private int mTimeLimits = 30; /* in seconds */ + + private final static String REVOKE = "revoke"; + private final static String ON_HOLD = "on-hold"; + private final static int ON_HOLD_REASON = 6; + private final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST = + "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_5"; + private final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED = + "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED_7"; + + public DoRevokeTPS() { + super(); + } + + /** + * initialize the servlet. This servlet uses the template + * file "revocationResult.template" to render the result + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + + if (mAuthority instanceof ICertificateAuthority) { + mCertDB = ((ICertificateAuthority) mAuthority).getCertificateRepository(); + } + if (mAuthority instanceof ICertAuthority) { + mPublisherProcessor = ((ICertAuthority) mAuthority).getPublisherProcessor(); + } + mQueue = mAuthority.getRequestQueue(); + + mTemplates.remove(CMSRequest.SUCCESS); + if (mOutputTemplatePath != null) + mFormPath = mOutputTemplatePath; + mRenderResult = false; + + /* Server-Side time limit */ + try { + mTimeLimits = Integer.parseInt(sc.getInitParameter("timeLimits")); + } catch (Exception e) { + /* do nothing, just use the default if integer parsing failed */ + } + } + + /** + * Serves HTTP request. The http parameters used by this request are as follows: + * + *

+     * serialNumber Serial number of certificate to revoke (in HEX)
+     * revocationReason Revocation reason (Described below)
+     * totalRecordCount [number]
+     * verifiedRecordCount [number]
+     * invalidityDate [number of seconds in Jan 1,1970]
+     * 
+     * 
+ * + * revocationReason can be one of these values: + * + *
+     * 0 = Unspecified   (default)
+     * 1 = Key compromised
+     * 2 = CA key compromised
+     * 3 = Affiliation changed
+     * 4 = Certificate superseded
+     * 5 = Cessation of operation
+     * 6 = Certificate is on hold
+     * 
+ */ + public void process(CMSRequest cmsReq) throws EBaseException { + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + CMS.debug("DoRevokeTPS after authenticate"); + + String revokeAll = null; + int totalRecordCount = -1; + EBaseException error = null; + int reason = -1; + boolean authorized = true; + Date invalidityDate = null; + Locale[] locale = new Locale[1]; + + CMS.debug("DoRevokeTPS before getTemplate"); + try { + @SuppressWarnings("unused") + CMSTemplate form = getTemplate(mFormPath, req, locale); // check for errors + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", mFormPath, e.toString())); + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + } catch (Exception e) { + CMS.debug("DoRevokeTPS getTemplate failed"); + throw new EBaseException(CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + } + + CMS.debug("DoRevokeTPS after getTemplate"); + IArgBlock header = CMS.createArgBlock(); + IArgBlock ctx = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, ctx); + + try { + if (req.getParameter("revocationReason") != null) { + reason = Integer.parseInt(req.getParameter( + "revocationReason")); + } + if (req.getParameter("totalRecordCount") != null) { + totalRecordCount = Integer.parseInt(req.getParameter( + "totalRecordCount")); + } + if (req.getParameter("invalidityDate") != null) { + long l = Long.parseLong(req.getParameter( + "invalidityDate")); + + if (l > 0) { + invalidityDate = new Date(l); + } + } + revokeAll = req.getParameter("revokeAll"); + String comments = req.getParameter(IRequest.REQUESTOR_COMMENTS); + + //for audit log. + String initiative = null; + + String authMgr = AuditFormat.NOAUTH; + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "revoke"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + if (mAuthMgr != null && mAuthMgr.equals(IAuthSubsystem.CERTUSERDB_AUTHMGR_ID)) { + if (authToken != null) { + authMgr = authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME); + String agentID = authToken.getInString("userid"); + + initiative = AuditFormat.FROMAGENT + " agentID: " + agentID + + " authenticated by " + authMgr; + } + } else { + CMS.debug("DoRevokeTPS: Missing authentication manager"); + o_status = "status=1"; + errorString = "errorString=Missing authentication manager."; + } + + if (authorized) { + process(argSet, header, reason, invalidityDate, initiative, req, + resp, revokeAll, totalRecordCount, comments, locale[0]); + } + } catch (NumberFormatException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("BASE_INVALID_NUMBER_FORMAT")); + error = new EBaseException(CMS.getLogMessage("BASE_INVALID_NUMBER_FORMAT")); + } catch (EBaseException e) { + error = e; + } + + try { + if (!authorized) { + o_status = "status=3"; + errorString = "error=unauthorized"; + } else if (error != null) { + o_status = "status=3"; + errorString = "error=" + error.toString(); + } + + String pp = o_status + "\n" + errorString; + byte[] b = pp.getBytes(); + resp.setContentType("text/html"); + resp.setContentLength(b.length); + OutputStream os = resp.getOutputStream(); + os.write(b); + os.flush(); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_OUT_STREAM_TEMPLATE", e.toString())); + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + } + } + + /** + * Process cert status change request + *

+ * + * (Certificate Request - either an "agent" cert status change request, or an "EE" cert status change request) + *

+ * + * (Certificate Request Processed - either an "agent" cert status change request, or an "EE" cert status change + * request) + *

+ * + *

    + *
  • signed.audit LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST used when a cert status change request (e. g. - + * "revocation") is made (before approval process) + *
  • signed.audit LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED used when a certificate status is + * changed (revoked, expired, on-hold, off-hold) + *
+ * + * @param argSet CMS template parameters + * @param header argument block + * @param reason revocation reason (0 - Unspecified, 1 - Key compromised, + * 2 - CA key compromised; should not be used, 3 - Affiliation changed, + * 4 - Certificate superceded, 5 - Cessation of operation, or + * 6 - Certificate is on hold) + * @param invalidityDate certificate validity date + * @param initiative string containing the audit format + * @param req HTTP servlet request + * @param resp HTTP servlet response + * @param revokeAll string containing information on all of the + * certificates to be revoked + * @param totalRecordCount total number of records (verified and unverified) + * @param comments string containing certificate comments + * @param locale the system locale + * @exception EBaseException an error has occurred + */ + private void process(CMSTemplateParams argSet, IArgBlock header, + int reason, Date invalidityDate, + String initiative, + HttpServletRequest req, + HttpServletResponse resp, + String revokeAll, + int totalRecordCount, + String comments, + Locale locale) + throws EBaseException { + boolean auditRequest = true; + String auditMessage = null; + String auditSubjectID = auditSubjectID(); + String auditRequesterID = auditRequesterID(req); + String auditSerialNumber = auditSerialNumber(null); + String auditRequestType = auditRequestType(reason); + String auditApprovalStatus = ILogger.SIGNED_AUDIT_EMPTY_VALUE; + String auditReasonNum = String.valueOf(reason); + + if (revokeAll != null) { + CMS.debug("DoRevokeTPS.process revokeAll" + revokeAll); + + String serial = ""; + String[] tokens; + tokens = revokeAll.split("="); + + if (tokens.length == 2) { + serial = tokens[1]; + //remove the trailing paren + if (serial.endsWith(")")) { + serial = serial.substring(0, serial.length() - 1); + } + auditSerialNumber = serial; + } + } + + long startTime = CMS.getCurrentDate().getTime(); + + try { + int count = 0; + Vector oldCertsV = new Vector(); + Vector revCertImplsV = new Vector(); + + // Construct a CRL reason code extension. + RevocationReason revReason = RevocationReason.fromInt(reason); + CRLReasonExtension crlReasonExtn = new CRLReasonExtension(revReason); + + // Construct a CRL invalidity date extension. + InvalidityDateExtension invalidityDateExtn = null; + + if (invalidityDate != null) { + invalidityDateExtn = new InvalidityDateExtension(invalidityDate); + } + + // Construct a CRL extension for this request. + CRLExtensions entryExtn = new CRLExtensions(); + + if (crlReasonExtn != null) { + entryExtn.set(crlReasonExtn.getName(), crlReasonExtn); + } + if (invalidityDateExtn != null) { + entryExtn.set(invalidityDateExtn.getName(), invalidityDateExtn); + } + + Enumeration e = mCertDB.searchCertificates(revokeAll, + totalRecordCount, mTimeLimits); + + boolean alreadyRevokedCertFound = false; + boolean badCertsRequested = false; + while (e != null && e.hasMoreElements()) { + ICertRecord rec = (ICertRecord) e.nextElement(); + + if (rec == null) { + badCertsRequested = true; + continue; + } + X509CertImpl xcert = rec.getCertificate(); + IArgBlock rarg = CMS.createArgBlock(); + + // we do not want to revoke the CA certificate accidentially + if (xcert != null && isSystemCertificate(xcert.getSerialNumber())) { + CMS.debug("DoRevokeTPS: skipped revocation request for system certificate " + + xcert.getSerialNumber()); + badCertsRequested = true; + continue; + } + + if (xcert != null) { + rarg.addStringValue("serialNumber", + xcert.getSerialNumber().toString(16)); + + if (rec.getStatus().equals(ICertRecord.STATUS_REVOKED)) { + alreadyRevokedCertFound = true; + CMS.debug("Certificate 0x" + xcert.getSerialNumber().toString(16) + " has been revoked."); + } else { + oldCertsV.addElement(xcert); + + RevokedCertImpl revCertImpl = + new RevokedCertImpl(xcert.getSerialNumber(), + CMS.getCurrentDate(), entryExtn); + + revCertImplsV.addElement(revCertImpl); + CMS.debug("Certificate 0x" + xcert.getSerialNumber().toString(16) + " is going to be revoked."); + count++; + } + } else { + badCertsRequested = true; + } + } + + if (count == 0) { + // Situation where no certs were reoked here, but some certs + // requested happened to be already revoked. Don't return error. + if (alreadyRevokedCertFound == true && badCertsRequested == false) { + CMS.debug("Only have previously revoked certs in the list."); + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + return; + } + + errorString = "error=No certificates are revoked."; + o_status = "status=2"; + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_REV_CERTS_ZERO")); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED")); + } + + X509CertImpl[] oldCerts = new X509CertImpl[count]; + RevokedCertImpl[] revCertImpls = new RevokedCertImpl[count]; + + for (int i = 0; i < count; i++) { + oldCerts[i] = (X509CertImpl) oldCertsV.elementAt(i); + revCertImpls[i] = (RevokedCertImpl) revCertImplsV.elementAt(i); + } + + IRequest revReq = + mQueue.newRequest(IRequest.REVOCATION_REQUEST); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + + revReq.setExtData(IRequest.CERT_INFO, revCertImpls); + revReq.setExtData(IRequest.REQ_TYPE, IRequest.REVOCATION_REQUEST); + if (initiative.equals(AuditFormat.FROMUSER)) { + revReq.setExtData(IRequest.REQUESTOR_TYPE, IRequest.REQUESTOR_EE); + } else { + revReq.setExtData(IRequest.REQUESTOR_TYPE, IRequest.REQUESTOR_AGENT); + } + revReq.setExtData(IRequest.OLD_CERTS, oldCerts); + if (comments != null) { + revReq.setExtData(IRequest.REQUESTOR_COMMENTS, comments); + } + revReq.setExtData(IRequest.REVOKED_REASON, + Integer.valueOf(reason)); + + // change audit processing from "REQUEST" to "REQUEST_PROCESSED" + // to distinguish which type of signed audit log message to save + // as a failure outcome in case an exception occurs + auditRequest = false; + + mQueue.processRequest(revReq); + + // retrieve the request status + auditApprovalStatus = revReq.getRequestStatus().toString(); + + RequestStatus stat = revReq.getRequestStatus(); + String type = revReq.getRequestType(); + + // The SVC_PENDING check has been added for the Cloned CA request + // that is meant for the Master CA. From Clone's point of view + // the request is complete + if ((stat == RequestStatus.COMPLETE) + || ((type.equals(IRequest.CLA_CERT4CRL_REQUEST)) && (stat == RequestStatus.SVC_PENDING))) { + // audit log the error + Integer result = revReq.getExtDataInInteger(IRequest.RESULT); + + if (result.equals(IRequest.RES_ERROR)) { + String[] svcErrors = + revReq.getExtDataInStringArray(IRequest.SVCERRORS); + + if (svcErrors != null && svcErrors.length > 0) { + for (int i = 0; i < svcErrors.length; i++) { + String err = svcErrors[i]; + + if (err != null) { + //cmsReq.setErrorDescription(err); + for (int j = 0; j < count; j++) { + if (oldCerts[j] instanceof X509CertImpl) { + X509CertImpl cert = (X509CertImpl) oldCerts[j]; + + if (oldCerts[j] != null) { + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOREVOKEFORMAT, + new Object[] { + revReq.getRequestId(), + initiative, + "completed with error: " + + err, + cert.getSubjectDN(), + cert.getSerialNumber().toString(16), + RevocationReason.fromInt(reason).toString() } + ); + } + } + } + } + } + } + + // store a message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals( + RequestStatus.COMPLETE_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.REJECTED_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + + return; + } + + long endTime = CMS.getCurrentDate().getTime(); + + // audit log the success. + for (int j = 0; j < count; j++) { + if (oldCerts[j] != null) { + if (oldCerts[j] instanceof X509CertImpl) { + X509CertImpl cert = (X509CertImpl) oldCerts[j]; + + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOREVOKEFORMAT, + new Object[] { + revReq.getRequestId(), + initiative, + "completed", + cert.getSubjectDN(), + cert.getSerialNumber().toString(16), + RevocationReason.fromInt(reason).toString() + + " time: " + (endTime - startTime) } + ); + } + } + } + + header.addStringValue("revoked", "yes"); + + Integer updateCRLResult = + revReq.getExtDataInInteger(IRequest.CRL_UPDATE_STATUS); + + if (updateCRLResult != null) { + if (!updateCRLResult.equals(IRequest.RES_SUCCESS)) { + + o_status = "status=3"; + if (revReq.getExtDataInString(IRequest.CRL_UPDATE_ERROR) != null) { + errorString = "error=Update CRL Error."; + // 3 means miscellaneous + } + } + // let known crl publishing status too. + Integer publishCRLResult = + revReq.getExtDataInInteger(IRequest.CRL_PUBLISH_STATUS); + + if (publishCRLResult != null) { + if (!publishCRLResult.equals(IRequest.RES_SUCCESS)) { + String publError = + revReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR); + + o_status = "status=3"; + if (publError != null) { + errorString = "error=" + publError; + } + } + } + } + + if (mAuthority instanceof ICertificateAuthority) { + // let known update and publish status of all crls. + Enumeration otherCRLs = + ((ICertificateAuthority) mAuthority).getCRLIssuingPoints(); + + while (otherCRLs.hasMoreElements()) { + ICRLIssuingPoint crl = (ICRLIssuingPoint) + otherCRLs.nextElement(); + String crlId = crl.getId(); + + if (crlId.equals(ICertificateAuthority.PROP_MASTER_CRL)) + continue; + String updateStatusStr = crl.getCrlUpdateStatusStr(); + Integer updateResult = revReq.getExtDataInInteger(updateStatusStr); + + if (updateResult != null) { + if (!updateResult.equals(IRequest.RES_SUCCESS)) { + String updateErrorStr = crl.getCrlUpdateErrorStr(); + + CMS.debug("DoRevoke: " + CMS.getLogMessage("ADMIN_SRVLT_ADDING_HEADER_NO", + updateStatusStr)); + String error = + revReq.getExtDataInString(updateErrorStr); + + o_status = "status=3"; + if (error != null) { + errorString = "error=" + error; + } + } + String publishStatusStr = crl.getCrlPublishStatusStr(); + Integer publishResult = + revReq.getExtDataInInteger(publishStatusStr); + + if (publishResult == null) + continue; + if (!publishResult.equals(IRequest.RES_SUCCESS)) { + String publishErrorStr = + crl.getCrlPublishErrorStr(); + + String error = + revReq.getExtDataInString(publishErrorStr); + + o_status = "status=3"; + if (error != null) { + errorString = "error=Publish CRL Status Error."; + } + } + } + } + } + + if (mPublisherProcessor != null && mPublisherProcessor.ldapEnabled()) { + header.addStringValue("dirEnabled", "yes"); + + // add crl publishing status. + String publError = + revReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR); + + if (publError != null) { + errorString = "error=" + publError; + o_status = "status=3"; + } + } else if (mPublisherProcessor == null && mPublisherProcessor.ldapEnabled()) { + errorString = "error=LDAP publishing not enabled."; + o_status = "status=3"; + } + } else { + if (stat == RequestStatus.PENDING || stat == RequestStatus.REJECTED) { + o_status = "status=2"; + errorString = "error=" + stat.toString(); + } else { + o_status = "status=2"; + errorString = "error=Undefined request status"; + } + Vector errors = revReq.getExtDataInStringVector(IRequest.ERRORS); + if (errors != null) { + StringBuffer errInfo = new StringBuffer(); + + for (int i = 0; i < errors.size(); i++) { + errInfo.append(errors.elementAt(i)); + errInfo.append("\n"); + } + o_status = "status=2"; + errorString = "error=" + errInfo.toString(); + + } else if (stat == RequestStatus.PENDING) { + o_status = "status=2"; + errorString = "error=Request pending"; + } else { + o_status = "status=2"; + errorString = "error=Undefined request status"; + } + + // audit log the pending, revoked and rest + for (int j = 0; j < count; j++) { + if (oldCerts[j] != null) { + if (oldCerts[j] instanceof X509CertImpl) { + X509CertImpl cert = (X509CertImpl) oldCerts[j]; + + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOREVOKEFORMAT, + new Object[] { + revReq.getRequestId(), + initiative, + stat.toString(), + cert.getSubjectDN(), + cert.getSerialNumber().toString(16), + RevocationReason.fromInt(reason).toString() } + ); + } + } + } + } + + // store a message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals(RequestStatus.COMPLETE_STRING)) + || (auditApprovalStatus.equals(RequestStatus.REJECTED_STRING)) + || (auditApprovalStatus.equals(RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, "error " + e); + + if (auditRequest) { + // store a "CERT_STATUS_CHANGE_REQUEST" failure + // message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + } else { + // store a "CERT_STATUS_CHANGE_REQUEST_PROCESSED" failure + // message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals( + RequestStatus.COMPLETE_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.REJECTED_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + } + + throw e; + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED_1", e.toString())); + + if (auditRequest) { + // store a "CERT_STATUS_CHANGE_REQUEST" failure + // message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + } else { + // store a "CERT_STATUS_CHANGE_REQUEST_PROCESSED" failure + // message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals( + RequestStatus.COMPLETE_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.REJECTED_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + } + + throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED")); + } + + return; + } + + /** + * Signed Audit Log Requester ID + * + * This method is called to obtain the "RequesterID" for + * a signed audit log message. + *

+ * + * @param req HTTP request + * @return id string containing the signed audit log message RequesterID + */ + private String auditRequesterID(HttpServletRequest req) { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String requesterID = null; + + // Obtain the requesterID + requesterID = req.getParameter("requestId"); + + if (requesterID != null) { + requesterID = requesterID.trim(); + } else { + requesterID = ILogger.UNIDENTIFIED; + } + + return requesterID; + } + + /** + * Signed Audit Log Serial Number + * + * This method is called to obtain the serial number of the certificate + * whose status is to be changed for a signed audit log message. + *

+ * + * @param eeSerialNumber a string containing the un-normalized serialNumber + * @return id string containing the signed audit log message RequesterID + */ + private String auditSerialNumber(String eeSerialNumber) { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String serialNumber = null; + + // Normalize the serialNumber + if (eeSerialNumber != null) { + serialNumber = eeSerialNumber.trim(); + + // convert it to hexadecimal + serialNumber = "0x" + (new BigInteger(serialNumber)).toString(16); + } else { + serialNumber = ILogger.SIGNED_AUDIT_EMPTY_VALUE; + } + + return serialNumber; + } + + /** + * Signed Audit Log Request Type + * + * This method is called to obtain the "Request Type" for + * a signed audit log message. + *

+ * + * @param reason an integer denoting the revocation reason + * @return string containing REVOKE or ON_HOLD + */ + private String auditRequestType(int reason) { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String requestType = null; + + // Determine the revocation type based upon the revocation reason + if (reason == ON_HOLD_REASON) { + requestType = ON_HOLD; + } else { + requestType = REVOKE; + } + + return requestType; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/DoUnrevoke.java b/base/common/src/com/netscape/cms/servlet/cert/DoUnrevoke.java new file mode 100644 index 000000000..c6b6065b4 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/DoUnrevoke.java @@ -0,0 +1,671 @@ +// --- 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.cert; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.X509CertImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.AuthToken; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authority.ICertAuthority; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.logging.AuditFormat; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.publish.IPublisherProcessor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.RequestStatus; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * 'Unrevoke' a certificate. (For certificates that are on-hold only, + * take them off-hold) + * + * @version $Revision$, $Date$ + */ +public class DoUnrevoke extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = -7978703730006036625L; + private final static String INFO = "DoUnrevoke"; + private final static String TPL_FILE = "unrevocationResult.template"; + private final static BigInteger MINUS_ONE = new BigInteger("-1"); + + private ICertificateRepository mCertDB = null; + private String mFormPath = null; + private IRequestQueue mQueue = null; + private IPublisherProcessor mPublisherProcessor = null; + + private final static String OFF_HOLD = "off-hold"; + private final static int OFF_HOLD_REASON = 6; + private final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST = + "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_5"; + private final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED = + "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED_7"; + + public DoUnrevoke() { + super(); + } + + /** + * initialize the servlet. + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + if (mAuthority instanceof ICertificateAuthority) { + mCertDB = ((ICertificateAuthority) mAuthority).getCertificateRepository(); + } + if (mAuthority instanceof ICertAuthority) { + mPublisherProcessor = ((ICertAuthority) mAuthority).getPublisherProcessor(); + } + mQueue = mAuthority.getRequestQueue(); + + mTemplates.remove(CMSRequest.SUCCESS); + if (mOutputTemplatePath != null) + mFormPath = mOutputTemplatePath; + } + + /** + * Process the HTTP request. + *

    + *
  • http.param serialNumber Decimal serial number of certificate to unrevoke. The certificate must be revoked + * with a revovcation reason 'on hold' for this operation to succeed. The serial number may be expressed as a hex + * number by prefixing '0x' to the serialNumber string + *
+ * + * @param cmsReq the object holding the request and response information + */ + public void process(CMSRequest cmsReq) throws EBaseException { + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + BigInteger[] serialNumber; + EBaseException error = null; + + CMSTemplate form = null; + + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, req, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock ctx = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, ctx); + + try { + serialNumber = getSerialNumbers(req); + + //for audit log. + IAuthToken authToken = authenticate(cmsReq); + String authMgr = AuditFormat.NOAUTH; + + if (authToken != null) { + authMgr = + authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME); + } else { + CMS.debug("DoUnrevoke::process() - authToken is null!"); + return; + } + String agentID = authToken.getInString("userid"); + String initiative = AuditFormat.FROMAGENT + " agentID: " + agentID + + " authenticated by " + authMgr; + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "unrevoke"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + process(argSet, header, serialNumber, req, resp, locale[0], initiative); + + } catch (NumberFormatException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_INVALID_SERIAL_NUM_FORMAT")); + error = new EBaseException(CMS.getUserMessage(getLocale(req), "CMS_BASE_INVALID_NUMBER_FORMAT")); + } catch (EBaseException e) { + error = e; + } + + try { + ServletOutputStream out = resp.getOutputStream(); + + if (error == null) { + String xmlOutput = req.getParameter("xml"); + if (xmlOutput != null && xmlOutput.equals("true")) { + outputXML(resp, argSet); + } else { + resp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } + } else { + cmsReq.setStatus(CMSRequest.ERROR); + cmsReq.setError(error); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_ERR_STREAM_TEMPLATE", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + } + + /** + * Process X509 cert status change request + *

+ * + * (Certificate Request - an "agent" cert status change request to take a certificate off-hold) + *

+ * + * (Certificate Request Processed - an "agent" cert status change request to take a certificate off-hold) + *

+ * + *

    + *
  • signed.audit LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST used when a cert status change request (e. g. - + * "revocation") is made (before approval process) + *
  • signed.audit LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED used when a certificate status is + * changed (taken off-hold) + *
+ * + * @param argSet CMS template parameters + * @param header argument block + * @param serialNumbers the serial number of the certificate + * @param req HTTP servlet request + * @param resp HTTP servlet response + * @param locale the system locale + * @param initiative string containing the audit format + * @exception EBaseException an error has occurred + */ + private void process(CMSTemplateParams argSet, IArgBlock header, + BigInteger[] serialNumbers, + HttpServletRequest req, + HttpServletResponse resp, + Locale locale, String initiative) + throws EBaseException { + boolean auditRequest = true; + String auditMessage = null; + String auditSubjectID = auditSubjectID(); + String auditRequesterID = auditRequesterID(req); + String auditSerialNumber = auditSerialNumber(serialNumbers[0].toString()); + String auditRequestType = OFF_HOLD; + String auditApprovalStatus = ILogger.SIGNED_AUDIT_EMPTY_VALUE; + String auditReasonNum = String.valueOf(OFF_HOLD_REASON); + + try { + StringBuffer snList = new StringBuffer(); + + // certs are for old cloning and they should be removed as soon as possible + X509CertImpl[] certs = new X509CertImpl[serialNumbers.length]; + for (int i = 0; i < serialNumbers.length; i++) { + certs[i] = (X509CertImpl) getX509Certificate(serialNumbers[i]); + if (snList.length() > 0) + snList.append(", "); + snList.append("0x"); + snList.append(serialNumbers[i].toString(16)); + } + header.addStringValue("serialNumber", snList.toString()); + + IRequest unrevReq = mQueue.newRequest(IRequest.UNREVOCATION_REQUEST); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + + unrevReq.setExtData(IRequest.REQ_TYPE, IRequest.UNREVOCATION_REQUEST); + unrevReq.setExtData(IRequest.OLD_SERIALS, serialNumbers); + unrevReq.setExtData(IRequest.REQUESTOR_TYPE, IRequest.REQUESTOR_AGENT); + + // change audit processing from "REQUEST" to "REQUEST_PROCESSED" + // to distinguish which type of signed audit log message to save + // as a failure outcome in case an exception occurs + auditRequest = false; + + mQueue.processRequest(unrevReq); + + // retrieve the request status + auditApprovalStatus = unrevReq.getRequestStatus().toString(); + + RequestStatus status = unrevReq.getRequestStatus(); + String type = unrevReq.getRequestType(); + + if ((status == RequestStatus.COMPLETE) + || ((type.equals(IRequest.CLA_UNCERT4CRL_REQUEST)) && (status == RequestStatus.SVC_PENDING))) { + + Integer result = unrevReq.getExtDataInInteger(IRequest.RESULT); + + if (result != null && result.equals(IRequest.RES_SUCCESS)) { + header.addStringValue("unrevoked", "yes"); + if (certs[0] != null) { + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOUNREVOKEFORMAT, + new Object[] { + unrevReq.getRequestId(), + initiative, + "completed", + certs[0].getSubjectDN(), + "0x" + serialNumbers[0].toString(16) } + ); + } + } else { + header.addStringValue("unrevoked", "no"); + String error = unrevReq.getExtDataInString(IRequest.ERROR); + + if (error != null) { + header.addStringValue("error", error); + if (certs[0] != null) { + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOUNREVOKEFORMAT, + new Object[] { + unrevReq.getRequestId(), + initiative, + "completed with error: " + + error, + certs[0].getSubjectDN(), + "0x" + serialNumbers[0].toString(16) } + ); + } + + /****************************************************/ + + /* IMPORTANT: In the event that the following */ + + /* "throw error;" statement is */ + + /* uncommented, uncomment the following */ + + /* signed audit log message, also!!! */ + + /****************************************************/ + + // // store a message in the signed audit log file + // // if and only if "auditApprovalStatus" is + // // "complete", "revoked", or "canceled" + // if( ( auditApprovalStatus.equals( + // RequestStatus.COMPLETE_STRING ) ) || + // ( auditApprovalStatus.equals( + // RequestStatus.REJECTED_STRING ) ) || + // ( auditApprovalStatus.equals( + // RequestStatus.CANCELED_STRING ) ) ) { + // auditMessage = CMS.getLogMessage( + // LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + // auditSubjectID, + // ILogger.FAILURE, + // auditRequesterID, + // auditSerialNumber, + // auditRequestType, + // auditReasonNum, + // auditApprovalStatus ); + // + // audit( auditMessage ); + // } + + // throw error; + } + } + + Integer updateCRLResult = + unrevReq.getExtDataInInteger(IRequest.CRL_UPDATE_STATUS); + + if (updateCRLResult != null) { + header.addStringValue("updateCRL", "yes"); + if (updateCRLResult.equals(IRequest.RES_SUCCESS)) { + header.addStringValue("updateCRLSuccess", "yes"); + } else { + header.addStringValue("updateCRLSuccess", "no"); + String crlError = + unrevReq.getExtDataInString(IRequest.CRL_UPDATE_ERROR); + + if (crlError != null) + header.addStringValue("updateCRLError", + crlError); + } + // let known crl publishing status too. + Integer publishCRLResult = + unrevReq.getExtDataInInteger(IRequest.CRL_PUBLISH_STATUS); + + if (publishCRLResult != null) { + if (publishCRLResult.equals(IRequest.RES_SUCCESS)) { + header.addStringValue("publishCRLSuccess", "yes"); + } else { + header.addStringValue("publishCRLSuccess", "no"); + String publError = + unrevReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR); + + if (publError != null) + header.addStringValue("publishCRLError", + publError); + } + } + } + + // let known update and publish status of all crls. + Enumeration otherCRLs = + ((ICertificateAuthority) mAuthority).getCRLIssuingPoints(); + + while (otherCRLs.hasMoreElements()) { + ICRLIssuingPoint crl = otherCRLs.nextElement(); + String crlId = crl.getId(); + + if (crlId.equals(ICertificateAuthority.PROP_MASTER_CRL)) + continue; + String updateStatusStr = crl.getCrlUpdateStatusStr(); + Integer updateResult = unrevReq.getExtDataInInteger(updateStatusStr); + + if (updateResult != null) { + if (updateResult.equals(IRequest.RES_SUCCESS)) { + CMS.debug("DoUnrevoke: adding header " + + updateStatusStr + " yes "); + header.addStringValue(updateStatusStr, "yes"); + } else { + String updateErrorStr = crl.getCrlUpdateErrorStr(); + + CMS.debug("DoUnrevoke: adding header " + + updateStatusStr + " no "); + header.addStringValue(updateStatusStr, "no"); + String error = + unrevReq.getExtDataInString(updateErrorStr); + + if (error != null) + header.addStringValue( + updateErrorStr, error); + } + String publishStatusStr = crl.getCrlPublishStatusStr(); + Integer publishResult = + unrevReq.getExtDataInInteger(publishStatusStr); + + if (publishResult == null) + continue; + if (publishResult.equals(IRequest.RES_SUCCESS)) { + header.addStringValue(publishStatusStr, "yes"); + } else { + String publishErrorStr = + crl.getCrlPublishErrorStr(); + + header.addStringValue(publishStatusStr, "no"); + String error = + unrevReq.getExtDataInString(publishErrorStr); + + if (error != null) + header.addStringValue( + publishErrorStr, error); + } + } + } + + if (mPublisherProcessor != null && mPublisherProcessor.ldapEnabled()) { + header.addStringValue("dirEnabled", "yes"); + Integer[] ldapPublishStatus = + unrevReq.getExtDataInIntegerArray("ldapPublishStatus"); + + if (ldapPublishStatus != null) { + if (ldapPublishStatus[0] == IRequest.RES_SUCCESS) { + header.addStringValue("dirUpdated", "yes"); + } else { + header.addStringValue("dirUpdated", "no"); + } + } + } else { + header.addStringValue("dirEnabled", "no"); + } + + } else if (status == RequestStatus.PENDING) { + header.addStringValue("error", "Request Pending"); + header.addStringValue("unrevoked", "pending"); + if (certs[0] != null) { + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOUNREVOKEFORMAT, + new Object[] { + unrevReq.getRequestId(), + initiative, + "pending", + certs[0].getSubjectDN(), + "0x" + serialNumbers[0].toString(16) } + ); + } + } else { + header.addStringValue("error", "Request Status.Error"); + header.addStringValue("unrevoked", "no"); + if (certs[0] != null) { + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOUNREVOKEFORMAT, + new Object[] { + unrevReq.getRequestId(), + initiative, + status.toString(), + certs[0].getSubjectDN(), + "0x" + serialNumbers[0].toString(16) } + ); + } + } + + // store a message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals(RequestStatus.COMPLETE_STRING)) + || (auditApprovalStatus.equals(RequestStatus.REJECTED_STRING)) + || (auditApprovalStatus.equals(RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + + } catch (EBaseException eAudit1) { + if (auditRequest) { + // store a "CERT_STATUS_CHANGE_REQUEST" failure + // message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + } else { + // store a "CERT_STATUS_CHANGE_REQUEST_PROCESSED" failure + // message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals( + RequestStatus.COMPLETE_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.REJECTED_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + } + } + + return; + } + + private BigInteger[] getSerialNumbers(HttpServletRequest req) + throws NumberFormatException { + String serialNumString = req.getParameter("serialNumber"); + + StringTokenizer snList = new StringTokenizer(serialNumString, " "); + Vector biList = new Vector(); + while (snList.hasMoreTokens()) { + String snStr = snList.nextToken(); + if (snStr != null) { + snStr = snStr.trim(); + BigInteger bi; + if (snStr.startsWith("0x") || snStr.startsWith("0X")) { + bi = new BigInteger(snStr.substring(2), 16); + } else { + bi = new BigInteger(snStr); + } + if (bi.compareTo(BigInteger.ZERO) < 0) { + throw new NumberFormatException(); + } + biList.addElement(bi); + } else { + throw new NumberFormatException(); + } + } + if (biList.size() < 1) { + throw new NumberFormatException(); + } + + BigInteger[] biNumbers = new BigInteger[biList.size()]; + for (int i = 0; i < biList.size(); i++) { + biNumbers[i] = (BigInteger) biList.elementAt(i); + } + + return biNumbers; + } + + /** + * Signed Audit Log Requester ID + * + * This method is called to obtain the "RequesterID" for + * a signed audit log message. + *

+ * + * @param req HTTP request + * @return id string containing the signed audit log message RequesterID + */ + private String auditRequesterID(HttpServletRequest req) { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String requesterID = null; + + // Obtain the requesterID + requesterID = req.getParameter("requestId"); + + if (requesterID != null) { + requesterID = requesterID.trim(); + } else { + requesterID = ILogger.UNIDENTIFIED; + } + + return requesterID; + } + + /** + * Signed Audit Log Serial Number + * + * This method is called to obtain the serial number of the certificate + * whose status is to be changed for a signed audit log message. + *

+ * + * @param eeSerialNumber a string containing the un-normalized serialNumber + * @return id string containing the signed audit log message RequesterID + */ + private String auditSerialNumber(String eeSerialNumber) { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String serialNumber = null; + + // Normalize the serialNumber + if (eeSerialNumber != null) { + serialNumber = eeSerialNumber.trim(); + + // convert it to hexadecimal + serialNumber = "0x" + (new BigInteger(serialNumber)).toString(16); + } else { + serialNumber = ILogger.SIGNED_AUDIT_EMPTY_VALUE; + } + + return serialNumber; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/DoUnrevokeTPS.java b/base/common/src/com/netscape/cms/servlet/cert/DoUnrevokeTPS.java new file mode 100644 index 000000000..5d096aff3 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/DoUnrevokeTPS.java @@ -0,0 +1,618 @@ +// --- 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.cert; + +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.X509CertImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.AuthToken; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authority.ICertAuthority; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.logging.AuditFormat; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.publish.IPublisherProcessor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.RequestStatus; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * 'Unrevoke' a certificate. (For certificates that are on-hold only, + * take them off-hold) + * + * @version $Revision$, $Date$ + */ +public class DoUnrevokeTPS extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = -6245049221697655642L; + private final static String INFO = "DoUnrevoke"; + private final static String TPL_FILE = "unrevocationResult.template"; + private final static BigInteger MINUS_ONE = new BigInteger("-1"); + + private ICertificateRepository mCertDB = null; + private String mFormPath = null; + private IRequestQueue mQueue = null; + private IPublisherProcessor mPublisherProcessor = null; + private String errorString = "error="; + private String o_status = "status=0"; + + private final static String OFF_HOLD = "off-hold"; + private final static int OFF_HOLD_REASON = 6; + private final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST = + "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_5"; + private final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED = + "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED_7"; + + public DoUnrevokeTPS() { + super(); + } + + /** + * initialize the servlet. + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + if (mAuthority instanceof ICertificateAuthority) { + mCertDB = ((ICertificateAuthority) mAuthority).getCertificateRepository(); + } + if (mAuthority instanceof ICertAuthority) { + mPublisherProcessor = ((ICertAuthority) mAuthority).getPublisherProcessor(); + } + mQueue = mAuthority.getRequestQueue(); + + mTemplates.remove(CMSRequest.SUCCESS); + mRenderResult = false; + } + + /** + * Process the HTTP request. + *

    + *
  • http.param serialNumber Decimal serial number of certificate to unrevoke. The certificate must be revoked + * with a revovcation reason 'on hold' for this operation to succeed. The serial number may be expressed as a hex + * number by prefixing '0x' to the serialNumber string + *
+ * + * @param cmsReq the object holding the request and response information + */ + public void process(CMSRequest cmsReq) throws EBaseException { + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + BigInteger[] serialNumbers; + EBaseException error = null; + + Locale[] locale = new Locale[1]; + + /* + try { + form = getTemplate(mFormPath, req, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + */ + + try { + serialNumbers = getSerialNumbers(req); + + //for audit log. + IAuthToken authToken = authenticate(cmsReq); + String authMgr = AuditFormat.NOAUTH; + + if (authToken != null) { + authMgr = + authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME); + } else { + CMS.debug("DoUnrevokeTPS::process() - authToken is null!"); + return; + } + String agentID = authToken.getInString("userid"); + String initiative = AuditFormat.FROMAGENT + " agentID: " + agentID + + " authenticated by " + authMgr; + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "unrevoke"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + o_status = "status=3"; + errorString = "error=unauthorized"; + String pp = o_status + "\n" + errorString; + byte[] b = pp.getBytes(); + resp.setContentType("text/html"); + resp.setContentLength(b.length); + OutputStream os = resp.getOutputStream(); + os.write(b); + os.flush(); + return; + } + + process(serialNumbers, req, resp, locale[0], initiative); + } catch (NumberFormatException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_INVALID_SERIAL_NUM_FORMAT")); + error = new EBaseException(CMS.getUserMessage(getLocale(req), "CMS_BASE_INVALID_NUMBER_FORMAT")); + } catch (EBaseException e) { + error = e; + } catch (IOException e) { + } + + try { + if (error == null) { + o_status = "status=0"; + errorString = "error="; + } else { + o_status = "status=3"; + errorString = "error=" + error.toString(); + } + + String pp = o_status + "\n" + errorString; + byte[] b = pp.getBytes(); + resp.setContentType("text/html"); + resp.setContentLength(b.length); + OutputStream os = resp.getOutputStream(); + os.write(b); + os.flush(); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_ERR_STREAM_TEMPLATE", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + } + + /** + * Process X509 cert status change request + *

+ * + * (Certificate Request - an "agent" cert status change request to take a certificate off-hold) + *

+ * + * (Certificate Request Processed - an "agent" cert status change request to take a certificate off-hold) + *

+ * + *

    + *
  • signed.audit LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST used when a cert status change request (e. g. - + * "revocation") is made (before approval process) + *
  • signed.audit LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED used when a certificate status is + * changed (taken off-hold) + *
+ * + * @param serialNumbers the serial number of the certificate + * @param req HTTP servlet request + * @param resp HTTP servlet response + * @param locale the system locale + * @param initiative string containing the audit format + * @exception EBaseException an error has occurred + */ + private void process(BigInteger[] serialNumbers, + HttpServletRequest req, + HttpServletResponse resp, + Locale locale, String initiative) + throws EBaseException { + boolean auditRequest = true; + String auditMessage = null; + String auditSubjectID = auditSubjectID(); + String auditRequesterID = auditRequesterID(req); + String auditSerialNumber = auditSerialNumber(serialNumbers[0].toString()); + String auditRequestType = OFF_HOLD; + String auditApprovalStatus = ILogger.SIGNED_AUDIT_EMPTY_VALUE; + String auditReasonNum = String.valueOf(OFF_HOLD_REASON); + + try { + String snList = ""; + + // certs are for old cloning and they should be removed as soon as possible + X509CertImpl[] certs = new X509CertImpl[serialNumbers.length]; + for (int i = 0; i < serialNumbers.length; i++) { + certs[i] = (X509CertImpl) getX509Certificate(serialNumbers[i]); + if (snList.length() > 0) + snList += ", "; + snList += "0x" + serialNumbers[i].toString(16); + } + + IRequest unrevReq = mQueue.newRequest(IRequest.UNREVOCATION_REQUEST); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + + unrevReq.setExtData(IRequest.REQ_TYPE, IRequest.UNREVOCATION_REQUEST); + unrevReq.setExtData(IRequest.OLD_SERIALS, serialNumbers); + unrevReq.setExtData(IRequest.REQUESTOR_TYPE, IRequest.REQUESTOR_AGENT); + + // change audit processing from "REQUEST" to "REQUEST_PROCESSED" + // to distinguish which type of signed audit log message to save + // as a failure outcome in case an exception occurs + auditRequest = false; + + mQueue.processRequest(unrevReq); + + // retrieve the request status + auditApprovalStatus = unrevReq.getRequestStatus().toString(); + + RequestStatus status = unrevReq.getRequestStatus(); + String type = unrevReq.getRequestType(); + + if ((status == RequestStatus.COMPLETE) + || ((type.equals(IRequest.CLA_UNCERT4CRL_REQUEST)) && (status == RequestStatus.SVC_PENDING))) { + + Integer result = unrevReq.getExtDataInInteger(IRequest.RESULT); + + if (result != null && result.equals(IRequest.RES_SUCCESS)) { + if (certs[0] != null) { + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOUNREVOKEFORMAT, + new Object[] { + unrevReq.getRequestId(), + initiative, + "completed", + certs[0].getSubjectDN(), + "0x" + serialNumbers[0].toString(16) } + ); + } + } else { + String error = unrevReq.getExtDataInString(IRequest.ERROR); + + if (error != null) { + o_status = "status=3"; + errorString = "error=" + error; + if (certs[0] != null) { + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOUNREVOKEFORMAT, + new Object[] { + unrevReq.getRequestId(), + initiative, + "completed with error: " + + error, + certs[0].getSubjectDN(), + "0x" + serialNumbers[0].toString(16) } + ); + } + } + } + + Integer updateCRLResult = + unrevReq.getExtDataInInteger(IRequest.CRL_UPDATE_STATUS); + + if (updateCRLResult != null) { + if (!updateCRLResult.equals(IRequest.RES_SUCCESS)) { + String crlError = + unrevReq.getExtDataInString(IRequest.CRL_UPDATE_ERROR); + + if (crlError != null) { + o_status = "status=3"; + errorString = "error=" + crlError; + } + } + // let known crl publishing status too. + Integer publishCRLResult = + unrevReq.getExtDataInInteger(IRequest.CRL_PUBLISH_STATUS); + + if (publishCRLResult != null) { + if (!publishCRLResult.equals(IRequest.RES_SUCCESS)) { + String publError = + unrevReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR); + + if (publError != null) { + o_status = "status=3"; + errorString = "error=" + publError; + } + } + } + } + + // let known update and publish status of all crls. + Enumeration otherCRLs = + ((ICertificateAuthority) mAuthority).getCRLIssuingPoints(); + + while (otherCRLs.hasMoreElements()) { + ICRLIssuingPoint crl = otherCRLs.nextElement(); + String crlId = crl.getId(); + + if (crlId.equals(ICertificateAuthority.PROP_MASTER_CRL)) + continue; + String updateStatusStr = crl.getCrlUpdateStatusStr(); + Integer updateResult = unrevReq.getExtDataInInteger(updateStatusStr); + + if (updateResult != null) { + if (!updateResult.equals(IRequest.RES_SUCCESS)) { + String updateErrorStr = crl.getCrlUpdateErrorStr(); + String error = + unrevReq.getExtDataInString(updateErrorStr); + + if (error != null) { + o_status = "status=3"; + errorString = "error=" + error; + } + } + String publishStatusStr = crl.getCrlPublishStatusStr(); + Integer publishResult = + unrevReq.getExtDataInInteger(publishStatusStr); + + if (publishResult == null) + continue; + if (!publishResult.equals(IRequest.RES_SUCCESS)) { + String publishErrorStr = + crl.getCrlPublishErrorStr(); + + String error = + unrevReq.getExtDataInString(publishErrorStr); + + if (error != null) { + o_status = "status=3"; + errorString = "error=" + error; + } + } + } + } + + if (mPublisherProcessor != null && mPublisherProcessor.ldapEnabled()) { + Integer[] ldapPublishStatus = + unrevReq.getExtDataInIntegerArray("ldapPublishStatus"); + + if (ldapPublishStatus != null) { + if (ldapPublishStatus[0] != IRequest.RES_SUCCESS) { + o_status = "status=3"; + errorString = "error=Problem in publishing to LDAP"; + } + } + } else if (mPublisherProcessor == null || (!mPublisherProcessor.ldapEnabled())) { + o_status = "status=3"; + errorString = "error=LDAP Publisher not enabled"; + } + + } else if (status == RequestStatus.PENDING) { + o_status = "status=2"; + errorString = "error=" + status.toString(); + if (certs[0] != null) { + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOUNREVOKEFORMAT, + new Object[] { + unrevReq.getRequestId(), + initiative, + "pending", + certs[0].getSubjectDN(), + "0x" + serialNumbers[0].toString(16) } + ); + } + } else { + o_status = "status=2"; + errorString = "error=Undefined request status"; + + if (certs[0] != null) { + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.DOUNREVOKEFORMAT, + new Object[] { + unrevReq.getRequestId(), + initiative, + status.toString(), + certs[0].getSubjectDN(), + "0x" + serialNumbers[0].toString(16) } + ); + } + } + + // store a message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals(RequestStatus.COMPLETE_STRING)) + || (auditApprovalStatus.equals(RequestStatus.REJECTED_STRING)) + || (auditApprovalStatus.equals(RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + + } catch (EBaseException eAudit1) { + if (auditRequest) { + // store a "CERT_STATUS_CHANGE_REQUEST" failure + // message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType); + + audit(auditMessage); + } else { + // store a "CERT_STATUS_CHANGE_REQUEST_PROCESSED" failure + // message in the signed audit log file + // if and only if "auditApprovalStatus" is + // "complete", "revoked", or "canceled" + if ((auditApprovalStatus.equals( + RequestStatus.COMPLETE_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.REJECTED_STRING)) || + (auditApprovalStatus.equals( + RequestStatus.CANCELED_STRING))) { + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditSerialNumber, + auditRequestType, + auditReasonNum, + auditApprovalStatus); + + audit(auditMessage); + } + } + } + + return; + } + + private BigInteger[] getSerialNumbers(HttpServletRequest req) + throws NumberFormatException { + String serialNumString = req.getParameter("serialNumber"); + + StringTokenizer snList = new StringTokenizer(serialNumString, " "); + Vector biList = new Vector(); + while (snList.hasMoreTokens()) { + String snStr = snList.nextToken(); + if (snStr != null) { + snStr = snStr.trim(); + BigInteger bi; + if (snStr.startsWith("0x") || snStr.startsWith("0X")) { + bi = new BigInteger(snStr.substring(2), 16); + } else { + bi = new BigInteger(snStr); + } + if (bi.compareTo(BigInteger.ZERO) < 0) { + throw new NumberFormatException(); + } + biList.addElement(bi); + } else { + throw new NumberFormatException(); + } + } + if (biList.size() < 1) { + throw new NumberFormatException(); + } + + BigInteger[] biNumbers = new BigInteger[biList.size()]; + for (int i = 0; i < biList.size(); i++) { + biNumbers[i] = (BigInteger) biList.elementAt(i); + } + + return biNumbers; + } + + /** + * Signed Audit Log Requester ID + * + * This method is called to obtain the "RequesterID" for + * a signed audit log message. + *

+ * + * @param req HTTP request + * @return id string containing the signed audit log message RequesterID + */ + private String auditRequesterID(HttpServletRequest req) { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String requesterID = null; + + // Obtain the requesterID + requesterID = req.getParameter("requestId"); + + if (requesterID != null) { + requesterID = requesterID.trim(); + } else { + requesterID = ILogger.UNIDENTIFIED; + } + + return requesterID; + } + + /** + * Signed Audit Log Serial Number + * + * This method is called to obtain the serial number of the certificate + * whose status is to be changed for a signed audit log message. + *

+ * + * @param eeSerialNumber a string containing the un-normalized serialNumber + * @return id string containing the signed audit log message RequesterID + */ + private String auditSerialNumber(String eeSerialNumber) { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String serialNumber = null; + + // Normalize the serialNumber + if (eeSerialNumber != null) { + serialNumber = eeSerialNumber.trim(); + + // convert it to hexadecimal + serialNumber = "0x" + (new BigInteger(serialNumber)).toString(16); + } else { + serialNumber = ILogger.SIGNED_AUDIT_EMPTY_VALUE; + } + + return serialNumber; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/EnableEnrollResult.java b/base/common/src/com/netscape/cms/servlet/cert/EnableEnrollResult.java new file mode 100644 index 000000000..2a143b668 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/EnableEnrollResult.java @@ -0,0 +1,184 @@ +// --- 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.cert; + +import java.io.IOException; +import java.security.cert.X509Certificate; +import java.util.Locale; +import java.util.Random; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthManager; +import com.netscape.certsrv.authentication.IAuthSubsystem; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.ra.IRegistrationAuthority; +import com.netscape.cms.authentication.HashAuthentication; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * For Face-to-face enrollment, enable EE enrollment feature + * + * @version $Revision$, $Date$ + * @see com.netscape.cms.servlet.cert.DisableEnrollResult + */ +public class EnableEnrollResult extends CMSServlet { + /** + * + */ + private static final long serialVersionUID = -2646998784859783012L; + private final static String TPL_FILE = "enableEnrollResult.template"; + private String mFormPath = null; + private Random random = null; + + public EnableEnrollResult() { + super(); + } + + /** + * Initializes the servlet. + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + // override success to display own output. + + // coming from agent + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + + mTemplates.remove(CMSRequest.SUCCESS); + random = new Random(); + } + + protected CMSRequest newCMSRequest() { + return new CMSRequest(); + } + + /** + * Services the request + */ + protected void process(CMSRequest cmsReq) + throws EBaseException { + HttpServletRequest httpReq = cmsReq.getHttpReq(); + HttpServletResponse httpResp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "enable"); + } catch (Exception e) { + // do nothing for now + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + X509Certificate sslClientCert = null; + + sslClientCert = getSSLClientCertificate(httpReq); + String dn = (String) sslClientCert.getSubjectDN().toString(); + + // Construct an ArgBlock + IArgBlock args = cmsReq.getHttpParams(); + + if (!(mAuthority instanceof IRegistrationAuthority)) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_CA_FROM_RA_NOT_IMP")); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_NOT_YET_IMPLEMENTED"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, httpReq, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", mFormPath, e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + IConfigStore configStore = CMS.getConfigStore(); + String machine = configStore.getString("machineName"); + String port = CMS.getEESSLPort(); + + header.addStringValue("machineName", machine); + header.addStringValue("port", port); + String val = configStore.getString("hashDirEnrollment.name"); + IAuthSubsystem authSS = (IAuthSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_AUTH); + IAuthManager authMgr = authSS.get(val); + HashAuthentication mgr = (HashAuthentication) authMgr; + + String host = args.getValueAsString("hostname", null); + boolean isEnable = mgr.isEnable(host); + + if (isEnable) { + header.addStringValue("code", "1"); + } else { + String timeout = args.getValueAsString("timeout", "600"); + + mgr.createEntry(host, dn, Long.parseLong(timeout) * 1000, + random.nextLong() + "", 0); + header.addStringValue("code", "0"); + } + + try { + ServletOutputStream out = httpResp.getOutputStream(); + + httpResp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_STREAM_TEMPLATE", e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + } + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } + +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/EnrollServlet.java b/base/common/src/com/netscape/cms/servlet/cert/EnrollServlet.java new file mode 100644 index 000000000..a73a8146c --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/EnrollServlet.java @@ -0,0 +1,1768 @@ +// --- 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.cert; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.Enumeration; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.pkcs.PKCS10; +import netscape.security.x509.AlgorithmId; +import netscape.security.x509.CertificateAlgorithmId; +import netscape.security.x509.CertificateX509Key; +import netscape.security.x509.X509CertImpl; +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.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.KeyGenInfo; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertRecordList; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.logging.AuditFormat; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.IPolicyProcessor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.RequestStatus; +import com.netscape.certsrv.usrgrp.IGroup; +import com.netscape.certsrv.usrgrp.IUGSubsystem; +import com.netscape.certsrv.usrgrp.IUser; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSGateway; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.ECMSGWException; +import com.netscape.cms.servlet.common.ICMSTemplateFiller; +import com.netscape.cms.servlet.processors.CMCProcessor; +import com.netscape.cms.servlet.processors.CRMFProcessor; +import com.netscape.cms.servlet.processors.KeyGenProcessor; +import com.netscape.cms.servlet.processors.PKCS10Processor; +import com.netscape.cms.servlet.processors.PKIProcessor; +import com.netscape.cmsutil.util.Utils; + +/** + * Submit a Certificate Enrollment request + * + * @version $Revision$, $Date$ + */ +public class EnrollServlet extends CMSServlet { + /** + * + */ + private static final long serialVersionUID = -6983729702665630013L; + + public final static String ADMIN_ENROLL_SERVLET_ID = "caadminEnroll"; + + // enrollment templates. + public static final String ENROLL_SUCCESS_TEMPLATE = "EnrollSuccess.template"; + + // http params + public static final String OLD_CERT_TYPE = "csrCertType"; + public static final String CERT_TYPE = "certType"; + // same as in ConfigConstant.java + public static final String REQUEST_FORMAT = "reqFormat"; + public static final String REQUEST_FORMAT_PKCS10 = "PKCS10"; + public static final String REQUEST_FORMAT_CMC = "CMC"; + public static final String REQUEST_CONTENT = "requestContent"; + public static final String SUBJECT_KEYGEN_INFO = "subjectKeyGenInfo"; + public static final String PKCS10_REQUEST = "pkcs10Request"; + public static final String CMC_REQUEST = "cmcRequest"; + public static final String CRMF_REQUEST = "CRMFRequest"; + public static final String SUBJECT_NAME = "subject"; + public static final String CRMF_REQID = "crmfReqId"; + public static final String CHALLENGE_PASSWORD = "challengePhrase"; + + private static final String CERT_AUTH_DUAL = "dual"; + private static final String CERT_AUTH_ENCRYPTION = "encryption"; + private static final String CERT_AUTH_SINGLE = "single"; + private static final String CLIENT_ISSUER = "clientIssuer"; + + private boolean mAuthTokenOverride = true; + private String mEnrollSuccessTemplate = null; + private ICMSTemplateFiller mEnrollSuccessFiller = new ImportCertsTemplateFiller(); + + ICertificateAuthority mCa = null; + ICertificateRepository mRepository = null; + + private boolean enforcePop = false; + + private String auditServiceID = ILogger.UNIDENTIFIED; + private final static String ADMIN_CA_ENROLLMENT_SERVLET = + "caadminEnroll"; + private final static String AGENT_CA_BULK_ENROLLMENT_SERVLET = + "cabulkissuance"; + private final static String AGENT_RA_BULK_ENROLLMENT_SERVLET = + "rabulkissuance"; + private final static String EE_CA_CERT_BASED_ENROLLMENT_SERVLET = + "cacertbasedenrollment"; + private final static String EE_CA_ENROLLMENT_SERVLET = + "caenrollment"; + private final static String EE_RA_CERT_BASED_ENROLLMENT_SERVLET = + "racertbasedenrollment"; + private final static String EE_RA_ENROLLMENT_SERVLET = + "raenrollment"; + private final static byte EOL[] = { Character.LINE_SEPARATOR }; + private final static String[] SIGNED_AUDIT_AUTOMATED_REJECTION_REASON = new String[] { + + /* 0 */"automated non-profile cert request rejection: " + + "unable to render OLD_CERT_TYPE response", + + /* 1 */"automated non-profile cert request rejection: " + + "unable to complete handleEnrollAuditLog() method", + + /* 2 */"automated non-profile cert request rejection: " + + "unable to render success template", + + /* 3 */"automated non-profile cert request rejection: " + + "indeterminate reason for inability to process " + + "cert request due to an EBaseException" + }; + private final static String LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST = + "LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST_5"; + private final static String LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED = + "LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED_5"; + + private static final String HEADER = "-----BEGIN NEW CERTIFICATE REQUEST-----"; + private static final String TRAILER = "-----END NEW CERTIFICATE REQUEST-----"; + + public EnrollServlet() { + super(); + } + + /** + * initialize the servlet. + *

+ * the following parameters are read from the servlet config: + *

    + *
  • CMSServlet.PROP_ID - ID for signed audit log messages + *
  • CMSServlet.PROP_SUCCESS_TEMPLATE - success template file + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + try { + super.init(sc); + + CMS.debug("EnrollServlet: In Enroll Servlet init!"); + + try { + IConfigStore configStore = CMS.getConfigStore(); + String PKI_Subsystem = configStore.getString("subsystem.0.id", + null); + + // CMS 6.1 began utilizing the "Certificate Profiles" framework + // instead of the legacy "Certificate Policies" framework. + // + // Beginning with CS 8.1, to meet the Common Criteria + // evaluation performed on this version of the product, it + // was determined that this legacy "Certificate Policies" + // framework would be deprecated and disabled by default + // (see Bugzilla Bug #472597). + // + // NOTE: The "Certificate Policies" framework ONLY applied to + // to CA, KRA, and legacy RA (pre-CMS 7.0) subsystems. + // + // Further, the "EnrollServlet.java" servlet is ONLY + // used by the CA for the following: + // + // SERVLET-NAME URL-PATTERN + // ==================================================== + // caadminEnroll ca/admin/ca/adminEnroll.html + // cabulkissuance ca/agent/ca/bulkissuance.html + // cacertbasedenrollment ca/certbasedenrollment.html + // caenrollment ca/enrollment.html + // + // The "EnrollServlet.java" servlet is NOT used by + // the KRA. + // + if (PKI_Subsystem.trim().equalsIgnoreCase("ca")) { + String policyStatus = PKI_Subsystem.trim().toLowerCase() + + "." + "Policy" + + "." + IPolicyProcessor.PROP_ENABLE; + + if (configStore.getBoolean(policyStatus, true) == true) { + // NOTE: If ".Policy.enable=" + // is missing, then the referenced instance + // existed prior to this name=value pair + // existing in its 'CS.cfg' file, and thus + // we err on the side that the user may + // still need to use the policy framework. + CMS.debug("EnrollServlet::init Certificate " + + "Policy Framework (deprecated) " + + "is ENABLED"); + } else { + // CS 8.1 Default: .Policy.enable=false + CMS.debug("EnrollServlet::init Certificate " + + "Policy Framework (deprecated) " + + "is DISABLED"); + return; + } + } + } catch (EBaseException e) { + throw new ServletException("EnrollServlet::init - " + + "EBaseException: " + + "Unable to initialize " + + "Certificate Policy Framework " + + "(deprecated)"); + } + + // override success template to allow direct import of keygen certs. + mTemplates.remove(CMSRequest.SUCCESS); + + try { + // determine the service ID for signed audit log messages + String id = sc.getInitParameter(CMSServlet.PROP_ID); + + if (id != null) { + if (!(auditServiceID.equals( + ADMIN_CA_ENROLLMENT_SERVLET)) + && !(auditServiceID.equals( + AGENT_CA_BULK_ENROLLMENT_SERVLET)) + && !(auditServiceID.equals( + AGENT_RA_BULK_ENROLLMENT_SERVLET)) + && !(auditServiceID.equals( + EE_CA_CERT_BASED_ENROLLMENT_SERVLET)) + && !(auditServiceID.equals( + EE_CA_ENROLLMENT_SERVLET)) + && !(auditServiceID.equals( + EE_RA_CERT_BASED_ENROLLMENT_SERVLET)) + && !(auditServiceID.equals( + EE_RA_ENROLLMENT_SERVLET))) { + auditServiceID = ILogger.UNIDENTIFIED; + } else { + auditServiceID = id.trim(); + } + } + + mEnrollSuccessTemplate = sc.getInitParameter( + CMSServlet.PROP_SUCCESS_TEMPLATE); + if (mEnrollSuccessTemplate == null) + mEnrollSuccessTemplate = ENROLL_SUCCESS_TEMPLATE; + String fillername = sc.getInitParameter( + PROP_SUCCESS_TEMPLATE_FILLER); + + if (fillername != null) { + ICMSTemplateFiller filler = newFillerObject(fillername); + + if (filler != null) + mEnrollSuccessFiller = filler; + } + + // cfu + mCa = (ICertificateAuthority) CMS.getSubsystem("ca"); + + init_testbed_hack(mConfig); + } catch (Exception e) { + // this should never happen. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_IMP_INIT_SERV_ERR", + e.toString(), mId)); + } + } catch (ServletException eAudit1) { + // rethrow caught exception + throw eAudit1; + } + } + + /** + * XXX (SHOULD CHANGE TO READ FROM Servletconfig) + * Getter method to see if Proof of Posession checking is enabled. + * this value is set in the CMS.cfg filem with the parameter + * "enrollment.enforcePop". It defaults to false + * + * @return true if user is required to Prove that they possess the + * private key corresponding to the public key in the certificate + * request they are submitting + */ + public boolean getEnforcePop() { + return enforcePop; + } + + /** + * Process the HTTP request. + *
      + *
    • If the request is coming through the admin port, it is only allowed to continue if 'admin enrollment' is + * enabled in the CMS.cfg file + *
    • If the CMS.cfg parameter useThreadNaming is true, the current thread is renamed with more information about + * the current request ID + *
    • The request is preprocessed, then processed further in one of the cert request processor classes: + * KeyGenProcessor, PKCS10Processor, CMCProcessor, CRMFProcessor + *
    + * + * @param cmsReq the object holding the request and response information + */ + protected void process(CMSRequest cmsReq) + throws EBaseException { + // SPECIAL CASE: + // if it is adminEnroll servlet,check if it's enabled + if (mId.equals(ADMIN_ENROLL_SERVLET_ID) && + !CMSGateway.getEnableAdminEnroll()) { + log(ILogger.LL_SECURITY, + CMS.getLogMessage("ADMIN_SRVLT_ENROLL_ACCESS_AFTER_SETUP")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_REDIRECTING_ADMINENROLL_ERROR", + "Attempt to access adminEnroll after already setup.")); + } + + processX509(cmsReq); + } + + private boolean getCertAuthEnrollStatus(IArgBlock httpParams) { + + /* + * === certAuth based enroll === + * "certAuthEnroll" is on. + * "certauthEnrollType can be one of the three: + * single - it's for single cert enrollment + * dual - it's for dual certs enrollment + * encryption - getting the encryption cert only via + * authentication of the signing cert + * (crmf or keyGenInfo) + */ + boolean certAuthEnroll = false; + + String certAuthEnrollOn = + httpParams.getValueAsString("certauthEnroll", null); + + if ((certAuthEnrollOn != null) && (certAuthEnrollOn.equals("on"))) { + certAuthEnroll = true; + CMS.debug("EnrollServlet: certAuthEnroll is on"); + } + + return certAuthEnroll; + + } + + private String getCertAuthEnrollType(IArgBlock httpParams, boolean certAuthEnroll) + throws EBaseException { + + String certauthEnrollType = null; + + if (certAuthEnroll == true) { + certauthEnrollType = + httpParams.getValueAsString("certauthEnrollType", null); + if (certauthEnrollType != null) { + if (certauthEnrollType.equals("dual")) { + CMS.debug("EnrollServlet: certauthEnrollType is dual"); + } else if (certauthEnrollType.equals("encryption")) { + CMS.debug("EnrollServlet: certauthEnrollType is encryption"); + } else if (certauthEnrollType.equals("single")) { + CMS.debug("EnrollServlet: certauthEnrollType is single"); + } else { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_INVALID_CERTAUTH_ENROLL_TYPE_1", certauthEnrollType)); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_INVALID_CERTAUTH_ENROLL_TYPE")); + } + } else { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("MSGW_MISSING_CERTAUTH_ENROLL_TYPE")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_MISSING_CERTAUTH_ENROLL_TYPE")); + } + } + + return certauthEnrollType; + + } + + private boolean checkClientCertSigningOnly(X509Certificate sslClientCert) + throws EBaseException { + if ((CMS.isSigningCert((X509CertImpl) sslClientCert) == + false) || + ((CMS.isSigningCert((X509CertImpl) sslClientCert) == + true) && + (CMS.isEncryptionCert((X509CertImpl) sslClientCert) == + true))) { + + // either it's not a signing cert, or it's a dual cert + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_INVALID_CERT_TYPE")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_INVALID_CERT_TYPE")); + } + + return true; + } + + private X509CertInfo[] handleCertAuthDual(X509CertInfo certInfo, IAuthToken authToken, + X509Certificate sslClientCert, + ICertificateAuthority mCa, String certBasedOldSubjectDN, + BigInteger certBasedOldSerialNum) + throws EBaseException { + + CMS.debug("EnrollServlet: In handleCertAuthDual!"); + + if (mCa == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_NOT_A_CA")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_NOT_A_CA")); + } + + // first, make sure the client cert is indeed a + // signing only cert + + try { + + checkClientCertSigningOnly(sslClientCert); + } catch (ECMSGWException e) { + + throw new ECMSGWException(e.toString()); + + } + + X509Key key = null; + + // for signing cert + key = (X509Key) sslClientCert.getPublicKey(); + try { + certInfo.set(X509CertInfo.KEY, new CertificateX509Key(key)); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAILED_SET_KEY_FROM_CERT_AUTH_ENROLL_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_KEY_FROM_CERT_AUTH_ENROLL_FAILED", e.toString())); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAILED_SET_KEY_FROM_CERT_AUTH_ENROLL_IO", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_KEY_FROM_CERT_AUTH_ENROLL_FAILED", e.toString())); + } + + String filter = + "(&(x509cert.subject=" + + certBasedOldSubjectDN + ")(!(x509cert.serialNumber=" + certBasedOldSerialNum + + "))(certStatus=VALID))"; + ICertRecordList list = + (ICertRecordList) mCa.getCertificateRepository().findCertRecordsInList(filter, null, 10); + int size = list.getSize(); + Enumeration en = list.getCertRecords(0, size - 1); + + CMS.debug("EnrollServlet: signing cert filter " + filter); + + if (!en.hasMoreElements()) { + CMS.debug("EnrollServlet: pairing encryption cert not found!"); + return null; + // pairing encryption cert not found + } else { + X509CertInfo encCertInfo = CMS.getDefaultX509CertInfo(); + X509CertInfo[] cInfoArray = new X509CertInfo[] { certInfo, + encCertInfo }; + int i = 1; + + boolean encCertFound = false; + + while (en.hasMoreElements()) { + ICertRecord record = en.nextElement(); + X509CertImpl cert = record.getCertificate(); + + // if not encryption cert only, try next one + if ((CMS.isEncryptionCert(cert) == false) || + ((CMS.isEncryptionCert(cert) == true) && + (CMS.isSigningCert(cert) == true))) { + + CMS.debug("EnrollServlet: Not encryption only cert, will try next one."); + continue; + } + + key = (X509Key) cert.getPublicKey(); + CMS.debug("EnrollServlet: Found key for encryption cert."); + encCertFound = true; + + try { + encCertInfo = (X509CertInfo) + cert.get( + X509CertImpl.NAME + "." + X509CertImpl.INFO); + + } catch (CertificateParsingException ex) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_CERTINFO_ENCRYPT_CERT")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_MISSING_CERTINFO")); + } + + try { + encCertInfo.set(X509CertInfo.KEY, new CertificateX509Key(key)); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAILED_SET_KEY_FROM_CERT_AUTH_ENROLL_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_KEY_FROM_CERT_AUTH_ENROLL_FAILED", e.toString())); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAILED_SET_KEY_FROM_CERT_AUTH_ENROLL_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_KEY_FROM_CERT_AUTH_ENROLL_FAILED", e.toString())); + } + + CMS.debug("EnrollServlet: About to fillCertInfoFromAuthToken!"); + PKIProcessor.fillCertInfoFromAuthToken(encCertInfo, authToken); + + cInfoArray[i++] = encCertInfo; + break; + + } + if (encCertFound == false) { + CMS.debug("EnrollServlet: Leaving because Enc Cert not found."); + return null; + } + + CMS.debug("EnrollServlet: returning cInfoArray of length " + cInfoArray.length); + return cInfoArray; + } + + } + + private boolean handleEnrollAuditLog(IRequest req, CMSRequest cmsReq, String authMgr, IAuthToken authToken, + X509CertInfo certInfo, long startTime) + throws EBaseException { + //for audit log + + String initiative = null; + String agentID = null; + + if (authToken == null) { + // request is from eegateway, so fromUser. + initiative = AuditFormat.FROMUSER; + } else { + agentID = authToken.getInString("userid"); + initiative = AuditFormat.FROMAGENT + " agentID: " + agentID; + } + + // if service not complete return standard templates. + RequestStatus status = req.getRequestStatus(); + + if (status != RequestStatus.COMPLETE) { + cmsReq.setIRequestStatus(); // set status acc. to IRequest status. + // audit log the status + try { + if (status == RequestStatus.REJECTED) { + Vector messages = req.getExtDataInStringVector(IRequest.ERRORS); + + if (messages != null) { + Enumeration msgs = messages.elements(); + StringBuffer wholeMsg = new StringBuffer(); + + while (msgs.hasMoreElements()) { + wholeMsg.append("\n"); + wholeMsg.append(msgs.nextElement()); + } + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.ENROLLMENTFORMAT, + new Object[] { + req.getRequestId(), + initiative, + authMgr, + status.toString(), + certInfo.get(X509CertInfo.SUBJECT), + " violation: " + + wholeMsg.toString() } + ); + } else { // no policy violation, from agent + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.ENROLLMENTFORMAT, + new Object[] { + req.getRequestId(), + initiative, + authMgr, + status.toString(), + certInfo.get(X509CertInfo.SUBJECT), "" } + ); + } + } else { // other imcomplete status + long endTime = CMS.getCurrentDate().getTime(); + + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.ENROLLMENTFORMAT, + new Object[] { + req.getRequestId(), + initiative, + authMgr, + status.toString(), + certInfo.get(X509CertInfo.SUBJECT) + " time: " + (endTime - startTime), "" } + ); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CANT_GET_CERT_SUBJ_AUDITING", + e.toString())); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CANT_GET_CERT_SUBJ_AUDITING", + e.toString())); + } + return false; + } + // if service error use standard error templates. + Integer result = req.getExtDataInInteger(IRequest.RESULT); + + if (result.equals(IRequest.RES_ERROR)) { + + cmsReq.setStatus(CMSRequest.ERROR); + cmsReq.setError(req.getExtDataInString(IRequest.ERROR)); + String[] svcErrors = + req.getExtDataInStringArray(IRequest.SVCERRORS); + + if (svcErrors != null && svcErrors.length > 0) { + for (int i = 0; i < svcErrors.length; i++) { + String err = svcErrors[i]; + + if (err != null) { + //System.out.println( + //"revocation servlet: setting error description "+ + //err.toString()); + cmsReq.setErrorDescription(err); + // audit log the error + try { + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.ENROLLMENTFORMAT, + new Object[] { + req.getRequestId(), + initiative, + authMgr, + "completed with error: " + + err, + certInfo.get(X509CertInfo.SUBJECT), "" + } + ); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CANT_GET_CERT_SUBJ_AUDITING", + e.toString())); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CANT_GET_CERT_SUBJ_AUDITING", + e.toString())); + } + + } + } + } + return false; + + } + + return true; + + } + + /** + * Process X509 certificate enrollment request + *

    + * + * (Certificate Request - either an "admin" cert request for an admin certificate, an "agent" cert request for + * "bulk enrollment", or an "EE" standard cert request) + *

    + * + * (Certificate Request Processed - either an automated "admin" non-profile based CA admin cert acceptance, an + * automated "admin" non-profile based CA admin cert rejection, an automated "EE" non-profile based cert acceptance, + * or an automated "EE" non-profile based cert rejection) + *

    + * + *

      + *
    • signed.audit LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST used when a non-profile cert request is made + * (before approval process) + *
    • signed.audit LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED used when a certificate request has just been + * through the approval process + *
    + * + * @param cmsReq a certificate enrollment request + * @exception EBaseException an error has occurred + */ + protected void processX509(CMSRequest cmsReq) + throws EBaseException { + String auditMessage = null; + String auditSubjectID = auditSubjectID(); + String auditRequesterID = ILogger.UNIDENTIFIED; + String auditCertificateSubjectName = ILogger.SIGNED_AUDIT_EMPTY_VALUE; + String id = null; + + // define variables common to try-catch-blocks + long startTime = 0; + IArgBlock httpParams = null; + HttpServletRequest httpReq = null; + IAuthToken authToken = null; + AuthzToken authzToken = null; + IRequest req = null; + X509CertInfo certInfo = null; + + IConfigStore configStore = CMS.getConfigStore(); + + /* XXX shouldn't we read this from ServletConfig at init time? */ + enforcePop = configStore.getBoolean("enrollment.enforcePop", false); + CMS.debug("EnrollServlet: enforcePop " + enforcePop); + + // ensure that any low-level exceptions are reported + // to the signed audit log and stored as failures + try { + startTime = CMS.getCurrentDate().getTime(); + httpParams = cmsReq.getHttpParams(); + httpReq = cmsReq.getHttpReq(); + if (mAuthMgr != null) { + authToken = authenticate(cmsReq); + } + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "submit"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + + // store a message in the signed audit log file + // (either an "admin" cert request for an admin certificate, + // an "agent" cert request for "bulk enrollment", or + // an "EE" standard cert request) + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditServiceID, + auditCertificateSubjectName); + + audit(auditMessage); + + return; + } + + // create enrollment request in request queue. + req = mRequestQueue.newRequest(IRequest.ENROLLMENT_REQUEST); + + // retrieve the actual "auditRequesterID" + if (req != null) { + // overwrite "auditRequesterID" if and only if "id" != null + id = req.getRequestId().toString(); + if (id != null) { + auditRequesterID = id.trim(); + } + } + + try { + if (CMS.getConfigStore().getBoolean("useThreadNaming", false)) { + String currentName = Thread.currentThread().getName(); + + Thread.currentThread().setName(currentName + + "-request-" + + req.getRequestId().toString() + + "-" + + (new Date()).getTime()); + } + } catch (Exception e) { + } + + /* + * === certAuth based enroll === + * "certAuthEnroll" is on. + * "certauthEnrollType can be one of the three: + * single - it's for single cert enrollment + * dual - it's for dual certs enrollment + * encryption - getting the encryption cert only via + * authentication of the signing cert + * (crmf or keyGenInfo) + */ + boolean certAuthEnroll = false; + String certauthEnrollType = null; + + certAuthEnroll = getCertAuthEnrollStatus(httpParams); + + try { + if (certAuthEnroll == true) { + certauthEnrollType = getCertAuthEnrollType(httpParams, + certAuthEnroll); + } + } catch (ECMSGWException e) { + // store a message in the signed audit log file + // (either an "admin" cert request for an admin certificate, + // an "agent" cert request for "bulk enrollment", or + // an "EE" standard cert request) + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditServiceID, + auditCertificateSubjectName); + + audit(auditMessage); + + throw new ECMSGWException(e.toString()); + } + + CMS.debug("EnrollServlet: In EnrollServlet.processX509!"); + CMS.debug("EnrollServlet: certAuthEnroll " + certAuthEnroll); + CMS.debug("EnrollServlet: certauthEnrollType " + certauthEnrollType); + + String challengePassword = httpParams.getValueAsString( + "challengePassword", ""); + + cmsReq.setIRequest(req); + saveHttpHeaders(httpReq, req); + saveHttpParams(httpParams, req); + + X509Certificate sslClientCert = null; + + // cert auth enroll + String certBasedOldSubjectDN = null; + BigInteger certBasedOldSerialNum = null; + + // check if request was authenticated, if so set authtoken & + // certInfo. also if authenticated, take certInfo from authToken. + certInfo = null; + if (certAuthEnroll == true) { + sslClientCert = getSSLClientCertificate(httpReq); + if (sslClientCert == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_SSL_CLIENT_CERT")); + + // store a message in the signed audit log file + // (either an "admin" cert request for an admin certificate, + // an "agent" cert request for "bulk enrollment", or + // an "EE" standard cert request) + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditServiceID, + auditCertificateSubjectName); + + audit(auditMessage); + + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_MISSING_SSL_CLIENT_CERT")); + } + + certBasedOldSubjectDN = (String) + sslClientCert.getSubjectDN().toString(); + certBasedOldSerialNum = (BigInteger) + sslClientCert.getSerialNumber(); + + CMS.debug("EnrollServlet: certBasedOldSubjectDN " + certBasedOldSubjectDN); + CMS.debug("EnrollServlet: certBasedOldSerialNum " + certBasedOldSerialNum); + + // if the cert subject name is NOT MISSING, retrieve the + // actual "auditCertificateSubjectName" and "normalize" it + if (certBasedOldSubjectDN != null) { + // NOTE: This is ok even if the cert subject name + // is "" (empty)! + auditCertificateSubjectName = certBasedOldSubjectDN.trim(); + } + + try { + certInfo = (X509CertInfo) + ((X509CertImpl) sslClientCert).get( + X509CertImpl.NAME + "." + X509CertImpl.INFO); + } catch (CertificateParsingException ex) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_CERTINFO")); + + // store a message in the signed audit log file + // (either an "admin" cert request for an admin certificate, + // an "agent" cert request for "bulk enrollment", or + // an "EE" standard cert request) + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditServiceID, + auditCertificateSubjectName); + + audit(auditMessage); + + throw new ECMSGWException( + CMS.getUserMessage(getLocale(httpReq), "CMS_GW_MISSING_CERTINFO")); + } + } else { + CMS.debug("EnrollServlet: No CertAuthEnroll."); + certInfo = CMS.getDefaultX509CertInfo(); + } + + X509CertInfo[] certInfoArray = new X509CertInfo[] { certInfo }; + + String authMgr = AuditFormat.NOAUTH; + + // if authentication + if (authToken != null) { + authMgr = + authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME); + // don't store agent token in request. + // agent currently used for bulk issuance. + // if (!authMgr.equals(AuthSubsystem.CERTUSERDB_AUTHMGR_ID)) { + log(ILogger.LL_INFO, + "Enrollment request was authenticated by " + + authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME)); + + PKIProcessor.fillCertInfoFromAuthToken(certInfo, + authToken); + // save authtoken attrs to request directly + // (for policy use) + saveAuthToken(authToken, req); + // req.set(IRequest.AUTH_TOKEN, authToken); + // } + } + + CMS.debug("EnrollServlet: Enroll authMgr " + authMgr); + + if (certAuthEnroll == true) { + // log(ILogger.LL_DEBUG, + // "just gotten subjectDN and serialNumber " + + // "from ssl client cert"); + if (authToken == null) { + // authToken is null, can't match to anyone; bail! + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_PROCESS_ENROLL_NO_AUTH")); + + // store a message in the signed audit log file + // (either an "admin" cert request for an admin certificate, + // an "agent" cert request for "bulk enrollment", or + // an "EE" standard cert request) + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditServiceID, + auditCertificateSubjectName); + + audit(auditMessage); + + return; + } + } + + // fill certInfo from input types: keygen, cmc, pkcs10 or crmf + KeyGenInfo keyGenInfo = httpParams.getValueAsKeyGenInfo( + SUBJECT_KEYGEN_INFO, null); + PKCS10 pkcs10 = null; + + // support Enterprise 3.5.1 server where CERT_TYPE=csrCertType + // instead of certType + String certType = httpParams.getValueAsString(OLD_CERT_TYPE, null); + CMS.debug("EnrollServlet: certType " + certType); + + if (certType == null) { + certType = httpParams.getValueAsString(CERT_TYPE, "client"); + CMS.debug("EnrollServlet: certType " + certType); + } 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 here. + req.setExtData(IRequest.HTTP_PARAMS, CERT_TYPE, certType); + } + if (certType.equals("client")) { + // coming from MSIE + String p10b64 = httpParams.getValueAsString(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(PKCS10_REQUEST, + false, null); + // e.printStackTrace(); + } + } + + //pkcs10 = httpParams.getValuePKCS10(PKCS10_REQUEST, null); + + } else { + try { + // coming from server cut & paste blob. + pkcs10 = httpParams.getValueAsPKCS10(PKCS10_REQUEST, + false, null); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + String cmc = null; + String asciiBASE64Blob = httpParams.getValueAsString(CMC_REQUEST, null); + + if (asciiBASE64Blob != null) { + int startIndex = asciiBASE64Blob.indexOf(HEADER); + int endIndex = asciiBASE64Blob.indexOf(TRAILER); + if (startIndex != -1 && endIndex != -1) { + startIndex = startIndex + HEADER.length(); + cmc = asciiBASE64Blob.substring(startIndex, endIndex); + } else + cmc = asciiBASE64Blob; + CMS.debug("EnrollServlet: cmc " + cmc); + } + + String crmf = httpParams.getValueAsString(CRMF_REQUEST, null); + + CMS.debug("EnrollServlet: crmf " + crmf); + + if (certAuthEnroll == true) { + + PKIProcessor.fillCertInfoFromAuthToken(certInfo, authToken); + + // for dual certs + if (certauthEnrollType.equals(CERT_AUTH_DUAL)) { + + CMS.debug("EnrollServlet: Attempting CERT_AUTH_DUAL"); + boolean gotEncCert = false; + X509CertInfo[] cInfoArray = null; + + try { + cInfoArray = handleCertAuthDual(certInfo, authToken, + sslClientCert, mCa, + certBasedOldSubjectDN, + certBasedOldSerialNum); + } catch (ECMSGWException e) { + // store a message in the signed audit log file + // (either an "admin" cert request for an admin + // certificate, an "agent" cert request for + // "bulk enrollment", or an "EE" standard cert request) + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditServiceID, + auditCertificateSubjectName); + + audit(auditMessage); + + throw new ECMSGWException(e.toString()); + } + + if (cInfoArray != null && cInfoArray.length != 0) { + CMS.debug("EnrollServlet: cInfoArray Length " + cInfoArray.length); + + certInfoArray = cInfoArray; + gotEncCert = true; + } + + if (gotEncCert == false) { + // encryption cert not found, bail + log(ILogger.LL_FAILURE, + CMS.getLogMessage( + "CMSGW_ENCRYPTION_CERT_NOT_FOUND")); + + // store a message in the signed audit log file + // (either an "admin" cert request for an admin + // certificate, an "agent" cert request for + // "bulk enrollment", or an "EE" standard cert request) + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditServiceID, + auditCertificateSubjectName); + + audit(auditMessage); + + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_ENCRYPTION_CERT_NOT_FOUND")); + } + + } else if (certauthEnrollType.equals(CERT_AUTH_ENCRYPTION)) { + + // first, make sure the client cert is indeed a + // signing only cert + + try { + + checkClientCertSigningOnly(sslClientCert); + } catch (ECMSGWException e) { + // store a message in the signed audit log file + // (either an "admin" cert request for an admin + // certificate, an "agent" cert request for + // "bulk enrollment", or an "EE" standard cert request) + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditServiceID, + auditCertificateSubjectName); + + audit(auditMessage); + + throw new ECMSGWException(e.toString()); + } + + /* + * either crmf or keyGenInfo + */ + if (keyGenInfo != null) { + KeyGenProcessor keyGenProc = new KeyGenProcessor(cmsReq, + this); + + keyGenProc.fillCertInfo(null, certInfo, + authToken, httpParams); + + req.setExtData(CLIENT_ISSUER, + sslClientCert.getIssuerDN().toString()); + CMS.debug("EnrollServlet: sslClientCert issuerDN = " + + sslClientCert.getIssuerDN().toString()); + } else if (crmf != null && crmf != "") { + CRMFProcessor crmfProc = new CRMFProcessor(cmsReq, this, enforcePop); + + certInfoArray = crmfProc.fillCertInfoArray(crmf, + authToken, + httpParams, + req); + + req.setExtData(CLIENT_ISSUER, + sslClientCert.getIssuerDN().toString()); + CMS.debug("EnrollServlet: sslClientCert issuerDN = " + + sslClientCert.getIssuerDN().toString()); + } else { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CANT_PROCESS_ENROLL_REQ") + + CMS.getLogMessage("CMSGW_MISSING_KEYGEN_INFO")); + + // store a message in the signed audit log file + // (either an "admin" cert request for an admin + // certificate, an "agent" cert request for + // "bulk enrollment", or an "EE" standard cert request) + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditServiceID, + auditCertificateSubjectName); + + audit(auditMessage); + + throw new ECMSGWException( + CMS.getUserMessage(getLocale(httpReq), "CMS_GW_MISSING_KEYGEN_INFO")); + } + + } else if (certauthEnrollType.equals(CERT_AUTH_SINGLE)) { + + // have to be buried here to handle the issuer + + if (keyGenInfo != null) { + KeyGenProcessor keyGenProc = new KeyGenProcessor(cmsReq, + this); + + keyGenProc.fillCertInfo(null, certInfo, + authToken, httpParams); + } else if (pkcs10 != null) { + PKCS10Processor pkcs10Proc = new PKCS10Processor(cmsReq, + this); + + pkcs10Proc.fillCertInfo(pkcs10, certInfo, + authToken, httpParams); + } else if (cmc != null && cmc != "") { + CMCProcessor cmcProc = new CMCProcessor(cmsReq, this, enforcePop); + + certInfoArray = cmcProc.fillCertInfoArray(cmc, + authToken, + httpParams, + req); + } else if (crmf != null && crmf != "") { + CRMFProcessor crmfProc = new CRMFProcessor(cmsReq, this, enforcePop); + + certInfoArray = crmfProc.fillCertInfoArray(crmf, + authToken, + httpParams, + req); + } else { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CANT_PROCESS_ENROLL_REQ") + + CMS.getLogMessage("CMSGW_MISSING_KEYGEN_INFO")); + + // store a message in the signed audit log file + // (either an "admin" cert request for an admin + // certificate, an "agent" cert request for + // "bulk enrollment", or an "EE" standard cert request) + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditServiceID, + auditCertificateSubjectName); + + audit(auditMessage); + + throw new ECMSGWException( + CMS.getUserMessage(getLocale(httpReq), "CMS_GW_MISSING_KEYGEN_INFO")); + } + req.setExtData(CLIENT_ISSUER, + sslClientCert.getIssuerDN().toString()); + } + + } else if (keyGenInfo != null) { + + CMS.debug("EnrollServlet: Trying KeyGen with no cert auth."); + KeyGenProcessor keyGenProc = new KeyGenProcessor(cmsReq, this); + + keyGenProc.fillCertInfo(null, certInfo, authToken, httpParams); + } else if (pkcs10 != null) { + CMS.debug("EnrollServlet: Trying PKCS10 with no cert auth."); + PKCS10Processor pkcs10Proc = new PKCS10Processor(cmsReq, this); + + pkcs10Proc.fillCertInfo(pkcs10, certInfo, authToken, httpParams); + } else if (cmc != null) { + CMS.debug("EnrollServlet: Trying CMC with no cert auth."); + CMCProcessor cmcProc = new CMCProcessor(cmsReq, this, enforcePop); + + certInfoArray = cmcProc.fillCertInfoArray(cmc, authToken, + httpParams, req); + } else if (crmf != null && crmf != "") { + CMS.debug("EnrollServlet: Trying CRMF with no cert auth."); + CRMFProcessor crmfProc = new CRMFProcessor(cmsReq, this, enforcePop); + + certInfoArray = crmfProc.fillCertInfoArray(crmf, authToken, + httpParams, req); + } else { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CANT_PROCESS_ENROLL_REQ") + + CMS.getLogMessage("CMSGW_MISSING_KEYGEN_INFO")); + + // store a message in the signed audit log file + // (either an "admin" cert request for an admin certificate, + // an "agent" cert request for "bulk enrollment", or + // an "EE" standard cert request) + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditServiceID, + auditCertificateSubjectName); + + audit(auditMessage); + + throw new ECMSGWException(CMS.getUserMessage(getLocale(httpReq), "CMS_GW_MISSING_KEYGEN_INFO")); + } + + // if ca, fill in default signing alg here + + try { + ICertificateAuthority caSub = + (ICertificateAuthority) CMS.getSubsystem("ca"); + if (certInfoArray != null && caSub != null) { + for (int ix = 0; ix < certInfoArray.length; ix++) { + X509CertInfo ci = (X509CertInfo) certInfoArray[ix]; + String defaultSig = caSub.getDefaultAlgorithm(); + AlgorithmId algid = AlgorithmId.get(defaultSig); + ci.set(X509CertInfo.ALGORITHM_ID, + new CertificateAlgorithmId(algid)); + } + } + } catch (Exception e) { + CMS.debug("Failed to set signing alg to certinfo " + e.toString()); + } + + req.setExtData(IRequest.CERT_INFO, certInfoArray); + + if (challengePassword != null && !challengePassword.equals("")) { + String pwd = hashPassword(challengePassword); + + req.setExtData(CHALLENGE_PASSWORD, pwd); + } + + // store a message in the signed audit log file + // (either an "admin" cert request for an admin certificate, + // an "agent" cert request for "bulk enrollment", or + // an "EE" standard cert request) + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + auditServiceID, + auditCertificateSubjectName); + + audit(auditMessage); + + } catch (EBaseException eAudit1) { + // store a message in the signed audit log file + // (either an "admin" cert request for an admin certificate, + // an "agent" cert request for "bulk enrollment", or + // an "EE" standard cert request) + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditServiceID, + auditCertificateSubjectName); + + audit(auditMessage); + + throw eAudit1; + } + + X509CertImpl[] issuedCerts = null; + + // ensure that any low-level exceptions are reported + // to the signed audit log and stored as failures + try { + // send request to request queue. + mRequestQueue.processRequest(req); + // process result. + + // render OLD_CERT_TYPE's response differently, we + // do not want any javascript in HTML, and need to + // override the default render. + if (httpParams.getValueAsString(OLD_CERT_TYPE, null) != null) { + try { + renderServerEnrollResult(cmsReq); + cmsReq.setStatus(CMSRequest.SUCCESS); // no default render + + issuedCerts = + cmsReq.getIRequest().getExtDataInCertArray( + IRequest.ISSUED_CERTS); + + for (int i = 0; i < issuedCerts.length; i++) { + // (automated "agent" cert request processed + // - "accepted") + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + ILogger.SIGNED_AUDIT_ACCEPTANCE, + auditInfoCertValue(issuedCerts[i])); + + audit(auditMessage); + } + } catch (IOException ex) { + cmsReq.setStatus(CMSRequest.ERROR); + + // (automated "agent" cert request processed - "rejected") + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + ILogger.SIGNED_AUDIT_REJECTION, + SIGNED_AUDIT_AUTOMATED_REJECTION_REASON[0]); + + audit(auditMessage); + } + + return; + } + + boolean completed = handleEnrollAuditLog(req, cmsReq, + mAuthMgr, authToken, + certInfo, startTime); + + if (completed == false) { + // (automated "agent" cert request processed - "rejected") + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + ILogger.SIGNED_AUDIT_REJECTION, + SIGNED_AUDIT_AUTOMATED_REJECTION_REASON[1]); + + audit(auditMessage); + + return; + } + + // service success + cmsReq.setStatus(CMSRequest.SUCCESS); + issuedCerts = req.getExtDataInCertArray(IRequest.ISSUED_CERTS); + + String initiative = null; + String agentID; + + if (authToken == null) { + // request is from eegateway, so fromUser. + initiative = AuditFormat.FROMUSER; + } else { + agentID = authToken.getInString("userid"); + initiative = AuditFormat.FROMAGENT + " agentID: " + agentID; + } + + // audit log the success. + long endTime = CMS.getCurrentDate().getTime(); + + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.ENROLLMENTFORMAT, + new Object[] + { req.getRequestId(), + initiative, + mAuthMgr, + "completed", + issuedCerts[0].getSubjectDN(), + "cert issued serial number: 0x" + + issuedCerts[0].getSerialNumber().toString(16) + + " time: " + + (endTime - startTime) } + ); + + // handle initial admin enrollment if in adminEnroll mode. + checkAdminEnroll(cmsReq, issuedCerts); + + // return cert as mime type binary if requested. + if (checkImportCertToNav(cmsReq.getHttpResp(), + httpParams, issuedCerts[0])) { + cmsReq.setStatus(CMSRequest.SUCCESS); + + for (int i = 0; i < issuedCerts.length; i++) { + // (automated "agent" cert request processed - "accepted") + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + ILogger.SIGNED_AUDIT_ACCEPTANCE, + auditInfoCertValue(issuedCerts[i])); + + audit(auditMessage); + } + + return; + } + + // use success template. + try { + cmsReq.setResult(issuedCerts); + renderTemplate(cmsReq, mEnrollSuccessTemplate, + mEnrollSuccessFiller); + cmsReq.setStatus(CMSRequest.SUCCESS); + + for (int i = 0; i < issuedCerts.length; i++) { + // (automated "agent" cert request processed - "accepted") + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + ILogger.SIGNED_AUDIT_ACCEPTANCE, + auditInfoCertValue(issuedCerts[i])); + + audit(auditMessage); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_TEMP_REND_ERR", + mEnrollSuccessFiller.toString(), + e.toString())); + + // (automated "agent" cert request processed - "rejected") + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + ILogger.SIGNED_AUDIT_REJECTION, + SIGNED_AUDIT_AUTOMATED_REJECTION_REASON[2]); + + audit(auditMessage); + + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_RETURNING_RESULT_ERROR")); + } + } catch (EBaseException eAudit1) { + // store a message in the signed audit log file + // (automated "agent" cert request processed - "rejected") + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + ILogger.SIGNED_AUDIT_REJECTION, + SIGNED_AUDIT_AUTOMATED_REJECTION_REASON[3]); + + audit(auditMessage); + + throw eAudit1; + } + + return; + } + + /** + * check if this is first enroll from admin enroll. + * If so disable admin enroll from here on. + */ + protected void checkAdminEnroll(CMSRequest cmsReq, X509CertImpl[] issuedCerts) + throws EBaseException { + // this is special case, get the admin certificate + if (mAuthMgr != null && mAuthMgr.equals(IAuthSubsystem.PASSWDUSERDB_AUTHMGR_ID)) { + addAdminAgent(cmsReq, issuedCerts); + CMSGateway.disableAdminEnroll(); + } + } + + protected void addAdminAgent(CMSRequest cmsReq, X509CertImpl[] issuedCerts) + throws EBaseException { + String userid = cmsReq.getHttpParams().getValueAsString("uid"); + IUGSubsystem ug = (IUGSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_UG); + + IUser adminuser = ug.createUser(userid); + + adminuser.setX509Certificates(issuedCerts); + try { + ug.addUserCert(adminuser); + } catch (netscape.ldap.LDAPException e) { + CMS.debug( + "EnrollServlet: Cannot add admin's certificate to its entry in the " + + "user group database. Error " + e); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_ADDING_ADMIN_CERT_ERROR", e.toString())); + } + IGroup agentGroup = + ug.getGroupFromName(CA_AGENT_GROUP); + + if (agentGroup != null) { + // add user to the group if necessary + if (!agentGroup.isMember(userid)) { + agentGroup.addMemberName(userid); + ug.modifyGroup(agentGroup); + mLogger.log(ILogger.EV_AUDIT, ILogger.S_USRGRP, + AuditFormat.LEVEL, AuditFormat.ADDUSERGROUPFORMAT, + new Object[] { userid, userid, CA_AGENT_GROUP } + ); + + } + } else { + String msg = "Cannot add admin to the " + + CA_AGENT_GROUP + + " group: Group does not exist."; + + CMS.debug("EnrollServlet: " + msg); + throw new ECMSGWException(CMS.getUserMessage("CMS_GW_ADDING_ADMIN_ERROR")); + } + } + + protected void renderServerEnrollResult(CMSRequest cmsReq) throws + IOException { + HttpServletResponse httpResp = cmsReq.getHttpResp(); + + httpResp.setContentType("text/html"); + ServletOutputStream out = null; + + out = httpResp.getOutputStream(); + + // get template based on request status + out.println(""); + out.println(""); + out.println("Server Enrollment"); + out.println(""); + // out.println(""); + + if (cmsReq.getIRequest().getRequestStatus().equals(RequestStatus.COMPLETE)) { + out.println("

    "); + out.println("SUCCESS"); + out.println("

    "); + out.println("Your request is submitted and approved. Please cut and paste the certificate into your server."); // XXX - localize the message + out.println("

    "); + out.println("Request Creation Time: "); + out.println(cmsReq.getIRequest().getCreationTime().toString()); + out.println("

    "); + out.println("Request Status: "); + out.println(cmsReq.getStatus().toString()); + out.println("

    "); + out.println("Request ID: "); + out.println(cmsReq.getIRequest().getRequestId().toString()); + out.println("

    "); + out.println("Certificate: "); + out.println("

    "); + out.println("

    ");
    +            X509CertImpl certs[] =
    +                    cmsReq.getIRequest().getExtDataInCertArray(IRequest.ISSUED_CERTS);
    +
    +            out.println(CMS.getEncodedCert(certs[0]));
    +            out.println("
    "); + out.println("

    "); + out.println(""); + out.println(""); + out.println(""); + out.println(""); + } else if (cmsReq.getIRequest().getRequestStatus().equals(RequestStatus.PENDING)) { + out.println("

    "); + out.println("PENDING"); + out.println("

    "); + out.println("Your request is submitted. You can check on the status of your request with an authorized agent or local administrator by referring to the request ID."); // XXX - localize the message + out.println("

    "); + out.println("Request Creation Time: "); + out.println(cmsReq.getIRequest().getCreationTime().toString()); + out.println("

    "); + out.println("Request Status: "); + out.println(cmsReq.getStatus().toString()); + out.println("

    "); + out.println("Request ID: "); + out.println(cmsReq.getIRequest().getRequestId().toString()); + out.println("

    "); + out.println(""); + out.println(""); + out.println(""); + } else { + out.println("

    "); + out.println("ERROR"); + out.println("

    "); + out.println(""); + out.println("Please consult your local administrator for assistance."); // XXX - localize the message + out.println(""); + out.println("

    "); + out.println("Request Status: "); + out.println(cmsReq.getStatus().toString()); + out.println("

    "); + out.println("Error: "); + out.println(cmsReq.getError()); // XXX - need to parse in Locale + out.println("

    "); + out.println(""); + out.println(""); + } + + /** + * // include all the input data + * ArgBlock args = cmsReq.getHttpParams(); + * Enumeration ele = args.getElements(); + * while (ele.hasMoreElements()) { + * String eleT = (String)ele.nextElement(); + * out.println(""); + * } + **/ + + out.println(""); + } + + // XXX ALERT !! + // Remove the following and calls to them when we bundle a cartman + // later than alpha1. + // These are here to cover up problem in cartman where the + // key usage extension always ends up being digital signature only + // and for rsa-ex ends up having no bits set. + + private boolean mIsTestBed = false; + + private void init_testbed_hack(IConfigStore config) + throws EBaseException { + mIsTestBed = config.getBoolean("isTestBed", true); + } + + /** + * Signed Audit Log Info Certificate Value + * + * This method is called to obtain the certificate from the passed in + * "X509CertImpl" for a signed audit log message. + *

    + * + * @param x509cert an X509CertImpl + * @return cert string containing the certificate + */ + private String auditInfoCertValue(X509CertImpl x509cert) { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + if (x509cert == null) { + return ILogger.SIGNED_AUDIT_EMPTY_VALUE; + } + + byte rawData[] = null; + + try { + rawData = x509cert.getEncoded(); + } catch (CertificateEncodingException e) { + return ILogger.SIGNED_AUDIT_EMPTY_VALUE; + } + + String cert = null; + + // convert "rawData" into "base64Data" + if (rawData != null) { + String base64Data = null; + + base64Data = Utils.base64encode(rawData).trim(); + + StringBuffer sb = new StringBuffer(); + // extract all line separators from the "base64Data" + for (int i = 0; i < base64Data.length(); i++) { + if (base64Data.substring(i, i).getBytes() != EOL) { + sb.append(base64Data.substring(i, i)); + } + } + cert = sb.toString(); + } + + if (cert != null) { + cert = cert.trim(); + + if (cert.equals("")) { + return ILogger.SIGNED_AUDIT_EMPTY_VALUE; + } else { + return cert; + } + } else { + return ILogger.SIGNED_AUDIT_EMPTY_VALUE; + } + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/GetBySerial.java b/base/common/src/com/netscape/cms/servlet/cert/GetBySerial.java new file mode 100644 index 000000000..663397f54 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/GetBySerial.java @@ -0,0 +1,296 @@ +// --- 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.cert; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.X509Certificate; +import java.util.Locale; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.pkcs.ContentInfo; +import netscape.security.pkcs.PKCS7; +import netscape.security.pkcs.SignerInfo; +import netscape.security.x509.AlgorithmId; +import netscape.security.x509.CertificateChain; +import netscape.security.x509.X509CertImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.MetaInfo; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.RequestId; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; +import com.netscape.cms.servlet.common.ICMSTemplateFiller; +import com.netscape.cmsutil.crypto.CryptoUtil; + +/** + * Retrieve certificate by serial number. + * + * @version $Revision$, $Date$ + */ +public class GetBySerial extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = -2276677839178370838L; + + private final static String INFO = "GetBySerial"; + + private final static String IMPORT_CERT_TEMPLATE = "ImportCert.template"; + private String mImportTemplate = null; + private String mIETemplate = null; + private ICMSTemplateFiller mImportTemplateFiller = null; + IRequestQueue mReqQ = null; + + public GetBySerial() { + super(); + } + + /** + * Initialize the servlet. This servlet uses the template file + * "ImportCert.template" to import the cert to the users browser, + * if that is what the user requested + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + try { + mImportTemplate = sc.getInitParameter( + PROP_SUCCESS_TEMPLATE); + mIETemplate = sc.getInitParameter("importCertTemplate"); + if (mImportTemplate == null) + mImportTemplate = IMPORT_CERT_TEMPLATE; + } catch (Exception e) { + mImportTemplate = null; + } + mImportTemplateFiller = new ImportCertsTemplateFiller(); + + // override success and error templates to null - + // handle templates locally. + mTemplates.remove(CMSRequest.SUCCESS); + + ICertificateAuthority mCa = (ICertificateAuthority) CMS.getSubsystem("ca"); + if (mCa == null) { + return; + } + + mReqQ = mCa.getRequestQueue(); + } + + /** + * Process the HTTP request. + *

      + *
    • http.param serialNumber serial number of certificate in HEX + *
    + * + * @param cmsReq the object holding the request and response information + */ + public void process(CMSRequest cmsReq) throws EBaseException { + + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse response = cmsReq.getHttpResp(); + IArgBlock args = cmsReq.getHttpParams(); + + IAuthToken authToken = authenticate(cmsReq); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "import"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + String serial = args.getValueAsString("serialNumber", null); + String browser = args.getValueAsString("browser", null); + BigInteger serialNo = null; + + try { + serialNo = new BigInteger(serial, 16); + } catch (NumberFormatException e) { + serialNo = null; + } + if (serial == null || serialNo == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_INVALID_SERIAL_NUMBER")); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_INVALID_SERIAL_NUMBER"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + ICertRecord certRecord = (ICertRecord) getCertRecord(serialNo); + if (certRecord == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CERT_SERIAL_NOT_FOUND_1", serialNo.toString(16))); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_CERT_SERIAL_NOT_FOUND", "0x" + serialNo.toString(16)))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + // if RA, needs requestOwner to match + // first, find the user's group + if (authToken != null) { + String group = authToken.getInString("group"); + + if ((group != null) && (group != "")) { + CMS.debug("GetBySerial process: auth group=" + group); + if (group.equals("Registration Manager Agents")) { + boolean groupMatched = false; + // find the cert record's orig. requestor's group + MetaInfo metai = certRecord.getMetaInfo(); + if (metai != null) { + String reqId = (String) metai.get(ICertRecord.META_REQUEST_ID); + RequestId rid = new RequestId(reqId); + IRequest creq = mReqQ.findRequest(rid); + if (creq != null) { + String reqOwner = creq.getRequestOwner(); + if (reqOwner != null) { + CMS.debug("GetBySerial process: req owner=" + reqOwner); + if (reqOwner.equals(group)) + groupMatched = true; + } + } + } + if (groupMatched == false) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CERT_SERIAL_NOT_FOUND_1", serialNo.toString(16))); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_CERT_SERIAL_NOT_FOUND", "0x" + serialNo.toString(16)))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + } + } + } + + X509CertImpl cert = certRecord.getCertificate(); + + if (cert != null) { + // if there's a crmf request id, set that too. + if (browser != null && browser.equals("ie")) { + IArgBlock header = CMS.createArgBlock(); + IArgBlock ctx = CMS.createArgBlock(); + Locale[] locale = new Locale[1]; + CMSTemplateParams argSet = new CMSTemplateParams(header, ctx); + ICertificateAuthority ca = (ICertificateAuthority) CMS.getSubsystem("ca"); + CertificateChain cachain = ca.getCACertChain(); + X509Certificate[] cacerts = cachain.getChain(); + X509CertImpl[] userChain = new X509CertImpl[cacerts.length + 1]; + int m = 1, n = 0; + + for (; n < cacerts.length; m++, n++) { + userChain[m] = (X509CertImpl) cacerts[n]; + } + + userChain[0] = cert; + PKCS7 p7 = new PKCS7(new AlgorithmId[0], + new ContentInfo(new byte[0]), userChain, new SignerInfo[0]); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + try { + p7.encodeSignedData(bos); + } catch (Exception eee) { + } + + byte[] p7Bytes = bos.toByteArray(); + String p7Str = CMS.BtoA(p7Bytes); + + header.addStringValue("pkcs7", CryptoUtil.normalizeCertStr(p7Str)); + try { + CMSTemplate form = getTemplate(mIETemplate, req, locale); + ServletOutputStream out = response.getOutputStream(); + cmsReq.setStatus(CMSRequest.SUCCESS); + response.setContentType("text/html"); + form.renderOutput(out, argSet); + return; + } catch (Exception ee) { + CMS.debug("GetBySerial process: Exception=" + ee.toString()); + } + } //browser is IE + + MetaInfo metai = certRecord.getMetaInfo(); + String crmfReqId = null; + + if (metai != null) { + crmfReqId = (String) metai.get(ICertRecord.META_CRMF_REQID); + if (crmfReqId != null) + cmsReq.setResult(IRequest.CRMF_REQID, crmfReqId); + } + + if (crmfReqId == null && checkImportCertToNav( + cmsReq.getHttpResp(), cmsReq.getHttpParams(), cert)) { + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } + + // use import cert template to return cert. + X509CertImpl[] certs = new X509CertImpl[] { (X509CertImpl) cert }; + + cmsReq.setResult(certs); + + cmsReq.setStatus(CMSRequest.SUCCESS); + + // XXX follow request in cert record to set certtype, which will + // import cert only if it's client. For now assume "client" if + // someone clicked to import this cert. + cmsReq.getHttpParams().set("certType", "client"); + + try { + renderTemplate(cmsReq, mImportTemplate, mImportTemplateFiller); + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERROR_DISPLAY_TEMPLATE")); + throw new ECMSGWException(CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + } + + return; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/GetCAChain.java b/base/common/src/com/netscape/cms/servlet/cert/GetCAChain.java new file mode 100644 index 000000000..fe55f335b --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/GetCAChain.java @@ -0,0 +1,407 @@ +// --- 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.cert; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.Locale; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.CertificateChain; +import netscape.security.x509.X509CertImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authority.ICertAuthority; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.ICertPrettyPrint; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.base.UserInfo; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Retrieve the Certificates comprising the CA Chain for this CA. + * + * @version $Revision$, $Date$ + */ +public class GetCAChain extends CMSServlet { + /** + * + */ + private static final long serialVersionUID = -8189048155415074581L; + private final static String TPL_FILE = "displayCaCert.template"; + private String mFormPath = null; + + public GetCAChain() { + super(); + } + + /** + * initialize the servlet. + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + + // override success to display own output. + mTemplates.remove(CMSRequest.SUCCESS); + // coming from ee + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + } + + /** + * Process the HTTP request. + *
      + *
    • http.param op 'downloadBIN' - return the binary certificate chain + *
    • http.param op 'displayIND' - display pretty-print of certificate chain components + *
    + * + * @param cmsReq the object holding the request and response information + */ + protected void process(CMSRequest cmsReq) + throws EBaseException { + HttpServletRequest httpReq = cmsReq.getHttpReq(); + HttpServletResponse httpResp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + + // Construct an ArgBlock + IArgBlock args = cmsReq.getHttpParams(); + + // Get the operation code + String op = null; + + op = args.getValueAsString("op", null); + if (op == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_NO_OPTIONS_SELECTED")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_NO_OPTIONS_SELECTED")); + } + + cmsReq.setStatus(CMSRequest.SUCCESS); + + AuthzToken authzToken = null; + + if (op.startsWith("download")) { + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "download"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + downloadChain(op, args, httpReq, httpResp, cmsReq); + } else if (op.startsWith("display")) { + try { + authzToken = mAuthz.authorize(mAclMethod, authToken, + mAuthzResourceName, "read"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + displayChain(op, args, httpReq, httpResp, cmsReq); + } else { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_INVALID_OPTIONS_CA_CHAIN")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_INVALID_OPTIONS_SELECTED")); + } + // cmsReq.setResult(null); + return; + } + + private void downloadChain(String op, + IArgBlock args, + HttpServletRequest httpReq, + HttpServletResponse httpResp, + CMSRequest cmsReq) + throws EBaseException { + + /* check browser info ? */ + + /* check if pkcs7 will work for both nav and ie */ + + byte[] bytes = null; + + /* + * Some IE actions - IE doesn't want PKCS7 for "download" CA Cert. + * This means that we can only hand out the root CA, and not + * the whole chain. + */ + + if (clientIsMSIE(httpReq) && (op.equals("download") || op.equals("downloadBIN"))) { + X509Certificate[] caCerts = + ((ICertAuthority) mAuthority).getCACertChain().getChain(); + + try { + bytes = caCerts[0].getEncoded(); + } catch (CertificateEncodingException e) { + cmsReq.setStatus(CMSRequest.ERROR); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERROR_GETTING_CACERT_ENCODED", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_GETTING_CA_CERT_ERROR")); + } + } else { + CertificateChain certChain = + ((ICertAuthority) mAuthority).getCACertChain(); + + if (certChain == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_CA_CHAIN_EMPTY")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_CA_CHAIN_EMPTY")); + } + + try { + ByteArrayOutputStream encoded = new ByteArrayOutputStream(); + + certChain.encode(encoded, false); + bytes = encoded.toByteArray(); + } catch (IOException e) { + cmsReq.setStatus(CMSRequest.ERROR); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERROR_ENCODING_CA_CHAIN_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_ENCODING_CA_CHAIN_ERROR")); + } + } + + String mimeType = null; + + if (op.equals("downloadBIN")) { + mimeType = "application/octet-stream"; + } else { + try { + mimeType = args.getValueAsString("mimeType"); + } catch (EBaseException e) { + mimeType = "application/octet-stream"; + } + } + + try { + if (op.equals("downloadBIN")) { + // file suffixes changed to comply with RFC 5280 + // requirements for AIA extensions + if (clientIsMSIE(httpReq)) { + httpResp.setHeader("Content-disposition", + "attachment; filename=ca.cer"); + } else { + httpResp.setHeader("Content-disposition", + "attachment; filename=ca.p7c"); + } + } + httpResp.setContentType(mimeType); + httpResp.getOutputStream().write(bytes); + httpResp.setContentLength(bytes.length); + httpResp.getOutputStream().flush(); + } catch (IOException e) { + cmsReq.setStatus(CMSRequest.ERROR); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_DISPLAYING_CACHAIN_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAYING_CACHAIN_ERROR")); + } + } + + private void displayChain(String op, + IArgBlock args, + HttpServletRequest httpReq, + HttpServletResponse httpResp, + CMSRequest cmsReq) + throws EBaseException { + + CertificateChain certChain = + ((ICertAuthority) mAuthority).getCACertChain(); + + if (certChain == null) { + cmsReq.setStatus(CMSRequest.ERROR); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_CA_CHAIN_NOT_AVAILABLE")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_CA_CHAIN_NOT_AVAILABLE")); + } + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + if (mOutputTemplatePath != null) + mFormPath = mOutputTemplatePath; + try { + form = getTemplate(mFormPath, httpReq, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + String displayFormat = null; + + if (op.equals("displayIND")) { + displayFormat = "individual"; + } else { + try { + displayFormat = args.getValueAsString("displayFormat"); + } catch (EBaseException e) { + displayFormat = "chain"; + } + } + + header.addStringValue("displayFormat", displayFormat); + + if (displayFormat.equals("chain")) { + String subjectdn = null; + byte[] bytes = null; + + try { + subjectdn = + certChain.getFirstCertificate().getSubjectDN().toString(); + ByteArrayOutputStream encoded = new ByteArrayOutputStream(); + + certChain.encode(encoded); + bytes = encoded.toByteArray(); + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERROR_ENCODING_CA_CHAIN_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_ENCODING_CA_CHAIN_ERROR")); + } + + String chainBase64 = getBase64(bytes); + + header.addStringValue("subjectdn", subjectdn); + header.addStringValue("chainBase64", chainBase64); + } else { + try { + X509Certificate[] certs = certChain.getChain(); + + header.addIntegerValue("length", certs.length); + locale[0] = getLocale(httpReq); + for (int i = 0; i < certs.length; i++) { + byte[] bytes = null; + + try { + bytes = certs[i].getEncoded(); + } catch (CertificateEncodingException e) { + throw new IOException("Internal Error"); + } + String subjectdn = certs[i].getSubjectDN().toString(); + String finger = null; + try { + finger = CMS.getFingerPrints(certs[i]); + } catch (Exception e) { + throw new IOException("Internal Error"); + } + + ICertPrettyPrint certDetails = + CMS.getCertPrettyPrint((X509CertImpl) certs[i]); + + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addStringValue("fingerprints", finger); + rarg.addStringValue("subjectdn", subjectdn); + rarg.addStringValue("base64", getBase64(bytes)); + rarg.addStringValue("certDetails", + certDetails.toString(locale[0])); + argSet.addRepeatRecord(rarg); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_DISPLAYING_CACHAIN_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAYING_CACHAIN_ERROR")); + } + } + + try { + ServletOutputStream out = httpResp.getOutputStream(); + + httpResp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_BAD_SERV_OUT_STREAM", "", e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + } + + } + + /** + * gets base 64 encoded cert + */ + private String getBase64(byte[] certBytes) { + String certBase64 = CMS.BtoA(certBytes); + + return certBase64; + } + + /** + * Retrieves locale based on the request. + */ + protected Locale getLocale(HttpServletRequest req) { + Locale locale = null; + String lang = req.getHeader("accept-language"); + + if (lang == null) { + // use server locale + locale = Locale.getDefault(); + } else { + locale = new Locale(UserInfo.getUserLanguage(lang), + UserInfo.getUserCountry(lang)); + } + return locale; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/GetCRL.java b/base/common/src/com/netscape/cms/servlet/cert/GetCRL.java new file mode 100644 index 000000000..4c8661359 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/GetCRL.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.cms.servlet.cert; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.CRLException; +import java.util.Locale; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.X509CRLImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.ICRLPrettyPrint; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.crldb.ICRLIssuingPointRecord; +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.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; +import com.netscape.cmsutil.util.Utils; + +/** + * Retrieve CRL for a Certificate Authority + * + * @version $Revision$, $Date$ + */ +public class GetCRL extends CMSServlet { + /** + * + */ + private static final long serialVersionUID = 7132206924070383013L; + private final static String TPL_FILE = "displayCRL.template"; + private String mFormPath = null; + + public GetCRL() { + super(); + } + + /** + * initialize the servlet. + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + + mTemplates.remove(CMSRequest.SUCCESS); + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + if (mOutputTemplatePath != null) + mFormPath = mOutputTemplatePath; + } + + /** + * Process the HTTP request. + * + * @param cmsReq the object holding the request and response information + * @see DisplayCRL#process + */ + protected void process(CMSRequest cmsReq) + throws EBaseException { + HttpServletRequest httpReq = cmsReq.getHttpReq(); + HttpServletResponse httpResp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "read"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + // Construct an ArgBlock + IArgBlock args = cmsReq.getHttpParams(); + + if (!(mAuthority instanceof ICertificateAuthority)) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_CA_FROM_RA_NOT_IMP")); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_NOT_YET_IMPLEMENTED"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + CMS.debug("**** mFormPath before getTemplate = " + mFormPath); + try { + form = getTemplate(mFormPath, httpReq, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", mFormPath, e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + // Get the operation code + String op = null; + String crlId = null; + + op = args.getValueAsString("op", null); + crlId = args.getValueAsString("crlIssuingPoint", null); + if (op == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_NO_OPTIONS_SELECTED")); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_NO_OPTIONS_SELECTED"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + if (crlId == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_NO_CRL_ISSUING_POINT")); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_NO_CRL_SELECTED"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + ICRLIssuingPointRecord crlRecord = null; + ICertificateAuthority ca = (ICertificateAuthority) mAuthority; + ICRLIssuingPoint crlIP = null; + if (ca != null) + crlIP = ca.getCRLIssuingPoint(crlId); + + try { + crlRecord = (ICRLIssuingPointRecord) ca.getCRLRepository().readCRLIssuingPointRecord(crlId); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_NO_CRL_ISSUING_POINT_FOUND", crlId)); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_CRL_NOT_FOUND"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + if (crlRecord == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CRL_NOT_YET_UPDATED_1", crlId)); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_CRL_NOT_UPDATED"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + header.addStringValue("crlIssuingPoint", crlId); + header.addStringValue("crlNumber", crlRecord.getCRLNumber().toString()); + long lCRLSize = crlRecord.getCRLSize().longValue(); + + header.addLongValue("crlSize", lCRLSize); + if (crlIP != null) { + header.addStringValue("crlDescription", crlIP.getDescription()); + } + + String crlDisplayType = args.getValueAsString("crlDisplayType", null); + if (crlDisplayType != null) { + header.addStringValue("crlDisplayType", crlDisplayType); + } + + if ((op.equals("checkCRLcache") || + (op.equals("displayCRL") && crlDisplayType != null && crlDisplayType.equals("cachedCRL"))) && + (crlIP == null || (!crlIP.isCRLCacheEnabled()) || crlIP.isCRLCacheEmpty())) { + cmsReq.setError( + CMS.getUserMessage( + ((crlIP != null && crlIP.isCRLCacheEnabled() && crlIP.isCRLCacheEmpty()) ? + "CMS_GW_CRL_CACHE_IS_EMPTY" : "CMS_GW_CRL_CACHE_IS_NOT_ENABLED"), crlId)); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + byte[] crlbytes = null; + + if (op.equals("importDeltaCRL") || op.equals("getDeltaCRL") || + (op.equals("displayCRL") && crlDisplayType != null && + crlDisplayType.equals("deltaCRL"))) { + crlbytes = crlRecord.getDeltaCRL(); + } else if (op.equals("importCRL") || op.equals("getCRL") || + op.equals("checkCRL") || + (op.equals("displayCRL") && + crlDisplayType != null && + (crlDisplayType.equals("entireCRL") || + crlDisplayType.equals("crlHeader") || + crlDisplayType.equals("base64Encoded")))) { + crlbytes = crlRecord.getCRL(); + } + + if (crlbytes == null && (!op.equals("checkCRLcache")) && + (!(op.equals("displayCRL") && crlDisplayType != null && + crlDisplayType.equals("cachedCRL")))) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CRL_NOT_YET_UPDATED_1", crlId)); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_CRL_NOT_UPDATED"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + byte[] bytes = crlbytes; + + X509CRLImpl crl = null; + + if (op.equals("checkCRL") || op.equals("importCRL") || + op.equals("importDeltaCRL") || + (op.equals("displayCRL") && crlDisplayType != null && + (crlDisplayType.equals("entireCRL") || + crlDisplayType.equals("crlHeader") || + crlDisplayType.equals("base64Encoded") || + crlDisplayType.equals("deltaCRL")))) { + try { + if (op.equals("displayCRL") && crlDisplayType != null && + crlDisplayType.equals("crlHeader")) { + crl = new X509CRLImpl(crlbytes, false); + } else { + crl = new X509CRLImpl(crlbytes); + } + } catch (Exception e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_FAILED_DECODE_CRL_1", e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DECODE_CRL_FAILED"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + if ((op.equals("importDeltaCRL") || (op.equals("displayCRL") && + crlDisplayType != null && crlDisplayType.equals("deltaCRL"))) && + ((!(crlIP != null && crlIP.isThisCurrentDeltaCRL(crl))) && + (crlRecord.getCRLNumber() == null || + crlRecord.getDeltaCRLNumber() == null || + crlRecord.getDeltaCRLNumber().compareTo(crlRecord.getCRLNumber()) < 0 || + crlRecord.getDeltaCRLSize() == null || + crlRecord.getDeltaCRLSize().longValue() == -1))) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERR_NO_DELTA_CRL_1")); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_CRL_NOT_UPDATED"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + } + + String mimeType = "application/x-pkcs7-crl"; + + if (op.equals("checkCRLcache") || op.equals("checkCRL") || op.equals("displayCRL")) { + header.addStringValue("toDo", op); + String certSerialNumber = args.getValueAsString("certSerialNumber", ""); + + header.addStringValue("certSerialNumber", certSerialNumber); + if (certSerialNumber.startsWith("0x")) { + certSerialNumber = hexToDecimal(certSerialNumber); + } + + if (op.equals("checkCRLcache")) { + if (crlIP.getRevocationDateFromCache( + new BigInteger(certSerialNumber), false, false) != null) { + header.addBooleanValue("isOnCRL", true); + } else { + header.addBooleanValue("isOnCRL", false); + } + } + + if (op.equals("checkCRL")) { + header.addBooleanValue("isOnCRL", + crl.isRevoked(new BigInteger(certSerialNumber))); + } + + if (op.equals("displayCRL")) { + if (crlDisplayType.equals("entireCRL") || crlDisplayType.equals("cachedCRL")) { + ICRLPrettyPrint crlDetails = (crlDisplayType.equals("entireCRL")) ? + CMS.getCRLPrettyPrint(crl) : + CMS.getCRLCachePrettyPrint(crlIP); + String pageStart = args.getValueAsString("pageStart", null); + String pageSize = args.getValueAsString("pageSize", null); + + if (pageStart != null && pageSize != null) { + long lPageStart = new Long(pageStart).longValue(); + long lPageSize = new Long(pageSize).longValue(); + + if (lPageStart < 1) + lPageStart = 1; + + header.addStringValue("crlPrettyPrint", + crlDetails.toString(locale[0], + lCRLSize, lPageStart, lPageSize)); + header.addLongValue("pageStart", lPageStart); + header.addLongValue("pageSize", lPageSize); + } else { + header.addStringValue( + "crlPrettyPrint", crlDetails.toString(locale[0])); + } + } else if (crlDisplayType.equals("crlHeader")) { + ICRLPrettyPrint crlDetails = CMS.getCRLPrettyPrint(crl); + + header.addStringValue( + "crlPrettyPrint", crlDetails.toString(locale[0], lCRLSize, 0, 0)); + } else if (crlDisplayType.equals("base64Encoded")) { + try { + byte[] ba = crl.getEncoded(); + String crlBase64Encoded = Utils.base64encode(ba); + int length = crlBase64Encoded.length(); + int i = 0; + int j = 0; + int n = 1; + + while (i < length) { + int k = crlBase64Encoded.indexOf('\n', i); + + if (n < 100 && k > -1) { + n++; + i = k + 1; + } else { + n = 1; + IArgBlock rarg = CMS.createArgBlock(); + + if (k > -1) { + rarg.addStringValue("crlBase64Encoded", crlBase64Encoded.substring(j, k)); + i = k + 1; + j = i; + } else { + rarg.addStringValue("crlBase64Encoded", crlBase64Encoded.substring(j, length)); + i = length; + } + argSet.addRepeatRecord(rarg); + } + } + } catch (CRLException e) { + } + } else if (crlDisplayType.equals("deltaCRL")) { + header.addIntegerValue("deltaCRLSize", + crl.getNumberOfRevokedCertificates()); + + ICRLPrettyPrint crlDetails = CMS.getCRLPrettyPrint(crl); + + header.addStringValue( + "crlPrettyPrint", crlDetails.toString(locale[0], 0, 0, 0)); + + try { + byte[] ba = crl.getEncoded(); + String crlBase64Encoded = Utils.base64encode(ba); + int length = crlBase64Encoded.length(); + int i = 0; + int j = 0; + int n = 1; + + while (i < length) { + int k = crlBase64Encoded.indexOf('\n', i); + + if (n < 100 && k > -1) { + n++; + i = k + 1; + } else { + n = 1; + IArgBlock rarg = CMS.createArgBlock(); + + if (k > -1) { + rarg.addStringValue("crlBase64Encoded", crlBase64Encoded.substring(j, k)); + i = k + 1; + j = i; + } else { + rarg.addStringValue("crlBase64Encoded", crlBase64Encoded.substring(j, length)); + i = length; + } + argSet.addRepeatRecord(rarg); + } + } + } catch (CRLException e) { + } + } + } + + try { + ServletOutputStream out = httpResp.getOutputStream(); + + httpResp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_OUT_STREAM_TEMPLATE", e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + } + return; + } else if (op.equals("importCRL") || op.equals("importDeltaCRL")) { + if (clientIsMSIE(httpReq)) + mimeType = "application/pkix-crl"; + else + mimeType = "application/x-pkcs7-crl"; + } else if (op.equals("getCRL")) { + mimeType = "application/octet-stream"; + httpResp.setHeader("Content-disposition", + "attachment; filename=" + crlId + ".crl"); + } else if (op.equals("getDeltaCRL")) { + mimeType = "application/octet-stream"; + httpResp.setHeader("Content-disposition", + "attachment; filename=delta-" + crlId + ".crl"); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_INVALID_OPTIONS_SELECTED")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_INVALID_OPTIONS_SELECTED")); + } + + try { + // if (clientIsMSIE(httpReq) && op.equals("getCRL")) + // httpResp.setHeader("Content-disposition", + // "attachment; filename=getCRL.crl"); + httpResp.setContentType(mimeType); + httpResp.setContentLength(bytes.length); + httpResp.getOutputStream().write(bytes); + httpResp.getOutputStream().flush(); + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERROR_DISPLAYING_CRLINFO")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAYING_CRLINFO_ERROR")); + } + // cmsReq.setResult(null); + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } + + private String hexToDecimal(String hex) { + String newHex = hex.substring(2); + BigInteger bi = new BigInteger(newHex, 16); + + return bi.toString(); + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/GetCertFromRequest.java b/base/common/src/com/netscape/cms/servlet/cert/GetCertFromRequest.java new file mode 100644 index 000000000..71b0004cd --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/GetCertFromRequest.java @@ -0,0 +1,350 @@ +// --- 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.cert; + +import java.io.IOException; +import java.util.Locale; +import java.math.BigInteger; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + +import netscape.security.extensions.NSCertTypeExtension; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.Extension; +import netscape.security.x509.KeyUsageExtension; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authority.IAuthority; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.profile.IEnrollProfile; +import com.netscape.certsrv.ra.IRegistrationAuthority; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.RequestId; +import com.netscape.certsrv.request.RequestStatus; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; +import com.netscape.cms.servlet.common.ICMSTemplateFiller; + +/** + * Gets a issued certificate from a request id. + * + * @version $Revision$, $Date$ + */ +public class GetCertFromRequest extends CMSServlet { + /** + * + */ + private static final long serialVersionUID = 5310646832256611066L; + private final static String PROP_IMPORT = "importCert"; + protected static final String GET_CERT_FROM_REQUEST_TEMPLATE = "ImportCert.template"; + protected static final String DISPLAY_CERT_FROM_REQUEST_TEMPLATE = "displayCertFromRequest.template"; + + protected static final String REQUEST_ID = "requestId"; + protected static final String CERT_TYPE = "certtype"; + + protected String mCertFrReqSuccessTemplate = null; + protected ICMSTemplateFiller mCertFrReqFiller = null; + + protected IRequestQueue mQueue = null; + protected boolean mImportCert = true; + + public GetCertFromRequest() { + super(); + } + + /** + * initialize the servlet. This servlet uses the template files + * "displayCertFromRequest.template" and "ImportCert.template" + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + mTemplates.remove(CMSRequest.SUCCESS); + mQueue = mAuthority.getRequestQueue(); + try { + String tmp = sc.getInitParameter( + PROP_IMPORT); + + if (tmp != null && tmp.trim().equalsIgnoreCase("false")) + mImportCert = false; + + String defTemplate = null; + + if (mImportCert) + defTemplate = GET_CERT_FROM_REQUEST_TEMPLATE; + else + defTemplate = DISPLAY_CERT_FROM_REQUEST_TEMPLATE; + if (mAuthority instanceof IRegistrationAuthority) + defTemplate = "/ra/" + defTemplate; + else + defTemplate = "/ca/" + defTemplate; + mCertFrReqSuccessTemplate = sc.getInitParameter( + PROP_SUCCESS_TEMPLATE); + if (mCertFrReqSuccessTemplate == null) + mCertFrReqSuccessTemplate = defTemplate; + String fillername = + sc.getInitParameter(PROP_SUCCESS_TEMPLATE_FILLER); + + if (fillername != null) { + ICMSTemplateFiller filler = newFillerObject(fillername); + + if (filler != null) + mCertFrReqFiller = filler; + } else { + mCertFrReqFiller = new CertFrRequestFiller(); + } + } catch (Exception e) { + // should never happen. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_IMP_INIT_SERV_ERR", e.toString(), + mId)); + } + } + + /** + * Process the HTTP request. + *
      + *
    • http.param requestId The request ID to search on + *
    + * + * @param cmsReq the object holding the request and response information + */ + protected void process(CMSRequest cmsReq) + throws EBaseException { + IArgBlock httpParams = cmsReq.getHttpParams(); + HttpServletRequest httpReq = cmsReq.getHttpReq(); + + IAuthToken authToken = authenticate(cmsReq); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "read"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + String requestId = httpParams.getValueAsString(REQUEST_ID, null); + + if (requestId == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_NO_REQUEST_ID_PROVIDED")); + throw new ECMSGWException(CMS.getUserMessage("CMS_GW_NO_REQUEST_ID_PROVIDED")); + } + // check if request Id is valid. + try { + new BigInteger(requestId); + } catch (NumberFormatException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_INVALID_REQ_ID_FORMAT", requestId)); + throw new EBaseException( + CMS.getUserMessage(getLocale(httpReq), "CMS_BASE_INVALID_NUMBER_FORMAT_1", requestId)); + } + + IRequest r = mQueue.findRequest(new RequestId(requestId)); + + if (r == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_REQUEST_ID_NOT_FOUND", requestId)); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_REQUEST_ID_NOT_FOUND", requestId)); + } + + if (authToken != null) { + //if RA, group and requestOwner must match + String group = authToken.getInString("group"); + if ((group != null) && (group != "") && + group.equals("Registration Manager Agents")) { + boolean groupMatched = false; + String reqOwner = r.getRequestOwner(); + if (reqOwner != null) { + CMS.debug("GetCertFromRequest process: req owner=" + reqOwner); + if (reqOwner.equals(group)) + groupMatched = true; + } + if (groupMatched == false) { + CMS.debug("RA group unmatched"); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_REQUEST_ID_NOT_FOUND", requestId)); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_REQUEST_ID_NOT_FOUND", requestId)); + } + } + } + + if (!((r.getRequestType().equals(IRequest.ENROLLMENT_REQUEST)) || + (r.getRequestType().equals(IRequest.RENEWAL_REQUEST)))) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_REQUEST_NOT_ENROLLMENT_1", requestId)); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_REQUEST_NOT_ENROLLMENT", requestId)); + } + RequestStatus status = r.getRequestStatus(); + + if (!status.equals(RequestStatus.COMPLETE)) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_REQUEST_NOT_COMPLETED_1", requestId)); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_REQUEST_NOT_COMPLETED", requestId)); + } + Integer result = r.getExtDataInInteger(IRequest.RESULT); + + if (result != null && !result.equals(IRequest.RES_SUCCESS)) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_REQUEST_HAD_ERROR_1", requestId)); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_REQUEST_HAD_ERROR", requestId)); + } + Object o = r.getExtDataInCertArray(IRequest.ISSUED_CERTS); + + if (r.getExtDataInString("profile") != null) { + // handle profile-based request + X509CertImpl cert = r.getExtDataInCert(IEnrollProfile.REQUEST_ISSUED_CERT); + X509CertImpl certs[] = new X509CertImpl[1]; + + certs[0] = cert; + o = certs; + } + if (o == null || !(o instanceof X509CertImpl[])) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_REQUEST_HAD_NO_CERTS_1", requestId)); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_REQUEST_HAD_NO_CERTS", requestId)); + } + if (o instanceof X509CertImpl[]) { + X509CertImpl[] certs = (X509CertImpl[]) o; + + if (certs == null || certs.length == 0 || certs[0] == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_REQUEST_HAD_NO_CERTS_1", requestId)); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_REQUEST_HAD_NO_CERTS", requestId)); + } + + // for importsCert to get the crmf_reqid. + cmsReq.setIRequest(r); + + cmsReq.setStatus(CMSRequest.SUCCESS); + + if (mImportCert && + checkImportCertToNav(cmsReq.getHttpResp(), httpParams, certs[0])) { + return; + } + try { + cmsReq.setResult(certs); + renderTemplate(cmsReq, mCertFrReqSuccessTemplate, mCertFrReqFiller); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGE_ERROR_DISPLAY_TEMPLATE_1", + mCertFrReqSuccessTemplate, e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + } + return; + } +} + +class CertFrRequestFiller extends ImportCertsTemplateFiller { + public CertFrRequestFiller() { + } + + public CMSTemplateParams getTemplateParams( + CMSRequest cmsReq, IAuthority authority, Locale locale, Exception e) + throws Exception { + CMSTemplateParams tparams = + super.getTemplateParams(cmsReq, authority, locale, e); + String reqId = cmsReq.getHttpParams().getValueAsString( + GetCertFromRequest.REQUEST_ID); + + tparams.getHeader().addStringValue(GetCertFromRequest.REQUEST_ID, reqId); + + if (reqId != null) { + IRequest r = authority.getRequestQueue().findRequest(new RequestId(reqId)); + if (r != null) { + boolean noCertImport = true; + String certType = r.getExtDataInString(IRequest.HTTP_PARAMS, IRequest.CERT_TYPE); + + if (certType != null && certType.equals(IRequest.CLIENT_CERT)) { + noCertImport = false; + } + tparams.getHeader().addBooleanValue("noCertImport", noCertImport); + + X509CertImpl[] certs = r.getExtDataInCertArray(IRequest.ISSUED_CERTS); + + if (certs != null) { + X509CertInfo info = (X509CertInfo) certs[0].get(X509CertImpl.NAME + "." + X509CertImpl.INFO); + CertificateExtensions extensions = (CertificateExtensions) info.get(X509CertInfo.EXTENSIONS); + + tparams.getHeader().addStringValue(GetCertFromRequest.CERT_TYPE, "x509"); + + boolean emailCert = false; + + if (extensions != null) { + for (int i = 0; i < extensions.size(); i++) { + Extension ext = (Extension) extensions.elementAt(i); + + if (ext instanceof NSCertTypeExtension) { + NSCertTypeExtension type = (NSCertTypeExtension) ext; + + if (((Boolean) type.get(NSCertTypeExtension.EMAIL)).booleanValue()) + emailCert = true; + } + if (ext instanceof KeyUsageExtension) { + KeyUsageExtension usage = + (KeyUsageExtension) ext; + + try { + if (((Boolean) usage.get(KeyUsageExtension.DIGITAL_SIGNATURE)).booleanValue() || + ((Boolean) usage.get(KeyUsageExtension.DATA_ENCIPHERMENT)).booleanValue()) + emailCert = true; + } catch (ArrayIndexOutOfBoundsException e0) { + // bug356108: + // In case there is only DIGITAL_SIGNATURE, + // don't report error + } + } + } + } + tparams.getHeader().addBooleanValue("emailCert", emailCert); + } + } + } + + return tparams; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/GetEnableStatus.java b/base/common/src/com/netscape/cms/servlet/cert/GetEnableStatus.java new file mode 100644 index 000000000..d0dfb8f9a --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/GetEnableStatus.java @@ -0,0 +1,173 @@ +// --- 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.cert; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Locale; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthManager; +import com.netscape.certsrv.authentication.IAuthSubsystem; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.ra.IRegistrationAuthority; +import com.netscape.cms.authentication.HashAuthentication; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Servlet to get the enrollment status, enable or disable. + * + * @version $Revision$, $Date$ + */ +public class GetEnableStatus extends CMSServlet { + /** + * + */ + private static final long serialVersionUID = 3879769989681379834L; + private final static String TPL_FILE = "userEnroll.template"; + private String mFormPath = null; + + public GetEnableStatus() { + super(); + } + + /** + * initialize the servlet. + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + // coming from agent + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + + mTemplates.remove(CMSRequest.SUCCESS); + } + + protected CMSRequest newCMSRequest() { + return new CMSRequest(); + } + + /** + * Process the HTTP request. + *
      + *
    • http.param + *
    + * + * @param cmsReq the object holding the request and response information + */ + protected void process(CMSRequest cmsReq) + throws EBaseException { + HttpServletRequest httpReq = cmsReq.getHttpReq(); + HttpServletResponse httpResp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "read"); + } catch (Exception e) { + // do nothing for now + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + String reqHost = httpReq.getRemoteHost(); + + if (!(mAuthority instanceof IRegistrationAuthority)) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_CA_FROM_RA_NOT_IMP")); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_NOT_YET_IMPLEMENTED"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, httpReq, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", + mFormPath, e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + IConfigStore configStore = CMS.getConfigStore(); + String val = configStore.getString("hashDirEnrollment.name"); + IAuthSubsystem authSS = (IAuthSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_AUTH); + IAuthManager authMgr = authSS.get(val); + HashAuthentication mgr = (HashAuthentication) authMgr; + long timeout = HashAuthentication.DEFAULT_TIMEOUT / 1000; + + header.addStringValue("timeout", "" + timeout); + header.addStringValue("reqHost", reqHost); + + for (Enumeration hosts = mgr.getHosts(); hosts.hasMoreElements();) { + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addStringValue("hosts", hosts.nextElement()); + argSet.addRepeatRecord(rarg); + } + + try { + ServletOutputStream out = httpResp.getOutputStream(); + + httpResp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_STREAM_TEMPLATE", e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + } + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } + +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/GetInfo.java b/base/common/src/com/netscape/cms/servlet/cert/GetInfo.java new file mode 100644 index 000000000..6af5c0c39 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/GetInfo.java @@ -0,0 +1,377 @@ +// --- 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.cert; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.AlgorithmId; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.crldb.ICRLIssuingPointRecord; +import com.netscape.certsrv.dbs.crldb.ICRLRepository; +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.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Get detailed information about CA CRL processing + * + * @version $Revision$, $Date$ + */ +public class GetInfo extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = 1909881831730252799L; + + private final static String INFO = "GetInfo"; + + private String mFormPath = null; + private ICertificateAuthority mCA = null; + + /** + * Constructs GetInfo servlet. + */ + public GetInfo() { + super(); + } + + /** + * initialize the servlet. + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + + mFormPath = ""; + if (mAuthority instanceof ICertificateAuthority) + mCA = (ICertificateAuthority) mAuthority; + + // override success to do output our own template. + mTemplates.remove(CMSRequest.SUCCESS); + } + + /** + * XXX Process the HTTP request. + *
      + *
    • http.param template filename of template to use to render the result + *
    + * + * @param cmsReq the object holding the request and response information + */ + public void process(CMSRequest cmsReq) throws EBaseException { + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "read"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + EBaseException error = null; + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + String template = req.getParameter("template"); + String formFile = ""; + + /* + for (int i = 0; ((template != null) && (i < template.length())); i++) { + char c = template.charAt(i); + if (!Character.isLetterOrDigit(c) && c != '_' && c != '-') { + template = null; + break; + } + } + */ + + if (template != null) { + formFile = template + ".template"; + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE_1")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + CMS.debug("*** formFile = " + formFile); + try { + form = getTemplate(formFile, req, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", formFile, e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + try { + process(argSet, header, req, resp, locale[0]); + } catch (EBaseException e) { + error = e; + } + + try { + ServletOutputStream out = resp.getOutputStream(); + + if (error == null) { + String xmlOutput = req.getParameter("xml"); + if (xmlOutput != null && xmlOutput.equals("true")) { + outputXML(resp, argSet); + } else { + resp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } + } else { + cmsReq.setStatus(CMSRequest.ERROR); + cmsReq.setError(error); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_STREAM_TEMPLATE", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + } + + private void process(CMSTemplateParams argSet, IArgBlock header, + HttpServletRequest req, + HttpServletResponse resp, + Locale locale) + throws EBaseException { + if (mCA != null) { + String crlIssuingPoints = ""; + String crlNumbers = ""; + String deltaNumbers = ""; + String crlSizes = ""; + String deltaSizes = ""; + String crlDescriptions = ""; + StringBuffer crlSplits = new StringBuffer(); + String recentChanges = ""; + String crlTesting = ""; + boolean isDeltaCRLEnabled = false; + + String masterHost = CMS.getConfigStore().getString("master.ca.agent.host", ""); + String masterPort = CMS.getConfigStore().getString("master.ca.agent.port", ""); + + if (masterHost != null && masterHost.length() > 0 && + masterPort != null && masterPort.length() > 0) { + + ICRLRepository crlRepository = mCA.getCRLRepository(); + + Vector ipNames = crlRepository.getIssuingPointsNames(); + for (int i = 0; i < ipNames.size(); i++) { + String ipName = ipNames.elementAt(i); + ICRLIssuingPointRecord crlRecord = null; + try { + crlRecord = crlRepository.readCRLIssuingPointRecord(ipName); + } catch (Exception e) { + } + if (crlRecord != null) { + if (crlIssuingPoints.length() > 0) + crlIssuingPoints += "+"; + crlIssuingPoints += ipName; + + BigInteger crlNumber = crlRecord.getCRLNumber(); + if (crlNumbers.length() > 0) + crlNumbers += "+"; + if (crlNumber != null) + crlNumbers += crlNumber.toString(); + + if (crlSizes.length() > 0) + crlSizes += "+"; + crlSizes += ((crlRecord.getCRLSize() != null) ? + crlRecord.getCRLSize().toString() : "-1"); + + if (deltaSizes.length() > 0) + deltaSizes += "+"; + long dSize = -1; + if (crlRecord.getDeltaCRLSize() != null) + dSize = crlRecord.getDeltaCRLSize().longValue(); + deltaSizes += dSize; + + BigInteger deltaNumber = crlRecord.getDeltaCRLNumber(); + if (deltaNumbers.length() > 0) + deltaNumbers += "+"; + if (deltaNumber != null && dSize > -1) { + deltaNumbers += deltaNumber.toString(); + isDeltaCRLEnabled |= true; + } else { + deltaNumbers += "0"; + } + + if (recentChanges.length() > 0) + recentChanges += "+"; + recentChanges += "-, -, -"; + + if (crlTesting.length() > 0) + crlTesting += "+"; + crlTesting += "0"; + } + } + + } else { + Enumeration ips = mCA.getCRLIssuingPoints(); + + while (ips.hasMoreElements()) { + ICRLIssuingPoint ip = ips.nextElement(); + + if (ip.isCRLIssuingPointEnabled()) { + if (crlIssuingPoints.length() > 0) + crlIssuingPoints += "+"; + crlIssuingPoints += ip.getId(); + + BigInteger crlNumber = ip.getCRLNumber(); + if (crlNumbers.length() > 0) + crlNumbers += "+"; + if (crlNumber != null) + crlNumbers += crlNumber.toString(); + + BigInteger deltaNumber = ip.getDeltaCRLNumber(); + if (deltaNumbers.length() > 0) + deltaNumbers += "+"; + if (deltaNumber != null) + deltaNumbers += deltaNumber.toString(); + + if (crlSizes.length() > 0) + crlSizes += "+"; + crlSizes += ip.getCRLSize(); + + if (deltaSizes.length() > 0) + deltaSizes += "+"; + deltaSizes += ip.getDeltaCRLSize(); + + if (crlDescriptions.length() > 0) + crlDescriptions += "+"; + crlDescriptions += ip.getDescription(); + + if (recentChanges.length() > 0) + recentChanges += "+"; + if (ip.isCRLUpdateInProgress() == ICRLIssuingPoint.CRL_PUBLISHING_STARTED) { + recentChanges += "Publishing CRL #" + ip.getCRLNumber(); + } else if (ip.isCRLUpdateInProgress() == ICRLIssuingPoint.CRL_UPDATE_STARTED) { + recentChanges += "Creating CRL #" + ip.getNextCRLNumber(); + } else { // ip.CRL_UPDATE_DONE + recentChanges += ip.getNumberOfRecentlyRevokedCerts() + ", " + + ip.getNumberOfRecentlyUnrevokedCerts() + ", " + + ip.getNumberOfRecentlyExpiredCerts(); + } + isDeltaCRLEnabled |= ip.isDeltaCRLEnabled(); + + if (crlSplits.length() > 0) + crlSplits.append("+"); + Vector splits = ip.getSplitTimes(); + + for (int i = 0; i < splits.size(); i++) { + crlSplits.append(splits.elementAt(i)); + if (i + 1 < splits.size()) + crlSplits.append(","); + } + + if (crlTesting.length() > 0) + crlTesting += "+"; + crlTesting += ((ip.isCRLCacheTestingEnabled()) ? "1" : "0"); + } + } + + } + + header.addStringValue("crlIssuingPoints", crlIssuingPoints); + header.addStringValue("crlDescriptions", crlDescriptions); + header.addStringValue("crlNumbers", crlNumbers); + header.addStringValue("deltaNumbers", deltaNumbers); + header.addStringValue("crlSizes", crlSizes); + header.addStringValue("deltaSizes", deltaSizes); + header.addStringValue("crlSplits", crlSplits.toString()); + header.addStringValue("crlTesting", crlTesting); + header.addBooleanValue("isDeltaCRLEnabled", isDeltaCRLEnabled); + + header.addStringValue("master_host", masterHost); + header.addStringValue("master_port", masterPort); + + header.addStringValue("masterCRLIssuingPoint", ICertificateAuthority.PROP_MASTER_CRL); + ICRLIssuingPoint ip0 = mCA.getCRLIssuingPoint(ICertificateAuthority.PROP_MASTER_CRL); + + if (ip0 != null) { + header.addStringValue("defaultAlgorithm", ip0.getSigningAlgorithm()); + } + + if (recentChanges.length() > 0) + header.addStringValue("recentChanges", recentChanges); + + String validAlgorithms = null; + String[] allAlgorithms = mCA.getCASigningAlgorithms(); + + if (allAlgorithms == null) { + CMS.debug("GetInfo: signing algorithms set to All algorithms"); + allAlgorithms = AlgorithmId.ALL_SIGNING_ALGORITHMS; + } + + for (int i = 0; i < allAlgorithms.length; i++) { + if (i > 0) { + validAlgorithms += "+" + allAlgorithms[i]; + } else { + validAlgorithms = allAlgorithms[i]; + } + } + if (validAlgorithms != null) + header.addStringValue("validAlgorithms", validAlgorithms); + } + + return; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/HashEnrollServlet.java b/base/common/src/com/netscape/cms/servlet/cert/HashEnrollServlet.java new file mode 100644 index 000000000..5e6207e1a --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/HashEnrollServlet.java @@ -0,0 +1,1241 @@ +// --- 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.cert; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +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.KeyUsageExtension; +import netscape.security.x509.X500Name; +import netscape.security.x509.X509CertImpl; +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.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.IAuthManager; +import com.netscape.certsrv.authentication.IAuthSubsystem; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertRecordList; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.logging.AuditFormat; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.RequestStatus; +import com.netscape.cms.authentication.HashAuthentication; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; +import com.netscape.cms.servlet.common.ICMSTemplateFiller; + +/** + * performs face-to-face enrollment. + * + * @version $Revision$, $Date$ + */ +public class HashEnrollServlet extends CMSServlet { + /** + * + */ + private static final long serialVersionUID = 5532936020515258333L; + + public final static String ADMIN_ENROLL_SERVLET_ID = "adminEnroll"; + + // enrollment templates. + public static final String ENROLL_SUCCESS_TEMPLATE = "/ra/HashEnrollSuccess.template"; + + // http params + public static final String OLD_CERT_TYPE = "csrCertType"; + public static final String CERT_TYPE = "certType"; + // same as in ConfigConstant.java + public static final String REQUEST_FORMAT = "reqFormat"; + public static final String REQUEST_CONTENT = "requestContent"; + public static final String SUBJECT_KEYGEN_INFO = "subjectKeyGenInfo"; + public static final String CRMF_REQUEST = "CRMFRequest"; + public static final String SUBJECT_NAME = "subject"; + public static final String CRMF_REQID = "crmfReqId"; + public static final String CHALLENGE_PASSWORD = "challengePhrase"; + + private static final String CERT_AUTH_DUAL = "dual"; + private static final String CERT_AUTH_ENCRYPTION = "encryption"; + private static final String CERT_AUTH_SINGLE = "single"; + private static final String CLIENT_ISSUER = "clientIssuer"; + public static final String TPL_ERROR_FILE = "/ra/GenErrorHashDirEnroll.template"; + + private boolean mAuthTokenOverride = true; + private String mEnrollSuccessTemplate = null; + private ICMSTemplateFiller mEnrollSuccessFiller = new ImportCertsTemplateFiller(); + + ICertificateAuthority mCa = null; + ICertificateRepository mRepository = null; + + public HashEnrollServlet() { + super(); + } + + /** + * initialize the servlet. + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + // override success template to allow direct import of keygen certs. + mTemplates.remove(CMSRequest.SUCCESS); + try { + mEnrollSuccessTemplate = sc.getInitParameter( + CMSServlet.PROP_SUCCESS_TEMPLATE); + if (mEnrollSuccessTemplate == null) + mEnrollSuccessTemplate = ENROLL_SUCCESS_TEMPLATE; + String fillername = + sc.getInitParameter(PROP_SUCCESS_TEMPLATE_FILLER); + + if (fillername != null) { + ICMSTemplateFiller filler = newFillerObject(fillername); + + if (filler != null) + mEnrollSuccessFiller = filler; + } + + // cfu + mCa = (ICertificateAuthority) CMS.getSubsystem("ca"); + + init_testbed_hack(mConfig); + } catch (Exception e) { + // this should never happen. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_IMP_INIT_SERV_ERR", e.toString(), mId)); + } + } + + /** + * Process the HTTP request. + * + * @param cmsReq the object holding the request and response information + */ + protected void process(CMSRequest cmsReq) + throws EBaseException { + IArgBlock httpParams = cmsReq.getHttpParams(); + HttpServletRequest httpReq = cmsReq.getHttpReq(); + String certType = null; + + String reqHost = httpReq.getRemoteHost(); + + String host = httpParams.getValueAsString("hostname", null); + + if (host == null || !host.equals(reqHost)) { + printError(cmsReq, "0"); + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } + + IConfigStore configStore = CMS.getConfigStore(); + String val = configStore.getString("hashDirEnrollment.name"); + IAuthSubsystem authSS = (IAuthSubsystem) + CMS.getSubsystem(CMS.SUBSYSTEM_AUTH); + IAuthManager authMgr = authSS.get(val); + HashAuthentication mgr = (HashAuthentication) authMgr; + + Date date = new Date(); + long currTime = date.getTime(); + long timeout = mgr.getTimeout(reqHost); + long lastlogin = mgr.getLastLogin(reqHost); + long diff = currTime - lastlogin; + + boolean enable = mgr.isEnable(reqHost); + + if (!enable) { + printError(cmsReq, "0"); + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } + if (lastlogin == 0) + mgr.setLastLogin(reqHost, currTime); + else if (diff > timeout) { + mgr.disable(reqHost); + printError(cmsReq, "2"); + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } + + mgr.setLastLogin(reqHost, currTime); + + // support Enterprise 3.5.1 server where CERT_TYPE=csrCertType + // instead of certType + certType = httpParams.getValueAsString(OLD_CERT_TYPE, null); + if (certType == null) { + certType = httpParams.getValueAsString(CERT_TYPE, "client"); + } else { + ; + } + + processX509(cmsReq); + } + + private void printError(CMSRequest cmsReq, String errorCode) + throws EBaseException { + HttpServletRequest httpReq = cmsReq.getHttpReq(); + HttpServletResponse httpResp = cmsReq.getHttpResp(); + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + mTemplates.remove(CMSRequest.SUCCESS); + header.addStringValue("authority", "Registration Manager"); + header.addStringValue("errorCode", errorCode); + String formPath = TPL_ERROR_FILE; + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(formPath, httpReq, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", formPath, e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + return; + } + try { + ServletOutputStream out = httpResp.getOutputStream(); + + httpResp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_BAD_SERV_OUT_STREAM", + e.toString())); + cmsReq.setError(new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR"))); + cmsReq.setStatus(CMSRequest.ERROR); + } + } + + protected void processX509(CMSRequest cmsReq) + throws EBaseException { + IArgBlock httpParams = cmsReq.getHttpParams(); + HttpServletRequest httpReq = cmsReq.getHttpReq(); + + // create enrollment request in request queue. + IRequest req = mRequestQueue.newRequest(IRequest.ENROLLMENT_REQUEST); + + /* + * === certAuth based enroll === + * "certAuthEnroll" is on. + * "certauthEnrollType can be one of the three: + * single - it's for single cert enrollment + * dual - it's for dual certs enrollment + * encryption - getting the encryption cert only via + * authentication of the signing cert + * (crmf or keyGenInfo) + */ + boolean certAuthEnroll = false; + + String certAuthEnrollOn = + httpParams.getValueAsString("certauthEnroll", null); + + if ((certAuthEnrollOn != null) && (certAuthEnrollOn.equals("on"))) { + certAuthEnroll = true; + CMS.debug("HashEnrollServlet: certAuthEnroll is on"); + } + + String certauthEnrollType = null; + + if (certAuthEnroll == true) { + certauthEnrollType = + httpParams.getValueAsString("certauthEnrollType", null); + if (certauthEnrollType != null) { + if (certauthEnrollType.equals("dual")) { + CMS.debug("HashEnrollServlet: certauthEnrollType is dual"); + } else if (certauthEnrollType.equals("encryption")) { + CMS.debug("HashEnrollServlet: certauthEnrollType is encryption"); + } else if (certauthEnrollType.equals("single")) { + CMS.debug("HashEnrollServlet: certauthEnrollType is single"); + } else { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_INVALID_CERTAUTH_ENROLL_TYPE_1", certauthEnrollType)); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_INVALID_CERTAUTH_ENROLL_TYPE")); + } + } else { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_CERTAUTH_ENROLL_TYPE")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_MISSING_CERTAUTH_ENROLL_TYPE")); + } + } + + String challengePassword = httpParams.getValueAsString("challengePassword", ""); + + cmsReq.setIRequest(req); + saveHttpHeaders(httpReq, req); + saveHttpParams(httpParams, req); + IAuthToken token = authenticate(cmsReq); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, token, + mAuthzResourceName, "import"); + } catch (Exception e) { + // do nothing for now + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + X509Certificate sslClientCert = null; + // cert auth enroll + String certBasedOldSubjectDN = null; + BigInteger certBasedOldSerialNum = null; + + // check if request was authenticated, if so set authtoken & certInfo. + // also if authenticated, take certInfo from authToken. + X509CertInfo certInfo = null; + + if (certAuthEnroll == true) { + sslClientCert = getSSLClientCertificate(httpReq); + if (sslClientCert == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_MISSING_SSL_CLIENT_CERT")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_MISSING_SSL_CLIENT_CERT")); + } + + certBasedOldSubjectDN = (String) sslClientCert.getSubjectDN().toString(); + certBasedOldSerialNum = (BigInteger) sslClientCert.getSerialNumber(); + try { + certInfo = (X509CertInfo) + ((X509CertImpl) sslClientCert).get( + X509CertImpl.NAME + "." + X509CertImpl.INFO); + } catch (CertificateParsingException ex) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_CERTINFO_ENCRYPT_CERT")); + throw new ECMSGWException( + CMS.getUserMessage(getLocale(httpReq), "CMS_GW_MISSING_CERTINFO")); + } + } else { + certInfo = CMS.getDefaultX509CertInfo(); + } + + X509CertInfo[] certInfoArray = new X509CertInfo[] { certInfo }; + + //AuthToken authToken = access.getAuthToken(); + IConfigStore configStore = CMS.getConfigStore(); + String val = configStore.getString("hashDirEnrollment.name"); + IAuthSubsystem authSS = (IAuthSubsystem) + CMS.getSubsystem(CMS.SUBSYSTEM_AUTH); + IAuthManager authMgr1 = authSS.get(val); + HashAuthentication mgr = (HashAuthentication) authMgr1; + String pageID = httpParams.getValueAsString("pageID", null); + + IAuthToken authToken = mgr.getAuthToken(pageID); + + String authMgr = AuditFormat.NOAUTH; + + if (authToken == null) { + printError(cmsReq, "3"); + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } else { + authMgr = + authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME); + // don't store agent token in request. + // agent currently used for bulk issuance. + // if (!authMgr.equals(IAuthSubsystem.CERTUSERDB_AUTHMGR_ID)) { + log(ILogger.LL_INFO, + "Enrollment request was authenticated by " + + authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME)); + fillCertInfoFromAuthToken(certInfo, authToken); + // save authtoken attrs to request directly (for policy use) + saveAuthToken(authToken, req); + // req.set(IRequest.AUTH_TOKEN, authToken); + // } + } + + // support Enterprise 3.5.1 server where CERT_TYPE=csrCertType + // instead of certType + String certType = httpParams.getValueAsString(OLD_CERT_TYPE, null); + if (certType == null) { + certType = httpParams.getValueAsString(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 here. + req.setExtData(IRequest.HTTP_PARAMS, CERT_TYPE, certType); + } + + String crmf = + httpParams.getValueAsString(CRMF_REQUEST, null); + + if (certAuthEnroll == true) { + + fillCertInfoFromAuthToken(certInfo, authToken); + + // for dual certs + if (certauthEnrollType.equals(CERT_AUTH_DUAL)) { + if (mCa == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_NOT_A_CA")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_NOT_A_CA")); + } + + // first, make sure the client cert is indeed a + // signing only cert + if ((CMS.isSigningCert((X509CertImpl) sslClientCert) == + false) || + ((CMS.isSigningCert((X509CertImpl) sslClientCert) == + true) && + (CMS.isEncryptionCert((X509CertImpl) sslClientCert) == + true))) { + // either it's not a signing cert, or it's a dual cert + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_INVALID_CERT_TYPE")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_INVALID_CERT_TYPE")); + } + X509Key key = null; + + // for signing cert + key = (X509Key) sslClientCert.getPublicKey(); + try { + certInfo.set(X509CertInfo.KEY, new CertificateX509Key(key)); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAILED_SET_KEY_FROM_CERT_AUTH_ENROLL_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_KEY_FROM_CERT_AUTH_ENROLL_FAILED", e.toString())); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAILED_SET_KEY_FROM_CERT_AUTH_ENROLL_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_KEY_FROM_CERT_AUTH_ENROLL_FAILED", e.toString())); + } + + String filter = + "(&(x509cert.subject=" + + certBasedOldSubjectDN + ")(!(x509cert.serialNumber=" + certBasedOldSerialNum + + "))(certStatus=VALID))"; + ICertRecordList list = + (ICertRecordList) mCa.getCertificateRepository().findCertRecordsInList(filter, + null, 10); + int size = list.getSize(); + Enumeration en = list.getCertRecords(0, size - 1); + boolean gotEncCert = false; + + if (!en.hasMoreElements()) { + // pairing encryption cert not found + } else { + X509CertInfo encCertInfo = CMS.getDefaultX509CertInfo(); + X509CertInfo[] cInfoArray = new X509CertInfo[] { certInfo, + encCertInfo }; + int i = 1; + + while (en.hasMoreElements()) { + ICertRecord record = en.nextElement(); + X509CertImpl cert = record.getCertificate(); + + // if not encryption cert only, try next one + if ((CMS.isEncryptionCert(cert) == false) || + ((CMS.isEncryptionCert(cert) == true) && + (CMS.isSigningCert(cert) == true))) { + continue; + } + + key = (X509Key) cert.getPublicKey(); + try { + encCertInfo = (X509CertInfo) + cert.get( + X509CertImpl.NAME + "." + X509CertImpl.INFO); + + } catch (CertificateParsingException ex) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_CERTINFO_ENCRYPT_CERT")); + throw new ECMSGWException( + CMS.getUserMessage(getLocale(httpReq), "CMS_GW_MISSING_CERTINFO")); + } + + try { + encCertInfo.set(X509CertInfo.KEY, new CertificateX509Key(key)); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAILED_SET_KEY_FROM_CERT_AUTH_ENROLL_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_KEY_FROM_CERT_AUTH_ENROLL_FAILED", e.toString())); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAILED_SET_KEY_FROM_CERT_AUTH_ENROLL_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SET_KEY_FROM_CERT_AUTH_ENROLL_FAILED", e.toString())); + } + fillCertInfoFromAuthToken(encCertInfo, authToken); + + cInfoArray[i++] = encCertInfo; + certInfoArray = cInfoArray; + gotEncCert = true; + break; + } + } + + if (gotEncCert == false) { + // encryption cert not found, bail + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ENCRYPTION_CERT_NOT_FOUND")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_ENCRYPTION_CERT_NOT_FOUND")); + } + } else if (certauthEnrollType.equals(CERT_AUTH_ENCRYPTION)) { + // first, make sure the client cert is indeed a + // signing only cert + if ((CMS.isSigningCert((X509CertImpl) sslClientCert) == + false) || + ((CMS.isSigningCert((X509CertImpl) sslClientCert) == + true) && + (CMS.isEncryptionCert((X509CertImpl) sslClientCert) == + true))) { + // either it's not a signing cert, or it's a dual cert + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_INVALID_CERT_TYPE")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_INVALID_CERT_TYPE")); + } + + /* + * crmf + */ + if (crmf != null && crmf != "") { + certInfoArray = fillCRMF(crmf, authToken, httpParams, req); + req.setExtData(CLIENT_ISSUER, + sslClientCert.getIssuerDN().toString()); + CMS.debug( + "HashEnrollServlet: sslClientCert issuerDN = " + sslClientCert.getIssuerDN().toString()); + } else { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_KEYGEN_INFO")); + throw new ECMSGWException(CMS.getUserMessage(getLocale(httpReq), + "CMS_GW_MISSING_KEYGEN_INFO")); + } + } else if (certauthEnrollType.equals(CERT_AUTH_SINGLE)) { + // have to be buried here to handle the issuer + + if (crmf != null && crmf != "") { + certInfoArray = fillCRMF(crmf, authToken, httpParams, req); + } else { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_KEYGEN_INFO")); + throw new ECMSGWException(CMS.getUserMessage(getLocale(httpReq), + "CMS_GW_MISSING_KEYGEN_INFO")); + } + req.setExtData(CLIENT_ISSUER, + sslClientCert.getIssuerDN().toString()); + } + } else if (crmf != null && crmf != "") { + certInfoArray = fillCRMF(crmf, authToken, httpParams, req); + } else { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_KEYGEN_INFO")); + throw new ECMSGWException(CMS.getUserMessage(getLocale(httpReq), + "CMS_GW_MISSING_KEYGEN_INFO")); + } + + req.setExtData(IRequest.CERT_INFO, certInfoArray); + + if (challengePassword != null && !challengePassword.equals("")) { + String pwd = hashPassword(challengePassword); + + req.setExtData(CHALLENGE_PASSWORD, pwd); + } + + // send request to request queue. + mRequestQueue.processRequest(req); + // process result. + + // render OLD_CERT_TYPE's response differently, we + // dont want any javascript in HTML, and need to + // override the default render. + if (httpParams.getValueAsString(OLD_CERT_TYPE, null) != null) { + try { + renderServerEnrollResult(cmsReq); + cmsReq.setStatus(CMSRequest.SUCCESS); // no default render + } catch (IOException ex) { + cmsReq.setStatus(CMSRequest.ERROR); + } + return; + } + + //for audit log + String initiative = null; + String agentID = null; + + if (!authMgr.equals(IAuthSubsystem.CERTUSERDB_AUTHMGR_ID)) { + // request is from eegateway, so fromUser. + initiative = AuditFormat.FROMUSER; + } else { + agentID = authToken.getInString("userid"); + initiative = AuditFormat.FROMAGENT + " agentID: " + agentID; + } + + // if service not complete return standard templates. + RequestStatus status = req.getRequestStatus(); + + if (status != RequestStatus.COMPLETE) { + cmsReq.setIRequestStatus(); // set status acc. to IRequest status. + // audit log the status + try { + if (status == RequestStatus.REJECTED) { + Vector messages = req.getExtDataInStringVector(IRequest.ERRORS); + + if (messages != null) { + Enumeration msgs = messages.elements(); + StringBuffer wholeMsg = new StringBuffer(); + + while (msgs.hasMoreElements()) { + wholeMsg.append("\n"); + wholeMsg.append(msgs.nextElement()); + } + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.ENROLLMENTFORMAT, + new Object[] { + req.getRequestId(), + initiative, + authMgr, + status.toString(), + certInfo.get(X509CertInfo.SUBJECT), + " violation: " + + wholeMsg.toString() }, + ILogger.L_MULTILINE + ); + } else { // no policy violation, from agent + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.ENROLLMENTFORMAT, + new Object[] { + req.getRequestId(), + initiative, + authMgr, + status.toString(), + certInfo.get(X509CertInfo.SUBJECT), "" } + ); + } + } else { // other imcomplete status + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.ENROLLMENTFORMAT, + new Object[] { + req.getRequestId(), + initiative, + authMgr, + status.toString(), + certInfo.get(X509CertInfo.SUBJECT), "" } + ); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CANT_GET_CERT_SUBJ_AUDITING", e.toString())); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CANT_GET_CERT_SUBJ_AUDITING", e.toString())); + } + return; + } + // if service error use standard error templates. + Integer result = req.getExtDataInInteger(IRequest.RESULT); + + if (result.equals(IRequest.RES_ERROR)) { + + cmsReq.setStatus(CMSRequest.ERROR); + cmsReq.setError(req.getExtDataInString(IRequest.ERROR)); + String[] svcErrors = + req.getExtDataInStringArray(IRequest.SVCERRORS); + + if (svcErrors != null && svcErrors.length > 0) { + for (int i = 0; i < svcErrors.length; i++) { + String err = svcErrors[i]; + + if (err != null) { + //System.out.println( + //"revocation servlet: setting error description "+ + //err.toString()); + cmsReq.setErrorDescription(err); + // audit log the error + try { + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.ENROLLMENTFORMAT, + new Object[] { + req.getRequestId(), + initiative, + authMgr, + "completed with error: " + + err, + certInfo.get(X509CertInfo.SUBJECT), "" } + ); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CANT_GET_CERT_SUBJ_AUDITING", + e.toString())); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CANT_GET_CERT_SUBJ_AUDITING", + e.toString())); + } + } + } + } + return; + } + + // service success + cmsReq.setStatus(CMSRequest.SUCCESS); + X509CertImpl[] issuedCerts = + req.getExtDataInCertArray(IRequest.ISSUED_CERTS); + + // audit log the success. + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.ENROLLMENTFORMAT, + new Object[] { + req.getRequestId(), + initiative, + authMgr, + "completed", + issuedCerts[0].getSubjectDN(), + "cert issued serial number: 0x" + + issuedCerts[0].getSerialNumber().toString(16) } + ); + + // return cert as mime type binary if requested. + if (checkImportCertToNav( + cmsReq.getHttpResp(), httpParams, issuedCerts[0])) { + cmsReq.setStatus(CMSRequest.SUCCESS); + return; + } + + // use success template. + try { + cmsReq.setResult(issuedCerts); + renderTemplate(cmsReq, mEnrollSuccessTemplate, + mEnrollSuccessFiller); + cmsReq.setStatus(CMSRequest.SUCCESS); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_TEMP_REND_ERR", mEnrollSuccessFiller.toString(), e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_RETURNING_RESULT_ERROR")); + } + return; + } + + /** + * 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. + */ + protected 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. + + // 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_1", + 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")); + } + } + + protected X509CertInfo[] fillCRMF( + String crmf, IAuthToken authToken, IArgBlock httpParams, IRequest req) + throws EBaseException { + 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); + + /* + if (certReqMsg.hasPop()) { + try { + certReqMsg.verify(); + } catch (ChallengeResponseException ex) { + // create and save the challenge + // construct the cmmf message together + // in a sequence to challenge the requestor + } catch (Exception e) { + // failed, should only affect one request + } + } + */ + CertRequest certReq = certReqMsg.getCertReq(); + INTEGER certReqId = certReq.getCertReqId(); + int srcId = certReqId.intValue(); + + req.setExtData(IRequest.CRMF_REQID, String.valueOf(srcId)); + + 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); + } + + certInfoArray[i] = certInfo; + } + + do_testbed_hack(nummsgs, certInfoArray, httpParams); + + return certInfoArray; + } 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( + CMS.getUserMessage("CMS_GW_CRMF_TO_CERTINFO_ERROR")); + } 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")); + } + } + + protected void renderServerEnrollResult(CMSRequest cmsReq) throws + IOException { + HttpServletResponse httpResp = cmsReq.getHttpResp(); + + httpResp.setContentType("text/html"); + ServletOutputStream out = null; + + out = httpResp.getOutputStream(); + + // get template based on request status + out.println(""); + out.println(""); + out.println("Server Enrollment"); + out.println(""); + // out.println(""); + + if (cmsReq.getIRequest().getRequestStatus().equals(RequestStatus.COMPLETE)) { + out.println("

    "); + out.println("SUCCESS"); + out.println("

    "); + out.println("Your request is submitted and approved. Please cut and paste the certificate into your server."); // XXX - localize the message + out.println("

    "); + out.println("Request Creation Time: "); + out.println(cmsReq.getIRequest().getCreationTime().toString()); + out.println("

    "); + out.println("Request Status: "); + out.println(cmsReq.getStatus().toString()); + out.println("

    "); + out.println("Request ID: "); + out.println(cmsReq.getIRequest().getRequestId().toString()); + out.println("

    "); + out.println("Certificate: "); + out.println("

    "); + out.println("

    ");
    +            X509CertImpl certs[] =
    +                    cmsReq.getIRequest().getExtDataInCertArray(IRequest.ISSUED_CERTS);
    +
    +            out.println(CMS.getEncodedCert(certs[0]));
    +            out.println("
    "); + out.println("

    "); + out.println(""); + out.println(""); + out.println(""); + out.println(""); + } else if (cmsReq.getIRequest().getRequestStatus().equals(RequestStatus.PENDING)) { + out.println("

    "); + out.println("PENDING"); + out.println("

    "); + out.println("Your request is submitted. You can check on the status of your request with an authorized agent or local administrator by referring to the request ID."); // XXX - localize the message + out.println("

    "); + out.println("Request Creation Time: "); + out.println(cmsReq.getIRequest().getCreationTime().toString()); + out.println("

    "); + out.println("Request Status: "); + out.println(cmsReq.getStatus().toString()); + out.println("

    "); + out.println("Request ID: "); + out.println(cmsReq.getIRequest().getRequestId().toString()); + out.println("

    "); + out.println(""); + out.println(""); + out.println(""); + } else { + out.println("

    "); + out.println("ERROR"); + out.println("

    "); + out.println(""); + out.println("Please consult your local administrator for assistance."); // XXX - localize the message + out.println(""); + out.println("

    "); + out.println("Request Status: "); + out.println(cmsReq.getStatus().toString()); + out.println("

    "); + out.println("Error: "); + out.println(cmsReq.getError()); // XXX - need to parse in Locale + out.println("

    "); + out.println(""); + out.println(""); + } + + /** + * // include all the input data + * IArgBlock args = cmsReq.getHttpParams(); + * Enumeration ele = args.getElements(); + * while (ele.hasMoreElements()) { + * String eleT = (String)ele.nextElement(); + * out.println(""); + * } + **/ + + out.println(""); + } + + // XXX ALERT !! + // Remove the following and calls to them when we bundle a cartman + // later than alpha1. + // These are here to cover up problem in cartman where the + // key usage extension always ends up being digital signature only + // and for rsa-ex ends up having no bits set. + + private boolean mIsTestBed = false; + + private void init_testbed_hack(IConfigStore config) + throws EBaseException { + mIsTestBed = config.getBoolean("isTestBed", true); + } + + private void do_testbed_hack( + int nummsgs, X509CertInfo[] certinfo, IArgBlock httpParams) + throws EBaseException { + if (!mIsTestBed) + return; + + // get around bug in cartman - bits are off by one byte. + for (int i = 0; i < certinfo.length; i++) { + try { + X509CertInfo cert = certinfo[i]; + CertificateExtensions exts = (CertificateExtensions) + cert.get(CertificateExtensions.NAME); + + if (exts == null) { + // should not happen. + continue; + } + KeyUsageExtension ext = (KeyUsageExtension) + exts.get(KeyUsageExtension.NAME); + + if (ext == null) + // should not happen + continue; + byte[] value = ext.getExtensionValue(); + + if (value[0] == 0x03 && value[1] == 0x02 && value[2] == 0x07) { + byte[] newvalue = new byte[value.length + 1]; + + newvalue[0] = 0x03; + newvalue[1] = 0x03; + newvalue[2] = 0x07; + newvalue[3] = value[3]; + // force encryption certs to have digitial signature + // set too so smime can find the cert for encryption. + if (value[3] == 0x20) { + + /* + newvalue[3] = 0x3f; + newvalue[4] = (byte)0x80; + */ + if (httpParams.getValueAsBoolean( + "dual-use-hack", true)) { + newvalue[3] = (byte) 0xE0; // same as rsa-dual-use. + } + } + newvalue[4] = 0; + KeyUsageExtension newext = + new KeyUsageExtension(Boolean.valueOf(true), + (Object) newvalue); + + exts.delete(KeyUsageExtension.NAME); + exts.set(KeyUsageExtension.NAME, newext); + } + } catch (IOException e) { + // should never happen + continue; + } catch (CertificateException e) { + // should never happen + continue; + } + } + + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/ImportCertsTemplateFiller.java b/base/common/src/com/netscape/cms/servlet/cert/ImportCertsTemplateFiller.java new file mode 100644 index 000000000..2f551d3f5 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/ImportCertsTemplateFiller.java @@ -0,0 +1,381 @@ +// --- 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.cert; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.StringReader; +import java.io.StringWriter; +import java.math.BigInteger; +import java.security.NoSuchAlgorithmException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.Locale; + +import javax.servlet.http.HttpServletRequest; + +import netscape.security.pkcs.ContentInfo; +import netscape.security.pkcs.PKCS7; +import netscape.security.pkcs.SignerInfo; +import netscape.security.x509.AlgorithmId; +import netscape.security.x509.CertificateChain; +import netscape.security.x509.X509CertImpl; + +import org.mozilla.jss.asn1.INTEGER; +import org.mozilla.jss.pkix.cmmf.CertOrEncCert; +import org.mozilla.jss.pkix.cmmf.CertRepContent; +import org.mozilla.jss.pkix.cmmf.CertResponse; +import org.mozilla.jss.pkix.cmmf.CertifiedKeyPair; +import org.mozilla.jss.pkix.cmmf.PKIStatusInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authority.IAuthority; +import com.netscape.certsrv.authority.ICertAuthority; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.ICertPrettyPrint; +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.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; +import com.netscape.cms.servlet.common.ICMSTemplateFiller; +import com.netscape.cmsutil.util.Utils; + +/** + * Set up HTTP response to import certificate into browsers + * + * The result must have been populate with the set of certificates + * to return. + * + *

    + * inputs: certtype.
    + * outputs: 
    + * 	- cert type from http input (if any)
    + *      - CA chain 
    + * 	- authority name (RM, CM, DRM)
    + *      - scheme:host:port of server.
    + *  array of one or more 
    + *      - cert serial number
    + *      - cert pretty print
    + * 	- cert in base 64 encoding.
    + * 	- cmmf blob to import
    + * 
    + * + * @version $Revision$, $Date$ + */ +public class ImportCertsTemplateFiller implements ICMSTemplateFiller { + public static final String CRMF_REQID = "crmfReqId"; + public static final String ISSUED_CERT_SERIAL = "serialNo"; + public static final String CERT_TYPE = "certType"; + public static final String BASE64_CERT = "base64Cert"; + public static final String CERT_PRETTYPRINT = "certPrettyPrint"; + public static final String CERT_FINGERPRINT = "certFingerprint"; // cisco + public static final String CERT_NICKNAME = "certNickname"; + public static final String CMMF_RESP = "cmmfResponse"; + public static final String PKCS7_RESP = "pkcs7ChainBase64"; // for MSIE + + public ImportCertsTemplateFiller() { + } + + /** + * @param cmsReq CMS Request + * @param authority this authority + * @param locale locale of template. + * @param e unexpected exception e. ignored. + */ + public CMSTemplateParams getTemplateParams( + CMSRequest cmsReq, IAuthority authority, Locale locale, Exception e) + throws Exception { + Certificate[] certs = (Certificate[]) cmsReq.getResult(); + + if (certs instanceof X509CertImpl[]) + return getX509TemplateParams(cmsReq, authority, locale, e); + else + return null; + } + + public CMSTemplateParams getX509TemplateParams( + CMSRequest cmsReq, IAuthority authority, Locale locale, Exception e) + throws Exception { + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams params = new CMSTemplateParams(header, fixed); + + // set host name and port. + HttpServletRequest httpReq = cmsReq.getHttpReq(); + String host = httpReq.getServerName(); + int port = httpReq.getServerPort(); + String scheme = httpReq.getScheme(); + String format = httpReq.getParameter("format"); + if (format != null && format.equals("cmc")) + fixed.set("importCMC", "false"); + String agentPort = "" + port; + fixed.set("agentHost", host); + fixed.set("agentPort", agentPort); + fixed.set(ICMSTemplateFiller.HOST, host); + fixed.set(ICMSTemplateFiller.PORT, Integer.valueOf(port)); + fixed.set(ICMSTemplateFiller.SCHEME, scheme); + IRequest r = cmsReq.getIRequest(); + + if (r != null) { + fixed.set(ICMSTemplateFiller.REQUEST_ID, r.getRequestId().toString()); + } + + // set key record (if KRA enabled) + if (r != null) { + BigInteger keyRecSerialNo = r.getExtDataInBigInteger("keyRecord"); + + if (keyRecSerialNo != null) { + fixed.set(ICMSTemplateFiller.KEYREC_ID, keyRecSerialNo.toString()); + } + } + + // set cert type. + IArgBlock httpParams = cmsReq.getHttpParams(); + String certType = + httpParams.getValueAsString(CERT_TYPE, null); + + if (certType != null) + fixed.set(CERT_TYPE, certType); + + // this authority + fixed.set(ICMSTemplateFiller.AUTHORITY, + (String) authority.getOfficialName()); + + // CA chain. + CertificateChain cachain = + ((ICertAuthority) authority).getCACertChain(); + X509Certificate[] cacerts = cachain.getChain(); + + String replyTo = httpParams.getValueAsString("replyTo", null); + + if (replyTo != null) + fixed.set("replyTo", replyTo); + + // set user + CA cert chain and pkcs7 for MSIE. + X509CertImpl[] userChain = new X509CertImpl[cacerts.length + 1]; + int m = 1, n = 0; + + for (; n < cacerts.length; m++, n++) + userChain[m] = (X509CertImpl) cacerts[n]; + + // certs. + X509CertImpl[] certs = (X509CertImpl[]) cmsReq.getResult(); + + // expose CRMF request id + String crmfReqId = cmsReq.getExtData(IRequest.CRMF_REQID); + + if (crmfReqId == null) { + crmfReqId = (String) cmsReq.getResult( + IRequest.CRMF_REQID); + } + if (crmfReqId != null) { + fixed.set(CRMF_REQID, crmfReqId); + } + + // set CA certs in cmmf, initialize CertRepContent + // note cartman can't trust ca certs yet but it'll import them. + // also set cert nickname for cartman. + CertRepContent certRepContent = null; + + if (CMSServlet.doCMMFResponse(httpParams)) { + byte[][] caPubs = new byte[cacerts.length][]; + + for (int j = 0; j < cacerts.length; j++) + caPubs[j] = ((X509CertImpl) cacerts[j]).getEncoded(); + certRepContent = new CertRepContent(caPubs); + + String certnickname = + cmsReq.getHttpParams().getValueAsString(CERT_NICKNAME, null); + + // if nickname is not requested set to subject name by default. + if (certnickname == null) + fixed.set(CERT_NICKNAME, certs[0].getSubjectDN().toString()); + else + fixed.set(CERT_NICKNAME, certnickname); + } + + // make pkcs7 for MSIE + if (CMSServlet.clientIsMSIE(cmsReq.getHttpReq()) && + (certType == null || certType.equals("client"))) { + userChain[0] = certs[0]; + PKCS7 p7 = new PKCS7(new AlgorithmId[0], + new ContentInfo(new byte[0]), + userChain, + new SignerInfo[0]); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + p7.encodeSignedData(bos); + byte[] p7Bytes = bos.toByteArray(); + // String p7Str = encoder.encodeBuffer(p7Bytes); + String p7Str = CMS.BtoA(p7Bytes); + + header.set(PKCS7_RESP, p7Str); + } + + // set base 64, pretty print and cmmf response for each issued cert. + for (int i = 0; i < certs.length; i++) { + IArgBlock repeat = CMS.createArgBlock(); + X509CertImpl cert = certs[i]; + + // set serial number. + BigInteger serialNo = + ((X509Certificate) cert).getSerialNumber(); + + repeat.addBigIntegerValue(ISSUED_CERT_SERIAL, serialNo, 16); + + // set base64 encoded blob. + byte[] certEncoded = cert.getEncoded(); + // String b64 = encoder.encodeBuffer(certEncoded); + String b64 = CMS.BtoA(certEncoded); + String b64cert = "-----BEGIN CERTIFICATE-----\n" + + b64 + "\n-----END CERTIFICATE-----"; + + repeat.set(BASE64_CERT, b64cert); + + // set cert pretty print. + + String prettyPrintRequested = + cmsReq.getHttpParams().getValueAsString(CERT_PRETTYPRINT, null); + + if (prettyPrintRequested == null) { + prettyPrintRequested = "true"; + } + String ppStr = ""; + + if (!prettyPrintRequested.equals("false")) { + ICertPrettyPrint pp = CMS.getCertPrettyPrint(cert); + + ppStr = pp.toString(locale); + } + repeat.set(CERT_PRETTYPRINT, ppStr); + + // Now formulate a PKCS#7 blob + X509CertImpl[] certsInChain = new X509CertImpl[1]; + ; + if (cacerts != null) { + for (int j = 0; j < cacerts.length; j++) { + if (cert.equals(cacerts[j])) { + certsInChain = new + X509CertImpl[cacerts.length]; + break; + } + certsInChain = new X509CertImpl[cacerts.length + 1]; + } + } + + // Set the EE cert + certsInChain[0] = cert; + + // Set the Ca certificate chain + if (cacerts != null) { + for (int j = 0; j < cacerts.length; j++) { + if (!cert.equals(cacerts[j])) + certsInChain[j + 1] = (X509CertImpl) cacerts[j]; + } + } + // Wrap the chain into a degenerate P7 object + String p7Str; + + try { + PKCS7 p7 = new PKCS7(new AlgorithmId[0], + new ContentInfo(new byte[0]), + certsInChain, + new SignerInfo[0]); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + p7.encodeSignedData(bos); + byte[] p7Bytes = bos.toByteArray(); + + //p7Str = encoder.encodeBuffer(p7Bytes); + p7Str = CMS.BtoA(p7Bytes); + repeat.addStringValue("pkcs7ChainBase64", p7Str); + } catch (Exception ex) { + //p7Str = "PKCS#7 B64 Encoding error - " + ex.toString() + //+ "; Please contact your administrator"; + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_FORMING_PKCS7_ERROR")); + } + + // set cert fingerprint (for Cisco routers) + String fingerprint = null; + + try { + fingerprint = CMS.getFingerPrints(cert); + } catch (CertificateEncodingException ex) { + // should never happen + throw new EBaseException( + CMS.getUserMessage(locale, "CMS_BASE_INTERNAL_ERROR", ex.toString())); + } catch (NoSuchAlgorithmException ex) { + // should never happen + throw new EBaseException( + CMS.getUserMessage(locale, "CMS_BASE_INTERNAL_ERROR", ex.toString())); + } + if (fingerprint != null && fingerprint.length() > 0) + repeat.set(CERT_FINGERPRINT, fingerprint); + + // cmmf response for this cert. + if (CMSServlet.doCMMFResponse(httpParams) && crmfReqId != null && + (certType == null || certType.equals("client"))) { + PKIStatusInfo status = new PKIStatusInfo(PKIStatusInfo.granted); + CertifiedKeyPair certifiedKP = + new CertifiedKeyPair(new CertOrEncCert(certEncoded)); + CertResponse resp = + new CertResponse(new INTEGER(crmfReqId), status, + certifiedKP); + + certRepContent.addCertResponse(resp); + } + + params.addRepeatRecord(repeat); + } + + // if cartman set whole cmmf response (CertRepContent) string. + if (CMSServlet.doCMMFResponse(httpParams)) { + ByteArrayOutputStream certRepOut = new ByteArrayOutputStream(); + + certRepContent.encode(certRepOut); + byte[] certRepBytes = certRepOut.toByteArray(); + String certRepB64 = Utils.base64encode(certRepBytes); + // add CR to each return as required by cartman + BufferedReader certRepB64lines = + new BufferedReader(new StringReader(certRepB64)); + StringWriter certRepStringOut = new StringWriter(); + String oneLine = null; + boolean first = true; + + while ((oneLine = certRepB64lines.readLine()) != null) { + if (first) { + //certRepStringOut.write("\""+oneLine+"\""); + certRepStringOut.write(oneLine); + first = false; + } else { + //certRepStringOut.write("+\"\\n"+oneLine+"\""); + certRepStringOut.write("\n" + oneLine); + } + } + String certRepString = certRepStringOut.toString(); + + fixed.set(CMMF_RESP, certRepString); + } + + return params; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/ListCerts.java b/base/common/src/com/netscape/cms/servlet/cert/ListCerts.java new file mode 100644 index 000000000..b93a82fb8 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/ListCerts.java @@ -0,0 +1,672 @@ +// --- 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.cert; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.PublicKey; +import java.util.Enumeration; +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.provider.RSAPublicKey; +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.CRLReasonExtension; +import netscape.security.x509.CertificateX509Key; +import netscape.security.x509.Extension; +import netscape.security.x509.X500Name; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509Key; + +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertRecordList; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.dbs.certdb.IRevocationInfo; +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.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Retrieve a paged list of certs matching the specified query + * + * @version $Revision$, $Date$ + */ +public class ListCerts extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = -3568155814023099576L; + private final static String TPL_FILE = "queryCert.template"; + private final static BigInteger MINUS_ONE = new BigInteger("-1"); + + private final static String USE_CLIENT_FILTER = "useClientFilter"; + private final static String ALLOWED_CLIENT_FILTERS = "allowedClientFilters"; + + private ICertificateRepository mCertDB = null; + private X500Name mAuthName = null; + private String mFormPath = null; + private boolean mReverse = false; + private boolean mHardJumpTo = false; //jump to the end + private String mDirection = null; + private boolean mUseClientFilter = false; + private Vector mAllowedClientFilters = new Vector(); + private int mMaxReturns = 2000; + + /** + * Constructs query key servlet. + */ + public ListCerts() { + super(); + } + + /** + * initialize the servlet. This servlet uses the template file + * "queryCert.template" to render the response + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + // override success to render own template. + mTemplates.remove(CMSRequest.SUCCESS); + + if (mAuthority instanceof ICertificateAuthority) { + ICertificateAuthority ca = (ICertificateAuthority) mAuthority; + + mCertDB = ca.getCertificateRepository(); + mAuthName = ca.getX500Name(); + } + + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + if (mOutputTemplatePath != null) + mFormPath = mOutputTemplatePath; + + try { + mMaxReturns = Integer.parseInt(sc.getInitParameter("maxResults")); + } catch (Exception e) { + /* do nothing, just use the default if integer parsing failed */ + } + + /* useClientFilter should be off by default. We keep + this parameter around so that we do not break + the client applications that submits raw LDAP + filter into this servlet. */ + if (sc.getInitParameter(USE_CLIENT_FILTER) != null && + sc.getInitParameter(USE_CLIENT_FILTER).equalsIgnoreCase("true")) { + mUseClientFilter = true; + } + if (sc.getInitParameter(ALLOWED_CLIENT_FILTERS) == null + || sc.getInitParameter(ALLOWED_CLIENT_FILTERS).equals("")) { + mAllowedClientFilters.addElement("(certStatus=*)"); + mAllowedClientFilters.addElement("(certStatus=VALID)"); + mAllowedClientFilters.addElement("(|(certStatus=VALID)(certStatus=INVALID)(certStatus=EXPIRED))"); + mAllowedClientFilters.addElement("(|(certStatus=VALID)(certStatus=REVOKED))"); + } else { + StringTokenizer st = new StringTokenizer(sc.getInitParameter(ALLOWED_CLIENT_FILTERS), ","); + while (st.hasMoreTokens()) { + mAllowedClientFilters.addElement(st.nextToken()); + } + } + } + + public String buildFilter(HttpServletRequest req) { + String queryCertFilter = req.getParameter("queryCertFilter"); + + com.netscape.certsrv.apps.CMS.debug("client queryCertFilter=" + queryCertFilter); + + if (mUseClientFilter) { + com.netscape.certsrv.apps.CMS.debug("useClientFilter=true"); + Enumeration filters = mAllowedClientFilters.elements(); + // check to see if the filter is allowed + while (filters.hasMoreElements()) { + String filter = (String) filters.nextElement(); + com.netscape.certsrv.apps.CMS.debug("Comparing filter=" + + filter + " queryCertFilter=" + queryCertFilter); + if (filter.equals(queryCertFilter)) { + return queryCertFilter; + } + } + com.netscape.certsrv.apps.CMS.debug("Requested filter '" + + queryCertFilter + "' is not allowed. Please check the " + ALLOWED_CLIENT_FILTERS + "parameter"); + return null; + } else { + com.netscape.certsrv.apps.CMS.debug("useClientFilter=false"); + } + + boolean skipRevoked = false; + boolean skipNonValid = false; + if (req.getParameter("skipRevoked") != null && + req.getParameter("skipRevoked").equals("on")) { + skipRevoked = true; + } + if (req.getParameter("skipNonValid") != null && + req.getParameter("skipNonValid").equals("on")) { + skipNonValid = true; + } + + if (!skipRevoked && !skipNonValid) { + queryCertFilter = "(certStatus=*)"; + } else if (skipRevoked && skipNonValid) { + queryCertFilter = "(certStatus=VALID)"; + } else if (skipRevoked) { + queryCertFilter = "(|(certStatus=VALID)(certStatus=INVALID)(certStatus=EXPIRED))"; + } else if (skipNonValid) { + queryCertFilter = "(|(certStatus=VALID)(certStatus=REVOKED))"; + } + return queryCertFilter; + } + + /** + * Process the HTTP request. + *
      + *
    • http.param maxCount Number of certificates to show + *
    • http.param queryFilter and ldap style filter specifying the certificates to show + *
    • http.param querySentinelDown the serial number of the first certificate to show (default decimal, or hex if + * prefixed with 0x) when paging down + *
    • http.param querySentinelUp the serial number of the first certificate to show (default decimal, or hex if + * prefixed with 0x) when paging up + *
    • http.param direction "up", "down", "begin", or "end" + *
    + */ + public void process(CMSRequest cmsReq) throws EBaseException { + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "list"); + } catch (Exception e) { + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + String revokeAll = null; + EBaseException error = null; + + int maxCount = -1; + BigInteger sentinel = new BigInteger("0"); + + IArgBlock header = com.netscape.certsrv.apps.CMS.createArgBlock(); + IArgBlock ctx = com.netscape.certsrv.apps.CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, ctx); + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, req, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + com.netscape.certsrv.apps.CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", mFormPath, e.toString())); + throw new ECMSGWException( + com.netscape.certsrv.apps.CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + mHardJumpTo = false; + try { + + if (req.getParameter("direction") != null) { + mDirection = req.getParameter("direction").trim(); + mReverse = mDirection.equals("up"); + if (mReverse) + com.netscape.certsrv.apps.CMS.debug("reverse is true"); + else + com.netscape.certsrv.apps.CMS.debug("reverse is false"); + + } + + if (req.getParameter("maxCount") != null) { + maxCount = Integer.parseInt(req.getParameter("maxCount")); + } + if (maxCount == -1 || maxCount > mMaxReturns) { + com.netscape.certsrv.apps.CMS.debug("Resetting page size from " + maxCount + " to " + mMaxReturns); + maxCount = mMaxReturns; + } + + String sentinelStr = ""; + if (mReverse) { + sentinelStr = req.getParameter("querySentinelUp"); + } else if (mDirection.equals("end")) { + // this servlet will figure out the end + sentinelStr = "0"; + mReverse = true; + mHardJumpTo = true; + } else if (mDirection.equals("down")) { + sentinelStr = req.getParameter("querySentinelDown"); + } else + sentinelStr = "0"; + //begin and non-specified have sentinel default "0" + + if (sentinelStr != null) { + if (sentinelStr.trim().startsWith("0x")) { + sentinel = new BigInteger(sentinelStr.trim().substring(2), 16); + } else { + sentinel = new BigInteger(sentinelStr, 10); + } + } + + revokeAll = req.getParameter("revokeAll"); + + if (mAuthority instanceof ICertificateAuthority) { + X509CertImpl caCert = ((ICertificateAuthority) mAuthority).getSigningUnit().getCertImpl(); + + //if (isCertFromCA(caCert)) + header.addStringValue("caSerialNumber", + caCert.getSerialNumber().toString(16)); + } + + // constructs the ldap filter on the server side + String queryCertFilter = buildFilter(req); + + if (queryCertFilter == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + com.netscape.certsrv.apps.CMS.debug("queryCertFilter=" + queryCertFilter); + + int totalRecordCount = -1; + + try { + totalRecordCount = Integer.parseInt(req.getParameter("totalRecordCount")); + } catch (Exception e) { + } + processCertFilter(argSet, header, maxCount, + sentinel, + totalRecordCount, + req.getParameter("serialTo"), + queryCertFilter, + req, resp, revokeAll, locale[0]); + } catch (NumberFormatException e) { + log(ILogger.LL_FAILURE, com.netscape.certsrv.apps.CMS.getLogMessage("BASE_INVALID_NUMBER_FORMAT")); + + error = + new EBaseException(com.netscape.certsrv.apps.CMS.getUserMessage(getLocale(req), + "CMS_BASE_INVALID_NUMBER_FORMAT")); + } catch (EBaseException e) { + error = e; + } + + ctx.addIntegerValue("maxCount", maxCount); + + try { + ServletOutputStream out = resp.getOutputStream(); + + if (error == null) { + String xmlOutput = req.getParameter("xml"); + if (xmlOutput != null && xmlOutput.equals("true")) { + outputXML(resp, argSet); + } else { + cmsReq.setStatus(CMSRequest.SUCCESS); + resp.setContentType("text/html"); + form.renderOutput(out, argSet); + } + } else { + cmsReq.setStatus(CMSRequest.ERROR); + cmsReq.setError(error); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + com.netscape.certsrv.apps.CMS.getLogMessage("CMSGW_ERR_OUT_STREAM_TEMPLATE", e.toString())); + throw new ECMSGWException( + com.netscape.certsrv.apps.CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + } + + private void processCertFilter(CMSTemplateParams argSet, + IArgBlock header, + int maxCount, + BigInteger sentinel, + int totalRecordCount, + String serialTo, + String filter, + HttpServletRequest req, + HttpServletResponse resp, + String revokeAll, + Locale locale + ) throws EBaseException { + BigInteger serialToVal = MINUS_ONE; + + try { + if (serialTo != null) { + serialTo = serialTo.trim(); + if (serialTo.startsWith("0x")) { + serialToVal = new BigInteger + (serialTo.substring(2), 16); + serialTo = serialToVal.toString(); + } else { + serialToVal = new BigInteger(serialTo); + } + } + } catch (Exception e) { + } + + String jumpTo = sentinel.toString(); + int pSize = 0; + if (mReverse) { + if (!mHardJumpTo) //reverse gets one more + pSize = -1 * maxCount - 1; + else + pSize = -1 * maxCount; + } else + pSize = maxCount; + + ICertRecordList list = (ICertRecordList) mCertDB.findCertRecordsInList( + filter, (String[]) null, jumpTo, mHardJumpTo, "serialno", + pSize); + // retrive maxCount + 1 entries + + Enumeration e = list.getCertRecords(0, maxCount); + + ICertRecordList tolist = null; + int toCurIndex = 0; + + if (!serialToVal.equals(MINUS_ONE)) { + // if user specify a range, we need to + // calculate the totalRecordCount + tolist = (ICertRecordList) mCertDB.findCertRecordsInList( + filter, + (String[]) null, serialTo, + "serialno", maxCount); + Enumeration en = tolist.getCertRecords(0, 0); + + if (en == null || (!en.hasMoreElements())) { + toCurIndex = list.getSize() - 1; + } else { + toCurIndex = tolist.getCurrentIndex(); + ICertRecord rx = en.nextElement(); + BigInteger curToSerial = rx.getSerialNumber(); + + if (curToSerial.compareTo(serialToVal) == -1) { + toCurIndex = list.getSize() - 1; + } else { + if (!rx.getSerialNumber().toString().equals(serialTo.trim())) { + toCurIndex = toCurIndex - 1; + } + } + } + } + + int curIndex = list.getCurrentIndex(); + + int count = 0; + BigInteger firstSerial = new BigInteger("0"); + BigInteger curSerial = new BigInteger("0"); + ICertRecord[] recs = new ICertRecord[maxCount]; + int rcount = 0; + + if (e != null) { + /* in reverse (page up), because the sentinel is the one after the + * last item to be displayed, we need to skip it + */ + while ((count < ((mReverse && !mHardJumpTo) ? (maxCount + 1) : maxCount)) && e.hasMoreElements()) { + ICertRecord rec = (ICertRecord) e.nextElement(); + + if (rec == null) { + com.netscape.certsrv.apps.CMS.debug("record " + count + " is null"); + break; + } + curSerial = rec.getSerialNumber(); + com.netscape.certsrv.apps.CMS.debug("record " + count + " is serial#" + curSerial); + + if (count == 0) { + firstSerial = curSerial; + if (mReverse && !mHardJumpTo) {//reverse got one more, skip + count++; + continue; + } + } + + // DS has a problem where last record will be returned + // even though the filter is not matched. + /*cfu - is this necessary? it breaks when paging up + if (curSerial.compareTo(sentinel) == -1) { + com.netscape.certsrv.apps.CMS.debug("curSerial compare sentinel -1 break..."); + + break; + } + */ + if (!serialToVal.equals(MINUS_ONE)) { + // check if we go over the limit + if (curSerial.compareTo(serialToVal) == 1) { + com.netscape.certsrv.apps.CMS.debug("curSerial compare serialToVal 1 breaking..."); + break; + } + } + + if (mReverse) { + recs[rcount++] = rec; + } else { + + IArgBlock rarg = com.netscape.certsrv.apps.CMS.createArgBlock(); + + fillRecordIntoArg(rec, rarg); + argSet.addRepeatRecord(rarg); + } + count++; + } + } else { + com.netscape.certsrv.apps.CMS.debug( + "ListCerts::processCertFilter() - no Cert Records found!"); + return; + } + + if (mReverse) { + // fill records into arg block and argSet + for (int ii = rcount - 1; ii >= 0; ii--) { + if (recs[ii] != null) { + IArgBlock rarg = com.netscape.certsrv.apps.CMS.createArgBlock(); + //com.netscape.certsrv.apps.CMS.debug("item "+ii+" is serial # "+ recs[ii].getSerialNumber()); + fillRecordIntoArg(recs[ii], rarg); + argSet.addRepeatRecord(rarg); + } + } + } + + // peek ahead + ICertRecord nextRec = null; + + if (e.hasMoreElements()) { + nextRec = (ICertRecord) e.nextElement(); + } + + header.addStringValue("op", req.getParameter("op")); + if (revokeAll != null) + header.addStringValue("revokeAll", revokeAll); + if (mAuthName != null) + header.addStringValue("issuerName", mAuthName.toString()); + if (!serialToVal.equals(MINUS_ONE)) + header.addStringValue("serialTo", serialToVal.toString()); + header.addStringValue("serviceURL", req.getRequestURI()); + header.addStringValue("queryCertFilter", filter); + header.addStringValue("templateName", "queryCert"); + header.addStringValue("queryFilter", filter); + header.addIntegerValue("maxCount", maxCount); + if (totalRecordCount == -1) { + if (!serialToVal.equals(MINUS_ONE)) { + totalRecordCount = toCurIndex - curIndex + 1; + com.netscape.certsrv.apps.CMS.debug("totalRecordCount=" + totalRecordCount); + } else { + totalRecordCount = list.getSize() - + list.getCurrentIndex(); + com.netscape.certsrv.apps.CMS.debug("totalRecordCount=" + totalRecordCount); + } + } + + header.addIntegerValue("totalRecordCount", totalRecordCount); + header.addIntegerValue("currentRecordCount", list.getSize() - + list.getCurrentIndex()); + + String qs = ""; + if (mReverse) + qs = "querySentinelUp"; + else + qs = "querySentinelDown"; + + if (mHardJumpTo) { + com.netscape.certsrv.apps.CMS.debug("curSerial added to querySentinelUp:" + curSerial.toString()); + + header.addStringValue("querySentinelUp", curSerial.toString()); + } else { + if (nextRec == null) { + header.addStringValue(qs, null); + com.netscape.certsrv.apps.CMS.debug("nextRec is null"); + if (mReverse) { + com.netscape.certsrv.apps.CMS.debug("curSerial added to querySentinelUp:" + curSerial.toString()); + + header.addStringValue("querySentinelUp", curSerial.toString()); + } + } else { + BigInteger nextRecNo = nextRec.getSerialNumber(); + + if (serialToVal.equals(MINUS_ONE)) { + header.addStringValue( + qs, nextRecNo.toString()); + } else { + if (nextRecNo.compareTo(serialToVal) <= 0) { + header.addStringValue( + qs, nextRecNo.toString()); + } else { + header.addStringValue(qs, + null); + } + } + com.netscape.certsrv.apps.CMS.debug("querySentinel " + qs + " = " + nextRecNo.toString()); + } + } // !mHardJumpto + + header.addStringValue(!mReverse ? "querySentinelUp" : "querySentinelDown", + firstSerial.toString()); + + } + + /** + * Fills cert record into argument block. + */ + private void fillRecordIntoArg(ICertRecord rec, IArgBlock rarg) + throws EBaseException { + + X509CertImpl xcert = rec.getCertificate(); + + if (xcert != null) { + fillX509RecordIntoArg(rec, rarg); + } + } + + private void fillX509RecordIntoArg(ICertRecord rec, IArgBlock rarg) + throws EBaseException { + + X509CertImpl cert = rec.getCertificate(); + + rarg.addIntegerValue("version", cert.getVersion()); + rarg.addStringValue("serialNumber", cert.getSerialNumber().toString(16)); + rarg.addStringValue("serialNumberDecimal", cert.getSerialNumber().toString()); + + if (cert.getSubjectDN().toString().equals("")) { + rarg.addStringValue("subject", " "); + } else + rarg.addStringValue("subject", cert.getSubjectDN().toString()); + + rarg.addStringValue("type", "X.509"); + + try { + PublicKey pKey = cert.getPublicKey(); + X509Key key = null; + + if (pKey instanceof CertificateX509Key) { + CertificateX509Key certKey = (CertificateX509Key) pKey; + + key = (X509Key) certKey.get(CertificateX509Key.KEY); + } + if (pKey instanceof X509Key) { + key = (X509Key) pKey; + } + rarg.addStringValue("subjectPublicKeyAlgorithm", key.getAlgorithmId().getOID().toString()); + if (key.getAlgorithmId().toString().equalsIgnoreCase("RSA")) { + RSAPublicKey rsaKey = new RSAPublicKey(key.getEncoded()); + + rarg.addIntegerValue("subjectPublicKeyLength", rsaKey.getKeySize()); + } + } catch (Exception e) { + rarg.addStringValue("subjectPublicKeyAlgorithm", null); + rarg.addIntegerValue("subjectPublicKeyLength", 0); + } + + rarg.addLongValue("validNotBefore", cert.getNotBefore().getTime() / 1000); + rarg.addLongValue("validNotAfter", cert.getNotAfter().getTime() / 1000); + rarg.addStringValue("signatureAlgorithm", cert.getSigAlgOID()); + String issuedBy = rec.getIssuedBy(); + + if (issuedBy == null) + issuedBy = ""; + rarg.addStringValue("issuedBy", issuedBy); // cert.getIssuerDN().toString() + rarg.addLongValue("issuedOn", rec.getCreateTime().getTime() / 1000); + + rarg.addStringValue("revokedBy", + ((rec.getRevokedBy() == null) ? "" : rec.getRevokedBy())); + if (rec.getRevokedOn() == null) { + rarg.addStringValue("revokedOn", null); + } else { + rarg.addLongValue("revokedOn", rec.getRevokedOn().getTime() / 1000); + + IRevocationInfo revocationInfo = rec.getRevocationInfo(); + + if (revocationInfo != null) { + CRLExtensions crlExts = revocationInfo.getCRLEntryExtensions(); + + if (crlExts != null) { + Enumeration enum1 = crlExts.getElements(); + int reason = 0; + + while (enum1.hasMoreElements()) { + Extension ext = (Extension) enum1.nextElement(); + + if (ext instanceof CRLReasonExtension) { + reason = ((CRLReasonExtension) ext).getReason().toInt(); + break; + } + } + rarg.addIntegerValue("revocationReason", reason); + } + } + } + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/Monitor.java b/base/common/src/com/netscape/cms/servlet/cert/Monitor.java new file mode 100644 index 000000000..ac531caca --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/Monitor.java @@ -0,0 +1,407 @@ +// --- 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.cert; + +import java.io.IOException; +import java.util.Calendar; +import java.util.Date; +import java.util.Enumeration; +import java.util.Locale; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.X500Name; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.request.IRequestList; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.IRequestRecord; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Provide statistical queries of request and certificate records. + * + * @version $Revision$, $Date$ + */ +public class Monitor extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = -8492837942132357692L; + private final static String TPL_FILE = "monitor.template"; + private final static String INFO = "Monitor"; + + private ICertificateRepository mCertDB = null; + private IRequestQueue mQueue = null; + private X500Name mAuthName = null; + private String mFormPath = null; + + private int mTotalCerts = 0; + private int mTotalReqs = 0; + + /** + * Constructs query servlet. + */ + public Monitor() { + super(); + } + + /** + * initialize the servlet. This servlet uses the template file + * 'monitor.template' to render the response. + * + * @param sc servlet configuration, read from the web.xml file + */ + + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + // override success to render own template. + mTemplates.remove(CMSRequest.SUCCESS); + + if (mAuthority instanceof ICertificateAuthority) { + ICertificateAuthority ca = (ICertificateAuthority) mAuthority; + + mCertDB = ca.getCertificateRepository(); + mAuthName = ca.getX500Name(); + } + mQueue = mAuthority.getRequestQueue(); + + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + + if (mOutputTemplatePath != null) + mFormPath = mOutputTemplatePath; + } + + /** + * Process the HTTP request. + *
      + *
    • http.param startTime start of time period to query + *
    • http.param endTime end of time period to query + *
    • http.param interval time between queries + *
    • http.param numberOfIntervals number of queries to run + *
    • http.param maxResults =number + *
    • http.param timeLimit =time + *
    + */ + public void process(CMSRequest cmsReq) throws EBaseException { + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "read"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + String startTime = null; + String endTime = null; + String interval = null; + String numberOfIntervals = null; + + EBaseException error = null; + + IArgBlock header = CMS.createArgBlock(); + IArgBlock ctx = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, ctx); + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, req, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", mFormPath, e.toString())); + throw new ECMSGWException(CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + try { + startTime = req.getParameter("startTime"); + endTime = req.getParameter("endTime"); + interval = req.getParameter("interval"); + numberOfIntervals = req.getParameter("numberOfIntervals"); + + process(argSet, header, startTime, endTime, interval, numberOfIntervals, locale[0]); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_PROCESSING_REQ", e.toString())); + error = e; + } + + try { + ServletOutputStream out = resp.getOutputStream(); + + if (error == null) { + String xmlOutput = req.getParameter("xml"); + if (xmlOutput != null && xmlOutput.equals("true")) { + outputXML(resp, argSet); + } else { + resp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } + } else { + cmsReq.setStatus(CMSRequest.ERROR); + cmsReq.setError(error); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_STREAM_TEMPLATE", + e.toString())); + throw new ECMSGWException(CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + } + + private void process(CMSTemplateParams argSet, IArgBlock header, + String startTime, String endTime, + String interval, String numberOfIntervals, + Locale locale) + throws EBaseException { + if (interval == null || interval.length() == 0) { + header.addStringValue("error", "Invalid interval: " + interval); + return; + } + if (numberOfIntervals == null || numberOfIntervals.length() == 0) { + header.addStringValue("error", "Invalid number of intervals: " + numberOfIntervals); + return; + } + + Date startDate = StringToDate(startTime); + + if (startDate == null) { + header.addStringValue("error", "Invalid start time: " + startTime); + return; + } + + int iInterval = 0; + + try { + iInterval = Integer.parseInt(interval); + } catch (NumberFormatException nfe) { + header.addStringValue("error", "Invalid interval: " + interval); + return; + } + + int iNumberOfIntervals = 0; + + try { + iNumberOfIntervals = Integer.parseInt(numberOfIntervals); + } catch (NumberFormatException nfe) { + header.addStringValue("error", "Invalid number of intervals: " + numberOfIntervals); + return; + } + + header.addStringValue("startDate", startDate.toString()); + header.addStringValue("startTime", startTime); + header.addIntegerValue("interval", iInterval); + header.addIntegerValue("numberOfIntervals", iNumberOfIntervals); + + mTotalCerts = 0; + mTotalReqs = 0; + + Date d1 = startDate; + + for (int i = 0; i < iNumberOfIntervals; i++) { + Date d2 = nextDate(d1, iInterval - 1); + IArgBlock rarg = CMS.createArgBlock(); + String e = getIntervalInfo(rarg, d1, d2); + + if (e != null) { + header.addStringValue("error", e); + return; + } + argSet.addRepeatRecord(rarg); + d1 = nextDate(d2, 1); + } + + header.addIntegerValue("totalNumberOfCertificates", mTotalCerts); + header.addIntegerValue("totalNumberOfRequests", mTotalReqs); + + if (mAuthName != null) + header.addStringValue("issuerName", mAuthName.toString()); + + return; + } + + Date nextDate(Date d, int seconds) { + Date date = new Date((d.getTime()) + ((long) (seconds * 1000))); + + return date; + } + + String getIntervalInfo(IArgBlock arg, Date startDate, Date endDate) { + if (startDate != null && endDate != null) { + String startTime = DateToZString(startDate); + String endTime = DateToZString(endDate); + String filter = null; + + arg.addStringValue("startTime", startTime); + arg.addStringValue("endTime", endTime); + + try { + if (mCertDB != null) { + filter = Filter(ICertRecord.ATTR_CREATE_TIME, startTime, endTime); + + Enumeration e = mCertDB.findCertRecs(filter); + + int count = 0; + + while (e != null && e.hasMoreElements()) { + ICertRecord rec = (ICertRecord) e.nextElement(); + + if (rec != null) { + count++; + } + } + arg.addIntegerValue("numberOfCertificates", count); + mTotalCerts += count; + } + + if (mQueue != null) { + filter = Filter(IRequestRecord.ATTR_CREATE_TIME, startTime, endTime); + + IRequestList reqList = mQueue.listRequestsByFilter(filter); + + int count = 0; + + while (reqList != null && reqList.hasMoreElements()) { + IRequestRecord rec = (IRequestRecord) reqList.nextRequest(); + + if (rec != null) { + if (count == 0) { + arg.addStringValue("firstRequest", rec.getRequestId().toString()); + } + count++; + } + } + arg.addIntegerValue("numberOfRequests", count); + mTotalReqs += count; + } + } catch (Exception ex) { + return "Exception: " + ex; + } + + return null; + } else { + return "Missing start or end date"; + } + } + + Date StringToDate(String z) { + Date d = null; + + if (z != null && (z.length() == 14 || + z.length() == 15 && (z.charAt(14) == 'Z' || z.charAt(14) == 'z'))) { + // 20020516132030Z or 20020516132030 + try { + int year = Integer.parseInt(z.substring(0, 4)); + int month = Integer.parseInt(z.substring(4, 6)) - 1; + int date = Integer.parseInt(z.substring(6, 8)); + int hour = Integer.parseInt(z.substring(8, 10)); + int minute = Integer.parseInt(z.substring(10, 12)); + int second = Integer.parseInt(z.substring(12, 14)); + Calendar calendar = Calendar.getInstance(); + calendar.set(year, month, date, hour, minute, second); + d = calendar.getTime(); + } catch (NumberFormatException nfe) { + } + } else if (z != null && z.length() > 1 && z.charAt(0) == '-') { // -5 + try { + int i = Integer.parseInt(z); + + d = new Date(); + d = nextDate(d, i); + } catch (NumberFormatException nfe) { + } + } + + return d; + } + + String DateToZString(Date d) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(d); + + String time = "" + (calendar.get(Calendar.YEAR)); + int i = calendar.get(Calendar.MONTH) + 1; + + if (i < 10) + time += "0"; + time += i; + i = calendar.get(Calendar.DAY_OF_MONTH); + if (i < 10) + time += "0"; + time += i; + i = calendar.get(Calendar.HOUR_OF_DAY); + if (i < 10) + time += "0"; + time += i; + i = calendar.get(Calendar.MINUTE); + if (i < 10) + time += "0"; + time += i; + i = calendar.get(Calendar.SECOND); + if (i < 10) + time += "0"; + time += i + "Z"; + return time; + } + + String Filter(String name, String start, String end) { + String filter = "(&(" + name + ">=" + start + ")(" + name + "<=" + end + "))"; + + return filter; + } + + String uriFilter(String name, String start, String end) { + String filter = "(%26(" + name + "%3e%3d" + start + ")(" + name + "%3c%3d" + end + "))"; + + return filter; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/ReasonToRevoke.java b/base/common/src/com/netscape/cms/servlet/cert/ReasonToRevoke.java new file mode 100644 index 000000000..0f21e1921 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/ReasonToRevoke.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.cert; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Random; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.X509CertImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.Nonces; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +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.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Specify the RevocationReason when revoking a certificate + * + * @version $Revision$, $Date$ + */ +public class ReasonToRevoke extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = -8447580860330758660L; + private final static String TPL_FILE = "reasonToRevoke.template"; + private final static String INFO = "ReasonToRevoke"; + + private ICertificateRepository mCertDB = null; + private String mFormPath = null; + private ICertificateAuthority mCA = null; + private Random mRandom = null; + private Nonces mNonces = null; + private int mTimeLimits = 30; /* in seconds */ + + public ReasonToRevoke() { + super(); + } + + /** + * initialize the servlet. This servlet uses the template file + * 'reasonToRevoke.template' to render the response + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + if (mAuthority instanceof ICertificateAuthority) { + mCA = (ICertificateAuthority) mAuthority; + mCertDB = ((ICertificateAuthority) mAuthority).getCertificateRepository(); + } + + if (mCA != null && mCA.noncesEnabled()) { + mRandom = new Random(); + mNonces = mCA.getNonces(); + } + + mTemplates.remove(CMSRequest.SUCCESS); + if (mOutputTemplatePath != null) + mFormPath = mOutputTemplatePath; + + /* Server-Side time limit */ + try { + mTimeLimits = Integer.parseInt(sc.getInitParameter("timeLimits")); + } catch (Exception e) { + /* do nothing, just use the default if integer parsing failed */ + } + } + + /** + * Returns serlvet information. + */ + public String getServletInfo() { + return INFO; + } + + /** + * Process the HTTP request. + * + * @param cmsReq the object holding the request and response information + */ + public void process(CMSRequest cmsReq) throws EBaseException { + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "revoke"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + String revokeAll = null; + int totalRecordCount = 1; + EBaseException error = null; + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, req, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", mFormPath, e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock ctx = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, ctx); + + try { + if (req.getParameter("totalRecordCount") != null) { + totalRecordCount = + Integer.parseInt(req.getParameter("totalRecordCount")); + } + + revokeAll = req.getParameter("revokeAll"); + + process(argSet, header, req, resp, + revokeAll, totalRecordCount, locale[0]); + } catch (EBaseException e) { + error = e; + } catch (NumberFormatException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_INVALID_RECORD_COUNT_FORMAT")); + error = new EBaseException(CMS.getUserMessage(getLocale(req), "CMS_BASE_INVALID_NUMBER_FORMAT")); + } + + /* + catch (Exception e) { + noError = false; + header.addStringValue(OUT_ERROR, + MessageFormatter.getLocalizedString( + errorlocale[0], + BaseResources.class.getName(), + BaseResources.INTERNAL_ERROR_1, + e.toString())); + } + */ + + try { + ServletOutputStream out = resp.getOutputStream(); + + if (error == null) { + String xmlOutput = req.getParameter("xml"); + if (xmlOutput != null && xmlOutput.equals("true")) { + outputXML(resp, argSet); + } else { + resp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } + } else { + cmsReq.setStatus(CMSRequest.ERROR); + cmsReq.setError(error); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_OUT_STREAM_TEMPLATE", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + } + + private void process(CMSTemplateParams argSet, IArgBlock header, + HttpServletRequest req, + HttpServletResponse resp, + String revokeAll, int totalRecordCount, + Locale locale) + throws EBaseException { + + header.addStringValue("revokeAll", revokeAll); + header.addIntegerValue("totalRecordCount", totalRecordCount); + + if (mNonces != null) { + long n = mRandom.nextLong(); + long m = mNonces.addNonce(n, getSSLClientCertificate(req)); + if ((n + m) != 0) { + header.addStringValue("nonce", Long.toString(m)); + } + } + + try { + if (mCA != null) { + X509CertImpl caCert = mCA.getSigningUnit().getCertImpl(); + + if (isCertFromCA(caCert)) { + header.addStringValue("caSerialNumber", + caCert.getSerialNumber().toString(16)); + } + } + + /** + * ICertRecordList list = mCertDB.findCertRecordsInList( + * revokeAll, null, totalRecordCount); + * Enumeration e = list.getCertRecords(0, totalRecordCount - 1); + **/ + Enumeration e = mCertDB.searchCertificates(revokeAll, + totalRecordCount, mTimeLimits); + + int count = 0; + + while (e != null && e.hasMoreElements()) { + ICertRecord rec = e.nextElement(); + + if (rec == null) + continue; + X509CertImpl xcert = rec.getCertificate(); + + if (xcert != null) + if (!(rec.getStatus().equals(ICertRecord.STATUS_REVOKED))) { + count++; + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addStringValue("serialNumber", + xcert.getSerialNumber().toString(16)); + rarg.addStringValue("serialNumberDecimal", + xcert.getSerialNumber().toString()); + rarg.addStringValue("subject", + xcert.getSubjectDN().toString()); + rarg.addLongValue("validNotBefore", + xcert.getNotBefore().getTime() / 1000); + rarg.addLongValue("validNotAfter", + xcert.getNotAfter().getTime() / 1000); + argSet.addRepeatRecord(rarg); + } + } + + header.addIntegerValue("verifiedRecordCount", count); + + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, "Error " + e); + throw e; + } + return; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/RemoteAuthConfig.java b/base/common/src/com/netscape/cms/servlet/cert/RemoteAuthConfig.java new file mode 100644 index 000000000..478df161d --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/RemoteAuthConfig.java @@ -0,0 +1,624 @@ +// --- 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.cert; + +import java.io.IOException; +import java.util.Calendar; +import java.util.Enumeration; +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPConnection; +import netscape.ldap.LDAPEntry; +import netscape.ldap.LDAPException; +import netscape.ldap.LDAPSearchResults; +import netscape.ldap.LDAPv2; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.AuthMgrPlugin; +import com.netscape.certsrv.authentication.IAuthManager; +import com.netscape.certsrv.authentication.IAuthSubsystem; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.IConfigStore; +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.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Allow agent to turn on/off authentication managers + * + * @version $Revision$, $Date$ + */ +public class RemoteAuthConfig extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = -5803015919915253940L; + private final static String INFO = "RemoteAuthConfig"; + private final static String TPL_FILE = "remoteAuthConfig.template"; + private final static String ENABLE_REMOTE_CONFIG = "enableRemoteConfiguration"; + private final static String REMOTELY_SET_INSTANCES = "remotelySetInstances"; + private final static String MEMBER_OF = "memberOf"; + private final static String UNIQUE_MEMBER = "uniqueMember"; + + private String mFormPath = null; + private IAuthSubsystem mAuthSubsystem = null; + private IConfigStore mAuthConfig = null; + private IConfigStore mFileConfig = null; + private Vector mRemotelySetInstances = new Vector(); + private boolean mEnableRemoteConfiguration = false; + + /** + * Constructs RemoteAuthConfig servlet. + */ + public RemoteAuthConfig() { + super(); + } + + /** + * Initializes the servlet. + * + * Presence of "auths.enableRemoteConfiguration=true" in CMS.cfg + * enables remote configuration for authentication plugins. + * List of remotely set instances can be found in CMS.cfg + * at "auths.remotelySetInstances=,,...," + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + mFileConfig = CMS.getConfigStore(); + mAuthConfig = mFileConfig.getSubStore("auths"); + try { + mEnableRemoteConfiguration = mAuthConfig.getBoolean(ENABLE_REMOTE_CONFIG, false); + } catch (EBaseException eb) { + // Thanks to design of getBoolean we have to catch but we will never get anything. + } + + String remoteList = null; + + try { + remoteList = mAuthConfig.getString(REMOTELY_SET_INSTANCES, null); + } catch (EBaseException eb) { + // Thanks to design of getString we have to catch but we will never get anything. + } + if (remoteList != null) { + StringTokenizer s = new StringTokenizer(remoteList, ","); + + while (s.hasMoreTokens()) { + String token = s.nextToken(); + + if (token != null && token.trim().length() > 0) { + mRemotelySetInstances.add(token.trim()); + } + } + } + + mAuthSubsystem = (IAuthSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_AUTH); + + mTemplates.remove(CMSRequest.SUCCESS); + } + + /** + * Serves HTTPS request. The format of this request is as follows: + * https://host:ee-port/remoteAuthConfig? + * op="add"|"delete"& + * instance=& + * of=& + * host=& + * port=& + * password=& + * [adminDN=]& + * [uid=]& + * [baseDN=] + */ + public void process(CMSRequest cmsReq) throws EBaseException { + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + authenticate(cmsReq); + + IArgBlock header = CMS.createArgBlock(); + IArgBlock ctx = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, ctx); + + String host = req.getParameter("host"); + String port = req.getParameter("port"); + + String adminDN = req.getParameter("adminDN"); + String uid = req.getParameter("uid"); + String baseDN = req.getParameter("baseDN"); + String password = req.getParameter("password"); + + String replyTo = req.getParameter("replyTo"); + + if (replyTo != null && replyTo.length() > 0) { + ctx.addStringValue("replyTo", replyTo); + } + + if (mEnableRemoteConfiguration) { + String errMsg = null; + + if (adminDN != null && adminDN.length() > 0) { + errMsg = authenticateRemoteAdmin(host, port, adminDN, password); + } else { + errMsg = authenticateRemoteAdmin(host, port, uid, baseDN, password); + } + if (errMsg == null || errMsg.length() == 0) { + if (mAuthSubsystem != null && mAuthConfig != null) { + String op = req.getParameter("op"); + + if (op == null || op.length() == 0) { + header.addStringValue("error", "Undefined operation"); + } else { + header.addStringValue("op", op); + + if (op.equals("delete")) { + String plugin = req.getParameter("of"); + + if (isPluginListed(plugin)) { + String instance = req.getParameter("instance"); + + if (isInstanceListed(instance)) { + errMsg = deleteInstance(instance); + if (errMsg != null && errMsg.length() > 0) { + header.addStringValue("error", errMsg); + } else { + header.addStringValue("plugin", plugin); + header.addStringValue("instance", instance); + } + } else { + header.addStringValue("error", "Unknown instance " + + instance + "."); + } + } else { + header.addStringValue("error", "Unknown plugin name: " + plugin); + } + } else if (op.equals("add")) { + String plugin = req.getParameter("of"); + + if (isPluginListed(plugin)) { + String instance = req.getParameter("instance"); + + if (instance == null || instance.length() == 0) { + instance = makeInstanceName(); + } + if (isInstanceListed(instance)) { + header.addStringValue("error", "Instance name " + + instance + " is already in use."); + } else { + errMsg = addInstance(instance, plugin, + host, port, baseDN, + req.getParameter("dnPattern")); + if (errMsg != null && errMsg.length() > 0) { + header.addStringValue("error", errMsg); + } else { + header.addStringValue("plugin", plugin); + header.addStringValue("instance", instance); + } + } + } else { + header.addStringValue("error", "Unknown plugin name: " + plugin); + } + } else { + header.addStringValue("error", "Unsupported operation: " + op); + } + } + } else { + header.addStringValue("error", "Invalid configuration data."); + } + } else { + header.addStringValue("error", errMsg); + } + } else { + header.addStringValue("error", "Remote configuration is disabled."); + } + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, req, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + try { + ServletOutputStream out = resp.getOutputStream(); + + resp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_STREAM_TEMPLATE", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + } + + private String authenticateRemoteAdmin(String host, String port, + String adminDN, String password) { + if (host == null || host.length() == 0) { + return "Missing host name."; + } + if (port == null || port.length() == 0 || port.trim().length() == 0) { + return "Missing port number."; + } + if (adminDN == null || adminDN.length() == 0) { + return "Missing admin DN."; + } + if (password == null || password.length() == 0) { + return "Missing password."; + } + int p = 0; + + try { + p = Integer.parseInt(port.trim()); + } catch (NumberFormatException e) { + return "Invalid port number: " + port + " (" + e.toString() + ")"; + } + + boolean connected = false; + LDAPConnection c = new LDAPConnection(); + + try { + c.connect(host, p); + connected = true; + try { + c.authenticate(adminDN, password); + LDAPEntry entry = c.read(adminDN); + LDAPAttribute attr = entry.getAttribute(MEMBER_OF); + + if (attr != null) { + @SuppressWarnings("unchecked") + Enumeration eVals = attr.getStringValues(); + + while (eVals.hasMoreElements()) { + String nextValue = eVals.nextElement(); + + if (nextValue.indexOf("Administrator") > -1) { + LDAPEntry groupEntry = c.read(nextValue); + + if (groupEntry != null) { + LDAPAttribute gAttr = groupEntry.getAttribute(UNIQUE_MEMBER); + + if (gAttr != null) { + @SuppressWarnings("unchecked") + Enumeration eValues = gAttr.getStringValues(); + + while (eValues.hasMoreElements()) { + String value = eValues.nextElement(); + + if (value.equals(entry.getDN())) { + c.disconnect(); + return null; + } + } + } + } + break; + } + } + } else { + c.disconnect(); + return null; + } + + } catch (LDAPException e) { + + /* + switch (e.getLDAPResultCode()) { + case LDAPException.NO_SUCH_OBJECT: + case LDAPException.INVALID_CREDENTIALS: + case LDAPException.INSUFFICIENT_ACCESS_RIGHTS: + case LDAPException.LDAP_PARTIAL_RESULTS: + default: + } + */ + c.disconnect(); + return "LDAP error: " + e.toString(); + } + + if (connected) { + c.disconnect(); + } + } catch (LDAPException e) { + return "LDAP error: " + e.toString(); + } + + return "Access unauthorized"; + } + + private String authenticateRemoteAdmin(String host, String port, + String uid, String baseDN, + String password) { + if (host == null || host.length() == 0) { + return "Missing host name."; + } + if (port == null || port.length() == 0 || port.trim().length() == 0) { + return "Missing port number."; + } + if (uid == null || uid.length() == 0) { + return "Missing UID."; + } + if (uid.indexOf('*') > -1) { + return "Invalid UID: " + uid; + } + if (password == null || password.length() == 0) { + return "Missing password."; + } + int p = 0; + + try { + p = Integer.parseInt(port.trim()); + } catch (NumberFormatException e) { + return "Invalid port number: " + port + " (" + e.toString() + ")"; + } + if (baseDN == null || baseDN.length() == 0) { + return "Missing base DN."; + } + + boolean connected = false; + LDAPConnection c = new LDAPConnection(); + + try { + c.connect(host, p); + connected = true; + boolean memberOf = false; + LDAPSearchResults results = c.search(baseDN, LDAPv2.SCOPE_SUB, + "(uid=" + uid + ")", + null, false); + + while (results.hasMoreElements()) { + LDAPEntry entry = null; + + try { + entry = results.next(); + c.authenticate(entry.getDN(), password); + LDAPAttribute attr = entry.getAttribute(MEMBER_OF); + + if (attr != null) { + memberOf = true; + @SuppressWarnings("unchecked") + Enumeration eVals = attr.getStringValues(); + + while (eVals.hasMoreElements()) { + String nextValue = eVals.nextElement(); + + if (nextValue.indexOf("Administrator") > -1) { + LDAPEntry groupEntry = c.read(nextValue); + + if (groupEntry != null) { + LDAPAttribute gAttr = groupEntry.getAttribute(UNIQUE_MEMBER); + + if (gAttr != null) { + @SuppressWarnings("unchecked") + Enumeration eValues = gAttr.getStringValues(); + + while (eValues.hasMoreElements()) { + String value = eValues.nextElement(); + + if (value.equals(entry.getDN())) { + c.disconnect(); + return null; + } + } + } + } + break; + } + } + } + } catch (LDAPException e) { + switch (e.getLDAPResultCode()) { + case LDAPException.NO_SUCH_OBJECT: + continue; + + case LDAPException.INVALID_CREDENTIALS: + break; + + case LDAPException.INSUFFICIENT_ACCESS_RIGHTS: + break; + + case LDAPException.LDAP_PARTIAL_RESULTS: + break; + + default: + continue; + } + } + } + if (connected) { + c.disconnect(); + } + + if (!memberOf) { + return null; + } + } catch (LDAPException e) { + return "LDAP error: " + e.toString(); + } + + return "Access unauthorized"; + } + + private String addInstance(String instance, String plugin, + String host, String port, + String baseDN, String dnPattern) { + if (host == null || host.length() == 0) { + return "Missing host name."; + } + if (port == null || port.length() == 0) { + return "Missing port number."; + } + + IConfigStore c0 = mAuthConfig.getSubStore("instance"); + IConfigStore c1 = c0.makeSubStore(instance); + + c1.putString("dnpattern", dnPattern); + c1.putString("ldapByteAttributes", ""); + c1.putString("ldapStringAttributes", ""); + c1.putString("pluginName", plugin); + if (baseDN != null && baseDN.length() > 0) + c1.putString("ldap.basedn", baseDN); + c1.putString("ldap.minConns", ""); + c1.putString("ldap.maxConns", ""); + c1.putString("ldap.ldapconn.host", host); + c1.putString("ldap.ldapconn.port", port); + c1.putString("ldap.ldapconn.secureConn", "false"); + c1.putString("ldap.ldapconn.version", "3"); + + mRemotelySetInstances.add(instance); + + IAuthManager authMgrInst = mAuthSubsystem.getAuthManagerPlugin(plugin); + + if (authMgrInst != null) { + try { + authMgrInst.init(instance, plugin, c1); + } catch (EBaseException e) { + c0.removeSubStore(instance); + mRemotelySetInstances.remove(instance); + return e.toString(); + } + mAuthSubsystem.add(instance, authMgrInst); + } + + StringBuffer list = new StringBuffer(); + + for (int i = 0; i < mRemotelySetInstances.size(); i++) { + if (i > 0) + list.append(","); + list.append(mRemotelySetInstances.elementAt(i)); + } + + mAuthConfig.putString(REMOTELY_SET_INSTANCES, list.toString()); + + try { + mFileConfig.commit(false); + } catch (EBaseException e) { + c0.removeSubStore(instance); + mRemotelySetInstances.remove(instance); + return e.toString(); + } + + return null; + } + + private String deleteInstance(String instance) { + IConfigStore c = mAuthConfig.getSubStore("instance"); + + c.removeSubStore(instance); + + if (mRemotelySetInstances.remove(instance)) { + StringBuffer list = new StringBuffer(); + + for (int i = 0; i < mRemotelySetInstances.size(); i++) { + if (i > 0) + list.append(","); + list.append(mRemotelySetInstances.elementAt(i)); + } + + mAuthConfig.putString(REMOTELY_SET_INSTANCES, list.toString()); + } + + try { + mFileConfig.commit(false); + } catch (EBaseException e) { + return e.toString(); + } + mAuthSubsystem.delete(instance); + + return null; + } + + private boolean isPluginListed(String pluginName) { + boolean isListed = false; + + if (pluginName != null && pluginName.length() > 0) { + Enumeration e = mAuthSubsystem.getAuthManagerPlugins(); + + while (e.hasMoreElements()) { + AuthMgrPlugin plugin = e.nextElement(); + + if (pluginName.equals(plugin.getId())) { + isListed = true; + break; + } + } + } + + return isListed; + } + + private boolean isInstanceListed(String instanceName) { + boolean isListed = false; + + if (instanceName != null && instanceName.length() > 0) { + Enumeration e = mAuthSubsystem.getAuthManagers(); + + while (e.hasMoreElements()) { + IAuthManager authManager = e.nextElement(); + + if (instanceName.equals(authManager.getName())) { + isListed = true; + break; + } + } + } + + return isListed; + } + + private String makeInstanceName() { + Calendar now = Calendar.getInstance(); + int y = now.get(Calendar.YEAR); + String name = "R" + y; + + if (now.get(Calendar.MONTH) < 10) + name += "0"; + name += now.get(Calendar.MONTH); + if (now.get(Calendar.DAY_OF_MONTH) < 10) + name += "0"; + name += now.get(Calendar.DAY_OF_MONTH); + if (now.get(Calendar.HOUR_OF_DAY) < 10) + name += "0"; + name += now.get(Calendar.HOUR_OF_DAY); + if (now.get(Calendar.MINUTE) < 10) + name += "0"; + name += now.get(Calendar.MINUTE); + if (now.get(Calendar.SECOND) < 10) + name += "0"; + name += now.get(Calendar.SECOND); + return name; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/RenewalServlet.java b/base/common/src/com/netscape/cms/servlet/cert/RenewalServlet.java new file mode 100644 index 000000000..223121577 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/RenewalServlet.java @@ -0,0 +1,523 @@ +// --- 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.cert; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Calendar; +import java.util.Date; +import java.util.Enumeration; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + +import netscape.security.extensions.CertInfo; +import netscape.security.x509.CertificateSerialNumber; +import netscape.security.x509.CertificateValidity; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; + +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.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.MetaInfo; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.logging.AuditFormat; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.RequestStatus; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.ECMSGWException; +import com.netscape.cms.servlet.common.ICMSTemplateFiller; + +/** + * Certificate Renewal + * + * @version $Revision$, $Date$ + */ +public class RenewalServlet extends CMSServlet { + /** + * + */ + private static final long serialVersionUID = -3094124661102395244L; + + // renewal templates. + public static final String RENEWAL_SUCCESS_TEMPLATE = "RenewalSuccess.template"; + + // http params + public static final String CERT_TYPE = "certType"; + public static final String SERIAL_NO = "serialNo"; + // XXX can't do pkcs10 cause it's got no serial no. + // (unless put serial no in pki attributes) + // public static final String PKCS10 = "pkcs10"; + public static final String IMPORT_CERT = "importCert"; + + private String mRenewalSuccessTemplate = RENEWAL_SUCCESS_TEMPLATE; + private ICMSTemplateFiller mRenewalSuccessFiller = new ImportCertsTemplateFiller(); + + public RenewalServlet() { + super(); + } + + /** + * initialize the servlet. This servlet makes use of the + * template file "RenewalSuccess.template" to render the + * response + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + // override success template. has same info as enrollment. + mTemplates.remove(CMSRequest.SUCCESS); + try { + mRenewalSuccessTemplate = sc.getInitParameter( + PROP_SUCCESS_TEMPLATE); + if (mRenewalSuccessTemplate == null) + mRenewalSuccessTemplate = RENEWAL_SUCCESS_TEMPLATE; + String fillername = + sc.getInitParameter(PROP_SUCCESS_TEMPLATE_FILLER); + + if (fillername != null) { + ICMSTemplateFiller filler = newFillerObject(fillername); + + if (filler != null) + mRenewalSuccessFiller = filler; + } + } catch (Exception e) { + // this should never happen. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_IMP_INIT_SERV_ERR", e.toString(), + mId)); + } + + } + + /** + * Process the HTTP request. + * + * @param cmsReq the object holding the request and response information + */ + protected void process(CMSRequest cmsReq) + throws EBaseException { + long startTime = CMS.getCurrentDate().getTime(); + IArgBlock httpParams = cmsReq.getHttpParams(); + HttpServletRequest httpReq = cmsReq.getHttpReq(); + + // renewal requires either: + // - coming from ee: + // - old cert from ssl client auth + // - old certs from auth manager + // - coming from agent or trusted RA: + // - serial no of cert to be renewed. + + BigInteger old_serial_no = null; + X509CertImpl old_cert = null; + X509CertImpl renewed_cert = null; + Date notBefore = null; + Date notAfter = null; + boolean doSaveAuthToken = false; + + IAuthToken authToken = authenticate(cmsReq); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "renew"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + String authMgr = AuditFormat.NOAUTH; + + if (authToken != null && !mAuthMgr.equals("sslClientCertAuthMgr")) { + authMgr = + authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME); + } + + // coming from agent + if (mAuthMgr != null && mAuthMgr.equals(IAuthSubsystem.CERTUSERDB_AUTHMGR_ID)) { + X509Certificate[] cert = new X509Certificate[1]; + + old_serial_no = getCertFromAgent(httpParams, cert); + old_cert = (X509CertImpl) cert[0]; + + // optional validity params from input. + int beginYear = httpParams.getValueAsInt("beginYear", -1); + int beginMonth = httpParams.getValueAsInt("beginMonth", -1); + int beginDate = httpParams.getValueAsInt("beginDate", -1); + int endYear = httpParams.getValueAsInt("endYear", -1); + int endMonth = httpParams.getValueAsInt("endMonth", -1); + int endDate = httpParams.getValueAsInt("endDate", -1); + + if (beginYear != -1 && beginMonth != -1 && beginDate != -1 && + endYear != -1 && endMonth != -1 && endDate != -1) { + Calendar calendar = Calendar.getInstance(); + calendar.set(beginYear, beginMonth, beginDate); + notBefore = calendar.getTime(); + calendar.set(endYear, endMonth, endDate); + notAfter = calendar.getTime(); + } + } // coming from client + else { + // from auth manager + X509CertImpl[] cert = new X509CertImpl[1]; + + old_serial_no = getCertFromAuthMgr(authToken, cert); + old_cert = cert[0]; + } + + IRequest req = null; + + try { + // get ready to send request to request queue. + X509CertInfo new_certInfo = null; + + req = mRequestQueue.newRequest(IRequest.RENEWAL_REQUEST); + req.setExtData(IRequest.OLD_SERIALS, new BigInteger[] { old_serial_no }); + if (old_cert != null) { + req.setExtData(IRequest.OLD_CERTS, + new X509CertImpl[] { old_cert } + ); + // create new certinfo from old_cert contents. + X509CertInfo old_certInfo = (X509CertInfo) + ((X509CertImpl) old_cert).get( + X509CertImpl.NAME + "." + X509CertImpl.INFO); + + new_certInfo = new X509CertInfo(old_certInfo.getEncodedInfo()); + } else { + // if no old cert (came from RA agent) create new cert info + // (serializable) to pass through policies. And set the old + // serial number to pick up. + new_certInfo = new CertInfo(); + new_certInfo.set(X509CertInfo.SERIAL_NUMBER, + new CertificateSerialNumber(old_serial_no)); + } + + if (notBefore == null || notAfter == null) { + notBefore = new Date(0); + notAfter = new Date(0); + } + new_certInfo.set(X509CertInfo.VALIDITY, + new CertificateValidity(notBefore, notAfter)); + req.setExtData(IRequest.CERT_INFO, new X509CertInfo[] { new_certInfo } + ); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_SETTING_RENEWAL_VALIDITY_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SETTING_RENEWAL_VALIDITY_ERROR")); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERROR_SETTING_RENEWAL_VALIDITY_1", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_SETTING_RENEWAL_VALIDITY_ERROR")); + } + + saveHttpHeaders(httpReq, req); + saveHttpParams(httpParams, req); + if (doSaveAuthToken) + saveAuthToken(authToken, req); + cmsReq.setIRequest(req); + + // send request to request queue. + mRequestQueue.processRequest(req); + + // for audit log + String initiative = null; + String agentID = null; + + if (mAuthMgr != null && mAuthMgr.equals(IAuthSubsystem.CERTUSERDB_AUTHMGR_ID)) { + agentID = authToken.getInString("userid"); + initiative = AuditFormat.FROMAGENT + " agentID: " + agentID; + } else { + // request is from eegateway, so fromUser. + initiative = AuditFormat.FROMUSER; + } + + // check resulting status + RequestStatus status = req.getRequestStatus(); + + if (status != RequestStatus.COMPLETE) { + cmsReq.setIRequestStatus(); + // audit log the status + if (status == RequestStatus.REJECTED) { + Vector messages = req.getExtDataInStringVector(IRequest.ERRORS); + + if (messages != null) { + Enumeration msgs = messages.elements(); + StringBuffer wholeMsg = new StringBuffer(); + + while (msgs.hasMoreElements()) { + wholeMsg.append("\n"); + wholeMsg.append(msgs.nextElement()); + } + + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.RENEWALFORMAT, + new Object[] { + req.getRequestId(), + initiative, + authMgr, + status.toString(), + old_cert.getSubjectDN(), + old_cert.getSerialNumber().toString(16), + "violation: " + + wholeMsg.toString() } + // wholeMsg}, + // ILogger.L_MULTILINE + ); + } else { // no policy violation, from agent + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.RENEWALFORMAT, + new Object[] { + req.getRequestId(), + initiative, + authMgr, + status.toString(), + old_cert.getSubjectDN(), + old_cert.getSerialNumber().toString(16), + "" } + ); + } + } else { // other imcomplete status + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.RENEWALFORMAT, + new Object[] { + req.getRequestId(), + initiative, + authMgr, + status.toString(), + old_cert.getSubjectDN(), + old_cert.getSerialNumber().toString(16), + "" } + ); + } + return; + } + + // service error + Integer result = req.getExtDataInInteger(IRequest.RESULT); + + CMS.debug( + "RenewalServlet: Result for request " + req.getRequestId() + " is " + result); + if (result.equals(IRequest.RES_ERROR)) { + CMS.debug( + "RenewalServlet: Result for request " + req.getRequestId() + " is error."); + + cmsReq.setStatus(CMSRequest.ERROR); + cmsReq.setError(req.getExtDataInString(IRequest.ERROR)); + String[] svcErrors = + req.getExtDataInStringArray(IRequest.SVCERRORS); + + if (svcErrors != null && svcErrors.length > 0) { + for (int i = 0; i < svcErrors.length; i++) { + String err = svcErrors[i]; + + if (err != null) { + //System.out.println( + //"revocation servlet: setting error description "+ + //err.toString()); + cmsReq.setErrorDescription(err); + mLogger.log(ILogger.EV_AUDIT, + ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.RENEWALFORMAT, + new Object[] { + req.getRequestId(), + initiative, + authMgr, + "completed with error: " + + err, + old_cert.getSubjectDN(), + old_cert.getSerialNumber().toString(16), + "" } + ); + + } + } + } + return; + } + + // success. + X509CertImpl[] certs = req.getExtDataInCertArray(IRequest.ISSUED_CERTS); + + renewed_cert = certs[0]; + respondSuccess(cmsReq, renewed_cert); + long endTime = CMS.getCurrentDate().getTime(); + + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.RENEWALFORMAT, + new Object[] { + req.getRequestId(), + initiative, + authMgr, + "completed", + old_cert.getSubjectDN(), + old_cert.getSerialNumber().toString(16), + "new serial number: 0x" + + renewed_cert.getSerialNumber().toString(16) + " time: " + (endTime - startTime) } + ); + + return; + } + + private void respondSuccess( + CMSRequest cmsReq, X509CertImpl renewed_cert) + throws EBaseException { + cmsReq.setResult(new X509CertImpl[] { renewed_cert } + ); + cmsReq.setStatus(CMSRequest.SUCCESS); + + // check if cert should be imported. + // browser must have input type set to nav or cartman since + // there's no other way to tell + + IArgBlock httpParams = cmsReq.getHttpParams(); + + if (checkImportCertToNav(cmsReq.getHttpResp(), + httpParams, renewed_cert)) { + return; + } else { + try { + renderTemplate(cmsReq, + mRenewalSuccessTemplate, mRenewalSuccessFiller); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGE_ERROR_DISPLAY_TEMPLATE_1", + mRenewalSuccessTemplate, e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + } + return; + } + + protected BigInteger getRenewedCert(ICertRecord certRec) + throws EBaseException { + BigInteger renewedCert = null; + String serial = null; + MetaInfo meta = certRec.getMetaInfo(); + + if (meta == null) { + log(ILogger.LL_INFO, + "no meta info in cert serial 0x" + certRec.getSerialNumber().toString(16)); + return null; + } + serial = (String) meta.get(ICertRecord.META_RENEWED_CERT); + if (serial == null) { + log(ILogger.LL_INFO, + "no renewed cert in cert 0x" + certRec.getSerialNumber().toString(16)); + return null; + } + renewedCert = new BigInteger(serial); + log(ILogger.LL_INFO, + "renewed cert serial 0x" + renewedCert.toString(16) + "found for 0x" + + certRec.getSerialNumber().toString(16)); + return renewedCert; + } + + /** + * get certs to renew from agent. + */ + private BigInteger getCertFromAgent( + IArgBlock httpParams, X509Certificate[] certContainer) + throws EBaseException { + BigInteger serialno = null; + X509Certificate cert = null; + + // get serial no + serialno = httpParams.getValueAsBigInteger(SERIAL_NO, null); + if (serialno == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_SERIALNO_FOR_RENEW")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_MISSING_SERIALNO_FOR_RENEW")); + } + // get cert from db if we're cert authority. + if (mAuthority instanceof ICertificateAuthority) { + cert = getX509Certificate(serialno); + if (cert == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_SERIALNO_FOR_RENEW_1", serialno.toString(16))); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_INVALID_CERT_FOR_RENEWAL")); + } + } + certContainer[0] = cert; + return serialno; + } + + /** + * get cert to renew from auth manager + */ + private BigInteger getCertFromAuthMgr( + IAuthToken authToken, X509Certificate[] certContainer) + throws EBaseException { + X509CertImpl cert = + authToken.getInCert(AuthToken.TOKEN_CERT); + + if (cert == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_CERTS_RENEW_FROM_AUTHMGR")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_MISSING_CERTS_RENEW_FROM_AUTHMGR")); + } + if (mAuthority instanceof ICertificateAuthority && + !isCertFromCA(cert)) { + log(ILogger.LL_FAILURE, "certficate from auth manager for " + + " renewal is not from this ca."); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_INVALID_CERT_FOR_RENEWAL")); + } + certContainer[0] = cert; + BigInteger serialno = ((X509Certificate) cert).getSerialNumber(); + + return serialno; + } + +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/RevocationServlet.java b/base/common/src/com/netscape/cms/servlet/cert/RevocationServlet.java new file mode 100644 index 000000000..22aa29eda --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/RevocationServlet.java @@ -0,0 +1,392 @@ +// --- 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.cert; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Random; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; + +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.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.Nonces; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.ra.IRegistrationAuthority; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.RequestStatus; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; +import com.netscape.cmsutil.util.Utils; + +/** + * Perform the first step in revoking a certificate + * + * @version $Revision$, $Date$ + */ +public class RevocationServlet extends CMSServlet { + /** + * + */ + private static final long serialVersionUID = -9086730404084717413L; + private final static String PROP_REVOKEBYDN = "revokeByDN"; + // revocation templates. + private final static String TPL_FILE = "reasonToRevoke.template"; + + // http params + public static final String SERIAL_NO = "serialNo"; + // XXX can't do pkcs10 cause it's got no serial no. + // (unless put serial no in pki attributes) + // public static final String PKCS10 = "pkcs10"; + public static final String REASON_CODE = "reasonCode"; + + private String mFormPath = null; + private boolean mRevokeByDN = true; + + private Random mRandom = null; + private Nonces mNonces = null; + + public RevocationServlet() { + super(); + } + + /** + * initialize the servlet. This servlet uses + * the template file "reasonToRevoke.template" to render the + * result. + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + // override success template. has same info as enrollment. + mTemplates.remove(CMSRequest.SUCCESS); + + mFormPath = "/" + TPL_FILE; + try { + mFormPath = sc.getInitParameter( + PROP_SUCCESS_TEMPLATE); + if (mFormPath == null) + mFormPath = "/" + TPL_FILE; + + if (mAuthority instanceof ICertificateAuthority) { + if (((ICertificateAuthority) mAuthority).noncesEnabled()) { + mNonces = ((ICertificateAuthority) mAuthority).getNonces(); + mRandom = new Random(); + } + } + + // set to false by revokeByDN=false in web.xml + mRevokeByDN = false; + String tmp = sc.getInitParameter(PROP_REVOKEBYDN); + + if (tmp == null || tmp.trim().equalsIgnoreCase("false")) + mRevokeByDN = false; + else if (tmp.trim().equalsIgnoreCase("true")) + mRevokeByDN = true; + } catch (Exception e) { + } + } + + /** + * Process the HTTP request. Note that this servlet does not + * actually perform the certificate revocation. This is the first + * step in the multi-step revocation process. (the next step is + * in the ReasonToRevoke servlet. + * + * @param cmsReq the object holding the request and response information + */ + protected void process(CMSRequest cmsReq) + throws EBaseException { + IArgBlock httpParams = cmsReq.getHttpParams(); + HttpServletRequest httpReq = cmsReq.getHttpReq(); + HttpServletResponse httpResp = cmsReq.getHttpResp(); + + // revocation requires either: + // - coming from ee: + // - old cert from ssl client auth + // - old certs from auth manager + // - coming from agent or trusted RA: + // - serial no of cert to be revoked. + + BigInteger old_serial_no = null; + X509CertImpl old_cert = null; + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, httpReq, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", mFormPath, e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock ctx = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, ctx); + + IAuthToken authToken = authenticate(cmsReq); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "submit"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + // coming from agent + if (mAuthMgr != null && mAuthMgr.equals(IAuthSubsystem.CERTUSERDB_AUTHMGR_ID)) { + X509Certificate[] cert = new X509Certificate[1]; + + old_serial_no = getCertFromAgent(httpParams, cert); + old_cert = (X509CertImpl) cert[0]; + } // coming from client + else { + // from auth manager + X509CertImpl[] cert = new X509CertImpl[1]; + + old_serial_no = getCertFromAuthMgr(authToken, cert); + old_cert = cert[0]; + } + + header.addStringValue("serialNumber", old_cert.getSerialNumber().toString(16)); + header.addStringValue("serialNumberDecimal", old_cert.getSerialNumber().toString()); + // header.addStringValue("subject", old_cert.getSubjectDN().toString()); + // header.addLongValue("validNotBefore", old_cert.getNotBefore().getTime()/1000); + // header.addLongValue("validNotAfter", old_cert.getNotAfter().getTime()/1000); + + if (mNonces != null) { + long n = mRandom.nextLong(); + long m = mNonces.addNonce(n, (X509Certificate) old_cert); + if ((n + m) != 0) { + header.addStringValue("nonce", Long.toString(m)); + } + } + + boolean noInfo = false; + X509CertImpl[] certsToRevoke = null; + + if (mAuthority instanceof ICertificateAuthority) { + certsToRevoke = ((ICertificateAuthority) mAuthority).getCertificateRepository().getX509Certificates( + old_cert.getSubjectDN().toString(), + ICertificateRepository.ALL_UNREVOKED_CERTS); + + } else if (mAuthority instanceof IRegistrationAuthority) { + IRequest req = mRequestQueue.newRequest(IRequest.GETCERTS_REQUEST); + String filter = "(&(" + ICertRecord.ATTR_X509CERT + "." + + X509CertInfo.SUBJECT + "=" + + old_cert.getSubjectDN().toString() + ")(|(" + + ICertRecord.ATTR_CERT_STATUS + "=" + + ICertRecord.STATUS_VALID + ")(" + + ICertRecord.ATTR_CERT_STATUS + "=" + + ICertRecord.STATUS_EXPIRED + ")))"; + + req.setExtData(IRequest.CERT_FILTER, filter); + mRequestQueue.processRequest(req); + RequestStatus status = req.getRequestStatus(); + + if (status == RequestStatus.COMPLETE) { + header.addStringValue("request", req.getRequestId().toString()); + Enumeration enum1 = req.getExtDataKeys(); + + while (enum1.hasMoreElements()) { + String name = enum1.nextElement(); + + if (name.equals(IRequest.OLD_CERTS)) { + X509CertImpl[] certs = req.getExtDataInCertArray(IRequest.OLD_CERTS); + + certsToRevoke = certs; + } + } + } else { + noInfo = true; + } + } + + boolean authorized = false; + + if (certsToRevoke != null && certsToRevoke.length > 0) { + for (int i = 0; i < certsToRevoke.length; i++) { + if (old_cert.getSerialNumber().equals(certsToRevoke[i].getSerialNumber())) { + authorized = true; + break; + } + } + } + + if (!noInfo && (certsToRevoke == null || certsToRevoke.length == 0 || + (!authorized))) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CA_CERT_ALREADY_REVOKED_1", old_serial_no.toString(16))); + throw new ECMSGWException(CMS.getUserMessage("CMS_GW_CERT_ALREADY_REVOKED")); + } + + if (!mRevokeByDN || noInfo) { + certsToRevoke = new X509CertImpl[1]; + certsToRevoke[0] = old_cert; + try { + byte[] ba = old_cert.getEncoded(); + // Do base 64 encoding + + header.addStringValue("b64eCertificate", Utils.base64encode(ba)); + } catch (CertificateEncodingException e) { + } + } + + if (certsToRevoke != null && certsToRevoke.length > 0) { + header.addIntegerValue("totalRecordCount", certsToRevoke.length); + header.addIntegerValue("verifiedRecordCount", certsToRevoke.length); + + for (int i = 0; i < certsToRevoke.length; i++) { + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addStringValue("serialNumber", + certsToRevoke[i].getSerialNumber().toString(16)); + rarg.addStringValue("serialNumberDecimal", + certsToRevoke[i].getSerialNumber().toString()); + rarg.addStringValue("subject", + certsToRevoke[i].getSubjectDN().toString()); + rarg.addLongValue("validNotBefore", + certsToRevoke[i].getNotBefore().getTime() / 1000); + rarg.addLongValue("validNotAfter", + certsToRevoke[i].getNotAfter().getTime() / 1000); + argSet.addRepeatRecord(rarg); + } + } else { + header.addIntegerValue("totalRecordCount", 0); + header.addIntegerValue("verifiedRecordCount", 0); + } + + // set revocation reason, default to unspecified if not set. + int reasonCode = httpParams.getValueAsInt(REASON_CODE, 0); + + header.addIntegerValue("reason", reasonCode); + + try { + ServletOutputStream out = httpResp.getOutputStream(); + + httpResp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_OUT_STREAM_TEMPLATE", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + return; + } + + /** + * get cert to revoke from agent. + */ + private BigInteger getCertFromAgent( + IArgBlock httpParams, X509Certificate[] certContainer) + throws EBaseException { + BigInteger serialno = null; + X509Certificate cert = null; + + // get serial no + serialno = httpParams.getValueAsBigInteger(SERIAL_NO, null); + if (serialno == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_SERIALNO_FOR_REVOKE")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_MISSING_SERIALNO_FOR_REVOKE")); + } + + // get cert from db if we're cert authority. + if (mAuthority instanceof ICertificateAuthority) { + cert = getX509Certificate(serialno); + if (cert == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_INVALID_CERT_FOR_REVOCATION")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_INVALID_CERT_FOR_REVOCATION")); + } + } + certContainer[0] = cert; + return serialno; + } + + /** + * get cert to revoke from auth manager + */ + private BigInteger getCertFromAuthMgr( + IAuthToken authToken, X509Certificate[] certContainer) + throws EBaseException { + X509CertImpl cert = + authToken.getInCert(AuthToken.TOKEN_CERT); + + if (cert == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_CERTS_REVOKE_FROM_AUTHMGR")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_MISSING_CERTS_REVOKE_FROM_AUTHMGR")); + } + if (mAuthority instanceof ICertificateAuthority && + !isCertFromCA(cert)) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_INVALID_CERT_FOR_REVOCATION")); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_INVALID_CERT_FOR_REVOCATION")); + } + certContainer[0] = cert; + BigInteger serialno = ((X509Certificate) cert).getSerialNumber(); + + return serialno; + } + +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/RevocationSuccessTemplateFiller.java b/base/common/src/com/netscape/cms/servlet/cert/RevocationSuccessTemplateFiller.java new file mode 100644 index 000000000..cfc562d71 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/RevocationSuccessTemplateFiller.java @@ -0,0 +1,97 @@ +// --- 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.cert; + +import java.util.Locale; + +import javax.servlet.http.HttpServletRequest; + +import netscape.security.x509.RevokedCertImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authority.IAuthority; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ICMSTemplateFiller; + +/** + * Certificates Template filler. + * must have list of certificates in result. + * looks at inputs: certtype. + * outputs: + * - cert type from http input (if any) + * - CA chain + * - authority name (RM, CM, DRM) + * - scheme:host:port of server. + * array of one or more + * - cert serial number + * - cert pretty print + * - cert in base 64 encoding. + * - cmmf blob to import + * + * @version $Revision$, $Date$ + */ +class RevocationSuccessTemplateFiller implements ICMSTemplateFiller { + public final static String SERIAL_NO = "serialNo"; + + public RevocationSuccessTemplateFiller() { + } + + /** + * @param cmsReq CMS Request + * @param authority this authority + * @param locale locale of template. + * @param e unexpected exception e. ignored. + */ + public CMSTemplateParams getTemplateParams( + CMSRequest cmsReq, IAuthority authority, Locale locale, Exception e) + throws Exception { + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams params = new CMSTemplateParams(null, fixed); + + // set host name and port. + HttpServletRequest httpReq = cmsReq.getHttpReq(); + String host = httpReq.getServerName(); + int port = httpReq.getServerPort(); + String scheme = httpReq.getScheme(); + + fixed.set(ICMSTemplateFiller.HOST, host); + fixed.set(ICMSTemplateFiller.PORT, Integer.valueOf(port)); + fixed.set(ICMSTemplateFiller.SCHEME, scheme); + + // this authority + fixed.set(ICMSTemplateFiller.AUTHORITY, + (String) authority.getOfficialName()); + + // XXX CA chain. + + RevokedCertImpl[] revoked = + (RevokedCertImpl[]) cmsReq.getResult(); + + // revoked certs. + for (int i = 0; i < revoked.length; i++) { + IArgBlock repeat = CMS.createArgBlock(); + + repeat.set(SERIAL_NO, revoked[i].getSerialNumber()); + params.addRepeatRecord(repeat); + } + + return params; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/SrchCerts.java b/base/common/src/com/netscape/cms/servlet/cert/SrchCerts.java new file mode 100644 index 000000000..3602515c9 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/SrchCerts.java @@ -0,0 +1,762 @@ +// --- 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.cert; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.PublicKey; +import java.util.Calendar; +import java.util.Date; +import java.util.Enumeration; +import java.util.Locale; +import java.util.StringTokenizer; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.provider.RSAPublicKey; +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.CRLReasonExtension; +import netscape.security.x509.CertificateX509Key; +import netscape.security.x509.Extension; +import netscape.security.x509.X500Name; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509Key; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.dbs.certdb.IRevocationInfo; +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.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Search for certificates matching complex query filter + * + * @version $Revision$, $Date$ + */ +public class SrchCerts extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = -5876805830088921643L; + private final static String TPL_FILE = "srchCert.template"; + private final static String INFO = "SrchCerts"; + private final static BigInteger MINUS_ONE = new BigInteger("-1"); + private final static String PROP_MAX_SEARCH_RETURNS = "maxSearchReturns"; + + private final static String CURRENT_TIME = "currentTime"; + private final static int MAX_RESULTS = 1000; + + private ICertificateRepository mCertDB = null; + private X500Name mAuthName = null; + private String mFormPath = null; + private int mMaxReturns = MAX_RESULTS; + private int mTimeLimits = 30; /* in seconds */ + private boolean mUseClientFilter = false; + + /** + * Constructs query key servlet. + */ + public SrchCerts() { + super(); + } + + /** + * initialize the servlet. This servlet uses srchCert.template + * to render the response + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + // override success to render own template. + mTemplates.remove(CMSRequest.SUCCESS); + + if (mAuthority instanceof ISubsystem) { + ISubsystem sub = (ISubsystem) mAuthority; + IConfigStore authConfig = sub.getConfigStore(); + + if (authConfig != null) { + try { + mMaxReturns = authConfig.getInteger(PROP_MAX_SEARCH_RETURNS, MAX_RESULTS); + } catch (EBaseException e) { + // do nothing + } + } + } + if (mAuthority instanceof ICertificateAuthority) { + ICertificateAuthority ca = (ICertificateAuthority) mAuthority; + + mCertDB = ca.getCertificateRepository(); + mAuthName = ca.getX500Name(); + } + + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + + /* Server-Side time limit */ + try { + int maxResults = Integer.parseInt(sc.getInitParameter("maxResults")); + if (maxResults < mMaxReturns) + mMaxReturns = maxResults; + } catch (Exception e) { + /* do nothing, just use the default if integer parsing failed */ + } + try { + mTimeLimits = Integer.parseInt(sc.getInitParameter("timeLimits")); + } catch (Exception e) { + /* do nothing, just use the default if integer parsing failed */ + } + + /* useClientFilter should be off by default. We keep + this parameter around so that we do not break + the client applications that submits raw LDAP + filter into this servlet. */ + if (sc.getInitParameter("useClientFilter") != null && + sc.getInitParameter("useClientFilter").equalsIgnoreCase("true")) { + mUseClientFilter = true; + } + } + + private boolean isOn(HttpServletRequest req, String name) { + String inUse = req.getParameter(name); + if (inUse == null) { + return false; + } + if (inUse.equals("on")) { + return true; + } + return false; + } + + private boolean isOff(HttpServletRequest req, String name) { + String inUse = req.getParameter(name); + if (inUse == null) { + return false; + } + if (inUse.equals("off")) { + return true; + } + return false; + } + + private void buildCertStatusFilter(HttpServletRequest req, StringBuffer filter) { + if (!isOn(req, "statusInUse")) { + return; + } + String status = req.getParameter("status"); + filter.append("(certStatus="); + filter.append(status); + filter.append(")"); + } + + private void buildProfileFilter(HttpServletRequest req, StringBuffer filter) { + if (!isOn(req, "profileInUse")) { + return; + } + String profile = req.getParameter("profile"); + filter.append("(certMetaInfo=profileId:"); + filter.append(profile); + filter.append(")"); + } + + private void buildBasicConstraintsFilter(HttpServletRequest req, StringBuffer filter) { + if (!isOn(req, "basicConstraintsInUse")) { + return; + } + filter.append("(x509cert.BasicConstraints.isCA=on)"); + } + + private void buildSerialNumberRangeFilter(HttpServletRequest req, StringBuffer filter) { + if (!isOn(req, "serialNumberRangeInUse")) { + return; + } + boolean changed = false; + String serialFrom = req.getParameter("serialFrom"); + if (serialFrom != null && !serialFrom.equals("")) { + filter.append("(certRecordId>=" + serialFrom + ")"); + changed = true; + } + String serialTo = req.getParameter("serialTo"); + if (serialTo != null && !serialTo.equals("")) { + filter.append("(certRecordId<=" + serialTo + ")"); + changed = true; + } + if (!changed) { + filter.append("(certRecordId=*)"); + } + } + + private void buildAVAFilter(HttpServletRequest req, String paramName, + String avaName, StringBuffer lf, String match) { + String val = req.getParameter(paramName); + if (val != null && !val.equals("")) { + if (match != null && match.equals("exact")) { + lf.append("(|"); + lf.append("(x509cert.subject=*"); + lf.append(avaName); + lf.append("="); + lf.append(escapeValueRfc1779(val, true)); + lf.append(",*)"); + lf.append("(x509cert.subject=*"); + lf.append(avaName); + lf.append("="); + lf.append(escapeValueRfc1779(val, true)); + lf.append(")"); + lf.append(")"); + } else { + lf.append("(x509cert.subject=*"); + lf.append(avaName); + lf.append("="); + lf.append("*"); + lf.append(escapeValueRfc1779(val, true)); + lf.append("*)"); + } + } + } + + private void buildSubjectFilter(HttpServletRequest req, StringBuffer filter) { + if (!isOn(req, "subjectInUse")) { + return; + } + StringBuffer lf = new StringBuffer(); + String match = req.getParameter("match"); + + buildAVAFilter(req, "eMail", "E", lf, match); + buildAVAFilter(req, "commonName", "CN", lf, match); + buildAVAFilter(req, "userID", "UID", lf, match); + buildAVAFilter(req, "orgUnit", "OU", lf, match); + buildAVAFilter(req, "org", "O", lf, match); + buildAVAFilter(req, "locality", "L", lf, match); + buildAVAFilter(req, "state", "ST", lf, match); + buildAVAFilter(req, "country", "C", lf, match); + + if (lf.length() == 0) { + filter.append("(x509cert.subject=*)"); + return; + } + if (match.equals("exact")) { + filter.append("(&"); + filter.append(lf); + filter.append(")"); + } else { + filter.append("(|"); + filter.append(lf); + filter.append(")"); + } + } + + private void buildRevokedByFilter(HttpServletRequest req, + StringBuffer filter) { + if (!isOn(req, "revokedByInUse")) { + return; + } + String revokedBy = req.getParameter("revokedBy"); + if (revokedBy == null || revokedBy.equals("")) { + filter.append("(certRevokedBy=*)"); + } else { + filter.append("(certRevokedBy="); + filter.append(revokedBy); + filter.append(")"); + } + } + + private void buildDateFilter(HttpServletRequest req, String prefix, + String outStr, long adjustment, + StringBuffer filter) { + long epoch = 0; + try { + epoch = Long.parseLong(req.getParameter(prefix)); + } catch (NumberFormatException e) { + // exception safely ignored + } + Calendar from = Calendar.getInstance(); + from.setTimeInMillis(epoch); + CMS.debug("buildDateFilter epoch=" + req.getParameter(prefix)); + CMS.debug("buildDateFilter from=" + from); + filter.append("("); + filter.append(outStr); + filter.append(Long.toString(from.getTimeInMillis() + adjustment)); + filter.append(")"); + } + + private void buildRevokedOnFilter(HttpServletRequest req, + StringBuffer filter) { + if (!isOn(req, "revokedOnInUse")) { + return; + } + buildDateFilter(req, "revokedOnFrom", "certRevokedOn>=", 0, filter); + buildDateFilter(req, "revokedOnTo", "certRevokedOn<=", 86399999, + filter); + } + + private void buildRevocationReasonFilter(HttpServletRequest req, + StringBuffer filter) { + if (!isOn(req, "revocationReasonInUse")) { + return; + } + String reasons = req.getParameter("revocationReason"); + if (reasons == null) { + return; + } + String queryCertFilter = null; + StringTokenizer st = new StringTokenizer(reasons, ","); + if (st.hasMoreTokens()) { + filter.append("(|"); + while (st.hasMoreTokens()) { + String token = st.nextToken(); + if (queryCertFilter == null) { + queryCertFilter = ""; + } + filter.append("(x509cert.certRevoInfo="); + filter.append(token); + filter.append(")"); + } + filter.append(")"); + } + } + + private void buildIssuedByFilter(HttpServletRequest req, + StringBuffer filter) { + if (!isOn(req, "issuedByInUse")) { + return; + } + String issuedBy = req.getParameter("issuedBy"); + if (issuedBy == null || issuedBy.equals("")) { + filter.append("(certIssuedBy=*)"); + } else { + filter.append("(certIssuedBy="); + filter.append(issuedBy); + filter.append(")"); + } + } + + private void buildIssuedOnFilter(HttpServletRequest req, + StringBuffer filter) { + if (!isOn(req, "issuedOnInUse")) { + return; + } + buildDateFilter(req, "issuedOnFrom", "certCreateTime>=", 0, filter); + buildDateFilter(req, "issuedOnTo", "certCreateTime<=", 86399999, + filter); + } + + private void buildValidNotBeforeFilter(HttpServletRequest req, + StringBuffer filter) { + if (!isOn(req, "validNotBeforeInUse")) { + return; + } + buildDateFilter(req, "validNotBeforeFrom", "x509cert.notBefore>=", + 0, filter); + buildDateFilter(req, "validNotBeforeTo", "x509cert.notBefore<=", + 86399999, filter); + } + + private void buildValidNotAfterFilter(HttpServletRequest req, + StringBuffer filter) { + if (!isOn(req, "validNotAfterInUse")) { + return; + } + buildDateFilter(req, "validNotAfterFrom", "x509cert.notAfter>=", + 0, filter); + buildDateFilter(req, "validNotAfterTo", "x509cert.notAfter<=", + 86399999, filter); + } + + private void buildValidityLengthFilter(HttpServletRequest req, + StringBuffer filter) { + if (!isOn(req, "validityLengthInUse")) { + return; + } + String op = req.getParameter("validityOp"); + long count = 0; + try { + count = Long.parseLong(req.getParameter("count")); + } catch (NumberFormatException e) { + // safely ignore + } + long unit = 0; + try { + unit = Long.parseLong(req.getParameter("unit")); + } catch (NumberFormatException e) { + // safely ignore + } + filter.append("("); + filter.append("x509cert.duration"); + filter.append(op); + filter.append(count * unit); + filter.append(")"); + } + + private void buildCertTypeFilter(HttpServletRequest req, + StringBuffer filter) { + if (!isOn(req, "certTypeInUse")) { + return; + } + if (isOn(req, "SSLClient")) { + filter.append("(x509cert.nsExtension.SSLClient=on)"); + } else if (isOff(req, "SSLClient")) { + filter.append("(x509cert.nsExtension.SSLClient=off)"); + } + if (isOn(req, "SSLServer")) { + filter.append("(x509cert.nsExtension.SSLServer=on)"); + } else if (isOff(req, "SSLServer")) { + filter.append("(x509cert.nsExtension.SSLServer=off)"); + } + if (isOn(req, "SecureEmail")) { + filter.append("(x509cert.nsExtension.SecureEmail=on)"); + } else if (isOff(req, "SecureEmail")) { + filter.append("(x509cert.nsExtension.SecureEmail=off)"); + } + if (isOn(req, "SubordinateSSLCA")) { + filter.append("(x509cert.nsExtension.SubordinateSSLCA=on)"); + } else if (isOff(req, "SubordinateSSLCA")) { + filter.append("(x509cert.nsExtension.SubordinateSSLCA=off)"); + } + if (isOn(req, "SubordinateEmailCA")) { + filter.append("(x509cert.nsExtension.SubordinateEmailCA=on)"); + } else if (isOff(req, "SubordinateEmailCA")) { + filter.append("(x509cert.nsExtension.SubordinateEmailCA=off)"); + } + } + + public String buildFilter(HttpServletRequest req) { + String queryCertFilter = req.getParameter("queryCertFilter"); + + StringBuffer filter = new StringBuffer(); + buildSerialNumberRangeFilter(req, filter); + buildSubjectFilter(req, filter); + buildRevokedByFilter(req, filter); + buildRevokedOnFilter(req, filter); + buildRevocationReasonFilter(req, filter); + buildIssuedByFilter(req, filter); + buildIssuedOnFilter(req, filter); + buildValidNotBeforeFilter(req, filter); + buildValidNotAfterFilter(req, filter); + buildValidityLengthFilter(req, filter); + buildCertTypeFilter(req, filter); + buildCertStatusFilter(req, filter); + buildProfileFilter(req, filter); + buildBasicConstraintsFilter(req, filter); + + if (mUseClientFilter) { + CMS.debug("useClientFilter=true"); + } else { + CMS.debug("useClientFilter=false"); + CMS.debug("client queryCertFilter = " + queryCertFilter); + queryCertFilter = "(&" + filter.toString() + ")"; + } + CMS.debug("queryCertFilter = " + queryCertFilter); + return queryCertFilter; + } + + /** + * Serves HTTP request. This format of this request is as follows: + * queryCert? + * [maxCount=] + * [queryFilter=] + * [revokeAll=] + */ + public void process(CMSRequest cmsReq) throws EBaseException { + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "list"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + String revokeAll = null; + EBaseException error = null; + int maxResults = -1; + int timeLimit = -1; + + IArgBlock header = CMS.createArgBlock(); + IArgBlock ctx = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, ctx); + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + if (mOutputTemplatePath != null) + mFormPath = mOutputTemplatePath; + + try { + form = getTemplate(mFormPath, req, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + try { + revokeAll = req.getParameter("revokeAll"); + + String maxResultsStr = req.getParameter("maxResults"); + + if (maxResultsStr != null && maxResultsStr.length() > 0) + maxResults = Integer.parseInt(maxResultsStr); + String timeLimitStr = req.getParameter("timeLimit"); + + if (timeLimitStr != null && timeLimitStr.length() > 0) + timeLimit = Integer.parseInt(timeLimitStr); + + String queryCertFilter = buildFilter(req); + process(argSet, header, queryCertFilter, + revokeAll, maxResults, timeLimit, req, resp, locale[0]); + } catch (NumberFormatException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("BASE_INVALID_NUMBER_FORMAT")); + error = new EBaseException(CMS.getUserMessage(getLocale(req), "CMS_BASE_INVALID_NUMBER_FORMAT")); + } catch (EBaseException e) { + error = e; + } + + try { + ServletOutputStream out = resp.getOutputStream(); + + if (error == null) { + String xmlOutput = req.getParameter("xml"); + if (xmlOutput != null && xmlOutput.equals("true")) { + outputXML(resp, argSet); + } else { + cmsReq.setStatus(CMSRequest.SUCCESS); + resp.setContentType("text/html"); + form.renderOutput(out, argSet); + } + } else { + cmsReq.setStatus(CMSRequest.ERROR); + cmsReq.setError(error); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_OUT_STREAM_TEMPLATE", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + } + + /** + * Process the key search. + */ + private void process(CMSTemplateParams argSet, IArgBlock header, + String filter, String revokeAll, + int maxResults, int timeLimit, + HttpServletRequest req, HttpServletResponse resp, + Locale locale) + throws EBaseException { + try { + long startTime = CMS.getCurrentDate().getTime(); + + if (filter.indexOf(CURRENT_TIME, 0) > -1) { + filter = insertCurrentTime(filter); + } + + // xxx the filter includes serial number range??? + if (maxResults == -1 || maxResults > mMaxReturns) { + CMS.debug("Resetting maximum of returned results from " + maxResults + " to " + mMaxReturns); + maxResults = mMaxReturns; + } + if (timeLimit == -1 || timeLimit > mTimeLimits) { + CMS.debug("Resetting timelimit from " + timeLimit + " to " + mTimeLimits); + timeLimit = mTimeLimits; + } + CMS.debug("Start searching ... " + + "filter=" + filter + " maxreturns=" + maxResults + " timelimit=" + timeLimit); + Enumeration e = mCertDB.searchCertificates(filter, maxResults, timeLimit); + + int count = 0; + + while (e != null && e.hasMoreElements()) { + ICertRecord rec = e.nextElement(); + + if (rec != null) { + count++; + IArgBlock rarg = CMS.createArgBlock(); + + fillRecordIntoArg(rec, rarg); + argSet.addRepeatRecord(rarg); + } + } + + long endTime = CMS.getCurrentDate().getTime(); + + header.addStringValue("op", req.getParameter("op")); + if (mAuthName != null) + header.addStringValue("issuerName", mAuthName.toString()); + header.addStringValue("time", Long.toString(endTime - startTime)); + header.addStringValue("serviceURL", req.getRequestURI()); + header.addStringValue("queryFilter", filter); + if (revokeAll != null) + header.addStringValue("revokeAll", revokeAll); + header.addIntegerValue("totalRecordCount", count); + header.addIntegerValue("maxSize", maxResults); + } catch (EBaseException e) { + CMS.getLogMessage("CMSGW_ERROR_LISTCERTS", e.toString()); + throw e; + } + return; + } + + private String insertCurrentTime(String filter) { + Date now = null; + StringBuffer newFilter = new StringBuffer(); + int k = 0; + int i = filter.indexOf(CURRENT_TIME, k); + + while (i > -1) { + if (now == null) + now = new Date(); + newFilter.append(filter.substring(k, i)); + newFilter.append(now.getTime()); + k = i + CURRENT_TIME.length(); + i = filter.indexOf(CURRENT_TIME, k); + } + if (k > 0) { + newFilter.append(filter.substring(k, filter.length())); + } + return newFilter.toString(); + } + + /** + * Fills cert record into argument block. + */ + private void fillRecordIntoArg(ICertRecord rec, IArgBlock rarg) + throws EBaseException { + + X509CertImpl xcert = rec.getCertificate(); + + if (xcert != null) { + fillX509RecordIntoArg(rec, rarg); + } + } + + private void fillX509RecordIntoArg(ICertRecord rec, IArgBlock rarg) + throws EBaseException { + + X509CertImpl cert = rec.getCertificate(); + + rarg.addIntegerValue("version", cert.getVersion()); + rarg.addStringValue("serialNumber", cert.getSerialNumber().toString(16)); + rarg.addStringValue("serialNumberDecimal", cert.getSerialNumber().toString()); + + String subject = (String) cert.getSubjectDN().toString(); + + if (subject.equals("")) { + rarg.addStringValue("subject", " "); + } else { + rarg.addStringValue("subject", subject); + + } + + rarg.addStringValue("type", "X.509"); + + try { + PublicKey pKey = cert.getPublicKey(); + X509Key key = null; + + if (pKey instanceof CertificateX509Key) { + CertificateX509Key certKey = (CertificateX509Key) pKey; + + key = (X509Key) certKey.get(CertificateX509Key.KEY); + } + if (pKey instanceof X509Key) { + key = (X509Key) pKey; + } + rarg.addStringValue("subjectPublicKeyAlgorithm", key.getAlgorithmId().getOID().toString()); + if (key.getAlgorithmId().toString().equalsIgnoreCase("RSA")) { + RSAPublicKey rsaKey = new RSAPublicKey(key.getEncoded()); + + rarg.addIntegerValue("subjectPublicKeyLength", rsaKey.getKeySize()); + } + } catch (Exception e) { + rarg.addStringValue("subjectPublicKeyAlgorithm", null); + rarg.addIntegerValue("subjectPublicKeyLength", 0); + } + + rarg.addLongValue("validNotBefore", cert.getNotBefore().getTime() / 1000); + rarg.addLongValue("validNotAfter", cert.getNotAfter().getTime() / 1000); + rarg.addStringValue("signatureAlgorithm", cert.getSigAlgOID()); + String issuedBy = rec.getIssuedBy(); + + if (issuedBy == null) + issuedBy = ""; + rarg.addStringValue("issuedBy", issuedBy); // cert.getIssuerDN().toString() + rarg.addLongValue("issuedOn", rec.getCreateTime().getTime() / 1000); + + rarg.addStringValue("revokedBy", + ((rec.getRevokedBy() == null) ? "" : rec.getRevokedBy())); + if (rec.getRevokedOn() == null) { + rarg.addStringValue("revokedOn", null); + } else { + rarg.addLongValue("revokedOn", rec.getRevokedOn().getTime() / 1000); + + IRevocationInfo revocationInfo = rec.getRevocationInfo(); + + if (revocationInfo != null) { + CRLExtensions crlExts = revocationInfo.getCRLEntryExtensions(); + + if (crlExts != null) { + Enumeration enum1 = crlExts.getElements(); + int reason = 0; + + while (enum1.hasMoreElements()) { + Extension ext = enum1.nextElement(); + + if (ext instanceof CRLReasonExtension) { + reason = ((CRLReasonExtension) ext).getReason().toInt(); + break; + } + } + rarg.addIntegerValue("revocationReason", reason); + } + } + } + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/UpdateCRL.java b/base/common/src/com/netscape/cms/servlet/cert/UpdateCRL.java new file mode 100644 index 000000000..c0298d1e7 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/UpdateCRL.java @@ -0,0 +1,530 @@ +// --- 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.cert; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.Date; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.CRLReasonExtension; +import netscape.security.x509.InvalidityDateExtension; +import netscape.security.x509.RevocationReason; +import netscape.security.x509.RevokedCertImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.AuthToken; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.SessionContext; +import com.netscape.certsrv.ca.EErrorPublishCRL; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.ldap.ELdapException; +import com.netscape.certsrv.logging.AuditFormat; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.publish.ILdapRule; +import com.netscape.certsrv.publish.IPublisherProcessor; +import com.netscape.certsrv.util.IStatsSubsystem; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Force the CRL to be updated now. + * + * @version $Revision$, $Date$ + */ +public class UpdateCRL extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = -1182106454856991246L; + private final static String INFO = "UpdateCRL"; + private final static String TPL_FILE = "updateCRL.template"; + + private static Vector mTesting = new Vector(); + + private String mFormPath = null; + private ICertificateAuthority mCA = null; + + /** + * Constructs UpdateCRL servlet. + */ + public UpdateCRL() { + super(); + } + + /** + * Initializes the servlet. This servlet uses updateCRL.template + * to render the result + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + if (mAuthority instanceof ICertificateAuthority) + mCA = (ICertificateAuthority) mAuthority; + + // override success to do output orw own template. + mTemplates.remove(CMSRequest.SUCCESS); + if (mOutputTemplatePath != null) + mFormPath = mOutputTemplatePath; + } + + /** + * Process the HTTP request. + *
      + *
    • http.param signatureAlgorithm the algorithm to use to sign the CRL + *
    • http.param waitForUpdate true/false - should the servlet wait until the CRL update is complete? + *
    • http.param clearCRLCache true/false - should the CRL cache cleared before the CRL is generated? + *
    • http.param crlIssuingPoint the CRL Issuing Point to Update + *
    + * + * @param cmsReq the object holding the request and response information + */ + public void process(CMSRequest cmsReq) throws EBaseException { + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + IStatsSubsystem statsSub = (IStatsSubsystem) CMS.getSubsystem("stats"); + if (statsSub != null) { + statsSub.startTiming("crl", true /* main action */); + } + + IAuthToken authToken = authenticate(cmsReq); + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "update"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + if (statsSub != null) { + statsSub.endTiming("crl"); + } + return; + } + + EBaseException error = null; + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, req, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", mFormPath, e.toString())); + if (statsSub != null) { + statsSub.endTiming("crl"); + } + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + try { + String signatureAlgorithm = + req.getParameter("signatureAlgorithm"); + + process(argSet, header, req, resp, + signatureAlgorithm, locale[0]); + } catch (EBaseException e) { + error = e; + } + + try { + ServletOutputStream out = resp.getOutputStream(); + + if (error == null) { + String xmlOutput = req.getParameter("xml"); + if (xmlOutput != null && xmlOutput.equals("true")) { + outputXML(resp, argSet); + } else { + resp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } + } else { + cmsReq.setStatus(CMSRequest.ERROR); + cmsReq.setError(error); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_STREAM_TEMPLATE", + e.toString())); + if (statsSub != null) { + statsSub.endTiming("crl"); + } + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + if (statsSub != null) { + statsSub.endTiming("crl"); + } + } + + private CRLExtensions crlEntryExtensions(String reason, String invalidity) { + CRLExtensions entryExts = new CRLExtensions(); + + CRLReasonExtension crlReasonExtn = null; + if (reason != null && reason.length() > 0) { + try { + RevocationReason revReason = RevocationReason.fromInt(Integer.parseInt(reason)); + if (revReason == null) + revReason = RevocationReason.UNSPECIFIED; + crlReasonExtn = new CRLReasonExtension(revReason); + } catch (Exception e) { + CMS.debug("Invalid revocation reason: " + reason); + } + } + + InvalidityDateExtension invalidityDateExtn = null; + if (invalidity != null && invalidity.length() > 0) { + long now = System.currentTimeMillis(); + Date invalidityDate = null; + try { + long backInTime = Long.parseLong(invalidity); + invalidityDate = new Date(now - (backInTime * 60000)); + } catch (Exception e) { + CMS.debug("Invalid invalidity time offset: " + invalidity); + } + if (invalidityDate != null) { + try { + invalidityDateExtn = new InvalidityDateExtension(invalidityDate); + } catch (Exception e) { + CMS.debug("Error creating invalidity extension: " + e); + } + } + } + + if (crlReasonExtn != null) { + try { + entryExts.set(crlReasonExtn.getName(), crlReasonExtn); + } catch (Exception e) { + CMS.debug("Error adding revocation reason extension to entry extensions: " + e); + } + } + + if (invalidityDateExtn != null) { + try { + entryExts.set(invalidityDateExtn.getName(), invalidityDateExtn); + } catch (Exception e) { + CMS.debug("Error adding invalidity date extension to entry extensions: " + e); + } + } + + return entryExts; + } + + private void addInfo(CMSTemplateParams argSet, ICRLIssuingPoint crlIssuingPoint, long cacheUpdate) { + IArgBlock rarg = CMS.createArgBlock(); + + rarg.addLongValue("cacheUpdate", cacheUpdate); + + String crlNumbers = crlIssuingPoint.getCRLNumber().toString(); + BigInteger deltaNumber = crlIssuingPoint.getDeltaCRLNumber(); + String crlSizes = "" + crlIssuingPoint.getCRLSize(); + if (deltaNumber != null && deltaNumber.compareTo(BigInteger.ZERO) > 0) { + if (crlNumbers != null) + crlNumbers += ","; + if (crlNumbers != null) + crlNumbers += deltaNumber.toString(); + if (crlSizes != null) + crlSizes += "," + crlIssuingPoint.getDeltaCRLSize(); + } + rarg.addStringValue("crlNumbers", crlNumbers); + rarg.addStringValue("crlSizes", crlSizes); + + StringBuffer crlSplits = new StringBuffer(); + Vector splits = crlIssuingPoint.getSplitTimes(); + for (int i = 0; i < splits.size(); i++) { + crlSplits.append(splits.elementAt(i)); + if (i + 1 < splits.size()) + crlSplits.append(","); + } + rarg.addStringValue("crlSplits", crlSplits.toString()); + + argSet.addRepeatRecord(rarg); + } + + private void process(CMSTemplateParams argSet, IArgBlock header, + HttpServletRequest req, + HttpServletResponse resp, + String signatureAlgorithm, + Locale locale) + throws EBaseException { + long startTime = CMS.getCurrentDate().getTime(); + String waitForUpdate = + req.getParameter("waitForUpdate"); + String clearCache = + req.getParameter("clearCRLCache"); + String crlIssuingPointId = + req.getParameter("crlIssuingPoint"); + String test = req.getParameter("test"); + String add = req.getParameter("add"); + String from = req.getParameter("from"); + String by = req.getParameter("by"); + String reason = req.getParameter("reason"); + String invalidity = req.getParameter("invalidity"); + String results = req.getParameter("results"); + + if (crlIssuingPointId != null) { + Enumeration ips = mCA.getCRLIssuingPoints(); + + while (ips.hasMoreElements()) { + ICRLIssuingPoint ip = ips.nextElement(); + + if (crlIssuingPointId.equals(ip.getId())) { + break; + } + if (!ips.hasMoreElements()) + crlIssuingPointId = null; + } + } + if (crlIssuingPointId == null) { + crlIssuingPointId = ICertificateAuthority.PROP_MASTER_CRL; + } + + ICRLIssuingPoint crlIssuingPoint = + mCA.getCRLIssuingPoint(crlIssuingPointId); + header.addStringValue("crlIssuingPoint", crlIssuingPointId); + IPublisherProcessor lpm = mCA.getPublisherProcessor(); + + if (crlIssuingPoint != null) { + if (clearCache != null && clearCache.equals("true") && + crlIssuingPoint.isCRLGenerationEnabled() && + crlIssuingPoint.isCRLUpdateInProgress() == ICRLIssuingPoint.CRL_UPDATE_DONE && + crlIssuingPoint.isCRLIssuingPointInitialized() + == ICRLIssuingPoint.CRL_IP_INITIALIZED) { + crlIssuingPoint.clearCRLCache(); + } + if (waitForUpdate != null && waitForUpdate.equals("true") && + crlIssuingPoint.isCRLGenerationEnabled() && + crlIssuingPoint.isCRLUpdateInProgress() == ICRLIssuingPoint.CRL_UPDATE_DONE && + crlIssuingPoint.isCRLIssuingPointInitialized() + == ICRLIssuingPoint.CRL_IP_INITIALIZED) { + if (test != null && test.equals("true") && + crlIssuingPoint.isCRLCacheTestingEnabled() && + (!mTesting.contains(crlIssuingPointId))) { + CMS.debug("CRL test started."); + mTesting.add(crlIssuingPointId); + BigInteger addLen = null; + BigInteger startFrom = null; + if (add != null && add.length() > 0 && + from != null && from.length() > 0) { + try { + addLen = new BigInteger(add); + startFrom = new BigInteger(from); + } catch (Exception e) { + } + } + if (addLen != null && startFrom != null) { + Date revocationDate = CMS.getCurrentDate(); + String err = null; + + CRLExtensions entryExts = crlEntryExtensions(reason, invalidity); + + BigInteger serialNumber = startFrom; + BigInteger counter = addLen; + BigInteger stepBy = null; + if (by != null && by.length() > 0) { + try { + stepBy = new BigInteger(by); + } catch (Exception e) { + } + } + + long t1 = System.currentTimeMillis(); + long t2 = 0; + + while (counter.compareTo(BigInteger.ZERO) > 0) { + RevokedCertImpl revokedCert = + new RevokedCertImpl(serialNumber, revocationDate, entryExts); + crlIssuingPoint.addRevokedCert(serialNumber, revokedCert); + serialNumber = serialNumber.add(BigInteger.ONE); + counter = counter.subtract(BigInteger.ONE); + + if ((counter.compareTo(BigInteger.ZERO) == 0) || + (stepBy != null && ((counter.mod(stepBy)).compareTo(BigInteger.ZERO) == 0))) { + t2 = System.currentTimeMillis(); + long t0 = t2 - t1; + t1 = t2; + try { + if (signatureAlgorithm != null) { + crlIssuingPoint.updateCRLNow(signatureAlgorithm); + } else { + crlIssuingPoint.updateCRLNow(); + } + } catch (Throwable e) { + counter = BigInteger.ZERO; + err = e.toString(); + } + if (results != null && results.equals("1")) { + addInfo(argSet, crlIssuingPoint, t0); + } + } + } + if (err != null) { + header.addStringValue("crlUpdate", "Failure"); + header.addStringValue("error", err); + } else { + header.addStringValue("crlUpdate", "Success"); + } + } else { + CMS.debug("CRL test error: missing parameters."); + header.addStringValue("crlUpdate", "missingParameters"); + } + + mTesting.remove(crlIssuingPointId); + CMS.debug("CRL test finished."); + } else if (test != null && test.equals("true") && + crlIssuingPoint.isCRLCacheTestingEnabled() && + mTesting.contains(crlIssuingPointId)) { + header.addStringValue("crlUpdate", "testingInProgress"); + } else if (test != null && test.equals("true") && + (!crlIssuingPoint.isCRLCacheTestingEnabled())) { + header.addStringValue("crlUpdate", "testingNotEnabled"); + } else { + try { + EBaseException publishError = null; + + try { + long now1 = System.currentTimeMillis(); + + if (signatureAlgorithm != null) { + crlIssuingPoint.updateCRLNow(signatureAlgorithm); + } else { + crlIssuingPoint.updateCRLNow(); + } + + long now2 = System.currentTimeMillis(); + + header.addStringValue("time", "" + (now2 - now1)); + } catch (EErrorPublishCRL e) { + publishError = e; + } + + if (lpm != null && lpm.enabled()) { + Enumeration rules = lpm.getRules(IPublisherProcessor.PROP_LOCAL_CRL); + if (rules != null && rules.hasMoreElements()) { + if (publishError != null) { + header.addStringValue("crlPublished", "Failure"); + header.addStringValue("error", publishError.toString(locale)); + } else { + header.addStringValue("crlPublished", "Success"); + } + } + } + + // for audit log + SessionContext sContext = SessionContext.getContext(); + String agentId = (String) sContext.get(SessionContext.USER_ID); + IAuthToken authToken = (IAuthToken) sContext.get(SessionContext.AUTH_TOKEN); + String authMgr = AuditFormat.NOAUTH; + + if (authToken != null) { + authMgr = authToken.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME); + } + long endTime = CMS.getCurrentDate().getTime(); + + if (crlIssuingPoint.getNextUpdate() != null) { + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.CRLUPDATEFORMAT, + new Object[] { + AuditFormat.FROMAGENT + " agentID: " + agentId, + authMgr, + "completed", + crlIssuingPoint.getId(), + crlIssuingPoint.getCRLNumber(), + crlIssuingPoint.getLastUpdate(), + crlIssuingPoint.getNextUpdate(), + Long.toString(crlIssuingPoint.getCRLSize()) + + " time: " + (endTime - startTime) } + ); + } else { + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.CRLUPDATEFORMAT, + new Object[] { + AuditFormat.FROMAGENT + " agentID: " + agentId, + authMgr, + "completed", + crlIssuingPoint.getId(), + crlIssuingPoint.getCRLNumber(), + crlIssuingPoint.getLastUpdate(), + "not set", + Long.toString(crlIssuingPoint.getCRLSize()) + + " time: " + (endTime - startTime) } + ); + } + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERR_UPDATE_CRL", e.toString())); + if ((lpm != null) && lpm.enabled() && (e instanceof ELdapException)) { + header.addStringValue("crlPublished", "Failure"); + header.addStringValue("error", e.toString(locale)); + } else { + throw e; + } + } + } + } else { + if (crlIssuingPoint.isCRLIssuingPointInitialized() != ICRLIssuingPoint.CRL_IP_INITIALIZED) { + header.addStringValue("crlUpdate", "notInitialized"); + } else if (crlIssuingPoint.isCRLUpdateInProgress() + != ICRLIssuingPoint.CRL_UPDATE_DONE || + crlIssuingPoint.isManualUpdateSet()) { + header.addStringValue("crlUpdate", "inProgress"); + } else if (!crlIssuingPoint.isCRLGenerationEnabled()) { + header.addStringValue("crlUpdate", "Disabled"); + } else { + crlIssuingPoint.setManualUpdate(signatureAlgorithm); + header.addStringValue("crlUpdate", "Scheduled"); + } + } + } + return; + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/UpdateDir.java b/base/common/src/com/netscape/cms/servlet/cert/UpdateDir.java new file mode 100644 index 000000000..707e7ff5f --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/UpdateDir.java @@ -0,0 +1,747 @@ +// --- 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.cert; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.X509CRLImpl; +import netscape.security.x509.X509CertImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzAccessDenied; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.MetaInfo; +import com.netscape.certsrv.base.SessionContext; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.dbs.crldb.ICRLIssuingPointRecord; +import com.netscape.certsrv.dbs.crldb.ICRLRepository; +import com.netscape.certsrv.ldap.ELdapException; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.publish.IPublisherProcessor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.RequestId; +import com.netscape.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; +import com.netscape.cms.servlet.common.CMSTemplate; +import com.netscape.cms.servlet.common.CMSTemplateParams; +import com.netscape.cms.servlet.common.ECMSGWException; + +/** + * Update the configured LDAP server with specified objects + * + * @version $Revision$, $Date$ + */ +public class UpdateDir extends CMSServlet { + + /** + * + */ + private static final long serialVersionUID = 3063889978908136789L; + private final static String INFO = "UpdateDir"; + private final static String TPL_FILE = "updateDir.template"; + private final static int UPDATE_ALL = 0; + private final static int UPDATE_CRL = 1; + private final static int UPDATE_CA = 2; + private final static int UPDATE_VALID = 3; + private final static int VALID_FROM = 4; + private final static int VALID_TO = 5; + private final static int UPDATE_EXPIRED = 6; + private final static int EXPIRED_FROM = 7; + private final static int EXPIRED_TO = 8; + private final static int UPDATE_REVOKED = 9; + private final static int REVOKED_FROM = 10; + private final static int REVOKED_TO = 11; + private final static int CHECK_FLAG = 12; + private final static String[] updateName = + { "updateAll", "updateCRL", "updateCA", + "updateValid", "validFrom", "validTo", + "updateExpired", "expiredFrom", "expiredTo", + "updateRevoked", "revokedFrom", "revokedTo", + "checkFlag" }; + + private String mFormPath = null; + private ICertificateAuthority mCA = null; + private IPublisherProcessor mPublisherProcessor = null; + private ICRLRepository mCRLRepository = null; + private boolean mClonedCA = false; + + /** + * Constructs UpdateDir servlet. + */ + public UpdateDir() { + super(); + } + + /** + * Initialize the servlet. This servlet uses the template + * 'updateDir.template' to render the response + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + + if (mAuthority != null) { + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + if (mAuthority instanceof ICertificateAuthority) { + mCA = (ICertificateAuthority) mAuthority; + mPublisherProcessor = mCA.getPublisherProcessor(); + mCRLRepository = mCA.getCRLRepository(); + } + + // override success to do output orw own template. + mTemplates.remove(CMSRequest.SUCCESS); + if (mOutputTemplatePath != null) { + mFormPath = mOutputTemplatePath; + } + } + } + + /** + * Process the HTTP request. + * + * @param cmsReq the object holding the request and response information + */ + public void process(CMSRequest cmsReq) throws EBaseException { + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "update"); + } catch (EAuthzAccessDenied e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString())); + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + return; + } + + EBaseException error = null; + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + form = getTemplate(mFormPath, req, locale); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", mFormPath, e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + try { + String crlIssuingPointId = req.getParameter("crlIssuingPoint"); + + if (mPublisherProcessor == null || + !mPublisherProcessor.enabled()) + throw new ECMSGWException(CMS.getUserMessage("CMS_GW_NO_PUB_MODULE")); + + String[] updateValue = new String[updateName.length]; + + for (int i = 0; i < updateName.length; i++) { + updateValue[i] = req.getParameter(updateName[i]); + } + + String masterHost = CMS.getConfigStore().getString("master.ca.agent.host", ""); + String masterPort = CMS.getConfigStore().getString("master.ca.agent.port", ""); + if (masterHost != null && masterHost.length() > 0 && + masterPort != null && masterPort.length() > 0) { + mClonedCA = true; + } + + process(argSet, header, req, resp, crlIssuingPointId, updateValue, locale[0]); + } catch (EBaseException e) { + error = e; + } + + try { + ServletOutputStream out = resp.getOutputStream(); + + if (error == null) { + String xmlOutput = req.getParameter("xml"); + if (xmlOutput != null && xmlOutput.equals("true")) { + outputXML(resp, argSet); + } else { + resp.setContentType("text/html"); + form.renderOutput(out, argSet); + cmsReq.setStatus(CMSRequest.SUCCESS); + } + } else { + cmsReq.setStatus(CMSRequest.ERROR); + cmsReq.setError(error); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_OUT_STREAM_TEMPLATE", e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + } + + private void updateCRLIssuingPoint( + IArgBlock header, + String crlIssuingPointId, + ICRLIssuingPoint crlIssuingPoint, + Locale locale) { + SessionContext sc = SessionContext.getContext(); + + sc.put(ICRLIssuingPoint.SC_ISSUING_POINT_ID, crlIssuingPointId); + sc.put(ICRLIssuingPoint.SC_IS_DELTA_CRL, "false"); + ICRLIssuingPointRecord crlRecord = null; + + try { + if (mCRLRepository != null) { + crlRecord = (ICRLIssuingPointRecord) mCRLRepository.readCRLIssuingPointRecord(crlIssuingPointId); + } + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERR_GET_CRL_RECORD", e.toString())); + } + + if (crlRecord == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CRL_NOT_YET_UPDATED_1", crlIssuingPointId)); + header.addStringValue("crlPublished", "Failure"); + header.addStringValue("crlError", + new ECMSGWException(CMS.getUserMessage(locale, "CMS_GW_CRL_NOT_YET_UPDATED")).toString()); + } else { + String publishDN = (crlIssuingPoint != null) ? crlIssuingPoint.getPublishDN() : null; + byte[] crlbytes = crlRecord.getCRL(); + + if (crlbytes == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_CRL_NOT_YET_UPDATED_1", "")); + header.addStringValue("crlPublished", "Failure"); + header.addStringValue("crlError", + new ECMSGWException(CMS.getUserMessage(locale, "CMS_GW_CRL_NOT_YET_UPDATED")).toString()); + } else { + X509CRLImpl crl = null; + + try { + crl = new X509CRLImpl(crlbytes); + } catch (Exception e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERR_DECODE_CRL", e.toString())); + } + + if (crl == null) { + header.addStringValue("crlPublished", "Failure"); + header.addStringValue("crlError", + new ECMSGWException(CMS.getUserMessage(locale, "CMS_GW_DECODE_CRL_FAILED")).toString()); + } else { + try { + if (publishDN != null) { + mPublisherProcessor.publishCRL(publishDN, crl); + } else { + mPublisherProcessor.publishCRL(crl, crlIssuingPointId); + } + header.addStringValue("crlPublished", "Success"); + } catch (ELdapException e) { + header.addStringValue("crlPublished", "Failure"); + header.addStringValue("crlError", e.toString(locale)); + log(ILogger.LL_FAILURE, CMS.getLogMessage("LDAP_ERROR_PUBLISH_CRL", e.toString())); + } + } + } + + sc.put(ICRLIssuingPoint.SC_IS_DELTA_CRL, "true"); + // handle delta CRL if any + byte[] deltaCrlBytes = crlRecord.getDeltaCRL(); + + if (deltaCrlBytes != null) { + X509CRLImpl deltaCrl = null; + + try { + deltaCrl = new X509CRLImpl(deltaCrlBytes); + } catch (Exception e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERR_DECODE_DELTA_CRL", e.toString())); + } + + boolean goodDelta = false; + if (mClonedCA) { + BigInteger crlNumber = crlRecord.getCRLNumber(); + BigInteger deltaNumber = crlRecord.getDeltaCRLNumber(); + Long deltaCRLSize = crlRecord.getDeltaCRLSize(); + if (deltaCRLSize != null && deltaCRLSize.longValue() > -1 && + crlNumber != null && deltaNumber != null && + deltaNumber.compareTo(crlNumber) >= 0) { + goodDelta = true; + } + } + + if (deltaCrl != null && ((mClonedCA && goodDelta) || + (crlIssuingPoint != null && + crlIssuingPoint.isThisCurrentDeltaCRL(deltaCrl)))) { + try { + if (publishDN != null) { + mPublisherProcessor.publishCRL(publishDN, deltaCrl); + } else { + mPublisherProcessor.publishCRL(deltaCrl, crlIssuingPointId); + } + } catch (ELdapException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERR_PUBLISH_DELTA_CRL", e.toString())); + } + } + } + } // if + } + + private void process(CMSTemplateParams argSet, IArgBlock header, + HttpServletRequest req, + HttpServletResponse resp, + String crlIssuingPointId, + String[] updateValue, + Locale locale) + throws EBaseException { + // all or crl + if ((updateValue[UPDATE_ALL] != null && + updateValue[UPDATE_ALL].equalsIgnoreCase("yes")) || + (updateValue[UPDATE_CRL] != null && + updateValue[UPDATE_CRL].equalsIgnoreCase("yes"))) { + // check if received issuing point ID is known to the server + if (crlIssuingPointId != null) { + Enumeration ips = mCA.getCRLIssuingPoints(); + + while (ips.hasMoreElements()) { + ICRLIssuingPoint ip = ips.nextElement(); + + if (crlIssuingPointId.equals(ip.getId())) { + break; + } + if (!ips.hasMoreElements()) + crlIssuingPointId = null; + } + } + if (crlIssuingPointId == null) { + // publish all issuing points + if (mClonedCA && mCRLRepository != null) { + Vector ipNames = mCRLRepository.getIssuingPointsNames(); + if (ipNames != null && ipNames.size() > 0) { + for (int i = 0; i < ipNames.size(); i++) { + String ipName = ipNames.elementAt(i); + + updateCRLIssuingPoint(header, ipName, null, locale); + } + } + } else { + Enumeration oips = mCA.getCRLIssuingPoints(); + + while (oips.hasMoreElements()) { + ICRLIssuingPoint oip = oips.nextElement(); + + updateCRLIssuingPoint(header, oip.getId(), oip, locale); + } + } + } else { + ICRLIssuingPoint crlIssuingPoint = + mCA.getCRLIssuingPoint(crlIssuingPointId); + + updateCRLIssuingPoint(header, crlIssuingPointId, + crlIssuingPoint, locale); + } + } + + ICertificateRepository certificateRepository = (ICertificateRepository) mCA.getCertificateRepository(); + + // all or ca + if ((updateValue[UPDATE_ALL] != null && + updateValue[UPDATE_ALL].equalsIgnoreCase("yes")) || + (updateValue[UPDATE_CA] != null && + updateValue[UPDATE_CA].equalsIgnoreCase("yes"))) { + X509CertImpl caCert = mCA.getSigningUnit().getCertImpl(); + + try { + mPublisherProcessor.publishCACert(caCert); + header.addStringValue("caCertPublished", "Success"); + } catch (ELdapException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("LDAP_ERROR_PUBLISH_CACERT_1", + caCert.getSerialNumber().toString(16), e.toString())); + header.addStringValue("caCertPublished", "Failure"); + header.addStringValue("caCertError", e.toString(locale)); + } + } + + // all or valid + if ((updateValue[UPDATE_ALL] != null && + updateValue[UPDATE_ALL].equalsIgnoreCase("yes")) || + (updateValue[UPDATE_VALID] != null && + updateValue[UPDATE_VALID].equalsIgnoreCase("yes"))) { + if (certificateRepository != null) { + if (updateValue[VALID_FROM].startsWith("0x")) { + updateValue[VALID_FROM] = hexToDecimal(updateValue[VALID_FROM]); + } + if (updateValue[VALID_TO].startsWith("0x")) { + updateValue[VALID_TO] = hexToDecimal(updateValue[VALID_TO]); + } + Enumeration validCerts = null; + + if (updateValue[CHECK_FLAG] != null && + updateValue[CHECK_FLAG].equalsIgnoreCase("yes")) { + validCerts = + certificateRepository.getValidNotPublishedCertificates( + updateValue[VALID_FROM], + updateValue[VALID_TO]); + } else { + validCerts = + certificateRepository.getValidCertificates( + updateValue[VALID_FROM], + updateValue[VALID_TO]); + } + int i = 0; + int l = 0; + String validCertsError = ""; + + if (validCerts != null) { + while (validCerts.hasMoreElements()) { + ICertRecord certRecord = + validCerts.nextElement(); + //X509CertImpl cert = certRecord.getCertificate(); + X509CertImpl cert = null; + Object o = certRecord.getCertificate(); + + if (o instanceof X509CertImpl) + cert = (X509CertImpl) o; + + MetaInfo metaInfo = null; + String ridString = null; + + metaInfo = (MetaInfo) certRecord.get(ICertRecord.ATTR_META_INFO); + if (metaInfo == null) { + // ca's self signed signing cert and + // server cert has no related request and + // have no metaInfo + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAIL_GET_ICERT_RECORD", + cert.getSerialNumber().toString(16))); + } else { + ridString = (String) metaInfo.get(ICertRecord.META_REQUEST_ID); + } + + IRequest r = null; + + if (ridString != null) { + RequestId rid = new RequestId(ridString); + + r = mCA.getRequestQueue().findRequest(rid); + } + + try { + l++; + SessionContext sc = SessionContext.getContext(); + + if (r == null) { + if (CMS.isEncryptionCert(cert)) + sc.put((Object) "isEncryptionCert", (Object) "true"); + else + sc.put((Object) "isEncryptionCert", (Object) "false"); + mPublisherProcessor.publishCert(cert, null); + } else { + if (CMS.isEncryptionCert(cert)) + r.setExtData("isEncryptionCert", "true"); + else + r.setExtData("isEncryptionCert", "false"); + mPublisherProcessor.publishCert(cert, r); + } + i++; + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAIL_PUBLISH_CERT", + certRecord.getSerialNumber().toString(16), + e.toString())); + validCertsError += + "Failed to publish certificate: 0x" + + certRecord.getSerialNumber().toString(16) + + ".\n
        "; + } + } + } + if (i > 0 && i == l) { + header.addStringValue("validCertsPublished", + "Success"); + if (i == 1) + header.addStringValue("validCertsError", i + + " valid certificate is published in the directory."); + else + header.addStringValue("validCertsError", i + + " valid certificates are published in the directory."); + } else { + if (l == 0) { + header.addStringValue("validCertsPublished", "No"); + } else { + header.addStringValue("validCertsPublished", "Failure"); + header.addStringValue("validCertsError", + validCertsError); + } + } + } else { + header.addStringValue("validCertsPublished", "Failure"); + header.addStringValue("validCertsError", "Certificate repository is unavailable."); + } + } + + // all or expired + if ((updateValue[UPDATE_ALL] != null && + updateValue[UPDATE_ALL].equalsIgnoreCase("yes")) || + (updateValue[UPDATE_EXPIRED] != null && + updateValue[UPDATE_EXPIRED].equalsIgnoreCase("yes"))) { + if (certificateRepository != null) { + if (updateValue[EXPIRED_FROM].startsWith("0x")) { + updateValue[EXPIRED_FROM] = hexToDecimal(updateValue[EXPIRED_FROM]); + } + if (updateValue[EXPIRED_TO].startsWith("0x")) { + updateValue[EXPIRED_TO] = hexToDecimal(updateValue[EXPIRED_TO]); + } + Enumeration expiredCerts = null; + + if (updateValue[CHECK_FLAG] != null && + updateValue[CHECK_FLAG].equalsIgnoreCase("yes")) { + expiredCerts = + certificateRepository.getExpiredPublishedCertificates( + updateValue[EXPIRED_FROM], + updateValue[EXPIRED_TO]); + } else { + expiredCerts = + certificateRepository.getExpiredCertificates( + updateValue[EXPIRED_FROM], + updateValue[EXPIRED_TO]); + } + int i = 0; + int l = 0; + StringBuffer expiredCertsError = new StringBuffer(); + + if (expiredCerts != null) { + while (expiredCerts.hasMoreElements()) { + ICertRecord certRecord = expiredCerts.nextElement(); + //X509CertImpl cert = certRecord.getCertificate(); + X509CertImpl cert = null; + Object o = certRecord.getCertificate(); + + if (o instanceof X509CertImpl) + cert = (X509CertImpl) o; + + MetaInfo metaInfo = null; + String ridString = null; + + metaInfo = (MetaInfo) certRecord.get(ICertRecord.ATTR_META_INFO); + if (metaInfo == null) { + // ca's self signed signing cert and + // server cert has no related request and + // have no metaInfo + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAIL_GET_ICERT_RECORD", + cert.getSerialNumber().toString(16))); + } else { + ridString = (String) metaInfo.get(ICertRecord.META_REQUEST_ID); + } + + IRequest r = null; + + if (ridString != null) { + RequestId rid = new RequestId(ridString); + + r = mCA.getRequestQueue().findRequest(rid); + } + + try { + l++; + if (r == null) { + mPublisherProcessor.unpublishCert(cert, null); + } else { + mPublisherProcessor.unpublishCert(cert, r); + } + i++; + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("LDAP_ERROR_UNPUBLISH_CERT", + certRecord.getSerialNumber().toString(16), + e.toString())); + expiredCertsError.append( + "Failed to unpublish certificate: 0x"); + expiredCertsError.append( + certRecord.getSerialNumber().toString(16)); + expiredCertsError.append( + ".\n
        "); + } + } + } + if (i > 0 && i == l) { + header.addStringValue("expiredCertsUnpublished", "Success"); + if (i == 1) + header.addStringValue("expiredCertsError", i + + " expired certificate is unpublished in the directory."); + else + header.addStringValue("expiredCertsError", i + + " expired certificates are unpublished in the directory."); + } else { + if (l == 0) { + header.addStringValue("expiredCertsUnpublished", "No"); + } else { + header.addStringValue("expiredCertsUnpublished", "Failure"); + header.addStringValue("expiredCertsError", + expiredCertsError.toString()); + } + } + } else { + header.addStringValue("expiredCertsUnpublished", "Failure"); + header.addStringValue("expiredCertsError", "Certificate repository is unavailable."); + } + } + + // all or revoked + if ((updateValue[UPDATE_ALL] != null && + updateValue[UPDATE_ALL].equalsIgnoreCase("yes")) || + (updateValue[UPDATE_REVOKED] != null && + updateValue[UPDATE_REVOKED].equalsIgnoreCase("yes"))) { + if (certificateRepository != null) { + if (updateValue[REVOKED_FROM].startsWith("0x")) { + updateValue[REVOKED_FROM] = hexToDecimal(updateValue[REVOKED_FROM]); + } + if (updateValue[REVOKED_TO].startsWith("0x")) { + updateValue[REVOKED_TO] = hexToDecimal(updateValue[REVOKED_TO]); + } + Enumeration revokedCerts = null; + + if (updateValue[CHECK_FLAG] != null && + updateValue[CHECK_FLAG].equalsIgnoreCase("yes")) { + revokedCerts = + certificateRepository.getRevokedPublishedCertificates( + updateValue[REVOKED_FROM], + updateValue[REVOKED_TO]); + } else { + revokedCerts = + certificateRepository.getRevokedCertificates( + updateValue[REVOKED_FROM], + updateValue[REVOKED_TO]); + } + int i = 0; + int l = 0; + String revokedCertsError = ""; + + if (revokedCerts != null) { + while (revokedCerts.hasMoreElements()) { + ICertRecord certRecord = revokedCerts.nextElement(); + //X509CertImpl cert = certRecord.getCertificate(); + X509CertImpl cert = null; + Object o = certRecord.getCertificate(); + + if (o instanceof X509CertImpl) + cert = (X509CertImpl) o; + + MetaInfo metaInfo = null; + String ridString = null; + + metaInfo = (MetaInfo) certRecord.get(ICertRecord.ATTR_META_INFO); + if (metaInfo == null) { + // ca's self signed signing cert and + // server cert has no related request and + // have no metaInfo + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_FAIL_GET_ICERT_RECORD", + cert.getSerialNumber().toString(16))); + } else { + ridString = (String) metaInfo.get(ICertRecord.META_REQUEST_ID); + } + + IRequest r = null; + + if (ridString != null) { + RequestId rid = new RequestId(ridString); + + r = mCA.getRequestQueue().findRequest(rid); + } + + try { + l++; + if (r == null) { + mPublisherProcessor.unpublishCert(cert, null); + } else { + mPublisherProcessor.unpublishCert(cert, r); + } + i++; + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("LDAP_ERROR_UNPUBLISH_CERT", + certRecord.getSerialNumber().toString(16), + e.toString())); + revokedCertsError += + "Failed to unpublish certificate: 0x" + + certRecord.getSerialNumber().toString(16) + + ".\n
        "; + } + } + } + if (i > 0 && i == l) { + header.addStringValue("revokedCertsUnpublished", "Success"); + if (i == 1) + header.addStringValue("revokedCertsError", i + + " revoked certificate is unpublished in the directory."); + else + header.addStringValue("revokedCertsError", i + + " revoked certificates are unpublished in the directory."); + } else { + if (l == 0) { + header.addStringValue("revokedCertsUnpublished", "No"); + } else { + header.addStringValue("revokedCertsUnpublished", "Failure"); + header.addStringValue("revokedCertsError", + revokedCertsError); + } + } + } else { + header.addStringValue("revokedCertsUnpublished", "Failure"); + header.addStringValue("revokedCertsError", "Certificate repository is unavailable."); + } + } + + return; + } + + private String hexToDecimal(String hex) { + String newHex = hex.substring(2); + BigInteger bi = new BigInteger(newHex, 16); + + return bi.toString(); + } +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/model/CertificateData.java b/base/common/src/com/netscape/cms/servlet/cert/model/CertificateData.java new file mode 100644 index 000000000..14c537098 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/model/CertificateData.java @@ -0,0 +1,53 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2012 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cms.servlet.cert.model; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; + +/** + * @author alee + * + */ +@XmlRootElement(name = "CertificateData") +@XmlAccessorType(XmlAccessType.FIELD) +public class CertificateData { + @XmlElement + private String b64; + + public CertificateData() { + // required for jaxb + } + + /** + * @return the b64 + */ + public String getB64() { + return b64; + } + + /** + * @param b64 the b64 to set + */ + public void setB64(String b64) { + this.b64 = b64; + } + +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/scep/CRSEnrollment.java b/base/common/src/com/netscape/cms/servlet/cert/scep/CRSEnrollment.java new file mode 100644 index 000000000..90a48cb4e --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/scep/CRSEnrollment.java @@ -0,0 +1,2135 @@ +// --- 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.cert.scep; + +import java.io.ByteArrayInputStream; +import java.io.FileOutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Locale; +import java.util.Random; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; +import netscape.ldap.LDAPConnection; +import netscape.ldap.LDAPEntry; +import netscape.security.pkcs.PKCS10; +import netscape.security.pkcs.PKCS10Attribute; +import netscape.security.pkcs.PKCS10Attributes; +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.AVA; +import netscape.security.x509.CertAttrSet; +import netscape.security.x509.CertificateChain; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateSubjectName; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.CertificateX509Key; +import netscape.security.x509.DNSName; +import netscape.security.x509.Extension; +import netscape.security.x509.GeneralName; +import netscape.security.x509.GeneralNameInterface; +import netscape.security.x509.GeneralNames; +import netscape.security.x509.IPAddressName; +import netscape.security.x509.KeyUsageExtension; +import netscape.security.x509.OIDMap; +import netscape.security.x509.RDN; +import netscape.security.x509.SubjectAlternativeNameExtension; +import netscape.security.x509.X500Name; +import netscape.security.x509.X500NameAttrMap; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; +import netscape.security.x509.X509Key; + +import org.mozilla.jss.CryptoManager; +import org.mozilla.jss.NoSuchTokenException; +import org.mozilla.jss.asn1.ANY; +import org.mozilla.jss.asn1.ASN1Util; +import org.mozilla.jss.asn1.BIT_STRING; +import org.mozilla.jss.asn1.INTEGER; +import org.mozilla.jss.asn1.InvalidBERException; +import org.mozilla.jss.asn1.SEQUENCE; +import org.mozilla.jss.crypto.Cipher; +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.ObjectNotFoundException; +import org.mozilla.jss.crypto.SymmetricKey; +import org.mozilla.jss.crypto.TokenException; +import org.mozilla.jss.pkcs7.IssuerAndSerialNumber; +import org.mozilla.jss.pkix.cert.Certificate; +import org.mozilla.jss.util.IncorrectPasswordException; +import org.mozilla.jss.util.PasswordCallback; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.AuthCredentials; +import com.netscape.certsrv.authentication.AuthToken; +import com.netscape.certsrv.authentication.EInvalidCredentials; +import com.netscape.certsrv.authentication.EMissingCredential; +import com.netscape.certsrv.authentication.IAuthSubsystem; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authority.ICertAuthority; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IArgBlock; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.base.SessionContext; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.common.Constants; +import com.netscape.certsrv.ldap.ILdapConnFactory; +import com.netscape.certsrv.logging.AuditFormat; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.IEnrollProfile; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.profile.IProfileAuthenticator; +import com.netscape.certsrv.profile.IProfileContext; +import com.netscape.certsrv.profile.IProfileSubsystem; +import com.netscape.certsrv.publish.IPublisherProcessor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.RequestId; +import com.netscape.certsrv.request.RequestStatus; +import com.netscape.cms.servlet.profile.SSLClientCertProvider; +import com.netscape.cmsutil.scep.CRSPKIMessage; +import com.netscape.cmsutil.util.Utils; + +/** + * This servlet deals with PKCS#10-based certificate requests from + * CRS, now called SCEP, and defined at: + * http://search.ietf.org/internet-drafts/draft-nourse-scep-02.txt + * + * The router is hardcoded to look for the http://host:80/cgi-bin/pkiclient.exe + * + * The HTTP parameters are 'operation' and 'message' + * operation can be either 'GetCACert' or 'PKIOperation' + * + * @version $Revision$, $Date$ + */ +public class CRSEnrollment extends HttpServlet { + /** + * + */ + private static final long serialVersionUID = 8483002540957382369L; + protected IProfileSubsystem mProfileSubsystem = null; + protected String mProfileId = null; + protected ICertAuthority mAuthority; + protected IConfigStore mConfig = null; + protected IAuthSubsystem mAuthSubsystem; + protected String mAppendDN = null; + protected String mEntryObjectclass = null; + protected boolean mCreateEntry = false; + protected boolean mFlattenDN = false; + + private String mAuthManagerName; + private String mSubstoreName; + private boolean mEnabled = false; + private boolean mUseCA = true; + private String mNickname = null; + private String mTokenName = ""; + private String mHashAlgorithm = "SHA1"; + private String mHashAlgorithmList = null; + private String[] mAllowedHashAlgorithm; + private String mConfiguredEncryptionAlgorithm = "DES3"; + private String mEncryptionAlgorithm = "DES3"; + private String mEncryptionAlgorithmList = null; + private String[] mAllowedEncryptionAlgorithm; + private Random mRandom = null; + private int mNonceSizeLimit = 0; + protected ILogger mLogger = CMS.getLogger(); + private ICertificateAuthority ca; + /* for hashing challenge password */ + protected MessageDigest mSHADigest = null; + + private static final String PROP_SUBSTORENAME = "substorename"; + private static final String PROP_AUTHORITY = "authority"; + private static final String PROP_CRS = "crs"; + private static final String PROP_CRSCA = "casubsystem"; + private static final String PROP_CRSAUTHMGR = "authName"; + private static final String PROP_APPENDDN = "appendDN"; + private static final String PROP_CREATEENTRY = "createEntry"; + private static final String PROP_FLATTENDN = "flattenDN"; + private static final String PROP_ENTRYOC = "entryObjectclass"; + + // URL parameters + private static final String URL_OPERATION = "operation"; + private static final String URL_MESSAGE = "message"; + + // possible values for 'operation' + private static final String OP_GETCACERT = "GetCACert"; + private static final String OP_PKIOPERATION = "PKIOperation"; + + public static final String AUTH_PASSWORD = "pwd"; + + public static final String AUTH_CREDS = "AuthCreds"; + public static final String AUTH_TOKEN = "AuthToken"; + public static final String AUTH_FAILED = "AuthFailed"; + + public static final String SANE_DNSNAME = "DNSName"; + public static final String SANE_IPADDRESS = "IPAddress"; + + public static final String CERTINFO = "CertInfo"; + public static final String SUBJECTNAME = "SubjectName"; + + public static ObjectIdentifier OID_UNSTRUCTUREDNAME = null; + public static ObjectIdentifier OID_UNSTRUCTUREDADDRESS = null; + public static ObjectIdentifier OID_SERIALNUMBER = null; + + public CRSEnrollment() { + } + + public static Hashtable toHashtable(HttpServletRequest req) { + Hashtable httpReqHash = new Hashtable(); + @SuppressWarnings("unchecked") + Enumeration names = req.getParameterNames(); + while (names.hasMoreElements()) { + String name = (String) names.nextElement(); + httpReqHash.put(name, req.getParameter(name)); + } + return httpReqHash; + } + + public void init(ServletConfig sc) { + // Find the CertificateAuthority we should use for CRS. + String crsCA = sc.getInitParameter(PROP_AUTHORITY); + if (crsCA == null) + crsCA = "ca"; + mAuthority = (ICertAuthority) CMS.getSubsystem(crsCA); + ca = (ICertificateAuthority) mAuthority; + + if (mAuthority == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_CANT_FIND_AUTHORITY", crsCA)); + } + + try { + if (mAuthority instanceof ISubsystem) { + IConfigStore authorityConfig = ((ISubsystem) mAuthority).getConfigStore(); + IConfigStore scepConfig = authorityConfig.getSubStore("scep"); + mEnabled = scepConfig.getBoolean("enable", false); + mHashAlgorithm = scepConfig.getString("hashAlgorithm", "SHA1"); + mConfiguredEncryptionAlgorithm = scepConfig.getString("encryptionAlgorithm", "DES3"); + mNonceSizeLimit = scepConfig.getInteger("nonceSizeLimit", 0); + mHashAlgorithmList = scepConfig.getString("allowedHashAlgorithms", "SHA1,SHA256,SHA512"); + mAllowedHashAlgorithm = mHashAlgorithmList.split(","); + mEncryptionAlgorithmList = scepConfig.getString("allowedEncryptionAlgorithms", "DES3"); + mAllowedEncryptionAlgorithm = mEncryptionAlgorithmList.split(","); + mNickname = scepConfig.getString("nickname", ca.getNickname()); + if (mNickname.equals(ca.getNickname())) { + mTokenName = ca.getSigningUnit().getTokenName(); + } else { + mTokenName = scepConfig.getString("tokenname", ""); + mUseCA = false; + } + if (!(mTokenName.equalsIgnoreCase(Constants.PR_INTERNAL_TOKEN) || + mTokenName.equalsIgnoreCase("Internal Key Storage Token") || mTokenName.length() == 0)) { + int i = mNickname.indexOf(':'); + if (!((i > -1) && (mTokenName.length() == i) && (mNickname.startsWith(mTokenName)))) { + mNickname = mTokenName + ":" + mNickname; + } + } + } + } catch (EBaseException e) { + CMS.debug("CRSEnrollment: init: EBaseException: " + e); + } + mEncryptionAlgorithm = mConfiguredEncryptionAlgorithm; + CMS.debug("CRSEnrollment: init: SCEP support is " + ((mEnabled) ? "enabled" : "disabled") + "."); + CMS.debug("CRSEnrollment: init: SCEP nickname: " + mNickname); + CMS.debug("CRSEnrollment: init: CA nickname: " + ca.getNickname()); + CMS.debug("CRSEnrollment: init: Token name: " + mTokenName); + CMS.debug("CRSEnrollment: init: Is SCEP using CA keys: " + mUseCA); + CMS.debug("CRSEnrollment: init: mNonceSizeLimit: " + mNonceSizeLimit); + CMS.debug("CRSEnrollment: init: mHashAlgorithm: " + mHashAlgorithm); + CMS.debug("CRSEnrollment: init: mHashAlgorithmList: " + mHashAlgorithmList); + for (int i = 0; i < mAllowedHashAlgorithm.length; i++) { + mAllowedHashAlgorithm[i] = mAllowedHashAlgorithm[i].trim(); + CMS.debug("CRSEnrollment: init: mAllowedHashAlgorithm[" + i + "]=" + mAllowedHashAlgorithm[i]); + } + CMS.debug("CRSEnrollment: init: mEncryptionAlgorithm: " + mEncryptionAlgorithm); + CMS.debug("CRSEnrollment: init: mEncryptionAlgorithmList: " + mEncryptionAlgorithmList); + for (int i = 0; i < mAllowedEncryptionAlgorithm.length; i++) { + mAllowedEncryptionAlgorithm[i] = mAllowedEncryptionAlgorithm[i].trim(); + CMS.debug("CRSEnrollment: init: mAllowedEncryptionAlgorithm[" + i + "]=" + mAllowedEncryptionAlgorithm[i]); + } + + try { + mProfileSubsystem = (IProfileSubsystem) CMS.getSubsystem("profile"); + mProfileId = sc.getInitParameter("profileId"); + CMS.debug("CRSEnrollment: init: mProfileId=" + mProfileId); + + mAuthSubsystem = (IAuthSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_AUTH); + mAuthManagerName = sc.getInitParameter(PROP_CRSAUTHMGR); + mAppendDN = sc.getInitParameter(PROP_APPENDDN); + String tmp = sc.getInitParameter(PROP_CREATEENTRY); + if (tmp != null && tmp.trim().equalsIgnoreCase("true")) + mCreateEntry = true; + else + mCreateEntry = false; + tmp = sc.getInitParameter(PROP_FLATTENDN); + if (tmp != null && tmp.trim().equalsIgnoreCase("true")) + mFlattenDN = true; + else + mFlattenDN = false; + mEntryObjectclass = sc.getInitParameter(PROP_ENTRYOC); + if (mEntryObjectclass == null) + mEntryObjectclass = "cep"; + mSubstoreName = sc.getInitParameter(PROP_SUBSTORENAME); + if (mSubstoreName == null) + mSubstoreName = "default"; + } catch (Exception e) { + } + + OID_UNSTRUCTUREDNAME = X500NameAttrMap.getDefault().getOid("UNSTRUCTUREDNAME"); + OID_UNSTRUCTUREDADDRESS = X500NameAttrMap.getDefault().getOid("UNSTRUCTUREDADDRESS"); + OID_SERIALNUMBER = X500NameAttrMap.getDefault().getOid("SERIALNUMBER"); + + try { + mSHADigest = MessageDigest.getInstance("SHA1"); + } catch (NoSuchAlgorithmException e) { + } + + mRandom = new Random(); + } + + /** + * + * Service a CRS Request. It all starts here. This is where the message from the + * router is processed + * + * @param httpReq The HttpServletRequest. + * @param httpResp The HttpServletResponse. + * + */ + public void service(HttpServletRequest httpReq, + HttpServletResponse httpResp) + throws ServletException { + boolean running_state = CMS.isInRunningState(); + if (!running_state) + throw new ServletException( + "CMS server is not ready to serve."); + + String operation = null; + String message = null; + mEncryptionAlgorithm = mConfiguredEncryptionAlgorithm; + + // Parse the URL from the HTTP Request. Split it up into + // a structure which enables us to read the form elements + IArgBlock input = CMS.createArgBlock(toHashtable(httpReq)); + + try { + // Read in two form parameters - the router sets these + operation = (String) input.get(URL_OPERATION); + CMS.debug("operation=" + operation); + message = (String) input.get(URL_MESSAGE); + CMS.debug("message=" + message); + + if (!mEnabled) { + CMS.debug("CRSEnrollment: SCEP support is disabled."); + throw new ServletException("SCEP support is disabled."); + } + if (operation == null) { + // 'operation' is mandatory. + throw new ServletException("Bad request: operation missing from URL"); + } + + /** + * the router can make two kinds of requests + * 1) simple request for CA cert + * 2) encoded, signed, enveloped request for anything else (PKIOperation) + */ + + if (operation.equals(OP_GETCACERT)) { + handleGetCACert(httpReq, httpResp); + } else if (operation.equals(OP_PKIOPERATION)) { + String decodeMode = (String) input.get("decode"); + if (decodeMode == null || decodeMode.equals("false")) { + handlePKIOperation(httpReq, httpResp, message); + } else { + decodePKIMessage(httpReq, httpResp, message); + } + } else { + CMS.debug("Invalid operation " + operation); + throw new ServletException("unknown operation requested: " + operation); + } + + } catch (ServletException e) { + CMS.debug("ServletException " + e); + throw new ServletException(e.getMessage().toString()); + } catch (Exception e) { + CMS.debug("Service exception " + e); + log(ILogger.LL_FAILURE, e.getMessage()); + } + + } + + /** + * Log a message to the system log + */ + + private void log(int level, String msg) { + + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + level, "CEP Enrollment: " + msg); + } + + private boolean isAlgorithmAllowed(String[] allowedAlgorithm, String algorithm) { + boolean allowed = false; + + if (algorithm != null && algorithm.length() > 0) { + for (int i = 0; i < allowedAlgorithm.length; i++) { + if (algorithm.equalsIgnoreCase(allowedAlgorithm[i])) { + allowed = true; + } + } + } + + return allowed; + } + + public IAuthToken authenticate(AuthCredentials credentials, IProfileAuthenticator authenticator, + HttpServletRequest request) throws EBaseException { + + // build credential + Enumeration authNames = authenticator.getValueNames(); + + if (authNames != null) { + while (authNames.hasMoreElements()) { + String authName = (String) authNames.nextElement(); + + credentials.set(authName, request.getParameter(authName)); + } + } + + credentials.set("clientHost", request.getRemoteHost()); + IAuthToken authToken = authenticator.authenticate(credentials); + if (authToken == null) { + return null; + } + SessionContext sc = SessionContext.getContext(); + if (sc != null) { + sc.put(SessionContext.AUTH_MANAGER_ID, authenticator.getName()); + String userid = authToken.getInString(IAuthToken.USER_ID); + if (userid != null) { + sc.put(SessionContext.USER_ID, userid); + } + } + + return authToken; + } + + /** + * Return the CA certificate back to the requestor. + * This needs to be changed so that if the CA has a certificate chain, + * the whole thing should get packaged as a PKIMessage (degnerate PKCS7 - no + * signerInfo) + */ + + public void handleGetCACert(HttpServletRequest httpReq, + HttpServletResponse httpResp) + throws ServletException { + java.security.cert.X509Certificate[] chain = null; + + CertificateChain certChain = mAuthority.getCACertChain(); + + try { + if (certChain == null) { + throw new ServletException("Internal Error: cannot get CA Cert"); + } + + chain = certChain.getChain(); + + byte[] bytes = null; + + int i = 0; + String message = (String) httpReq.getParameter(URL_MESSAGE); + CMS.debug("handleGetCACert message=" + message); + if (message != null) { + try { + int j = Integer.parseInt(message); + if (j < chain.length) { + i = j; + } + } catch (NumberFormatException e1) { + } + } + CMS.debug("handleGetCACert selected chain=" + i); + + if (mUseCA) { + bytes = chain[i].getEncoded(); + } else { + CryptoContext cx = new CryptoContext(); + bytes = cx.getSigningCert().getEncoded(); + } + + httpResp.setContentType("application/x-x509-ca-cert"); + + // The following code may be used one day to encode + // the RA/CA cert chain for RA mode, but it will need some + // work. + + /****** + * SET certs = new SET(); + * for (int i=0; i e = p10atts.getElements(); + + try { + while (e.hasMoreElements()) { + PKCS10Attribute p10a = (PKCS10Attribute) e.nextElement(); + CertAttrSet attr = p10a.getAttributeValue(); + + if (attr.getName().equals(ChallengePassword.NAME)) { + if (attr.get(ChallengePassword.PASSWORD) != null) { + return (String) attr.get(ChallengePassword.PASSWORD); + } + } + } + } catch (Exception e1) { + // do nothing + } + return null; + } + + /** + * If the 'operation' is 'PKIOperation', the 'message' part of the URL is a + * PKIMessage structure. We decode it to see what type message it is. + */ + + /** + * Decodes the PKI message and return information to RA. + */ + public void decodePKIMessage(HttpServletRequest httpReq, + HttpServletResponse httpResp, + String msg) + throws ServletException { + + CryptoContext cx = null; + + CRSPKIMessage req = null; + + byte[] decodedPKIMessage; + byte[] response = null; + String responseData = ""; + + decodedPKIMessage = Utils.base64decode(msg); + + try { + ByteArrayInputStream is = new ByteArrayInputStream(decodedPKIMessage); + + // We make two CRSPKIMessages. One of them, is the request, so we initialize + // it from the DER given to us from the router. + // The second is the response, and we'll fill this in as we go. + + if (decodedPKIMessage.length < 50) { + throw new ServletException("CRS request is too small to be a real request (" + + decodedPKIMessage.length + " bytes)"); + } + try { + req = new CRSPKIMessage(is); + String ea = req.getEncryptionAlgorithm(); + if (!isAlgorithmAllowed(mAllowedEncryptionAlgorithm, ea)) { + CMS.debug("CRSEnrollment: decodePKIMessage: Encryption algorithm '" + ea + + "' is not allowed (" + mEncryptionAlgorithmList + ")."); + throw new ServletException("Encryption algorithm '" + ea + + "' is not allowed (" + mEncryptionAlgorithmList + ")."); + } + String da = req.getDigestAlgorithmName(); + if (!isAlgorithmAllowed(mAllowedHashAlgorithm, da)) { + CMS.debug("CRSEnrollment: decodePKIMessage: Hashing algorithm '" + da + + "' is not allowed (" + mHashAlgorithmList + ")."); + throw new ServletException("Hashing algorithm '" + da + + "' is not allowed (" + mHashAlgorithmList + ")."); + } + if (ea != null) { + mEncryptionAlgorithm = ea; + } + } catch (Exception e) { + CMS.debug(e); + throw new ServletException("Could not decode the request."); + } + + // Create a new crypto context for doing all the crypto operations + cx = new CryptoContext(); + + // Verify Signature on message (throws exception if sig bad) + verifyRequest(req, cx); + unwrapPKCS10(req, cx); + + IProfile profile = mProfileSubsystem.getProfile(mProfileId); + if (profile == null) { + CMS.debug("Profile '" + mProfileId + "' not found."); + throw new ServletException("Profile '" + mProfileId + "' not found."); + } else { + CMS.debug("Found profile '" + mProfileId + "'."); + } + + IProfileAuthenticator authenticator = null; + try { + CMS.debug("Retrieving authenticator"); + authenticator = profile.getAuthenticator(); + if (authenticator == null) { + CMS.debug("Authenticator not found."); + throw new ServletException("Authenticator not found."); + } else { + CMS.debug("Got authenticator=" + authenticator.getClass().getName()); + } + } catch (EProfileException e) { + throw new ServletException("Authenticator not found."); + } + AuthCredentials credentials = new AuthCredentials(); + IAuthToken authToken = null; + // for ssl authentication; pass in servlet for retrieving + // ssl client certificates + SessionContext context = SessionContext.getContext(); + + // insert profile context so that input parameter can be retrieved + context.put("sslClientCertProvider", new SSLClientCertProvider(httpReq)); + + try { + authToken = authenticate(credentials, authenticator, httpReq); + } catch (Exception e) { + CMS.debug("Authentication failure: " + e.getMessage()); + throw new ServletException("Authentication failure: " + e.getMessage()); + } + if (authToken == null) { + CMS.debug("Authentication failure."); + throw new ServletException("Authentication failure."); + } + + // Deal with Transaction ID + String transactionID = req.getTransactionID(); + responseData = responseData + + "" + transactionID + ""; + + // End-User or RA's IP address + responseData = responseData + + "" + httpReq.getRemoteAddr() + ""; + + responseData = responseData + + "" + httpReq.getRemoteHost() + ""; + + // Deal with message type + String mt = req.getMessageType(); + responseData = responseData + + "" + mt + ""; + + PKCS10 p10 = (PKCS10) req.getP10(); + X500Name p10subject = p10.getSubjectName(); + responseData = responseData + + "" + p10subject.toString() + ""; + + String pkcs10Attr = ""; + PKCS10Attributes p10atts = p10.getAttributes(); + Enumeration e = p10atts.getElements(); + + while (e.hasMoreElements()) { + PKCS10Attribute p10a = (PKCS10Attribute) e.nextElement(); + CertAttrSet attr = p10a.getAttributeValue(); + + if (attr.getName().equals(ChallengePassword.NAME)) { + if (attr.get(ChallengePassword.PASSWORD) != null) { + pkcs10Attr = + pkcs10Attr + + + "" + + (String) attr.get(ChallengePassword.PASSWORD) + + ""; + } + + } + String extensionsStr = ""; + if (attr.getName().equals(ExtensionsRequested.NAME)) { + + Enumeration exts = ((ExtensionsRequested) attr).getExtensions().elements(); + while (exts.hasMoreElements()) { + Extension ext = exts.nextElement(); + + if (ext.getExtensionId().equals( + OIDMap.getOID(SubjectAlternativeNameExtension.IDENT))) { + SubjectAlternativeNameExtension sane = new SubjectAlternativeNameExtension( + Boolean.valueOf(false), // noncritical + ext.getExtensionValue()); + + @SuppressWarnings("unchecked") + Vector v = + (Vector) sane + .get(SubjectAlternativeNameExtension.SUBJECT_NAME); + + Enumeration gne = v.elements(); + + StringBuffer subjAltNameStr = new StringBuffer(); + while (gne.hasMoreElements()) { + GeneralNameInterface gni = gne.nextElement(); + if (gni instanceof GeneralName) { + GeneralName genName = (GeneralName) gni; + + String gn = genName.toString(); + int colon = gn.indexOf(':'); + String gnType = gn.substring(0, colon).trim(); + String gnValue = gn.substring(colon + 1).trim(); + + subjAltNameStr.append("<"); + subjAltNameStr.append(gnType); + subjAltNameStr.append(">"); + subjAltNameStr.append(gnValue); + subjAltNameStr.append(""); + } + } // while + extensionsStr = "" + + subjAltNameStr.toString() + ""; + } // if + } // while + pkcs10Attr = pkcs10Attr + + "" + extensionsStr + ""; + } // if extensions + } // while + responseData = responseData + + "" + pkcs10Attr + ""; + + } catch (ServletException e) { + throw new ServletException(e.getMessage().toString()); + } catch (CRSInvalidSignatureException e) { + CMS.debug("handlePKIMessage exception " + e); + CMS.debug(e); + } catch (Exception e) { + CMS.debug("handlePKIMessage exception " + e); + CMS.debug(e); + throw new ServletException("Failed to process message in CEP servlet: " + e.getMessage()); + } + + // We have now processed the request, and need to make the response message + + try { + + responseData = "" + responseData + ""; + // Get the response coding + response = responseData.getBytes(); + + // Encode the httpResp into B64 + httpResp.setContentType("application/xml"); + httpResp.setContentLength(response.length); + httpResp.getOutputStream().write(response); + httpResp.getOutputStream().flush(); + + int i1 = responseData.indexOf(""); + if (i1 > -1) { + i1 += 10; // 10 is a length of "" + int i2 = responseData.indexOf("", i1); + if (i2 > -1) { + responseData = responseData.substring(0, i1) + "********" + + responseData.substring(i2, responseData.length()); + } + } + + CMS.debug("Output (decoding) PKIOperation response:"); + CMS.debug(responseData); + } catch (Exception e) { + throw new ServletException("Failed to create response for CEP message" + e.getMessage()); + } + + } + + /** + * finds a request with this transaction ID. + * If could not find any request - return null + * If could only find 'rejected' or 'cancelled' requests, return null + * If found 'pending' or 'completed' request - return that request + */ + + public void handlePKIOperation(HttpServletRequest httpReq, + HttpServletResponse httpResp, + String msg) + throws ServletException { + + CryptoContext cx = null; + + CRSPKIMessage req = null; + CRSPKIMessage crsResp = null; + + byte[] decodedPKIMessage; + byte[] response = null; + X509CertImpl cert = null; + + decodedPKIMessage = Utils.base64decode(msg); + + try { + ByteArrayInputStream is = new ByteArrayInputStream(decodedPKIMessage); + + // We make two CRSPKIMessages. One of them, is the request, so we initialize + // it from the DER given to us from the router. + // The second is the response, and we'll fill this in as we go. + + if (decodedPKIMessage.length < 50) { + throw new ServletException("CRS request is too small to be a real request (" + + decodedPKIMessage.length + " bytes)"); + } + try { + req = new CRSPKIMessage(is); + String ea = req.getEncryptionAlgorithm(); + if (!isAlgorithmAllowed(mAllowedEncryptionAlgorithm, ea)) { + CMS.debug("CRSEnrollment: handlePKIOperation: Encryption algorithm '" + ea + + "' is not allowed (" + mEncryptionAlgorithmList + ")."); + throw new ServletException("Encryption algorithm '" + ea + + "' is not allowed (" + mEncryptionAlgorithmList + ")."); + } + String da = req.getDigestAlgorithmName(); + if (!isAlgorithmAllowed(mAllowedHashAlgorithm, da)) { + CMS.debug("CRSEnrollment: handlePKIOperation: Hashing algorithm '" + da + + "' is not allowed (" + mHashAlgorithmList + ")."); + throw new ServletException("Hashing algorithm '" + da + + "' is not allowed (" + mHashAlgorithmList + ")."); + } + if (ea != null) { + mEncryptionAlgorithm = ea; + } + crsResp = new CRSPKIMessage(); + } catch (ServletException e) { + throw new ServletException(e.getMessage().toString()); + } catch (Exception e) { + CMS.debug(e); + throw new ServletException("Could not decode the request."); + } + crsResp.setMessageType(CRSPKIMessage.mType_CertRep); + + // Create a new crypto context for doing all the crypto operations + cx = new CryptoContext(); + + // Verify Signature on message (throws exception if sig bad) + verifyRequest(req, cx); + + // Deal with Transaction ID + String transactionID = req.getTransactionID(); + if (transactionID == null) { + throw new ServletException("Error: malformed PKIMessage - missing transactionID"); + } else { + crsResp.setTransactionID(transactionID); + } + + // Deal with Nonces + byte[] sn = req.getSenderNonce(); + if (sn == null) { + throw new ServletException("Error: malformed PKIMessage - missing sendernonce"); + } else { + if (mNonceSizeLimit > 0 && sn.length > mNonceSizeLimit) { + byte[] snLimited = (mNonceSizeLimit > 0) ? new byte[mNonceSizeLimit] : null; + System.arraycopy(sn, 0, snLimited, 0, mNonceSizeLimit); + crsResp.setRecipientNonce(snLimited); + } else { + crsResp.setRecipientNonce(sn); + } + byte[] serverNonce = new byte[16]; + mRandom.nextBytes(serverNonce); + crsResp.setSenderNonce(serverNonce); + // crsResp.setSenderNonce(new byte[] {0}); + } + + // Deal with message type + String mt = req.getMessageType(); + if (mt == null) { + throw new ServletException("Error: malformed PKIMessage - missing messageType"); + } + + // now run appropriate code, depending on message type + if (mt.equals(CRSPKIMessage.mType_PKCSReq)) { + CMS.debug("Processing PKCSReq"); + try { + // Check if there is an existing request. If this returns non-null, + // then the request is 'active' (either pending or completed) in + // which case, we compare the hash of the new request to the hash of the + // one in the queue - if they are the same, I return the state of the + // original request - as if it was 'getCertInitial' message. + // If the hashes are different, then the user attempted to enroll + // for a new request with the same txid, which is not allowed - + // so we return 'failure'. + + IRequest cmsRequest = findRequestByTransactionID(req.getTransactionID(), true); + + // If there was no request (with a cert) with this transaction ID, + // process it as a new request + + cert = handlePKCSReq(httpReq, cmsRequest, req, crsResp, cx); + + } catch (CRSFailureException e) { + throw new ServletException("Couldn't handle CEP request (PKCSReq) - " + e.getMessage()); + } + } else if (mt.equals(CRSPKIMessage.mType_GetCertInitial)) { + CMS.debug("Processing GetCertInitial"); + cert = handleGetCertInitial(req, crsResp); + } else { + CMS.debug("Invalid request type " + mt); + } + } catch (ServletException e) { + throw new ServletException(e.getMessage().toString()); + } catch (CRSInvalidSignatureException e) { + CMS.debug("handlePKIMessage exception " + e); + CMS.debug(e); + crsResp.setFailInfo(CRSPKIMessage.mFailInfo_badMessageCheck); + } catch (Exception e) { + CMS.debug("handlePKIMessage exception " + e); + CMS.debug(e); + throw new ServletException("Failed to process message in CEP servlet: " + e.getMessage()); + } + + // We have now processed the request, and need to make the response message + + try { + // make the response + processCertRep(cx, cert, crsResp, req); + + // Get the response coding + response = crsResp.getResponse(); + + // Encode the crsResp into B64 + httpResp.setContentType("application/x-pki-message"); + httpResp.setContentLength(response.length); + httpResp.getOutputStream().write(response); + httpResp.getOutputStream().flush(); + + CMS.debug("Output PKIOperation response:"); + CMS.debug(CMS.BtoA(response)); + } catch (Exception e) { + throw new ServletException("Failed to create response for CEP message" + e.getMessage()); + } + + } + + /** + * finds a request with this transaction ID. + * If could not find any request - return null + * If could only find 'rejected' or 'cancelled' requests, return null + * If found 'pending' or 'completed' request - return that request + */ + + public IRequest findRequestByTransactionID(String txid, boolean ignoreRejected) + throws EBaseException { + + /* Check if certificate request has been completed */ + + IRequestQueue rq = ca.getRequestQueue(); + IRequest foundRequest = null; + + Enumeration rids = rq.findRequestsBySourceId(txid); + if (rids == null) { + return null; + } + + while (rids.hasMoreElements()) { + RequestId rid = rids.nextElement(); + if (rid == null) { + continue; + } + + IRequest request = rq.findRequest(rid); + if (request == null) { + continue; + } + if (!ignoreRejected || + request.getRequestStatus().equals(RequestStatus.PENDING) || + request.getRequestStatus().equals(RequestStatus.COMPLETE)) { + if (foundRequest != null) { + } + foundRequest = request; + } + } + return foundRequest; + } + + /** + * Called if the router is requesting us to send it its certificate + * Examine request queue for a request matching the transaction ID. + * Ignore any rejected or cancelled requests. + * + * If a request is found in the pending state, the response should be + * 'pending' + * + * If a request is found in the completed state, the response should be + * to return the certificate + * + * If no request is found, the response should be to return null + * + */ + + public X509CertImpl handleGetCertInitial(CRSPKIMessage req, CRSPKIMessage resp) { + IRequest foundRequest = null; + + // already done by handlePKIOperation + // resp.setRecipientNonce(req.getSenderNonce()); + // resp.setSenderNonce(null); + + try { + foundRequest = findRequestByTransactionID(req.getTransactionID(), false); + } catch (EBaseException e) { + } + + if (foundRequest == null) { + resp.setFailInfo(CRSPKIMessage.mFailInfo_badCertId); + resp.setPKIStatus(CRSPKIMessage.mStatus_FAILURE); + return null; + } + + return makeResponseFromRequest(req, resp, foundRequest); + } + + public void verifyRequest(CRSPKIMessage req, CryptoContext cx) + throws CRSInvalidSignatureException { + + // Get Signed Data + + @SuppressWarnings("unused") + byte[] reqAAbytes = req.getAA(); // check for errors + + @SuppressWarnings("unused") + byte[] reqAAsig = req.getAADigest(); // check for errors + + } + + /** + * Create an entry for this user in the publishing directory + * + */ + + private boolean createEntry(String dn) { + boolean result = false; + + IPublisherProcessor ldapPub = mAuthority.getPublisherProcessor(); + if (ldapPub == null || !ldapPub.enabled()) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERROR_CREATE_ENTRY_FROM_CEP")); + + return result; + } + + ILdapConnFactory connFactory = ((IPublisherProcessor) ldapPub).getLdapConnModule().getLdapConnFactory(); + if (connFactory == null) { + return result; + } + + LDAPConnection connection = null; + try { + connection = connFactory.getConn(); + String[] objectclasses = { "top", mEntryObjectclass }; + LDAPAttribute ocAttrs = new LDAPAttribute("objectclass", objectclasses); + + LDAPAttributeSet attrSet = new LDAPAttributeSet(); + attrSet.add(ocAttrs); + + LDAPEntry newEntry = new LDAPEntry(dn, attrSet); + connection.add(newEntry); + result = true; + } catch (Exception e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_FAIL_CREAT_ENTRY_EXISTS", dn)); + } finally { + try { + connFactory.returnConn(connection); + } catch (Exception f) { + } + } + return result; + } + + /** + * Here we decrypt the PKCS10 message from the client + * + */ + + public void unwrapPKCS10(CRSPKIMessage req, CryptoContext cx) + throws ServletException, + CryptoManager.NotInitializedException, + CryptoContext.CryptoContextException, + CRSFailureException { + + byte[] decryptedP10bytes = null; + SymmetricKey sk; + SymmetricKey skinternal; + SymmetricKey.Type skt; + KeyWrapper kw; + Cipher cip; + EncryptionAlgorithm ea; + + // Unwrap the session key with the Cert server key + try { + kw = cx.getKeyWrapper(); + + kw.initUnwrap(cx.getPrivateKey(), null); + + skt = SymmetricKey.Type.DES; + ea = EncryptionAlgorithm.DES_CBC; + if (mEncryptionAlgorithm != null && mEncryptionAlgorithm.equals("DES3")) { + skt = SymmetricKey.Type.DES3; + ea = EncryptionAlgorithm.DES3_CBC; + } + + sk = kw.unwrapSymmetric(req.getWrappedKey(), + skt, + SymmetricKey.Usage.DECRYPT, + 0); // keylength is ignored + + skinternal = cx.getDESKeyGenerator().clone(sk); + + cip = skinternal.getOwningToken().getCipherContext(ea); + + cip.initDecrypt(skinternal, (new IVParameterSpec(req.getIV()))); + + decryptedP10bytes = cip.doFinal(req.getEncryptedPkcs10()); + CMS.debug("decryptedP10bytes:"); + CMS.debug(decryptedP10bytes); + + req.setP10(new PKCS10(decryptedP10bytes)); + } catch (Exception e) { + CMS.debug("failed to unwrap PKCS10 " + e); + throw new CRSFailureException("Could not unwrap PKCS10 blob: " + e.getMessage()); + } + + } + + private void getDetailFromRequest(CRSPKIMessage req, CRSPKIMessage crsResp) + throws CRSFailureException { + + SubjectAlternativeNameExtension sane = null; + + try { + PKCS10 p10 = req.getP10(); + + if (p10 == null) { + crsResp.setFailInfo(CRSPKIMessage.mFailInfo_badMessageCheck); + crsResp.setPKIStatus(CRSPKIMessage.mStatus_FAILURE); + throw new CRSFailureException("Failed to decode pkcs10 from CEP request"); + } + + AuthCredentials authCreds = new AuthCredentials(); + + // Here, we make a new CertInfo - it's a new start for a certificate + + X509CertInfo certInfo = CMS.getDefaultX509CertInfo(); + + // get some stuff out of the request + X509Key key = p10.getSubjectPublicKeyInfo(); + X500Name p10subject = p10.getSubjectName(); + + X500Name subject = null; + + // The following code will copy all the attributes + // into the AuthCredentials so they can be used for + // authentication + // + // Optionally, you can re-map the subject name from: + // one RDN, with many AVA's to + // many RDN's with one AVA in each. + + Enumeration rdne = p10subject.getRDNs(); + Vector rdnv = new Vector(); + + Hashtable sanehash = new Hashtable(); + + X500NameAttrMap xnap = X500NameAttrMap.getDefault(); + while (rdne.hasMoreElements()) { + RDN rdn = (RDN) rdne.nextElement(); + int i = 0; + AVA[] oldavas = rdn.getAssertion(); + for (i = 0; i < rdn.getAssertionLength(); i++) { + AVA[] newavas = new AVA[1]; + newavas[0] = oldavas[i]; + + authCreds.set(xnap.getName(oldavas[i].getOid()), + oldavas[i].getValue().getAsString()); + + if (oldavas[i].getOid().equals(OID_UNSTRUCTUREDNAME)) { + + sanehash.put(SANE_DNSNAME, oldavas[i].getValue().getAsString()); + } + if (oldavas[i].getOid().equals(OID_UNSTRUCTUREDADDRESS)) { + sanehash.put(SANE_IPADDRESS, oldavas[i].getValue().getAsString()); + } + + RDN newrdn = new RDN(newavas); + if (mFlattenDN) { + rdnv.addElement(newrdn); + } + } + } + + if (mFlattenDN) + subject = new X500Name(rdnv); + else + subject = p10subject; + + // create default key usage extension + KeyUsageExtension kue = new KeyUsageExtension(); + kue.set(KeyUsageExtension.DIGITAL_SIGNATURE, Boolean.valueOf(true)); + kue.set(KeyUsageExtension.KEY_ENCIPHERMENT, Boolean.valueOf(true)); + + PKCS10Attributes p10atts = p10.getAttributes(); + Enumeration e = p10atts.getElements(); + + while (e.hasMoreElements()) { + PKCS10Attribute p10a = (PKCS10Attribute) e.nextElement(); + CertAttrSet attr = p10a.getAttributeValue(); + + if (attr.getName().equals(ChallengePassword.NAME)) { + if (attr.get(ChallengePassword.PASSWORD) != null) { + req.put(AUTH_PASSWORD, + (String) attr.get(ChallengePassword.PASSWORD)); + req.put(ChallengePassword.NAME, + hashPassword( + (String) attr.get(ChallengePassword.PASSWORD))); + } + } + + if (attr.getName().equals(ExtensionsRequested.NAME)) { + + Enumeration exts = ((ExtensionsRequested) attr).getExtensions().elements(); + while (exts.hasMoreElements()) { + Extension ext = exts.nextElement(); + + if (ext.getExtensionId().equals( + OIDMap.getOID(KeyUsageExtension.IDENT))) { + + kue = new KeyUsageExtension( + new Boolean(false), // noncritical + ext.getExtensionValue()); + } + + if (ext.getExtensionId().equals( + OIDMap.getOID(SubjectAlternativeNameExtension.IDENT))) { + sane = new SubjectAlternativeNameExtension( + new Boolean(false), // noncritical + ext.getExtensionValue()); + + @SuppressWarnings("unchecked") + Vector v = + (Vector) sane + .get(SubjectAlternativeNameExtension.SUBJECT_NAME); + + Enumeration gne = v.elements(); + + while (gne.hasMoreElements()) { + GeneralNameInterface gni = (GeneralNameInterface) gne.nextElement(); + if (gni instanceof GeneralName) { + GeneralName genName = (GeneralName) gni; + + String gn = genName.toString(); + int colon = gn.indexOf(':'); + String gnType = gn.substring(0, colon).trim(); + String gnValue = gn.substring(colon + 1).trim(); + + authCreds.set(gnType, gnValue); + } + } + } + } + } + } + + if (authCreds != null) + req.put(AUTH_CREDS, authCreds); + + try { + if (sane == null) + sane = makeDefaultSubjectAltName(sanehash); + } catch (Exception sane_e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ENROLL_FAIL_NO_SUBJ_ALT_NAME", + sane_e.getMessage())); + } + + try { + if (mAppendDN != null && !mAppendDN.equals("")) { + + new X500Name(subject.toString()); // check for errors + + subject = new X500Name(subject.toString().concat("," + mAppendDN)); + } + + } catch (Exception sne) { + log(ILogger.LL_INFO, + "Unable to use appendDN parameter: " + + mAppendDN + ". Error is " + sne.getMessage() + " Using unmodified subjectname"); + } + + if (subject != null) + req.put(SUBJECTNAME, subject); + + if (key == null || subject == null) { + // log + //throw new ERegistrationException(RegistrationResources.ERROR_MALFORMED_P10); + } + + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + + certInfo.set(X509CertInfo.SUBJECT, + new CertificateSubjectName(subject)); + + certInfo.set(X509CertInfo.KEY, + new CertificateX509Key(key)); + + CertificateExtensions ext = new CertificateExtensions(); + + if (kue != null) { + ext.set(KeyUsageExtension.NAME, kue); + } + + // add subjectAltName extension, if present + if (sane != null) { + ext.set(SubjectAlternativeNameExtension.NAME, sane); + } + + certInfo.set(X509CertInfo.EXTENSIONS, ext); + + req.put(CERTINFO, certInfo); + } catch (Exception e) { + crsResp.setFailInfo(CRSPKIMessage.mFailInfo_badMessageCheck); + crsResp.setPKIStatus(CRSPKIMessage.mStatus_FAILURE); + return; + } // NEED TO FIX + } + + private SubjectAlternativeNameExtension makeDefaultSubjectAltName(Hashtable ht) { + + // if no subjectaltname extension was requested, we try to make it up + // from some of the elements of the subject name + + int itemCount = ht.size(); + GeneralNameInterface[] gn = new GeneralNameInterface[ht.size()]; + + itemCount = 0; + Enumeration en = ht.keys(); + while (en.hasMoreElements()) { + String key = (String) en.nextElement(); + if (key.equals(SANE_DNSNAME)) { + gn[itemCount++] = new DNSName((String) ht.get(key)); + } + if (key.equals(SANE_IPADDRESS)) { + gn[itemCount++] = new IPAddressName((String) ht.get(key)); + } + } + + try { + return new SubjectAlternativeNameExtension(new GeneralNames(gn)); + } catch (Exception e) { + log(ILogger.LL_INFO, CMS.getLogMessage("CMSGW_ENROLL_FAIL_NO_SUBJ_ALT_NAME", + e.getMessage())); + return null; + } + } + + // Perform authentication + + /* + * if the authentication is set up for CEP, and the user provides + * some credential, an attempt is made to authenticate the user + * If this fails, this method will return true + * If it is sucessful, this method will return true and + * an authtoken will be in the request + * + * If authentication is not configured, this method will + * return false. The request will be processed in the usual + * way, but no authtoken will be in the request. + * + * In other word, this method returns true if the request + * should be aborted, false otherwise. + */ + + private boolean authenticateUser(CRSPKIMessage req) { + boolean authenticationFailed = true; + + if (mAuthManagerName == null) { + return false; + } + + String password = (String) req.get(AUTH_PASSWORD); + + AuthCredentials authCreds = (AuthCredentials) req.get(AUTH_CREDS); + + if (authCreds == null) { + authCreds = new AuthCredentials(); + } + + // authtoken starts as null + AuthToken token = null; + + if (password != null && !password.equals("")) { + try { + authCreds.set(AUTH_PASSWORD, password); + } catch (Exception e) { + } + } + + try { + token = (AuthToken) mAuthSubsystem.authenticate(authCreds, mAuthManagerName); + authCreds.delete(AUTH_PASSWORD); + // if we got here, the authenticate call must not have thrown + // an exception + authenticationFailed = false; + } catch (EInvalidCredentials ex) { + // Invalid credentials - we must reject the request + authenticationFailed = true; + } catch (EMissingCredential mc) { + // Misssing credential - we'll log, and process manually + authenticationFailed = false; + } catch (EBaseException ex) { + // If there's some other error, we'll reject + // So, we just continue on, - AUTH_TOKEN will not be set. + } + + if (token != null) { + req.put(AUTH_TOKEN, token); + } + + return authenticationFailed; + } + + private boolean areFingerprintsEqual(IRequest req, Hashtable fingerprints) { + + Hashtable old_fprints = req.getExtDataInHashtable(IRequest.FINGERPRINTS); + if (old_fprints == null) { + return false; + } + + byte[] old_md5 = CMS.AtoB(old_fprints.get("MD5")); + byte[] new_md5 = fingerprints.get("MD5"); + + if (old_md5.length != new_md5.length) + return false; + + for (int i = 0; i < old_md5.length; i++) { + if (old_md5[i] != new_md5[i]) + return false; + } + return true; + } + + public X509CertImpl handlePKCSReq(HttpServletRequest httpReq, + IRequest cmsRequest, CRSPKIMessage req, + CRSPKIMessage crsResp, CryptoContext cx) + throws ServletException, + CryptoManager.NotInitializedException, + CRSFailureException { + + try { + unwrapPKCS10(req, cx); + Hashtable fingerprints = makeFingerPrints(req); + + if (cmsRequest != null) { + if (areFingerprintsEqual(cmsRequest, fingerprints)) { + CMS.debug("created response from request"); + return makeResponseFromRequest(req, crsResp, cmsRequest); + } else { + CMS.debug("duplicated transaction id"); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ENROLL_FAIL_DUP_TRANS_ID")); + crsResp.setFailInfo(CRSPKIMessage.mFailInfo_badRequest); + crsResp.setPKIStatus(CRSPKIMessage.mStatus_FAILURE); + return null; + } + } + + getDetailFromRequest(req, crsResp); + boolean authFailed = authenticateUser(req); + + if (authFailed) { + CMS.debug("authentication failed"); + log(ILogger.LL_SECURITY, CMS.getLogMessage("CMSGW_ENROLL_FAIL_NO_AUTH")); + crsResp.setFailInfo(CRSPKIMessage.mFailInfo_badIdentity); + crsResp.setPKIStatus(CRSPKIMessage.mStatus_FAILURE); + + // perform audit log + String auditMessage = CMS.getLogMessage( + "LOGGING_SIGNED_AUDIT_NON_PROFILE_CERT_REQUEST_5", + httpReq.getRemoteAddr(), + ILogger.FAILURE, + req.getTransactionID(), + "CRSEnrollment", + ILogger.SIGNED_AUDIT_EMPTY_VALUE); + ILogger signedAuditLogger = CMS.getSignedAuditLogger(); + if (signedAuditLogger != null) { + signedAuditLogger.log(ILogger.EV_SIGNED_AUDIT, + null, ILogger.S_SIGNED_AUDIT, + ILogger.LL_SECURITY, auditMessage); + } + + return null; + } else { + IRequest ireq = postRequest(httpReq, req, crsResp); + + CMS.debug("created response"); + return makeResponseFromRequest(req, crsResp, ireq); + } + } catch (CryptoContext.CryptoContextException e) { + CMS.debug("failed to decrypt the request " + e); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ENROLL_FAIL_NO_DECRYPT_PKCS10", + e.getMessage())); + crsResp.setFailInfo(CRSPKIMessage.mFailInfo_badMessageCheck); + crsResp.setPKIStatus(CRSPKIMessage.mStatus_FAILURE); + } catch (EBaseException e) { + CMS.debug("operation failure - " + e); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERNOLL_FAIL_NO_NEW_REQUEST_POSTED", + e.getMessage())); + crsResp.setFailInfo(CRSPKIMessage.mFailInfo_internalCAError); + crsResp.setPKIStatus(CRSPKIMessage.mStatus_FAILURE); + } + return null; + } + + ////// post the request + + /* + needed: + + token (authtoken) + certInfo + fingerprints x + req.transactionID + crsResp + */ + + private IRequest postRequest(HttpServletRequest httpReq, CRSPKIMessage req, CRSPKIMessage crsResp) + throws EBaseException { + X500Name subject = (X500Name) req.get(SUBJECTNAME); + + if (mCreateEntry) { + if (subject == null) { + CMS.debug("CRSEnrollment::postRequest() - subject is null!"); + return null; + } + createEntry(subject.toString()); + } + + // use profile framework to handle SCEP + if (mProfileId != null) { + PKCS10 pkcs10data = req.getP10(); + String pkcs10blob = CMS.BtoA(pkcs10data.toByteArray()); + + // XXX authentication handling + CMS.debug("Found profile=" + mProfileId); + IProfile profile = mProfileSubsystem.getProfile(mProfileId); + if (profile == null) { + CMS.debug("profile " + mProfileId + " not found"); + return null; + } + IProfileContext ctx = profile.createContext(); + + IProfileAuthenticator authenticator = null; + try { + CMS.debug("Retrieving authenticator"); + authenticator = profile.getAuthenticator(); + if (authenticator == null) { + CMS.debug("No authenticator Found"); + } else { + CMS.debug("Got authenticator=" + authenticator.getClass().getName()); + } + } catch (EProfileException e) { + // authenticator not installed correctly + } + + IAuthToken authToken = null; + + // for ssl authentication; pass in servlet for retrieving + // ssl client certificates + SessionContext context = SessionContext.getContext(); + + // insert profile context so that input parameter can be retrieved + context.put("profileContext", ctx); + context.put("sslClientCertProvider", + new SSLClientCertProvider(httpReq)); + + String p10Password = getPasswordFromP10(pkcs10data); + AuthCredentials credentials = new AuthCredentials(); + credentials.set("UID", httpReq.getRemoteAddr()); + credentials.set("PWD", p10Password); + + if (authenticator == null) { + // XXX - to help caRouterCert to work, we need to + // add authentication to caRouterCert + authToken = new AuthToken(null); + } else { + authToken = authenticate(credentials, authenticator, httpReq); + } + + IRequest reqs[] = null; + CMS.debug("CRSEnrollment: Creating profile requests"); + ctx.set(IEnrollProfile.CTX_CERT_REQUEST_TYPE, "pkcs10"); + ctx.set(IEnrollProfile.CTX_CERT_REQUEST, pkcs10blob); + Locale locale = Locale.getDefault(); + reqs = profile.createRequests(ctx, locale); + if (reqs == null) { + CMS.debug("CRSEnrollment: No request has been created"); + return null; + } else { + CMS.debug("CRSEnrollment: Request (" + reqs.length + ") have been created"); + } + // set transaction id + reqs[0].setSourceId(req.getTransactionID()); + reqs[0].setExtData("profile", "true"); + reqs[0].setExtData("profileId", mProfileId); + reqs[0].setExtData(IEnrollProfile.CTX_CERT_REQUEST_TYPE, IEnrollProfile.REQ_TYPE_PKCS10); + reqs[0].setExtData(IEnrollProfile.CTX_CERT_REQUEST, pkcs10blob); + reqs[0].setExtData("requestor_name", ""); + reqs[0].setExtData("requestor_email", ""); + reqs[0].setExtData("requestor_phone", ""); + reqs[0].setExtData("profileRemoteHost", httpReq.getRemoteHost()); + reqs[0].setExtData("profileRemoteAddr", httpReq.getRemoteAddr()); + reqs[0].setExtData("profileApprovedBy", profile.getApprovedBy()); + + CMS.debug("CRSEnrollment: Populating inputs"); + profile.populateInput(ctx, reqs[0]); + CMS.debug("CRSEnrollment: Populating requests"); + profile.populate(reqs[0]); + + CMS.debug("CRSEnrollment: Submitting request"); + profile.submit(authToken, reqs[0]); + CMS.debug("CRSEnrollment: Done submitting request"); + profile.getRequestQueue().markAsServiced(reqs[0]); + CMS.debug("CRSEnrollment: Request marked as serviced"); + + return reqs[0]; + + } + + IRequestQueue rq = ca.getRequestQueue(); + IRequest pkiReq = rq.newRequest(IRequest.ENROLLMENT_REQUEST); + + AuthToken token = (AuthToken) req.get(AUTH_TOKEN); + if (token != null) { + pkiReq.setExtData(IRequest.AUTH_TOKEN, token); + } + + pkiReq.setExtData(IRequest.HTTP_PARAMS, IRequest.CERT_TYPE, IRequest.CEP_CERT); + X509CertInfo certInfo = (X509CertInfo) req.get(CERTINFO); + pkiReq.setExtData(IRequest.CERT_INFO, new X509CertInfo[] { certInfo }); + pkiReq.setExtData("cepsubstore", mSubstoreName); + + try { + String chpwd = (String) req.get(ChallengePassword.NAME); + if (chpwd != null) { + pkiReq.setExtData("challengePhrase", + chpwd); + } + } catch (Exception pwex) { + } + + Hashtable fingerprints = (Hashtable) req.get(IRequest.FINGERPRINTS); + if (fingerprints.size() > 0) { + Hashtable encodedPrints = new Hashtable(fingerprints.size()); + Enumeration e = fingerprints.keys(); + while (e.hasMoreElements()) { + String key = (String) e.nextElement(); + byte[] value = (byte[]) fingerprints.get(key); + encodedPrints.put(key, CMS.BtoA(value)); + } + pkiReq.setExtData(IRequest.FINGERPRINTS, encodedPrints); + } + + pkiReq.setSourceId(req.getTransactionID()); + + rq.processRequest(pkiReq); + + crsResp.setPKIStatus(CRSPKIMessage.mStatus_SUCCESS); + + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + AuditFormat.ENROLLMENTFORMAT, + new Object[] { + pkiReq.getRequestId(), + AuditFormat.FROMROUTER, + mAuthManagerName == null ? AuditFormat.NOAUTH : mAuthManagerName, + "pending", + subject, + "" } + ); + + return pkiReq; + } + + public Hashtable makeFingerPrints(CRSPKIMessage req) { + Hashtable fingerprints = new Hashtable(); + + MessageDigest md; + String[] hashes = new String[] { "MD2", "MD5", "SHA1", "SHA256", "SHA512" }; + PKCS10 p10 = (PKCS10) req.getP10(); + + for (int i = 0; i < hashes.length; i++) { + try { + md = MessageDigest.getInstance(hashes[i]); + md.update(p10.getCertRequestInfo()); + fingerprints.put(hashes[i], md.digest()); + } catch (NoSuchAlgorithmException nsa) { + } + } + + if (fingerprints != null) { + req.put(IRequest.FINGERPRINTS, fingerprints); + } + return fingerprints; + } + + // Take a look to see if the request was successful, and fill + // in the response message + + private X509CertImpl makeResponseFromRequest(CRSPKIMessage crsReq, CRSPKIMessage crsResp, + IRequest pkiReq) { + + X509CertImpl issuedCert = null; + + RequestStatus status = pkiReq.getRequestStatus(); + + String profileId = pkiReq.getExtDataInString("profileId"); + if (profileId != null) { + CMS.debug("CRSEnrollment: Found profile request"); + X509CertImpl cert = + pkiReq.getExtDataInCert(IEnrollProfile.REQUEST_ISSUED_CERT); + if (cert == null) { + CMS.debug("CRSEnrollment: No certificate has been found"); + } else { + CMS.debug("CRSEnrollment: Found certificate"); + } + crsResp.setPKIStatus(CRSPKIMessage.mStatus_SUCCESS); + return cert; + } + + if (status.equals(RequestStatus.COMPLETE)) { + Integer success = pkiReq.getExtDataInInteger(IRequest.RESULT); + + if (success.equals(IRequest.RES_SUCCESS)) { + // The cert was issued, lets send it back to the router + X509CertImpl[] issuedCertBuf = + pkiReq.getExtDataInCertArray(IRequest.ISSUED_CERTS); + if (issuedCertBuf == null || issuedCertBuf.length == 0) { + // writeError("Internal Error: Bad operation",httpReq,httpResp); + CMS.debug("CRSEnrollment::makeResponseFromRequest() - " + + "Bad operation"); + return null; + } + issuedCert = issuedCertBuf[0]; + crsResp.setPKIStatus(CRSPKIMessage.mStatus_SUCCESS); + + } else { // status is not 'success' - there must've been a problem + + crsResp.setPKIStatus(CRSPKIMessage.mStatus_FAILURE); + crsResp.setFailInfo(CRSPKIMessage.mFailInfo_badAlg); + } + } else if (status.equals(RequestStatus.REJECTED_STRING) || + status.equals(RequestStatus.CANCELED_STRING)) { + crsResp.setPKIStatus(CRSPKIMessage.mStatus_FAILURE); + crsResp.setFailInfo(CRSPKIMessage.mFailInfo_badRequest); + } else { // not complete + crsResp.setPKIStatus(CRSPKIMessage.mStatus_PENDING); + } + + return issuedCert; + } + + protected String hashPassword(String pwd) { + String salt = "lala123"; + byte[] pwdDigest = mSHADigest.digest((salt + pwd).getBytes()); + String b64E = Utils.base64encode(pwdDigest); + return "{SHA}" + b64E; + } + + /** + * Make the CRSPKIMESSAGE response + */ + + private void processCertRep(CryptoContext cx, + X509CertImpl issuedCert, + CRSPKIMessage crsResp, + CRSPKIMessage crsReq) + throws CRSFailureException { + byte[] msgdigest = null; + byte[] encryptedDesKey = null; + + try { + if (issuedCert != null) { + + SymmetricKey sk; + SymmetricKey skinternal; + + KeyGenAlgorithm kga = KeyGenAlgorithm.DES; + EncryptionAlgorithm ea = EncryptionAlgorithm.DES_CBC; + if (mEncryptionAlgorithm != null && mEncryptionAlgorithm.equals("DES3")) { + kga = KeyGenAlgorithm.DES3; + ea = EncryptionAlgorithm.DES3_CBC; + } + + // 1. Make the Degenerated PKCS7 with the recipient's certificate in it + + byte toBeEncrypted[] = + crsResp.makeSignedRep(1, // version + issuedCert.getEncoded() + ); + + // 2. Encrypt the above byte array with a new random DES key + + sk = cx.getDESKeyGenerator().generate(); + + skinternal = cx.getInternalToken().getKeyGenerator(kga).clone(sk); + + byte[] padded = Cipher.pad(toBeEncrypted, ea.getBlockSize()); + + // This should be changed to generate proper DES IV. + + Cipher cipher = cx.getInternalToken().getCipherContext(ea); + IVParameterSpec desIV = + new IVParameterSpec(new byte[] { + (byte) 0xff, (byte) 0x00, + (byte) 0xff, (byte) 0x00, + (byte) 0xff, (byte) 0x00, + (byte) 0xff, (byte) 0x00 }); + + cipher.initEncrypt(sk, desIV); + byte[] encryptedData = cipher.doFinal(padded); + + crsResp.makeEncryptedContentInfo(desIV.getIV(), encryptedData, mEncryptionAlgorithm); + + // 3. Extract the recipient's public key + + PublicKey rcpPK = crsReq.getSignerPublicKey(); + + // 4. Encrypt the DES key with the public key + + // we have to move the key onto the interal token. + //skinternal = cx.getInternalKeyStorageToken().cloneKey(sk); + skinternal = cx.getInternalToken().cloneKey(sk); + + KeyWrapper kw = cx.getInternalKeyWrapper(); + kw.initWrap(rcpPK, null); + encryptedDesKey = kw.wrap(skinternal); + + crsResp.setRcpIssuerAndSerialNumber(crsReq.getSgnIssuerAndSerialNumber()); + crsResp.makeRecipientInfo(0, encryptedDesKey); + + } + + byte[] ed = crsResp.makeEnvelopedData(0); + + // 7. Make Digest of SignedData Content + MessageDigest md = MessageDigest.getInstance(mHashAlgorithm); + msgdigest = md.digest(ed); + + crsResp.setMsgDigest(msgdigest); + + } + + catch (Exception e) { + throw new CRSFailureException("Failed to create inner response to CEP message: " + e.getMessage()); + } + + // 5. Make a RecipientInfo + + // The issuer name & serial number here, should be that of + // the EE's self-signed Certificate + // [I can get it from the req blob, but later, I should + // store the recipient's self-signed certificate with the request + // so I can get at it later. I need to do this to support + // 'PENDING'] + + try { + + // 8. Make Authenticated Attributes + // we can just pull the transaction ID out of the request. + // Later, we will have to put it out of the Request queue, + // so we can support PENDING + crsResp.setTransactionID(crsReq.getTransactionID()); + // recipientNonce and SenderNonce have already been set + + crsResp.makeAuthenticatedAttributes(); + // crsResp.makeAuthenticatedAttributes_old(); + + // now package up the rest of the SignerInfo + { + byte[] signingcertbytes = cx.getSigningCert().getEncoded(); + + Certificate.Template sgncert_t = new Certificate.Template(); + Certificate sgncert = + (Certificate) sgncert_t.decode(new ByteArrayInputStream(signingcertbytes)); + + IssuerAndSerialNumber sgniasn = + new IssuerAndSerialNumber(sgncert.getInfo().getIssuer(), + sgncert.getInfo().getSerialNumber()); + + crsResp.setSgnIssuerAndSerialNumber(sgniasn); + + // 10. Make SignerInfo + crsResp.makeSignerInfo(1, cx.getPrivateKey(), mHashAlgorithm); + + // 11. Make SignedData + crsResp.makeSignedData(1, signingcertbytes, mHashAlgorithm); + + crsResp.debug(); + } + } catch (Exception e) { + throw new CRSFailureException("Failed to create outer response to CEP request: " + e.getMessage()); + } + + // if debugging, dump out the response into a file + + } + + class CryptoContext { + private CryptoManager cm; + private CryptoToken internalToken; + private CryptoToken keyStorageToken; + private CryptoToken internalKeyStorageToken; + private KeyGenerator DESkg; + private Enumeration externalTokens = null; + private org.mozilla.jss.crypto.X509Certificate signingCert; + private org.mozilla.jss.crypto.PrivateKey signingCertPrivKey; + private int signingCertKeySize = 0; + + class CryptoContextException extends Exception { + /** + * + */ + private static final long serialVersionUID = -1124116326126256475L; + + public CryptoContextException() { + super(); + } + + public CryptoContextException(String s) { + super(s); + } + } + + public CryptoContext() + throws CryptoContextException { + try { + KeyGenAlgorithm kga = KeyGenAlgorithm.DES; + if (mEncryptionAlgorithm != null && mEncryptionAlgorithm.equals("DES3")) { + kga = KeyGenAlgorithm.DES3; + } + cm = CryptoManager.getInstance(); + internalToken = cm.getInternalCryptoToken(); + DESkg = internalToken.getKeyGenerator(kga); + if (mTokenName.equalsIgnoreCase(Constants.PR_INTERNAL_TOKEN) || + mTokenName.equalsIgnoreCase("Internal Key Storage Token") || + mTokenName.length() == 0) { + keyStorageToken = cm.getInternalKeyStorageToken(); + internalKeyStorageToken = keyStorageToken; + CMS.debug("CRSEnrollment: CryptoContext: internal token name: '" + mTokenName + "'"); + } else { + keyStorageToken = cm.getTokenByName(mTokenName); + internalKeyStorageToken = null; + } + if (!mUseCA && internalKeyStorageToken == null) { + PasswordCallback cb = CMS.getPasswordCallback(); + keyStorageToken.login(cb); // ONE_TIME by default. + } + signingCert = cm.findCertByNickname(mNickname); + signingCertPrivKey = cm.findPrivKeyByCert(signingCert); + byte[] encPubKeyInfo = signingCert.getPublicKey().getEncoded(); + SEQUENCE.Template outer = SEQUENCE.getTemplate(); + outer.addElement(ANY.getTemplate()); // algid + outer.addElement(BIT_STRING.getTemplate()); + SEQUENCE outerSeq = (SEQUENCE) ASN1Util.decode(outer, encPubKeyInfo); + BIT_STRING bs = (BIT_STRING) outerSeq.elementAt(1); + byte[] encPubKey = bs.getBits(); + if (bs.getPadCount() != 0) { + throw new CryptoContextException( + "Internal error: Invalid Public key. Not an integral number of bytes."); + } + SEQUENCE.Template inner = new SEQUENCE.Template(); + inner.addElement(INTEGER.getTemplate()); + inner.addElement(INTEGER.getTemplate()); + SEQUENCE pubKeySeq = (SEQUENCE) ASN1Util.decode(inner, encPubKey); + INTEGER modulus = (INTEGER) pubKeySeq.elementAt(0); + signingCertKeySize = modulus.bitLength(); + + try { + FileOutputStream fos = new FileOutputStream("pubkey.der"); + fos.write(signingCert.getPublicKey().getEncoded()); + fos.close(); + } catch (Exception e) { + } + + } catch (InvalidBERException e) { + throw new CryptoContextException( + "Internal Error: Bad internal Certificate Representation. Not a valid RSA-signed certificate"); + } catch (CryptoManager.NotInitializedException e) { + throw new CryptoContextException("Crypto Manager not initialized"); + } catch (NoSuchAlgorithmException e) { + throw new CryptoContextException("Cannot create DES key generator"); + } catch (ObjectNotFoundException e) { + throw new CryptoContextException("Certificate not found: " + ca.getNickname()); + } catch (TokenException e) { + throw new CryptoContextException("Problem with Crypto Token: " + e.getMessage()); + } catch (NoSuchTokenException e) { + throw new CryptoContextException("Crypto Token not found: " + e.getMessage()); + } catch (IncorrectPasswordException e) { + throw new CryptoContextException("Incorrect Password."); + } + } + + public KeyGenerator getDESKeyGenerator() { + return DESkg; + } + + public CryptoToken getInternalToken() { + return internalToken; + } + + public void setExternalTokens(Enumeration tokens) { + externalTokens = tokens; + } + + public Enumeration getExternalTokens() { + return externalTokens; + } + + public CryptoToken getInternalKeyStorageToken() { + return internalKeyStorageToken; + } + + public CryptoToken getKeyStorageToken() { + return keyStorageToken; + } + + public CryptoManager getCryptoManager() { + return cm; + } + + public KeyWrapper getKeyWrapper() + throws CryptoContextException { + try { + return signingCertPrivKey.getOwningToken().getKeyWrapper(KeyWrapAlgorithm.RSA); + } catch (TokenException e) { + throw new CryptoContextException("Problem with Crypto Token: " + e.getMessage()); + } catch (NoSuchAlgorithmException e) { + throw new CryptoContextException(e.getMessage()); + } + } + + public KeyWrapper getInternalKeyWrapper() + throws CryptoContextException { + try { + return getInternalToken().getKeyWrapper(KeyWrapAlgorithm.RSA); + } catch (TokenException e) { + throw new CryptoContextException("Problem with Crypto Token: " + e.getMessage()); + } catch (NoSuchAlgorithmException e) { + throw new CryptoContextException(e.getMessage()); + } + } + + public org.mozilla.jss.crypto.PrivateKey getPrivateKey() { + return signingCertPrivKey; + } + + public org.mozilla.jss.crypto.X509Certificate getSigningCert() { + return signingCert; + } + + } + + /* General failure. The request/response cannot be processed. */ + + class CRSFailureException extends Exception { + /** + * + */ + private static final long serialVersionUID = 1962741611501549051L; + + public CRSFailureException() { + super(); + } + + public CRSFailureException(String s) { + super(s); + } + } + + class CRSInvalidSignatureException extends Exception { + /** + * + */ + private static final long serialVersionUID = 9096408193567657944L; + + public CRSInvalidSignatureException() { + super(); + } + + public CRSInvalidSignatureException(String s) { + super(s); + } + } + + class CRSPolicyException extends Exception { + /** + * + */ + private static final long serialVersionUID = 5846593800658787396L; + + public CRSPolicyException() { + super(); + } + + public CRSPolicyException(String s) { + super(s); + } + } + +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/scep/ChallengePassword.java b/base/common/src/com/netscape/cms/servlet/cert/scep/ChallengePassword.java new file mode 100644 index 000000000..ff55dc9ce --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/scep/ChallengePassword.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.cms.servlet.cert.scep; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.cert.CertificateException; +import java.util.Enumeration; +import java.util.Vector; + +import netscape.security.util.DerValue; +import netscape.security.x509.CertAttrSet; + +/** + * Class for handling the decoding of a SCEP Challenge Password + * object. Currently this class cannot be used for encoding + * thus some fo the methods are unimplemented + */ +public class ChallengePassword implements CertAttrSet { + + public static final String NAME = "ChallengePassword"; + public static final String PASSWORD = "password"; + + private String cpw; + + /** + * Get the password marshalled in this object + * + * @return the challenge password + */ + public String toString() { + return cpw; + } + + /** + * Create a ChallengePassword object + * + * @param stuff (must be of type byte[]) a DER-encoded by array following + * The ASN.1 template for ChallenegePassword specified in the SCEP + * documentation + * @throws IOException if the DER encoded byt array was malformed, or if it + * did not match the template + */ + + public ChallengePassword(Object stuff) + throws IOException { + + ByteArrayInputStream is = new ByteArrayInputStream((byte[]) stuff); + try { + decode(is); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + + } + + /** + * Currently Unimplemented + */ + public void encode(OutputStream out) + throws CertificateException, IOException { + } + + public void decode(InputStream in) + throws CertificateException, IOException { + DerValue derVal = new DerValue(in); + + construct(derVal); + + } + + private void construct(DerValue derVal) throws IOException { + try { + cpw = derVal.getPrintableString(); + } catch (NullPointerException e) { + cpw = ""; + } + } + + /** + * Currently Unimplemented + */ + public void set(String name, Object obj) + throws CertificateException, IOException { + } + + /** + * Get an attribute of this object. + * + * @param name the name of the attribute of this object to get. The only + * supported attribute is "password" + */ + public Object get(String name) + throws CertificateException, IOException { + if (name.equalsIgnoreCase(PASSWORD)) { + return cpw; + } else { + throw new IOException("Attribute name not recognized by " + + "CertAttrSet: ChallengePassword"); + } + } + + /** + * Currently Unimplemented + */ + public void delete(String name) + throws CertificateException, IOException { + } + + /** + * @return an empty set of elements + */ + public Enumeration getAttributeNames() { + return (new Vector()).elements(); + } + + /** + * @return the String "ChallengePassword" + */ + public String getName() { + return NAME; + } + +} diff --git a/base/common/src/com/netscape/cms/servlet/cert/scep/ExtensionsRequested.java b/base/common/src/com/netscape/cms/servlet/cert/scep/ExtensionsRequested.java new file mode 100644 index 000000000..85f3938b8 --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/cert/scep/ExtensionsRequested.java @@ -0,0 +1,176 @@ +// --- 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.cert.scep; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.cert.CertificateException; +import java.util.Enumeration; +import java.util.Vector; + +import netscape.security.util.DerInputStream; +import netscape.security.util.DerValue; +import netscape.security.x509.CertAttrSet; +import netscape.security.x509.Extension; + +public class ExtensionsRequested implements CertAttrSet { + + public static final String NAME = "EXTENSIONS_REQUESTED"; + + public static final String KUE_DIGITAL_SIGNATURE = "kue_digital_signature"; + public static final String KUE_KEY_ENCIPHERMENT = "kue_key_encipherment"; + + private String kue_digital_signature = "false"; + private String kue_key_encipherment = "false"; + + private Vector exts = new Vector(); + + public ExtensionsRequested(Object stuff) throws IOException { + ByteArrayInputStream is = new ByteArrayInputStream((byte[]) stuff); + + try { + decode(is); + } catch (Exception e) { + e.printStackTrace(); + throw new IOException(e.getMessage()); + } + } + + public void encode(OutputStream out) + throws CertificateException, IOException { + } + + public void decode(InputStream in) + throws CertificateException, IOException { + DerValue derVal = new DerValue(in); + + construct(derVal); + } + + public void set(String name, Object obj) + throws CertificateException, IOException { + } + + public Object get(String name) + throws CertificateException, IOException { + if (name.equalsIgnoreCase(KUE_DIGITAL_SIGNATURE)) { + return kue_digital_signature; + } + if (name.equalsIgnoreCase(KUE_KEY_ENCIPHERMENT)) { + return kue_key_encipherment; + } + + throw new IOException("Unsupported attribute queried"); + } + + public void delete(String name) + throws CertificateException, IOException { + } + + public Enumeration getAttributeNames() { + return (new Vector()).elements(); + } + + public String getName() { + return NAME; + } + + /** + * construct - expects this in the inputstream (from the router): + * + * 211 30 31: SEQUENCE { + * 213 06 10: OBJECT IDENTIFIER '2 16 840 1 113733 1 9 8' + * 225 31 17: SET { + * 227 04 15: OCTET STRING, encapsulates { + * 229 30 13: SEQUENCE { + * 231 30 11: SEQUENCE { + * 233 06 3: OBJECT IDENTIFIER keyUsage (2 5 29 15) + * 238 04 4: OCTET STRING + * : 03 02 05 A0 + * : } + * : } + * : } + * + * or this (from IRE client): + * + * 262 30 51: SEQUENCE { + * 264 06 9: OBJECT IDENTIFIER extensionReq (1 2 840 113549 1 9 14) + * 275 31 38: SET { + * 277 30 36: SEQUENCE { + * 279 30 34: SEQUENCE { + * 281 06 3: OBJECT IDENTIFIER subjectAltName (2 5 29 17) + * 286 04 27: OCTET STRING + * : 30 19 87 04 D0 0C 3E 6F 81 03 61 61 61 82 0C 61 + * : 61 61 2E 6D 63 6F 6D 2E 63 6F 6D + * : } + * : } + * : } + * : } + */ + private void construct(DerValue dv) throws IOException { + + DerInputStream stream = null; + + try { // try decoding as sequence first + + stream = dv.toDerInputStream(); + + stream.getDerValue(); // consume stream + stream.reset(); + + stream.getSequence(2); // consume stream + } catch (IOException ioe) { + // if it failed, the outer sequence may be + // encapsulated in an octet string, as in the first + // example above + + byte[] octet_string = dv.getOctetString(); + + // Make a new input stream from the byte array, + // and re-parse it as a sequence. + + dv = new DerValue(octet_string); + + stream = dv.toDerInputStream(); + stream.getSequence(2); // consume stream + } + + // now, the stream will be in the correct format + stream.reset(); + + while (true) { + DerValue ext_dv = null; + try { + ext_dv = stream.getDerValue(); + } catch (IOException ex) { + break; + } + + Extension ext = new Extension(ext_dv); + exts.addElement(ext); + } + + } + + public Vector getExtensions() { + return exts; + } + +} -- cgit