diff options
Diffstat (limited to 'pki/base/common/src/com/netscape/cms/publish/publishers')
9 files changed, 2976 insertions, 0 deletions
diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/FileBasedPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/FileBasedPublisher.java new file mode 100644 index 000000000..18af1a98b --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/publish/publishers/FileBasedPublisher.java @@ -0,0 +1,424 @@ +// --- 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.math.*; +import java.io.*; +import java.security.cert.*; +import java.util.*; +import java.util.zip.*; +import netscape.ldap.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.ldap.*; +import com.netscape.certsrv.publish.*; +import org.mozilla.jss.util.Base64OutputStream; + +/** + * This publisher writes certificate and CRL into + * a directory. + * + * @version $Revision$, $Date$ + */ +public class FileBasedPublisher implements ILdapPublisher, IExtendedPluginInfo { + private static final String PROP_DIR = "directory"; + private static final String PROP_DER = "Filename.der"; + private static final String PROP_B64 = "Filename.b64"; + private static final String PROP_LNK = "latestCrlLink"; + private static final String PROP_GMT = "timeStamp"; + private static final String PROP_EXT = "crlLinkExt"; + private static final String PROP_ZIP = "zipCRLs"; + private static final String PROP_LEV = "zipLevel"; + private IConfigStore mConfig = null; + private String mDir = null; + private ILogger mLogger = CMS.getLogger(); + private String mCrlIssuingPointId; + protected boolean mDerAttr = true; + protected boolean mB64Attr = false; + protected boolean mLatestCRL = false; + protected boolean mZipCRL = false; + protected String mTimeStamp = null; + protected String mLinkExt = null; + protected int mZipLevel = 9; + + public void setIssuingPointId(String crlIssuingPointId) + { + mCrlIssuingPointId = crlIssuingPointId; + } + /** + * Returns the implementation name. + */ + public String getImplName() { + return "FileBasedPublisher"; + } + + /** + * Returns the description of the ldap publisher. + */ + + public String getDescription() { + return "This publisher writes the Certificates and CRLs into files."; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_DIR + ";string;Directory in which to put the files (absolute path or relative path to cert-* instance directory).", + PROP_DER + ";boolean;Store certificates or CRLs into *.der files.", + PROP_B64 + ";boolean;Store certificates or CRLs into *.b64 files.", + PROP_GMT + ";choice(LocalTime,GMT);Use local time or GMT to time stamp CRL file name with CRL's 'thisUpdate' field.", + PROP_LNK + ";boolean;Generate link to the latest binary CRL. It requires '"+PROP_DER+"' to be enabled.", + PROP_EXT + ";string;Name extension used by link to the latest CRL. Default name extension is 'der'.", + PROP_ZIP + ";boolean;Generate compressed CRLs.", + PROP_LEV + ";choice(0,1,2,3,4,5,6,7,8,9);Set compression level from 0 to 9.", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-ldappublish-publisher-filepublisher", + IExtendedPluginInfo.HELP_TEXT + + ";Stores the certificates or CRLs into files. Certificate is named as cert-<serialno>.der or *.b64, and CRL is named as <IssuingPoint>-<thisUpdate-time>.der or *.b64." + }; + + return params; + } + + /** + * Returns the current instance parameters. + */ + public Vector getInstanceParams() { + Vector v = new Vector(); + String dir = ""; + String ext = ""; + + try { + dir = mConfig.getString(PROP_DIR); + } catch (EBaseException e) { + } + try { + ext = mConfig.getString(PROP_EXT); + } catch (EBaseException e) { + } + try { + mTimeStamp = mConfig.getString(PROP_GMT); + } catch (EBaseException e) { + } + try { + mZipLevel = mConfig.getInteger(PROP_LEV, 9); + } catch (EBaseException e) { + } + try { + if (mTimeStamp == null || (!mTimeStamp.equals("GMT"))) + mTimeStamp = "LocalTime"; + v.addElement(PROP_DIR+"=" + dir); + v.addElement(PROP_DER+"=" + mConfig.getBoolean(PROP_DER,true)); + v.addElement(PROP_B64+"=" + mConfig.getBoolean(PROP_B64,false)); + v.addElement(PROP_GMT+"=" + mTimeStamp); + v.addElement(PROP_LNK+"=" + mConfig.getBoolean(PROP_LNK,false)); + v.addElement(PROP_EXT+"=" + ext); + v.addElement(PROP_ZIP+"=" + mConfig.getBoolean(PROP_ZIP,false)); + v.addElement(PROP_LEV+"=" + mZipLevel); + } catch (Exception e) { + } + return v; + } + + /** + * Returns the initial default parameters. + */ + public Vector getDefaultParams() { + Vector v = new Vector(); + + v.addElement(PROP_DIR+"="); + v.addElement(PROP_DER+"=true"); + v.addElement(PROP_B64+"=false"); + v.addElement(PROP_GMT+"=LocalTime"); + v.addElement(PROP_LNK+"=false"); + v.addElement(PROP_EXT+"="); + v.addElement(PROP_ZIP+"=false"); + v.addElement(PROP_LEV+"=9"); + return v; + } + + /** + * Initializes this plugin. + */ + public void init(IConfigStore config) { + mConfig = config; + String dir = null; + String ext = null; + + try { + dir = mConfig.getString(PROP_DIR, null); + mDerAttr = mConfig.getBoolean(PROP_DER, true); + mB64Attr = mConfig.getBoolean(PROP_B64, false); + mTimeStamp = mConfig.getString(PROP_GMT, "LocalTime"); + mLatestCRL = mConfig.getBoolean(PROP_LNK, false); + mLinkExt = mConfig.getString(PROP_EXT, null); + mZipCRL = mConfig.getBoolean(PROP_ZIP, false); + mZipLevel = mConfig.getInteger(PROP_LEV, 9); + } catch (EBaseException e) { + } + if (dir == null) { + throw new RuntimeException("No Directory Specified"); + } + + // convert to forward slash + dir = dir.replace('\\', '/'); + config.putString(PROP_DIR, dir); + + File dirCheck = new File(dir); + + if (dirCheck.isDirectory()) { + mDir = dir; + } else { + // maybe it is relative path + String mInstanceRoot = null; + + try { + mInstanceRoot = CMS.getConfigStore().getString("instanceRoot"); + } catch (Exception e) { + throw new RuntimeException("Invalid Instance Dir " + e); + } + dirCheck = new File(mInstanceRoot + + File.separator + dir); + if (dirCheck.isDirectory()) { + mDir = mInstanceRoot + File.separator + dir; + } else { + throw new RuntimeException("Invalid Directory " + dir); + } + } + } + + public IConfigStore getConfigStore() { + return mConfig; + } + + private String[] getCrlNamePrefix(X509CRL crl, boolean useGMT) { + String[] namePrefix = {"crl", "crl"}; + + if (mCrlIssuingPointId != null && mCrlIssuingPointId.length() != 0) { + namePrefix[0] = mCrlIssuingPointId; + namePrefix[1] = mCrlIssuingPointId; + } + java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("yyyyMMdd-HHmmss"); + TimeZone tz = TimeZone.getTimeZone("GMT"); + if (useGMT) format.setTimeZone(tz); + String timeStamp = format.format(crl.getThisUpdate()).toString(); + namePrefix[0] += "-" + timeStamp; + if (((netscape.security.x509.X509CRLImpl)crl).isDeltaCRL()) { + namePrefix[0] += "-delta"; + namePrefix[1] += "-delta"; + } + + return namePrefix; + } + + private void createLink(String linkName, String fileName) { + String cmd = "ln -s " + fileName + " " + linkName + ".new"; + if (com.netscape.cmsutil.util.Utils.exec(cmd)) { + File oldLink = new File(linkName + ".old"); + if (oldLink.exists()) { // remove old link if exists + oldLink.delete(); + } + File link = new File(linkName); + if (link.exists()) { // current link becomes an old link + link.renameTo(new File(linkName + ".old")); + } + File newLink = new File(linkName + ".new"); + if (newLink.exists()) { // new link becomes current link + newLink.renameTo(new File(linkName)); + } + oldLink = new File(linkName + ".old"); + if (oldLink.exists()) { // remove a new old link + oldLink.delete(); + } + } else { + CMS.debug("FileBasedPublisher: createLink: '" + cmd + "' --- failed"); + } + } + + /** + * 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 void publish(LDAPConnection conn, String dn, Object object) + throws ELdapException { + CMS.debug("FileBasedPublisher: publish"); + try { + if (object instanceof X509Certificate) { + X509Certificate cert = (X509Certificate) object; + BigInteger sno = cert.getSerialNumber(); + String name = mDir + + File.separator + "cert-" + + sno.toString(); + if (mDerAttr) + { + String fileName = name + ".der"; + FileOutputStream fos = new FileOutputStream(fileName); + fos.write(cert.getEncoded()); + fos.close(); + } + if (mB64Attr) + { + String fileName = name + ".b64"; + FileOutputStream fos = new FileOutputStream(fileName); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + Base64OutputStream b64 = + new Base64OutputStream(new PrintStream(new FilterOutputStream(output))); + b64.write(cert.getEncoded()); + b64.flush(); + (new PrintStream(fos)).print(output.toString("8859_1")); + fos.close(); + } + } else if (object instanceof X509CRL) { + X509CRL crl = (X509CRL) object; + String[] namePrefix = getCrlNamePrefix(crl, mTimeStamp.equals("GMT")); + String baseName = mDir + File.separator + namePrefix[0]; + String tempFile = baseName + ".temp"; + FileOutputStream fos; + ZipOutputStream zos; + byte [] encodedArray = null; + File destFile = null; + String destName = null; + File renameFile = null; + + if (mDerAttr) { + fos = new FileOutputStream(tempFile); + encodedArray = crl.getEncoded(); + fos.write(encodedArray); + fos.close(); + if (mZipCRL) { + zos = new ZipOutputStream(new FileOutputStream(baseName+".zip")); + zos.setLevel(mZipLevel); + zos.putNextEntry(new ZipEntry(baseName+".der")); + zos.write(encodedArray, 0, encodedArray.length); + zos.closeEntry(); + zos.close(); + } + destName = baseName + ".der"; + destFile = new File(destName); + + if (destFile.exists()) + destFile.delete(); + renameFile = new File(tempFile); + renameFile.renameTo(destFile); + + if (mLatestCRL) { + String linkExt = "."; + if (mLinkExt != null && mLinkExt.length() > 0) { + linkExt += mLinkExt; + } else { + linkExt += "der"; + } + String linkName = mDir + File.separator + namePrefix[1] + linkExt; + createLink(linkName, destName); + if (mZipCRL) { + linkName = mDir + File.separator + namePrefix[1] + ".zip"; + createLink(linkName, baseName+".zip"); + } + } + } + + // output base64 file + if(mB64Attr==true) + { + if (encodedArray ==null) + encodedArray = crl.getEncoded(); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + + fos = new FileOutputStream(tempFile); + fos.write(com.netscape.osutil.OSUtil.BtoA(encodedArray).getBytes()); + fos.close(); + destName = baseName + ".b64"; + destFile = new File(destName); + + if(destFile.exists()) + destFile.delete(); + renameFile = new File(tempFile); + renameFile.renameTo(destFile); + } + } + } catch (IOException e) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_FILE_PUBLISHER_ERROR", e.toString())); + } catch (CertificateEncodingException e) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_FILE_PUBLISHER_ERROR", e.toString())); + } catch (CRLException e) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_FILE_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 { + CMS.debug("FileBasedPublisher: unpublish"); + String name = mDir + File.separator; + String fileName; + + if (object instanceof X509Certificate) { + X509Certificate cert = (X509Certificate) object; + BigInteger sno = cert.getSerialNumber(); + name += "cert-" + sno.toString(); + } else if (object instanceof X509CRL) { + X509CRL crl = (X509CRL) object; + String[] namePrefix = getCrlNamePrefix(crl, mTimeStamp.equals("GMT")); + name += namePrefix[0]; + + fileName = name + ".zip"; + File f = new File(fileName); + f.delete(); + } + fileName = name + ".der"; + File f = new File(fileName); + f.delete(); + + fileName = name + ".b64"; + f = new File(fileName); + f.delete(); + } + /** + * returns the Der attribute where it'll be published. + */ + public boolean getDerAttr() { + return mDerAttr; + } + /** + * returns the B64 attribute where it'll be published. + */ + public boolean getB64Attr() { + return mB64Attr; + } +} diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCaCertPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCaCertPublisher.java new file mode 100644 index 000000000..5b6533e13 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCaCertPublisher.java @@ -0,0 +1,408 @@ +// --- 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 netscape.ldap.*; +import java.security.cert.*; +import java.io.*; +import java.util.*; +import netscape.security.x509.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.ldap.*; +import com.netscape.certsrv.publish.*; + + +/** + * Interface for publishing a CA certificate to + * + * @version $Revision$, $Date$ + */ +public class LdapCaCertPublisher + implements ILdapPublisher, IExtendedPluginInfo { + public static final String LDAP_CACERT_ATTR = "caCertificate;binary"; + public static final String LDAP_CA_OBJECTCLASS = "pkiCA"; + public static final String LDAP_ARL_ATTR = "authorityRevocationList;binary"; + public static final String LDAP_CRL_ATTR = "certificateRevocationList;binary"; + + protected String mCaCertAttr = LDAP_CACERT_ATTR; + protected String mCaObjectclass = LDAP_CA_OBJECTCLASS; + protected String mObjAdded = ""; + protected String mObjDeleted = ""; + + private ILogger mLogger = CMS.getLogger(); + private boolean mInited = false; + protected IConfigStore mConfig = null; + private String mcrlIssuingPointId; + + + /** + * constructor constructs default values. + */ + public LdapCaCertPublisher() { + } + + public String[] getExtendedPluginInfo(Locale locale) { + String s[] = { + "caCertAttr;string;Name of Ldap attribute in which to store certificate", + "caObjectClass;string;The name of the objectclasses which should be " + + "added to this entry, if they do not already exist. This can be " + + "'certificationAuthority' (if using RFC 2256) or 'pkiCA' (if using RFC 4523)", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-ldappublish-publisher-cacertpublisher", + IExtendedPluginInfo.HELP_TEXT + + ";This plugin knows how to publish the CA cert to " + + "'certificateAuthority' and 'pkiCA' -type entries" + }; + + return s; + } + + public String getImplName() { + return "LdapCaCertPublisher"; + } + + public String getDescription() { + return "LdapCaCertPublisher"; + } + + public Vector getInstanceParams() { + Vector v = new Vector(); + + v.addElement("caCertAttr=" + mCaCertAttr); + v.addElement("caObjectClass=" + mCaObjectclass); + return v; + } + + public Vector getDefaultParams() { + Vector v = new Vector(); + + v.addElement("caCertAttr=" + mCaCertAttr); + v.addElement("caObjectClass=" + mCaObjectclass); + return v; + } + + public IConfigStore getConfigStore() { + return mConfig; + } + + public void init(IConfigStore config) + throws EBaseException { + if (mInited) + return; + mConfig = config; + mCaCertAttr = mConfig.getString("caCertAttr", LDAP_CACERT_ATTR); + mCaObjectclass = mConfig.getString("caObjectClass", + LDAP_CA_OBJECTCLASS); + mObjAdded = mConfig.getString("caObjectClassAdded", ""); + mObjDeleted = mConfig.getString("caObjectClassDeleted", ""); + mInited = true; + } + + // don't think anyone would ever use this but just in case. + public LdapCaCertPublisher(String caCertAttr, String caObjectclass) { + mCaCertAttr = caCertAttr; + mCaObjectclass = caObjectclass; + mInited = true; + } + + /** + * Gets the CA object class to convert to. + */ + public String getCAObjectclass() { + return mCaObjectclass; + } + + /** + * returns the ca cert attribute where it'll be published. + */ + public String getCaCertAttrName() { + return mCaCertAttr; + } + + /** + * publish a CA certificate + * Adds the cert to the multi-valued certificate attribute as a + * DER encoded binary blob. Does not check if cert already exists. + * Converts the class to certificateAuthority. + * @param conn the LDAP connection + * @param dn dn of the entry to publish the certificate + * @param certObj the certificate object. + */ + public void publish(LDAPConnection conn, String dn, Object certObj) + throws ELdapException { + if (conn == null) { + log(ILogger.LL_INFO, "LdapCaCertPublisher: no LDAP connection"); + return; + } + + try { + mCaCertAttr = mConfig.getString("caCertAttr", LDAP_CACERT_ATTR); + mCaObjectclass = mConfig.getString("caObjectClass", LDAP_CA_OBJECTCLASS); + } catch (EBaseException e) { + } + + // Bugscape #56124 - support multiple publishing directory + // see if we should create local connection + LDAPConnection altConn = null; + try { + String host = mConfig.getString("host", null); + String port = mConfig.getString("port", null); + if (host != null && port != null) { + int portVal = Integer.parseInt(port); + int version = Integer.parseInt(mConfig.getString("version", "2")); + String cert_nick = mConfig.getString("clientCertNickname", null); + LDAPSSLSocketFactoryExt sslSocket = null; + if (cert_nick != null) { + sslSocket = CMS.getLdapJssSSLSocketFactory(cert_nick); + } + String mgr_dn = mConfig.getString("bindDN", null); + String mgr_pwd = mConfig.getString("bindPWD", null); + + altConn = CMS.getBoundConnection(host, portVal, + version, + sslSocket, mgr_dn, mgr_pwd); + conn = altConn; + } + } catch (LDAPException e) { + CMS.debug("Failed to create alt connection " + e); + } catch (EBaseException e) { + CMS.debug("Failed to create alt connection " + e); + } + + + if (!(certObj instanceof X509Certificate)) + throw new IllegalArgumentException("Illegal arg to publish"); + + X509Certificate cert = (X509Certificate) certObj; + + try { + byte[] certEnc = cert.getEncoded(); + + /* search for attribute names to determine existence of attributes */ + LDAPSearchResults res = + conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)", + new String[] { LDAP_CRL_ATTR, LDAP_ARL_ATTR }, true); + LDAPEntry entry = res.next(); + LDAPAttribute arls = entry.getAttribute(LDAP_ARL_ATTR); + LDAPAttribute crls = entry.getAttribute(LDAP_CRL_ATTR); + + /* search for objectclass and caCert values */ + LDAPSearchResults res1 = + conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)", + new String[] { "objectclass", mCaCertAttr }, false); + LDAPEntry entry1 = res1.next(); + LDAPAttribute ocs = entry1.getAttribute("objectclass"); + LDAPAttribute certs = entry1.getAttribute(mCaCertAttr); + + boolean hasCert = + LdapUserCertPublisher.ByteValueExists(certs, certEnc); + + LDAPModificationSet modSet = new LDAPModificationSet(); + + if (hasCert) { + log(ILogger.LL_INFO, "publish: CA " + dn + " already has Cert"); + } else { + /* + fix for 360458 - if no cert, use add, if has cert but + not equal, use replace + */ + if (certs == null) { + modSet.add(LDAPModification.ADD, + new LDAPAttribute(mCaCertAttr, certEnc)); + log(ILogger.LL_INFO, "CA cert added"); + } else { + modSet.add(LDAPModification.REPLACE, + new LDAPAttribute(mCaCertAttr, certEnc)); + log(ILogger.LL_INFO, "CA cert replaced"); + } + } + + String[] oclist = mCaObjectclass.split(","); + + boolean attrsAdded = false; + for (int i=0; i < oclist.length; i++) { + String oc = oclist[i].trim(); + boolean hasoc = LdapUserCertPublisher.StringValueExists(ocs, oc); + if (!hasoc) { + log(ILogger.LL_INFO, "adding CA objectclass " + oc + " to " + dn); + modSet.add(LDAPModification.ADD, + new LDAPAttribute("objectclass", oc)); + + if ((!attrsAdded) && oc.equalsIgnoreCase("certificationAuthority")) { + // add MUST attributes + if (arls == null) + modSet.add(LDAPModification.ADD, + new LDAPAttribute(LDAP_ARL_ATTR, "")); + if (crls == null) + modSet.add(LDAPModification.ADD, + new LDAPAttribute(LDAP_CRL_ATTR, "")); + attrsAdded = true; + } + } + } + + // delete objectclasses that have been deleted from config + String[] delList = mObjDeleted.split(","); + if (delList.length > 0) { + for (int i=0; i< delList.length; i++) { + String deloc = delList[i].trim(); + boolean hasoc = LdapUserCertPublisher.StringValueExists(ocs, deloc); + boolean match = false; + for (int j=0; j< oclist.length; j++) { + if ((oclist[j].trim()).equals(deloc)) { + match = true; + break; + } + } + if (!match && hasoc) { + log(ILogger.LL_INFO, "deleting CA objectclass " + deloc + " from " + dn); + modSet.add(LDAPModification.DELETE, + new LDAPAttribute("objectclass", deloc)); + } + } + } + + // reset mObjAdded and mObjDeleted, if needed + if ((!mObjAdded.equals("")) || (!mObjDeleted.equals(""))) { + mObjAdded = ""; + mObjDeleted = ""; + mConfig.putString("caObjectClassAdded", ""); + mConfig.putString("caObjectClassDeleted", ""); + try { + mConfig.commit(false); + } catch (Exception e) { + log(ILogger.LL_INFO, "Failure in updating mObjAdded and mObjDeleted"); + } + } + + if (modSet.size() > 0) conn.modify(dn, modSet); + } catch (CertificateEncodingException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_CANT_DECODE_CERT", dn)); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString())); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) { + // need to intercept this because message from LDAP is + // "DSA is unavailable" which confuses with DSA PKI. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER")); + throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort())); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISHER_EXCEPTION", "", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_CACERT_ERROR", e.toString())); + } + } finally { + if (altConn != null) { + try { + altConn.disconnect(); + } catch (LDAPException e) { + // safely ignored + } + } + } + + return; + } + + /** + * deletes the certificate from CA's certificate attribute. + * if it's the last cert will also remove the certificateAuthority + * objectclass. + */ + public void unpublish(LDAPConnection conn, String dn, Object certObj) + throws ELdapException { + if (!(certObj instanceof X509Certificate)) + throw new IllegalArgumentException("Illegal arg to publish"); + + X509Certificate cert = (X509Certificate) certObj; + + try { + mCaCertAttr = mConfig.getString("caCertAttr", LDAP_CACERT_ATTR); + mCaObjectclass = mConfig.getString("caObjectClass", LDAP_CA_OBJECTCLASS); + } catch (EBaseException e) { + } + + try { + byte[] certEnc = cert.getEncoded(); + + LDAPSearchResults res = + conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)", + new String[] { mCaCertAttr, "objectclass" }, false); + + LDAPEntry entry = res.next(); + LDAPAttribute certs = entry.getAttribute(mCaCertAttr); + LDAPAttribute ocs = entry.getAttribute("objectclass"); + + boolean hasCert = + LdapUserCertPublisher.ByteValueExists(certs, certEnc); + + if (!hasCert) { + log(ILogger.LL_INFO, "unpublish: " + dn + " has not cert already"); + //throw new ELdapException( + // LdapResources.ALREADY_UNPUBLISHED_1, dn); + return; + } + + LDAPModificationSet modSet = new LDAPModificationSet(); + + modSet.add(LDAPModification.DELETE, + new LDAPAttribute(mCaCertAttr, certEnc)); + if (certs.size() == 1) { + // if last ca cert, remove oc also. + + String[] oclist = mCaObjectclass.split(","); + for (int i =0 ; i < oclist.length; i++) { + String oc = oclist[i].trim(); + boolean hasOC = LdapUserCertPublisher.StringValueExists(ocs, oc); + if (hasOC) { + log(ILogger.LL_INFO, "unpublish: deleting CA oc" + oc + " from " + dn); + modSet.add(LDAPModification.DELETE, + new LDAPAttribute("objectclass", oc)); + } + } + } + conn.modify(dn, modSet); + } catch (CertificateEncodingException e) { + CMS.debug("LdapCaCertPublisher: unpublish: Cannot decode cert for " + dn); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString())); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) { + // need to intercept this because message from LDAP is + // "DSA is unavailable" which confuses with DSA PKI. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER")); + throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort())); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_UNPUBLISH_CACERT_ERROR", e.toString())); + } + } + return; + } + + /** + * handy routine for logging in this class. + */ + private void log(int level, String msg) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level, + "LdapCaPublisher: " + msg); + } + +} diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCertSubjPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCertSubjPublisher.java new file mode 100644 index 000000000..654a93150 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCertSubjPublisher.java @@ -0,0 +1,332 @@ +// --- 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.*; +import java.util.*; +import netscape.ldap.*; +import java.security.cert.*; +import netscape.security.x509.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.ldap.*; +import com.netscape.certsrv.publish.*; + + +/** + * Interface for mapping a X509 certificate to a LDAP entry + * Publishes a certificate as binary and its subject name. + * there is one subject name value for each certificate. + * + * @version $Revision$, $Date$ + */ +public class LdapCertSubjPublisher implements ILdapPublisher { + public static final String LDAP_CERTSUBJNAME_ATTR = "certSubjectName"; + protected String mCertAttr = LdapUserCertPublisher.LDAP_USERCERT_ATTR; + protected String mSubjNameAttr = LDAP_CERTSUBJNAME_ATTR; + + private ILogger mLogger = CMS.getLogger(); + private boolean mInited = false; + protected IConfigStore mConfig = null; + + /** + * constructor using default certificate subject name and attribute for + * publishing subject name. + */ + public LdapCertSubjPublisher() { + } + + public String getImplName() { + return "LdapCertSubjPublisher"; + } + + public String getDescription() { + return "LdapCertSubjPublisher"; + } + + public Vector getInstanceParams() { + Vector v = new Vector(); + + v.addElement("certAttr=" + mCertAttr); + v.addElement("subjectNameAttr=" + mSubjNameAttr); + return v; + } + + public Vector getDefaultParams() { + Vector v = new Vector(); + + v.addElement("certAttr=" + mCertAttr); + v.addElement("subjectNameAttr=" + mSubjNameAttr); + return v; + } + + public IConfigStore getConfigStore() { + return mConfig; + } + + public void init(IConfigStore config) + throws EBaseException { + if (mInited) + return; + mConfig = config; + mCertAttr = mConfig.getString("certAttr", + LdapUserCertPublisher.LDAP_USERCERT_ATTR); + mSubjNameAttr = mConfig.getString("certSubjectName", + LDAP_CERTSUBJNAME_ATTR); + mInited = true; + } + + /** + * constrcutor using specified certificate attribute and + * certificate subject name attribute. + */ + public LdapCertSubjPublisher(String certAttr, String subjNameAttr) { + mCertAttr = certAttr; + mSubjNameAttr = subjNameAttr; + } + + public String getCertAttr() { + return mCertAttr; + } + + public String getSubjNameAttr() { + return mSubjNameAttr; + } + + public void setSubjNameAttr(String subjNameAttr) { + mSubjNameAttr = subjNameAttr; + } + + public void setCertAttr(String certAttr) { + mCertAttr = certAttr; + } + + /** + * publish a user certificate + * Adds the cert to the multi-valued certificate attribute as a + * DER encoded binary blob. Does not check if cert already exists. + * Then adds the subject name of the cert to the subject name attribute. + * @param conn the LDAP connection + * @param dn dn of the entry to publish the certificate + * @param certObj the certificate object. + * @exception ELdapException if cert or subject name already exists, + * if cert encoding fails, if getting cert subject name fails. + * Use ELdapException.getException() to find underlying exception. + */ + public void publish(LDAPConnection conn, String dn, Object certObj) + throws ELdapException { + if (conn == null) { + log(ILogger.LL_INFO, "LdapCertSubjPublisher: no LDAP connection"); + return; + } + + if (!(certObj instanceof X509Certificate)) + throw new IllegalArgumentException("Illegal arg to publish"); + + X509Certificate cert = (X509Certificate) certObj; + + try { + boolean hasCert = false, hasSubjname = false; + byte[] certEnc = cert.getEncoded(); + String subjName = ((X500Name) cert.getSubjectDN()).toLdapDNString(); + + LDAPSearchResults res = + conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)", + new String[] { mCertAttr, mSubjNameAttr }, false); + + LDAPEntry entry = res.next(); + LDAPAttribute certs = entry.getAttribute(mCertAttr); + LDAPAttribute subjnames = entry.getAttribute(mSubjNameAttr); + + // check if has cert already. + if (certs != null) { + hasCert = LdapUserCertPublisher.ByteValueExists(certs, certEnc); + } + + // check if has subject name already. + if (subjnames != null) { + hasSubjname = + LdapUserCertPublisher.StringValueExists(subjnames, subjName); + } + + // if has both, done. + if (hasCert && hasSubjname) { + log(ILogger.LL_INFO, + "publish: " + subjName + " already has cert & subject name"); + return; + } + + // add cert if not already there. + LDAPModificationSet modSet = new LDAPModificationSet(); + + if (!hasCert) { + log(ILogger.LL_INFO, "publish: adding cert to " + subjName); + modSet.add(LDAPModification.ADD, + new LDAPAttribute(mCertAttr, certEnc)); + } + // add subject name if not already there. + if (!hasSubjname) { + log(ILogger.LL_INFO, "publish: adding " + subjName + " to " + dn); + modSet.add(LDAPModification.ADD, + new LDAPAttribute(mSubjNameAttr, subjName)); + } + conn.modify(dn, modSet); + } catch (CertificateEncodingException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISH_ERROR", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString())); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) { + // need to intercept this because message from LDAP is + // "DSA is unavailable" which confuses with DSA PKI. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER")); + throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort())); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISHER_EXCEPTION", "", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_USERCERT_ERROR", e.toString())); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISH_ERROR", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_USERCERT_ERROR", e.toString())); + } + } + + /** + * deletes the certificate from the list of certificates. + * does not check if certificate is already there. + * also takes out the subject name if no other certificate remain + * with the same subject name. + */ + public void unpublish(LDAPConnection conn, String dn, Object certObj) + throws ELdapException { + if (!(certObj instanceof X509Certificate)) + throw new IllegalArgumentException("Illegal arg to publish"); + + try { + boolean hasCert = false, hasSubjname = false; + boolean hasAnotherCert = false; + X509Certificate cert = (X509Certificate) certObj; + String subjName = ((X500Name) cert.getSubjectDN()).toLdapDNString(); + + byte[] certEnc = cert.getEncoded(); + + LDAPSearchResults res = + conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)", + new String[] { mCertAttr, mSubjNameAttr }, false); + + LDAPEntry entry = res.next(); + LDAPAttribute certs = entry.getAttribute(mCertAttr); + LDAPAttribute subjnames = entry.getAttribute(mSubjNameAttr); + + // check for cert and other certs with same subject name. + if (certs != null) { + hasCert = LdapUserCertPublisher.ByteValueExists(certs, certEnc); + // check for other certs with the same subject name + Enumeration vals = certs.getByteValues(); + byte[] val = null; + + while (vals.hasMoreElements()) { + val = (byte[]) vals.nextElement(); + if (Utils.byteArraysAreEqual(certEnc, val)) { + hasCert = true; + continue; + } + try { + X509CertImpl certval = new X509CertImpl(val); + // XXX use some sort of X500name equals function here. + String subjnam = + ((X500Name) certval.getSubjectDN()).toLdapDNString(); + + if (subjnam.equalsIgnoreCase(subjName)) { + hasAnotherCert = true; + } + } catch (CertificateEncodingException e) { + // ignore this certificate. + CMS.debug( + "LdapCertSubjPublisher: unpublish: an invalid cert in dn entry encountered"); + } catch (CertificateException e) { + // ignore this certificate. + CMS.debug( + "LdapCertSubjPublisher: unpublish: an invalid cert in dn entry encountered"); + } + } + } + + // check if doesn't have subject name already. + if (subjnames != null) { + hasSubjname = + LdapUserCertPublisher.StringValueExists(subjnames, subjName); + } + + // if doesn't have both, done. + if (!hasCert && !hasSubjname) { + log(ILogger.LL_INFO, + "unpublish: " + subjName + " already has not cert & subjname"); + return; + } + + // delete cert if there. + LDAPModificationSet modSet = new LDAPModificationSet(); + + if (hasCert) { + log(ILogger.LL_INFO, + "unpublish: deleting cert " + subjName + " from " + dn); + modSet.add(LDAPModification.DELETE, + new LDAPAttribute(mCertAttr, certEnc)); + } + // delete subject name if no other cert has the same name. + if (hasSubjname && !hasAnotherCert) { + log(ILogger.LL_INFO, + "unpublish: deleting subject name " + subjName + " from " + dn); + modSet.add(LDAPModification.DELETE, + new LDAPAttribute(mSubjNameAttr, subjName)); + } + conn.modify(dn, modSet); + } catch (CertificateEncodingException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString())); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString())); + throw new ELdapException( + CMS.getUserMessage("CMS_LDAP_DECODING_CERT_FAILED", e.toString())); + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_LDAP_DN_STRING_FAILED", e.toString())); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) { + // need to intercept this because message from LDAP is + // "DSA is unavailable" which confuses with DSA PKI. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER")); + throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort())); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_UNPUBLISH_USERCERT_ERROR", e.toString())); + } + } + return; + } + + private void log(int level, String msg) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level, + "LdapCertSubjPublisher: " + msg); + } + +} diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCertificatePairPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCertificatePairPublisher.java new file mode 100644 index 000000000..ca8a07ef4 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCertificatePairPublisher.java @@ -0,0 +1,306 @@ +// --- 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 netscape.ldap.*; +import java.security.cert.*; +import java.io.*; +import java.util.*; +import netscape.security.x509.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.ldap.*; +import com.netscape.certsrv.publish.*; + + +/** + * module for publishing a cross certificate pair to ldap + * crossCertificatePair attribute + * + * @version $Revision$, $Date$ + */ +public class LdapCertificatePairPublisher + implements ILdapPublisher, IExtendedPluginInfo { + public static final String LDAP_CROSS_CERT_PAIR_ATTR = "crossCertificatePair;binary"; + public static final String LDAP_CA_OBJECTCLASS = "pkiCA"; + public static final String LDAP_ARL_ATTR = "authorityRevocationList;binary"; + public static final String LDAP_CRL_ATTR = "certificateRevocationList;binary"; + public static final String LDAP_CACERT_ATTR = "caCertificate;binary"; + + protected String mCrossCertPairAttr = LDAP_CROSS_CERT_PAIR_ATTR; + protected String mCaObjectclass = LDAP_CA_OBJECTCLASS; + protected String mObjAdded = ""; + protected String mObjDeleted = ""; + + private ILogger mLogger = CMS.getLogger(); + private boolean mInited = false; + protected IConfigStore mConfig = null; + + /** + * constructor constructs default values. + */ + public LdapCertificatePairPublisher() { + } + + public String[] getExtendedPluginInfo(Locale locale) { + String s[] = { + "crossCertPairAttr;string;Name of Ldap attribute in which to store cross certificates", + "caObjectClass;string;The name of the objectclasses which should be " + + "added to this entry, if they do not already exist. This can be " + + "'certificationAuthority' (if using RFC 2256) or 'pkiCA' (if using RFC 4523)", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-ldappublish-publisher-crosscertpairpublisher", + IExtendedPluginInfo.HELP_TEXT + + ";This plugin knows how to publish the CA cert to " + + "'certificateAuthority' and 'pkiCA' -type entries" + }; + + return s; + } + + public String getImplName() { + return "LdapCertificatePairPublisher"; + } + + public String getDescription() { + return "LdapCertificatePairPublisher"; + } + + public Vector getInstanceParams() { + Vector v = new Vector(); + + v.addElement("crossCertPairAttr=" + mCrossCertPairAttr); + v.addElement("caObjectClass=" + mCaObjectclass); + return v; + } + + public Vector getInstanceParamsWithExtras() { + return getInstanceParams(); + } + + public Vector getDefaultParams() { + Vector v = new Vector(); + + v.addElement("crossCertPairAttr=" + mCrossCertPairAttr); + v.addElement("caObjectClass=" + mCaObjectclass); + return v; + } + + public IConfigStore getConfigStore() { + return mConfig; + } + + public void init(IConfigStore config) + throws EBaseException { + if (mInited) + return; + mConfig = config; + mCrossCertPairAttr = mConfig.getString("crossCertPairAttr", LDAP_CROSS_CERT_PAIR_ATTR); + mCaObjectclass = mConfig.getString("caObjectClass", + LDAP_CA_OBJECTCLASS); + mObjAdded = mConfig.getString("caObjectClassAdded", ""); + mObjDeleted = mConfig.getString("caObjectClassDeleted", ""); + + mInited = true; + } + + // don't think anyone would ever use this but just in case. + public LdapCertificatePairPublisher(String crossCertPairAttr, String caObjectclass) { + mCrossCertPairAttr = crossCertPairAttr; + mCaObjectclass = caObjectclass; + mInited = true; + } + + /** + * Gets the Certificate Authority object class to convert to. + */ + public String getCAObjectclass() { + return mCaObjectclass; + } + + /** + * returns the cross cert pair attribute where it'll be published. + */ + public String getXCertAttrName() { + return mCrossCertPairAttr; + } + + /** + * publish a certificatePair + * -should not be called from listeners. + * @param conn the LDAP connection + * @param dn dn of the entry to publish the XcertificatePair + * @param pair the Xcertificate bytes object. + */ + public synchronized void publish(LDAPConnection conn, String dn, Object pair) + throws ELdapException { + publish(conn, dn, (byte[]) pair); + } + + /** + * publish a certificatePair + * -should not be called from listeners. + * @param conn the LDAP connection + * @param dn dn of the entry to publish the XcertificatePair + * @param pair the cross cert bytes + */ + public synchronized void publish(LDAPConnection conn, String dn, + byte[] pair) + throws ELdapException { + + if (conn == null) { + log(ILogger.LL_INFO, "LdapCertificatePairPublisher: no LDAP connection"); + return; + } + + try { + mCrossCertPairAttr = mConfig.getString("crossCertPairAttr", LDAP_CROSS_CERT_PAIR_ATTR); + mCaObjectclass = mConfig.getString("caObjectClass", LDAP_CA_OBJECTCLASS); + } catch (EBaseException e) { + } + + try { + // search for attributes to determine if they exist + LDAPSearchResults res = + conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)", + new String[] { LDAP_CACERT_ATTR, LDAP_CRL_ATTR, LDAP_ARL_ATTR }, true); + LDAPEntry entry = res.next(); + LDAPAttribute certs = entry.getAttribute(LDAP_CACERT_ATTR); + LDAPAttribute arls = entry.getAttribute(LDAP_ARL_ATTR); + LDAPAttribute crls = entry.getAttribute(LDAP_CRL_ATTR); + + // search for objectclass and crosscertpair attributes and values + LDAPSearchResults res1 = + conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)", + new String[] { "objectclass", mCrossCertPairAttr }, false); + LDAPEntry entry1 = res1.next(); + LDAPAttribute ocs = entry1.getAttribute("objectclass"); + LDAPAttribute certPairs = entry1.getAttribute("crosscertificatepair;binary"); + + LDAPModificationSet modSet = new LDAPModificationSet(); + + boolean hasCert = LdapUserCertPublisher.ByteValueExists(certPairs, pair); + if (LdapUserCertPublisher.ByteValueExists(certPairs, pair)) { + CMS.debug("LdapCertificatePairPublisher: cross cert pair bytes exist in publishing directory, do not publish again."); + return; + } + if (hasCert) { + log(ILogger.LL_INFO, "publish: CA " + dn + " already has cross cert pair bytes"); + } else { + modSet.add(LDAPModification.ADD, + new LDAPAttribute(mCrossCertPairAttr, pair)); + log(ILogger.LL_INFO, "cross cert pair published with dn=" + dn); + } + + String[] oclist = mCaObjectclass.split(","); + + boolean attrsAdded = false; + for (int i=0; i < oclist.length; i++) { + String oc = oclist[i].trim(); + boolean hasoc = LdapUserCertPublisher.StringValueExists(ocs, oc); + if (!hasoc) { + log(ILogger.LL_INFO, "adding CA objectclass " + oc + " to " + dn); + modSet.add(LDAPModification.ADD, + new LDAPAttribute("objectclass", oc)); + + if ((!attrsAdded) && oc.equalsIgnoreCase("certificationAuthority")) { + // add MUST attributes + if (arls == null) + modSet.add(LDAPModification.ADD, + new LDAPAttribute(LDAP_ARL_ATTR, "")); + if (crls == null) + modSet.add(LDAPModification.ADD, + new LDAPAttribute(LDAP_CRL_ATTR, "")); + if (certs == null) + modSet.add(LDAPModification.ADD, + new LDAPAttribute(LDAP_CACERT_ATTR, "")); + attrsAdded = true; + } + } + } + + // delete objectclasses that have been deleted from config + String[] delList = mObjDeleted.split(","); + if (delList.length > 0) { + for (int i=0; i< delList.length; i++) { + String deloc = delList[i].trim(); + boolean hasoc = LdapUserCertPublisher.StringValueExists(ocs, deloc); + boolean match = false; + for (int j=0; j< oclist.length; j++) { + if ((oclist[j].trim()).equals(deloc)) { + match = true; + break; + } + } + if (!match && hasoc) { + log(ILogger.LL_INFO, "deleting CRL objectclass " + deloc + " from " + dn); + modSet.add(LDAPModification.DELETE, + new LDAPAttribute("objectclass", deloc)); + } + } + } + + // reset mObjAdded and mObjDeleted, if needed + if ((!mObjAdded.equals("")) || (!mObjDeleted.equals(""))) { + mObjAdded = ""; + mObjDeleted = ""; + mConfig.putString("caObjectClassAdded", ""); + mConfig.putString("caObjectClassDeleted", ""); + try { + mConfig.commit(false); + } catch (Exception e) { + log(ILogger.LL_INFO, "Failure in updating mObjAdded and mObjDeleted"); + } + } + + if (modSet.size() > 0) conn.modify(dn, modSet); + CMS.debug("LdapCertificatePairPublisher: in publish() just published"); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) { + // need to intercept this because message from LDAP is + // "DSA is unavailable" which confuses with DSA PKI. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER")); + throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort())); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISHER_EXCEPTION", "", e.toString())); + throw new ELdapException("error publishing cross cert pair:" + e.toString()); + } + } + return; + } + + /** + * unsupported + */ + public void unpublish(LDAPConnection conn, String dn, Object certObj) + throws ELdapException { + CMS.debug("LdapCertificatePairPublisher: unpublish() is unsupported in this revision"); + } + + /** + * handy routine for logging in this class. + */ + private void log(int level, String msg) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level, + "LdapCertificatePairPublisher: " + msg); + } + +} diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCrlPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCrlPublisher.java new file mode 100644 index 000000000..074d21ee0 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCrlPublisher.java @@ -0,0 +1,367 @@ +// --- 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.*; +import java.util.*; +import java.security.cert.*; +import netscape.ldap.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.apps.*; + +import com.netscape.certsrv.ldap.*; +import com.netscape.certsrv.publish.*; + + +/** + * For publishing master or global CRL. + * Publishes (replaces) the CRL in the CA's LDAP entry. + * + * @version $Revision$, $Date$ + */ +public class LdapCrlPublisher implements ILdapPublisher, IExtendedPluginInfo { + private ILogger mLogger = CMS.getLogger(); + protected IConfigStore mConfig = null; + boolean mInited = false; + + public static final String LDAP_CACERT_ATTR = "caCertificate;binary"; + public static final String LDAP_ARL_ATTR = "authorityRevocationList;binary"; + public static final String LDAP_CRL_ATTR = "certificateRevocationList;binary"; + public static final String LDAP_CRL_OBJECTCLASS = "pkiCA,deltaCRL"; + + protected String mCrlAttr = LDAP_CRL_ATTR; + protected String mCrlObjectClass = LDAP_CRL_OBJECTCLASS; + protected String mObjAdded = ""; + protected String mObjDeleted = ""; + + /** + * constructs ldap crl publisher with default values + */ + public LdapCrlPublisher() { + } + + public String getImplName() { + return "LdapCrlPublisher"; + } + + public String getDescription() { + return "LdapCrlPublisher"; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + "crlAttr;string;Name of Ldap attribute in which to store the CRL", + "crlObjectClass;string;The name of the objectclasses which should be " + + "added to this entry, if they do not already exist. This can be a comma-" + + "separated list such as 'certificationAuthority,certificationAuthority-V2' " + + "(if using RFC 2256) or 'pkiCA, deltaCRL' (if using RFC 4523)", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-ldappublish-publisher-crlpublisher", + IExtendedPluginInfo.HELP_TEXT + + ";This plugin knows how to publish CRL's to " + + "'certificateAuthority' and 'pkiCA' -type entries" + }; + + return params; + } + + public Vector getInstanceParams() { + Vector v = new Vector(); + + v.addElement("crlAttr=" + mCrlAttr); + v.addElement("crlObjectClass=" + mCrlObjectClass); + return v; + } + + public Vector getDefaultParams() { + Vector v = new Vector(); + + v.addElement("crlAttr=" + mCrlAttr); + v.addElement("crlObjectClass=" + mCrlObjectClass); + return v; + } + + public IConfigStore getConfigStore() { + return mConfig; + } + + public void init(IConfigStore config) + throws EBaseException { + if (mInited) + return; + mConfig = config; + mCrlAttr = mConfig.getString("crlAttr", LDAP_CRL_ATTR); + mCrlObjectClass = mConfig.getString("crlObjectClass", + LDAP_CRL_OBJECTCLASS); + mObjAdded = mConfig.getString("crlObjectClassAdded", ""); + mObjDeleted = mConfig.getString("crlObjectClassDeleted", ""); + + mInited = true; + } + + public LdapCrlPublisher(String crlAttr, String crlObjectClass) { + mCrlAttr = crlAttr; + mCrlObjectClass = crlObjectClass; + } + + /** + * Gets the CA object class to convert to. + */ + public String getCRLObjectclass() { + return mCrlObjectClass; + } + + /** + * Replaces the CRL in the certificateRevocationList attribute. + * CRL's are published as a DER encoded blob. + */ + public void publish(LDAPConnection conn, String dn, Object crlObj) + throws ELdapException { + if (conn == null) { + log(ILogger.LL_INFO, "publish CRL: no LDAP connection"); + return; + } + + try { + mCrlAttr = mConfig.getString("crlAttr", LDAP_CRL_ATTR); + mCrlObjectClass = mConfig.getString("crlObjectClass", LDAP_CRL_OBJECTCLASS); + } catch (EBaseException e) { + } + + // Bugscape #56124 - support multiple publishing directory + // see if we should create local connection + LDAPConnection altConn = null; + try { + String host = mConfig.getString("host", null); + String port = mConfig.getString("port", null); + if (host != null && port != null) { + int portVal = Integer.parseInt(port); + int version = Integer.parseInt(mConfig.getString("version", "2")); + String cert_nick = mConfig.getString("clientCertNickname", null); + LDAPSSLSocketFactoryExt sslSocket = null; + if (cert_nick != null) { + sslSocket = CMS.getLdapJssSSLSocketFactory(cert_nick); + } + String mgr_dn = mConfig.getString("bindDN", null); + String mgr_pwd = mConfig.getString("bindPWD", null); + + altConn = CMS.getBoundConnection(host, portVal, + version, + sslSocket, mgr_dn, mgr_pwd); + conn = altConn; + } + } catch (LDAPException e) { + CMS.debug("Failed to create alt connection " + e); + } catch (EBaseException e) { + CMS.debug("Failed to create alt connection " + e); + } + + try { + byte[] crlEnc = ((X509CRL) crlObj).getEncoded(); + log(ILogger.LL_INFO, "publish CRL: " + dn); + + /* search for attribute names to determine existence of attributes */ + LDAPSearchResults res = null; + if (mCrlAttr.equals(LDAP_CRL_ATTR)) { + res = conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)", + new String[] { LDAP_CACERT_ATTR, LDAP_ARL_ATTR }, true); + } else { + res = conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)", + new String[] { LDAP_CRL_ATTR, LDAP_CACERT_ATTR, LDAP_ARL_ATTR }, true); + } + + LDAPEntry entry = res.next(); + LDAPAttribute crls = entry.getAttribute(LDAP_CRL_ATTR); + LDAPAttribute certs = entry.getAttribute(LDAP_CACERT_ATTR); + LDAPAttribute arls = entry.getAttribute(LDAP_ARL_ATTR); + + /* get object class values */ + LDAPSearchResults res1 = null; + res1 = conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)", + new String[] { "objectclass" }, false); + LDAPEntry entry1 = res1.next(); + LDAPAttribute ocs = entry1.getAttribute("objectclass"); + + LDAPModificationSet modSet = new LDAPModificationSet(); + + String[] oclist = mCrlObjectClass.split(","); + boolean attrsAdded = false; + for (int i=0; i < oclist.length; i++) { + String oc = oclist[i].trim(); + boolean hasoc = LdapUserCertPublisher.StringValueExists(ocs, oc); + if (!hasoc) { + log(ILogger.LL_INFO, "adding CRL objectclass " + oc + " to " + dn); + modSet.add(LDAPModification.ADD, + new LDAPAttribute("objectclass", oc)); + + if ((!attrsAdded) && oc.equalsIgnoreCase("certificationAuthority")) { + // add MUST attributes + if (arls == null) + modSet.add(LDAPModification.ADD, + new LDAPAttribute(LDAP_ARL_ATTR, "")); + if (certs == null) + modSet.add(LDAPModification.ADD, + new LDAPAttribute(LDAP_CACERT_ATTR, "")); + + if ((crls == null) && (!mCrlAttr.equals(LDAP_CRL_ATTR))) + modSet.add(LDAPModification.ADD, + new LDAPAttribute(LDAP_CRL_ATTR, "")); + attrsAdded = true; + } + } + } + + modSet.add(LDAPModification.REPLACE, new LDAPAttribute(mCrlAttr, crlEnc)); + + // delete objectclasses that have been deleted from config + String[] delList = mObjDeleted.split(","); + if (delList.length > 0) { + for (int i=0; i< delList.length; i++) { + String deloc = delList[i].trim(); + boolean hasoc = LdapUserCertPublisher.StringValueExists(ocs, deloc); + boolean match = false; + for (int j=0; j< oclist.length; j++) { + if ((oclist[j].trim()).equals(deloc)) { + match = true; + break; + } + } + if (!match && hasoc) { + log(ILogger.LL_INFO, "deleting CRL objectclass " + deloc + " from " + dn); + modSet.add(LDAPModification.DELETE, + new LDAPAttribute("objectclass", deloc)); + } + } + } + + // reset mObjAdded and mObjDeleted, if needed + if ((!mObjAdded.equals("")) || (!mObjDeleted.equals(""))) { + mObjAdded = ""; + mObjDeleted = ""; + mConfig.putString("crlObjectClassAdded", ""); + mConfig.putString("crlObjectClassDeleted", ""); + try { + mConfig.commit(false); + } catch (Exception e) { + log(ILogger.LL_INFO, "Failure in updating mObjAdded and mObjDeleted"); + } + } + + conn.modify(dn, modSet); + } catch (CRLException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISH_ERROR", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_CRL_ERROR", e.toString())); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) { + // need to intercept this because message from LDAP is + // "DSA is unavailable" which confuses with DSA PKI. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER")); + throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort())); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISH_ERROR", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_CRL_ERROR", e.toString())); + } + } finally { + if (altConn != null) { + try { + altConn.disconnect(); + } catch (LDAPException e) { + // safely ignored + } + } + } + + } + + /** + * There shouldn't be a need to call this. + * CRLs are always replaced but this is implemented anyway in case + * there is ever a reason to remove a global CRL. + */ + public void unpublish(LDAPConnection conn, String dn, Object crlObj) + throws ELdapException { + try { + byte[] crlEnc = ((X509CRL) crlObj).getEncoded(); + + try { + mCrlAttr = mConfig.getString("crlAttr", LDAP_CRL_ATTR); + mCrlObjectClass = mConfig.getString("crlObjectClass", LDAP_CRL_OBJECTCLASS); + } catch (EBaseException e) { + } + + + LDAPSearchResults res = conn.search(dn, LDAPv2.SCOPE_BASE, + "(objectclass=*)", new String[] { mCrlAttr, "objectclass" }, false); + LDAPEntry e = res.next(); + LDAPAttribute crls = e.getAttribute(mCrlAttr); + LDAPAttribute ocs = e.getAttribute("objectclass"); + + LDAPModificationSet modSet = new LDAPModificationSet(); + + boolean hasOC = false; + boolean hasCRL = + LdapUserCertPublisher.ByteValueExists(crls, crlEnc); + + if (hasCRL) { + modSet.add(LDAPModification.DELETE, + new LDAPAttribute(mCrlAttr, crlEnc)); + } + + String[] oclist = mCrlObjectClass.split(","); + for (int i=0; i < oclist.length; i++) { + String oc = oclist[i].trim(); + if (LdapUserCertPublisher.StringValueExists(ocs, oc)) { + log(ILogger.LL_INFO, "unpublish: deleting CRL object class " + oc + " from " + dn); + modSet.add(LDAPModification.DELETE, + new LDAPAttribute("objectClass", oc)); + hasOC = true; + } + } + + if (hasCRL || hasOC) { + conn.modify(dn, modSet); + } else { + log(ILogger.LL_INFO, + "unpublish: " + dn + " already has not CRL"); + } + } catch (CRLException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_CRL_ERROR", e.toString())); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) { + // need to intercept this because message from LDAP is + // "DSA is unavailable" which confuses with DSA PKI. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER")); + throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort())); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_UNPUBLISH_CRL_ERROR", e.toString())); + } + } + return; + } + + private void log(int level, String msg) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level, + "LdapCrlPublisher: " + msg); + } +} diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/LdapEncryptCertPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapEncryptCertPublisher.java new file mode 100644 index 000000000..543088ecb --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapEncryptCertPublisher.java @@ -0,0 +1,342 @@ +// --- 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.*; +import java.math.*; +import netscape.ldap.*; +import java.security.cert.*; +import java.util.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.request.*; +import com.netscape.certsrv.publish.*; +import com.netscape.certsrv.ldap.*; +import com.netscape.certsrv.ca.*; +import com.netscape.certsrv.apps.*; +import netscape.security.x509.*; + + +/** + * Interface for mapping a X509 certificate to a LDAP entry + * + * @version $Revision$, $Date$ + */ +public class LdapEncryptCertPublisher implements ILdapPublisher, IExtendedPluginInfo { + public static final String LDAP_USERCERT_ATTR = "userCertificate;binary"; + public static final String PROP_REVOKE_CERT = "revokeCert"; + + protected String mCertAttr = LDAP_USERCERT_ATTR; + private ILogger mLogger = CMS.getLogger(); + private IConfigStore mConfig = null; + private boolean mInited = false; + private boolean mRevokeCert; + + public LdapEncryptCertPublisher() { + } + + public String getImplName() { + return "LdapEncryptCertPublisher"; + } + + public String getDescription() { + return "LdapEncryptCertPublisher"; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + "certAttr;string;LDAP attribute in which to store the certificate", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-ldappublish-publisher-usercertpublisher", + IExtendedPluginInfo.HELP_TEXT + + ";This plugin knows how to publish user certificates" + }; + + return params; + + } + + public Vector getInstanceParams() { + Vector v = new Vector(); + + v.addElement("certAttr=" + mCertAttr); + return v; + } + + public Vector getDefaultParams() { + Vector v = new Vector(); + + v.addElement("certAttr=" + mCertAttr); + return v; + } + + public IConfigStore getConfigStore() { + return mConfig; + } + + public void init(IConfigStore config) + throws EBaseException { + if (mInited) + return; + mConfig = config; + mCertAttr = mConfig.getString("certAttr", LDAP_USERCERT_ATTR); + mRevokeCert = mConfig.getBoolean(PROP_REVOKE_CERT, true); + mInited = true; + } + + public LdapEncryptCertPublisher(String certAttr) { + mCertAttr = certAttr; + } + + /** + * publish a user certificate + * Adds the cert to the multi-valued certificate attribute as a + * DER encoded binary blob. Does not check if cert already exists. + * + * @param conn the LDAP connection + * @param dn dn of the entry to publish the certificate + * @param certObj the certificate object. + */ + public void publish(LDAPConnection conn, String dn, Object certObj) + throws ELdapException { + if (conn == null) + return; + + if (!(certObj instanceof X509Certificate)) + throw new IllegalArgumentException("Illegal arg to publish"); + + X509Certificate cert = (X509Certificate) certObj; + + log(ILogger.LL_INFO, "Publishing " + cert); + try { + byte[] certEnc = cert.getEncoded(); + + // check if cert already exists. + LDAPSearchResults res = conn.search(dn, LDAPv2.SCOPE_BASE, + "(objectclass=*)", new String[] { mCertAttr }, false); + LDAPEntry entry = res.next(); + LDAPAttribute attr = getModificationAttribute(entry.getAttribute(mCertAttr), certEnc); + + if (attr == null) { + log(ILogger.LL_INFO, "publish: " + dn + " already has cert."); + return; + } + + // publish + LDAPModification mod = new LDAPModification(LDAPModification.REPLACE, attr); + + conn.modify(dn, mod); + } catch (CertificateEncodingException e) { + CMS.debug("LdapEncryptCertPublisher: error in publish: " + e.toString()); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString())); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) { + // need to intercept this because message from LDAP is + // "DSA is unavailable" which confuses with DSA PKI. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER")); + throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort())); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISH_ERROR", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_USERCERT_ERROR", e.toString())); + } + } + return; + } + + /** + * unpublish a user certificate + * deletes the certificate from the list of certificates. + * does not check if certificate is already there. + */ + public void unpublish(LDAPConnection conn, String dn, Object certObj) + throws ELdapException { + if (!(certObj instanceof X509Certificate)) + throw new IllegalArgumentException("Illegal arg to publish"); + + X509Certificate cert = (X509Certificate) certObj; + + try { + byte[] certEnc = cert.getEncoded(); + + // check if cert already deleted. + LDAPSearchResults res = conn.search(dn, LDAPv2.SCOPE_BASE, + "(objectclass=*)", new String[] { mCertAttr }, false); + LDAPEntry entry = res.next(); + + if (!ByteValueExists(entry.getAttribute(mCertAttr), certEnc)) { + log(ILogger.LL_INFO, dn + " already has not cert"); + return; + } + + LDAPModification mod = new LDAPModification(LDAPModification.DELETE, + new LDAPAttribute(mCertAttr, certEnc)); + + conn.modify(dn, mod); + } catch (CertificateEncodingException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString())); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) { + // need to intercept this because message from LDAP is + // "DSA is unavailable" which confuses with DSA PKI. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER")); + throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort())); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_UNPUBLISH_USERCERT_ERROR", e.toString())); + } + } + return; + } + + private void log(int level, String msg) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level, + "LdapUserCertPublisher: " + msg); + } + + public LDAPAttribute getModificationAttribute( + LDAPAttribute attr, byte[] bval) { + + LDAPAttribute at = new LDAPAttribute(attr.getName(), bval); + if (at == null) { + return at; + } + + // determine if the given cert is a signing or an encryption + // certificate + X509CertImpl thisCert = null; + + try { + thisCert = new X509CertImpl(bval); + } catch (Exception e) { + } + if (thisCert == null) { + return at; + } + + Enumeration vals = attr.getByteValues(); + byte[] val = null; + + while (vals.hasMoreElements()) { + val = (byte[]) vals.nextElement(); + try { + X509CertImpl cert = new X509CertImpl(val); + + log(ILogger.LL_INFO, "Checking " + cert); + if (CMS.isEncryptionCert(thisCert) && + CMS.isEncryptionCert(cert)) { + // skip + log(ILogger.LL_INFO, "SKIP ENCRYPTION " + cert); + revokeCert(cert); + } else if (CMS.isSigningCert(thisCert) && + CMS.isSigningCert(cert)) { + // skip + log(ILogger.LL_INFO, "SKIP SIGNING " + cert); + revokeCert(cert); + } else { + at.addValue(val); + } + } catch (Exception e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_CHECK_FAILED", e.toString())); + } + } + return at; + } + + private RevokedCertImpl formCRLEntry( + BigInteger serialNo, RevocationReason reason) + throws EBaseException { + CRLReasonExtension reasonExt = new CRLReasonExtension(reason); + CRLExtensions crlentryexts = new CRLExtensions(); + + try { + crlentryexts.set(CRLReasonExtension.NAME, reasonExt); + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_SET_CRL_REASON", reason.toString(), e.toString())); + + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString())); + } + RevokedCertImpl crlentry = + new RevokedCertImpl(serialNo, new Date(), crlentryexts); + + return crlentry; + } + + private void revokeCert(X509CertImpl cert) + throws EBaseException { + try { + if (mConfig.getBoolean(PROP_REVOKE_CERT, true) == false) { + return; + } + } catch (EBaseException e) { + return; + } + BigInteger serialNum = cert.getSerialNumber(); + // need to revoke certificate also + ICertificateAuthority ca = (ICertificateAuthority) + CMS.getSubsystem("ca"); + ICAService service = (ICAService) ca.getCAService(); + RevokedCertImpl crlEntry = formCRLEntry( + serialNum, RevocationReason.KEY_COMPROMISE); + + service.revokeCert(crlEntry); + } + + /** + * checks if a byte attribute has a certain value. + */ + public static boolean ByteValueExists(LDAPAttribute attr, byte[] bval) { + if (attr == null) { + return false; + } + Enumeration vals = attr.getByteValues(); + byte[] val = null; + + while (vals.hasMoreElements()) { + val = (byte[]) vals.nextElement(); + if (Utils.byteArraysAreEqual(val, bval)) { + return true; + } + } + return false; + } + + /** + * checks if a attribute has a string value. + */ + public static boolean StringValueExists(LDAPAttribute attr, String sval) { + if (attr == null) { + return false; + } + Enumeration vals = attr.getStringValues(); + String val = null; + + while (vals.hasMoreElements()) { + val = (String) vals.nextElement(); + if (val.equalsIgnoreCase(sval)) { + return true; + } + } + return false; + } + +} + diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/LdapUserCertPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapUserCertPublisher.java new file mode 100644 index 000000000..fbc5cf6d1 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapUserCertPublisher.java @@ -0,0 +1,315 @@ +// --- 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 netscape.ldap.*; +import java.security.cert.*; +import java.util.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.ldap.*; +import com.netscape.certsrv.publish.*; + + +/** + * Interface for mapping a X509 certificate to a LDAP entry + * + * @version $Revision$, $Date$ + */ +public class LdapUserCertPublisher implements ILdapPublisher, IExtendedPluginInfo { + public static final String LDAP_USERCERT_ATTR = "userCertificate;binary"; + + protected String mCertAttr = LDAP_USERCERT_ATTR; + private ILogger mLogger = CMS.getLogger(); + private IConfigStore mConfig = null; + private boolean mInited = false; + + public LdapUserCertPublisher() { + } + + public String getImplName() { + return "LdapUserCertPublisher"; + } + + public String getDescription() { + return "LdapUserCertPublisher"; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + "certAttr;string;LDAP attribute in which to store the certificate", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-ldappublish-publisher-usercertpublisher", + IExtendedPluginInfo.HELP_TEXT + + ";This plugin knows how to publish user certificates" + }; + + return params; + + } + + public Vector getInstanceParams() { + Vector v = new Vector(); + + v.addElement("certAttr=" + mCertAttr); + return v; + } + + public Vector getDefaultParams() { + Vector v = new Vector(); + + v.addElement("certAttr=" + mCertAttr); + return v; + } + + public IConfigStore getConfigStore() { + return mConfig; + } + + public void init(IConfigStore config) + throws EBaseException { + if (mInited) + return; + mConfig = config; + mCertAttr = mConfig.getString("certAttr", LDAP_USERCERT_ATTR); + mInited = true; + } + + public LdapUserCertPublisher(String certAttr) { + mCertAttr = certAttr; + } + + /** + * publish a user certificate + * Adds the cert to the multi-valued certificate attribute as a + * DER encoded binary blob. Does not check if cert already exists. + * + * @param conn the LDAP connection + * @param dn dn of the entry to publish the certificate + * @param certObj the certificate object. + */ + public void publish(LDAPConnection conn, String dn, Object certObj) + throws ELdapException { + if (conn == null) + return; + + // Bugscape #56124 - support multiple publishing directory + // see if we should create local connection + LDAPConnection altConn = null; + try { + String host = mConfig.getString("host", null); + String port = mConfig.getString("port", null); + if (host != null && port != null) { + int portVal = Integer.parseInt(port); + int version = Integer.parseInt(mConfig.getString("version", "2")); + String cert_nick = mConfig.getString("clientCertNickname", null); + LDAPSSLSocketFactoryExt sslSocket = null; + if (cert_nick != null) { + sslSocket = CMS.getLdapJssSSLSocketFactory(cert_nick); + } + String mgr_dn = mConfig.getString("bindDN", null); + String mgr_pwd = mConfig.getString("bindPWD", null); + + altConn = CMS.getBoundConnection(host, portVal, + version, + sslSocket, mgr_dn, mgr_pwd); + conn = altConn; + } + } catch (LDAPException e) { + CMS.debug("Failed to create alt connection " + e); + } catch (EBaseException e) { + CMS.debug("Failed to create alt connection " + e); + } + + if (!(certObj instanceof X509Certificate)) + throw new IllegalArgumentException("Illegal arg to publish"); + + X509Certificate cert = (X509Certificate) certObj; + + boolean deleteCert = false; + try { + deleteCert = mConfig.getBoolean("deleteCert", false); + } catch (Exception e) { + } + + try { + byte[] certEnc = cert.getEncoded(); + + // check if cert already exists. + LDAPSearchResults res = conn.search(dn, LDAPv2.SCOPE_BASE, + "(objectclass=*)", new String[] { mCertAttr }, false); + LDAPEntry entry = res.next(); + + if (ByteValueExists(entry.getAttribute(mCertAttr), certEnc)) { + log(ILogger.LL_INFO, "publish: " + dn + " already has cert."); + return; + } + + // publish + LDAPModification mod = null; + if (deleteCert) { + mod = new LDAPModification(LDAPModification.REPLACE, + new LDAPAttribute(mCertAttr, certEnc)); + } else { + mod = new LDAPModification(LDAPModification.ADD, + new LDAPAttribute(mCertAttr, certEnc)); + } + + conn.modify(dn, mod); + + // log a successful message to the "transactions" log + mLogger.log( ILogger.EV_AUDIT, + ILogger.S_LDAP, + ILogger.LL_INFO, + AuditFormat.LDAP_PUBLISHED_FORMAT, + new Object[] { "LdapUserCertPublisher", + cert.getSerialNumber().toString(16), + cert.getSubjectDN() } ); + } catch (CertificateEncodingException e) { + CMS.debug("LdapUserCertPublisher: error in publish: " + e.toString()); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString())); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) { + // need to intercept this because message from LDAP is + // "DSA is unavailable" which confuses with DSA PKI. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER")); + throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort())); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISH_ERROR", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_USERCERT_ERROR", e.toString())); + } + } finally { + if (altConn != null) { + try { + altConn.disconnect(); + } catch (LDAPException e) { + // safely ignored + } + } + } + return; + } + + /** + * unpublish a user certificate + * deletes the certificate from the list of certificates. + * does not check if certificate is already there. + */ + public void unpublish(LDAPConnection conn, String dn, Object certObj) + throws ELdapException { + + boolean disableUnpublish = false; + try { + disableUnpublish = mConfig.getBoolean("disableUnpublish", false); + } catch (Exception e) { + } + + if (disableUnpublish) { + CMS.debug("UserCertPublisher: disable unpublish"); + return; + } + + if (!(certObj instanceof X509Certificate)) + throw new IllegalArgumentException("Illegal arg to publish"); + + X509Certificate cert = (X509Certificate) certObj; + + try { + byte[] certEnc = cert.getEncoded(); + + // check if cert already deleted. + LDAPSearchResults res = conn.search(dn, LDAPv2.SCOPE_BASE, + "(objectclass=*)", new String[] { mCertAttr }, false); + LDAPEntry entry = res.next(); + + if (!ByteValueExists(entry.getAttribute(mCertAttr), certEnc)) { + log(ILogger.LL_INFO, dn + " already has not cert"); + return; + } + + LDAPModification mod = new LDAPModification(LDAPModification.DELETE, + new LDAPAttribute(mCertAttr, certEnc)); + + conn.modify(dn, mod); + } catch (CertificateEncodingException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString())); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString())); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) { + // need to intercept this because message from LDAP is + // "DSA is unavailable" which confuses with DSA PKI. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER")); + throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort())); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR")); + throw new ELdapException(CMS.getUserMessage("CMS_LDAP_UNPUBLISH_USERCERT_ERROR", e.toString())); + } + } + return; + } + + private void log(int level, String msg) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level, + "LdapUserCertPublisher: " + msg); + } + + /** + * checks if a byte attribute has a certain value. + */ + public static boolean ByteValueExists(LDAPAttribute attr, byte[] bval) { + if (attr == null) { + return false; + } + Enumeration vals = attr.getByteValues(); + byte[] val = null; + + while (vals.hasMoreElements()) { + val = (byte[]) vals.nextElement(); + if (val.length == 0) + continue; + if (Utils.byteArraysAreEqual(val, bval)) { + return true; + } + } + return false; + } + + /** + * checks if a attribute has a string value. + */ + public static boolean StringValueExists(LDAPAttribute attr, String sval) { + if (attr == null) { + return false; + } + Enumeration vals = attr.getStringValues(); + String val = null; + + while (vals.hasMoreElements()) { + val = (String) vals.nextElement(); + if (val.equalsIgnoreCase(sval)) { + return true; + } + } + return false; + } + +} diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/OCSPPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/OCSPPublisher.java new file mode 100644 index 000000000..846ea7c48 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/publish/publishers/OCSPPublisher.java @@ -0,0 +1,351 @@ +// --- 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.net.*; +import java.math.*; +import java.io.*; +import java.security.cert.*; +import java.util.*; +import netscape.ldap.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.logging.*; +import org.mozilla.jss.ssl.*; +import org.mozilla.jss.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.ldap.*; +import com.netscape.certsrv.publish.*; +import com.netscape.cmsutil.http.*; + + +/** + * 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 getInstanceParams() { + Vector v = new Vector(); + 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 getDefaultParams() { + Vector v = new Vector(); + + 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")); + query.append(URLEncoder.encode(CMS.BtoA(crl.getEncoded()))); + query.append(URLEncoder.encode("\n-----END CERTIFICATE REVOCATION LIST-----")); + 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 line = ""; + 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 + } +} diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/Utils.java b/pki/base/common/src/com/netscape/cms/publish/publishers/Utils.java new file mode 100644 index 000000000..358a762b3 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/publish/publishers/Utils.java @@ -0,0 +1,131 @@ +// --- 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.net.*; +import java.io.*; +import java.util.*; +import java.text.*; + + +/** + * Publisher utility class. + * + * @version $Revision$, $Date$ + */ +public class Utils { + public static void checkHost(String hostname) throws UnknownHostException { + InetAddress addr = InetAddress.getByName(hostname); + } + + public static void copyStream(InputStream in, OutputStream out) throws IOException { + byte[] buf = new byte[4096]; + int len; + + while ((len = in.read(buf)) != -1) { + out.write(buf, 0, len); + } + } + + public static void copyStream(BufferedReader in, OutputStreamWriter out) throws IOException { + char[] buf = new char[4096]; + int len; + + while ((len = in.read(buf)) != -1) { + out.write(buf, 0, len); + } + } + + /// Sorts an array of Strings. + // Java currently has no general sort function. Sorting Strings is + // common enough that it's worth making a special case. + public static void sortStrings(String[] strings) { + // Just does a bubblesort. + for (int i = 0; i < strings.length - 1; ++i) { + for (int j = i + 1; j < strings.length; ++j) { + if (strings[i].compareTo(strings[j]) > 0) { + String t = strings[i]; + + strings[i] = strings[j]; + strings[j] = t; + } + } + } + } + + /// Returns a date string formatted in Unix ls style - if it's within + // six months of now, Mmm dd hh:ss, else Mmm dd yyyy. + public static String lsDateStr(Date date) { + long dateTime = date.getTime(); + + if (dateTime == -1L) + return "------------"; + long nowTime = System.currentTimeMillis(); + SimpleDateFormat formatter = new SimpleDateFormat(); + + if (Math.abs(nowTime - dateTime) < 183L * 24L * 60L * 60L * 1000L) + formatter.applyPattern("MMM dd hh:ss"); + else + formatter.applyPattern("MMM dd yyyy"); + return formatter.format(date); + } + + /** + * compares contents two byte arrays returning true if exactly same. + */ + static public boolean byteArraysAreEqual(byte[] a, byte[] b) { + if (a.length != b.length) + return false; + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) + return false; + } + return true; + } + + /** + * strips out double quotes around String parameter + * @param s the string potentially bracketed with double quotes + * @return string stripped of surrounding double quotes + */ + public static String stripQuotes(String s) { + if (s == null) { + return s; + } + + if ((s.startsWith("\"")) && (s.endsWith("\""))) { + return (s.substring(1, (s.length() - 1))); + } + + return s; + } + + /** + * returns an array of strings from a vector of Strings + * there'll be trouble if the Vector contains something other + * than just Strings + */ + public static String[] getStringArrayFromVector(Vector v) { + String s[] = new String[v.size()]; + + v.copyInto(s); + return s; + } + +} |