Blob Blame History Raw
commit 55a18f821446f69331b50b8126f86b30312245c2
Author: Endi S. Dewata <edewata@redhat.com>
Date:   Sat Jan 7 02:32:47 2017 +0100

    Added global TCP Keep-Alive option.
    
    A new tcp.keepAlive parameter has been added for CS.cfg to
    configure the TCP Keep-Alive option for all LDAP connections
    created by PKI server. By default the option is enabled.
    
    The LdapJssSSLSocketFactory has been modified to support both
    plain and secure sockets. For clarity, the socket factory has been
    renamed to PKISocketFactory.
    
    All codes that create LDAP connections have been modified to use
    PKISocketFactory such that the TCP Keep-Alive option can be applied
    globally.
    
    https://fedorahosted.org/pki/ticket/2564
    
    (cherry picked from commit b3ee1c28f658a70468c5a5fcf3cb4840574be756)
    (cherry picked from commit 4252656c27f230a5198a01a6085dad4b8e4df59f)

diff --git a/base/common/src/com/netscape/certsrv/apps/CMS.java b/base/common/src/com/netscape/certsrv/apps/CMS.java
index bc82a98..907b5bb 100644
--- a/base/common/src/com/netscape/certsrv/apps/CMS.java
+++ b/base/common/src/com/netscape/certsrv/apps/CMS.java
@@ -91,6 +91,7 @@ import com.netscape.cmsutil.password.IPasswordStore;
 import netscape.ldap.LDAPConnection;
 import netscape.ldap.LDAPException;
 import netscape.ldap.LDAPSSLSocketFactoryExt;
+import netscape.ldap.LDAPSocketFactory;
 import netscape.security.util.ObjectIdentifier;
 import netscape.security.x509.Extension;
 import netscape.security.x509.GeneralName;
@@ -1345,6 +1346,10 @@ public final class CMS {
         return _engine.getLdapJssSSLSocketFactory();
     }
 
+    public static LDAPSocketFactory getLDAPSocketFactory(boolean secure) {
+        return _engine.getLDAPSocketFactory(secure);
+    }
+
     /**
      * Creates a LDAP Auth Info object.
      *
diff --git a/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java b/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java
index f781c41..7cf73fa 100644
--- a/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java
+++ b/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java
@@ -75,6 +75,7 @@ import com.netscape.cmsutil.password.IPasswordStore;
 import netscape.ldap.LDAPConnection;
 import netscape.ldap.LDAPException;
 import netscape.ldap.LDAPSSLSocketFactoryExt;
+import netscape.ldap.LDAPSocketFactory;
 import netscape.security.util.ObjectIdentifier;
 import netscape.security.x509.Extension;
 import netscape.security.x509.GeneralName;
@@ -648,6 +649,13 @@ public interface ICMSEngine extends ISubsystem {
     public LDAPSSLSocketFactoryExt getLdapJssSSLSocketFactory();
 
     /**
+     * Creates an LDAP socket factory.
+     *
+     * @return LDAP SSL socket factory
+     */
+    public LDAPSocketFactory getLDAPSocketFactory(boolean secure);
+
+    /**
      * Creates a LDAP Auth Info object.
      *
      * @return LDAP authentication info
diff --git a/base/server/cms/src/com/netscape/cms/publish/publishers/LdapCaCertPublisher.java b/base/server/cms/src/com/netscape/cms/publish/publishers/LdapCaCertPublisher.java
index f740ef3..c7f818a 100644
--- a/base/server/cms/src/com/netscape/cms/publish/publishers/LdapCaCertPublisher.java
+++ b/base/server/cms/src/com/netscape/cms/publish/publishers/LdapCaCertPublisher.java
@@ -22,6 +22,15 @@ import java.security.cert.X509Certificate;
 import java.util.Locale;
 import java.util.Vector;
 
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.IExtendedPluginInfo;
+import com.netscape.certsrv.ldap.ELdapException;
+import com.netscape.certsrv.ldap.ELdapServerDownException;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.publish.ILdapPublisher;
+
 import netscape.ldap.LDAPAttribute;
 import netscape.ldap.LDAPConnection;
 import netscape.ldap.LDAPEntry;
@@ -32,15 +41,6 @@ import netscape.ldap.LDAPSSLSocketFactoryExt;
 import netscape.ldap.LDAPSearchResults;
 import netscape.ldap.LDAPv2;
 
-import com.netscape.certsrv.apps.CMS;
-import com.netscape.certsrv.base.EBaseException;
-import com.netscape.certsrv.base.IConfigStore;
-import com.netscape.certsrv.base.IExtendedPluginInfo;
-import com.netscape.certsrv.ldap.ELdapException;
-import com.netscape.certsrv.ldap.ELdapServerDownException;
-import com.netscape.certsrv.logging.ILogger;
-import com.netscape.certsrv.publish.ILdapPublisher;
-
 /**
  * Interface for publishing a CA certificate to
  *
@@ -179,9 +179,11 @@ public class LdapCaCertPublisher
                 int portVal = Integer.parseInt(port);
                 int version = Integer.parseInt(mConfig.getString("version", "2"));
                 String cert_nick = mConfig.getString("clientCertNickname", null);
-                LDAPSSLSocketFactoryExt sslSocket = null;
+                LDAPSSLSocketFactoryExt sslSocket;
                 if (cert_nick != null) {
                     sslSocket = CMS.getLdapJssSSLSocketFactory(cert_nick);
+                } else {
+                    sslSocket = CMS.getLdapJssSSLSocketFactory();
                 }
                 String mgr_dn = mConfig.getString("bindDN", null);
                 String mgr_pwd = mConfig.getString("bindPWD", null);
diff --git a/base/server/cms/src/com/netscape/cms/publish/publishers/LdapCrlPublisher.java b/base/server/cms/src/com/netscape/cms/publish/publishers/LdapCrlPublisher.java
index 80ffa3c..64df143 100644
--- a/base/server/cms/src/com/netscape/cms/publish/publishers/LdapCrlPublisher.java
+++ b/base/server/cms/src/com/netscape/cms/publish/publishers/LdapCrlPublisher.java
@@ -22,6 +22,15 @@ import java.security.cert.X509CRL;
 import java.util.Locale;
 import java.util.Vector;
 
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.IExtendedPluginInfo;
+import com.netscape.certsrv.ldap.ELdapException;
+import com.netscape.certsrv.ldap.ELdapServerDownException;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.publish.ILdapPublisher;
+
 import netscape.ldap.LDAPAttribute;
 import netscape.ldap.LDAPConnection;
 import netscape.ldap.LDAPConstraints;
@@ -33,15 +42,6 @@ import netscape.ldap.LDAPSSLSocketFactoryExt;
 import netscape.ldap.LDAPSearchResults;
 import netscape.ldap.LDAPv2;
 
-import com.netscape.certsrv.apps.CMS;
-import com.netscape.certsrv.base.EBaseException;
-import com.netscape.certsrv.base.IConfigStore;
-import com.netscape.certsrv.base.IExtendedPluginInfo;
-import com.netscape.certsrv.ldap.ELdapException;
-import com.netscape.certsrv.ldap.ELdapServerDownException;
-import com.netscape.certsrv.logging.ILogger;
-import com.netscape.certsrv.publish.ILdapPublisher;
-
 /**
  * For publishing master or global CRL.
  * Publishes (replaces) the CRL in the CA's LDAP entry.
@@ -170,9 +170,11 @@ public class LdapCrlPublisher implements ILdapPublisher, IExtendedPluginInfo {
                 int portVal = Integer.parseInt(port);
                 int version = Integer.parseInt(mConfig.getString("version", "2"));
                 String cert_nick = mConfig.getString("clientCertNickname", null);
-                LDAPSSLSocketFactoryExt sslSocket = null;
+                LDAPSSLSocketFactoryExt sslSocket;
                 if (cert_nick != null) {
                     sslSocket = CMS.getLdapJssSSLSocketFactory(cert_nick);
+                } else {
+                    sslSocket = CMS.getLdapJssSSLSocketFactory();
                 }
                 String mgr_dn = mConfig.getString("bindDN", null);
                 String mgr_pwd = mConfig.getString("bindPWD", null);
diff --git a/base/server/cms/src/com/netscape/cms/publish/publishers/LdapUserCertPublisher.java b/base/server/cms/src/com/netscape/cms/publish/publishers/LdapUserCertPublisher.java
index a01cf80..e87fca9 100644
--- a/base/server/cms/src/com/netscape/cms/publish/publishers/LdapUserCertPublisher.java
+++ b/base/server/cms/src/com/netscape/cms/publish/publishers/LdapUserCertPublisher.java
@@ -23,15 +23,6 @@ import java.util.Enumeration;
 import java.util.Locale;
 import java.util.Vector;
 
-import netscape.ldap.LDAPAttribute;
-import netscape.ldap.LDAPConnection;
-import netscape.ldap.LDAPEntry;
-import netscape.ldap.LDAPException;
-import netscape.ldap.LDAPModification;
-import netscape.ldap.LDAPSSLSocketFactoryExt;
-import netscape.ldap.LDAPSearchResults;
-import netscape.ldap.LDAPv2;
-
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.IConfigStore;
@@ -42,6 +33,15 @@ import com.netscape.certsrv.logging.AuditFormat;
 import com.netscape.certsrv.logging.ILogger;
 import com.netscape.certsrv.publish.ILdapPublisher;
 
+import netscape.ldap.LDAPAttribute;
+import netscape.ldap.LDAPConnection;
+import netscape.ldap.LDAPEntry;
+import netscape.ldap.LDAPException;
+import netscape.ldap.LDAPModification;
+import netscape.ldap.LDAPSSLSocketFactoryExt;
+import netscape.ldap.LDAPSearchResults;
+import netscape.ldap.LDAPv2;
+
 /**
  * Interface for mapping a X509 certificate to a LDAP entry
  *
@@ -134,9 +134,11 @@ public class LdapUserCertPublisher implements ILdapPublisher, IExtendedPluginInf
                 int portVal = Integer.parseInt(port);
                 int version = Integer.parseInt(mConfig.getString("version", "2"));
                 String cert_nick = mConfig.getString("clientCertNickname", null);
-                LDAPSSLSocketFactoryExt sslSocket = null;
+                LDAPSSLSocketFactoryExt sslSocket;
                 if (cert_nick != null) {
                     sslSocket = CMS.getLdapJssSSLSocketFactory(cert_nick);
+                } else {
+                    sslSocket = CMS.getLdapJssSSLSocketFactory();
                 }
                 String mgr_dn = mConfig.getString("bindDN", null);
                 String mgr_pwd = mConfig.getString("bindPWD", null);
diff --git a/base/server/cms/src/com/netscape/cms/servlet/admin/PublisherAdminServlet.java b/base/server/cms/src/com/netscape/cms/servlet/admin/PublisherAdminServlet.java
index 423fad3..22dd8c1 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/admin/PublisherAdminServlet.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/admin/PublisherAdminServlet.java
@@ -27,9 +27,6 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import netscape.ldap.LDAPConnection;
-import netscape.ldap.LDAPException;
-
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.authority.IAuthority;
 import com.netscape.certsrv.authority.ICertAuthority;
@@ -67,6 +64,9 @@ import com.netscape.certsrv.publish.RulePlugin;
 import com.netscape.certsrv.security.ICryptoSubsystem;
 import com.netscape.cmsutil.password.IPasswordStore;
 
+import netscape.ldap.LDAPConnection;
+import netscape.ldap.LDAPException;
+
 /**
  * A class representing an publishing servlet for the
  * Publishing subsystem. This servlet is responsible
@@ -770,14 +770,13 @@ public class PublisherAdminServlet extends AdminServlet {
                 }
             } else {
                 try {
+                    conn = new LDAPConnection(
+                            CMS.getLDAPSocketFactory(secure));
                     if (secure) {
-                        conn = new LDAPConnection(
-                                    CMS.getLdapJssSSLSocketFactory());
                         params.put(Constants.PR_CONN_INITED,
                                 "Create ssl LDAPConnection" +
                                         dashes(70 - 25) + " Success");
                     } else {
-                        conn = new LDAPConnection();
                         params.put(Constants.PR_CONN_INITED,
                                 "Create LDAPConnection" +
                                         dashes(70 - 21) + " Success");
diff --git a/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java b/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
index c62087e..af0d44e 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
@@ -143,7 +143,7 @@ import com.netscape.cmscore.ldapconn.LdapAuthInfo;
 import com.netscape.cmscore.ldapconn.LdapBoundConnFactory;
 import com.netscape.cmscore.ldapconn.LdapBoundConnection;
 import com.netscape.cmscore.ldapconn.LdapConnInfo;
-import com.netscape.cmscore.ldapconn.LdapJssSSLSocketFactory;
+import com.netscape.cmscore.ldapconn.PKISocketFactory;
 import com.netscape.cmscore.logging.Auditor;
 import com.netscape.cmscore.logging.LogSubsystem;
 import com.netscape.cmscore.logging.Logger;
@@ -174,6 +174,7 @@ import com.netscape.cmsutil.util.Utils;
 import netscape.ldap.LDAPConnection;
 import netscape.ldap.LDAPException;
 import netscape.ldap.LDAPSSLSocketFactoryExt;
+import netscape.ldap.LDAPSocketFactory;
 import netscape.security.extensions.CertInfo;
 import netscape.security.pkcs.ContentInfo;
 import netscape.security.pkcs.PKCS7;
@@ -480,9 +481,7 @@ public class CMSEngine implements ICMSEngine {
         String host = info.getHost();
         int port = info.getPort();
 
-        LDAPConnection conn = info.getSecure() ?
-                new LDAPConnection(CMS.getLdapJssSSLSocketFactory()) :
-                new LDAPConnection();
+        LDAPConnection conn = new LDAPConnection(CMS.getLDAPSocketFactory(info.getSecure()));
 
         System.out.println("testLDAPConnection connecting to " + host + ":" + port);
 
@@ -1027,11 +1026,15 @@ public class CMSEngine implements ICMSEngine {
 
     public LDAPSSLSocketFactoryExt getLdapJssSSLSocketFactory(
             String certNickname) {
-        return new LdapJssSSLSocketFactory(certNickname);
+        return new PKISocketFactory(certNickname);
     }
 
     public LDAPSSLSocketFactoryExt getLdapJssSSLSocketFactory() {
-        return new LdapJssSSLSocketFactory();
+        return new PKISocketFactory(true);
+    }
+
+    public LDAPSocketFactory getLDAPSocketFactory(boolean secure) {
+        return new PKISocketFactory(secure);
     }
 
     public ILdapAuthInfo getLdapAuthInfo() {
diff --git a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/LdapAnonConnection.java b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/LdapAnonConnection.java
index 52cdc4b..5d5e142 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/LdapAnonConnection.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/LdapAnonConnection.java
@@ -40,7 +40,7 @@ public class LdapAnonConnection extends LDAPConnection {
      */
     public LdapAnonConnection(LdapConnInfo connInfo)
             throws LDAPException {
-        super(connInfo.getSecure() ? new LdapJssSSLSocketFactory() : null);
+        super(new PKISocketFactory(connInfo.getSecure()));
 
         // Set option to automatically follow referrals.
         // rebind info is also anonymous.
diff --git a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/LdapBoundConnection.java b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/LdapBoundConnection.java
index 787967a..a326344 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/LdapBoundConnection.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/LdapBoundConnection.java
@@ -19,6 +19,8 @@ package com.netscape.cmscore.ldapconn;
 
 import java.util.Properties;
 
+import com.netscape.certsrv.apps.CMS;
+
 import netscape.ldap.LDAPConnection;
 import netscape.ldap.LDAPException;
 import netscape.ldap.LDAPRebind;
@@ -26,8 +28,6 @@ import netscape.ldap.LDAPRebindAuth;
 import netscape.ldap.LDAPSocketFactory;
 import netscape.ldap.LDAPv2;
 
-import com.netscape.certsrv.apps.CMS;
-
 /**
  * A LDAP connection that is bound to a server host, port, secure type.
  * and authentication.
@@ -56,8 +56,8 @@ public class LdapBoundConnection extends LDAPConnection {
         // this LONG line to satisfy super being the first call. (yuk)
         super(
                 authInfo.getAuthType() == LdapAuthInfo.LDAP_AUTHTYPE_SSLCLIENTAUTH ?
-                        new LdapJssSSLSocketFactory(authInfo.getParms()[0]) :
-                        (connInfo.getSecure() ? new LdapJssSSLSocketFactory() : null));
+                        new PKISocketFactory(authInfo.getParms()[0]) :
+                        new PKISocketFactory(connInfo.getSecure()));
 
         // Set option to automatically follow referrals.
         // Use the same credentials to follow referrals; this is the easiest
diff --git a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/LdapJssSSLSocketFactory.java b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/LdapJssSSLSocketFactory.java
deleted file mode 100644
index b54d1e2..0000000
--- a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/LdapJssSSLSocketFactory.java
+++ /dev/null
@@ -1,177 +0,0 @@
-// --- 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.cmscore.ldapconn;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.UnknownHostException;
-import java.util.Iterator;
-import java.util.Vector;
-
-import netscape.ldap.LDAPException;
-import netscape.ldap.LDAPSSLSocketFactoryExt;
-
-import org.mozilla.jss.ssl.SSLClientCertificateSelectionCallback;
-import org.mozilla.jss.ssl.SSLHandshakeCompletedEvent;
-import org.mozilla.jss.ssl.SSLHandshakeCompletedListener;
-import org.mozilla.jss.ssl.SSLSocket;
-
-import com.netscape.certsrv.apps.CMS;
-import com.netscape.certsrv.logging.ILogger;
-
-/**
- * Uses HCL ssl socket.
- *
- * @author Lily Hsiao lhsiao@netscape.com
- */
-public class LdapJssSSLSocketFactory implements LDAPSSLSocketFactoryExt {
-    private String mClientAuthCertNickname = null;
-    private boolean mClientAuth = false;
-
-    public LdapJssSSLSocketFactory() {
-    }
-
-    public LdapJssSSLSocketFactory(String certNickname) {
-        mClientAuthCertNickname = certNickname;
-    }
-
-    public Socket makeSocket(String host, int port) throws LDAPException {
-        SSLSocket s = null;
-
-        try {
-            /*
-             * let inherit TLS range and cipher settings
-             */
-
-            if (mClientAuthCertNickname == null) {
-                s = new SSLSocket(host, port);
-            }
-            else {
-                //Let's create a selection callback in the case the client auth
-                //No longer manually set the cert name.
-                //This two step process, used in the JSS client auth test suite,
-                //appears to be needed to get this working.
-
-                Socket js = new Socket(InetAddress.getByName(host), port);
-                s = new SSLSocket(js, host,
-                        null,
-                        new SSLClientCertificateSelectionCB(mClientAuthCertNickname));
-            }
-
-            s.setUseClientMode(true);
-            s.enableV2CompatibleHello(false);
-
-            SSLHandshakeCompletedListener listener = null;
-
-            listener = new ClientHandshakeCB(this);
-            s.addHandshakeCompletedListener(listener);
-
-            if (mClientAuthCertNickname != null) {
-                mClientAuth = true;
-                CMS.debug("LdapJssSSLSocket: set client auth cert nickname " +
-                        mClientAuthCertNickname);
-
-                //We have already established the manual cert selection callback
-                //Doing it this way will provide some debugging info on the candidate certs
-            }
-            s.forceHandshake();
-
-        } catch (UnknownHostException e) {
-            log(ILogger.LL_FAILURE,
-                    CMS.getLogMessage("CMSCORE_LDAPCONN_UNKNOWN_HOST"));
-            throw new LDAPException(
-                    "Cannot Create JSS SSL Socket - Unknown host: " + e);
-
-        } catch (IOException e) {
-            if (s != null) {
-                try {
-                    s.close();
-                } catch (IOException e1) {
-                    e1.printStackTrace();
-                }
-            }
-            log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_LDAPCONN_IO_ERROR", e.toString()));
-            throw new LDAPException("IO Error creating JSS SSL Socket: " + e);
-        }
-
-        return s;
-    }
-
-    public boolean isClientAuth() {
-        return mClientAuth;
-    }
-
-    public Object getCipherSuites() {
-        return null;
-    }
-
-    public void log(int level, String msg) {
-    }
-
-    static class ClientHandshakeCB implements SSLHandshakeCompletedListener {
-        Object sc;
-
-        public ClientHandshakeCB(Object sc) {
-            this.sc = sc;
-        }
-
-        public void handshakeCompleted(SSLHandshakeCompletedEvent event) {
-            CMS.debug("SSL handshake happened");
-        }
-    }
-
-    static class SSLClientCertificateSelectionCB implements SSLClientCertificateSelectionCallback {
-        String desiredCertName = null;
-
-        public SSLClientCertificateSelectionCB(String clientAuthCertNickname) {
-            CMS.debug("SSLClientCertificateSelectionCB: Setting desired cert nickname to: " + clientAuthCertNickname);
-            desiredCertName = clientAuthCertNickname;
-        }
-
-        @Override
-        public String select(Vector certs) {
-
-            CMS.debug("SSLClientCertificatSelectionCB: Entering!");
-
-            if(desiredCertName == null) {
-                return null;
-            }
-
-            @SuppressWarnings("unchecked")
-            Iterator<String> itr = certs.iterator();
-            String selection = null;
-
-            while(itr.hasNext()){
-                String candidate = itr.next();
-                CMS.debug("Candidate cert: " + candidate);
-                if(desiredCertName.equalsIgnoreCase(candidate)) {
-                    selection = candidate;
-                    CMS.debug("SSLClientCertificateSelectionCB: desired cert found in list: " + desiredCertName);
-                    break;
-                }
-            }
-
-            CMS.debug("SSLClientCertificateSelectionCB: returning: " + selection);
-            return selection;
-
-        }
-
-    }
-
-}
diff --git a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java
new file mode 100644
index 0000000..d0c23ed
--- /dev/null
+++ b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java
@@ -0,0 +1,211 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmscore.ldapconn;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.mozilla.jss.ssl.SSLClientCertificateSelectionCallback;
+import org.mozilla.jss.ssl.SSLHandshakeCompletedEvent;
+import org.mozilla.jss.ssl.SSLHandshakeCompletedListener;
+import org.mozilla.jss.ssl.SSLSocket;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.IConfigStore;
+
+import netscape.ldap.LDAPException;
+import netscape.ldap.LDAPSSLSocketFactoryExt;
+
+/**
+ * Uses HCL ssl socket.
+ *
+ * @author Lily Hsiao lhsiao@netscape.com
+ */
+public class PKISocketFactory implements LDAPSSLSocketFactoryExt {
+
+    private boolean secure;
+    private String mClientAuthCertNickname;
+    private boolean mClientAuth;
+    private boolean keepAlive;
+
+    public PKISocketFactory() {
+        init();
+    }
+
+    public PKISocketFactory(boolean secure) {
+        this.secure = secure;
+        init();
+    }
+
+    public PKISocketFactory(String certNickname) {
+        this.secure = true;
+        mClientAuthCertNickname = certNickname;
+        init();
+    }
+
+    public void init() {
+        try {
+            IConfigStore cs = CMS.getConfigStore();
+            keepAlive = cs.getBoolean("tcp.keepAlive", true);
+            CMS.debug("TCP Keep-Alive: " + keepAlive);
+
+        } catch (Exception e) {
+            CMS.debug(e);
+            throw new RuntimeException("Unable to read TCP configuration: " + e, e);
+        }
+    }
+
+    public SSLSocket makeSSLSocket(String host, int port) throws UnknownHostException, IOException {
+
+        /*
+         * let inherit TLS range and cipher settings
+         */
+
+        SSLSocket s;
+
+        if (mClientAuthCertNickname == null) {
+            s = new SSLSocket(host, port);
+
+        } else {
+            // Let's create a selection callback in the case the client auth
+            // No longer manually set the cert name.
+            // This two step process, used in the JSS client auth test suite,
+            // appears to be needed to get this working.
+
+            Socket js = new Socket(InetAddress.getByName(host), port);
+            s = new SSLSocket(js, host,
+                    null,
+                    new SSLClientCertificateSelectionCB(mClientAuthCertNickname));
+        }
+
+        s.setUseClientMode(true);
+        s.enableV2CompatibleHello(false);
+
+        SSLHandshakeCompletedListener listener = null;
+
+        listener = new ClientHandshakeCB(this);
+        s.addHandshakeCompletedListener(listener);
+
+        if (mClientAuthCertNickname != null) {
+            mClientAuth = true;
+            CMS.debug("LdapJssSSLSocket: set client auth cert nickname " +
+                    mClientAuthCertNickname);
+
+            //We have already established the manual cert selection callback
+            //Doing it this way will provide some debugging info on the candidate certs
+        }
+        s.forceHandshake();
+
+        return s;
+    }
+
+    public Socket makeSocket(String host, int port) throws LDAPException {
+
+        Socket s = null;
+
+        try {
+            if (!secure) {
+                s = new Socket(host, port);
+
+            } else {
+                s = makeSSLSocket(host, port);
+            }
+
+            s.setKeepAlive(keepAlive);
+
+        } catch (Exception e) {
+            CMS.debug(e);
+            if (s != null) {
+                try {
+                    s.close();
+                } catch (IOException e1) {
+                    CMS.debug(e1);
+                }
+            }
+            throw new LDAPException("Unable to create socket: " + e);
+        }
+
+        return s;
+    }
+
+    public boolean isClientAuth() {
+        return mClientAuth;
+    }
+
+    public Object getCipherSuites() {
+        return null;
+    }
+
+    public void log(int level, String msg) {
+    }
+
+    static class ClientHandshakeCB implements SSLHandshakeCompletedListener {
+        Object sc;
+
+        public ClientHandshakeCB(Object sc) {
+            this.sc = sc;
+        }
+
+        public void handshakeCompleted(SSLHandshakeCompletedEvent event) {
+            CMS.debug("SSL handshake happened");
+        }
+    }
+
+    static class SSLClientCertificateSelectionCB implements SSLClientCertificateSelectionCallback {
+        String desiredCertName = null;
+
+        public SSLClientCertificateSelectionCB(String clientAuthCertNickname) {
+            CMS.debug("SSLClientCertificateSelectionCB: Setting desired cert nickname to: " + clientAuthCertNickname);
+            desiredCertName = clientAuthCertNickname;
+        }
+
+        @Override
+        public String select(Vector certs) {
+
+            CMS.debug("SSLClientCertificatSelectionCB: Entering!");
+
+            if(desiredCertName == null) {
+                return null;
+            }
+
+            @SuppressWarnings("unchecked")
+            Iterator<String> itr = certs.iterator();
+            String selection = null;
+
+            while(itr.hasNext()){
+                String candidate = itr.next();
+                CMS.debug("Candidate cert: " + candidate);
+                if(desiredCertName.equalsIgnoreCase(candidate)) {
+                    selection = candidate;
+                    CMS.debug("SSLClientCertificateSelectionCB: desired cert found in list: " + desiredCertName);
+                    break;
+                }
+            }
+
+            CMS.debug("SSLClientCertificateSelectionCB: returning: " + selection);
+            return selection;
+
+        }
+
+    }
+
+}
diff --git a/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java b/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java
index d2b7fe8..73d039f 100644
--- a/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java
+++ b/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java
@@ -60,6 +60,7 @@ import com.netscape.cmsutil.password.IPasswordStore;
 import netscape.ldap.LDAPConnection;
 import netscape.ldap.LDAPException;
 import netscape.ldap.LDAPSSLSocketFactoryExt;
+import netscape.ldap.LDAPSocketFactory;
 import netscape.security.util.ObjectIdentifier;
 import netscape.security.x509.Extension;
 import netscape.security.x509.GeneralName;
@@ -344,6 +345,10 @@ public class CMSEngineDefaultStub implements ICMSEngine {
         return null;
     }
 
+    public LDAPSocketFactory getLDAPSocketFactory(boolean secure) {
+        return null;
+    }
+
     public ILdapAuthInfo getLdapAuthInfo() {
         return null;
     }