diff --git a/SOURCES/pki-core-added-global-TCP-Keep-Alive-option.patch b/SOURCES/pki-core-added-global-TCP-Keep-Alive-option.patch
new file mode 100644
index 0000000..5693769
--- /dev/null
+++ b/SOURCES/pki-core-added-global-TCP-Keep-Alive-option.patch
@@ -0,0 +1,779 @@
+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;
+     }
diff --git a/SOURCES/pki-core-added-option-to-remove-signing-cert-entry.patch b/SOURCES/pki-core-added-option-to-remove-signing-cert-entry.patch
new file mode 100644
index 0000000..dabd033
--- /dev/null
+++ b/SOURCES/pki-core-added-option-to-remove-signing-cert-entry.patch
@@ -0,0 +1,193 @@
+commit 1dbe79d48ac48d320fb0d2cac0f20329846cdbb1
+Author: Ade Lee <alee@redhat.com>
+Date:   Fri Jan 20 11:01:41 2017 -0500
+
+    Add option to remove signing cert entry
+    
+    In the migration case, it is useful to delete the initially
+    created signing certificate database record and have that be
+    imported through the ldif data import instead.
+    
+    Therefore, we add an option to remove this entry.  The user
+    also needs to provide the serial number for the entry.
+    
+    This resolves the following tickets/BZs:
+    BZ# 1409949/Trac 2573 - CA Certificate Issuance Date displayed
+       on CA website incorrect
+    BZ# 1409946/Trac 2571 -  Request ID undefined for CA signing
+       certificate
+    
+    (cherry picked from commit 049a4e3e09328bfcdff62dc189ad95917647fb22)
+    (cherry picked from commit 42bc6fc8eeef3c8bea036a7fc327696983dcf17c)
+
+diff --git a/base/ca/src/org/dogtagpki/server/ca/rest/CAInstallerService.java b/base/ca/src/org/dogtagpki/server/ca/rest/CAInstallerService.java
+index 3c7e483..309f68d 100644
+--- a/base/ca/src/org/dogtagpki/server/ca/rest/CAInstallerService.java
++++ b/base/ca/src/org/dogtagpki/server/ca/rest/CAInstallerService.java
+@@ -24,8 +24,7 @@ import java.net.MalformedURLException;
+ import java.net.URL;
+ import java.util.StringTokenizer;
+ 
+-import netscape.ldap.LDAPAttribute;
+-
++import org.apache.commons.lang.StringUtils;
+ import org.dogtagpki.server.rest.SystemConfigService;
+ 
+ import com.netscape.certsrv.apps.CMS;
+@@ -41,6 +40,10 @@ import com.netscape.cms.servlet.csadmin.ConfigurationUtils;
+ import com.netscape.cmscore.base.LDAPConfigStore;
+ import com.netscape.cmscore.profile.LDAPProfileSubsystem;
+ 
++import netscape.ldap.LDAPAttribute;
++import netscape.ldap.LDAPConnection;
++import netscape.ldap.LDAPException;
++
+ /**
+  * @author alee
+  *
+@@ -93,6 +96,19 @@ public class CAInstallerService extends SystemConfigService {
+             CMS.debug(e);
+             throw new PKIException("Error enabling profile subsystem");
+         }
++
++        if (! request.createSigningCertRecord()) {
++            // This is the migration case.  In this case, we will delete the
++            // record that was created during the install process.
++
++            try {
++                String serialNumber = request.getSigningCertSerialNumber();
++                deleteSigningRecord(serialNumber);
++            } catch (Exception e) {
++                CMS.debug(e);
++                throw new PKIException("Error deleting signing cert record:" + e, e);
++            }
++        }
+     }
+ 
+     @Override
+@@ -189,9 +205,37 @@ public class CAInstallerService extends SystemConfigService {
+         configStore.commit(false /* no backup */);
+     }
+ 
++    private void deleteSigningRecord(String serialNumber) throws EBaseException, LDAPException {
++
++        if (StringUtils.isEmpty(serialNumber)) {
++            throw new PKIException("signing certificate serial number not specified in configuration request");
++        }
++
++        LDAPConnection conn = null;
++        try {
++            IConfigStore dbCfg = cs.getSubStore("internaldb");
++            ILdapConnFactory dbFactory = CMS.getLdapBoundConnFactory("CAInstallerService");
++            dbFactory.init(dbCfg);
++            conn = dbFactory.getConn();
++
++            String basedn = dbCfg.getString("basedn", "");
++            String dn = "cn=" + serialNumber + ",ou=certificateRepository,ou=ca," + basedn;
++
++            conn.delete(dn);
++        } finally {
++            try {
++                if (conn != null)
++                    conn.disconnect();
++            } catch (LDAPException e) {
++                CMS.debug(e);
++                CMS.debug("releaseConnection: " + e);
++            }
++        }
++    }
++
+     private void configureStartingCRLNumber(ConfigurationRequest data) {
+         CMS.debug("CAInstallerService:configureStartingCRLNumber entering.");
+-        cs.putString("ca.crl.MasterCRL.startingCrlNumber",data.getStartingCRLNumber() );
++        cs.putString("ca.crl.MasterCRL.startingCrlNumber",data.getStartingCRLNumber());
+ 
+     }
+     private void disableCRLCachingAndGenerationForClone(ConfigurationRequest data) throws MalformedURLException {
+diff --git a/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java b/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java
+index cd9d3c8..5d69200 100644
+--- a/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java
++++ b/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java
+@@ -237,6 +237,12 @@ public class ConfigurationRequest {
+     @XmlElement
+     protected String startingCRLNumber;
+ 
++    @XmlElement
++    protected Boolean createSigningCertRecord;
++
++    @XmlElement
++    protected String signingCertSerialNumber;
++
+     public ConfigurationRequest() {
+         // required for JAXB
+     }
+@@ -943,6 +949,30 @@ public class ConfigurationRequest {
+         this.startingCRLNumber = startingCRLNumber;
+     }
+ 
++    public String getIsClone() {
++        return isClone;
++    }
++
++    public void setIsClone(String isClone) {
++        this.isClone = isClone;
++    }
++
++    public Boolean createSigningCertRecord() {
++        return createSigningCertRecord;
++    }
++
++    public void setCreateSigningCertRecord(Boolean createSigningCertRecord) {
++        this.createSigningCertRecord = createSigningCertRecord;
++    }
++
++    public String getSigningCertSerialNumber() {
++        return signingCertSerialNumber;
++    }
++
++    public void setSigningCertSerialNumber(String signingCertSerialNumber) {
++        this.signingCertSerialNumber = signingCertSerialNumber;
++    }
++
+     @Override
+     public String toString() {
+         return "ConfigurationRequest [pin=XXXX" +
+@@ -1007,6 +1037,8 @@ public class ConfigurationRequest {
+                ", subordinateSecurityDomainName=" + subordinateSecurityDomainName +
+                ", reindexData=" + reindexData +
+                ", startingCrlNumber=" + startingCRLNumber +
++               ", createSigningCertRecord=" + createSigningCertRecord +
++               ", signingCertSerialNumber=" + signingCertSerialNumber +
+                "]";
+     }
+ 
+diff --git a/base/server/etc/default.cfg b/base/server/etc/default.cfg
+index e79ff06..cd506cc 100644
+--- a/base/server/etc/default.cfg
++++ b/base/server/etc/default.cfg
+@@ -291,6 +291,8 @@ pki_ca_signing_key_algorithm=SHA256withRSA
+ pki_ca_signing_key_size=2048
+ pki_ca_signing_key_type=rsa
+ pki_ca_signing_nickname=caSigningCert cert-%(pki_instance_name)s CA
++pki_ca_signing_record_create=True
++pki_ca_signing_serial_number=1
+ pki_ca_signing_signing_algorithm=SHA256withRSA
+ pki_ca_signing_subject_dn=cn=CA Signing Certificate,ou=%(pki_instance_name)s,o=%(pki_security_domain_name)s
+ pki_ca_signing_token=
+diff --git a/base/server/python/pki/server/deployment/pkihelper.py b/base/server/python/pki/server/deployment/pkihelper.py
+index b6eacf1..f77c21a 100644
+--- a/base/server/python/pki/server/deployment/pkihelper.py
++++ b/base/server/python/pki/server/deployment/pkihelper.py
+@@ -4095,6 +4095,12 @@ class ConfigClient:
+         # Misc CA parameters
+         if self.subsystem == "CA":
+             data.startingCRLNumber = self.mdict['pki_ca_starting_crl_number']
++            data.createSigningCertRecord = (
++                self.mdict['pki_ca_signing_record_create'].lower()
++            )
++            data.signingCertSerialNumber = (
++                self.mdict['pki_ca_signing_serial_number'].lower()
++            )
+ 
+         return data
+ 
diff --git a/SOURCES/pki-core-added-upgrade-script-to-update-AJP-localhost.patch b/SOURCES/pki-core-added-upgrade-script-to-update-AJP-localhost.patch
new file mode 100644
index 0000000..9e48d0b
--- /dev/null
+++ b/SOURCES/pki-core-added-upgrade-script-to-update-AJP-localhost.patch
@@ -0,0 +1,83 @@
+commit 219c633d2aae2ae81724d4588e6aaf6969603ebb
+Author: Endi S. Dewata <edewata@redhat.com>
+Date:   Thu Jan 19 21:43:24 2017 +0100
+
+    Added upgrade script to update AJP loopback address.
+    
+    An upgrade script has been added to replace IPv4- and IPv6-specific
+    AJP loopback address with a more generic "localhost" in existing
+    instances.
+    
+    https://fedorahosted.org/pki/ticket/2570
+    
+    (cherry picked from commit cb839206d6c1d562e2e4385f6822c7934e9455c6)
+    (cherry picked from commit 6b8c54d29cfc4f448566f50cb27a40eda07052ca)
+
+diff --git a/base/server/upgrade/10.3.5/03-UpdateAJPLoopbackAddress b/base/server/upgrade/10.3.5/03-UpdateAJPLoopbackAddress
+new file mode 100755
+index 0000000..b7d5c0e
+--- /dev/null
++++ b/base/server/upgrade/10.3.5/03-UpdateAJPLoopbackAddress
+@@ -0,0 +1,62 @@
++#!/usr/bin/python
++# Authors:
++#     Endi S. Dewata <edewata@redhat.com>
++#
++# 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.
++#
++# Copyright (C) 2017 Red Hat, Inc.
++# All rights reserved.
++#
++
++from __future__ import absolute_import
++import os
++from lxml import etree
++
++import pki
++
++
++class UpdateAJPLoopbackAddress(
++        pki.server.upgrade.PKIServerUpgradeScriptlet):
++
++    def __init__(self):
++        super(UpdateAJPLoopbackAddress, self).__init__()
++        self.message = 'Update AJP loopback address'
++
++        self.parser = etree.XMLParser(remove_blank_text=True)
++
++    def upgrade_instance(self, instance):
++
++        server_xml = os.path.join(instance.conf_dir, 'server.xml')
++        self.backup(server_xml)
++
++        document = etree.parse(server_xml, self.parser)
++
++        server = document.getroot()
++        connectors = server.findall('.//Connector')
++
++        # replace IPv4- or IPv6-specific AJP loopback address with localhost
++        for connector in connectors:
++
++            protocol = connector.get('protocol')
++            if protocol != 'AJP/1.3':
++                continue
++
++            address = connector.get('address')
++            if address != '127.0.0.1' and address != '::1':
++                continue
++
++            connector.set('address', 'localhost')
++
++        with open(server_xml, 'wb') as f:
++            document.write(f, pretty_print=True, encoding='utf-8')
diff --git a/SOURCES/pki-core-fixed-problem-searching-for-latest-cert-req.patch b/SOURCES/pki-core-fixed-problem-searching-for-latest-cert-req.patch
new file mode 100644
index 0000000..e546a5f
--- /dev/null
+++ b/SOURCES/pki-core-fixed-problem-searching-for-latest-cert-req.patch
@@ -0,0 +1,35 @@
+commit e1ae89e9f110cf4af75f6ea82a38a9ce085617ac
+Author: Endi S. Dewata <edewata@redhat.com>
+Date:   Thu Jan 26 23:38:53 2017 +0100
+
+    Fixed problem searching the latest certificate request.
+    
+    Previously if a certificate request page only has one entry the
+    entry itself will be removed from the page, resulting in a blank
+    page.
+    
+    The QueryReq.trim() has been modified not to remove the marker
+    entry if it's the only entry in the page.
+    
+    https://fedorahosted.org/pki/ticket/2450
+    
+    (cherry picked from commit 755fb2834d22131628ad1929c1bd4b1cd7592203)
+    (cherry picked from commit 196ae21e55a3210ef9db1ad6b8c84d64d4d1959e)
+
+diff --git a/base/server/cms/src/com/netscape/cms/servlet/request/QueryReq.java b/base/server/cms/src/com/netscape/cms/servlet/request/QueryReq.java
+index d05da10..376349b 100644
+--- a/base/server/cms/src/com/netscape/cms/servlet/request/QueryReq.java
++++ b/base/server/cms/src/com/netscape/cms/servlet/request/QueryReq.java
+@@ -503,6 +503,12 @@ public class QueryReq extends CMSServlet {
+      */
+     private void trim(Vector<IRequest> v, RequestId marker) {
+         int i = v.size() - 1;
++
++        if (i == 0) {
++            // do not remove the only element in the list
++            return;
++        }
++
+         if (v.elementAt(i).getRequestId().toString().equals(
+                 marker.toString())) {
+             v.remove(i);
diff --git a/SOURCES/pki-core-javadoc-special-characters.patch b/SOURCES/pki-core-javadoc-special-characters.patch
new file mode 100644
index 0000000..0e43e3e
--- /dev/null
+++ b/SOURCES/pki-core-javadoc-special-characters.patch
@@ -0,0 +1,26 @@
+commit ef0710a1b4f1e49aba7877eb90c8274a25240afd
+Author: Endi S. Dewata <edewata@redhat.com>
+Date:   Tue Jan 24 22:00:12 2017 +0100
+
+    Fixed Javadoc failure caused by HTML special characters.
+    
+    The CMSTemplate has been fixed to escape HTML special characters
+    in method documentation.
+    
+    Fixes: https://fedorahosted.org/pki/ticket/2579
+    (cherry picked from commit 8c6707f1117e56c68d147e0b37c018efa3c81fb2)
+    (cherry picked from commit 423c986c57a0baacf1dc8d817dc8b356b9cf0d06)
+
+diff --git a/base/server/cms/src/com/netscape/cms/servlet/common/CMSTemplate.java b/base/server/cms/src/com/netscape/cms/servlet/common/CMSTemplate.java
+index ba4e840..fe5a14b 100644
+--- a/base/server/cms/src/com/netscape/cms/servlet/common/CMSTemplate.java
++++ b/base/server/cms/src/com/netscape/cms/servlet/common/CMSTemplate.java
+@@ -343,7 +343,7 @@ public class CMSTemplate extends CMSFile {
+ 
+     /**
+      * Escape the contents of src string in preparation to be enclosed in
+-     * double quotes as a JavaScript String Literal within an <script>
++     * double quotes as a JavaScript String Literal within an &lt;script&gt;
+      * portion of an HTML document.
+      * stevep - performance improvements - about 4 times faster than before.
+      */
diff --git a/SOURCES/pki-core-omit-parameter-field-from-ECDSA-certs-Alg-IDs.patch b/SOURCES/pki-core-omit-parameter-field-from-ECDSA-certs-Alg-IDs.patch
new file mode 100644
index 0000000..59e0b1e
--- /dev/null
+++ b/SOURCES/pki-core-omit-parameter-field-from-ECDSA-certs-Alg-IDs.patch
@@ -0,0 +1,93 @@
+commit ee6b7ede62f62c6ea4da7fbb88176762a0c1cbc2
+Author: Christina Fu <cfu@dhcp-16-189.sjc.redhat.com>
+Date:   Fri Jan 20 16:01:17 2017 -0800
+
+    Ticket #1741 ECDSA certs Alg IDs contian parameter field
+    Per rfc5758, When the ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384, or ecdsa-with-SHA512 algorithm identifier appears in the algorithm field as an AlgorithmIdentifier, the encoding MUST omit the parameters field.
+    Note: Since we do not support DSA, this patch does not attempt to address them.
+    Also, while we do not claim to support sha224, the patch adds enough code to process the OID just for completeness.  However, it does not attempt to offer it as part of the signing algorithms.
+    
+    (cherry picked from commit 76ca6d1691e56274945b6f03760273208fafd791)
+    (cherry picked from commit 1e567854e643f50a7ca1f24daac0e92359eafe81)
+
+diff --git a/base/util/src/netscape/security/x509/AlgorithmId.java b/base/util/src/netscape/security/x509/AlgorithmId.java
+index 08c9c4f..a89843e 100644
+--- a/base/util/src/netscape/security/x509/AlgorithmId.java
++++ b/base/util/src/netscape/security/x509/AlgorithmId.java
+@@ -230,10 +230,18 @@ public class AlgorithmId implements Serializable, DerEncoder {
+         try (DerOutputStream tmp = new DerOutputStream()) {
+             DerOutputStream bytes = new DerOutputStream();
+             bytes.putOID(algid);
+-            if (params == null)
+-                bytes.putNull();
+-            else
+-                bytes.putDerValue(params);
++
++            // omit parameter field for ECDSA
++            if (!algid.equals(sha224WithEC_oid) &&
++                    !algid.equals(sha256WithEC_oid) &&
++                    !algid.equals(sha384WithEC_oid) &&
++                    !algid.equals(sha512WithEC_oid)) {
++                if (params == null) {
++                    bytes.putNull();
++                } else
++                    bytes.putDerValue(params);
++            }
++
+             tmp.write(DerValue.tag_Sequence, bytes);
+             out.write(tmp.toByteArray());
+         }
+@@ -246,12 +254,19 @@ public class AlgorithmId implements Serializable, DerEncoder {
+     public final byte[] encode() throws IOException {
+         try (DerOutputStream out = new DerOutputStream()) {
+             DerOutputStream bytes = new DerOutputStream();
+-
+             bytes.putOID(algid);
+-            if (params == null)
+-                bytes.putNull();
+-            else
+-                bytes.putDerValue(params);
++
++            // omit parameter field for ECDSA
++            if (!algid.equals(sha224WithEC_oid) &&
++                    !algid.equals(sha256WithEC_oid) &&
++                    !algid.equals(sha384WithEC_oid) &&
++                    !algid.equals(sha512WithEC_oid)) {
++                if (params == null) {
++                    bytes.putNull();
++                } else
++                    bytes.putDerValue(params);
++            }
++
+             out.write(DerValue.tag_Sequence, bytes);
+             return out.toByteArray();
+         }
+@@ -314,6 +329,9 @@ public class AlgorithmId implements Serializable, DerEncoder {
+         if (name.equals("SHA1withEC") || name.equals("SHA1/EC")
+                 || name.equals("1.2.840.10045.4.1"))
+             return AlgorithmId.sha1WithEC_oid;
++        if (name.equals("SHA224withEC") || name.equals("SHA224/EC")
++                || name.equals("1.2.840.10045.4.3.1"))
++            return AlgorithmId.sha224WithEC_oid;
+         if (name.equals("SHA256withEC") || name.equals("SHA256/EC")
+                 || name.equals("1.2.840.10045.4.3.2"))
+             return AlgorithmId.sha256WithEC_oid;
+@@ -646,6 +664,8 @@ public class AlgorithmId implements Serializable, DerEncoder {
+      */
+     private static final int sha1WithEC_data[] =
+                                    { 1, 2, 840, 10045, 4, 1 };
++    private static final int sha224WithEC_data[] =
++                                   { 1, 2, 840, 10045, 4, 3, 1 };
+     private static final int sha256WithEC_data[] =
+                                    { 1, 2, 840, 10045, 4, 3, 2 };
+     private static final int sha384WithEC_data[] =
+@@ -676,6 +696,9 @@ public class AlgorithmId implements Serializable, DerEncoder {
+     public static final ObjectIdentifier sha1WithEC_oid = new
+             ObjectIdentifier(sha1WithEC_data);
+ 
++    public static final ObjectIdentifier sha224WithEC_oid = new
++            ObjectIdentifier(sha224WithEC_data);
++
+     public static final ObjectIdentifier sha256WithEC_oid = new
+             ObjectIdentifier(sha256WithEC_data);
+ 
diff --git a/SOURCES/pki-core-replace-default-AJP-hostname-with-localhost.patch b/SOURCES/pki-core-replace-default-AJP-hostname-with-localhost.patch
new file mode 100644
index 0000000..081e57b
--- /dev/null
+++ b/SOURCES/pki-core-replace-default-AJP-hostname-with-localhost.patch
@@ -0,0 +1,42 @@
+commit 6dabd74991f54aa827bd38b7e1b50925620535ae
+Author: Endi S. Dewata <edewata@redhat.com>
+Date:   Thu Jan 5 07:28:51 2017 +0100
+
+    Replaced default AJP hostname with generic loopback address.
+    
+    Previously the default AJP hostname was an IPv4 loopback address.
+    To avoid problems in IPv6 environments the default has been
+    changed to a generic "localhost" address. The man page has been
+    updated accordingly.
+    
+    https://fedorahosted.org/pki/ticket/2570
+    
+    (cherry picked from commit 5ec9701229b4945cadcf60d84863521ad8485ca5)
+    (cherry picked from commit 3a49b9b3738befc03914b0a96aad61f9650fb935)
+
+diff --git a/base/server/etc/default.cfg b/base/server/etc/default.cfg
+index 6e9b074..e79ff06 100644
+--- a/base/server/etc/default.cfg
++++ b/base/server/etc/default.cfg
+@@ -198,7 +198,7 @@ pki_subsystem_registry_link=%(pki_subsystem_path)s/registry
+ ##               are MUTUALLY EXCLUSIVE entities!!!                          ##
+ ###############################################################################
+ [Tomcat]
+-pki_ajp_host=127.0.0.1
++pki_ajp_host=localhost
+ pki_ajp_port=8009
+ pki_server_pkcs12_path=
+ pki_server_pkcs12_password=
+diff --git a/base/server/man/man5/pki_default.cfg.5 b/base/server/man/man5/pki_default.cfg.5
+index aaf7b53..1eb4ab9 100644
+--- a/base/server/man/man5/pki_default.cfg.5
++++ b/base/server/man/man5/pki_default.cfg.5
+@@ -86,7 +86,7 @@ Ports for Tomcat subsystems.  Defaults to standard Tomcat ports of 8009 and 8005
+ .TP
+ .B pki_ajp_host
+ .IP
+-Host on which to listen for AJP requests.  Defaults to 127.0.0.1 to listen to local traffic only.
++Host on which to listen for AJP requests.  Defaults to localhost to listen to local traffic only.
+ .TP
+ .B pki_proxy_http_port, pki_proxy_https_port, pki_enable_proxy
+ .IP
diff --git a/SOURCES/pki-core-slf4j-api.patch b/SOURCES/pki-core-slf4j-api.patch
new file mode 100644
index 0000000..5f24d50
--- /dev/null
+++ b/SOURCES/pki-core-slf4j-api.patch
@@ -0,0 +1,25 @@
+commit 6b5c4705cee2ef4ab1ee150ac751f047a408e0cb
+Author: Endi S. Dewata <edewata@redhat.com>
+Date:   Tue Jan 24 21:42:58 2017 +0100
+
+    Fixed missing SLF4J in Javadoc classpath.
+    
+    The CMake script for Javadoc has been fixed to include the missing
+    SLF4J library in the class path.
+    
+    Fixes: https://fedorahosted.org/pki/ticket/2579
+    (cherry picked from commit 69cfd4328504ee78646bb34a551ef5d711ea3f18)
+    (cherry picked from commit eab6f76739e575f8d7a7fb9da7c1e6de3c8e3bfa)
+
+diff --git a/base/javadoc/CMakeLists.txt b/base/javadoc/CMakeLists.txt
+index 1341935..a71270c 100644
+--- a/base/javadoc/CMakeLists.txt
++++ b/base/javadoc/CMakeLists.txt
+@@ -88,6 +88,7 @@ javadoc(pki-javadoc
+         com.netscape.cmsutil
+         org.dogtagpki
+     CLASSPATH
++        ${SLF4J_API_JAR}
+         ${XALAN_JAR} ${XERCES_JAR}
+         ${APACHE_COMMONS_CLI_JAR} ${APACHE_COMMONS_LANG_JAR}
+         ${COMMONS_CODEC_JAR} ${COMMONS_HTTPCLIENT_JAR} ${COMMONS_IO_JAR}
diff --git a/SOURCES/pki-core-use-BigInteger-for-entryUSN.patch b/SOURCES/pki-core-use-BigInteger-for-entryUSN.patch
new file mode 100644
index 0000000..a4a3e19
--- /dev/null
+++ b/SOURCES/pki-core-use-BigInteger-for-entryUSN.patch
@@ -0,0 +1,118 @@
+commit d37d1cb1a2d33d17f15cbf9565a4bba99050e59a
+Author: Fraser Tweedale <ftweedal@redhat.com>
+Date:   Mon Jan 23 17:11:26 2017 +1000
+
+    Use BigInteger for entryUSN
+    
+    Currently we try to parse the entryUSN into an Integer, which wraps
+    the 'int' primitive type.  If entryUSN value is too large to fit in
+    'int', NumberFormatException is raised.
+    
+    Change LDAPProfileSubsystem and CertificateAuthority to use
+    BigInteger for entryUSN values.
+    
+    Fixes: https://fedorahosted.org/pki/ticket/2579
+    (cherry picked from commit 79c6d70a8434cf52f9bac8bfa0367876baccb054)
+    (cherry picked from commit 7727940c7f43161d5a7597756cf01f159b2a72d8)
+
+diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java
+index ae90d3a..9b2ba03 100644
+--- a/base/ca/src/com/netscape/ca/CertificateAuthority.java
++++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java
+@@ -333,7 +333,7 @@ public class CertificateAuthority
+ 
+     /* Maps and sets of entryUSNs and nsUniqueIds for avoiding race
+      * conditions and unnecessary reloads related to replication */
+-    private static TreeMap<AuthorityID,Integer> entryUSNs = new TreeMap<>();
++    private static TreeMap<AuthorityID,BigInteger> entryUSNs = new TreeMap<>();
+     private static TreeMap<AuthorityID,String> nsUniqueIds = new TreeMap<>();
+     private static TreeSet<String> deletedNsUniqueIds = new TreeSet<>();
+ 
+@@ -2904,7 +2904,7 @@ public class CertificateAuthority
+ 
+         LDAPAttribute attr = entry.getAttribute("entryUSN");
+         if (attr != null) {
+-            Integer entryUSN = new Integer(attr.getStringValueArray()[0]);
++            BigInteger entryUSN = new BigInteger(attr.getStringValueArray()[0]);
+             entryUSNs.put(aid, entryUSN);
+             CMS.debug("postCommit: new entryUSN = " + entryUSN);
+         }
+@@ -3270,7 +3270,7 @@ public class CertificateAuthority
+             return;
+         }
+ 
+-        Integer newEntryUSN = null;
++        BigInteger newEntryUSN = null;
+         LDAPAttribute entryUSNAttr = entry.getAttribute("entryUSN");
+         if (entryUSNAttr == null) {
+             CMS.debug("readAuthority: no entryUSN");
+@@ -3287,14 +3287,14 @@ public class CertificateAuthority
+                 // entryUSN attribute being added.
+             }
+         } else {
+-            newEntryUSN = new Integer(entryUSNAttr.getStringValueArray()[0]);
++            newEntryUSN = new BigInteger(entryUSNAttr.getStringValueArray()[0]);
+             CMS.debug("readAuthority: new entryUSN = " + newEntryUSN);
+         }
+ 
+-        Integer knownEntryUSN = entryUSNs.get(aid);
++        BigInteger knownEntryUSN = entryUSNs.get(aid);
+         if (newEntryUSN != null && knownEntryUSN != null) {
+             CMS.debug("readAuthority: known entryUSN = " + knownEntryUSN);
+-            if (newEntryUSN <= knownEntryUSN) {
++            if (newEntryUSN.compareTo(knownEntryUSN) <= 0) {
+                 CMS.debug("readAuthority: data is current");
+                 return;
+             }
+diff --git a/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java b/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java
+index 6dea1a0..348a9ab 100644
+--- a/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java
++++ b/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java
+@@ -19,6 +19,7 @@ package com.netscape.cmscore.profile;
+ 
+ import java.io.ByteArrayInputStream;
+ import java.io.InputStream;
++import java.math.BigInteger;
+ import java.util.Arrays;
+ import java.util.Hashtable;
+ import java.util.LinkedHashMap;
+@@ -64,7 +65,7 @@ public class LDAPProfileSubsystem
+ 
+     /* Map of profileId -> entryUSN for the most recent view
+      * of the profile entry that this instance has seen */
+-    private TreeMap<String,Integer> entryUSNs;
++    private TreeMap<String,BigInteger> entryUSNs;
+ 
+     private TreeMap<String,String> nsUniqueIds;
+ 
+@@ -149,14 +150,14 @@ public class LDAPProfileSubsystem
+         }
+         profileId = LDAPDN.explodeDN(dn, true)[0];
+ 
+-        Integer newEntryUSN = new Integer(
++        BigInteger newEntryUSN = new BigInteger(
+                 ldapProfile.getAttribute("entryUSN").getStringValueArray()[0]);
+         CMS.debug("readProfile: new entryUSN = " + newEntryUSN);
+ 
+-        Integer knownEntryUSN = entryUSNs.get(profileId);
++        BigInteger knownEntryUSN = entryUSNs.get(profileId);
+         if (knownEntryUSN != null) {
+             CMS.debug("readProfile: known entryUSN = " + knownEntryUSN);
+-            if (newEntryUSN <= knownEntryUSN) {
++            if (newEntryUSN.compareTo(knownEntryUSN) <= 0) {
+                 CMS.debug("readProfile: data is current");
+                 return;
+             }
+@@ -327,10 +328,10 @@ public class LDAPProfileSubsystem
+                 return;
+             }
+ 
+-            Integer entryUSN = null;
++            BigInteger entryUSN = null;
+             LDAPAttribute attr = entry.getAttribute("entryUSN");
+             if (attr != null)
+-                entryUSN = new Integer(attr.getStringValueArray()[0]);
++                entryUSN = new BigInteger(attr.getStringValueArray()[0]);
+             entryUSNs.put(id, entryUSN);
+             CMS.debug("commitProfile: new entryUSN = " + entryUSN);
+ 
diff --git a/SPECS/pki-core.spec b/SPECS/pki-core.spec
index 9fbafa5..d2203e0 100644
--- a/SPECS/pki-core.spec
+++ b/SPECS/pki-core.spec
@@ -65,8 +65,8 @@
 
 Name:             pki-core
 Version:          10.3.3
-#Release:          16%{?dist}
-Release:          16.el7_3
+#Release:          17%{?dist}
+Release:          17.el7_3
 Summary:          Certificate System - PKI Core Components
 URL:              http://pki.fedoraproject.org/
 License:          GPLv2
@@ -250,7 +250,7 @@ Patch11:          pki-core-KRA-external-CA-partial-cert-chain.patch
 Patch12:          pki-core-problems-with-FIPS-mode.patch
 Patch13:          pki-core-eliminate-duplicate-classes-in-jars.patch
 Patch14:          pki-core-typo-in-UserPwdDirAuthentication.patch
-## RHCS 9.1.z Batch Update 1
+## RHCS 9.1 (async) Batch Update 1
 #Patch15:          pki-core-token-format-external-reg.patch
 #Patch16:          pki-core-encryption-cert-auto-recovery-damaged-token.patch
 #Patch17:          pki-core-pin-reset-policy.patch
@@ -259,7 +259,7 @@ Patch18:          pki-core-tps-token-setupSecureChannel-fips-mode.patch
 #######################
 ## pki-core-10.3.3-13
 #######################
-## RHCS 9.1.z Batch Update 1
+## RHCS 9.1 (async) Batch Update 1
 ##Patch19:          pki-core-target-agent-approve-list.patch
 ## RHEL 7.3.z Batch Update 1
 Patch20:          pki-core-KRA-key-recovery-via-CLI-in-FIPS-mode.patch
@@ -273,17 +273,32 @@ Patch23:          pki-core-updated-account-info.patch
 Patch24:          pki-core-subordinate-CA-in-HSM-in-FIPS-mode.patch
 Patch25:          pki-core-pkispawn-ecc-key-size-change.patch
 Patch26:          pki-core-log-properties-and-man-pages.patch
-## RHCS 9.1.z Batch Update 2
+## RHCS 9.1 (async) Batch Update 2
 #Patch27:          pki-core-TPS-UI-target-agent-approve-list.patch
 #Patch28:          pki-core-TPS-tokendb-encryption-cert-automatic-recovery.patch
 #######################
 ## pki-core-10.3.3-16
 #######################
-## RHCS 9.1.z Batch Update 2
+## RHCS 9.1 (async) Batch Update 2
 #Patch29:          pki-core-TPS-format-G-and-D-cards.patch
 #Patch30:          pki-core-RHCS-log-properties.patch
 ## RHEL 7.3.z Batch Update 2
 Patch31:          pki-core-BASE-format-G-and-D-cards.patch
+#######################
+## pki-core-10.3.3-17
+#######################
+## RHEL 7.3.z Batch Update 3
+Patch32:          pki-core-replace-default-AJP-hostname-with-localhost.patch
+Patch33:          pki-core-added-global-TCP-Keep-Alive-option.patch
+Patch34:          pki-core-added-upgrade-script-to-update-AJP-localhost.patch
+Patch35:          pki-core-fixed-problem-searching-for-latest-cert-req.patch
+Patch36:          pki-core-omit-parameter-field-from-ECDSA-certs-Alg-IDs.patch
+Patch37:          pki-core-added-option-to-remove-signing-cert-entry.patch
+Patch38:          pki-core-use-BigInteger-for-entryUSN.patch
+Patch39:          pki-core-slf4j-api.patch
+Patch40:          pki-core-javadoc-special-characters.patch
+## RHCS 9.1 (async) Batch Update 3
+#Patch41:          pki-core-reset-cert-status-after-successful-unrevoke.patch
 
 # Obtain version phase number (e. g. - used by "alpha", "beta", etc.)
 #
@@ -929,6 +944,16 @@ This package is a part of the PKI Core used by the Certificate System.
 #%patch29 -p1
 #%patch30 -p1
 %patch31 -p1
+%patch32 -p1
+%patch33 -p1
+%patch34 -p1
+%patch35 -p1
+%patch36 -p1
+%patch37 -p1
+%patch38 -p1
+%patch39 -p1
+%patch40 -p1
+#%patch41 -p1
 
 %clean
 %{__rm} -rf %{buildroot}
@@ -1434,6 +1459,24 @@ systemctl daemon-reload
 %endif # %{with server}
 
 %changelog
+* Mon Jan 30 2017 Dogtag Team <pki-devel@redhat.com> 10.3.3-17
+- ## RHCS 9.1.z Batch Update 3
+- Bugzilla Bug #1391207 - Automatic recovery of encryption cert - CA and TPS
+  tokendb shows different certificate status (cfu)
+- ## RHEL 7.3.z Batch Update 3
+- Bugzilla Bug #1417063 - ECDSA Certificates Generated by Certificate System
+  8.1 fail NIST validation test with parameter field. (cfu)
+- Bugzilla Bug #1417064 - Unable to search certificate requests using the
+  latest request ID (edewata)
+- Bugzilla Bug #1417065 - CA Certificate Issuance Date displayed on CA website
+  incorrect (alee)
+- Bugzilla Bug #1417066 - update to 7.3 IPA with otpd bugfixes, tomcat will
+  not finish start, hangs (ftweedal)
+- Bugzilla Bug #1417067 - pki-tomcat for 10+ minutes before generating cert
+  (edewata)
+- Bugzilla Bug #1417190 - Problem with default AJP hostname in IPv6
+  environment. (edewata)
+
 * Thu Dec 15 2016 Dogtag Team <pki-devel@redhat.com> 10.3.3-16
 - Separate original patches into RHEL and RHCS portions
 - ## RHEL 7.3.z Batch Update 2