diff options
Diffstat (limited to 'pki/base/common/src/com/netscape/cms/servlet/ocsp')
6 files changed, 1677 insertions, 0 deletions
diff --git a/pki/base/common/src/com/netscape/cms/servlet/ocsp/AddCAServlet.java b/pki/base/common/src/com/netscape/cms/servlet/ocsp/AddCAServlet.java new file mode 100644 index 000000000..e4a93826c --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/servlet/ocsp/AddCAServlet.java @@ -0,0 +1,234 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cms.servlet.ocsp; + + +import com.netscape.cms.servlet.common.*; +import com.netscape.cms.servlet.base.*; + +import java.math.*; +import java.util.Vector; +import java.io.InputStream; +import java.io.IOException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.ServletException; + +import org.mozilla.jss.asn1.INTEGER; +import org.mozilla.jss.pkix.cert.Certificate; +import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier; +import org.mozilla.jss.asn1.BIT_STRING; + +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authority.*; +import com.netscape.certsrv.ocsp.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.dbs.crldb.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.authorization.*; +import com.netscape.cms.servlet.*; +import com.netscape.cmsutil.util.*; + +import netscape.security.pkcs.*; +import netscape.security.x509.*; +import java.security.cert.*; +import java.util.*; +import javax.servlet.*; +import javax.servlet.http.*; + + +/** + * Configure the CA to respond to OCSP requests for a CA + * + * $Revision: 14561 $ $Date: 2007-05-01 10:28:56 -0700 (Tue, 01 May 2007) $ + */ +public class AddCAServlet extends CMSServlet { + + public static final String BEGIN_HEADER = + "-----BEGIN CERTIFICATE-----"; + public static final String END_HEADER = + "-----END CERTIFICATE-----"; + + public static final BigInteger BIG_ZERO = new BigInteger("0"); + public static final Long MINUS_ONE = Long.valueOf(-1); + + private final static String TPL_FILE = "addCA.template"; + private String mFormPath = null; + private IOCSPAuthority mOCSPAuthority = null; + + public AddCAServlet() { + super(); + } + + /** + * initialize the servlet. This servlet uses the template file + * "addCA.template" to process 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 display own output. + + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + mTemplates.remove(CMSRequest.SUCCESS); + mOCSPAuthority = (IOCSPAuthority) mAuthority; + + if (mOutputTemplatePath != null) + mFormPath = mOutputTemplatePath; + } + + /** + * Process the HTTP request. + * <ul> + * <li>http.param cert ca certificate. The format is base-64, DER + * encoded, wrapped with -----BEGIN CERTIFICATE-----, + * -----END CERTIFICATE----- strings + * </ul> + * + * @param cmsReq the object holding the request and response information + */ + protected 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, "add"); + } 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", mFormPath, e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + String b64 = cmsReq.getHttpReq().getParameter("cert"); + + if (b64 == null) { + throw new ECMSGWException(CMS.getUserMessage(getLocale(req), "CMS_GW_MISSING_CA_CERT")); + } + + if (b64.indexOf(BEGIN_HEADER) == -1) { + throw new ECMSGWException(CMS.getUserMessage(getLocale(req), "CMS_GW_MISSING_CERT_HEADER")); + } + if (b64.indexOf(END_HEADER) == -1) { + throw new ECMSGWException(CMS.getUserMessage(getLocale(req), "CMS_GW_MISSING_CERT_FOOTER")); + } + + IDefStore defStore = mOCSPAuthority.getDefaultStore(); + + X509Certificate leafCert = null; + X509Certificate certs[] = null; + + try { + X509Certificate cert = Cert.mapCert(b64); + + if( cert == null ) { + CMS.debug( "AddCAServlet::process() - cert is null!" ); + throw new EBaseException( "cert is null" ); + } else { + certs = new X509Certificate[1]; + } + + certs[0] = cert; + leafCert = cert; + } catch (Exception e) { + } + if (certs == null) { + try { + // this could be a chain + certs = Cert.mapCertFromPKCS7(b64); + if (certs[0].getSubjectDN().getName().equals(certs[0].getIssuerDN().getName())) { + leafCert = certs[certs.length - 1]; + } else { + leafCert = certs[0]; + } + } catch (Exception e) { + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_ENCODING_CA_CHAIN_ERROR")); + } + } + if (certs != null && certs.length > 0) { + // (1) need to normalize (sort) the chain + + // (2) store certificate (and certificate chain) into + // database + ICRLIssuingPointRecord rec = defStore.createCRLIssuingPointRecord( + leafCert.getSubjectDN().getName(), + BIG_ZERO, + MINUS_ONE, null, null); + + try { + rec.set(ICRLIssuingPointRecord.ATTR_CA_CERT, leafCert.getEncoded()); + } catch (Exception e) { + // error + } + defStore.addCRLIssuingPoint(leafCert.getSubjectDN().getName(), rec); + log(ILogger.EV_AUDIT, AuditFormat.LEVEL, "Added CA certificate " + leafCert.getSubjectDN().getName()); + } + + try { + ServletOutputStream out = resp.getOutputStream(); + String error = null; + + 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")); + } + } +} diff --git a/pki/base/common/src/com/netscape/cms/servlet/ocsp/AddCRLServlet.java b/pki/base/common/src/com/netscape/cms/servlet/ocsp/AddCRLServlet.java new file mode 100644 index 000000000..dcb4d20ab --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/servlet/ocsp/AddCRLServlet.java @@ -0,0 +1,576 @@ +// --- 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.ocsp; + + +import com.netscape.cms.servlet.common.*; +import com.netscape.cms.servlet.base.*; + +import java.math.*; +import java.util.Vector; +import java.io.InputStream; +import java.io.IOException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.ServletException; + +import org.mozilla.jss.*; +import org.mozilla.jss.asn1.INTEGER; +import org.mozilla.jss.pkix.cert.Certificate; +import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier; +import org.mozilla.jss.asn1.BIT_STRING; + +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.util.*; +import com.netscape.certsrv.authority.*; +import com.netscape.certsrv.ocsp.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.dbs.crldb.*; +import com.netscape.certsrv.dbs.certdb.*; +import com.netscape.certsrv.dbs.repository.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.authorization.*; +import com.netscape.cms.servlet.*; +import com.netscape.cmsutil.util.*; + +import netscape.security.pkcs.*; +import netscape.security.x509.*; +import java.security.cert.*; +import java.util.*; +import javax.servlet.*; +import javax.servlet.http.*; + + +/** + * Update the OCSP responder with a new CRL + * + * $Revision: 14561 $ $Date: 2007-05-01 10:28:56 -0700 (Tue, 01 May 2007) $ + */ +public class AddCRLServlet extends CMSServlet { + + public static final String BEGIN_HEADER = + "-----BEGIN CERTIFICATE REVOCATION LIST-----"; + public static final String END_HEADER = + "-----END CERTIFICATE REVOCATION LIST-----"; + + private final static String TPL_FILE = "addCRL.template"; + private String mFormPath = null; + private IOCSPAuthority mOCSPAuthority = null; + + private final static String LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL = + "LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL_3"; + private final static String LOGGING_SIGNED_AUDIT_CRL_VALIDATION = + "LOGGING_SIGNED_AUDIT_CRL_VALIDATION_2"; + + public AddCRLServlet() { + super(); + } + + /** + * initialize the servlet. This servlet uses the template file + * "addCRL.template" to process 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 display own output. + + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + mTemplates.remove(CMSRequest.SUCCESS); + mOCSPAuthority = (IOCSPAuthority) mAuthority; + if (mOutputTemplatePath != null) + mFormPath = mOutputTemplatePath; + } + + /** + * Process the HTTP request. + * <P> + * + * <ul> + * <li>http.param crl certificate revocation list, base-64, DER encoded + * wrapped in -----BEGIN CERTIFICATE REVOCATION LIST-----, + * -----END CERTIFICATE REVOCATION LIST----- strings + * <li>http.param noui if true, use minimal hardcoded text response + * <li>signed.audit LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL used when CRLs are + * retrieved by the OCSP Responder ("agent" or "EE") + * <li>signed.audit LOGGING_SIGNED_AUDIT_CRL_VALIDATION used when CRL is + * retrieved and validation process occurs ("agent" or "EE") + * </ul> + * @param cmsReq the object holding the request and response information + * @exception EBaseException an error has occurred + */ + protected synchronized void process(CMSRequest cmsReq) + throws EBaseException { + boolean CRLFetched = false; + boolean CRLValidated = false; + String auditMessage = null; + String auditSubjectID = auditSubjectID(); + String auditCRLNum = ILogger.SIGNED_AUDIT_EMPTY_VALUE; + + IStatsSubsystem statsSub = (IStatsSubsystem)CMS.getSubsystem("stats"); + if (statsSub != null) { + statsSub.startTiming("add_crl", true /* main action */); + } + + try { + HttpServletRequest req = cmsReq.getHttpReq(); + HttpServletResponse resp = cmsReq.getHttpResp(); + + IAuthToken authToken = authenticate(cmsReq); + + AuthzToken authzToken = null; + + try { + authzToken = authorize(mAclMethod, authToken, + mAuthzResourceName, "add"); + } catch (Exception e) { + // do nothing for now + } + + if (authzToken == null) { + cmsReq.setStatus(CMSRequest.UNAUTHORIZED); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL, + auditSubjectID, + ILogger.FAILURE, + auditCRLNum ); + + audit( auditMessage ); + + return; + } + + log(ILogger.LL_INFO, "AddCRLServlet"); + String b64 = cmsReq.getHttpReq().getParameter("crl"); + if (CMS.debugOn()) CMS.debug("AddCRLServlet: b64=" + b64); + + if (b64 == null) { + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL, + auditSubjectID, + ILogger.FAILURE, + auditCRLNum ); + + audit( auditMessage ); + + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_MISSING_CRL")); + } + + String nouiParm = cmsReq.getHttpReq().getParameter("noui"); + boolean noUI = false; + + if (nouiParm != null && nouiParm.equals("true")) { + noUI = true; + CMS.debug("AddCRLServlet: noUI=true"); + } else { + CMS.debug("AddCRLServlet: noUI=false"); + } + + CMSTemplate form = null; + Locale[] locale = new Locale[1]; + + try { + if (!noUI) { + form = getTemplate(mFormPath, req, locale); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_GET_TEMPLATE", mFormPath, + e.toString())); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL, + auditSubjectID, + ILogger.FAILURE, + auditCRLNum ); + + audit( auditMessage ); + + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + if (b64.indexOf(BEGIN_HEADER) == -1) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_CRL_HEADER")); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL, + auditSubjectID, + ILogger.FAILURE, + auditCRLNum ); + + audit( auditMessage ); + + throw new ECMSGWException(CMS.getUserMessage(getLocale(req), + "CMS_GW_MISSING_CRL_HEADER")); + } + if (b64.indexOf(END_HEADER) == -1) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_MISSING_CRL_FOOTER")); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL, + auditSubjectID, + ILogger.FAILURE, + auditCRLNum ); + + audit( auditMessage ); + + throw new ECMSGWException(CMS.getUserMessage(getLocale(req), + "CMS_GW_MISSING_CRL_FOOTER")); + } + + IDefStore defStore = mOCSPAuthority.getDefaultStore(); + + X509CRLImpl crl = null; + + try { + long startTime = CMS.getCurrentDate().getTime(); + CMS.debug("AddCRLServlet: mapCRL start startTime=" + startTime); + if (statsSub != null) { + statsSub.startTiming("decode_crl"); + } + crl = mapCRL1( b64 ); + if (statsSub != null) { + statsSub.endTiming("decode_crl"); + } + long endTime = CMS.getCurrentDate().getTime(); + CMS.debug("AddCRLServlet: mapCRL done endTime=" + endTime + + " diff=" + (endTime - startTime)); + + // Retrieve the actual CRL number + BigInteger crlNum = crl.getCRLNumber(); + if( crlNum != null ) { + auditCRLNum = crlNum.toString(); + } + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL, + auditSubjectID, + ILogger.SUCCESS, + auditCRLNum ); + + audit( auditMessage ); + + // acknowledge that the CRL has been retrieved + CRLFetched = true; + } catch (Exception e) { + // error + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL, + auditSubjectID, + ILogger.FAILURE, + auditCRLNum ); + + audit( auditMessage ); + + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DECODING_CRL_ERROR")); + } + log(ILogger.LL_INFO, "AddCRLServlet: CRL Issuer DN " + + crl.getIssuerDN().getName()); + + // update the CRLIssuingPoint record + if (crl == null) { + // error + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CRL_VALIDATION, + auditSubjectID, + ILogger.FAILURE ); + + audit( auditMessage ); + + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DECODING_CRL_ERROR")); + } + + ICRLIssuingPointRecord pt = null; + + try { + pt = defStore.readCRLIssuingPoint( + crl.getIssuerDN().getName()); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_NO_CRL_ISSUING_POINT_FOUND", + crl.getIssuerDN().getName())); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CRL_VALIDATION, + auditSubjectID, + ILogger.FAILURE ); + + audit( auditMessage ); + + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DECODING_CRL_ERROR")); + } + log(ILogger.LL_INFO, "AddCRLServlet: IssuingPoint " + + pt.getThisUpdate()); + + // verify CRL + byte caCertData[] = pt.getCACert(); + if (caCertData != null) { + try { + X509CertImpl caCert = new X509CertImpl(caCertData); + CMS.debug("AddCRLServlet: start verify"); + + CryptoManager cmanager = CryptoManager.getInstance(); + org.mozilla.jss.crypto.X509Certificate jssCert = null; + try { + jssCert = cmanager.importCACertPackage( + caCert.getEncoded()); + } catch (Exception e2) { + CMS.debug("AddCRLServlet: importCACertPackage " + + e2.toString()); + throw new EBaseException( e2.toString() ); + } + + if (statsSub != null) { + statsSub.startTiming("verify_crl"); + } + crl.verify(jssCert.getPublicKey(), "Mozilla-JSS"); + if (statsSub != null) { + statsSub.endTiming("verify_crl"); + } + CMS.debug("AddCRLServlet: done verify"); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CRL_VALIDATION, + auditSubjectID, + ILogger.SUCCESS ); + + audit( auditMessage ); + + // acknowledge that the CRL has been validated + CRLValidated = true; + } catch (Exception e) { + CMS.debug("AddCRLServlet: failed to verify CRL " + e.toString()); + CMS.debug(e); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_NO_CRL_ISSUING_POINT_FOUND", + crl.getIssuerDN().getName())); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CRL_VALIDATION, + auditSubjectID, + ILogger.FAILURE ); + + audit( auditMessage ); + + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DECODING_CRL_ERROR")); + } + } + + if ((pt.getThisUpdate() != null) && + (pt.getThisUpdate().getTime() >= + crl.getThisUpdate().getTime())) { + // error, the uploaded CRL is older than the current + CMS.debug("AddCRLServlet: no update, CRL is older"); + log(ILogger.LL_INFO, + "AddCRLServlet: no update, received CRL is older " + + "than current CRL"); + if (noUI) { + try { + resp.setContentType("application/text"); + resp.getOutputStream().write("status=1\n".getBytes()); + resp.getOutputStream().write( + "error=Sent CRL is older than the current CRL\n".getBytes()); + resp.getOutputStream().flush(); + cmsReq.setStatus(CMSRequest.SUCCESS); + + // NOTE: The signed audit events + // LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL and + // LOGGING_SIGNED_AUDIT_CRL_VALIDATION have + // already been logged at this point! + + return; + } catch (Exception e) { + } + } else { + CMS.debug("AddCRLServlet: CRL is older"); + + // NOTE: The signed audit events + // LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL and + // LOGGING_SIGNED_AUDIT_CRL_VALIDATION have + // already been logged at this point! + + throw new ECMSGWException(CMS.getUserMessage( + "CMS_GW_OLD_CRL_ERROR")); + } + } + + CMS.debug("AddCRLServlet: strt committing CRL"); + log(ILogger.LL_INFO, "AddCRLServlet: Start Committing CRL"); + + // ***************************************************** + // The commit transaction may take long time and + // there may have a system crash during the transaction + // ***************************************************** + + IRepositoryRecord repRec = defStore.createRepositoryRecord(); + + repRec.set(IRepositoryRecord.ATTR_SERIALNO, + new BigInteger(Long.toString(crl.getThisUpdate().getTime()))); + try { + defStore.addRepository( + crl.getIssuerDN().getName(), + Long.toString(crl.getThisUpdate().getTime()), + repRec); + log(ILogger.EV_AUDIT, AuditFormat.LEVEL, "Added CRL Updated " + + Long.toString(crl.getThisUpdate().getTime())); + } catch (Exception e) { + CMS.debug("AddCRLServlet: add repository e=" + e.toString()); + } + log(ILogger.LL_INFO, "AddCRLServlet: Created CRL Repository " + + Long.toString(crl.getThisUpdate().getTime())); + + if (defStore.waitOnCRLUpdate()) { + defStore.updateCRL(crl); + } else { + // when the CRL large, the thread is terminiated by the + // servlet framework before it can finish its work + UpdateCRLThread uct = new UpdateCRLThread(defStore, crl); + + uct.start(); + } + + try { + ServletOutputStream out = resp.getOutputStream(); + + if (noUI) { + CMS.debug("AddCRLServlet: return result noUI=true"); + resp.setContentType("application/text"); + resp.getOutputStream().write("status=0".getBytes()); + resp.getOutputStream().flush(); + cmsReq.setStatus(CMSRequest.SUCCESS); + } else { + CMS.debug("AddCRLServlet: return result noUI=false"); + 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) { + CMS.debug("AddCRLServlet: return result error=" + e.toString()); + mOCSPAuthority.log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSGW_ERR_STREAM_TEMPLATE", + e.toString())); + + // NOTE: The signed audit events + // LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL and + // LOGGING_SIGNED_AUDIT_CRL_VALIDATION have + // already been logged at this point! + + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + } catch( EBaseException eAudit1 ) { + if( !CRLFetched ) { + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CRL_RETRIEVAL, + auditSubjectID, + ILogger.FAILURE, + auditCRLNum ); + + audit( auditMessage ); + } else { + if( !CRLValidated ) { + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CRL_VALIDATION, + auditSubjectID, + ILogger.FAILURE ); + + audit( auditMessage ); + } + } + throw eAudit1; + } + if (statsSub != null) { + statsSub.endTiming("add_crl"); + } + } + + public X509CRLImpl mapCRL1(String mime64) + throws IOException { + mime64 = Cert.stripCRLBrackets(mime64.trim()); + + byte rawPub[] = CMS.AtoB(mime64); + X509CRLImpl crl = null; + + try { + crl = new X509CRLImpl(rawPub, false); + } catch (Exception e) { + throw new IOException(e.toString()); + } + return crl; + } +} + + +class UpdateCRLThread extends Thread { + private IDefStore mDefStore = null; + private X509CRL mCRL = null; + + public UpdateCRLThread( + IDefStore defStore, X509CRL crl) { + mDefStore = defStore; + mCRL = crl; + } + + public void run() { + try { + if (!((X509CRLImpl)mCRL).areEntriesIncluded()) + mCRL = new X509CRLImpl(((X509CRLImpl)mCRL).getEncoded()); + mDefStore.updateCRL(mCRL); + } catch (CRLException e) { + } catch (X509ExtensionException e) { + } catch (EBaseException e) { + // ignore + } + } +} diff --git a/pki/base/common/src/com/netscape/cms/servlet/ocsp/CheckCertServlet.java b/pki/base/common/src/com/netscape/cms/servlet/ocsp/CheckCertServlet.java new file mode 100644 index 000000000..f566c1e75 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/servlet/ocsp/CheckCertServlet.java @@ -0,0 +1,224 @@ +// --- 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.ocsp; + + +import com.netscape.cms.servlet.common.*; +import com.netscape.cms.servlet.base.*; + +import java.util.Vector; +import java.io.InputStream; +import java.io.IOException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.ServletException; + +import org.mozilla.jss.asn1.INTEGER; +import org.mozilla.jss.pkix.cert.Certificate; +import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier; +import org.mozilla.jss.asn1.BIT_STRING; + +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.ocsp.*; +import com.netscape.certsrv.authority.*; +import com.netscape.cms.servlet.*; +import com.netscape.certsrv.dbs.crldb.*; +import com.netscape.certsrv.dbs.certdb.*; +import com.netscape.certsrv.apps.*; +import com.netscape.cmsutil.util.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.authorization.*; + +import netscape.security.pkcs.*; +import netscape.security.x509.*; +import java.security.cert.*; +import java.util.*; +import javax.servlet.*; +import javax.servlet.http.*; + + +/** + * Check the status of a specific certificate + * + * $Revision: 14561 $ $Date: 2007-05-01 10:28:56 -0700 (Tue, 01 May 2007) $ + */ +public class CheckCertServlet extends CMSServlet { + + public static final String BEGIN_HEADER = + "-----BEGIN CERTIFICATE-----"; + public static final String END_HEADER = + "-----END CERTIFICATE-----"; + + public static final String ATTR_STATUS = "status"; + public static final String ATTR_ISSUERDN = "issuerDN"; + public static final String ATTR_SUBJECTDN = "subjectDN"; + public static final String ATTR_SERIALNO = "serialno"; + + public static final String STATUS_GOOD = "good"; + public static final String STATUS_REVOKED = "revoked"; + public static final String STATUS_UNKNOWN = "unknown"; + + private final static String TPL_FILE = "checkCert.template"; + private String mFormPath = null; + private IOCSPAuthority mOCSPAuthority = null; + + public CheckCertServlet() { + super(); + } + + /** + * initialize the servlet. This servlet uses the template file + * "checkCert.template" to process 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 display own output. + + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + mTemplates.remove(CMSRequest.SUCCESS); + mOCSPAuthority = (IOCSPAuthority) mAuthority; + if (mOutputTemplatePath != null) + mFormPath = mOutputTemplatePath; + } + + /** + * Process the HTTP request. + * <ul> + * <li>http.param cert certificate to check. Base64, DER encoded, wrapped + * in -----BEGIN CERTIFICATE-----, -----END CERTIFICATE----- strings + * </ul> + * + * @param cmsReq the object holding the request and response information + */ + protected 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, "validate"); + } 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", mFormPath, e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + IDefStore defStore = mOCSPAuthority.getDefaultStore(); + + String b64 = cmsReq.getHttpReq().getParameter("cert"); + + if (b64.indexOf(BEGIN_HEADER) == -1) { + // error + throw new ECMSGWException(CMS.getUserMessage(getLocale(req), "CMS_GW_MISSING_CERT_HEADER")); + + } + if (b64.indexOf(END_HEADER) == -1) { + // error + throw new ECMSGWException(CMS.getUserMessage(getLocale(req), "CMS_GW_MISSING_CERT_FOOTER")); + } + + X509Certificate cert = null; + + try { + cert = Cert.mapCert(b64); + } catch (Exception e) { + throw new ECMSGWException(CMS.getUserMessage("CMS_GW_DECODING_CERT_ERROR")); + } + if (cert == null) { + throw new ECMSGWException(CMS.getUserMessage("CMS_GW_DECODING_CERT_ERROR")); + } + + ICRLIssuingPointRecord pt = defStore.readCRLIssuingPoint( + cert.getIssuerDN().getName()); + + header.addStringValue(ATTR_ISSUERDN, cert.getIssuerDN().getName()); + header.addStringValue(ATTR_SUBJECTDN, cert.getSubjectDN().getName()); + header.addStringValue(ATTR_SERIALNO, "0x" + cert.getSerialNumber().toString(16)); + try { + X509CRLImpl crl = null; + + crl = new X509CRLImpl(pt.getCRL()); + X509CRLEntry crlentry = crl.getRevokedCertificate(cert.getSerialNumber()); + + if (crlentry == null) { + if (defStore.isNotFoundGood()) { + header.addStringValue(ATTR_STATUS, STATUS_GOOD); + } else { + header.addStringValue(ATTR_STATUS, STATUS_UNKNOWN); + } + } else { + header.addStringValue(ATTR_STATUS, STATUS_REVOKED); + } + } catch (Exception e) { + header.addStringValue(ATTR_STATUS, STATUS_UNKNOWN); + } + log(ILogger.EV_AUDIT, AuditFormat.LEVEL, "Checked Certificate Status " + cert.getIssuerDN().getName() + " " + cert.getSerialNumber().toString()); + + try { + ServletOutputStream out = resp.getOutputStream(); + String error = null; + + 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")); + } + } +} diff --git a/pki/base/common/src/com/netscape/cms/servlet/ocsp/GetOCSPInfo.java b/pki/base/common/src/com/netscape/cms/servlet/ocsp/GetOCSPInfo.java new file mode 100644 index 000000000..443863759 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/servlet/ocsp/GetOCSPInfo.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.ocsp; + + +import com.netscape.cms.servlet.common.*; +import com.netscape.cms.servlet.base.*; + +import java.io.*; +import java.util.*; +import java.math.*; +import javax.servlet.*; +import java.security.cert.*; +import javax.servlet.http.*; +import netscape.ldap.*; +import netscape.security.x509.*; +import netscape.security.pkcs.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.ocsp.*; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.dbs.*; +import com.netscape.certsrv.dbs.certdb.*; +import com.netscape.certsrv.ldap.*; +import com.netscape.certsrv.authority.*; +import com.netscape.certsrv.ca.*; + +import com.netscape.certsrv.dbs.*; +import com.netscape.certsrv.dbs.crldb.*; +import com.netscape.cms.servlet.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.authorization.*; + + +/** + * Retrieve information about the number of OCSP requests the OCSP + * has serviced + * + * @version $Revision: 14561 $, $Date: 2007-05-01 10:28:56 -0700 (Tue, 01 May 2007) $ + */ +public class GetOCSPInfo extends CMSServlet { + private final static String TPL_FILE = "getOCSPInfo.template"; + private String mFormPath = null; + + public GetOCSPInfo() { + super(); + } + + /** + * initialize the servlet. This servlet uses the template + * file "getOCSPInfo.template" to render the result page. + * + * @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. + + // coming from agent + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + + mTemplates.remove(CMSRequest.SUCCESS); + 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 { + 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 IOCSPService)) { + 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); + + IOCSPService ca = (IOCSPService) mAuthority; + + header.addLongValue("numReq", ca.getNumOCSPRequest()); + header.addLongValue("totalSec", ca.getOCSPRequestTotalTime()); + header.addLongValue("totalSignSec", ca.getOCSPTotalSignTime()); + header.addLongValue("totalLookupSec", ca.getOCSPTotalLookupTime()); + header.addLongValue("totalData", ca.getOCSPTotalData()); + long secs = 0; + if (ca.getOCSPRequestTotalTime() != 0) { + secs = (ca.getNumOCSPRequest() * 1000) / ca.getOCSPRequestTotalTime(); + } + header.addLongValue("ReqSec", secs); + 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/pki/base/common/src/com/netscape/cms/servlet/ocsp/ListCAServlet.java b/pki/base/common/src/com/netscape/cms/servlet/ocsp/ListCAServlet.java new file mode 100644 index 000000000..1791b1763 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/servlet/ocsp/ListCAServlet.java @@ -0,0 +1,211 @@ +// --- 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.ocsp; + + +import com.netscape.cms.servlet.common.*; +import com.netscape.cms.servlet.base.*; + +import java.math.*; +import java.util.Vector; +import java.io.InputStream; +import java.io.IOException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.ServletException; + +import org.mozilla.jss.asn1.INTEGER; +import org.mozilla.jss.pkix.cert.Certificate; +import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier; +import org.mozilla.jss.asn1.BIT_STRING; + +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.authorization.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.dbs.crldb.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.ocsp.*; +import com.netscape.certsrv.authority.*; +import com.netscape.cmsutil.util.*; +import com.netscape.cms.servlet.*; +import com.netscape.certsrv.apps.*; + +import netscape.security.pkcs.*; +import netscape.security.x509.*; +import java.security.cert.*; +import java.util.*; +import javax.servlet.*; +import javax.servlet.http.*; + + +/** + * Show the list of CA's that the OCSP responder can service + * + * $Revision: 14561 $ $Date: 2007-05-01 10:28:56 -0700 (Tue, 01 May 2007) $ + */ +public class ListCAServlet extends CMSServlet { + + public static final String BEGIN_HEADER = + "-----BEGIN CERTIFICATE-----"; + public static final String END_HEADER = + "-----END CERTIFICATE-----"; + + private final static String TPL_FILE = "listCAs.template"; + private String mFormPath = null; + private IOCSPAuthority mOCSPAuthority = null; + + public ListCAServlet() { + super(); + } + + /** + * initialize the servlet. This servlet uses the template file + * "listCAs.template" to process 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 display own output. + + mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE; + mTemplates.remove(CMSRequest.SUCCESS); + mOCSPAuthority = (IOCSPAuthority) mAuthority; + 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 { + 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) { + // 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", mFormPath, e.toString())); + throw new ECMSGWException( + CMS.getUserMessage("CMS_GW_DISPLAY_TEMPLATE_ERROR")); + } + + IArgBlock header = CMS.createArgBlock(); + IArgBlock fixed = CMS.createArgBlock(); + CMSTemplateParams argSet = new CMSTemplateParams(header, fixed); + + IDefStore defStore = mOCSPAuthority.getDefaultStore(); + Enumeration recs = defStore.searchAllCRLIssuingPointRecord(100); + + // show the current CRL number if present + header.addStringValue("stateCount", + Integer.toString(defStore.getStateCount())); + + while (recs.hasMoreElements()) { + ICRLIssuingPointRecord rec = + (ICRLIssuingPointRecord) recs.nextElement(); + IArgBlock rarg = CMS.createArgBlock(); + String thisId = rec.getId(); + + rarg.addStringValue("Id", thisId); + Date thisUpdate = rec.getThisUpdate(); + + if (thisUpdate == null) { + rarg.addStringValue("ThisUpdate", "UNKNOWN"); + } else { + rarg.addStringValue("ThisUpdate", thisUpdate.toString()); + } + Date nextUpdate = rec.getNextUpdate(); + + if (nextUpdate == null) { + rarg.addStringValue("NextUpdate", "UNKNOWN"); + } else { + rarg.addStringValue("NextUpdate", nextUpdate.toString()); + } + Long rc = rec.getCRLSize(); + + if (rc == null) { + rarg.addLongValue("NumRevoked", 0); + } else { + if (rc.longValue() == -1) { + rarg.addStringValue("NumRevoked", "UNKNOWN"); + } else { + rarg.addLongValue("NumRevoked", rc.longValue()); + } + } + + BigInteger crlNumber = rec.getCRLNumber(); + if (crlNumber == null || crlNumber.equals(new BigInteger("-1"))) { + rarg.addStringValue("CRLNumber", "UNKNOWN"); + } else { + rarg.addStringValue("CRLNumber", crlNumber.toString()); + } + + rarg.addLongValue("ReqCount", defStore.getReqCount(thisId)); + argSet.addRepeatRecord(rarg); + } + + try { + ServletOutputStream out = resp.getOutputStream(); + String error = null; + + 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")); + } + } +} diff --git a/pki/base/common/src/com/netscape/cms/servlet/ocsp/OCSPServlet.java b/pki/base/common/src/com/netscape/cms/servlet/ocsp/OCSPServlet.java new file mode 100644 index 000000000..6a55e88b3 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/servlet/ocsp/OCSPServlet.java @@ -0,0 +1,259 @@ +// --- 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.ocsp; + + +import com.netscape.cms.servlet.common.*; +import com.netscape.cms.servlet.base.*; + +import java.util.*; +import java.security.*; +import java.util.Vector; +import java.io.*; +import java.io.InputStream; +import java.io.IOException; +import javax.servlet.ServletConfig; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.ServletException; + +import org.mozilla.jss.pkix.primitive.*; +import org.mozilla.jss.asn1.*; +import org.mozilla.jss.asn1.INTEGER; +import org.mozilla.jss.pkix.cert.Certificate; +import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier; +import org.mozilla.jss.asn1.BIT_STRING; + +import netscape.security.x509.*; +import java.security.cert.*; +import com.netscape.certsrv.util.*; +import com.netscape.certsrv.dbs.crldb.*; +import com.netscape.certsrv.dbs.certdb.*; +import com.netscape.certsrv.ocsp.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.authorization.*; +import com.netscape.cmsutil.ocsp.*; +import com.netscape.certsrv.base.*; + + +/** + * Process OCSP messages, According to RFC 2560 + * See http://www.ietf.org/rfc/rfc2560.txt + * + * $Revision: 14612 $ $Date: 2007-05-02 17:37:50 -0700 (Wed, 02 May 2007) $ + */ +public class OCSPServlet extends CMSServlet { + + public final static String PROP_AUTHORITY = "authority"; + public final static String PROP_CLIENTAUTH = "GetClientCert"; + public final static String PROP_MAX_REQUEST_SIZE = "MaxRequestSize"; + public final static String PROP_ID = "ID"; + + private int m_maxRequestSize=5000; + + public OCSPServlet() { + super(); + } + + /** + * initialize the servlet. This servlet uses the template file + * "ImportCert.template" to process the response. + * + * @param sc servlet configuration, read from the web.xml file + */ + public void init(ServletConfig sc) throws ServletException { + super.init(sc); + String s = sc.getInitParameter(PROP_MAX_REQUEST_SIZE); + if (s != null) { + try { + m_maxRequestSize = Integer.parseInt(s); + } catch (Exception e) {} + } + + } + + /** + * Process the HTTP request. + * This method is invoked when the OCSP service receives a OCSP + * request. Based on RFC 2560, the request should have the OCSP + * request in the HTTP body as binary blob. + * + * @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(); + + IStatsSubsystem statsSub = (IStatsSubsystem)CMS.getSubsystem("stats"); + if (statsSub != null) { + statsSub.startTiming("ocsp", true /* main action */); + } + + 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; + } + + CMS.debug("Servlet Path=" + httpReq.getServletPath()); + CMS.debug("RequestURI=" + httpReq.getRequestURI()); + String pathInfo = httpReq.getPathInfo(); + java.net.URLDecoder urldecoder = new java.net.URLDecoder(); + if (pathInfo != null && pathInfo.indexOf('%') != -1) { + pathInfo = urldecoder.decode(pathInfo); + } + CMS.debug("PathInfo=" + pathInfo); + + OCSPRequest ocspReq = null; + + try { + InputStream is = httpReq.getInputStream(); + byte reqbuf[] = null; + String method = httpReq.getMethod(); + CMS.debug("Method=" + method); + if (method != null && method.equals("POST")) { + int reqlen = httpReq.getContentLength(); + + if (reqlen == -1) { + throw new Exception("OCSPServlet: Content-Length not supplied"); + } + if (reqlen == 0) { + throw new Exception("OCSPServlet: Invalid Content-Length"); + } + if (reqlen > m_maxRequestSize) { + throw new Exception("OCSPServlet: Client sending too much OCSP request data ("+reqlen+")"); + } + + // for debugging + reqbuf = new byte[reqlen]; + int bytesread = 0; + boolean partial = false; + + while (bytesread < reqlen) { + int r = is.read(reqbuf, bytesread, reqlen - bytesread); + if (r == -1) { + throw new Exception("OCSPServlet: Client did not supply enough OCSP data"); + } + bytesread += r; + if (partial == false) { + if (bytesread < reqlen) { + partial = true; + } + } + } + is = new ByteArrayInputStream(reqbuf); + } else { + // GET method + if (pathInfo == null) { + throw new Exception("OCSPServlet: OCSP request not provided in GET method"); + } + is = new ByteArrayInputStream( + com.netscape.osutil.OSUtil.AtoB(pathInfo.substring(1))); + } + + // (1) retrieve OCSP request + // (2) decode request + OCSPResponse response = null; + + try { + OCSPRequest.Template reqTemplate = + new OCSPRequest.Template(); + + ocspReq = (OCSPRequest) reqTemplate.decode(is); + response = ((IOCSPService) mAuthority).validate(ocspReq); + } catch (Exception e) {; + CMS.debug("OCSPServlet: " + e.toString()); + } + + if (response != null) { + ByteArrayOutputStream fos1 = new ByteArrayOutputStream(); + + response.encode(fos1); + fos1.close(); + + byte[] respbytes; + + respbytes = fos1.toByteArray(); + + // print out OCSP response in debug mode so that + // we can validate the response + if (CMS.debugOn()) { + CMS.debug("OCSPServlet: OCSP Request:"); + CMS.debug("OCSPServlet: " + CMS.BtoA(ASN1Util.encode(ocspReq))); + TBSRequest tbsReq = ocspReq.getTBSRequest(); + for (int i = 0; i < tbsReq.getRequestCount(); i++) { + com.netscape.cmsutil.ocsp.Request req = tbsReq.getRequestAt(i); + CMS.debug("Serial Number: " + req.getCertID().getSerialNumber()); + } + CMS.debug("OCSPServlet: OCSP Response Size:"); + CMS.debug("OCSPServlet: " + Integer.toString(respbytes.length)); + CMS.debug("OCSPServlet: OCSP Response Data:"); + CMS.debug("OCSPServlet: " + CMS.BtoA(respbytes)); + ResponseBytes rbytes = response.getResponseBytes(); + if (rbytes == null) { + CMS.debug("Response bytes is null"); + } else if (rbytes.getObjectIdentifier().equals( + ResponseBytes.OCSP_BASIC)) { + BasicOCSPResponse basicRes = (BasicOCSPResponse) + BasicOCSPResponse.getTemplate().decode( + new ByteArrayInputStream(rbytes.getResponse().toByteArray())); + if (basicRes == null) { + CMS.debug("Basic Res is null"); + } else { + ResponseData data = basicRes.getResponseData(); + for (int i = 0; i < data.getResponseCount(); i++) { + SingleResponse res = data.getResponseAt(i); + CMS.debug("Serial Number: " + + res.getCertID().getSerialNumber() + + " Status: " + + res.getCertStatus().getClass().getName()); + } + } + } + } + + httpResp.setContentType("application/ocsp-response"); + + httpResp.setContentLength(respbytes.length); + OutputStream ooss = httpResp.getOutputStream(); + + ooss.write(respbytes); + ooss.flush(); + if (statsSub != null) { + statsSub.endTiming("ocsp"); + } + + mRenderResult = false; + } + } catch (Exception e) { + CMS.debug("OCSPServlet: " + e.toString()); + } + } +} |