diff options
Diffstat (limited to 'base/common/src/com/netscape/cms/publish/publishers/OCSPPublisher.java')
-rw-r--r-- | base/common/src/com/netscape/cms/publish/publishers/OCSPPublisher.java | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/base/common/src/com/netscape/cms/publish/publishers/OCSPPublisher.java b/base/common/src/com/netscape/cms/publish/publishers/OCSPPublisher.java new file mode 100644 index 000000000..600bbd110 --- /dev/null +++ b/base/common/src/com/netscape/cms/publish/publishers/OCSPPublisher.java @@ -0,0 +1,355 @@ +// --- 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.publish.publishers; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.Socket; +import java.net.URLEncoder; +import java.security.cert.CRLException; +import java.security.cert.X509CRL; +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.Vector; + +import netscape.ldap.LDAPConnection; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.ldap.ELdapException; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.publish.ILdapPublisher; +import com.netscape.cmsutil.http.HttpRequest; +import com.netscape.cmsutil.http.JssSSLSocketFactory; + +/** + * This publisher writes certificate and CRL into + * a directory. + * + * @version $Revision$, $Date$ + */ +public class OCSPPublisher implements ILdapPublisher, IExtendedPluginInfo { + private static final String PROP_HOST = "host"; + private static final String PROP_PORT = "port"; + private static final String PROP_PATH = "path"; + private static final String PROP_NICK = "nickName"; + private static final String PROP_CLIENT_AUTH_ENABLE = "enableClientAuth"; + + private IConfigStore mConfig = null; + private String mHost = null; + private String mPort = null; + private String mPath = null; + private String mNickname = null; + private boolean mClientAuthEnabled = true; + private ILogger mLogger = CMS.getLogger(); + + /** + * Returns the implementation name. + */ + public String getImplName() { + return "OCSPPublisher"; + } + + /** + * Returns the description of the ldap publisher. + */ + public String getDescription() { + return "This publisher writes the CRL to CMS's OCSP server."; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_HOST + ";string;Host of CMS's OCSP Secure agent service", + PROP_PORT + ";string;Port of CMS's OCSP Secure agent service", + PROP_PATH + ";string;URI of CMS's OCSP Secure agent service", + PROP_NICK + ";string;Nickname of cert used for client authentication", + PROP_CLIENT_AUTH_ENABLE + ";boolean;Client Authentication enabled", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-ldappublish-publisher-ocsppublisher", + IExtendedPluginInfo.HELP_TEXT + + ";Publishes CRLs to a Online Certificate Status Manager, an OCSP responder provided by CMS." + }; + + return params; + } + + /** + * Returns the current instance parameters. + */ + public Vector<String> getInstanceParams() { + Vector<String> v = new Vector<String>(); + String host = ""; + String port = ""; + String path = ""; + String nickname = ""; + String clientAuthEnabled = ""; + + try { + host = mConfig.getString(PROP_HOST); + } catch (EBaseException e) { + } + v.addElement(PROP_HOST + "=" + host); + try { + port = mConfig.getString(PROP_PORT); + } catch (EBaseException e) { + } + v.addElement(PROP_PORT + "=" + port); + try { + path = mConfig.getString(PROP_PATH); + } catch (EBaseException e) { + } + v.addElement(PROP_PATH + "=" + path); + try { + nickname = mConfig.getString(PROP_NICK); + } catch (EBaseException e) { + } + v.addElement(PROP_NICK + "=" + nickname); + try { + clientAuthEnabled = mConfig.getString(PROP_CLIENT_AUTH_ENABLE); + } catch (EBaseException e) { + } + v.addElement(PROP_CLIENT_AUTH_ENABLE + "=" + clientAuthEnabled); + return v; + } + + /** + * Returns the initial default parameters. + */ + public Vector<String> getDefaultParams() { + Vector<String> v = new Vector<String>(); + + IConfigStore config = CMS.getConfigStore(); + String nickname = ""; + // get subsystem cert nickname as default for client auth + try { + nickname = config.getString("ca.subsystem.nickname", ""); + String tokenname = config.getString("ca.subsystem.tokenname", ""); + if (!tokenname.equals("internal") && !tokenname.equals("Internal Key Storage Token")) + nickname = tokenname + ":" + nickname; + } catch (Exception e) { + } + + v.addElement(PROP_HOST + "="); + v.addElement(PROP_PORT + "="); + v.addElement(PROP_PATH + "=/ocsp/agent/ocsp/addCRL"); + v.addElement(PROP_CLIENT_AUTH_ENABLE + "=true"); + v.addElement(PROP_NICK + "=" + nickname); + return v; + } + + /** + * Initializes this plugin. + */ + public void init(IConfigStore config) { + mConfig = config; + try { + mHost = mConfig.getString(PROP_HOST, ""); + mPort = mConfig.getString(PROP_PORT, ""); + mPath = mConfig.getString(PROP_PATH, ""); + mNickname = mConfig.getString(PROP_NICK, ""); + mClientAuthEnabled = mConfig.getBoolean(PROP_CLIENT_AUTH_ENABLE, true); + } catch (EBaseException e) { + } + } + + public IConfigStore getConfigStore() { + return mConfig; + } + + protected Socket Connect(String host, boolean secure, JssSSLSocketFactory factory) { + Socket socket = null; + StringTokenizer st = new StringTokenizer(host, " "); + while (st.hasMoreTokens()) { + String hp = st.nextToken(); // host:port + StringTokenizer st1 = new StringTokenizer(hp, ":"); + String h = st1.nextToken(); + int p = Integer.parseInt(st1.nextToken()); + try { + if (secure) { + socket = factory.makeSocket(h, p); + } else { + socket = new Socket(h, p); + } + return socket; + } catch (Exception e) { + } + try { + Thread.sleep(5000); // 5 seconds delay + } catch (Exception e) { + } + } + return null; + } + + /** + * Publishs a object to the ldap directory. + * + * @param conn a Ldap connection + * (null if LDAP publishing is not enabled) + * @param dn dn of the ldap entry to publish cert + * (null if LDAP publishing is not enabled) + * @param object object to publish + * (java.security.cert.X509Certificate or, + * java.security.cert.X509CRL) + */ + public synchronized void publish(LDAPConnection conn, String dn, Object object) + throws ELdapException { + try { + if (!(object instanceof X509CRL)) + return; + X509CRL crl = (X509CRL) object; + + // talk to agent port of CMS + + // open the connection and prepare it to POST + boolean secure = true; + + String host = mHost; + int port = Integer.parseInt(mPort); + String path = mPath; + + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + ILogger.LL_INFO, "OCSPPublisher: " + + "Host='" + host + "' Port='" + port + + "' URL='" + path + "'"); + CMS.debug("OCSPPublisher: " + + "Host='" + host + "' Port='" + port + + "' URL='" + path + "'"); + + StringBuffer query = new StringBuffer(); + query.append("crl="); + query.append(URLEncoder.encode("-----BEGIN CERTIFICATE REVOCATION LIST-----\n", "UTF-8")); + query.append(URLEncoder.encode(CMS.BtoA(crl.getEncoded()), "UTF-8")); + query.append(URLEncoder.encode("\n-----END CERTIFICATE REVOCATION LIST-----", "UTF-8")); + query.append("&noui=true"); + + Socket socket = null; + JssSSLSocketFactory factory; + + if (mClientAuthEnabled) { + factory = new JssSSLSocketFactory(mNickname); + } else { + factory = new JssSSLSocketFactory(); + } + + if (mHost != null && mHost.indexOf(' ') != -1) { + // support failover hosts configuration + // host parameter can be + // "directory.knowledge.com:1050 people.catalog.com 199.254.1.2" + do { + socket = Connect(mHost, secure, factory); + } while (socket == null); + } else { + if (secure) { + socket = factory.makeSocket(host, port); + } else { + socket = new Socket(host, port); + } + } + + if (socket == null) { + CMS.debug("OCSPPublisher::publish() - socket is null!"); + throw new ELdapException("socket is null"); + } + + // use HttpRequest and POST + HttpRequest httpReq = new HttpRequest(); + + httpReq.setMethod("POST"); + httpReq.setURI(path); + httpReq.setHeader("Connection", "Keep-Alive"); + + httpReq.setHeader("Content-Type", + "application/x-www-form-urlencoded"); + httpReq.setHeader("Content-Transfer-Encoding", "7bit"); + + httpReq.setHeader("Content-Length", + Integer.toString(query.length())); + httpReq.setContent(query.toString()); + OutputStream os = socket.getOutputStream(); + OutputStreamWriter outputStreamWriter = new OutputStreamWriter(os, "UTF8"); + + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + ILogger.LL_INFO, "OCSPPublisher: start sending CRL"); + long startTime = CMS.getCurrentDate().getTime(); + CMS.debug("OCSPPublisher: start CRL sending startTime=" + startTime); + httpReq.write(outputStreamWriter); + long endTime = CMS.getCurrentDate().getTime(); + CMS.debug("OCSPPublisher: done CRL sending endTime=" + endTime + " diff=" + (endTime - startTime)); + + // Read the response + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + ILogger.LL_INFO, "OCSPPublisher: start getting response"); + DataInputStream dis = new DataInputStream(socket.getInputStream()); + String nextline; + String error = ""; + boolean status = false; + + while ((nextline = dis.readLine()) != null) { + if (nextline.startsWith("status=")) { + if (nextline.substring(7, nextline.length()).equals("0")) { + status = true; + } + } + if (nextline.startsWith("error=")) { + error = nextline.substring(6, nextline.length()); + } + } + dis.close(); + if (status) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + ILogger.LL_INFO, "OCSPPublisher: successful"); + } else { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + ILogger.LL_INFO, "OCSPPublisher: failed - " + error); + } + + } catch (IOException e) { + CMS.debug("OCSPPublisher: publish failed " + e.toString()); + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_OCSP_PUBLISHER_ERROR", e.toString())); + } catch (CRLException e) { + CMS.debug("OCSPPublisher: publish failed " + e.toString()); + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_OCSP_PUBLISHER_ERROR", e.toString())); + } catch (Exception e) { + CMS.debug("OCSPPublisher: publish failed " + e.toString()); + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_OCSP_PUBLISHER_ERROR", e.toString())); + } + } + + /** + * Unpublishs a object to the ldap directory. + * + * @param conn the Ldap connection + * (null if LDAP publishing is not enabled) + * @param dn dn of the ldap entry to unpublish cert + * (null if LDAP publishing is not enabled) + * @param object object to unpublish + * (java.security.cert.X509Certificate) + */ + public void unpublish(LDAPConnection conn, String dn, Object object) + throws ELdapException { + // NOT USED + } +} |