>From f819a1a7446fbd438cde3af5114beb0b1fe0388b Mon Sep 17 00:00:00 2001
From: Christina Fu <cfu@redhat.com>
Date: Tue, 20 Oct 2015 14:06:11 +0200
Subject: [PATCH] Ticket #1648 [RFE] provide separate cipher lists for CS
 instances acting as client and server This patch provides
 subsystem->subsystem cipher configuration when acting as a client Note: * It
 is only meant for cs subsystem->subsystem communication; i.e.. ca->kra,
 tps->ca, tps->kra, tps->tks (e.g. not for connection to the ldap server,
 internal, publishing, or authentication) * the clientCiphers configuration is
 a "strict" list, meaning, only the ciphers in the comma separated list are
 enabled in the connection when acting as a client * if the clientCiphers
 configuration parameter is undefined, default action is taken to enable all
 available ciphers provided (that means it works as it did prior to this
 patch) * pki-core and pki-util packages are expected to be updated together
 for   the newly added clientCiphers String parameter in various affected
 connection   interfaces; since it is handled in a way that if this parameter
 is null, it   goes to default, there is no need to add extra interface
 routines as they   are expected to be internal to cs subsystems

---
 base/ca/src/com/netscape/ca/CAService.java         |   6 +-
 base/common/src/com/netscape/certsrv/apps/CMS.java |   3 +-
 .../src/com/netscape/certsrv/apps/ICMSEngine.java  |   1 +
 .../src/com/netscape/cmscore/apps/CMSEngine.java   |   3 +-
 .../cmscore/connector/HttpConnFactory.java         |  10 +-
 .../netscape/cmscore/connector/HttpConnector.java  |  16 +-
 .../com/netscape/cmscore/connector/Resender.java   |   9 +-
 .../netscape/cmscore/app/CMSEngineDefaultStub.java |   2 +-
 .../server/tps/cms/ConnectionManager.java          |  10 +-
 .../com/netscape/cmsutil/crypto/CryptoUtil.java    | 250 +++++++++++++++++++++
 .../netscape/cmsutil/http/JssSSLSocketFactory.java |  13 ++
 11 files changed, 303 insertions(+), 20 deletions(-)

diff --git a/base/ca/src/com/netscape/ca/CAService.java b/base/ca/src/com/netscape/ca/CAService.java
index a49d641cec839b4dac33fe7a6be49bf86c3560a8..db692e3d0ddc10358880fdfb8bb0e14ebf5bd8bd 100644
--- a/base/ca/src/com/netscape/ca/CAService.java
+++ b/base/ca/src/com/netscape/ca/CAService.java
@@ -290,11 +290,13 @@ public class CAService implements ICAService, IService {
             // Changed by beomsuk
             //connector =
             //	new HttpConnector(mCA, nickname, remauthority, resendInterval);
+
+            String clientCiphers = config.getString("clientCiphers", null);
             if (timeout == 0)
-                connector = new HttpConnector((IAuthority) mCA, nickname, remauthority, resendInterval, config);
+                connector = new HttpConnector((IAuthority) mCA, nickname, clientCiphers, remauthority, resendInterval, config);
             else
                 connector =
-                        new HttpConnector((IAuthority) mCA, nickname, remauthority, resendInterval, config, timeout);
+                        new HttpConnector((IAuthority) mCA, nickname, clientCiphers, remauthority, resendInterval, config, timeout);
             // Change end
 
             // log(ILogger.LL_INFO, "remote authority "+
diff --git a/base/common/src/com/netscape/certsrv/apps/CMS.java b/base/common/src/com/netscape/certsrv/apps/CMS.java
index 187b1028a849f504b6e8ebb715e42521d5846613..2a88e2c3348e790ce9e075c718be216fa373468e 100644
--- a/base/common/src/com/netscape/certsrv/apps/CMS.java
+++ b/base/common/src/com/netscape/certsrv/apps/CMS.java
@@ -896,8 +896,9 @@ public final class CMS {
      * @return resender
      */
     public static IResender getResender(IAuthority authority, String nickname,
+            String clientCiphers,
             IRemoteAuthority remote, int interval) {
-        return _engine.getResender(authority, nickname, remote, interval);
+        return _engine.getResender(authority, nickname, clientCiphers, remote, interval);
     }
 
     /**
diff --git a/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java b/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java
index bf1d3ff61b1c1123e0990f94164b37509ac8f2eb..e9b5b765fca2c949db0db91494f48c12b4fee35a 100644
--- a/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java
+++ b/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java
@@ -1051,6 +1051,7 @@ public interface ICMSEngine extends ISubsystem {
      * @return resender
      */
     public IResender getResender(IAuthority authority, String nickname,
+            String clientCiphers,
             IRemoteAuthority remote, int interval);
 
     /**
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 2452a417f4ecf58d63495c6fc306a47dcf202bab..77f913636bda6a490755d3ea88b9d6c56b341c74 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
@@ -1010,8 +1010,9 @@ public class CMSEngine implements ICMSEngine {
     }
 
     public IResender getResender(IAuthority authority, String nickname,
+            String clientCiphers,
             IRemoteAuthority remote, int interval) {
-        return new Resender(authority, nickname, remote, interval);
+        return new Resender(authority, nickname, clientCiphers, remote, interval);
     }
 
     public IPKIMessage getHttpPKIMessage() {
diff --git a/base/server/cmscore/src/com/netscape/cmscore/connector/HttpConnFactory.java b/base/server/cmscore/src/com/netscape/cmscore/connector/HttpConnFactory.java
index db2a51afd50cb2366edfc74812b7ebd052720d59..47f5e6108c3f6ee8fadf3827d5e4f89f3fb9e114 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/connector/HttpConnFactory.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/connector/HttpConnFactory.java
@@ -43,6 +43,7 @@ public class HttpConnFactory {
     private IAuthority mSource;
     private IRemoteAuthority mDest = null;
     private String mNickname = "";
+    private String mClientCiphers = null;
     private int mTimeout = 0;
 
     /**
@@ -59,13 +60,18 @@ public class HttpConnFactory {
      * @param maxConns max number of connections to have available. This is
      * @param serverInfo server connection info - host, port, etc.
      */
-    public HttpConnFactory(int minConns, int maxConns, IAuthority source, IRemoteAuthority dest, String nickname,
+    public HttpConnFactory(int minConns, int maxConns, IAuthority source, IRemoteAuthority dest, String nickname, String clientCiphers,
             int timeout) throws EBaseException {
 
         CMS.debug("In HttpConnFactory constructor mTimeout " + timeout);
+        if (mClientCiphers != null)
+            CMS.debug("In HttpConnFactory constructor mClientCiphers: " + mClientCiphers);
+        else
+            CMS.debug("In HttpConnFactory constructor mClientCiphers not specified, will take default ");
         mSource = source;
         mDest = dest;
         mNickname = nickname;
+        mClientCiphers = clientCiphers;
         mTimeout = timeout;
 
         init(minConns, maxConns);
@@ -120,7 +126,7 @@ public class HttpConnFactory {
         CMS.debug("In HttpConnFactory.createConnection.");
 
         try {
-            ISocketFactory tFactory = new JssSSLSocketFactory(mNickname);
+            ISocketFactory tFactory = new JssSSLSocketFactory(mNickname, mClientCiphers);
 
             if (mTimeout == 0) {
                 retConn = CMS.getHttpConnection(mDest, tFactory);
diff --git a/base/server/cmscore/src/com/netscape/cmscore/connector/HttpConnector.java b/base/server/cmscore/src/com/netscape/cmscore/connector/HttpConnector.java
index 9b6f8dd9361aad5fcd8248af8795a55559ff31e6..398becc202e854c66e47bb0559a92cde25674fab 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/connector/HttpConnector.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/connector/HttpConnector.java
@@ -49,13 +49,13 @@ public class HttpConnector implements IConnector {
 
     private HttpConnFactory mConnFactory = null;
 
-    public HttpConnector(IAuthority source, String nickName,
+    public HttpConnector(IAuthority source, String nickName, String clientCiphers,
             IRemoteAuthority dest, int resendInterval, IConfigStore config) throws EBaseException {
 
         mTimeout = 0;
         mSource = source;
         mDest = dest;
-        mFactory = new JssSSLSocketFactory(nickName);
+        mFactory = new JssSSLSocketFactory(nickName, clientCiphers);
 
         int minConns = config.getInteger("minHttpConns", 1);
         int maxConns = config.getInteger("maxHttpConns", 15);
@@ -64,7 +64,7 @@ public class HttpConnector implements IConnector {
         CMS.debug("HttpConn: max " + maxConns);
 
         try {
-            mConnFactory = new HttpConnFactory(minConns, maxConns, source, dest, nickName, 0);
+            mConnFactory = new HttpConnFactory(minConns, maxConns, source, dest, nickName, clientCiphers, 0);
         } catch (EBaseException e) {
             CMS.debug("can't create new HttpConnFactory " + e.toString());
         }
@@ -72,17 +72,17 @@ public class HttpConnector implements IConnector {
         //        mConn = CMS.getHttpConnection(dest, mFactory);
         // this will start resending past requests in parallel.
         if (resendInterval >= 0) {
-            mResender = CMS.getResender(mSource, nickName, dest, resendInterval);
+            mResender = CMS.getResender(mSource, nickName, clientCiphers, dest, resendInterval);
         }
     }
 
     // Inserted by beomsuk
-    public HttpConnector(IAuthority source, String nickName,
+    public HttpConnector(IAuthority source, String nickName, String clientCiphers,
             IRemoteAuthority dest, int resendInterval, IConfigStore config, int timeout) throws EBaseException {
         mSource = source;
         mDest = dest;
         mTimeout = timeout;
-        mFactory = new JssSSLSocketFactory(nickName);
+        mFactory = new JssSSLSocketFactory(nickName, clientCiphers);
 
         int minConns = config.getInteger("minHttpConns", 1);
         int maxConns = config.getInteger("maxHttpConns", 15);
@@ -91,14 +91,14 @@ public class HttpConnector implements IConnector {
         CMS.debug("HttpConn: max " + maxConns);
 
         try {
-            mConnFactory = new HttpConnFactory(minConns, maxConns, source, dest, nickName, timeout);
+            mConnFactory = new HttpConnFactory(minConns, maxConns, source, dest, nickName, clientCiphers, timeout);
         } catch (EBaseException e) {
             CMS.debug("can't create new HttpConnFactory");
         }
 
         // this will start resending past requests in parallel.
         if (resendInterval >= 0) {
-            mResender = CMS.getResender(mSource, nickName, dest, resendInterval);
+            mResender = CMS.getResender(mSource, nickName, clientCiphers, dest, resendInterval);
         }
     }
 
diff --git a/base/server/cmscore/src/com/netscape/cmscore/connector/Resender.java b/base/server/cmscore/src/com/netscape/cmscore/connector/Resender.java
index a949b993e4765d02b5c8d5a327b4a1740417309f..e6d9ceda771b812802673a5c69659d86d0dc403b 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/connector/Resender.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/connector/Resender.java
@@ -57,6 +57,7 @@ public class Resender implements IResender {
     protected HttpConnection mConn = null;
 
     protected String mNickName = null;
+    protected String mClientCiphers = null;
     protected boolean connected = false;
 
     // default interval.
@@ -64,20 +65,22 @@ public class Resender implements IResender {
     // was down (versus being serviced in request queue)
     protected int mInterval = 1 * MINUTE;
 
-    public Resender(IAuthority authority, String nickName, IRemoteAuthority dest) {
+    public Resender(IAuthority authority, String nickName, String clientCiphers, IRemoteAuthority dest) {
         mAuthority = authority;
         mQueue = mAuthority.getRequestQueue();
         mDest = dest;
         mNickName = nickName;
+        mClientCiphers = clientCiphers;
     }
 
     public Resender(
-            IAuthority authority, String nickName,
+            IAuthority authority, String nickName, String clientCiphers,
             IRemoteAuthority dest, int interval) {
         mAuthority = authority;
         mQueue = mAuthority.getRequestQueue();
         mDest = dest;
         mNickName = nickName;
+        mClientCiphers = clientCiphers;
         if (interval > 0)
             mInterval = interval; // interval specified in seconds.
     }
@@ -124,7 +127,7 @@ public class Resender implements IResender {
 
         if (! connected) {
             CMS.debug("Connecting ...");
-            mConn = new HttpConnection(mDest, new JssSSLSocketFactory(mNickName));
+            mConn = new HttpConnection(mDest, new JssSSLSocketFactory(mNickName, mClientCiphers));
             initRequests();
             connected = true;
         }
diff --git a/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java b/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java
index 36a263e9248e8d3beb90b6abaf149cd7a32f0b34..b45b33b5feb57eaa510b3b2d239152cb48c6e740 100644
--- a/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java
+++ b/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java
@@ -509,7 +509,7 @@ public class CMSEngineDefaultStub implements ICMSEngine {
         return null;
     }
 
-    public IResender getResender(IAuthority authority, String nickname, IRemoteAuthority remote, int interval) {
+    public IResender getResender(IAuthority authority, String nickname, String clientCiphers, IRemoteAuthority remote, int interval) {
         return null;
     }
 
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/ConnectionManager.java b/base/tps/src/org/dogtagpki/server/tps/cms/ConnectionManager.java
index 2b5ab220895ec991fe548e7136be26c01ac955a6..692d4ba8788244f711d7e7e1c666705fc4840b3f 100644
--- a/base/tps/src/org/dogtagpki/server/tps/cms/ConnectionManager.java
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/ConnectionManager.java
@@ -178,6 +178,12 @@ public class ConnectionManager
             CMS.debug("ConnectionManager: createConnector(): nickName not found in config");
             throw new EBaseException("nickName not found in config");
         }
+        /*
+         * if tps.connector.<ca>.clientCiphers is specified, it will
+         * override the default;  If it is not specified, default will
+         * be used.
+         */
+        String clientCiphers = conf.getString("clientCiphers", null);
 
         // "resendInterval" is for Request Queue, and not supported in TPS
         int resendInterval = -1;
@@ -188,10 +194,10 @@ public class ConnectionManager
         CMS.debug("ConnectionManager: createConnector(): establishing HttpConnector");
         if (timeout == 0) {
             connector =
-                    new HttpConnector(null, nickname, remauthority, resendInterval, conf);
+                    new HttpConnector(null, nickname, clientCiphers, remauthority, resendInterval, conf);
         } else {
             connector =
-                    new HttpConnector(null, nickname, remauthority, resendInterval, conf, timeout);
+                    new HttpConnector(null, nickname, clientCiphers, remauthority, resendInterval, conf, timeout);
         }
 
         CMS.debug("ConnectionManager: createConnector(): ends.");
diff --git a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
index 8ef96d564de166002c73c8e78139bf3919ad870f..2a3f95528251a326d8e66e44fa10e527d0c87f7f 100644
--- a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
+++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
@@ -132,6 +132,7 @@ import org.mozilla.jss.util.Password;
 
 import com.netscape.cmsutil.util.Cert;
 import com.netscape.cmsutil.util.Utils;
+
 @SuppressWarnings("serial")
 public class CryptoUtil {
 
@@ -692,6 +693,242 @@ public class CryptoUtil {
         return pair;
     }
 
+
+    private static HashMap<String, Integer> cipherMap = new HashMap<String, Integer>();
+    static {
+        // SSLv2
+        cipherMap.put("SSL2_RC4_128_WITH_MD5", SSLSocket.SSL2_RC4_128_WITH_MD5);
+        cipherMap.put("SSL2_RC4_128_EXPORT40_WITH_MD5",
+                SSLSocket.SSL2_RC4_128_EXPORT40_WITH_MD5);
+        cipherMap.put("SSL2_RC2_128_CBC_WITH_MD5",
+                SSLSocket.SSL2_RC2_128_CBC_WITH_MD5);
+        cipherMap.put("SSL2_RC2_128_CBC_EXPORT40_WITH_MD5",
+                SSLSocket.SSL2_RC2_128_CBC_EXPORT40_WITH_MD5);
+        cipherMap.put("SSL2_IDEA_128_CBC_WITH_MD5",
+                SSLSocket.SSL2_IDEA_128_CBC_WITH_MD5);
+        cipherMap.put("SSL2_DES_64_CBC_WITH_MD5",
+                SSLSocket.SSL2_DES_64_CBC_WITH_MD5);
+        cipherMap.put("SSL2_DES_192_EDE3_CBC_WITH_MD5",
+                SSLSocket.SSL2_DES_192_EDE3_CBC_WITH_MD5);
+
+        // SSLv3
+        cipherMap.put("SSL3_RSA_WITH_NULL_MD5",
+                SSLSocket.SSL3_RSA_WITH_NULL_MD5);
+        cipherMap.put("SSL3_RSA_WITH_NULL_SHA",
+                SSLSocket.SSL3_RSA_WITH_NULL_SHA);
+        cipherMap.put("SSL3_RSA_EXPORT_WITH_RC4_40_MD5",
+                SSLSocket.SSL3_RSA_EXPORT_WITH_RC4_40_MD5);
+        cipherMap.put("SSL3_RSA_WITH_RC4_128_MD5",
+                SSLSocket.SSL3_RSA_WITH_RC4_128_MD5);
+        cipherMap.put("SSL3_RSA_WITH_RC4_128_SHA",
+                SSLSocket.SSL3_RSA_WITH_RC4_128_SHA);
+        cipherMap.put("SSL3_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
+                SSLSocket.SSL3_RSA_EXPORT_WITH_RC2_CBC_40_MD5);
+        cipherMap.put("SSL3_RSA_WITH_IDEA_CBC_SHA",
+                SSLSocket.SSL3_RSA_WITH_IDEA_CBC_SHA);
+        cipherMap.put("SSL3_RSA_EXPORT_WITH_DES40_CBC_SHA",
+                SSLSocket.SSL3_RSA_EXPORT_WITH_DES40_CBC_SHA);
+        cipherMap.put("SSL3_RSA_WITH_DES_CBC_SHA",
+                SSLSocket.SSL3_RSA_WITH_DES_CBC_SHA);
+        cipherMap.put("SSL3_RSA_WITH_3DES_EDE_CBC_SHA",
+                SSLSocket.SSL3_RSA_WITH_3DES_EDE_CBC_SHA);
+
+        cipherMap.put("SSL3_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",
+                SSLSocket.SSL3_DH_DSS_EXPORT_WITH_DES40_CBC_SHA);
+        cipherMap.put("SSL3_DH_DSS_WITH_DES_CBC_SHA",
+                SSLSocket.SSL3_DH_DSS_WITH_DES_CBC_SHA);
+        cipherMap.put("SSL3_DH_DSS_WITH_3DES_EDE_CBC_SHA",
+                SSLSocket.SSL3_DH_DSS_WITH_3DES_EDE_CBC_SHA);
+        cipherMap.put("SSL3_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",
+                SSLSocket.SSL3_DH_RSA_EXPORT_WITH_DES40_CBC_SHA);
+        cipherMap.put("SSL3_DH_RSA_WITH_DES_CBC_SHA",
+                SSLSocket.SSL3_DH_RSA_WITH_DES_CBC_SHA);
+        cipherMap.put("SSL3_DH_RSA_WITH_3DES_EDE_CBC_SHA",
+                SSLSocket.SSL3_DH_RSA_WITH_3DES_EDE_CBC_SHA);
+
+        cipherMap.put("SSL3_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
+                SSLSocket.SSL3_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA);
+        cipherMap.put("SSL3_DHE_DSS_WITH_DES_CBC_SHA",
+                SSLSocket.SSL3_DHE_DSS_WITH_DES_CBC_SHA);
+        cipherMap.put("SSL3_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
+                SSLSocket.SSL3_DHE_DSS_WITH_3DES_EDE_CBC_SHA);
+        cipherMap.put("SSL3_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
+                SSLSocket.SSL3_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA);
+        cipherMap.put("SSL3_DHE_RSA_WITH_DES_CBC_SHA",
+                SSLSocket.SSL3_DHE_RSA_WITH_DES_CBC_SHA);
+        cipherMap.put("SSL3_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+                SSLSocket.SSL3_DHE_RSA_WITH_3DES_EDE_CBC_SHA);
+
+        cipherMap.put("SSL3_DH_ANON_EXPORT_WITH_RC4_40_MD5",
+                SSLSocket.SSL3_DH_ANON_EXPORT_WITH_RC4_40_MD5);
+        cipherMap.put("SSL3_DH_ANON_WITH_RC4_128_MD5",
+                SSLSocket.SSL3_DH_ANON_WITH_RC4_128_MD5);
+        cipherMap.put("SSL3_DH_ANON_EXPORT_WITH_DES40_CBC_SHA",
+                SSLSocket.SSL3_DH_ANON_EXPORT_WITH_DES40_CBC_SHA);
+        cipherMap.put("SSL3_DH_ANON_WITH_DES_CBC_SHA",
+                SSLSocket.SSL3_DH_ANON_WITH_DES_CBC_SHA);
+        cipherMap.put("SSL3_DH_ANON_WITH_3DES_EDE_CBC_SHA",
+                SSLSocket.SSL3_DH_ANON_WITH_3DES_EDE_CBC_SHA);
+
+        cipherMap.put("SSL3_FORTEZZA_DMS_WITH_NULL_SHA",
+                SSLSocket.SSL3_FORTEZZA_DMS_WITH_NULL_SHA);
+        cipherMap.put("SSL3_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA",
+                SSLSocket.SSL3_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA);
+        cipherMap.put("SSL3_FORTEZZA_DMS_WITH_RC4_128_SHA",
+                SSLSocket.SSL3_FORTEZZA_DMS_WITH_RC4_128_SHA);
+
+        cipherMap.put("SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA",
+                SSLSocket.SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA);
+        cipherMap.put("SSL_RSA_FIPS_WITH_DES_CBC_SHA",
+                SSLSocket.SSL_RSA_FIPS_WITH_DES_CBC_SHA);
+
+        // TLS
+        cipherMap.put("TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA",
+                SSLSocket.TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA);
+        cipherMap.put("TLS_RSA_EXPORT1024_WITH_RC4_56_SHA",
+                SSLSocket.TLS_RSA_EXPORT1024_WITH_RC4_56_SHA);
+
+        cipherMap.put("TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA",
+                SSLSocket.TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA);
+        cipherMap.put("TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA",
+                SSLSocket.TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA);
+        cipherMap.put("TLS_DHE_DSS_WITH_RC4_128_SHA",
+                SSLSocket.TLS_DHE_DSS_WITH_RC4_128_SHA);
+
+        cipherMap.put("TLS_RSA_WITH_AES_128_CBC_SHA",
+                SSLSocket.TLS_RSA_WITH_AES_128_CBC_SHA);
+        cipherMap.put("TLS_DH_DSS_WITH_AES_128_CBC_SHA",
+                SSLSocket.TLS_DH_DSS_WITH_AES_128_CBC_SHA);
+        cipherMap.put("TLS_DH_RSA_WITH_AES_128_CBC_SHA",
+                SSLSocket.TLS_DH_RSA_WITH_AES_128_CBC_SHA);
+        cipherMap.put("TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+                SSLSocket.TLS_DHE_DSS_WITH_AES_128_CBC_SHA);
+        cipherMap.put("TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+                SSLSocket.TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
+        cipherMap.put("TLS_DH_ANON_WITH_AES_128_CBC_SHA",
+                SSLSocket.TLS_DH_ANON_WITH_AES_128_CBC_SHA);
+
+        cipherMap.put("TLS_RSA_WITH_AES_256_CBC_SHA",
+                SSLSocket.TLS_RSA_WITH_AES_256_CBC_SHA);
+        cipherMap.put("TLS_DH_DSS_WITH_AES_256_CBC_SHA",
+                SSLSocket.TLS_DH_DSS_WITH_AES_256_CBC_SHA);
+        cipherMap.put("TLS_DH_RSA_WITH_AES_256_CBC_SHA",
+                SSLSocket.TLS_DH_RSA_WITH_AES_256_CBC_SHA);
+        cipherMap.put("TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
+                SSLSocket.TLS_DHE_DSS_WITH_AES_256_CBC_SHA);
+        cipherMap.put("TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
+                SSLSocket.TLS_DHE_RSA_WITH_AES_256_CBC_SHA);
+        cipherMap.put("TLS_DH_ANON_WITH_AES_256_CBC_SHA",
+                SSLSocket.TLS_DH_ANON_WITH_AES_256_CBC_SHA);
+
+        // ECC
+        cipherMap.put("TLS_ECDH_ECDSA_WITH_NULL_SHA",
+                SSLSocket.TLS_ECDH_ECDSA_WITH_NULL_SHA);
+        cipherMap.put("TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
+                SSLSocket.TLS_ECDH_ECDSA_WITH_RC4_128_SHA);
+        cipherMap.put("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
+                SSLSocket.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA);
+        cipherMap.put("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
+                SSLSocket.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA);
+        cipherMap.put("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
+                SSLSocket.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA);
+
+        cipherMap.put("TLS_ECDHE_ECDSA_WITH_NULL_SHA",
+                SSLSocket.TLS_ECDHE_ECDSA_WITH_NULL_SHA);
+        cipherMap.put("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
+                SSLSocket.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA);
+        cipherMap.put("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
+                SSLSocket.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA);
+        cipherMap.put("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+                SSLSocket.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA);
+        cipherMap.put("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
+                SSLSocket.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA);
+
+        cipherMap.put("TLS_ECDHE_RSA_WITH_NULL_SHA",
+                SSLSocket.TLS_ECDHE_RSA_WITH_NULL_SHA);
+        cipherMap.put("TLS_ECDHE_RSA_WITH_RC4_128_SHA",
+                SSLSocket.TLS_ECDHE_RSA_WITH_RC4_128_SHA);
+        cipherMap.put("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
+                SSLSocket.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA);
+        cipherMap.put("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
+                SSLSocket.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA);
+        cipherMap.put("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
+                SSLSocket.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA);
+
+        cipherMap.put("TLS_ECDH_anon_WITH_NULL_SHA",
+                SSLSocket.TLS_ECDH_anon_WITH_NULL_SHA);
+        cipherMap.put("TLS_ECDH_anon_WITH_RC4_128_SHA",
+                SSLSocket.TLS_ECDH_anon_WITH_RC4_128_SHA);
+        cipherMap.put("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
+                SSLSocket.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA);
+        cipherMap.put("TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
+                SSLSocket.TLS_ECDH_anon_WITH_AES_128_CBC_SHA);
+        cipherMap.put("TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
+                SSLSocket.TLS_ECDH_anon_WITH_AES_256_CBC_SHA);
+
+        // TLSv1_2
+        cipherMap.put("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
+                SSLSocket.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256);
+        cipherMap.put("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
+                SSLSocket.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256);
+        cipherMap.put("TLS_RSA_WITH_NULL_SHA256",
+                SSLSocket.TLS_RSA_WITH_NULL_SHA256);
+        cipherMap.put("TLS_RSA_WITH_AES_128_CBC_SHA256",
+                SSLSocket.TLS_RSA_WITH_AES_128_CBC_SHA256);
+        cipherMap.put("TLS_RSA_WITH_AES_256_CBC_SHA256",
+                SSLSocket.TLS_RSA_WITH_AES_256_CBC_SHA256);
+        cipherMap.put("TLS_RSA_WITH_SEED_CBC_SHA",
+                SSLSocket.TLS_RSA_WITH_SEED_CBC_SHA);
+        cipherMap.put("TLS_RSA_WITH_AES_128_GCM_SHA256",
+                SSLSocket.TLS_RSA_WITH_AES_128_GCM_SHA256);
+        cipherMap.put("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
+                SSLSocket.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256);
+        cipherMap.put("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
+                SSLSocket.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256);
+        cipherMap.put("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+                SSLSocket.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256);
+        cipherMap.put("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+                SSLSocket.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256);
+        cipherMap.put("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+                SSLSocket.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256);
+        cipherMap.put("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
+                SSLSocket.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256);
+        cipherMap.put("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+                SSLSocket.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256);
+        cipherMap.put("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
+                SSLSocket.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256);
+
+    }
+
+
+    // if clientOverrideCiphers is provided in config, use it
+    public static void setClientCiphers(String clientOverrideCiphers)
+            throws SocketException {
+        if (clientOverrideCiphers != null) {
+            String strCiphers[] = clientOverrideCiphers.split(",");
+            if (strCiphers.length != 0) {
+                unsetSSLCiphers();
+                int cipherid;
+                for (int i=0; i< strCiphers.length; i++) {
+                    Object mapValue;
+
+                    mapValue = cipherMap.get(strCiphers[i]);
+                    if (mapValue == null) {
+                        cipherid = 0;
+                    } else {
+                        cipherid = (Integer) mapValue;
+                    }
+                    if (cipherid != 0) {
+                        SSLSocket.setCipherPreferenceDefault(cipherid, true);
+                    }
+                }
+            }
+            return;
+        } else { //use default
+            setClientCiphers();
+        }
+    }
+
     public static void setClientCiphers()
             throws SocketException {
         int ciphers[] = SSLSocket.getImplementedCipherSuites();
@@ -720,6 +957,19 @@ public class CryptoUtil {
         }
     }
 
+    /*
+     * unset all implemented cipehrs; for enforcing strict list of ciphers
+     */
+    private static void unsetSSLCiphers() throws SocketException {
+        int ciphers[] = SSLSocket.getImplementedCipherSuites();
+        try {
+            for (int i = 0; ciphers != null && i < ciphers.length; i++) {
+                SSLSocket.setCipherPreferenceDefault(ciphers[i], false);
+            }
+        } catch (Exception e) {
+        }
+    }
+
     public static byte[] getModulus(PublicKey pubk) {
         RSAPublicKey rsaKey = (RSAPublicKey) pubk;
 
diff --git a/base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java b/base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java
index 8c70480e289e19729505659368aa2a193108ab0d..eaed8216745d9c5b62f6bba3b3b354aaed694029 100644
--- a/base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java
+++ b/base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java
@@ -29,6 +29,7 @@ import org.mozilla.jss.ssl.SSLHandshakeCompletedListener;
 import org.mozilla.jss.ssl.SSLSocket;
 
 import com.netscape.cmsutil.net.ISocketFactory;
+import com.netscape.cmsutil.crypto.CryptoUtil;
 
 /**
  * Uses NSS ssl socket.
@@ -37,6 +38,7 @@ import com.netscape.cmsutil.net.ISocketFactory;
  */
 public class JssSSLSocketFactory implements ISocketFactory {
     private String mClientAuthCertNickname = null;
+    private String mClientCiphers = null;
     private SSLSocket s = null;
 
     public JssSSLSocketFactory() {
@@ -46,6 +48,14 @@ public class JssSSLSocketFactory implements ISocketFactory {
         mClientAuthCertNickname = certNickname;
     }
 
+    public JssSSLSocketFactory(String certNickname, String ciphers) {
+        if (certNickname != null)
+            mClientAuthCertNickname = certNickname;
+
+        if (ciphers != null)
+            mClientCiphers = ciphers;
+    }
+
     public Socket makeSocket(String host, int port)
             throws IOException, UnknownHostException {
         return makeSocket(host, port, null, null, 0);
@@ -60,7 +70,10 @@ public class JssSSLSocketFactory implements ISocketFactory {
         try {
             /*
              * let inherit tls range and cipher settings
+             * unless it's overwritten by config
              */
+            if (mClientCiphers != null)
+                CryptoUtil.setClientCiphers(mClientCiphers);
             s = new SSLSocket(host, port, null, 0, certApprovalCallback,
                     clientCertCallback);
             s.setUseClientMode(true);
-- 
1.8.4.2

