diff --git a/SOURCES/pki-core-Display-tokenType-and-tokenOrigin-in-TPS-UI-and-CLI-Server.patch b/SOURCES/pki-core-Display-tokenType-and-tokenOrigin-in-TPS-UI-and-CLI-Server.patch
new file mode 100644
index 0000000..615721b
--- /dev/null
+++ b/SOURCES/pki-core-Display-tokenType-and-tokenOrigin-in-TPS-UI-and-CLI-Server.patch
@@ -0,0 +1,151 @@
+From cf8ba1882bd5349f53d3171824d1eb4c56bc7348 Mon Sep 17 00:00:00 2001
+From: "Endi S. Dewata" <edewata@redhat.com>
+Date: Mon, 28 Aug 2017 23:50:33 +0200
+Subject: [PATCH] Displaying tokenType and tokenOrigin in TPS UI and CLI.
+
+The TPSCertService has been modified to include tokenType and
+tokenOrigin fields in the returned token certificate data. The
+TPS UI and CLI have been modified to display the fields.
+
+https://pagure.io/dogtagpki/issue/2793
+
+Change-Id: I740fa69b81de3033e186f8d99c335814275b7218
+(cherry picked from commit 062c99a9012b2d7b00fabc2d2b565415800ce6a7)
+---
+ .../com/netscape/certsrv/tps/cert/TPSCertData.java | 52 +++++++++++++++++-----
+ .../com/netscape/cmstools/tps/cert/TPSCertCLI.java |  4 +-
+ 2 files changed, 45 insertions(+), 11 deletions(-)
+
+diff --git a/base/common/src/com/netscape/certsrv/tps/cert/TPSCertData.java b/base/common/src/com/netscape/certsrv/tps/cert/TPSCertData.java
+index 7cefc791d..63ea26667 100644
+--- a/base/common/src/com/netscape/certsrv/tps/cert/TPSCertData.java
++++ b/base/common/src/com/netscape/certsrv/tps/cert/TPSCertData.java
+@@ -53,10 +53,12 @@ public class TPSCertData {
+     String id;
+     String serialNumber;
+     String subject;
++    String userID;
+     String tokenID;
++    String origin;
++    String type;
+     String keyType;
+     String status;
+-    String userID;
+     Date createTime;
+     Date modifyTime;
+ 
+@@ -89,6 +91,15 @@ public class TPSCertData {
+         this.subject = subject;
+     }
+ 
++    @XmlElement(name="UserID")
++    public String getUserID() {
++        return userID;
++    }
++
++    public void setUserID(String userID) {
++        this.userID = userID;
++    }
++
+     @XmlElement(name="TokenID")
+     public String getTokenID() {
+         return tokenID;
+@@ -98,6 +109,24 @@ public class TPSCertData {
+         this.tokenID = tokenID;
+     }
+ 
++    @XmlElement(name="Origin")
++    public String getOrigin() {
++        return origin;
++    }
++
++    public void setOrigin(String origin) {
++        this.origin = origin;
++    }
++
++    @XmlElement(name="Type")
++    public String getType() {
++        return type;
++    }
++
++    public void setType(String type) {
++        this.type = type;
++    }
++
+     @XmlElement(name="KeyType")
+     public String getKeyType() {
+         return keyType;
+@@ -116,15 +145,6 @@ public class TPSCertData {
+         this.status = status;
+     }
+ 
+-    @XmlElement(name="UserID")
+-    public String getUserID() {
+-        return userID;
+-    }
+-
+-    public void setUserID(String userID) {
+-        this.userID = userID;
+-    }
+-
+     @XmlElement(name="CreateTime")
+     public Date getCreateTime() {
+         return createTime;
+@@ -161,10 +181,12 @@ public class TPSCertData {
+         result = prime * result + ((keyType == null) ? 0 : keyType.hashCode());
+         result = prime * result + ((link == null) ? 0 : link.hashCode());
+         result = prime * result + ((modifyTime == null) ? 0 : modifyTime.hashCode());
++        result = prime * result + ((origin == null) ? 0 : origin.hashCode());
+         result = prime * result + ((serialNumber == null) ? 0 : serialNumber.hashCode());
+         result = prime * result + ((status == null) ? 0 : status.hashCode());
+         result = prime * result + ((subject == null) ? 0 : subject.hashCode());
+         result = prime * result + ((tokenID == null) ? 0 : tokenID.hashCode());
++        result = prime * result + ((type == null) ? 0 : type.hashCode());
+         result = prime * result + ((userID == null) ? 0 : userID.hashCode());
+         return result;
+     }
+@@ -203,6 +225,11 @@ public class TPSCertData {
+                 return false;
+         } else if (!modifyTime.equals(other.modifyTime))
+             return false;
++        if (origin == null) {
++            if (other.origin != null)
++                return false;
++        } else if (!origin.equals(other.origin))
++            return false;
+         if (serialNumber == null) {
+             if (other.serialNumber != null)
+                 return false;
+@@ -223,6 +250,11 @@ public class TPSCertData {
+                 return false;
+         } else if (!tokenID.equals(other.tokenID))
+             return false;
++        if (type == null) {
++            if (other.type != null)
++                return false;
++        } else if (!type.equals(other.type))
++            return false;
+         if (userID == null) {
+             if (other.userID != null)
+                 return false;
+diff --git a/base/java-tools/src/com/netscape/cmstools/tps/cert/TPSCertCLI.java b/base/java-tools/src/com/netscape/cmstools/tps/cert/TPSCertCLI.java
+index 835a522e1..db6867b2d 100644
+--- a/base/java-tools/src/com/netscape/cmstools/tps/cert/TPSCertCLI.java
++++ b/base/java-tools/src/com/netscape/cmstools/tps/cert/TPSCertCLI.java
+@@ -53,10 +53,12 @@ public class TPSCertCLI extends CLI {
+         System.out.println("  Cert ID: " + cert.getID());
+         if (cert.getSerialNumber() != null) System.out.println("  Serial Number: " + cert.getSerialNumber());
+         if (cert.getSubject() != null) System.out.println("  Subject: " + cert.getSubject());
++        if (cert.getUserID() != null) System.out.println("  User ID: " + cert.getUserID());
+         if (cert.getTokenID() != null) System.out.println("  Token ID: " + cert.getTokenID());
++        if (cert.getOrigin() != null) System.out.println("  Origin: " + cert.getOrigin());
++        if (cert.getType() != null) System.out.println("  Type: " + cert.getType());
+         if (cert.getKeyType() != null) System.out.println("  Key Type: " + cert.getKeyType());
+         if (cert.getStatus() != null) System.out.println("  Status: " + cert.getStatus());
+-        if (cert.getUserID() != null) System.out.println("  User ID: " + cert.getUserID());
+         if (cert.getCreateTime() != null) System.out.println("  Create Time: " + cert.getCreateTime());
+         if (cert.getModifyTime() != null) System.out.println("  Modify Time: " + cert.getModifyTime());
+
+-- 
+2.13.5
+
diff --git a/SOURCES/pki-core-Fix-JSON-encoding-in-Python-3.patch b/SOURCES/pki-core-Fix-JSON-encoding-in-Python-3.patch
new file mode 100644
index 0000000..8ae52e9
--- /dev/null
+++ b/SOURCES/pki-core-Fix-JSON-encoding-in-Python-3.patch
@@ -0,0 +1,59 @@
+From 4e76af1fe276a3b9b1392c97ef427a1ecfa42759 Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Mon, 28 Aug 2017 14:43:55 +1000
+Subject: [PATCH] KeyClient: fix json encoding in Python 3
+
+Fixes: https://pagure.io/dogtagpki/issue/2746
+Change-Id: Iec2912bb90192fec403ac94006ff5927d3526533
+(cherry picked from commit b654e60f20b9e83833313ab89006db8f063bff1f)
+---
+ base/common/python/pki/key.py | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/base/common/python/pki/key.py b/base/common/python/pki/key.py
+index d2b82970e..a5fc7928c 100644
+--- a/base/common/python/pki/key.py
++++ b/base/common/python/pki/key.py
+@@ -668,7 +668,7 @@ class KeyClient(object):
+             raise TypeError("Must specify Client Key ID")
+ 
+         if trans_wrapped_session_key is not None:
+-            twsk = base64.b64encode(trans_wrapped_session_key)
++            twsk = base64.b64encode(trans_wrapped_session_key).decode('ascii')
+             # noinspection PyUnusedLocal
+             request = SymKeyGenerationRequest(
+                 client_key_id=client_key_id,
+@@ -861,9 +861,9 @@ class KeyClient(object):
+         if not nonce_iv:
+             raise TypeError('Missing nonce IV')
+ 
+-        data = base64.b64encode(encrypted_data)
+-        twsk = base64.b64encode(wrapped_session_key)
+-        symkey_params = base64.b64encode(nonce_iv)
++        data = base64.b64encode(encrypted_data).decode('ascii')
++        twsk = base64.b64encode(wrapped_session_key).decode('ascii')
++        symkey_params = base64.b64encode(nonce_iv).decode('ascii')
+ 
+         request = KeyArchivalRequest(client_key_id=client_key_id,
+                                      data_type=data_type,
+@@ -904,7 +904,7 @@ class KeyClient(object):
+         if pki_archive_options is None:
+             raise TypeError("No data provided to be archived")
+ 
+-        data = base64.b64encode(pki_archive_options)
++        data = base64.b64encode(pki_archive_options).decode('ascii')
+         request = KeyArchivalRequest(client_key_id=client_key_id,
+                                      data_type=data_type,
+                                      pki_archive_options=data,
+@@ -1022,7 +1022,7 @@ class KeyClient(object):
+             key_id=key_id,
+             request_id=request_id,
+             trans_wrapped_session_key=base64.b64encode(
+-                trans_wrapped_session_key),
++                trans_wrapped_session_key).decode('ascii'),
+             payload_encryption_oid=self.encrypt_alg_oid,
+             payload_wrapping_name=self.wrap_name
+         )
+-- 
+2.13.5
+
diff --git a/SOURCES/pki-core-Fix-lightweight-CA-replication-NPE-failure.patch b/SOURCES/pki-core-Fix-lightweight-CA-replication-NPE-failure.patch
new file mode 100644
index 0000000..374da35
--- /dev/null
+++ b/SOURCES/pki-core-Fix-lightweight-CA-replication-NPE-failure.patch
@@ -0,0 +1,30 @@
+From 606027b188fee6d20c17323d7c464d6630024a20 Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Wed, 23 Aug 2017 20:53:25 +1000
+Subject: [PATCH] Fix regression in lightweight CA replication
+
+Fixes: https://pagure.io/dogtagpki/issue/2796
+Change-Id: Ic5e42b80156f777299f4e487932305160c2d48f6
+---
+ base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
+index eca8dddb6..2daf0d797 100644
+--- a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
++++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
+@@ -2307,8 +2307,9 @@ public class CryptoUtil {
+         BIT_STRING encSymKey = encVal.getEncSymmKey();
+         BIT_STRING encPrivKey = encVal.getEncValue();
+ 
+-        SymmetricKey sk = unwrap(token, SymmetricKey.Type.DES3, 0, null, unwrappingKey, encSymKey.getBits(),
+-                KeyWrapAlgorithm.RSA);
++        SymmetricKey sk = unwrap(
++                token, SymmetricKey.Type.DES3, 0, SymmetricKey.Usage.UNWRAP,
++                unwrappingKey, encSymKey.getBits(), KeyWrapAlgorithm.RSA);
+ 
+         ASN1Value v = algId.getParameters();
+         v = ((ANY) v).decodeWith(new OCTET_STRING.Template());
+-- 
+2.13.5
+
diff --git a/SOURCES/pki-core-Fix-missing-CN-error-in-CMC-user-signed.patch b/SOURCES/pki-core-Fix-missing-CN-error-in-CMC-user-signed.patch
new file mode 100644
index 0000000..9d0628e
--- /dev/null
+++ b/SOURCES/pki-core-Fix-missing-CN-error-in-CMC-user-signed.patch
@@ -0,0 +1,71 @@
+From ab0cb37875648abfc07e7d781fa91c368f67d313 Mon Sep 17 00:00:00 2001
+From: Christina Fu <cfu@redhat.com>
+Date: Tue, 25 Jul 2017 18:02:02 -0700
+Subject: [PATCH] Ticket #2788 Missing CN in user signing cert would cause
+ error in cmc user-signed This patch takes care of the issue that
+ CMCUserSignedAuth cannot handle cases when CN is not in the subjectDN
+
+Change-Id: Ieac0712d051dcb993498d9680f005c04158b5549
+(cherry picked from commit 507a8888b6eccfe716ca7bc4647f71cee973afcf)
+---
+ .../netscape/cms/authentication/CMCUserSignedAuth.java | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java b/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java
+index e11a34427..7f872c83d 100644
+--- a/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java
++++ b/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java
+@@ -371,9 +371,9 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
+                             } else {
+                                 CMS.debug(method + "signed with user cert");
+                                 userid = userToken.getInString("userid");
+-                                uid = userToken.getInString("cn");
++                                uid = userToken.getInString("id");
+                                 if (userid == null && uid == null) {
+-                                    msg = " verifySignerInfo failure... missing userid and cn";
++                                    msg = " verifySignerInfo failure... missing id";
+                                     CMS.debug(method + msg);
+                                     throw new EBaseException(msg);
+                                 }
+@@ -1069,7 +1069,8 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
+                             // cert subject principal later in CMCOutputTemplate
+                             // in case of user signed revocation
+                             auditContext.put(SessionContext.CMC_SIGNER_PRINCIPAL, cmcPrincipal);
+-                            auditContext.put(SessionContext.CMC_SIGNER_INFO, cmcPrincipal.getCommonName());
++                            auditContext.put(SessionContext.CMC_SIGNER_INFO,
++                                cmcPrincipal.toString());
+ 
+                             // check ssl client cert against cmc signer
+                             if (!clientPrincipal.equals(cmcPrincipal)) {
+@@ -1160,13 +1161,13 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
+ 
+                         IAuthToken tempToken = new AuthToken(null);
+                         netscape.security.x509.X500Name tempPrincipal = (X500Name) x509Certs[0].getSubjectDN();
+-                        String CN = tempPrincipal.getCommonName(); //tempToken.get("userid");
+-                        CMS.debug(method + " Principal name = " + CN);
++                        String ID = tempPrincipal.toString(); //tempToken.get("userid");
++                        CMS.debug(method + " Principal name = " + ID);
+ 
+                         BigInteger certSerial = x509Certs[0].getSerialNumber();
+                         CMS.debug(method + " verified cert serial=" + certSerial.toString());
+                         authToken.set(IAuthManager.CRED_CMC_SIGNING_CERT, certSerial.toString());
+-                        tempToken.set("cn", CN);
++                        tempToken.set("id", ID);
+ 
+                         s.close();
+                         return tempToken;
+@@ -1221,9 +1222,8 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
+         netscape.security.x509.X500Name principal =
+                 (X500Name) cert.getSubjectDN();
+ 
+-        String CN = principal.getCommonName();
+-        CMS.debug(method + " Principal name = " + CN);
+-        auditContext.put(SessionContext.USER_ID, CN);
++        CMS.debug(method + " Principal name = " + principal.toString());
++        auditContext.put(SessionContext.USER_ID, principal.toString());
+     }
+ 
+     public String[] getExtendedPluginInfo(Locale locale) {
+-- 
+2.13.5
+
diff --git a/SOURCES/pki-core-FixDeploymentDescriptor-upgrade-scriptlet.patch b/SOURCES/pki-core-FixDeploymentDescriptor-upgrade-scriptlet.patch
new file mode 100644
index 0000000..38d1c4e
--- /dev/null
+++ b/SOURCES/pki-core-FixDeploymentDescriptor-upgrade-scriptlet.patch
@@ -0,0 +1,34 @@
+From 09b673f3f4bbc5e9b70722bbe240e0347e3dd3fc Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Fri, 11 Aug 2017 15:17:09 +1000
+Subject: [PATCH] Fix FixDeploymentDescriptor upgrade script if source file is
+ missing
+
+On RHEL, the pki#admin.xml file may be absent, causing the
+FixDeploymentDescriptor to break (and subsequent upgrade scriptlets
+to not be executed).  Add a check that the source file exists.
+
+Fixes: https://pagure.io/dogtagpki/issue/2789
+Change-Id: I686e8fae534f8044cb1ce40b31e2462c4f0ac988
+(cherry picked from commit d0a861923a27672d8633c87e21fb8596080e84af)
+---
+ base/server/upgrade/10.3.5/02-FixDeploymentDescriptor | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/base/server/upgrade/10.3.5/02-FixDeploymentDescriptor b/base/server/upgrade/10.3.5/02-FixDeploymentDescriptor
+index 27c895980..858dbed43 100644
+--- a/base/server/upgrade/10.3.5/02-FixDeploymentDescriptor
++++ b/base/server/upgrade/10.3.5/02-FixDeploymentDescriptor
+@@ -46,6 +46,9 @@ class FixDeploymentDescriptor(pki.server.upgrade.PKIServerUpgradeScriptlet):
+         source_xml = pki.SHARE_DIR + '/server/conf/Catalina/localhost/' + context_xml
+         target_xml = instance.conf_dir + '/Catalina/localhost/' + context_xml
+ 
++        if not os.path.exists(source_xml):
++            return
++
+         # if deployment descriptor doesn't exist, install the default
+         if not os.path.exists(target_xml):
+             self.copy_file(instance, source_xml, target_xml)
+-- 
+2.13.5
+
diff --git a/SOURCES/pki-core-KRA-use-AES-in-PKCS12-encrypted-key-recovery.patch b/SOURCES/pki-core-KRA-use-AES-in-PKCS12-encrypted-key-recovery.patch
new file mode 100644
index 0000000..6a28873
--- /dev/null
+++ b/SOURCES/pki-core-KRA-use-AES-in-PKCS12-encrypted-key-recovery.patch
@@ -0,0 +1,77 @@
+From b16956b856e9bb8ffa8d2cd356f4120b36ebe6e9 Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Thu, 6 Apr 2017 13:27:56 +1000
+Subject: [PATCH] KRA: use AES in PKCS #12 recovery for encrypted keys
+
+The KRA has two private key recovery code paths: one dealing with
+keys wrapped to the storage key, and one dealing with symmetrically
+encrypted keys.  Each has a separate function for constructing a
+PKCS #12 file for the recovered key.
+
+This commit updates the PKCS #12 generation for encrypted keys to
+use AES encryption.  From the KRA recovery process we start with a
+byte[] of PrivateKeyInfo.  The previous procedure used
+EncryptedPrivateKeyInfo.createPBE(), the encryption algorithm being
+PBEAlgorithm.PBE_SHA1_DES3_CBC.  This commit changes the procedure
+to use AES, using the new EncryptedPrivateKeyInfo.createPBES2() JSS
+method and AES_128_CBC_PAD.
+
+The old codepath is retained and selected by the kra.legacyPKCS12
+CMS config.  It is needed if the token/HSM does not support the
+CKM_PKCS5_PBKD2 PKCS #11 mechanism.
+
+Fixes: https://pagure.io/dogtagpki/issue/2664
+
+Change-Id: Ie292147caab357679b2be5cf3b6cd739e5bed8e0
+(cherry picked from commit ae97f21bf8d2ec83a410127872dd196a46f9dbbd)
+---
+ base/kra/src/com/netscape/kra/RecoveryService.java | 24 +++++++++++++++++++---
+ 1 file changed, 21 insertions(+), 3 deletions(-)
+
+diff --git a/base/kra/src/com/netscape/kra/RecoveryService.java b/base/kra/src/com/netscape/kra/RecoveryService.java
+index 023eb8093..a7d639208 100644
+--- a/base/kra/src/com/netscape/kra/RecoveryService.java
++++ b/base/kra/src/com/netscape/kra/RecoveryService.java
+@@ -648,18 +648,36 @@ public class RecoveryService implements IService {
+             SEQUENCE safeContents = new SEQUENCE();
+             PasswordConverter passConverter = new
+                     PasswordConverter();
+-            byte salt[] = { 0x01, 0x01, 0x01, 0x01 };
+             PrivateKeyInfo pki = (PrivateKeyInfo)
+                     ASN1Util.decode(PrivateKeyInfo.getTemplate(),
+                             priData);
+-            ASN1Value key = EncryptedPrivateKeyInfo.createPBE(
++            EncryptedPrivateKeyInfo epki = null;
++
++            boolean legacyP12 =
++                CMS.getConfigStore().getBoolean("kra.legacyPKCS12", true);
++
++            if (legacyP12) {
++                /* legacy mode may be required e.g. when token/HSM
++                 * does not support CKM_PKCS5_PBKD2 mechanism */
++                byte salt[] = { 0x01, 0x01, 0x01, 0x01 };
++                epki = EncryptedPrivateKeyInfo.createPBE(
+                     PBEAlgorithm.PBE_SHA1_DES3_CBC,
+                     pass, salt, 1, passConverter, pki);
++            } else {
++                epki = EncryptedPrivateKeyInfo.createPBES2(
++                    16, // saltLen
++                    2000, // kdfIterations
++                    EncryptionAlgorithm.AES_128_CBC_PAD,
++                    pass,
++                    passConverter,
++                    pki);
++            }
++
+             SET keyAttrs = createBagAttrs(
+                     x509cert.getSubjectDN().toString(),
+                     localKeyId);
+             SafeBag keyBag = new SafeBag(
+-                    SafeBag.PKCS8_SHROUDED_KEY_BAG, key,
++                    SafeBag.PKCS8_SHROUDED_KEY_BAG, epki,
+                     keyAttrs); // ??
+ 
+             safeContents.addElement(keyBag);
+-- 
+2.13.5
+
diff --git a/SOURCES/pki-core-Make-PKCS12-files-compatible-with-PBES2.patch b/SOURCES/pki-core-Make-PKCS12-files-compatible-with-PBES2.patch
new file mode 100644
index 0000000..e0b175d
--- /dev/null
+++ b/SOURCES/pki-core-Make-PKCS12-files-compatible-with-PBES2.patch
@@ -0,0 +1,162 @@
+From 137832b2892dfc596ed067a86242d341f2c325e7 Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Thu, 14 Sep 2017 12:22:47 +1000
+Subject: [PATCH] Make PKCS #12 files compatible with OpenSSL, NSS >= 3.31
+
+For compatibility with OpenSSL and NSS >= 3.31, the passphrase must
+not be BMPString-encoded when non-PKCS #12 PBE schemes such as
+PBES2.
+
+Fixes: https://pagure.io/dogtagpki/issue/2809
+
+Change-Id: Ic78ad337ac0b9b2f5d2e75581cc0ee55e6d82782
+(cherry picked from commit ed5cccefebf98e588a5385191e43f727349b54a9)
+---
+ base/kra/src/com/netscape/kra/RecoveryService.java | 26 +++++++++++++++----
+ .../cms/servlet/csadmin/ConfigurationUtils.java    | 15 ++++++++---
+ .../src/netscape/security/pkcs/PKCS12Util.java     | 29 ++++++++++++++++++----
+ 3 files changed, 57 insertions(+), 13 deletions(-)
+
+diff --git a/base/kra/src/com/netscape/kra/RecoveryService.java b/base/kra/src/com/netscape/kra/RecoveryService.java
+index a7d639208..0d293e411 100644
+--- a/base/kra/src/com/netscape/kra/RecoveryService.java
++++ b/base/kra/src/com/netscape/kra/RecoveryService.java
+@@ -508,10 +508,21 @@ public class RecoveryService implements IService {
+                 }
+             } else {
+                 byte[] epkiBytes = ct.getCryptoStore().getEncryptedPrivateKeyInfo(
++                    /* For compatibility with OpenSSL and NSS >= 3.31,
++                     * do not BMPString-encode the passphrase when using
++                     * non-PKCS #12 PBE scheme such as PKCS #5 PBES2.
++                     *
++                     * The resulting PKCS #12 is not compatible with
++                     * NSS < 3.31.
++                     */
++                    null /* passConverter */,
++                    pass,
+                     /* NSS has a bug that causes any AES CBC encryption
+                      * to use AES-256, but AlgorithmID contains chosen
+                      * alg.  To avoid mismatch, use AES_256_CBC. */
+-                    passConverter, pass, EncryptionAlgorithm.AES_256_CBC, 0, priKey);
++                    EncryptionAlgorithm.AES_256_CBC,
++                    0 /* iterations (use default) */,
++                    priKey);
+                 CMS.debug("RecoverService: createPFX() getEncryptedPrivateKeyInfo() returned");
+                 if (epkiBytes == null) {
+                     CMS.debug("RecoverService: createPFX() epkiBytes null");
+@@ -646,8 +657,6 @@ public class RecoveryService implements IService {
+                             pwd.toCharArray());
+ 
+             SEQUENCE safeContents = new SEQUENCE();
+-            PasswordConverter passConverter = new
+-                    PasswordConverter();
+             PrivateKeyInfo pki = (PrivateKeyInfo)
+                     ASN1Util.decode(PrivateKeyInfo.getTemplate(),
+                             priData);
+@@ -662,14 +671,21 @@ public class RecoveryService implements IService {
+                 byte salt[] = { 0x01, 0x01, 0x01, 0x01 };
+                 epki = EncryptedPrivateKeyInfo.createPBE(
+                     PBEAlgorithm.PBE_SHA1_DES3_CBC,
+-                    pass, salt, 1, passConverter, pki);
++                    pass, salt, 1, new PasswordConverter(), pki);
+             } else {
+                 epki = EncryptedPrivateKeyInfo.createPBES2(
+                     16, // saltLen
+                     2000, // kdfIterations
+                     EncryptionAlgorithm.AES_128_CBC_PAD,
+                     pass,
+-                    passConverter,
++                    /* For compatibility with OpenSSL and NSS >= 3.31,
++                     * do not BMPString-encode the passphrase when using
++                     * non-PKCS #12 PBE scheme such as PKCS #5 PBES2.
++                     *
++                     * The resulting PKCS #12 is not compatible with
++                     * NSS < 3.31.
++                     */
++                    null /* passConverter */,
+                     pki);
+             }
+ 
+diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
+index ebade36bc..df3b4672d 100644
+--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
++++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
+@@ -1058,9 +1058,18 @@ public class ConfigurationUtils {
+                 // this is OK
+             }
+ 
+-            // import private key into database
+-            store.importEncryptedPrivateKeyInfo(
+-                new PasswordConverter(), password, nickname, publicKey, epki);
++            try {
++                // first true without BMPString-encoding the passphrase.
++                store.importEncryptedPrivateKeyInfo(
++                    null, password, nickname, publicKey, epki);
++            } catch (Exception e) {
++                // if that failed, try again with BMPString-encoded
++                // passphrase.  This is required for PKCS #12 PBE
++                // schemes and for PKCS #12 files using PBES2 generated
++                // by NSS < 3.31
++                store.importEncryptedPrivateKeyInfo(
++                    new PasswordConverter(), password, nickname, publicKey, epki);
++            }
+         }
+ 
+         CMS.debug("Importing new certificates:");
+diff --git a/base/util/src/netscape/security/pkcs/PKCS12Util.java b/base/util/src/netscape/security/pkcs/PKCS12Util.java
+index 1bc1baee5..1018b21f6 100644
+--- a/base/util/src/netscape/security/pkcs/PKCS12Util.java
++++ b/base/util/src/netscape/security/pkcs/PKCS12Util.java
+@@ -134,16 +134,25 @@ public class PKCS12Util {
+             }
+             logger.debug("Encrypting private key for " + keyInfo.subjectDN);
+ 
+-            PasswordConverter passConverter = new PasswordConverter();
+             epkiBytes = CryptoManager.getInstance()
+                 .getInternalKeyStorageToken()
+                 .getCryptoStore()
+                 .getEncryptedPrivateKeyInfo(
++                    /* For compatibility with OpenSSL and NSS >= 3.31,
++                     * do not BMPString-encode the passphrase when using
++                     * non-PKCS #12 PBE scheme such as PKCS #5 PBES2.
++                     *
++                     * The resulting PKCS #12 is not compatible with
++                     * NSS < 3.31.
++                     */
++                    null /* passConverter */,
++                    password,
+                     /* NSS has a bug that causes any AES CBC encryption
+                      * to use AES-256, but AlgorithmID contains chosen
+                      * alg.  To avoid mismatch, use AES_256_CBC. */
+-                    passConverter, password,
+-                    EncryptionAlgorithm.AES_256_CBC, 0, k);
++                    EncryptionAlgorithm.AES_256_CBC,
++                    0 /* iterations (default) */,
++                    k);
+         }
+ 
+         SET keyAttrs = createKeyBagAttrs(keyInfo);
+@@ -616,8 +625,18 @@ public class PKCS12Util {
+                 "No EncryptedPrivateKeyInfo for key '"
+                 + keyInfo.subjectDN + "'; skipping key");
+         }
+-        store.importEncryptedPrivateKeyInfo(
+-            new PasswordConverter(), password, nickname, publicKey, epkiBytes);
++        try {
++            // first true without BMPString-encoding the passphrase.
++            store.importEncryptedPrivateKeyInfo(
++                null, password, nickname, publicKey, epkiBytes);
++        } catch (Exception e) {
++            // if that failed, try again with BMPString-encoded
++            // passphrase.  This is required for PKCS #12 PBE
++            // schemes and for PKCS #12 files using PBES2 generated
++            // by NSS < 3.31
++            store.importEncryptedPrivateKeyInfo(
++                new PasswordConverter(), password, nickname, publicKey, epkiBytes);
++        }
+ 
+         // delete the cert again (it will be imported again later
+         // with the correct nickname)
+-- 
+2.13.5
+
diff --git a/SOURCES/pki-core-fix-ipa-replica-install-timing-issue.patch b/SOURCES/pki-core-fix-ipa-replica-install-timing-issue.patch
new file mode 100644
index 0000000..721c49f
--- /dev/null
+++ b/SOURCES/pki-core-fix-ipa-replica-install-timing-issue.patch
@@ -0,0 +1,278 @@
+From 609b98cccc77fa8b8e8d307c2f84651429068ec6 Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Mon, 9 Oct 2017 16:26:21 +1100
+Subject: [PATCH 1/5] CMSServlet.renderFinalError: log exception
+
+renderFinalError is a "last resort" error handler that writes an
+error message back to the client.  If the exception was not already
+logged, the call stack will be discarded after renderFinalError is
+finished with the exception.
+
+Log the exception so that the call stack information is not lost.
+
+Part of: https://pagure.io/dogtagpki/issue/2557
+
+Change-Id: I2fd608adf205e3f72b67d822b1966fdb1b8bc60f
+(cherry picked from commit 386357c347f8433e14ccd8637576f4c4a4e42492)
+(cherry picked from commit 3af42c306446ddc931fc0d44505cd237aa2267d7)
+---
+ base/server/cms/src/com/netscape/cms/servlet/base/CMSServlet.java | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/base/server/cms/src/com/netscape/cms/servlet/base/CMSServlet.java b/base/server/cms/src/com/netscape/cms/servlet/base/CMSServlet.java
+index 65dc06a..fe18ee1 100644
+--- a/base/server/cms/src/com/netscape/cms/servlet/base/CMSServlet.java
++++ b/base/server/cms/src/com/netscape/cms/servlet/base/CMSServlet.java
+@@ -763,6 +763,8 @@ public abstract class CMSServlet extends HttpServlet {
+ 
+     public void renderFinalError(CMSRequest cmsReq, Exception ex)
+             throws IOException {
++        CMS.debug("Caught exception in renderFinalError:");
++        CMS.debug(ex);
+         // this template is the last resort for all other unexpected
+         // errors in other templates so we can only output text.
+         HttpServletResponse httpResp = cmsReq.getHttpResp();
+-- 
+1.8.3.1
+
+
+From c160d49e0b61d650a14eae9be38e5f381aeb0b24 Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Mon, 9 Oct 2017 16:45:51 +1100
+Subject: [PATCH 2/5] TokenAuthenticate: avoid NPE on null session table
+
+If the security domain session table is null for some reason, detect
+this condition, log it, and return cleanly instead of throwing a
+NullPointerException.
+
+Part of: https://pagure.io/dogtagpki/issue/2557
+
+Change-Id: Ie487492ed6eec913f0271221fd12842fe7128ceb
+(cherry picked from commit bc329a0162ae9af382c81e75742b282ea8c5df0d)
+(cherry picked from commit 76d85a648bc6be0f690d36341e6a11d64a3ff6b6)
+---
+ .../cms/src/com/netscape/cms/servlet/csadmin/TokenAuthenticate.java | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/TokenAuthenticate.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/TokenAuthenticate.java
+index 27f4782..1d98693 100644
+--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/TokenAuthenticate.java
++++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/TokenAuthenticate.java
+@@ -81,7 +81,11 @@ public class TokenAuthenticate extends CMSServlet {
+         String uid = "";
+         String gid = "";
+         CMS.debug("TokenAuthentication: checking session in the session table");
+-        if (table.sessionExists(sessionId)) {
++        if (table == null) {
++            CMS.debug("TokenAuthentication: session table is null");
++            outputError(httpResp, "Error: session table is null");
++            return;
++        } else if (table.sessionExists(sessionId)) {
+             CMS.debug("TokenAuthentication: found session");
+             if (checkIP) {
+                 String hostname = table.getIP(sessionId);
+-- 
+1.8.3.1
+
+
+From 275d3b1ad88721e1a5a5bfd8b5013a14d3db2263 Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Tue, 10 Oct 2017 00:21:57 +1100
+Subject: [PATCH 3/5] TokenAuthentication: log error message on error
+
+If a TokenAuthenticate response indicates failure (state != 0), log
+the error string in addition to the status code.
+
+Part of: https://pagure.io/dogtagpki/issue/2557
+
+Change-Id: I22ba44be109a06f33ae6015e62393a2ef575b6b2
+(cherry picked from commit 9eb354883c9d965bb271223bf870839bb756db26)
+(cherry picked from commit c9908785df9f22b1ca4f507c9f51bf904193a143)
+---
+ .../cms/src/com/netscape/cms/authentication/TokenAuthentication.java     | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/base/server/cms/src/com/netscape/cms/authentication/TokenAuthentication.java b/base/server/cms/src/com/netscape/cms/authentication/TokenAuthentication.java
+index ebda0b6..2aa32d4 100644
+--- a/base/server/cms/src/com/netscape/cms/authentication/TokenAuthentication.java
++++ b/base/server/cms/src/com/netscape/cms/authentication/TokenAuthentication.java
+@@ -183,6 +183,7 @@ public class TokenAuthentication implements IAuthManager,
+                 CMS.debug("TokenAuthentication: status=" + status);
+                 if (!status.equals("0")) {
+                     String error = parser.getValue("Error");
++                    CMS.debug("TokenAuthentication: error: " + error);
+                     throw new EBaseException(error);
+                 }
+ 
+-- 
+1.8.3.1
+
+
+From 2a8f26e1169f8840a59f1707964d98b47619ca1c Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Wed, 11 Oct 2017 15:41:15 +1100
+Subject: [PATCH 4/5] Sleep after security domain login during configuration
+
+Clone installation can fail due to security domain token
+authentication failure that arises because:
+
+1. The security domain session gets created on the replica's CA
+   instance.
+
+2. The "updateNumberRange" is performed against the subsystem being
+   cloned, and results in a token authentication request to the CA
+   subsystem on the same host.
+
+3. LDAP replication lag means that the master does not yet see
+   the security domain session that was created on the replica.
+
+To avoid this problem, introduce a small delay after logging into
+the security domain, to allow for replication to occur.  The delay
+is configurable and defaults to 5 seconds.
+
+Fixes: https://pagure.io/dogtagpki/issue/2557
+Change-Id: Ib11c077518c40b3b16699c9170b61085f55a1913
+(cherry picked from commit fa2d731b6ce51c5db9fb0b004d586b8f3e1decd3)
+(cherry picked from commit 5fae20defb5e938a621fc40f92954eb7daba1c7b)
+---
+ .../netscape/certsrv/system/ConfigurationRequest.java   | 14 ++++++++++++++
+ .../org/dogtagpki/server/rest/SystemConfigService.java  | 17 ++++++++++++++++-
+ 2 files changed, 30 insertions(+), 1 deletion(-)
+
+diff --git a/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java b/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java
+index 26f45f0..03dbfa6 100644
+--- a/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java
++++ b/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java
+@@ -244,6 +244,11 @@ public class ConfigurationRequest {
+     @XmlElement
+     protected String signingCertSerialNumber;
+ 
++    /** Seconds to sleep after logging into the Security Domain,
++     * so that replication of the session data may complete. */
++    @XmlElement
++    protected Long securityDomainPostLoginSleepSeconds;
++
+     public ConfigurationRequest() {
+         // required for JAXB
+     }
+@@ -974,6 +979,14 @@ public class ConfigurationRequest {
+         this.signingCertSerialNumber = signingCertSerialNumber;
+     }
+ 
++    public Long getSecurityDomainPostLoginSleepSeconds() {
++        return securityDomainPostLoginSleepSeconds;
++    }
++
++    public void setSecurityDomainPostLoginSleepSeconds(Long d) {
++        securityDomainPostLoginSleepSeconds = d;
++    }
++
+     @Override
+     public String toString() {
+         return "ConfigurationRequest [pin=XXXX" +
+@@ -983,6 +996,7 @@ public class ConfigurationRequest {
+                ", securityDomainName=" + securityDomainName +
+                ", securityDomainUser=" + securityDomainUser +
+                ", securityDomainPassword=XXXX" +
++               ", securityDomainPostLoginSleepSeconds=" + securityDomainPostLoginSleepSeconds +
+                ", isClone=" + isClone +
+                ", cloneUri=" + cloneUri +
+                ", subsystemName=" + subsystemName +
+diff --git a/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java b/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
+index afbb24a..9ffb6e3 100644
+--- a/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
++++ b/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
+@@ -950,7 +950,22 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
+ 
+         getInstallToken(data, host, port);
+ 
+-        return getDomainXML(host, port);
++        String domainXML = getDomainXML(host, port);
++
++        /* Sleep for a bit to allow security domain session to replicate
++         * to other clones.  In the future we can use signed tokens
++         * (ticket https://pagure.io/dogtagpki/issue/2831) but we need to
++         * be mindful of working with older versions, too.
++         *
++         * The default sleep time is 5s.
++         */
++        Long d = data.getSecurityDomainPostLoginSleepSeconds();
++        if (null == d || d <= 0)
++            d = new Long(5);
++        CMS.debug("Logged into security domain; sleeping for " + d + "s");
++        Thread.sleep(d * 1000);
++
++        return domainXML;
+     }
+ 
+     private String getDomainXML(String host, int port) {
+-- 
+1.8.3.1
+
+
+From 2cf5ab35f9fda67405b209ae46891232c38eb4f0 Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Wed, 11 Oct 2017 18:12:04 +1100
+Subject: [PATCH 5/5] pkispawn: make security domain login sleep duration
+ configurable
+
+Add the pki_security_domain_post_login_sleep_seconds pkispawn
+config, so that the administrator may set a duration other than the
+default.
+
+Part of: https://pagure.io/dogtagpki/issue/2557
+
+Change-Id: I74f16ea15621773e0742f709adc87df559cb530a
+(cherry picked from commit 8c0a7eee3bbfe01b2d965dbe09e95221c5031c8b)
+(cherry picked from commit 32ec33f8e49d1085ac1b28657a8321547a6bf910)
+---
+ base/server/man/man8/pkispawn.8                       | 7 +++++++
+ base/server/python/pki/server/deployment/pkihelper.py | 7 +++++++
+ 2 files changed, 14 insertions(+)
+
+diff --git a/base/server/man/man8/pkispawn.8 b/base/server/man/man8/pkispawn.8
+index 002520a..1d4ae24 100644
+--- a/base/server/man/man8/pkispawn.8
++++ b/base/server/man/man8/pkispawn.8
+@@ -956,6 +956,7 @@ pki_security_domain_password=\fISecret123\fP
+ pki_security_domain_hostname=<master_ca_hostname>
+ pki_security_domain_https_port=<master_ca_https_port>
+ pki_security_domain_user=caadmin
++pki_security_domain_post_login_sleep_seconds=\fI5\fP
+ 
+ [Tomcat]
+ pki_clone=True
+@@ -997,6 +998,12 @@ and the \fBpki_backup_password\fP is set.  The PKCS#12 file is then found under
+ be generated at any time post-installation using \fBPKCS12Export\fP.
+ 
+ .PP
++The \fBpki_security_domain_post_login_sleep_seconds\fP config specifies sleep
++duration after logging into a security domain, to allow the security domain
++session data to be replicated to subsystems on other hosts.  It is optional and
++defaults to 5 seconds.
++
++.PP
+ An example invocation showing the export of the system certificates and keys,
+ copying the keys to the replica subsystem, and setting the relevant SELinux and
+ file permissions is shown below.  \fBpwfile\fP is a text file containing the
+diff --git a/base/server/python/pki/server/deployment/pkihelper.py b/base/server/python/pki/server/deployment/pkihelper.py
+index cf2a748..9bb0dfc 100644
+--- a/base/server/python/pki/server/deployment/pkihelper.py
++++ b/base/server/python/pki/server/deployment/pkihelper.py
+@@ -4045,6 +4045,13 @@ class ConfigClient:
+         if self.subordinate:
+             self.set_subca_security_domain(data)
+ 
++        try:
++            d = int(self.mdict['pki_security_domain_post_login_sleep_seconds'])
++            if d > 0:
++                data.securityDomainPostLoginSleepSeconds = d
++        except (KeyError, ValueError):
++            pass
++
+         # database
+         if self.subsystem != "RA":
+             self.set_database_parameters(data)
+-- 
+1.8.3.1
+
diff --git a/SOURCES/pki-core-fix-issuance-sans-subject-key-ID-ext.patch b/SOURCES/pki-core-fix-issuance-sans-subject-key-ID-ext.patch
new file mode 100644
index 0000000..4514c7b
--- /dev/null
+++ b/SOURCES/pki-core-fix-issuance-sans-subject-key-ID-ext.patch
@@ -0,0 +1,38 @@
+From 5f62e2db4a1a9040758a806095e1b4da5d0a0d1d Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Fri, 6 Oct 2017 11:21:48 +1100
+Subject: [PATCH] Fix issuance when CA cert lacks Subject Key ID ext
+
+If the CA signing cert does not have the Subject Key Identifier
+extension, issuance of certificates fails. Although such a CA
+certificate is not compliant with RFC 5280, this does happen in the
+wild, and we previously handled this case by computing the SHA-1
+digest of the signing key as a last resort. This behaviour was
+removed by 3c43b1119ca978c296a38a9fe404e1c0cdcdab63, breaking cert
+issuance in installations with CA certs that lack the SKI extention.
+
+Restore this behaviour.
+
+Fixes: https://pagure.io/dogtagpki/issue/2829
+Change-Id: I2f590abe258c0f9405549945b89e3c25c32c2a00
+(cherry picked from commit 8ec0cbd1bef372ed50e19f6c5b6332b75209beb0)
+(cherry picked from commit 119f4ee0288c1e6e6996847a66f617f04dd42ae6)
+---
+ base/server/cms/src/com/netscape/cms/profile/def/CAEnrollDefault.java | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/base/server/cms/src/com/netscape/cms/profile/def/CAEnrollDefault.java b/base/server/cms/src/com/netscape/cms/profile/def/CAEnrollDefault.java
+index 635c044..8d5361e 100644
+--- a/base/server/cms/src/com/netscape/cms/profile/def/CAEnrollDefault.java
++++ b/base/server/cms/src/com/netscape/cms/profile/def/CAEnrollDefault.java
+@@ -95,6 +95,6 @@ public abstract class CAEnrollDefault extends EnrollDefault {
+                 "CryptoUtil.generateKeyIdentifier returns null");
+             return null;
+         }
+-        return null;
++        return new KeyIdentifier(hash);
+     }
+ }
+-- 
+1.8.3.1
+
diff --git a/SOURCES/pki-core-tps-externalReg-regression.patch b/SOURCES/pki-core-tps-externalReg-regression.patch
new file mode 100644
index 0000000..1b727ba
--- /dev/null
+++ b/SOURCES/pki-core-tps-externalReg-regression.patch
@@ -0,0 +1,55 @@
+From 47fccfaa32bf327c56c5789f373e4d18c714556f Mon Sep 17 00:00:00 2001
+From: Jack Magne <jmagne@redhat.com>
+Date: Fri, 10 Nov 2017 15:55:36 -0800
+Subject: [PATCH] ReFix for  #2824 TPS new configuration to allow the protocol
+ of the to determine applet loaded.
+
+The problem discovered was that in only the external registration case, there was a problem obtaining the protocol
+information for the token being enrolled. This simple fix makes sure the protocol info is obtained correctly for external
+reg and non external reg enrollment cases.
+
+Change-Id: Iccd40adbdafd5e94e04cbb8c391bd2706e483a1f
+(cherry picked from commit e48374cd8a744fad5a03f64e8685ec3b3c465553)
+(cherry picked from commit 3718b369598c3ecfdb6733c25b08e4b51042423f)
+---
+ .../src/org/dogtagpki/server/tps/processor/TPSProcessor.java   | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
+index 4ec277e..03d6532 100644
+--- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
++++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
+@@ -33,8 +33,6 @@ import java.util.List;
+ import java.util.Map;
+ import java.util.Set;
+ 
+-import netscape.security.x509.RevocationReason;
+-
+ import org.dogtagpki.server.tps.TPSSession;
+ import org.dogtagpki.server.tps.TPSSubsystem;
+ import org.dogtagpki.server.tps.authentication.AuthUIParameter;
+@@ -102,6 +100,8 @@ import com.netscape.cms.servlet.tks.SecureChannelProtocol;
+ import com.netscape.cmsutil.crypto.CryptoUtil;
+ import com.netscape.symkey.SessionKey;
+ 
++import netscape.security.x509.RevocationReason;
++
+ public class TPSProcessor {
+ 
+     public static final int RESULT_NO_ERROR = 0;
+@@ -556,8 +556,10 @@ public class TPSProcessor {
+             CMS.debug("TPSProcessor.setupSecureChannel: obtained randomData");
+         }
+ 
+-        // We already do this when checking for applet upgrade earlier.
+-        //acquireChannelPlatformAndProtocolInfo();
++        // Do this on behalf of external reg, which needs it
++        // If already called, the routine will return anyway.
++
++        acquireChannelPlatformAndProtocolInfo();
+ 
+         TPSBuffer initUpdateResp = initializeUpdate(keyVersion, keyIndex, randomData);
+ 
+-- 
+1.8.3.1
+
diff --git a/SOURCES/pki-core-update-RHEL-cert-revocation-reasons.patch b/SOURCES/pki-core-update-RHEL-cert-revocation-reasons.patch
new file mode 100644
index 0000000..accac88
--- /dev/null
+++ b/SOURCES/pki-core-update-RHEL-cert-revocation-reasons.patch
@@ -0,0 +1,429 @@
+From d3f50c6a77b164cc876192ab95639ad913f33deb Mon Sep 17 00:00:00 2001
+From: Christina Fu <cfu@redhat.com>
+Date: Thu, 20 Jul 2017 17:50:38 -0700
+Subject: [PATCH] Ticket #1665 (code realignment) Certificate Revocation
+ Reasons not being updated in some cases This patch makes sure that when a
+ token is temporarily lost (certs on_hold), its certs are properly revoked
+ when moving to other revocation reasons when marked damaged or permanently
+ lost. In addition, on the CA side, this patch to some degree mimics the
+ original request for transitions from SUPERSEDED to KEY_COMPROMISED, although
+ in the current TPS that is prohibited. Also, the original requested code
+ skipped over informing CRLIssuingPoints, while in this patch, that is not
+ skipped as the revocation reason has changed it should be updated;  Time
+ stamp in the cert record is also updated, which is different from the
+ original requested code. Development tests were conducted on currently
+ allowed TPS token state transitions only.
+
+Change-Id: I675ce13892a7c48eba42870a87954398d7dc8168
+(cherry picked from commit 36213c8b614775feadfebef54db034e1155d33c7)
+(cherry picked from commit 34aabcc5fb21f35d96f76fc5b822959f26aacf42)
+---
+ base/ca/src/com/netscape/ca/CAService.java         | 58 +++++++++++++++++--
+ .../netscape/certsrv/dbs/certdb/ICertRecord.java   |  9 +++
+ .../com/netscape/cms/servlet/cert/DoRevokeTPS.java | 51 +++++++++++++----
+ base/server/cmsbundle/src/LogMessages.properties   |  2 +
+ base/server/cmsbundle/src/UserMessages.properties  |  1 +
+ .../src/com/netscape/cmscore/dbs/CertRecord.java   | 65 +++++++++++++++-------
+ .../cmscore/dbs/CertificateRepository.java         | 32 ++++++-----
+ 7 files changed, 166 insertions(+), 52 deletions(-)
+
+diff --git a/base/ca/src/com/netscape/ca/CAService.java b/base/ca/src/com/netscape/ca/CAService.java
+index c9eacfe..7cc6a31 100644
+--- a/base/ca/src/com/netscape/ca/CAService.java
++++ b/base/ca/src/com/netscape/ca/CAService.java
+@@ -980,8 +980,28 @@ public class CAService implements ICAService, IService {
+         BigInteger serialno = crlentry.getSerialNumber();
+         Date revdate = crlentry.getRevocationDate();
+         CRLExtensions crlentryexts = crlentry.getExtensions();
++        String msg = "";
+ 
+         CMS.debug("CAService.revokeCert: revokeCert begins");
++
++        // Get the revocation reason
++        Enumeration enum1 = crlentryexts.getElements();
++        RevocationReason revReason = null;
++        while (enum1.hasMoreElements()) {
++            Extension ext = (Extension) enum1.nextElement();
++            if (ext instanceof CRLReasonExtension) {
++                revReason = ((CRLReasonExtension) ext).getReason();
++                break;
++            }
++        }
++        if (revReason == null) {
++            CMS.debug("CAService.revokeCert: missing revocation reason");
++            mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_MISSING_REV_REASON=", serialno.toString(16)));
++            throw new ECAException(
++                    CMS.getUserMessage("CMS_CA_MISSING_REV_REASON",
++                            "0x" + serialno.toString(16)));
++        }
++
+         CertRecord certRec = (CertRecord) mCA.getCertificateRepository().readCertificateRecord(serialno);
+ 
+         if (certRec == null) {
+@@ -995,24 +1015,52 @@ public class CAService implements ICAService, IService {
+         // allow revoking certs that are on hold.
+         String certStatus = certRec.getStatus();
+ 
+-        if ((certStatus.equals(ICertRecord.STATUS_REVOKED) &&
+-                !certRec.isCertOnHold()) ||
++        RevocationReason recRevReason = null;
++        if (certStatus.equals(ICertRecord.STATUS_REVOKED)) {
++            try {
++                recRevReason = certRec.getRevReason();
++            } catch (Exception e) {
++                throw new EBaseException(e);
++            }
++            if (recRevReason == null) {
++                msg = "existing revoked cert missing revocation reason";
++                CMS.debug("CAService.revokeCert: " + msg);
++                throw new EBaseException(msg);
++            }
++        }
++
++        // for cert already revoked, also check whether revocation reason is changed from SUPERSEDED to KEY_COMPROMISE
++        if (((certStatus.equals(ICertRecord.STATUS_REVOKED) &&
++                !certRec.isCertOnHold()) &&
++                ((recRevReason != RevocationReason.SUPERSEDED) ||
++                        revReason != RevocationReason.KEY_COMPROMISE))
++                ||
+                 certStatus.equals(ICertRecord.STATUS_REVOKED_EXPIRED)) {
+             CMS.debug("CAService.revokeCert: cert already revoked:" +
+                     serialno.toString());
+             throw new ECAException(CMS.getUserMessage("CMS_CA_CERT_ALREADY_REVOKED",
+                     "0x" + Long.toHexString(serialno.longValue())));
+         }
++
+         try {
++            // if cert has already revoked, update the revocation info only
+             CMS.debug("CAService.revokeCert: about to call markAsRevoked");
+-            if (certRec.isCertOnHold()) {
++            if (certStatus.equals(ICertRecord.STATUS_REVOKED) && certRec.isCertOnHold()) {
+                 mCA.getCertificateRepository().markAsRevoked(serialno,
+-                        new RevocationInfo(revdate, crlentryexts), true /*isAlreadyOnHold*/);
++                        new RevocationInfo(revdate, crlentryexts),
++                        true /*isAlreadyRevoked*/);
++                CMS.debug("CAService.revokeCert: on_hold cert marked revoked");
++                mCA.log(ILogger.LL_INFO,
++                        CMS.getLogMessage("CMSCORE_CA_CERT_REVO_INFO_UPDATE",
++                                recRevReason.toString(),
++                                revReason.toString(),
++                                serialno.toString(16)));
+             } else {
+                 mCA.getCertificateRepository().markAsRevoked(serialno,
+                         new RevocationInfo(revdate, crlentryexts));
+             }
+-            CMS.debug("CAService.revokeCert: cert revoked");
++
++            CMS.debug("CAService.revokeCert: cert now revoked");
+             mCA.log(ILogger.LL_INFO, CMS.getLogMessage("CMSCORE_CA_CERT_REVOKED",
+                     serialno.toString(16)));
+             // inform all CRLIssuingPoints about revoked certificate
+diff --git a/base/common/src/com/netscape/certsrv/dbs/certdb/ICertRecord.java b/base/common/src/com/netscape/certsrv/dbs/certdb/ICertRecord.java
+index 3a0c955..65db57e 100644
+--- a/base/common/src/com/netscape/certsrv/dbs/certdb/ICertRecord.java
++++ b/base/common/src/com/netscape/certsrv/dbs/certdb/ICertRecord.java
+@@ -20,6 +20,9 @@ package com.netscape.certsrv.dbs.certdb;
+ import java.math.BigInteger;
+ import java.util.Date;
+ 
++import com.netscape.certsrv.base.EBaseException;
++import netscape.security.x509.RevocationReason;
++import netscape.security.x509.X509ExtensionException;
+ import netscape.security.x509.X509CertImpl;
+ 
+ import com.netscape.certsrv.base.MetaInfo;
+@@ -181,4 +184,10 @@ public interface ICertRecord extends IDBObj {
+      * is this cert on hold?
+      */
+     public boolean isCertOnHold();
++
++    /**
++     * returns the revocation reason
++     */
++    public RevocationReason getRevReason()
++           throws EBaseException, X509ExtensionException;
+ }
+diff --git a/base/server/cms/src/com/netscape/cms/servlet/cert/DoRevokeTPS.java b/base/server/cms/src/com/netscape/cms/servlet/cert/DoRevokeTPS.java
+index a9a6238..47062f2 100644
+--- a/base/server/cms/src/com/netscape/cms/servlet/cert/DoRevokeTPS.java
++++ b/base/server/cms/src/com/netscape/cms/servlet/cert/DoRevokeTPS.java
+@@ -1,4 +1,4 @@
+-// --- 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.
+@@ -330,8 +330,10 @@ public class DoRevokeTPS extends CMSServlet {
+         String auditRequestType = auditRequestType(reason);
+         RequestStatus auditApprovalStatus = null;
+         String auditReasonNum = String.valueOf(reason);
+-        String method = "DoRevokeTPS.process";
++        String method = "DoRevokeTPS.process:";
++        String msg = "";
+ 
++        CMS.debug(method + "begins");
+         if (revokeAll != null) {
+             CMS.debug("DoRevokeTPS.process revokeAll" + revokeAll);
+ 
+@@ -357,6 +359,8 @@ public class DoRevokeTPS extends CMSServlet {
+             Vector<RevokedCertImpl> revCertImplsV = new Vector<RevokedCertImpl>();
+ 
+             // Construct a CRL reason code extension.
++
++            CMS.debug(method + "reason code = " + reason);
+             RevocationReason revReason = RevocationReason.fromInt(reason);
+             CRLReasonExtension crlReasonExtn = new CRLReasonExtension(revReason);
+ 
+@@ -401,22 +405,47 @@ public class DoRevokeTPS extends CMSServlet {
+                 }
+ 
+                 if (xcert != null) {
++                    RevocationReason recRevReason = null;
++                    if (rec.getStatus().equals(ICertRecord.STATUS_REVOKED)) {
++                        try {
++                            recRevReason = rec.getRevReason();
++                        } catch (Exception ex) {
++                            CMS.debug(method + ex.toString());
++                            throw new EBaseException(ex);
++                        }
++                        if (recRevReason == null) {
++                            msg = "existing revoked cert missing revocation reason";
++                            CMS.debug(method + msg);
++                            throw new EBaseException(msg);
++                        }
++                    }
++
+                     rarg.addStringValue("serialNumber",
+                             xcert.getSerialNumber().toString(16));
+ 
+-                    if (rec.getStatus().equals(ICertRecord.STATUS_REVOKED)
+-                          && !rec.isCertOnHold()) {
+-                        alreadyRevokedCertFound = true;
+-                        CMS.debug(method + "Certificate 0x" + xcert.getSerialNumber().toString(16) + " has already been revoked.");
+-                    } else {
++                    boolean updateRevocation = true;
++                    if ((rec.getStatus().equals(ICertRecord.STATUS_REVOKED) &&
++                            revReason == RevocationReason.KEY_COMPROMISE)) {
++                        updateRevocation = false;
++                        if ((recRevReason == RevocationReason.SUPERSEDED) ||
++                                (rec.isCertOnHold())) {
++                            updateRevocation = true;
++                            CMS.debug(method + "Certificate 0x" + xcert.getSerialNumber().toString(16)
++                                    + " has been revoked, but reason is changed");
++                        } else {
++                            alreadyRevokedCertFound = true;
++                            CMS.debug("Certificate 0x" + xcert.getSerialNumber().toString(16) + " has been revoked.");
++                        }
++                    }
++                    if (updateRevocation) {
+                         oldCertsV.addElement(xcert);
+ 
+-                        RevokedCertImpl revCertImpl =
+-                                new RevokedCertImpl(xcert.getSerialNumber(),
+-                                        CMS.getCurrentDate(), entryExtn);
++                        RevokedCertImpl revCertImpl = new RevokedCertImpl(xcert.getSerialNumber(),
++                                CMS.getCurrentDate(), entryExtn);
+ 
+                         revCertImplsV.addElement(revCertImpl);
+-                        CMS.debug(method + "Certificate 0x" + xcert.getSerialNumber().toString(16) + " is going to be revoked.");
++                        CMS.debug(method + "Certificate 0x" + xcert.getSerialNumber().toString(16)
++                                + " is going to be revoked.");
+                         count++;
+                     }
+                 } else {
+diff --git a/base/server/cmsbundle/src/LogMessages.properties b/base/server/cmsbundle/src/LogMessages.properties
+index 5e51440..ff432b6 100644
+--- a/base/server/cmsbundle/src/LogMessages.properties
++++ b/base/server/cmsbundle/src/LogMessages.properties
+@@ -119,7 +119,9 @@ CMSCORE_CA_STORE_SERIAL=CA stored signed certificate serial number 0x{0}
+ CMSCORE_CA_MARK_SERIAL=CA marked certificate serial number 0x{0} as renewed with serial number 0x{1}
+ CMSCORE_CA_NO_STORE_SERIAL=Could not store certificate serial number 0x{0}
+ CMSCORE_CA_CERT_NOT_FOUND=Cannot find certificate serial number 0x{0}
++CMSCORE_CA_MISSING_REV_REASON=Missing revocation reason for revocation request on serial number 0x{0}
+ CMSCORE_CA_CERT_REVOKED=Revoked certificate serial number 0x{0}
++CMSCORE_CA_CERT_REVO_INFO_UPDATE=Revocation reason changed from {0} to {1} Certificate serial number 0x{2}
+ CMSCORE_CA_ERROR_REVOCATION=Error revoking certificate {0}. Error {1}
+ CMSCORE_CA_CERT_ON_HOLD=Certificate {0} has to be on-hold.
+ CMSCORE_CA_CERT_UNREVOKED=Unrevoked certificate serial number 0x{0}
+diff --git a/base/server/cmsbundle/src/UserMessages.properties b/base/server/cmsbundle/src/UserMessages.properties
+index ed2a620..4d1b755 100644
+--- a/base/server/cmsbundle/src/UserMessages.properties
++++ b/base/server/cmsbundle/src/UserMessages.properties
+@@ -397,6 +397,7 @@ CMS_CA_CERT4CRL_FAILED=One or more revoked certificates could not be recorded by
+ CMS_CA_UNCERT4CRL_FAILED=One or more revoked certificates could not be removed by the CLA
+ CMS_CA_RENEW_FAILED=One or more certificates could not be renewed
+ CMS_CA_CANT_FIND_CERT_SERIAL=Cannot find certificate with serial number {0}
++CMS_CA_MISSING_REV_REASON=Missing revocation reason for revocatoin request on serial number {0}
+ CMS_CA_TOKEN_NOT_FOUND=Token {0} not found
+ CMS_CA_CERT_OBJECT_NOT_FOUND=Certificate object not found
+ CMS_CA_TOKEN_ERROR=Token Error
+diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/CertRecord.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/CertRecord.java
+index a79f7a3..d4f3c03 100644
+--- a/base/server/cmscore/src/com/netscape/cmscore/dbs/CertRecord.java
++++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/CertRecord.java
+@@ -23,12 +23,6 @@ import java.util.Date;
+ import java.util.Enumeration;
+ import java.util.Vector;
+ 
+-import netscape.security.x509.CRLExtensions;
+-import netscape.security.x509.CRLReasonExtension;
+-import netscape.security.x509.RevocationReason;
+-import netscape.security.x509.X509CertImpl;
+-import netscape.security.x509.X509ExtensionException;
+-
+ import com.netscape.certsrv.apps.CMS;
+ import com.netscape.certsrv.base.EBaseException;
+ import com.netscape.certsrv.base.MetaInfo;
+@@ -37,6 +31,12 @@ import com.netscape.certsrv.dbs.IDBObj;
+ import com.netscape.certsrv.dbs.certdb.ICertRecord;
+ import com.netscape.certsrv.dbs.certdb.IRevocationInfo;
+ 
++import netscape.security.x509.CRLExtensions;
++import netscape.security.x509.CRLReasonExtension;
++import netscape.security.x509.RevocationReason;
++import netscape.security.x509.X509CertImpl;
++import netscape.security.x509.X509ExtensionException;
++
+ /**
+  * A class represents a serializable certificate record.
+  * <P>
+@@ -274,27 +274,50 @@ public class CertRecord implements IDBObj, ICertRecord {
+         return mModifyTime;
+     }
+ 
++    /*
++     * getRevReason -
++     * @returns RevocationReason if cert is revoked; null if not
++     * it throws exceptions if anything failed
++     */
++    public RevocationReason getRevReason()
++            throws EBaseException, X509ExtensionException {
++        String method = "CertRecord.getRevReason:";
++        String msg = "";
++        //CMS.debug(method + " checking for cert serial: "
++        //        + getSerialNumber().toString());
++        IRevocationInfo revInfo = getRevocationInfo();
++        if (revInfo == null) {
++            msg = "revInfo null for" + getSerialNumber().toString();
++            CMS.debug(method + msg);
++            return null;
++        }
++
++        CRLExtensions crlExts = revInfo.getCRLEntryExtensions();
++        if (crlExts == null)
++            throw new X509ExtensionException("crlExts null");
++
++        CRLReasonExtension reasonExt = null;
++        reasonExt = (CRLReasonExtension) crlExts.get(CRLReasonExtension.NAME);
++        if (reasonExt == null)
++            throw new EBaseException("reasonExt null");
++
++        return reasonExt.getReason();
++    }
++
+     public boolean isCertOnHold() {
+         String method = "CertRecord.isCertOnHold:";
+         CMS.debug(method + " checking for cert serial: "
+-             + getSerialNumber().toString());
+-        IRevocationInfo revInfo = getRevocationInfo();
+-        if (revInfo != null) {
+-            CRLExtensions crlExts = revInfo.getCRLEntryExtensions();
+-            if (crlExts == null) return false;
+-            CRLReasonExtension reasonExt = null;
+-            try {
+-                reasonExt = (CRLReasonExtension) crlExts.get(CRLReasonExtension.NAME);
+-            } catch (X509ExtensionException e) {
+-                CMS.debug(method + " returning false:" + e.toString());
+-                return false;
+-            }
+-            if (reasonExt.getReason() == RevocationReason.CERTIFICATE_HOLD) {
+-                CMS.debug(method + " returning true");
++                + getSerialNumber().toString());
++        try {
++            RevocationReason revReason = getRevReason();
++            if (revReason == RevocationReason.CERTIFICATE_HOLD) {
++                CMS.debug(method + "for " + getSerialNumber().toString() + " returning true");
+                 return true;
+             }
++        } catch (Exception e) {
++            CMS.debug(method + e);
+         }
+-        CMS.debug(method + " returning false");
++        CMS.debug(method + "for " + getSerialNumber().toString() + " returning false");
+         return false;
+     }
+ 
+diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/CertificateRepository.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/CertificateRepository.java
+index 9a333fe..367917f 100644
+--- a/base/server/cmscore/src/com/netscape/cmscore/dbs/CertificateRepository.java
++++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/CertificateRepository.java
+@@ -1110,19 +1110,21 @@ public class CertificateRepository extends Repository
+ 
+     /**
+      * Marks certificate as revoked.
+-     * isAlreadyOnHold - boolean to indicate that the cert was revoked onHold
+-     *   When a cert was originally onHold, some of the ldap attributes
+-     *   already exist, so "MOD_REPLACE" is needed instead of "MOD_ADD"
++     * isAlreadyRevoked - boolean to indicate that the cert was revoked
++     * ( possibly onHold )
++     * When a cert was originally revoked (possibly onHold),
++     * some of the ldap attributes already exist,
++     * so "MOD_REPLACE" is needed instead of "MOD_ADD"
+      */
+     public void markAsRevoked(BigInteger id, IRevocationInfo info)
+             throws EBaseException {
+         markAsRevoked(id, info, false);
+     }
+-    public void markAsRevoked(BigInteger id, IRevocationInfo info, boolean isAlreadyOnHold)
++
++    public void markAsRevoked(BigInteger id, IRevocationInfo info, boolean isAlreadyRevoked)
+             throws EBaseException {
+-        String method = "CertificateRepository.markAsRevoked:";
+         ModificationSet mods = new ModificationSet();
+-        if (isAlreadyOnHold) {
++        if (isAlreadyRevoked) {
+             mods.add(CertRecord.ATTR_REVO_INFO, Modification.MOD_REPLACE, info);
+         } else {
+             mods.add(CertRecord.ATTR_REVO_INFO, Modification.MOD_ADD, info);
+@@ -1134,30 +1136,30 @@ public class CertificateRepository extends Repository
+          * When already revoked onHold, the fields already existing in record
+          * can only be replaced instead of added
+          */
+-        if (isAlreadyOnHold) {
++        if (isAlreadyRevoked) {
+             if (uid == null) {
+                 mods.add(CertRecord.ATTR_REVOKED_BY, Modification.MOD_REPLACE,
+-                    "system");
++                        "system");
+             } else {
+                 mods.add(CertRecord.ATTR_REVOKED_BY, Modification.MOD_REPLACE,
+-                    uid);
++                        uid);
+             }
+             mods.add(CertRecord.ATTR_REVOKED_ON, Modification.MOD_REPLACE,
+-                CMS.getCurrentDate());
++                    CMS.getCurrentDate());
+         } else {
+             if (uid == null) {
+                 mods.add(CertRecord.ATTR_REVOKED_BY, Modification.MOD_ADD,
+-                    "system");
++                        "system");
+             } else {
+                 mods.add(CertRecord.ATTR_REVOKED_BY, Modification.MOD_ADD,
+-                    uid);
++                        uid);
+             }
+             mods.add(CertRecord.ATTR_REVOKED_ON, Modification.MOD_ADD,
+-                CMS.getCurrentDate());
++                    CMS.getCurrentDate());
++            mods.add(CertRecord.ATTR_CERT_STATUS, Modification.MOD_REPLACE,
++                    CertRecord.STATUS_REVOKED);
+         }
+ 
+-        mods.add(CertRecord.ATTR_CERT_STATUS, Modification.MOD_REPLACE,
+-                CertRecord.STATUS_REVOKED);
+         modifyCertificateRecord(id, mods);
+     }
+ 
+-- 
+1.8.3.1
diff --git a/SPECS/pki-core.spec b/SPECS/pki-core.spec
index dc582cc..142b6f1 100644
--- a/SPECS/pki-core.spec
+++ b/SPECS/pki-core.spec
@@ -66,11 +66,11 @@
 Name:             pki-core
 %if 0%{?rhel}
 Version:          10.4.1
-#Release:          13%{?dist}
-Release:          13.el7_4
+#Release:          17%{?dist}
+Release:          17.el7_4
 %else
 Version:          10.4.8
-Release:          1%{?dist}
+Release:          8%{?dist}
 %endif
 Summary:          Certificate System - PKI Core Components
 URL:              http://pki.fedoraproject.org/
@@ -184,10 +184,10 @@ BuildRequires:    python-ldap
 BuildRequires:    junit
 BuildRequires:    jpackage-utils >= 0:1.7.5-10
 %if 0%{?rhel}
-BuildRequires:    jss >= 4.4.0-7
+BuildRequires:    jss >= 4.4.0-8
 %else
 %if 0%{?fedora} >= 25
-BuildRequires:    jss >= 4.4.2-2
+BuildRequires:    jss >= 4.4.2-5
 %else
 BuildRequires:    jss >= 4.2.6-44
 %endif
@@ -206,6 +206,7 @@ BuildRequires:    tomcatjss >= 7.1.3
 %if 0%{?with_python3}
 BuildRequires:  python3-cryptography
 BuildRequires:  python3-devel
+BuildRequires:  python3-lxml
 BuildRequires:  python3-nss
 BuildRequires:  python3-pyldap
 BuildRequires:  python3-requests >= 2.6.0
@@ -278,11 +279,13 @@ Patch11:          pki-core-CMC-check-HTTPS-client-authentication-cert.patch
 Patch12:          pki-core-Fix-regression-in-pkcs12-key-bag-creation.patch
 #######################
 ## pki-core-10.4.1-11
+## (pki-core 0-day patch)
 #######################
 Patch13:          pki-core-cmc-plugin-default-change.patch
 #######################
 ## pki-core-10.4.1-12
 #######################
+## RHEL 7.4 Batch Update 1
 Patch14:          pki-core-server-access-banner-validation.patch
 Patch15:          pki-core-pre-signed-CMC-renewal-UniqueKeyConstraint.patch
 Patch16:          pki-core-platform-dependent-python-import.patch
@@ -293,7 +296,41 @@ Patch20:          pki-core-system-cert-CMC-enroll-profile.patch
 #######################
 ## pki-core-10.4.1-13
 #######################
+## RHEL 7.4 Batch Update 1
 Patch21:          pki-core-server-access-banner-retrieval-validation.patch
+#######################
+## pki-core-10.4.1-14
+#######################
+## RHEL 7.4 Batch Update 2
+Patch22:          pki-core-Fix-lightweight-CA-replication-NPE-failure.patch
+Patch23:          pki-core-Fix-missing-CN-error-in-CMC-user-signed.patch
+Patch24:          pki-core-FixDeploymentDescriptor-upgrade-scriptlet.patch
+Patch25:          pki-core-KRA-use-AES-in-PKCS12-encrypted-key-recovery.patch
+Patch26:          pki-core-Display-tokenType-and-tokenOrigin-in-TPS-UI-and-CLI-Server.patch
+Patch27:          pki-core-Fix-JSON-encoding-in-Python-3.patch
+## RHCS 9.2 Batch Update 2
+#Patch28:          pki-core-Fix-tokenOrigin-and-tokenType-attrs-in-recovered-certs.patch
+#Patch29:          pki-core-Display-tokenType-and-tokenOrigin-in-TPS-UI-and-CLI.patch
+#######################
+## pki-core-10.4.1-15
+#######################
+Patch30:          pki-core-Make-PKCS12-files-compatible-with-PBES2.patch
+#######################
+## pki-core-10.4.1-16
+#######################
+## RHCS 9.2 Batch Update 3
+#Patch31:          pki-core-externalRegRecover-multiple-KRA.patch
+#Patch32:          pki-core-TPS-applet-protocol-determination.patch
+#Patch33:          pki-core-update-RHCS-cert-revocation-reasons.patch
+## RHEL 7.4 Batch Update 3
+Patch34:          pki-core-update-RHEL-cert-revocation-reasons.patch
+Patch35:          pki-core-fix-issuance-sans-subject-key-ID-ext.patch
+Patch36:          pki-core-fix-ipa-replica-install-timing-issue.patch
+#######################
+## pki-core-10.4.1-17
+#######################
+## RHCS 9.2 Batch Update 3
+Patch37:          pki-core-tps-externalReg-regression.patch
 
 
 
@@ -405,10 +442,10 @@ Requires:         nss >= 3.27.0
 %endif
 Requires:         jpackage-utils >= 0:1.7.5-10
 %if 0%{?rhel}
-Requires:         jss >= 4.4.0-7
+Requires:         jss >= 4.4.0-8
 %else
 %if 0%{?fedora} >= 25
-Requires:         jss >= 4.4.2-2
+Requires:         jss >= 4.4.2-5
 %else
 Requires:         jss >= 4.2.6-44
 %endif
@@ -499,10 +536,10 @@ Requires:         slf4j-jdk14
 Requires:         javassist
 Requires:         jpackage-utils >= 0:1.7.5-10
 %if 0%{?rhel}
-Requires:         jss >= 4.4.0-7
+Requires:         jss >= 4.4.0-8
 %else
 %if 0%{?fedora} >= 25
-Requires:         jss >= 4.4.2-2
+Requires:         jss >= 4.4.2-5
 %else
 Requires:         jss >= 4.2.6-44
 %endif
@@ -568,6 +605,7 @@ BuildArch:        noarch
 Requires:         pki-base = %{version}-%{release}
 
 Requires:         python3-cryptography
+Requires:         python3-lxml
 Requires:         python3-nss
 Requires:         python3-requests >= 2.6.0
 Requires:         python3-six
@@ -982,6 +1020,22 @@ This package is a part of the PKI Core used by the Certificate System.
 %patch19 -p1
 %patch20 -p1
 %patch21 -p1
+%patch22 -p1
+%patch23 -p1
+%patch24 -p1
+%patch25 -p1
+%patch26 -p1
+%patch27 -p1
+#%patch28 -p1
+#%patch29 -p1
+%patch30 -p1
+#%patch31 -p1
+#%patch32 -p1
+#%patch33 -p1
+%patch34 -p1
+%patch35 -p1
+%patch36 -p1
+#%patch37 -p1
 
 %clean
 %{__rm} -rf %{buildroot}
@@ -1507,6 +1561,67 @@ fi
 %endif # %{with server}
 
 %changelog
+* Fri Nov 10 2017 Dogtag Team <pki-devel@redhat.com> 10.4.1-17
+- ###########################################################################
+- ## RHCS 9.2
+- ###########################################################################
+- #Bugzilla Bug #1507160 - TPS new configuration to allow the protocol of
+  #the to determine applet loaded (jmagne)
+
+* Fri Oct 13 2017 Dogtag Team <pki-devel@redhat.com> 10.4.1-16
+- ###########################################################################
+- ## RHCS 9.2
+- ###########################################################################
+- #Bugzilla Bug #1439228 - externalRegRecover does not support multiple
+  #KRA instances (cfu)
+- #Bugzilla Bug #1507160 - TPS new configuration to allow the protocol of
+  #the to determine applet loaded (jmagne)
+- #Bugzilla Bug #1471996 - Certificate Revocation Reasons not being updated
+  #in some cases [RHCS 9] (cfu)
+- ###########################################################################
+- ## RHEL 7.4
+- ###########################################################################
+- Bugzilla Bug #1500499 - Certificate Revocation Reasons not being updated
+  in some cases [rhel-7.4.z] (cfu)
+- Bugzilla Bug #1502527 - CA cert without Subject Key Identifier causes
+  issuance failure [rhel-7.4.z] (ftweedal)
+- Bugzilla Bug #1492560 - ipa-replica-install --setup-kra broken on DL0
+  [rhel-7.4.z] (ftweedal)
+  NOTE: Check-ins for #1492560 all reference the dogtagpki Pagure Issue
+        associated with Bugzilla Bug #1402280 - CA Cloning: Failed to
+        update number range in few cases (which is not yet fully resolved)
+
+* Mon Sep 18 2017 Dogtag Team <pki-devel@redhat.com> 10.4.1-15
+- Bugzilla Bug #1492560 - ipa-replica-install --setup-kra broken on DL0
+  [rhel-7.4.z] (ftweedal)
+
+* Tue Sep 12 2017 Dogtag Team <pki-devel@redhat.com> 10.4.1-14
+- Require "jss >= 4.4.0-8" as a build and runtime requirement
+- ##########################################################################
+- RHEL 7.4:
+- ##########################################################################
+- Resolves: rhbz #1486870,1485833,1487509,1490241,1491332
+- Bugzilla Bug #1486870 - Lightweight CA key replication fails (regressions)
+  [RHEL 7.4.z] (ftweedal)
+- Bugzilla Bug #1485833 - Missing CN in user signing cert would cause error
+  in cmc user-signed [rhel-7.4.z] (cfu)
+- Bugzilla Bug #1487509 - pki-server-upgrade fails when upgrading from
+  RHEL 7.1 [rhel-7.4.z] (ftweedal)
+- Bugzilla Bug #1490241 - PKCS12: upgrade to at least AES and SHA2 (FIPS)
+  [rhel-7.4.z] (ftweedal)
+- Bugzilla Bug #1491332 - TPS UI: need to display tokenType and tokenOrigin
+  for token certificates on TPS UI Server [rhel-7.4.z] (edewata)
+- dogtagpki Pagure Issue #2764 - py3: pki.key.archive_encrypted_data:
+  TypeError: ... is not JSON serializable (ftweedal)
+- ##########################################################################
+- RHCS 9.2:
+- ##########################################################################
+- Resolves: rhbz #1486870,1485833,1487509,1490241,1491332,1482729,1462271
+- Bugzilla Bug #1462271 - TPS incorrectly assigns "tokenOrigin" and
+  "tokenType" certificate attribute for recovered certificates. (cfu)
+- Bugzilla Bug #1482729 - TPS UI: need to display tokenType and tokenOrigin
+  for token certificates on TPS UI (edewata)
+
 * Mon Aug 21 2017 Dogtag Team <pki-devel@redhat.com> 10.4.1-13
 - Resolves: rhbz #1463350
 - ##########################################################################
@@ -2825,7 +2940,7 @@ fi
        to be open in the FW (alee)
 - 'pki-silent'
 
-* Wed Aug 10 2011 Matthew Harmsen <mharmsen@redhat.com> 9.0.11-1
+* Wed Aug 10 2011 Matthew Harmsen <mharmsen@redhat.com> 9.0.12
 - 'pki-setup'
 -      Bugzilla Bug #689909 - Dogtag installation under IPA takes too much
        time - remove the inefficient sleeps (alee)