diff --git a/.gitignore b/.gitignore index 3f75c1a..a57db63 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/pki-core-10.5.16.tar.gz +SOURCES/pki-core-10.5.17.tar.gz diff --git a/.pki-core.metadata b/.pki-core.metadata index f4cf1b7..306bc26 100644 --- a/.pki-core.metadata +++ b/.pki-core.metadata @@ -1 +1 @@ -1430dcca4dd3be3df8029a0e4ea13ef84880c6a8 SOURCES/pki-core-10.5.16.tar.gz +2debe6d869c88d4cd98de0cce80dfe8317d35dbc SOURCES/pki-core-10.5.17.tar.gz diff --git a/SOURCES/pki-core-Add-Subject-Key-ID-to-CSR.patch b/SOURCES/pki-core-Add-Subject-Key-ID-to-CSR.patch deleted file mode 100644 index d425865..0000000 --- a/SOURCES/pki-core-Add-Subject-Key-ID-to-CSR.patch +++ /dev/null @@ -1,366 +0,0 @@ -From 5c459c1861e4132904fe88e99341738f1c3555e8 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Thu, 11 Jan 2018 19:02:09 +1100 -Subject: [PATCH 1/2] install: support adding Subject Key ID to CSR - -For externally-signed CA installation, some users want to be able to -generate a CSR with a Subject Key Identifier extension - either -user-specified or a generated default. - -This commit adds support to NSSDatabase.create_request for -generating a CSR with an SKI extension. The process to achieve this -is: - -1. Generate the key. This behaviour has been extracted to a - separate method (NSSDatabase.generate_key). - -2. If a "default" SKI is requested, generate a throw-away CSR and - compute an SKI value from the public key contained therein. - This is a "minimal" CSR whose only purpose is to get the public - key in a convenient format. - -3. Generate the CSR and write it to the caller-specified file. - This CSR contains all the extensions the caller asked for. - -This commit relies on an enhancement to the certutil(1) program that -allows create a CSR for a private key specified by CKA_ID. - -Part-of: https://pagure.io/dogtagpki/issue/2854 -(cherry picked from commit f1f32c31d51dffb93e7874d8c4dd0325136c4db7) ---- - base/common/python/pki/nssdb.py | 177 ++++++++++++++++++++++++++++++++++------ - 1 file changed, 152 insertions(+), 25 deletions(-) - -diff --git a/base/common/python/pki/nssdb.py b/base/common/python/pki/nssdb.py -index bbcb261..11509f0 100644 ---- a/base/common/python/pki/nssdb.py -+++ b/base/common/python/pki/nssdb.py -@@ -22,14 +22,18 @@ - - from __future__ import absolute_import - import base64 -+import binascii - import logging - import os -+import re - import shutil - import stat - import subprocess - import tempfile - import datetime - -+import six -+ - from cryptography import x509 - from cryptography.hazmat.backends import default_backend - -@@ -444,20 +448,78 @@ class NSSDatabase(object): - basic_constraints_ext=None, - key_usage_ext=None, - extended_key_usage_ext=None, -+ cka_id=None, -+ subject_key_id=None, - generic_exts=None): -+ """ -+ Generate a CSR. -+ -+ ``cka_id`` -+ PKCS #11 CKA_ID of key in the NSSDB to use, as text. -+ If ``None`` a new key will be generated (this is -+ the typical use case). -+ -+ ``subject_key_id`` -+ If ``None``, no Subject Key ID will be included in the -+ request. If ``"DEFAULT"``, the Subject Key ID will be -+ derived from the generated key, using the default -+ digest. Otherwise the value must be a hex-encoded -+ string, without leading ``0x``, containing the desired -+ Subject Key ID. -+ -+ ``generic_exts`` -+ List of generic extensions, each being a mapping with -+ the following keys: -+ -+ ``oid`` -+ Extension OID (``str``) -+ ``critical`` -+ ``bool`` -+ ``data`` -+ Raw extension data (``bytes``) -+ -+ """ -+ if not cka_id: -+ cka_id = self.generate_key( -+ key_type=key_type, key_size=key_size, -+ curve=curve, noise_file=noise_file) -+ if not isinstance(cka_id, six.text_type): -+ raise TypeError('cka_id must be a text string') - - tmpdir = tempfile.mkdtemp() - - try: -- if not noise_file: -- noise_file = os.path.join(tmpdir, 'noise.bin') -- if key_size: -- size = key_size -+ if subject_key_id is not None: -+ if subject_key_id == 'DEFAULT': -+ # Caller wants a default subject key ID included -+ # in CSR. To do this we must first generate a -+ # temporary CSR for the key, then compute an SKI -+ # from the public key data. -+ tmp_csr = os.path.join(tmpdir, 'tmp_csr.pem') -+ self.create_request( -+ subject_dn, tmp_csr, -+ cka_id=cka_id, subject_key_id=None) -+ with open(tmp_csr, 'rb') as f: -+ data = f.read() -+ csr = x509.load_pem_x509_csr(data, default_backend()) -+ pub = csr.public_key() -+ ski = x509.SubjectKeyIdentifier.from_public_key(pub) -+ ski_bytes = ski.digest - else: -- size = 2048 -- self.create_noise( -- noise_file=noise_file, -- size=size) -+ # Explicit subject_key_id provided; decode it -+ ski_bytes = binascii.unhexlify(subject_key_id) -+ -+ if generic_exts is None: -+ generic_exts = [] -+ generic_exts.append({ -+ 'oid': x509.SubjectKeyIdentifier.oid.dotted_string, -+ 'critical': False, -+ 'data': bytearray([0x04, len(ski_bytes)]) + ski_bytes, -+ # OCTET STRING ^tag ^length ^data -+ # -+ # This structure is incorrect if len > 127 bytes, but this -+ # will be fine for a CKA_ID or SKID of sensible length. -+ }) - - binary_request_file = os.path.join(tmpdir, 'request.bin') - -@@ -478,25 +540,9 @@ class NSSDatabase(object): - '-f', self.password_file, - '-s', subject_dn, - '-o', binary_request_file, -- '-z', noise_file -+ '-k', cka_id, - ]) - -- if key_type: -- cmd.extend(['-k', key_type]) -- -- if key_type.lower() == 'ec': -- # This is fix for Bugzilla 1544843 -- cmd.extend([ -- '--keyOpFlagsOn', 'sign', -- '--keyOpFlagsOff', 'derive' -- ]) -- -- if key_size: -- cmd.extend(['-g', str(key_size)]) -- -- if curve: -- cmd.extend(['-q', curve]) -- - if hash_alg: - cmd.extend(['-Z', hash_alg]) - -@@ -603,6 +649,87 @@ class NSSDatabase(object): - finally: - shutil.rmtree(tmpdir) - -+ def generate_key( -+ self, -+ key_type=None, key_size=None, curve=None, -+ noise_file=None): -+ """ -+ Generate a key of the given type and size. -+ Returns the CKA_ID of the generated key, as a text string. -+ -+ ``noise_file`` -+ Path to a noise file, or ``None`` to automatically -+ generate a noise file. -+ -+ """ -+ ids_pre = set(self.list_private_keys()) -+ -+ cmd = [ -+ 'certutil', -+ '-d', self.directory, -+ '-f', self.password_file, -+ '-G', -+ ] -+ if self.token: -+ cmd.extend(['-h', self.token]) -+ if key_type: -+ cmd.extend(['-k', key_type]) -+ if key_type.lower() == 'ec': -+ # This is fix for Bugzilla 1544843 -+ cmd.extend([ -+ '--keyOpFlagsOn', 'sign', -+ '--keyOpFlagsOff', 'derive', -+ ]) -+ if key_size: -+ cmd.extend(['-g', str(key_size)]) -+ if curve: -+ cmd.extend(['-q', curve]) -+ -+ temp_noise_file = noise_file is None -+ if temp_noise_file: -+ fd, noise_file = tempfile.mkstemp() -+ os.close(fd) -+ size = key_size if key_size else 2048 -+ self.create_noise(noise_file=noise_file, size=size) -+ cmd.extend(['-z', noise_file]) -+ -+ try: -+ subprocess.check_call(cmd) -+ finally: -+ if temp_noise_file: -+ os.unlink(noise_file) -+ -+ ids_post = set(self.list_private_keys()) -+ return list(ids_post - ids_pre)[0].decode('ascii') -+ -+ def list_private_keys(self): -+ """ -+ Return list of hex-encoded private key CKA_IDs in the token. -+ -+ """ -+ cmd = [ -+ 'certutil', -+ '-d', self.directory, -+ '-f', self.password_file, -+ '-K', -+ ] -+ if self.token: -+ cmd.extend(['-h', self.token]) -+ try: -+ out = subprocess.check_output(cmd) -+ except subprocess.CalledProcessError as e: -+ if e.returncode == 255: -+ return [] # no keys were found -+ else: -+ raise e # other error; re-raise -+ -+ # output contains list that looks like: -+ # < 0> rsa b995381610fb58e8b45d3c2401dfd30d6efdd595 (orphan) -+ # < 1> rsa dcd6cbc1226ede02a961488553b01639ff981cdd someNickame -+ # -+ # The hex string is the hex-encoded CKA_ID -+ return re.findall(br'^<\s*\d+>\s+\w+\s+(\w+)', out, re.MULTILINE) -+ - def create_cert(self, request_file, cert_file, serial, issuer=None, - key_usage_ext=None, basic_constraints_ext=None, - aki_ext=None, ski_ext=None, aia_ext=None, --- -1.8.3.1 - - -From 8f638afeec1527d581a8dd9eefc84cde69c1c6b6 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Thu, 11 Jan 2018 19:46:40 +1100 -Subject: [PATCH 2/2] install: add pkispawn option for adding SKI to CSR - -For externally-signed CA installation, some users want to be able to -generate a CSR with a Subject Key Identifier extension - either -user-specified or a generated default. - -This commit adds the 'pki_req_ski' pkispwan option for specifying -that the CSR should bear the SKI extension. It can either be a -hex-encoded SKI value or the string "DEFAULT" which asks that the -value be derived from the public key. - -Update the pki_default.cfg.5 man page to document the new option. - -Fixes: https://pagure.io/dogtagpki/issue/2854 -(cherry picked from commit 4f9327b85eab58463adcece81269b823e9def2b4) ---- - base/server/man/man5/pki_default.cfg.5 | 6 ++++++ - base/server/python/pki/server/deployment/pkihelper.py | 2 ++ - .../server/python/pki/server/deployment/scriptlets/configuration.py | 6 +++++- - .../python/pki/server/deployment/scriptlets/security_databases.py | 4 ++++ - 4 files changed, 17 insertions(+), 1 deletion(-) - -diff --git a/base/server/man/man5/pki_default.cfg.5 b/base/server/man/man5/pki_default.cfg.5 -index afdcbfb..4d83fcc 100644 ---- a/base/server/man/man5/pki_default.cfg.5 -+++ b/base/server/man/man5/pki_default.cfg.5 -@@ -352,6 +352,12 @@ Sets whether the new CA will have a signing certificate that will be issued by a - .IP - Required in the first step of the external CA signing process. The CSR will be printed to the screen and stored in this location. - .PP -+.B pki_req_ski -+.IP -+Include a Subject Key Identifier extension in the CSR. The value is either a -+hex-encoded byte string (\fBwithout\fR leading "0x"), or the string "DEFAULT" -+which will derive a value from the public key. -+.PP - .B pki_external_step_two - .IP - Specifies that this is the second step of the external CA process. Defaults to False. -diff --git a/base/server/python/pki/server/deployment/pkihelper.py b/base/server/python/pki/server/deployment/pkihelper.py -index 740caff..48446b0 100644 ---- a/base/server/python/pki/server/deployment/pkihelper.py -+++ b/base/server/python/pki/server/deployment/pkihelper.py -@@ -429,6 +429,8 @@ class ConfigurationFile: - # generic extension support in CSR - for external CA - self.add_req_ext = config.str2bool( - self.mdict['pki_req_ext_add']) -+ # include SKI extension in CSR - for external CA -+ self.req_ski = self.mdict.get('pki_req_ski') - - self.existing = config.str2bool(self.mdict['pki_existing']) - self.external = config.str2bool(self.mdict['pki_external']) -diff --git a/base/server/python/pki/server/deployment/scriptlets/configuration.py b/base/server/python/pki/server/deployment/scriptlets/configuration.py -index b4f3141..3f153ec 100644 ---- a/base/server/python/pki/server/deployment/scriptlets/configuration.py -+++ b/base/server/python/pki/server/deployment/scriptlets/configuration.py -@@ -94,6 +94,7 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet): - basic_constraints_ext=None, - key_usage_ext=None, - extended_key_usage_ext=None, -+ subject_key_id=None, - generic_exts=None): - - cert_id = self.get_cert_id(subsystem, tag) -@@ -121,6 +122,7 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet): - basic_constraints_ext=basic_constraints_ext, - key_usage_ext=key_usage_ext, - extended_key_usage_ext=extended_key_usage_ext, -+ subject_key_id=subject_key_id, - generic_exts=generic_exts) - - with open(csr_path) as f: -@@ -174,7 +176,9 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet): - csr_path, - basic_constraints_ext=basic_constraints_ext, - key_usage_ext=key_usage_ext, -- generic_exts=generic_exts -+ generic_exts=generic_exts, -+ subject_key_id=subsystem.config.get( -+ 'preop.cert.signing.subject_key_id'), - ) - - def generate_sslserver_csr(self, deployer, nssdb, subsystem): -diff --git a/base/server/python/pki/server/deployment/scriptlets/security_databases.py b/base/server/python/pki/server/deployment/scriptlets/security_databases.py -index 7ce32a8..82dd85c 100644 ---- a/base/server/python/pki/server/deployment/scriptlets/security_databases.py -+++ b/base/server/python/pki/server/deployment/scriptlets/security_databases.py -@@ -240,6 +240,10 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet): - subsystem.config['preop.cert.signing.ext.critical'] = \ - deployer.configuration_file.req_ext_critical.lower() - -+ if deployer.configuration_file.req_ski: -+ subsystem.config['preop.cert.signing.subject_key_id'] = \ -+ deployer.configuration_file.req_ski -+ - subsystem.save() - - def update_external_certs_conf(self, external_path, deployer): --- -1.8.3.1 - diff --git a/SOURCES/pki-core-Fixed-Missing-SAN-extension-for-CA-Clone.patch b/SOURCES/pki-core-Fixed-Missing-SAN-extension-for-CA-Clone.patch deleted file mode 100644 index d274eb5..0000000 --- a/SOURCES/pki-core-Fixed-Missing-SAN-extension-for-CA-Clone.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 833c060b26756a17d0b85a19846888d71e4bdd5d Mon Sep 17 00:00:00 2001 -From: "Endi S. Dewata" -Date: Wed, 24 Jul 2019 17:46:30 -0500 -Subject: [PATCH] Fixed missing SAN extension for CA clone - -The CertUtil.buildSANSSLserverURLExtension() has been modified -to include SAN parameters in the request to generate the SSL -server certificate for CA clone. - -https://bugzilla.redhat.com/show_bug.cgi?id=1732637 ---- - .../src/com/netscape/cms/servlet/csadmin/CertUtil.java | 16 +++++++--------- - .../netscape/cms/servlet/csadmin/ConfigurationUtils.java | 16 ++++++++-------- - 2 files changed, 15 insertions(+), 17 deletions(-) - -diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/CertUtil.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/CertUtil.java -index 12d4ac1..e77be32 100644 ---- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/CertUtil.java -+++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/CertUtil.java -@@ -228,34 +228,32 @@ public class CertUtil { - // embed a certificate extension into - // a PKCS #10 certificate request. - // -- public static String buildSANSSLserverURLExtension(IConfigStore config) -+ public static void buildSANSSLserverURLExtension(IConfigStore config, MultivaluedMap content) - throws Exception { -- String url = ""; -- String entries = ""; - - CMS.debug("CertUtil: buildSANSSLserverURLExtension() " + - "building SAN SSL Server Certificate URL extension . . ."); -- int i = 0; -+ - if (config == null) { - throw new EBaseException("injectSANextensionIntoRequest: parameter config cannot be null"); - } -+ - String sanHostnames = config.getString("service.sslserver.san"); - String sans[] = StringUtils.split(sanHostnames, ","); -+ -+ int i = 0; - for (String san : sans) { - CMS.debug("CertUtil: buildSANSSLserverURLExtension() processing " + - "SAN hostname: " + san); - // Add the DNSName for all SANs -- entries = entries + -- "&req_san_pattern_" + i + "=" + san; -+ content.putSingle("req_san_pattern_" + i, san); - i++; - } - -- url = "&req_san_entries=" + i + entries; -+ content.putSingle("req_san_entries", "" + i); - - CMS.debug("CertUtil: buildSANSSLserverURLExtension() " + "placed " + - i + " SAN entries into SSL Server Certificate URL."); -- -- return url; - } - - -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 cc65c78..5395b06 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 -@@ -2685,16 +2685,9 @@ public class ConfigurationUtils { - } catch (Exception ee) { - } - -- String sslserver_extension = ""; -- Boolean injectSAN = config.getBoolean("service.injectSAN", false); -- CMS.debug("ConfigurationUtils: injectSAN: " + injectSAN); -- -- if (certTag.equals("sslserver") && injectSAN == true) { -- sslserver_extension = CertUtil.buildSANSSLserverURLExtension(config); -- } -- - MultivaluedMap content = new MultivaluedHashMap(); - content.putSingle("requestor_name", sysType + "-" + machineName + "-" + securePort); -+ - //Get the correct profile id to send in case it's sslserver type: - CMS.debug("configRemoteCert: tag: " + certTag + " : setting profileId to: " + profileId); - String actualProfileId = request.getSystemCertProfileID(certTag, profileId); -@@ -2706,6 +2699,13 @@ public class ConfigurationUtils { - content.putSingle("xmlOutput", "true"); - content.putSingle("sessionID", session_id); - -+ Boolean injectSAN = config.getBoolean("service.injectSAN", false); -+ CMS.debug("ConfigurationUtils: injectSAN: " + injectSAN); -+ -+ if (certTag.equals("sslserver") && injectSAN) { -+ CertUtil.buildSANSSLserverURLExtension(config, content); -+ } -+ - cert = CertUtil.createRemoteCert(ca_hostname, ca_port, content, response); - - if (cert == null) { --- -1.8.3.1 - diff --git a/SOURCES/pki-core-Fixed-Number-Range-Depletion-Issue.patch b/SOURCES/pki-core-Fixed-Number-Range-Depletion-Issue.patch deleted file mode 100644 index 3581f6e..0000000 --- a/SOURCES/pki-core-Fixed-Number-Range-Depletion-Issue.patch +++ /dev/null @@ -1,515 +0,0 @@ -From 93b1ecae5aff7a18e16556f749c8aba5806dc512 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Wed, 29 Aug 2018 16:55:31 +1000 -Subject: [PATCH 1/5] getTheSerialNumber: only return null if next range not - available - -When cloning, if the master's current number range has been depleted -due to a previous UpdateNumberRange request, -Repository.getTheSerialNumber() returns null because the next serial -number is out of the current range, but the next range has not been -activated yet. NullPointerException ensues. - -Update getTheSerialNumber() to return the next serial number even -when it exceeds the current number range, as long as there is a next -range. If there is no next range, return null (as before). It is -assumed that the next range is non-empty - -Also do a couple of drive-by method extractions to improve -readability. - -Part of: https://pagure.io/dogtagpki/issue/3055 - -(cherry picked from commit f1615df509053a8f474b82ea6a2fa0883ab06d09) ---- - .../src/com/netscape/cmscore/dbs/Repository.java | 61 ++++++++++++++++------ - 1 file changed, 44 insertions(+), 17 deletions(-) - -diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java -index afe9013..c5120c4 100644 ---- a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java -+++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java -@@ -317,7 +317,15 @@ public abstract class Repository implements IRepository { - } - - /** -- * get the next serial number in cache -+ * Peek at the next serial number in cache (does not consume the -+ * number). -+ * -+ * The returned number is not necessarily the previously emitted -+ * serial number plus one, i.e. if we are going to roll into the -+ * next range. This method does not actually switch the range. -+ * -+ * Returns null if the next number exceeds the current range and -+ * there is not a next range. - */ - public BigInteger getTheSerialNumber() throws EBaseException { - -@@ -327,7 +335,7 @@ public abstract class Repository implements IRepository { - BigInteger serial = mLastSerialNo.add(BigInteger.ONE); - - if (mMaxSerialNo != null && serial.compareTo(mMaxSerialNo) > 0) -- return null; -+ return hasNextRange() ? mNextMinSerialNo : null; - else - return serial; - } -@@ -390,9 +398,13 @@ public abstract class Repository implements IRepository { - } - - /** -- * Checks to see if range needs to be switched. -+ * Checks if the given number is in the current range. -+ * If it does not exceed the current range, return cleanly. -+ * If it exceeds the given range, and there is a next range, switch the range. -+ * If it exceeds the given range, and there is not a next range, throw EDBException. - * -- * @exception EBaseException thrown when next range is not allocated -+ * @exception EDBException thrown when range switch is needed -+ * but next range is not allocated - */ - protected void checkRange() throws EBaseException - { -@@ -413,7 +425,7 @@ public abstract class Repository implements IRepository { - - if (mDB.getEnableSerialMgmt()) { - CMS.debug("Reached the end of the range. Attempting to move to next range"); -- if ((mNextMinSerialNo == null) || (mNextMaxSerialNo == null)) { -+ if (!hasNextRange()) { - if (rangeLength != null && mCounter.compareTo(rangeLength) < 0) { - return; - } else { -@@ -421,18 +433,7 @@ public abstract class Repository implements IRepository { - mLastSerialNo.toString())); - } - } -- mMinSerialNo = mNextMinSerialNo; -- mMaxSerialNo = mNextMaxSerialNo; -- mLastSerialNo = mMinSerialNo; -- mNextMinSerialNo = null; -- mNextMaxSerialNo = null; -- mCounter = BigInteger.ZERO; -- -- // persist the changes -- mDB.setMinSerialConfig(mRepo, mMinSerialNo.toString(mRadix)); -- mDB.setMaxSerialConfig(mRepo, mMaxSerialNo.toString(mRadix)); -- mDB.setNextMinSerialConfig(mRepo, null); -- mDB.setNextMaxSerialConfig(mRepo, null); -+ switchToNextRange(); - } else { - throw new EDBException(CMS.getUserMessage("CMS_DBS_LIMIT_REACHED", - mLastSerialNo.toString())); -@@ -441,6 +442,32 @@ public abstract class Repository implements IRepository { - } - - /** -+ * Return true iff there is a next range ready to go. -+ */ -+ private boolean hasNextRange() { -+ return (mNextMinSerialNo != null) && (mNextMaxSerialNo != null); -+ } -+ -+ /** -+ * Switch to the next range and persist the changes. -+ */ -+ private void switchToNextRange() -+ throws EBaseException { -+ mMinSerialNo = mNextMinSerialNo; -+ mMaxSerialNo = mNextMaxSerialNo; -+ mLastSerialNo = mMinSerialNo; -+ mNextMinSerialNo = null; -+ mNextMaxSerialNo = null; -+ mCounter = BigInteger.ZERO; -+ -+ // persist the changes -+ mDB.setMinSerialConfig(mRepo, mMinSerialNo.toString(mRadix)); -+ mDB.setMaxSerialConfig(mRepo, mMaxSerialNo.toString(mRadix)); -+ mDB.setNextMinSerialConfig(mRepo, null); -+ mDB.setNextMaxSerialConfig(mRepo, null); -+ } -+ -+ /** - * Checks to see if a new range is needed, or if we have reached the end of the - * current range, or if a range conflict has occurred. - * --- -1.8.3.1 - - -From 35714763d32425f18a0ac8817aad96c8cfab589b Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Mon, 3 Sep 2018 15:55:35 +1000 -Subject: [PATCH 2/5] Repository: handle depleted range in initCache() - -Repository.initCache() does not handle the case where the current -range has been fully depleted, but the switch to the next range has -not occurred yet. This situation arises when the range has been -fully depleted by servicing UpdateNumberRange requests for clones. - -Detect this situation and handle it by switching to the next range -(when available). - -Part of: https://pagure.io/dogtagpki/issue/3055 - -(cherry picked from commit 2fb3611db5145dbdd5e7e14daaad1470691494f0) ---- - .../src/com/netscape/cmscore/dbs/Repository.java | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java -index c5120c4..828217c 100644 ---- a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java -+++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java -@@ -298,6 +298,25 @@ public abstract class Repository implements IRepository { - BigInteger theSerialNo = null; - theSerialNo = getLastSerialNumberInRange(mMinSerialNo, mMaxSerialNo); - -+ if (theSerialNo == null) { -+ // This arises when range has been depleted by servicing -+ // UpdateNumberRange requests for clones. Attempt to -+ // move to next range. -+ CMS.debug( -+ "Repository: failed to get last serial number in range " -+ + mMinSerialNo + ".." + mMaxSerialNo); -+ -+ if (hasNextRange()) { -+ CMS.debug("Repository: switching to next range."); -+ switchToNextRange(); -+ CMS.debug("Repository: new range: " + mMinSerialNo + ".." + mMaxSerialNo); -+ // try again with updated range -+ theSerialNo = getLastSerialNumberInRange(mMinSerialNo, mMaxSerialNo); -+ } else { -+ CMS.debug("Repository: next range not available."); -+ } -+ } -+ - if (theSerialNo != null) { - - mLastSerialNo = new BigInteger(theSerialNo.toString()); --- -1.8.3.1 - - -From e1345a22c1d5236754fbeb93b0d3f8f2c447d918 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Wed, 29 Aug 2018 17:31:34 +1000 -Subject: [PATCH 3/5] rename method getTheSerialNumber -> peekNextSerialNumber - -Rename Repository.getTheSerialNumber -> peekNextSerialNumber to more -accurately reflect what it does: peek at the next serial number -without actually consuming it. - -Part of: https://pagure.io/dogtagpki/issue/3055 - -(cherry picked from commit 85e356580f64f87c0b01736b71dc3d385db0bcba) ---- - base/ca/src/com/netscape/ca/CertificateAuthority.java | 2 +- - base/common/src/com/netscape/certsrv/dbs/repository/IRepository.java | 2 +- - .../cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java | 2 +- - base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java | 2 +- - 4 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java -index 0281db0..f414628 100644 ---- a/base/ca/src/com/netscape/ca/CertificateAuthority.java -+++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java -@@ -1077,7 +1077,7 @@ public class CertificateAuthority - public String getStartSerial() { - try { - BigInteger serial = -- mCertRepot.getTheSerialNumber(); -+ mCertRepot.peekNextSerialNumber(); - - if (serial == null) - return ""; -diff --git a/base/common/src/com/netscape/certsrv/dbs/repository/IRepository.java b/base/common/src/com/netscape/certsrv/dbs/repository/IRepository.java -index 39744ac..d0b6135 100644 ---- a/base/common/src/com/netscape/certsrv/dbs/repository/IRepository.java -+++ b/base/common/src/com/netscape/certsrv/dbs/repository/IRepository.java -@@ -50,7 +50,7 @@ public interface IRepository { - * @return serial number - * @exception EBaseException failed to retrieve next serial number - */ -- public BigInteger getTheSerialNumber() throws EBaseException; -+ public BigInteger peekNextSerialNumber() throws EBaseException; - - /** - * Set the maximum serial number. -diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java -index 2586da2..e5b5168 100644 ---- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java -+++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java -@@ -187,7 +187,7 @@ public class UpdateNumberRange extends CMSServlet { - BigInteger decrement = new BigInteger(decrementStr, radix); - beginNum = endNum.subtract(decrement).add(oneNum); - -- if (beginNum.compareTo(repo.getTheSerialNumber()) < 0) { -+ if (beginNum.compareTo(repo.peekNextSerialNumber()) < 0) { - String nextEndNumStr = cs.getString(nextEndConfig, ""); - BigInteger endNum2 = new BigInteger(nextEndNumStr, radix); - CMS.debug("Transferring from the end of on-deck range"); -diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java -index 828217c..55068ea 100644 ---- a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java -+++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java -@@ -346,7 +346,7 @@ public abstract class Repository implements IRepository { - * Returns null if the next number exceeds the current range and - * there is not a next range. - */ -- public BigInteger getTheSerialNumber() throws EBaseException { -+ public BigInteger peekNextSerialNumber() throws EBaseException { - - CMS.debug("Repository:In getTheSerialNumber "); - if (mLastSerialNo == null) --- -1.8.3.1 - - -From 26586f3e711f1e238d4692f801dd8de42b88fc53 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Wed, 29 Aug 2018 21:42:40 +1000 -Subject: [PATCH 4/5] checkRange: small refactor and add commentary - -Add some commentary about the behaviour and proper usage of -Repository.checkRange(). Also perform a small refactor, avoiding -a redundant stringify and parse. - -Part of: https://pagure.io/dogtagpki/issue/3055 - -(cherry picked from commit 5a606e83719272fb488047b28a9ca7d5ce2ea30b) ---- - .../src/com/netscape/cmscore/dbs/Repository.java | 19 +++++++++++++++---- - 1 file changed, 15 insertions(+), 4 deletions(-) - -diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java -index 55068ea..9bc7e2a 100644 ---- a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java -+++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java -@@ -406,14 +406,17 @@ public abstract class Repository implements IRepository { - throw new EBaseException("mLastSerialNo is null"); - } - -+ /* Advance the serial number. checkRange() will check if it exceeds -+ * the current range and, if so, rolls to the next range and resets -+ * mLastSerialNo to the start of the new range. Hence we return -+ * mLastSerialNo below, after the call to checkRange(). -+ */ - mLastSerialNo = mLastSerialNo.add(BigInteger.ONE); - - checkRange(); - -- BigInteger retSerial = new BigInteger(mLastSerialNo.toString()); -- -- CMS.debug("Repository: getNextSerialNumber: returning retSerial " + retSerial); -- return retSerial; -+ CMS.debug("Repository: getNextSerialNumber: returning " + mLastSerialNo); -+ return mLastSerialNo; - } - - /** -@@ -422,6 +425,14 @@ public abstract class Repository implements IRepository { - * If it exceeds the given range, and there is a next range, switch the range. - * If it exceeds the given range, and there is not a next range, throw EDBException. - * -+ * Precondition: the serial number should already have been advanced. -+ * This method will detect that and switch to the next range, including -+ * resetting mLastSerialNo to the start of the new (now current) range. -+ * -+ * Postcondition: the caller should again read mLastSerialNo after -+ * calling checkRange(), in case checkRange switched the range and the -+ * new range is not adjacent to the current range. -+ * - * @exception EDBException thrown when range switch is needed - * but next range is not allocated - */ --- -1.8.3.1 - - -From 57edb3ee50b3ae634ee31ed643e2bb3a891b80fa Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Wed, 29 Aug 2018 22:22:10 +1000 -Subject: [PATCH 5/5] Add missing synchronisation for range management - -Several methods in Repository (and CertificateRepository) need -synchronisation on the intrisic lock. Make these methods -synchronised. - -Also take the lock in UpdateNumberRange so that no serial numbers -can be handed out in other threads between peekNextSerialNumber() -and set(Next)?MaxSerial(). Without this synchronisation, it is -possible that the master instance will use some of the serial -numbers it transfers to the clone. - -Fixes: https://pagure.io/dogtagpki/issue/3055 -(cherry picked from commit 851a0bdd79c12c627a04cfc376338c1727cd50d9) ---- - .../cms/servlet/csadmin/UpdateNumberRange.java | 35 +++++++----- - .../cmscore/dbs/CertificateRepository.java | 62 ++++++++++------------ - .../src/com/netscape/cmscore/dbs/Repository.java | 6 +-- - 3 files changed, 53 insertions(+), 50 deletions(-) - -diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java -index e5b5168..c2ff7ed 100644 ---- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java -+++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java -@@ -187,20 +187,27 @@ public class UpdateNumberRange extends CMSServlet { - BigInteger decrement = new BigInteger(decrementStr, radix); - beginNum = endNum.subtract(decrement).add(oneNum); - -- if (beginNum.compareTo(repo.peekNextSerialNumber()) < 0) { -- String nextEndNumStr = cs.getString(nextEndConfig, ""); -- BigInteger endNum2 = new BigInteger(nextEndNumStr, radix); -- CMS.debug("Transferring from the end of on-deck range"); -- String newValStr = endNum2.subtract(decrement).toString(radix); -- repo.setNextMaxSerial(newValStr); -- cs.putString(nextEndConfig, newValStr); -- beginNum = endNum2.subtract(decrement).add(oneNum); -- endNum = endNum2; -- } else { -- CMS.debug("Transferring from the end of the current range"); -- String newValStr = beginNum.subtract(oneNum).toString(radix); -- repo.setMaxSerial(newValStr); -- cs.putString(endNumConfig, newValStr); -+ /* We need to synchronise on repo because we peek the next -+ * serial number, then set the max serial of the current or -+ * next range. If we don't synchronize, we could end up -+ * using serial numbers that were transferred. -+ */ -+ synchronized (repo) { -+ if (beginNum.compareTo(repo.peekNextSerialNumber()) < 0) { -+ String nextEndNumStr = cs.getString(nextEndConfig, ""); -+ BigInteger endNum2 = new BigInteger(nextEndNumStr, radix); -+ CMS.debug("Transferring from the end of on-deck range"); -+ String newValStr = endNum2.subtract(decrement).toString(radix); -+ repo.setNextMaxSerial(newValStr); -+ cs.putString(nextEndConfig, newValStr); -+ beginNum = endNum2.subtract(decrement).add(oneNum); -+ endNum = endNum2; -+ } else { -+ CMS.debug("Transferring from the end of the current range"); -+ String newValStr = beginNum.subtract(oneNum).toString(radix); -+ repo.setMaxSerial(newValStr); -+ cs.putString(endNumConfig, newValStr); -+ } - } - - if (beginNum == null) { -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 367917f..94087c8 100644 ---- a/base/server/cmscore/src/com/netscape/cmscore/dbs/CertificateRepository.java -+++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/CertificateRepository.java -@@ -251,49 +251,45 @@ public class CertificateRepository extends Repository - return nextSerialNumber; - } - -- private Object nextSerialNumberMonitor = new Object(); -- -- public BigInteger getNextSerialNumber() throws -+ public synchronized BigInteger getNextSerialNumber() throws - EBaseException { - - BigInteger nextSerialNumber = null; - BigInteger randomNumber = null; - -- synchronized (nextSerialNumberMonitor) { -- super.initCacheIfNeeded(); -- CMS.debug("CertificateRepository: getNextSerialNumber mEnableRandomSerialNumbers="+mEnableRandomSerialNumbers); -+ super.initCacheIfNeeded(); -+ CMS.debug("CertificateRepository: getNextSerialNumber mEnableRandomSerialNumbers="+mEnableRandomSerialNumbers); - -- if (mEnableRandomSerialNumbers) { -- int i = 0; -- do { -- if (i > 0) { -- CMS.debug("CertificateRepository: getNextSerialNumber regenerating serial number"); -- } -- randomNumber = getRandomNumber(); -- nextSerialNumber = getRandomSerialNumber(randomNumber); -- nextSerialNumber = checkSerialNumbers(randomNumber, nextSerialNumber); -- i++; -- } while (nextSerialNumber == null && i < mMaxCollisionRecoveryRegenerations); -- -- if (nextSerialNumber == null) { -- CMS.debug("CertificateRepository: in getNextSerialNumber nextSerialNumber is null"); -- throw new EBaseException( "nextSerialNumber is null" ); -+ if (mEnableRandomSerialNumbers) { -+ int i = 0; -+ do { -+ if (i > 0) { -+ CMS.debug("CertificateRepository: getNextSerialNumber regenerating serial number"); - } -+ randomNumber = getRandomNumber(); -+ nextSerialNumber = getRandomSerialNumber(randomNumber); -+ nextSerialNumber = checkSerialNumbers(randomNumber, nextSerialNumber); -+ i++; -+ } while (nextSerialNumber == null && i < mMaxCollisionRecoveryRegenerations); - -- if (mCounter.compareTo(BigInteger.ZERO) >= 0 && -- mMinSerialNo != null && mMaxSerialNo != null && -- nextSerialNumber != null && -- nextSerialNumber.compareTo(mMinSerialNo) >= 0 && -- nextSerialNumber.compareTo(mMaxSerialNo) <= 0) { -- mCounter = mCounter.add(BigInteger.ONE); -- } -- CMS.debug("CertificateRepository: getNextSerialNumber nextSerialNumber="+ -- nextSerialNumber+" mCounter="+mCounter); -+ if (nextSerialNumber == null) { -+ CMS.debug("CertificateRepository: in getNextSerialNumber nextSerialNumber is null"); -+ throw new EBaseException( "nextSerialNumber is null" ); -+ } - -- super.checkRange(); -- } else { -- nextSerialNumber = super.getNextSerialNumber(); -+ if (mCounter.compareTo(BigInteger.ZERO) >= 0 && -+ mMinSerialNo != null && mMaxSerialNo != null && -+ nextSerialNumber != null && -+ nextSerialNumber.compareTo(mMinSerialNo) >= 0 && -+ nextSerialNumber.compareTo(mMaxSerialNo) <= 0) { -+ mCounter = mCounter.add(BigInteger.ONE); - } -+ CMS.debug("CertificateRepository: getNextSerialNumber nextSerialNumber="+ -+ nextSerialNumber+" mCounter="+mCounter); -+ -+ super.checkRange(); -+ } else { -+ nextSerialNumber = super.getNextSerialNumber(); - } - - return nextSerialNumber; -diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java -index 9bc7e2a..c31d376 100644 ---- a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java -+++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java -@@ -185,7 +185,7 @@ public abstract class Repository implements IRepository { - * @param serial maximum number - * @exception EBaseException failed to set maximum serial number - */ -- public void setMaxSerial(String serial) throws EBaseException { -+ public synchronized void setMaxSerial(String serial) throws EBaseException { - BigInteger maxSerial = null; - CMS.debug("Repository:setMaxSerial " + serial); - -@@ -211,7 +211,7 @@ public abstract class Repository implements IRepository { - * @param serial maximum number in next range - * @exception EBaseException failed to set maximum serial number in next range - */ -- public void setNextMaxSerial(String serial) throws EBaseException { -+ public synchronized void setNextMaxSerial(String serial) throws EBaseException { - BigInteger maxSerial = null; - CMS.debug("Repository:setNextMaxSerial " + serial); - -@@ -346,7 +346,7 @@ public abstract class Repository implements IRepository { - * Returns null if the next number exceeds the current range and - * there is not a next range. - */ -- public BigInteger peekNextSerialNumber() throws EBaseException { -+ public synchronized BigInteger peekNextSerialNumber() throws EBaseException { - - CMS.debug("Repository:In getTheSerialNumber "); - if (mLastSerialNo == null) --- -1.8.3.1 - diff --git a/SOURCES/pki-core-Fixed-missing-audit-event.patch b/SOURCES/pki-core-Fixed-missing-audit-event.patch new file mode 100644 index 0000000..7389107 --- /dev/null +++ b/SOURCES/pki-core-Fixed-missing-audit-event.patch @@ -0,0 +1,84 @@ +From 624dc7f769c2a7744bd390eff3e3c6cd0dbd140f Mon Sep 17 00:00:00 2001 +From: Christina Fu +Date: Thu, 17 Oct 2019 16:36:05 -0700 +Subject: [PATCH] =?UTF-8?q?Bug=201523330=20-=20(addl=20fix)=20CC:=20missin?= + =?UTF-8?q?g=20audit=20event=20for=20CS=20acting=20as=20TLS=20client=20Bug?= + =?UTF-8?q?=201585722=20-=20TMS=20-=20PKISocketFactory=20=E2=80=93=20Modif?= + =?UTF-8?q?y=20Logging=20to=20Allow=20External=20Use=20of=20class=20to=20w?= + =?UTF-8?q?ork=20like=20CS8?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix in 1523330 might have broken 1585722; This patch is to put the audit +call under if (!external) so that external apps calling this class would +not reach the audit code. +I only tested to be sure that the CA continues to work; QE will need to +test both again. + +https://bugzilla.redhat.com/show_bug.cgi?id=1523330 +https://bugzilla.redhat.com/show_bug.cgi?id=1585722 +(cherry picked from commit 4dfd4893b6598d79ad5d5542795c4792091905c7) +--- + .../cmscore/ldapconn/PKISocketFactory.java | 27 ++++++++++++---------- + 1 file changed, 15 insertions(+), 12 deletions(-) + +diff --git a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java +index dc93f5d..6f5a876 100644 +--- a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java ++++ b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java +@@ -85,12 +85,12 @@ public class PKISocketFactory implements LDAPSSLSocketFactoryExt { + if(!external){ + IConfigStore cs = CMS.getConfigStore(); + keepAlive = cs.getBoolean("tcp.keepAlive", true); ++ sockListener = new PKIClientSocketListener(); + } else { + keepAlive = true; + } + + log(Level.INFO, "TCP Keep-Alive: " + keepAlive, null); +- sockListener = new PKIClientSocketListener(); + + } catch (Exception e) { + log(Level.SEVERE, null, e); +@@ -162,23 +162,26 @@ public class PKISocketFactory implements LDAPSSLSocketFactoryExt { + s.setKeepAlive(keepAlive); + + } catch (Exception e) { +- // for auditing +- String localIP = "localhost"; +- try { +- localIP = InetAddress.getLocalHost().getHostAddress(); +- } catch (UnknownHostException e2) { +- // default to "localhost"; +- } +- SignedAuditEvent auditEvent; +- auditEvent = ClientAccessSessionEstablishEvent.createFailureEvent( ++ if (!external) { ++ // for auditing ++ String localIP = "localhost"; ++ try { ++ localIP = InetAddress.getLocalHost().getHostAddress(); ++ } catch (UnknownHostException e2) { ++ // default to "localhost"; ++ } ++ ++ SignedAuditEvent auditEvent; ++ auditEvent = ClientAccessSessionEstablishEvent.createFailureEvent( + localIP, + host, + Integer.toString(port), + "SYSTEM", + "connect:" +e.toString()); +- signedAuditLogger.log(auditEvent); ++ signedAuditLogger.log(auditEvent); ++ } ++ log(Level.SEVERE, null, e); + +- CMS.debug(e); + if (s != null) { + try { + s.close(); +-- +1.8.3.1 + diff --git a/SOURCES/pki-core-Internal-LDAP-Server-goes-down-Audit-Event.patch b/SOURCES/pki-core-Internal-LDAP-Server-goes-down-Audit-Event.patch deleted file mode 100644 index 24280bf..0000000 --- a/SOURCES/pki-core-Internal-LDAP-Server-goes-down-Audit-Event.patch +++ /dev/null @@ -1,65 +0,0 @@ -From b5655c1f309893919435766e0e17f8d811680abb Mon Sep 17 00:00:00 2001 -From: Christina Fu -Date: Fri, 6 Sep 2019 16:49:00 -0400 -Subject: [PATCH] Bug 1523330 - CC: missing audit event for CS acting as TLS - client - -This patch adds failed CLIENT_ACCESS_SESSION_ESTABLISH audit event for the case -when internal ldap server goes down - -fixes https://bugzilla.redhat.com/show_bug.cgi?id=1523330 - -(cherry picked from commit 10d52dd0d6b562edc9e32c543017c67c1c0212a8) ---- - .../netscape/cmscore/ldapconn/PKISocketFactory.java | 21 +++++++++++++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java -index e9f28c9..e992016 100644 ---- a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java -+++ b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java -@@ -31,6 +31,9 @@ import org.mozilla.jss.ssl.SSLSocket; - - import com.netscape.certsrv.apps.CMS; - import com.netscape.certsrv.base.IConfigStore; -+import com.netscape.certsrv.logging.event.ClientAccessSessionEstablishEvent; -+import com.netscape.certsrv.logging.SignedAuditEvent; -+import com.netscape.cms.logging.SignedAuditLogger; - - import netscape.ldap.LDAPException; - import netscape.ldap.LDAPSSLSocketFactoryExt; -@@ -44,6 +47,8 @@ import org.dogtagpki.server.PKIClientSocketListener; - */ - public class PKISocketFactory implements LDAPSSLSocketFactoryExt { - -+ private static SignedAuditLogger signedAuditLogger = SignedAuditLogger.getLogger(); -+ - private boolean secure; - private String mClientAuthCertNickname; - private boolean mClientAuth; -@@ -140,6 +145,22 @@ public class PKISocketFactory implements LDAPSSLSocketFactoryExt { - s.setKeepAlive(keepAlive); - - } catch (Exception e) { -+ // for auditing -+ String localIP = "localhost"; -+ try { -+ localIP = InetAddress.getLocalHost().getHostAddress(); -+ } catch (UnknownHostException e2) { -+ // default to "localhost"; -+ } -+ SignedAuditEvent auditEvent; -+ auditEvent = ClientAccessSessionEstablishEvent.createFailureEvent( -+ localIP, -+ host, -+ Integer.toString(port), -+ "SYSTEM", -+ "connect:" +e.toString()); -+ signedAuditLogger.log(auditEvent); -+ - CMS.debug(e); - if (s != null) { - try { --- -1.8.3.1 - diff --git a/SOURCES/pki-core-PKI-startup-init-LDAP-operation-attr-independence.patch b/SOURCES/pki-core-PKI-startup-init-LDAP-operation-attr-independence.patch deleted file mode 100644 index 76e7ac7..0000000 --- a/SOURCES/pki-core-PKI-startup-init-LDAP-operation-attr-independence.patch +++ /dev/null @@ -1,541 +0,0 @@ -From d24a4a587dbd9e67d4401d3032008cdfe015f69b Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Mon, 12 Nov 2018 11:47:48 +1100 -Subject: [PATCH 1/2] LDAPProfileSubsystem: add watchdog timer for initial load - -During initial profile loading, if we receive fewer entries than -indicated by the parent entry's numSubordinates attribute, the -AsyncLoader will not unlock, and the Dogtag startup thread is -blocked. This situation can arise when there are entries that are -contributing to the numSubordinates count, which are not visible to -Dogtag. Replication conflicts are one such example. - -The implementation currently uses a persistent search that also -returns existing entries. The alternative approach - a regular -search followed by a persistent search - leaves open the possibility -of missing replicated changes to the subtree that were processed in -between the regular and persistent search. Therefore we use a -single search, which avoids this possibility. - -We also *do* want to block startup until all profiles are loaded. -The system reporting ready before profiles are loaded has led to -issues in CI and production environments. During a persistent -search, there is no in-band signal that indicates when all the -"immediate" results have been delivered. The solution was to read -the numSubordinates value of the container to know how many -immediate results to process. So we have to address the corner -cases discussed above. - -The approach to resolving this is to use a watchdog timer during -initial load of profiles. The AsyncLoader is now initialised with a -timeout value (in seconds). A timer is started and the lock is -forcibly released after the timeout. A value <= 0 suppresses the -watchdog. Update the LDAPProfileSubsystem to time out the loader -after 10 seconds. The existing behaviour of unlocking when the -expected number of entries have been processed is maintained. - -Also add a log message when the start await gets interrupted, to -indicate that there may be replication conflicts or other extraneous -data in the profile configuration subtree. - -Fixes: https://pagure.io/dogtagpki/issue/3078 -(cherry picked from commit 758d2a7e551e532f464419d68306cf13e096fe85) ---- - .../src/com/netscape/certsrv/util/AsyncLoader.java | 105 +++++++++++++++++++-- - .../cmscore/profile/LDAPProfileSubsystem.java | 65 +++++++++---- - 2 files changed, 145 insertions(+), 25 deletions(-) - -diff --git a/base/common/src/com/netscape/certsrv/util/AsyncLoader.java b/base/common/src/com/netscape/certsrv/util/AsyncLoader.java -index 39f8efd..6d10531 100644 ---- a/base/common/src/com/netscape/certsrv/util/AsyncLoader.java -+++ b/base/common/src/com/netscape/certsrv/util/AsyncLoader.java -@@ -18,6 +18,8 @@ - - package com.netscape.certsrv.util; - -+import java.util.Timer; -+import java.util.TimerTask; - import java.util.concurrent.CountDownLatch; - import java.util.concurrent.locks.ReentrantLock; - -@@ -33,28 +35,54 @@ import java.util.concurrent.locks.ReentrantLock; - */ - public class AsyncLoader { - private CountDownLatch producerInitialised = new CountDownLatch(1); -- private ReentrantLock loadingLock = new ReentrantLock(); -+ private GoAwayLock loadingLock = new GoAwayLock(); - private Integer numItems = null; - private int numItemsLoaded = 0; -+ private boolean loading = true; -+ private int timeoutSeconds = 0; -+ private Timer timer = new Timer("AsyncLoader watchdog"); -+ private TimerTask watchdog = null; -+ -+ /** Create an AsyncLoader with the specified timeout. -+ * -+ * If timeoutSeconds > 0, startLoading() will start a timer -+ * that will forcibly unlock the loader after the specified -+ * timeout. -+ */ -+ public AsyncLoader(int timeoutSeconds) { -+ this.timeoutSeconds = timeoutSeconds; -+ } - - /** -- * Acquire the lock as a producer. -+ * Acquire the lock as a producer and reset -+ * progress-tracking variables. - */ - public void startLoading() { -+ loadingLock.lock(); -+ loading = true; - numItems = null; - numItemsLoaded = 0; -- loadingLock.lock(); - producerInitialised.countDown(); -+ if (timeoutSeconds > 0) { -+ if (watchdog != null) -+ watchdog.cancel(); -+ watchdog = new AsyncLoaderWatchdog(); -+ timer.schedule(watchdog, timeoutSeconds * 1000); -+ } - } - - /** - * Increment the number of items loaded by 1. If the number - * of items is known and that many items have been loaded, - * unlock the loader. -+ * -+ * If the loader is not currently loading, does nothing. - */ - public void increment() { -- numItemsLoaded += 1; -- checkLoadDone(); -+ if (loading) { -+ numItemsLoaded += 1; -+ checkLoadDone(); -+ } - } - - /** -@@ -69,18 +97,77 @@ public class AsyncLoader { - - private void checkLoadDone() { - if (numItems != null && numItemsLoaded >= numItems) { -+ watchdog.cancel(); -+ loading = false; - while (loadingLock.isHeldByCurrentThread()) - loadingLock.unlock(); - } - } - -+ /** -+ * Wait upon the consumer to finish loading items. -+ * -+ * @throws InterruptedException if the thread is interrupted -+ * while waiting for the loading lock. This can happen due -+ * to timeout. -+ */ - public void awaitLoadDone() throws InterruptedException { - /* A consumer may await upon the Loader immediately after - * starting the producer. To ensure that the producer -- * has time to acquire the lock, we use a CountDownLatch. -+ * has time to acquire the lock, we use a CountDownLatch -+ * that only the producer can release (in 'startLoading'). - */ -- producerInitialised.await(); -- loadingLock.lock(); -- loadingLock.unlock(); -+ if (loading) { -+ producerInitialised.await(); -+ loadingLock.lockInterruptibly(); -+ loadingLock.unlock(); -+ } -+ } -+ -+ /** Forcibly unlock this AsyncLoader. -+ * -+ * There's no way we can safely interrupt the producer to -+ * release the loadingLock. So here's what we do. -+ * -+ * - Interrupt all threads that are waiting on the lock. -+ * - Set loading = false so that future call to awaitLoadDone() -+ * return immediately. -+ * -+ * Upon subseqent re-loads (e.g. due to loss and reesablishment -+ * of LDAP persistent search), the producer thread will call -+ * startLoading() again, which will increment the producer's -+ * hold count. That's OK because when the unlock condition is -+ * met, checkLoadDone() will call loadingLock.unlock() as many -+ * times as needed to effect the unlock. -+ * -+ * This method DOES NOT interrupt threads waiting on the -+ * producerInitialised CountDownLatch. The producer MUST call -+ * startLoading() which will acquire the loading lock then -+ * release the CountDownLatch. -+ */ -+ private void forceUnlock() { -+ loading = false; -+ loadingLock.interruptWaitingThreads(); -+ } -+ -+ /** Subclass of ReentrantLock that can tell waiting threads -+ * to go away (by interrupting them). Awaiters must use -+ * lockInterruptibly() to acquire the lock. -+ * -+ * This needed to be a subclass of ReentrantLock because -+ * ReentrantLock.getQueuedThreads() has visibility 'protected'. -+ */ -+ private static class GoAwayLock extends ReentrantLock { -+ public void interruptWaitingThreads() { -+ for (Thread thread : getQueuedThreads()) { -+ thread.interrupt(); -+ } -+ } -+ } -+ -+ private class AsyncLoaderWatchdog extends TimerTask { -+ public void run() { -+ forceUnlock(); -+ } - } - } -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 bce675e..7a9d0ba 100644 ---- a/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java -+++ b/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java -@@ -58,7 +58,9 @@ public class LDAPProfileSubsystem - extends AbstractProfileSubsystem - implements IProfileSubsystem, Runnable { - -- private String dn; -+ private String profileContainerDNString; -+ private DN profileContainerDN; -+ - private ILdapConnFactory dbFactory; - - private boolean stopped = false; -@@ -73,7 +75,7 @@ public class LDAPProfileSubsystem - /* Set of nsUniqueIds of deleted entries */ - private TreeSet deletedNsUniqueIds; - -- private AsyncLoader loader = new AsyncLoader(); -+ private AsyncLoader loader = new AsyncLoader(10 /*10s timeout*/); - - /** - * Initializes this subsystem with the given configuration -@@ -112,7 +114,8 @@ public class LDAPProfileSubsystem - - // read profile id, implementation, and its configuration files - String basedn = cs.getString("internaldb.basedn"); -- dn = "ou=certificateProfiles,ou=ca," + basedn; -+ profileContainerDNString = "ou=certificateProfiles,ou=ca," + basedn; -+ profileContainerDN = new DN(profileContainerDNString); - - monitor = new Thread(this, "profileChangeMonitor"); - monitor.start(); -@@ -121,6 +124,8 @@ public class LDAPProfileSubsystem - } catch (InterruptedException e) { - CMS.debug("LDAPProfileSubsystem: caught InterruptedException " - + "while waiting for initial load of profiles."); -+ CMS.debug("You may have replication conflict entries or " -+ + "extraneous data under " + profileContainerDNString); - } - CMS.debug("LDAPProfileSubsystem: finished init"); - } -@@ -294,12 +299,10 @@ public class LDAPProfileSubsystem - } - - private synchronized void handleMODDN(DN oldDN, LDAPEntry entry) { -- DN profilesDN = new DN(dn); -- -- if (oldDN.isDescendantOf(profilesDN)) -+ if (oldDN.isDescendantOf(profileContainerDN)) - forgetProfile(oldDN.explodeDN(true)[0]); - -- if ((new DN(entry.getDN())).isDescendantOf(profilesDN)) -+ if ((new DN(entry.getDN())).isDescendantOf(profileContainerDN)) - readProfile(entry); - } - -@@ -384,12 +387,14 @@ public class LDAPProfileSubsystem - if (id == null) { - throw new EProfileException("CMS_PROFILE_ID_NOT_FOUND"); - } -- return "cn=" + id + "," + dn; -+ return "cn=" + id + "," + profileContainerDNString; - } - - private void ensureProfilesOU(LDAPConnection conn) throws LDAPException { - try { -- conn.search(dn, LDAPConnection.SCOPE_BASE, "(objectclass=*)", null, false); -+ conn.search( -+ profileContainerDNString, LDAPConnection.SCOPE_BASE, -+ "(objectclass=*)", null, false); - } catch (LDAPException e) { - if (e.getLDAPResultCode() == LDAPException.NO_SUCH_OBJECT) { - CMS.debug("Adding LDAP certificate profiles container"); -@@ -398,7 +403,7 @@ public class LDAPProfileSubsystem - new LDAPAttribute("ou", "certificateProfiles") - }; - LDAPAttributeSet attrSet = new LDAPAttributeSet(attrs); -- LDAPEntry entry = new LDAPEntry(dn, attrSet); -+ LDAPEntry entry = new LDAPEntry(profileContainerDNString, attrSet); - conn.add(entry); - } - } -@@ -426,8 +431,8 @@ public class LDAPProfileSubsystem - cons.setServerTimeLimit(0 /* seconds */); - String[] attrs = {"*", "entryUSN", "nsUniqueId", "numSubordinates"}; - LDAPSearchResults results = conn.search( -- dn, LDAPConnection.SCOPE_SUB, "(objectclass=*)", -- attrs, false, cons); -+ profileContainerDNString, LDAPConnection.SCOPE_SUB, -+ "(objectclass=*)", attrs, false, cons); - - /* Wait until the last possible moment before taking - * the load lock and dropping all profiles, so that -@@ -443,16 +448,44 @@ public class LDAPProfileSubsystem - - while (!stopped && results.hasMoreElements()) { - LDAPEntry entry = results.next(); -- -- String[] objectClasses = -- entry.getAttribute("objectClass").getStringValueArray(); -- if (Arrays.asList(objectClasses).contains("organizationalUnit")) { -+ DN entryDN = new DN(entry.getDN()); -+ -+ if (entryDN.countRDNs() == profileContainerDN.countRDNs()) { -+ /* This is the profile container. Read numSubordinates to get -+ * the expected number of profiles entries to read. -+ * -+ * numSubordinates is not reliable; it may be too high -+ * due to objects we cannot see (e.g. replication conflict -+ * entries). In that case AsyncLoader has a watchdog -+ * timer to interrupt waiting threads. -+ */ - loader.setNumItems(new Integer( - entry.getAttribute("numSubordinates") - .getStringValueArray()[0])); - continue; - } - -+ if (entryDN.countRDNs() > profileContainerDN.countRDNs() + 1) { -+ /* This entry is unexpectedly deep. We ignore it. -+ * numSubordinates only counts immediate subordinates -+ * (https://tools.ietf.org/html/draft-boreham-numsubordinates-01) -+ * so don't increment() the AsyncLoader. -+ */ -+ continue; -+ } -+ -+ /* This entry is at the expected depth. Is it a certProfile? */ -+ String[] objectClasses = -+ entry.getAttribute("objectClass").getStringValueArray(); -+ if (!Arrays.asList(objectClasses).contains("certProfile")) { -+ /* It is not a certProfile; ignore it. But it does -+ * contribute to numSubordinates so increment the loader. */ -+ loader.increment(); -+ continue; -+ } -+ -+ /* We have a profile. Process it. */ -+ - LDAPEntryChangeControl changeControl = (LDAPEntryChangeControl) - LDAPUtil.getControl( - LDAPEntryChangeControl.class, results.getResponseControls()); --- -1.8.3.1 - - -From 94ce76abe56b680982b363bca8edf6d10d6d9a7f Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Thu, 28 Mar 2019 18:06:20 +1100 -Subject: [PATCH 2/2] Add watchdog timer for initial load of LWCAs - -Similar to the work done for LDAPProfileSubsystem, to avoid hanging -startup when the number of entries processed during initial load of -LWCAs is less than suggested by the numSubordinates attribute of the -container entry (replication conflict entries can cause this). -Switch the authority monitor to use AsyncLoader which provides the -watchdog timer, and takes care of some of the existing logic. - -Also add a log message when the startup await gets interrupted, to -indicate that there may be replication conflicts or other extraneous -data in the LWCA subtree. - -Related: https://pagure.io/dogtagpki/issue/3078 -(cherry picked from commit 54c15eb4eba3568eace3791d183f8d2700e5d04e) ---- - .../src/com/netscape/ca/CertificateAuthority.java | 102 +++++++++++---------- - 1 file changed, 55 insertions(+), 47 deletions(-) - -diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java -index 90a8fba..0281db0 100644 ---- a/base/ca/src/com/netscape/ca/CertificateAuthority.java -+++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java -@@ -125,6 +125,7 @@ import com.netscape.certsrv.request.IRequestScheduler; - import com.netscape.certsrv.request.IService; - import com.netscape.certsrv.request.RequestStatus; - import com.netscape.certsrv.security.ISigningUnit; -+import com.netscape.certsrv.util.AsyncLoader; - import com.netscape.certsrv.util.IStatsSubsystem; - import com.netscape.cms.logging.Logger; - import com.netscape.cms.logging.SignedAuditLogger; -@@ -335,20 +336,10 @@ public class CertificateAuthority - private boolean mUseNonces = true; - private int mMaxNonces = 100; - -- /* Variables to manage loading and tracking of lightweight CAs -- * -- * The initialLoadDone latch causes the host authority's 'init' -- * method to block until the monitor thread has finished the -- * initial loading of lightweight CAs. -- * -- * In other words: the "server startup" cannot complete until -- * all the lightweight CAs that exist at start time are loaded. -- */ -+ /* Variables to manage loading and tracking of lightweight CAs */ - private static boolean stopped = false; - private static boolean foundHostAuthority = false; -- private static Integer initialNumAuthorities = null; -- private static int numAuthoritiesLoaded = 0; -- private static CountDownLatch initialLoadDone = new CountDownLatch(1); -+ private AsyncLoader lwcaLoader = new AsyncLoader(10 /*10s timeout*/); - - /* Maps and sets of entryUSNs and nsUniqueIds for avoiding race - * conditions and unnecessary reloads related to replication */ -@@ -637,10 +628,17 @@ public class CertificateAuthority - if (isHostAuthority() && haveLightweightCAsContainer()) { - new Thread(this, "authorityMonitor").start(); - try { -- initialLoadDone.await(); -+ // block until the expected number of authorities -+ // have been loaded (based on numSubordinates of -+ // container entry), or watchdog times it out (in case -+ // numSubordinates is larger than the number of entries -+ // we can see, e.g. replication conflict entries). -+ lwcaLoader.awaitLoadDone(); - } catch (InterruptedException e) { - CMS.debug("CertificateAuthority: caught InterruptedException " - + "while waiting for initial load of authorities."); -+ CMS.debug("You may have replication conflict entries or " -+ + "extraneous data under " + authorityBaseDN()); - } - - if (!foundHostAuthority) { -@@ -3260,12 +3258,6 @@ public class CertificateAuthority - } - } - -- private void checkInitialLoadDone() { -- if (initialNumAuthorities != null -- && numAuthoritiesLoaded >= initialNumAuthorities) -- initialLoadDone.countDown(); -- } -- - public void run() { - int op = LDAPPersistSearchControl.ADD - | LDAPPersistSearchControl.MODIFY -@@ -3274,6 +3266,9 @@ public class CertificateAuthority - LDAPPersistSearchControl persistCtrl = - new LDAPPersistSearchControl(op, false, true, true); - -+ String lwcaContainerDNString = authorityBaseDN(); -+ DN lwcaContainerDN = new DN(lwcaContainerDNString); -+ - CMS.debug("authorityMonitor: starting."); - - while (!stopped) { -@@ -3286,38 +3281,52 @@ public class CertificateAuthority - cons.setServerTimeLimit(0 /* seconds */); - String[] attrs = {"*", "entryUSN", "nsUniqueId", "numSubordinates"}; - LDAPSearchResults results = conn.search( -- authorityBaseDN(), LDAPConnection.SCOPE_SUB, -+ lwcaContainerDNString, LDAPConnection.SCOPE_SUB, - "(objectclass=*)", attrs, false, cons); -+ -+ /* Wait until the last possible moment before taking -+ * the load lock so that we can continue to service -+ * requests while LDAP is down. -+ */ -+ lwcaLoader.startLoading(); -+ - while (!stopped && results.hasMoreElements()) { - LDAPEntry entry = results.next(); -+ DN entryDN = new DN(entry.getDN()); -+ -+ if (entryDN.countRDNs() == lwcaContainerDN.countRDNs()) { -+ /* This must be the base entry of the search, i.e. the -+ * LWCA container. Read numSubordinates to get the -+ * expected number of LWCA entries to read. -+ * -+ * numSubordinates is not reliable; it may be too high -+ * due to objects we cannot see (e.g. replication -+ * conflict entries). In that case AsyncLoader has a -+ * watchdog timer to interrupt waiting threads after it -+ * times out. -+ */ -+ lwcaLoader.setNumItems(new Integer( -+ entry.getAttribute("numSubordinates") -+ .getStringValueArray()[0])); -+ continue; -+ } - -- /* This behaviour requires detailed explanation. -- * -- * We want to block startup until all the -- * lightweight CAs existing at startup time are -- * loaded. To do this, we need to know how many -- * authority entries there are. And we must do -- * this atomically - we cannot issue two LDAP -- * searches in case things change. -- * -- * Therefore, we do a subtree search from the -- * authority container. When we find the -- * container (objectClass=organizationalUnit), -- * we set initialNumAuthorities to the value of -- * its numSubordinates attribute. -- * -- * We increment numAuthoritiesLoaded for each -- * authority entry. When numAuthoritiesLoaded -- * equals initialNumAuthorities, we unlock the -- * initialLoadDone latch. -- */ -+ if (entryDN.countRDNs() > lwcaContainerDN.countRDNs() + 1) { -+ /* This entry is unexpectedly deep. We ignore it. -+ * numSubordinates only counts immediate subordinates -+ * (https://tools.ietf.org/html/draft-boreham-numsubordinates-01) -+ * so don't increment() the AsyncLoader. -+ */ -+ continue; -+ } -+ -+ /* This entry is at the expected depth. Is it a LWCA entry? */ - String[] objectClasses = - entry.getAttribute("objectClass").getStringValueArray(); -- if (Arrays.asList(objectClasses).contains("organizationalUnit")) { -- initialNumAuthorities = new Integer( -- entry.getAttribute("numSubordinates") -- .getStringValueArray()[0]); -- checkInitialLoadDone(); -+ if (!Arrays.asList(objectClasses).contains("authority")) { -+ /* It is not a LWCA entry; ignore it. But it does -+ * contribute to numSubordinates so increment the loader. */ -+ lwcaLoader.increment(); - continue; - } - -@@ -3352,8 +3361,7 @@ public class CertificateAuthority - } else { - CMS.debug("authorityMonitor: immediate result"); - readAuthority(entry); -- numAuthoritiesLoaded += 1; -- checkInitialLoadDone(); -+ lwcaLoader.increment(); - } - } - } catch (ELdapException e) { --- -1.8.3.1 - diff --git a/SOURCES/pki-core-rhel-7-8-rhcs-9-6-alpha.patch b/SOURCES/pki-core-rhel-7-8-rhcs-9-6-alpha.patch new file mode 100644 index 0000000..25f39d5 --- /dev/null +++ b/SOURCES/pki-core-rhel-7-8-rhcs-9-6-alpha.patch @@ -0,0 +1,734 @@ +From fb857eac7f74c91fda65dd9d676b28b6df2eaa78 Mon Sep 17 00:00:00 2001 +From: "Endi S. Dewata" +Date: Thu, 3 Jan 2019 20:08:36 -0600 +Subject: [PATCH 1/7] Removed validation for token state transitions + +The TPSSubsystem has been modified to remove the validation for +tokendb.allowedTransitions property. This will allow adding new +transitions via PKI CLI or TPS Web UI. + +The TPSSubsystem will continue to validate tps.operations.allowedTransitions +as before so it will only allow transitions already defined in +the default CS.cfg. + +https://bugzilla.redhat.com/show_bug.cgi?id=1470433 +(cherry picked from commit e9079332d66f166cd89673e2160fd52dbb48728c) +--- + .../src/org/dogtagpki/server/tps/TPSSubsystem.java | 4 +- + docs/admin/TPS_Token_Lifecycle.md | 139 +++++++++++++++++++++ + 2 files changed, 141 insertions(+), 2 deletions(-) + create mode 100644 docs/admin/TPS_Token_Lifecycle.md + +diff --git a/base/tps/src/org/dogtagpki/server/tps/TPSSubsystem.java b/base/tps/src/org/dogtagpki/server/tps/TPSSubsystem.java +index 2f43ba3..0e8f318 100644 +--- a/base/tps/src/org/dogtagpki/server/tps/TPSSubsystem.java ++++ b/base/tps/src/org/dogtagpki/server/tps/TPSSubsystem.java +@@ -126,8 +126,8 @@ public class TPSSubsystem implements IAuthority, ISubsystem { + + FileConfigStore defaultConfig = new FileConfigStore("/usr/share/pki/tps/conf/CS.cfg"); + +- uiTransitions = loadAndValidateTokenStateTransitions( +- defaultConfig, cs, TPSEngine.CFG_TOKENDB_ALLOWED_TRANSITIONS); ++ uiTransitions = loadTokenStateTransitions( ++ cs, TPSEngine.CFG_TOKENDB_ALLOWED_TRANSITIONS); + + operationTransitions = loadAndValidateTokenStateTransitions( + defaultConfig, cs, TPSEngine.CFG_OPERATIONS_ALLOWED_TRANSITIONS); +diff --git a/docs/admin/TPS_Token_Lifecycle.md b/docs/admin/TPS_Token_Lifecycle.md +new file mode 100644 +index 0000000..194a95f +--- /dev/null ++++ b/docs/admin/TPS_Token_Lifecycle.md +@@ -0,0 +1,139 @@ ++# TPS Token Lifecycle ++ ++## Token States ++ ++Below are the supported token states in TPS: ++ ++| Code | Name | Label | ++| ---- | ----------- | ---------------------------- | ++| 0 | FORMATTED | Formatted (uninitialized) | ++| 1 | DAMAGED | Physically damaged | ++| 2 | PERM_LOST | Permanently lost | ++| 3 | SUSPENDED | Suspended (temporarily lost) | ++| 4 | ACTIVE | Active | ++| 6 | TERMINATED | Terminated | ++| 7 | UNFORMATTED | Unformatted | ++ ++In the CS.cfg the token states will be displayed by their codes. ++In PKI CLI the token states will be displayed by their names. ++In TPS Web UI the token states will be displayed by their labels. ++ ++## Token State Transitions via PKI CLI or TPS Web UI ++ ++Token state can be changed via PKI CLI or TPS Web UI. ++The transitions that can be done via PKI CLI or TPS Web UI are defined in the following property in ++/etc/pki/<instance>/tps/CS.cfg: ++ ++``` ++tokendb.allowedTransitions=0:1,0:2,0:3,0:6,3:2,3:6,4:1,4:2,4:3,4:6,6:7 ++``` ++ ++The property contains a comma-separated list of transitions. Each transition is written in this format: ++ ++ : ++ ++The above list represents the following transitions: ++ ++| Transition | Current State | Next State | Label | ++| ---------- | ------------- | ----------- | -------------------------------------------------------------- | ++| 0:1 | FORMATTED | DAMAGED | This token has been physically damaged. | ++| 0:2 | FORMATTED | PERM_LOST | This token has been permanently lost. | ++| 0:3 | FORMATTED | SUSPENDED | This token has been suspended (temporarily lost). | ++| 0:6 | FORMATTED | TERMINATED | This token has been terminated. | ++| 3:2 | SUSPENDED | TERMINATED | This suspended (temporarily lost) token has been terminated. | ++| 3:6 | SUSPENDED | PERM_LOST | This suspended (temporarily lost) has become permanently lost. | ++| 4:1 | ACTIVE | DAMAGED | This token has been physically damaged. | ++| 4:2 | ACTIVE | PERM_LOST | This token has been permanently lost. | ++| 4:3 | ACTIVE | SUSPENDED | This token has been suspended (temporarily lost). | ++| 4:6 | ACTIVE | TERMINATED | This token has been terminated. | ++| 6:7 | TERMINATED | UNFORMATTED | Reuse this token. | ++ ++The following transitions are generated automatically depending on the original state of the token. ++If a token was originally FORMATTED then became SUSPENDED, it can only return to FORMATTED state. ++If a token was originally ACTIVE then became SUSPENDED, it can only return to the ACTIVE state. ++ ++| Transition | Current State | Next State | Label | ++| ---------- | ------------- | ---------- | ------------------------------------------------------- | ++| 3:2 | SUSPENDED | FORMATTED | This suspended (temporarily lost) token has been found. | ++| 3:4 | SUSPENDED | ACTIVE | This suspended (temporarily lost) token has been found. | ++ ++To customize the tokendb.allowedTransitions property, edit the property in /etc/pki/<instance>/tps/CS.cfg, ++then restart the server. ++ ++## Token State Transitions via Token Operations ++ ++Token states can also be changed via token operations (e.g. format, enroll). ++The transitions that can be done via token operations are defined in the following property in ++/etc/pki/<instance>/tps/CS.cfg: ++ ++``` ++tps.operations.allowedTransitions=0:0,0:4,4:4,4:0,7:0 ++``` ++ ++The property contains a comma-delimited list of transitions. ++Each transition is written in this format: ++ ++ : ++ ++The above list represents the following transitions: ++ ++| Transition | Current State | Next State | Description | ++| ---------- | ------------- | ---------- | --------------------------------------------------------------------- | ++| 0:0 | FORMATTED | FORMATTED | This allows reformatting a token or upgrading applet/key in a token. | ++| 0:4 | FORMATTED | ACTIVE | This allows enrolling a token. | ++| 4:4 | ACTIVE | ACTIVE | This allows re-enrolling an active token (for external registration). | ++| 4:0 | ACTIVE | FORMATTED | This allows formatting an active token. | ++| 7:0 | UNFORMATTED | FORMATTED | This allows formatting a blank or previously used token. | ++ ++To customize the tps.operations.allowedTransitions property, edit the property in /etc/pki/<instance>/tps/CS.cfg, ++then restart the server. ++ ++This property can only be customized to remove transitions from the original list. ++New transitions cannot be added into tps.operations.allowedTransitions unless it is already defined ++in the default tps.operations.allowedTransitions in /usr/share/pki/tps/conf/CS.cfg. ++ ++## Token State and Transition Labels for TPS Web UI ++ ++The default token state and transition labels for TPS Web UI are defined in /usr/share/pki/tps/conf/token-states.properties: ++ ++``` ++# Token states ++UNFORMATTED = Unformatted ++FORMATTED = Formatted (uninitialized) ++ACTIVE = Active ++SUSPENDED = Suspended (temporarily lost) ++PERM_LOST = Permanently lost ++DAMAGED = Physically damaged ++TEMP_LOST_PERM_LOST = Temporarily lost then permanently lost ++TERMINATED = Terminated ++ ++# Token state transitions ++FORMATTED.DAMAGED = This token has been physically damaged. ++FORMATTED.PERM_LOST = This token has been permanently lost. ++FORMATTED.SUSPENDED = This token has been suspended (temporarily lost). ++FORMATTED.TERMINATED = This token has been terminated. ++SUSPENDED.ACTIVE = This suspended (temporarily lost) token has been found. ++SUSPENDED.PERM_LOST = This suspended (temporarily lost) token has become permanently lost. ++SUSPENDED.TERMINATED = This suspended (temporarily lost) token has been terminated. ++SUSPENDED.FORMATTED = This suspended (temporarily lost) token has been found. ++ACTIVE.DAMAGED = This token has been physically damaged. ++ACTIVE.PERM_LOST = This token has been permanently lost. ++ACTIVE.SUSPENDED = This token has been suspended (temporarily lost). ++ACTIVE.TERMINATED = This token has been terminated. ++TERMINATED.UNFORMATTED = Reuse this token. ++``` ++ ++To customize the labels, copy the default token-states.properties into TPS configuration folder: ++ ++``` ++$ cp /usr/share/pki/tps/conf/token-states.properties /var/lib/pki/pki-tomcat/tps/conf ++``` ++Then edit the new file. ++There is no need to restart the server, but the TPS Web UI will need to be reloaded. ++ ++To remove the customized labels simply delete the customized file: ++ ++``` ++$ rm /var/lib/pki/pki-tomcat/tps/conf/token-states.properties ++``` ++Then reload the TPS Web UI. +-- +1.8.3.1 + + +From 80c61529b041dca01116726535de87f18a5d16cd Mon Sep 17 00:00:00 2001 +From: Christina Fu +Date: Thu, 15 Aug 2019 12:23:57 -0400 +Subject: [PATCH 2/7] Resolve (additional patch for) Bug 1470410 - TPS doesn't + update revocation status when certificate already marked as + unformatted/terminated/damaged + +This is one of the previously missed patches. +Submited by RHCS-maint + +(cherry picked from commit e4b9e6ed3cf03bd8c026d2d944b615f9b306219a) +--- + base/ca/src/com/netscape/ca/CAService.java | 8 +++++--- + .../src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java | 3 ++- + 2 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/base/ca/src/com/netscape/ca/CAService.java b/base/ca/src/com/netscape/ca/CAService.java +index e4e4efe..4e8afac 100644 +--- a/base/ca/src/com/netscape/ca/CAService.java ++++ b/base/ca/src/com/netscape/ca/CAService.java +@@ -981,7 +981,7 @@ public class CAService implements ICAService, IService { + CRLExtensions crlentryexts = crlentry.getExtensions(); + String msg = ""; + +- CMS.debug("CAService.revokeCert: revokeCert begins"); ++ CMS.debug("CAService.revokeCert: revokeCert begins: serial:" + serialno.toString()); + + // Get the revocation reason + Enumeration enum1 = crlentryexts.getElements(); +@@ -1000,6 +1000,7 @@ public class CAService implements ICAService, IService { + CMS.getUserMessage("CMS_CA_MISSING_REV_REASON", + "0x" + serialno.toString(16))); + } ++ CMS.debug("CAService.revokeCert: revocaton request revocation reason: " + revReason.toString()); + + CertRecord certRec = (CertRecord) mCA.getCertificateRepository().readCertificateRecord(serialno); + +@@ -1026,6 +1027,7 @@ public class CAService implements ICAService, IService { + CMS.debug("CAService.revokeCert: " + msg); + throw new EBaseException(msg); + } ++ CMS.debug("CAService.revokeCert: already revoked cert with existing revocation reason:" + recRevReason.toString()); + } + + // for cert already revoked, also check whether revocation reason is changed from SUPERSEDED to KEY_COMPROMISE +@@ -1044,11 +1046,11 @@ public class CAService implements ICAService, IService { + try { + // if cert has already revoked, update the revocation info only + CMS.debug("CAService.revokeCert: about to call markAsRevoked"); +- if (certStatus.equals(ICertRecord.STATUS_REVOKED) && certRec.isCertOnHold()) { ++ if (certStatus.equals(ICertRecord.STATUS_REVOKED)) { + mCA.getCertificateRepository().markAsRevoked(serialno, + new RevocationInfo(revdate, crlentryexts), + true /*isAlreadyRevoked*/); +- CMS.debug("CAService.revokeCert: on_hold cert marked revoked"); ++ CMS.debug("CAService.revokeCert: Already-revoked cert marked revoked"); + mCA.log(ILogger.LL_INFO, + CMS.getLogMessage("CMSCORE_CA_CERT_REVO_INFO_UPDATE", + recRevReason.toString(), +diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java b/base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java +index 39529c9..16ae5fd 100644 +--- a/base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java ++++ b/base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java +@@ -540,10 +540,11 @@ public class CARemoteRequestHandler extends RemoteRequestHandler + } else { + CMS.debug("CARemoteRequestHandler: revokeCertificate(): using default ca ID:" + connid); + } +- CMS.debug("CARemoteRequestHandler: revokeCertificate(): begins on serial#:" + serialno); ++ CMS.debug("CARemoteRequestHandler: revokeCertificate(): begins"); + if (serialno == null || reason == null) { + throw new EBaseException("CARemoteRequestHandler: revokeCertificate(): input parameter null."); + } ++ CMS.debug("CARemoteRequestHandler: revokeCertificate(): revoking serial#:" + serialno + "; reason String:" + reason.toString() + "; reason code:" + reason.getCode()); + + // IConfigStore conf = CMS.getConfigStore(); + +-- +1.8.3.1 + + +From aef8f648e4651f29cec0ba7e8235185d94e8f39b Mon Sep 17 00:00:00 2001 +From: Christina Fu +Date: Thu, 15 Aug 2019 18:21:33 -0400 +Subject: [PATCH 3/7] Resolve (additiona patch for) Bug 1470433 - Add supported + transitions to TPS + +per suggestion in comment#4 + +Submited by RHCS-maint. + +(cherry picked from commit f9c10c352fc2129cd9f2cdf6baade6e445de5bd0) +--- + base/tps/shared/conf/CS.cfg | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/base/tps/shared/conf/CS.cfg b/base/tps/shared/conf/CS.cfg +index 8a9d828..eb5b831 100644 +--- a/base/tps/shared/conf/CS.cfg ++++ b/base/tps/shared/conf/CS.cfg +@@ -2448,7 +2448,7 @@ tokendb.addConfigTemplate=addConfig.template + tokendb.addResultTemplate=addResults.template + tokendb.agentSelectConfigTemplate=agentSelectConfig.template + tokendb.agentViewConfigTemplate=agentViewConfig.template +-tokendb.allowedTransitions=0:1,0:2,0:3,0:6,3:2,3:6,4:1,4:2,4:3,4:6,6:7 ++tokendb.allowedTransitions=0:1,0:2,0:3,0:6,3:2,3:6,4:1,4:2,4:3,4:6,6:7,1:2,7:1,7:2,6:1,6:2,3:1,3:4 + tokendb.auditAdminTemplate=auditAdmin.template + tokendb.auditLog=[PKI_INSTANCE_PATH]/logs/tokendb-audit.log + tokendb.baseDN=ou=Tokens,[TOKENDB_ROOT] +-- +1.8.3.1 + + +From a336e4d5a27f4de9d39b4e8131e0da5889ad8dd4 Mon Sep 17 00:00:00 2001 +From: Christina Fu +Date: Mon, 19 Aug 2019 21:26:23 -0400 +Subject: [PATCH 4/7] =?UTF-8?q?Resolve=20Bug=201585722=20-=20TMS=20-=20PKI?= + =?UTF-8?q?SocketFactory=20=E2=80=93=20Modify=20Logging=20to=20Allow=20Ext?= + =?UTF-8?q?ernal=20Use=20of=20class=20to=20work=20like=20CS8?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Submited by RHCS-maint. + +(cherry picked from commit 67b3b4fa936aa60618c2084dbbc15e8f9a13a699) +--- + .../cmscore/ldapconn/PKISocketFactory.java | 59 +++++++++++++++++----- + 1 file changed, 45 insertions(+), 14 deletions(-) + +diff --git a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java +index e9f28c9..00df65b 100644 +--- a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java ++++ b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java +@@ -23,6 +23,8 @@ import java.net.Socket; + import java.net.UnknownHostException; + import java.util.Iterator; + import java.util.Vector; ++import java.util.logging.Level; ++import java.util.logging.Logger; + + import org.mozilla.jss.ssl.SSLClientCertificateSelectionCallback; + import org.mozilla.jss.ssl.SSLHandshakeCompletedEvent; +@@ -48,6 +50,7 @@ public class PKISocketFactory implements LDAPSSLSocketFactoryExt { + private String mClientAuthCertNickname; + private boolean mClientAuth; + private boolean keepAlive; ++ private static boolean external = false; + PKIClientSocketListener sockListener = null; + + public PKISocketFactory() { +@@ -65,22 +68,34 @@ public class PKISocketFactory implements LDAPSSLSocketFactoryExt { + init(); + } + ++ public PKISocketFactory(String certNickname, boolean external) { ++ this.secure = true; ++ PKISocketFactory.external = external; ++ mClientAuthCertNickname = certNickname; ++ init(); ++ } ++ + public void init() { + try { +- IConfigStore cs = CMS.getConfigStore(); +- keepAlive = cs.getBoolean("tcp.keepAlive", true); +- CMS.debug("TCP Keep-Alive: " + keepAlive); ++ if(!external){ ++ IConfigStore cs = CMS.getConfigStore(); ++ keepAlive = cs.getBoolean("tcp.keepAlive", true); ++ } else { ++ keepAlive = true; ++ } ++ ++ log(Level.INFO, "TCP Keep-Alive: " + keepAlive, null); + sockListener = new PKIClientSocketListener(); + + } catch (Exception e) { +- CMS.debug(e); ++ log(Level.SEVERE, null, e); + throw new RuntimeException("Unable to read TCP configuration: " + e, e); + } + } + + public SSLSocket makeSSLSocket(String host, int port) throws UnknownHostException, IOException { + String method = "ldapconn/PKISocketFactory.makeSSLSocket: "; +- CMS.debug(method + "begins"); ++ log(Level.INFO, method + "begins", null); + + /* + * let inherit TLS range and cipher settings +@@ -115,8 +130,8 @@ public class PKISocketFactory implements LDAPSSLSocketFactoryExt { + + if (mClientAuthCertNickname != null) { + mClientAuth = true; +- CMS.debug("LdapJssSSLSocket: set client auth cert nickname " + +- mClientAuthCertNickname); ++ log(Level.INFO, method + " set client auth cert nickname " + ++ mClientAuthCertNickname, null); + + //We have already established the manual cert selection callback + //Doing it this way will provide some debugging info on the candidate certs +@@ -127,6 +142,8 @@ public class PKISocketFactory implements LDAPSSLSocketFactoryExt { + } + + public Socket makeSocket(String host, int port) throws LDAPException { ++ String method = "ldapconn/PKISocketFactory.makeSocket: "; ++ log(Level.INFO, method + "begins", null); + Socket s = null; + + try { +@@ -145,7 +162,7 @@ public class PKISocketFactory implements LDAPSSLSocketFactoryExt { + try { + s.close(); + } catch (IOException e1) { +- CMS.debug(e1); ++ log(Level.SEVERE, null, e1); + } + } + throw new LDAPException("Unable to create socket: " + e); +@@ -165,6 +182,20 @@ public class PKISocketFactory implements LDAPSSLSocketFactoryExt { + public void log(int level, String msg) { + } + ++ private static void log(Level level, String msg, Exception e) { ++ if(!external && e != null){ ++ CMS.debug(e); ++ } else if (!external) { ++ CMS.debug(msg); ++ } else { ++ if(e != null){ ++ Logger.getLogger("PKISocketFactory").log(level, e.getMessage()); ++ } else { ++ Logger.getLogger("PKISocketFactory").log(level, msg); ++ } ++ } ++ } ++ + static class ClientHandshakeCB implements SSLHandshakeCompletedListener { + Object sc; + +@@ -173,7 +204,7 @@ public class PKISocketFactory implements LDAPSSLSocketFactoryExt { + } + + public void handshakeCompleted(SSLHandshakeCompletedEvent event) { +- CMS.debug("SSL handshake happened"); ++ log(Level.INFO, "SSL handshake happened", null); + } + } + +@@ -181,14 +212,14 @@ public class PKISocketFactory implements LDAPSSLSocketFactoryExt { + String desiredCertName = null; + + public SSLClientCertificateSelectionCB(String clientAuthCertNickname) { +- CMS.debug("SSLClientCertificateSelectionCB: Setting desired cert nickname to: " + clientAuthCertNickname); ++ log(Level.INFO, "SSLClientCertificateSelectionCB: Setting desired cert nickname to: " + clientAuthCertNickname, null); + desiredCertName = clientAuthCertNickname; + } + + @Override + public String select(Vector certs) { + +- CMS.debug("SSLClientCertificatSelectionCB: Entering!"); ++ log(Level.INFO, "SSLClientCertificatSelectionCB: Entering!", null); + + if(desiredCertName == null) { + return null; +@@ -200,15 +231,15 @@ public class PKISocketFactory implements LDAPSSLSocketFactoryExt { + + while(itr.hasNext()){ + String candidate = itr.next(); +- CMS.debug("Candidate cert: " + candidate); ++ log(Level.INFO, "Candidate cert: " + candidate, null); + if(desiredCertName.equalsIgnoreCase(candidate)) { + selection = candidate; +- CMS.debug("SSLClientCertificateSelectionCB: desired cert found in list: " + desiredCertName); ++ log(Level.INFO, "SSLClientCertificateSelectionCB: desired cert found in list: " + desiredCertName, null); + break; + } + } + +- CMS.debug("SSLClientCertificateSelectionCB: returning: " + selection); ++ log(Level.INFO, "SSLClientCertificateSelectionCB: returning: " + selection, null); + return selection; + + } +-- +1.8.3.1 + + +From c92c65f52dcff03f47fc7f05efa427ee9166c2e6 Mon Sep 17 00:00:00 2001 +From: Christina Fu +Date: Mon, 26 Aug 2019 18:47:02 -0400 +Subject: [PATCH 5/7] =?UTF-8?q?Resolve=20(addition=20issues=20for)=20Bug?= + =?UTF-8?q?=201642577=20-=20TPS=20=E2=80=93=20Revoked=20Encryption=20Certi?= + =?UTF-8?q?ficates=20Marked=20as=20Active=20in=20TPS=20Cert=20LDAP=20Durin?= + =?UTF-8?q?g=20Token=20Key=20Recovery?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch addresses the following: +* in TokenKeyRecoveryService.java, unwrap should be with temperatory true +* in CS.cfg, auths.instance.ldap1.ldapStringAttributes and auths.instance.ldap1.externalReg.attributes are expanded to include additional elements +* in CS.cfg registrationTypeAttributeName is added as original submitter suggested +* TPSEnrollProcessor.java, additional error checkings +* TPSProcessor.java, addresses case sensitive nature of List "contains" method + +(cherry picked from commit 24bdc1e39a5bad6b944f6f5571bf48e7e2af52f6) +--- + .../com/netscape/kra/TokenKeyRecoveryService.java | 2 +- + base/tps/shared/conf/CS.cfg | 4 ++- + .../server/tps/processor/TPSEnrollProcessor.java | 2 +- + .../server/tps/processor/TPSProcessor.java | 34 ++++++++++++++++++---- + 4 files changed, 34 insertions(+), 8 deletions(-) + +diff --git a/base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java b/base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java +index dcccc78..e95945a 100644 +--- a/base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java ++++ b/base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java +@@ -678,7 +678,7 @@ public class TokenKeyRecoveryService implements IService { + privKey = mStorageUnit.unwrap( + keyRecord.getPrivateKeyData(), + pubkey, +- false, ++ true, + keyRecord.getWrappingParams(mStorageUnit.getOldWrappingParams())); + } catch (Exception e) { + CMS.debug("TokenKeyRecoveryService: recoverKey() - recovery failure"); +diff --git a/base/tps/shared/conf/CS.cfg b/base/tps/shared/conf/CS.cfg +index eb5b831..4bd4bb7 100644 +--- a/base/tps/shared/conf/CS.cfg ++++ b/base/tps/shared/conf/CS.cfg +@@ -61,10 +61,12 @@ auths.instance.ldap1.ldapStringAttributes._003=# $$ + auths.instance.ldap1.ldapStringAttributes._004=# attributes example: + auths.instance.ldap1.ldapStringAttributes._005=#mail,cn,uid,edipi,pcc,firstname,lastname,exec-edipi,exec-pcc,exec-mail,certsToAdd,tokenCUID,tokenType + auths.instance.ldap1.ldapStringAttributes._006=################################# +-auths.instance.ldap1.ldapStringAttributes=mail,cn,uid ++auths.instance.ldap1.ldapStringAttributes=mail,cn,uid,enrollmenttype,certsToAdd,tokenCUID,registrationtype,tokenType,firstname,lastname,exec-edipi,exec-mail + auths.instance.ldap1.ldap.basedn=[LDAP_ROOT] ++auths.instance.ldap1.externalReg.attributes=certsToAdd,tokenCUID,enrollmenttype,registrationtype,tokenType + auths.instance.ldap1.externalReg.certs.recoverAttributeName=certsToAdd + auths.instance.ldap1.externalReg.cuidAttributeName=tokenCUID ++auths.instance.ldap1.externalReg.registrationTypeAttributeName=registrationtype + auths.instance.ldap1.externalReg.tokenTypeAttributeName=tokenType + auths.instance.ldap1.ldap.maxConns=15 + auths.instance.ldap1.ldap.minConns=3 +diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java +index 77b320c..f1e773a 100644 +--- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java ++++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java +@@ -200,7 +200,7 @@ public class TPSEnrollProcessor extends TPSProcessor { + // Check if the external reg parameter registrationType matches currentTokenOperation, + // otherwise stop the operation. + CMS.debug(method + " checking if record registrationtype matches currentTokenOperation."); +- if(erAttrs.getRegistrationType() != null) { ++ if(erAttrs.getRegistrationType() != null && erAttrs.getRegistrationType().length() > 0) { + if(!erAttrs.getRegistrationType().equalsIgnoreCase(currentTokenOperation)) { + CMS.debug( + method + " Error: registrationType " + +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 ec069b1..61da1d6 100644 +--- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java ++++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java +@@ -1294,12 +1294,12 @@ public class TPSProcessor { + throws EBaseException, TPSException { + + String logMsg = null; +- CMS.debug("TPSProcessor.authenticateUser"); + if (op.isEmpty() || userAuth == null || userCred == null) { + logMsg = "TPSProcessor.authenticateUser: missing parameter(s): op, userAuth, or userCred"; + CMS.debug(logMsg); + throw new EBaseException(logMsg); + } ++ CMS.debug("TPSProcessor.authenticateUser: op: " + op); + IAuthManager auth = userAuth.getAuthManager(); + + try { +@@ -1311,6 +1311,12 @@ public class TPSProcessor { + while (n.hasMoreElements()) { + String name = n.nextElement(); + CMS.debug("TPSProcessor.authenticateUser: got authToken val name:" + name); ++ /* debugging authToken content vals ++ String[] vals = authToken.getInStringArray(name); ++ if (vals != null) { ++ CMS.debug("TPSProcessor.authenticateUser: got authToken val :" + vals[0]); ++ } ++ */ + } + return authToken; + } else { +@@ -1811,6 +1817,21 @@ public class TPSProcessor { + return ret; + } + ++ /* ++ * listCaseInsensitiveContains - case insensitive contain check ++ * @param s the string checked if contained in list ++ * @param list the list ++ * @returns true if list contains s; false otherwise ++ */ ++ public boolean listCaseInsensitiveContains(String s, List list){ ++ for (String element : list){ ++ if (element.equalsIgnoreCase(s)){ ++ return true; ++ } ++ } ++ return false; ++ } ++ + /* + * processExternalRegAttrs : + * - retrieve from authToken relevant attributes for externalReg +@@ -1836,7 +1857,7 @@ public class TPSProcessor { + if(attributesToProcess == null) + return erAttrs; + +- if(attributesToProcess.contains(erAttrs.ldapAttrNameTokenType)) { ++ if(listCaseInsensitiveContains(erAttrs.ldapAttrNameTokenType, attributesToProcess)) { + CMS.debug(method + ": getting from authToken:" + + erAttrs.ldapAttrNameTokenType); + vals = authToken.getInStringArray(erAttrs.ldapAttrNameTokenType); +@@ -1852,17 +1873,20 @@ public class TPSProcessor { + erAttrs.setTokenType(vals[0]); + } + } +- if(attributesToProcess.contains(erAttrs.ldapAttrNameTokenCUID)) { ++ if(listCaseInsensitiveContains(erAttrs.ldapAttrNameTokenCUID, attributesToProcess)) { + CMS.debug(method + ": getting from authToken:" + + erAttrs.ldapAttrNameTokenCUID); + vals = authToken.getInStringArray(erAttrs.ldapAttrNameTokenCUID); + if (vals != null) { + CMS.debug(method + ": retrieved cuid:" + vals[0]); + erAttrs.setTokenCUID(vals[0]); ++ } else { ++ CMS.debug(method + ": " + erAttrs.ldapAttrNameTokenCUID + ++ " attribute not found"); + } + } + +- if(attributesToProcess.contains(erAttrs.ldapAttrNameRegistrationType)) { ++ if(listCaseInsensitiveContains(erAttrs.ldapAttrNameRegistrationType, attributesToProcess)) { + CMS.debug(method + ": getting from authToken:" + + erAttrs.ldapAttrNameRegistrationType); + vals = authToken.getInStringArray(erAttrs.ldapAttrNameRegistrationType); +@@ -1876,7 +1900,7 @@ public class TPSProcessor { + + } + +- if(attributesToProcess.contains(erAttrs.ldapAttrNameCertsToRecover)) { ++ if(listCaseInsensitiveContains(erAttrs.ldapAttrNameCertsToRecover, attributesToProcess)) { + /* + * certs to be recovered for this user + * - multi-valued +-- +1.8.3.1 + + +From 74c7c1133fd8d2f216eb1330147e870632ded68f Mon Sep 17 00:00:00 2001 +From: Christina Fu +Date: Wed, 28 Aug 2019 18:11:36 -0400 +Subject: [PATCH 6/7] simple typo fix in a debug line. + +(cherry picked from commit 272b785d20bc807406bc1e89a52c0fc142e25e72) +--- + base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +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 61da1d6..baf0671 100644 +--- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java ++++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java +@@ -4172,7 +4172,7 @@ public class TPSProcessor { + + keyInfo = tokenRecord.getKeyInfo(); + +- CMS.debug("TPProcessor.getKeyInfioFromTokenDB: returning: " + keyInfo); ++ CMS.debug("TPProcessor.getKeyInfoFromTokenDB: returning: " + keyInfo); + + return keyInfo; + +-- +1.8.3.1 + + +From ce90aeab54f0a33d1c59bd5a95852ea2c62541e9 Mon Sep 17 00:00:00 2001 +From: Christina Fu +Date: Fri, 6 Sep 2019 16:49:00 -0400 +Subject: [PATCH 7/7] Bug 1523330 - CC: missing audit event for CS acting as + TLS client + +This patch adds failed CLIENT_ACCESS_SESSION_ESTABLISH audit event for the case +when internal ldap server goes down + +fixes https://bugzilla.redhat.com/show_bug.cgi?id=1523330 + +(cherry picked from commit 10d52dd0d6b562edc9e32c543017c67c1c0212a8) +--- + .../netscape/cmscore/ldapconn/PKISocketFactory.java | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java +index 00df65b..dc93f5d 100644 +--- a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java ++++ b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/PKISocketFactory.java +@@ -33,6 +33,9 @@ import org.mozilla.jss.ssl.SSLSocket; + + import com.netscape.certsrv.apps.CMS; + import com.netscape.certsrv.base.IConfigStore; ++import com.netscape.certsrv.logging.event.ClientAccessSessionEstablishEvent; ++import com.netscape.certsrv.logging.SignedAuditEvent; ++import com.netscape.cms.logging.SignedAuditLogger; + + import netscape.ldap.LDAPException; + import netscape.ldap.LDAPSSLSocketFactoryExt; +@@ -46,6 +49,8 @@ import org.dogtagpki.server.PKIClientSocketListener; + */ + public class PKISocketFactory implements LDAPSSLSocketFactoryExt { + ++ private static SignedAuditLogger signedAuditLogger = SignedAuditLogger.getLogger(); ++ + private boolean secure; + private String mClientAuthCertNickname; + private boolean mClientAuth; +@@ -157,6 +162,22 @@ public class PKISocketFactory implements LDAPSSLSocketFactoryExt { + s.setKeepAlive(keepAlive); + + } catch (Exception e) { ++ // for auditing ++ String localIP = "localhost"; ++ try { ++ localIP = InetAddress.getLocalHost().getHostAddress(); ++ } catch (UnknownHostException e2) { ++ // default to "localhost"; ++ } ++ SignedAuditEvent auditEvent; ++ auditEvent = ClientAccessSessionEstablishEvent.createFailureEvent( ++ localIP, ++ host, ++ Integer.toString(port), ++ "SYSTEM", ++ "connect:" +e.toString()); ++ signedAuditLogger.log(auditEvent); ++ + CMS.debug(e); + if (s != null) { + try { +-- +1.8.3.1 + diff --git a/SOURCES/pki-core-rhel-7-8-rhcs-9-6-beta.patch b/SOURCES/pki-core-rhel-7-8-rhcs-9-6-beta.patch new file mode 100644 index 0000000..091a1d9 --- /dev/null +++ b/SOURCES/pki-core-rhel-7-8-rhcs-9-6-beta.patch @@ -0,0 +1,1642 @@ +From 696422ef74f9e143684d6a79769217a32811ec16 Mon Sep 17 00:00:00 2001 +From: Christina Fu +Date: Mon, 9 Sep 2019 20:36:26 -0400 +Subject: [PATCH 01/14] Bug 1638891 - TPS - (addl fix) Add External + Registration Support to PIN Reset + +This small patch fixes a critical typo (during patch merge) that causes KeySet + to be accidentally written to token Type instead. + +(cherry picked from commit 78c86e6cf33e85a23e666e06708441ac58b46a75) +--- + .../src/org/dogtagpki/server/tps/processor/TPSPinResetProcessor.java | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSPinResetProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSPinResetProcessor.java +index a8589fe..de5c634 100644 +--- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSPinResetProcessor.java ++++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSPinResetProcessor.java +@@ -209,7 +209,7 @@ public class TPSPinResetProcessor extends TPSProcessor { + BaseMappingResolver resolverInst = + subsystem.getMappingResolverManager().getResolverInstance(resolverInstName); + String keySet = resolverInst.getResolvedMapping(mappingParams, "keySet"); +- setSelectedTokenType(keySet); ++ setSelectedKeySet(keySet); + CMS.debug(method + " resolved keySet: " + keySet); + } + } catch (TPSException e) { +-- +1.8.3.1 + + +From eee11e26487e7993d4923df4c30d72b667a14a2b Mon Sep 17 00:00:00 2001 +From: "Endi S. Dewata" +Date: Tue, 10 Sep 2019 15:50:38 -0500 +Subject: [PATCH 02/14] Fixed TPSTokendb.tdbFindTokenRecordsByUID() + +The TPSTokendb.tdbFindTokenRecordsByUID() has been modified such +that it uses (tokenUserID=) filter to find tokens with exact +owner UID instead of filter with wildcards. + +https://bugzilla.redhat.com/show_bug.cgi?id=1520258 +(cherry picked from commit e8c81c59f03a3db5886924e4e7ec272bc864d953) +--- + .../src/com/netscape/cmscore/dbs/LDAPDatabase.java | 23 +++++++++++++++++++--- + .../src/org/dogtagpki/server/tps/TPSTokendb.java | 22 ++++++++++++--------- + .../dogtagpki/server/tps/dbs/TokenDatabase.java | 1 + + 3 files changed, 34 insertions(+), 12 deletions(-) + +diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/LDAPDatabase.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/LDAPDatabase.java +index 8773423..8e7f1f3 100644 +--- a/base/server/cmscore/src/com/netscape/cmscore/dbs/LDAPDatabase.java ++++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/LDAPDatabase.java +@@ -108,12 +108,22 @@ public abstract class LDAPDatabase extends Database { + // if no attributes specified, don't change filter + if (attributes == null || attributes.isEmpty()) return; + +- // wrap current filter with attribute matching filter +- sb.insert(0, "(&"); ++ // count filter components ++ int components = 0; ++ if (sb.length() > 0) components++; // count original filter ++ components += attributes.size(); // count attribute filters ++ ++ // concatenate the original filter and attribute filters: ++ // (=)...(=) + for (Map.Entry entry : attributes.entrySet()) { + sb.append("(" + entry.getKey() + "=" + LDAPUtil.escapeFilter(entry.getValue()) + ")"); + } +- sb.append(")"); ++ ++ // if there are multiple filter components, join with AND operator ++ if (components > 1) { ++ sb.insert(0, "(&"); ++ sb.append(")"); ++ } + } + + @Override +@@ -121,13 +131,20 @@ public abstract class LDAPDatabase extends Database { + return findRecords(keyword, null); + } + ++ /** ++ * Search for LDAP records with the specified keyword and attributes. ++ * The keyword parameter will be used to search with wildcards on certain attributes. ++ * The attributes parameter will be used to find exact matches of the specified attributes. ++ */ + public Collection findRecords(String keyword, Map attributes) throws Exception { + + CMS.debug("LDAPDatabase: findRecords()"); + + try (IDBSSession session = dbSubsystem.createSession()) { + Collection list = new ArrayList(); ++ + String ldapFilter = createFilter(keyword, attributes); ++ + CMS.debug("LDAPDatabase: searching " + baseDN + " with filter " + ldapFilter); + IDBSearchResults results = session.search(baseDN, ldapFilter); + +diff --git a/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java b/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java +index 80c9bb1..da0b51d 100644 +--- a/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java ++++ b/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java +@@ -23,6 +23,7 @@ import java.util.Collection; + import java.util.Date; + import java.util.HashMap; + import java.util.Iterator; ++import java.util.LinkedHashMap; + import java.util.Map; + + import org.dogtagpki.server.tps.cms.CARemoteRequestHandler; +@@ -141,17 +142,20 @@ public class TPSTokendb { + */ + public ArrayList tdbFindTokenRecordsByUID(String uid) + throws Exception { +- ArrayList tokenRecords = new ArrayList(); +- String filter = uid; +- Iterator records = null; +- records = tps.tokenDatabase.findRecords(filter).iterator(); + +- while (records.hasNext()) { +- TokenRecord tokenRecord = records.next(); +- tokenRecords.add(tokenRecord); +- } ++ // search for tokens with (tokenUserID=) ++ Map attributes = new LinkedHashMap<>(); ++ attributes.put("tokenUserID", uid); ++ ++ Iterator records = tps.tokenDatabase.findRecords(null, attributes).iterator(); ++ ++ ArrayList tokenRecords = new ArrayList(); ++ while (records.hasNext()) { ++ TokenRecord tokenRecord = records.next(); ++ tokenRecords.add(tokenRecord); ++ } + +- return tokenRecords; ++ return tokenRecords; + } + + public void tdbHasActiveToken(String userid) +diff --git a/base/tps/src/org/dogtagpki/server/tps/dbs/TokenDatabase.java b/base/tps/src/org/dogtagpki/server/tps/dbs/TokenDatabase.java +index 9235e78..b349cb2 100644 +--- a/base/tps/src/org/dogtagpki/server/tps/dbs/TokenDatabase.java ++++ b/base/tps/src/org/dogtagpki/server/tps/dbs/TokenDatabase.java +@@ -60,6 +60,7 @@ public class TokenDatabase extends LDAPDatabase { + StringBuilder sb = new StringBuilder(); + + if (keyword != null) { ++ // if keyword is specified, generate filter with wildcards + keyword = LDAPUtil.escapeFilter(keyword); + sb.append("(|(id=*" + keyword + "*)(userID=*" + keyword + "*))"); + } +-- +1.8.3.1 + + +From 3cc98ae77dff2351c1ea6af0086d4d0daeb28497 Mon Sep 17 00:00:00 2001 +From: "Endi S. Dewata" +Date: Fri, 13 Sep 2019 17:31:21 -0500 +Subject: [PATCH 03/14] Fixed TPSTokendb.tdbFindTokenRecordsByUID() (part 2) + +The TPSTokendb.tdbFindTokenRecordsByUID() has been modified to +construct (userID=) filter which will be translated into +(tokenUserID=) LDAP filter as defined in TokenRecord. + +https://bugzilla.redhat.com/show_bug.cgi?id=1520258 +(cherry picked from commit def3453308c68493f7417e485a1db14419187af0) +--- + base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java b/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java +index da0b51d..49bfb7f 100644 +--- a/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java ++++ b/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java +@@ -143,9 +143,11 @@ public class TPSTokendb { + public ArrayList tdbFindTokenRecordsByUID(String uid) + throws Exception { + +- // search for tokens with (tokenUserID=) ++ // search for tokens with (userID=) filter which will be ++ // translated into (tokenUserID=) LDAP filter as defined ++ // in TokenRecord + Map attributes = new LinkedHashMap<>(); +- attributes.put("tokenUserID", uid); ++ attributes.put("userID", uid); + + Iterator records = tps.tokenDatabase.findRecords(null, attributes).iterator(); + +-- +1.8.3.1 + + +From 53766e02131741dc0cb6434755b3ba488f0bd927 Mon Sep 17 00:00:00 2001 +From: Dinesh Prasanth M K +Date: Wed, 18 Sep 2019 15:36:51 -0400 +Subject: [PATCH 04/14] Update KRATool to support netkeyKeyRecovery entries + (#248) + +The `netkeyKeyRecovery` request entries are generated when +the TPS retrieves encryption cert onto tokens. + +The attributes processed by KRATool include: +* requestId +* dn +* dateOfModify +* cn +* extdata-requestid +* extdata-request-notes (creates, if it doesn't exist) + +Resolves: BZ#1445479 + +Signed-off-by: Dinesh Prasanth M K + +(cherry picked from commit b02bc04fe16c59aec28d90323e7c9e31dbd7261f) +--- + base/java-tools/man/man1/KRATool.1 | 44 +- + .../src/com/netscape/cmstools/KRATool.cfg | 21 + + .../src/com/netscape/cmstools/KRATool.java | 460 ++++++++++++++++++++- + 3 files changed, 506 insertions(+), 19 deletions(-) + +diff --git a/base/java-tools/man/man1/KRATool.1 b/base/java-tools/man/man1/KRATool.1 +index b04cd2b..1e2fe99 100644 +--- a/base/java-tools/man/man1/KRATool.1 ++++ b/base/java-tools/man/man1/KRATool.1 +@@ -1,7 +1,7 @@ + .\" First parameter, NAME, should be all caps + .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection + .\" other parameters are allowed: see man(7), man(1) +-.TH KRATool 1 "July 18, 2016" "version 10.3" "PKI Key Recovery Authority (KRA) Tool" Dogtag Team ++.TH KRATool 1 "Sep 11, 2019" "version 10.5" "PKI Key Recovery Authority (KRA) Tool" Dogtag Team + .\" Please adjust this date whenever revising the man page. + .\" + .\" Some roff macros, for reference: +@@ -33,6 +33,8 @@ The syntax for rewrapping keys: + [-source_pki_security_database_pwdfile ]] + [-source_kra_naming_context -target_kra_naming_context ] + [-process_requests_and_key_records_only] ++ [-unwrap_algorithm AES|DES3] ++ + .fi + .PP + The syntax for renumbering keys: +@@ -130,6 +132,12 @@ Gives the path and filename to a password file that contains only the password f + + This argument is optional when other rewrap parameters are used. If this argument is not used, then the script prompts for the password. + ++.TP ++.B -unwrap_algorithm ++Specifies the symmetric key algorithm used by source KRA. Available options include \fBDES3\fP and \fBAES\fP ++ ++This argument is optional and defaults to \fBDES3\fP if unspecified. ++ + .PP + The following parameters are optional for renumbering keys: + +@@ -147,13 +155,14 @@ If \fB-remove_id_offset\fP is used, then do not use the \fB-append_id_offset\fP + + .SH Configuration File (.cfg) + .PP +-The required configuration file instructs the KRATool how to process attributes in the key archival and key request entries in the LDIF file. There are six types of entries: ++The required configuration file instructs the KRATool how to process attributes in the key archival and key request entries in the LDIF file. There are seven types of entries: + .IP + * CA enrollment requests + * TPS enrollment requests + * CA key records + * TPS key records + * CA and TPS recovery requests (which are treated the same in the KRA) ++* TPS token key recovery requests + .PP + Each key and key request has an LDAP entry with attributes that are specific to that kind of record. For example, for a recovery request: + .IP +@@ -198,7 +207,7 @@ nsUniqueId: b2891805-1dd111b2-a6d7e85f-2c2f0000 + .PP + Much of that information passes through the script processing unchanged, so it is entered into the new, target KRA just the same. However, some of those attributes can and should be edited, like the Common Name (CN) and DN being changed to match the new KRA instance. The fields which can safely be changed are listed in the configuration file for each type of key entry. (Any attribute not listed is not touched by the tool under any circumstances.) + .PP +-If a field /fIshould/fP be edited — meaning, the tool can update the record ID number or rename the entry — then the value is set to true in the configuration file. For example, this configuration updates the CN, DN, ID number, last modified date, and associated entry notes for all CA enrollment requests: ++If a field \fIshould\fP be edited — meaning, the tool can update the record ID number or rename the entry — then the value is set to true in the configuration file. For example, this configuration updates the CN, DN, ID number, last modified date, and associated entry notes for all CA enrollment requests: + .IP + .nf + kratool.ldif.caEnrollmentRequest.cn=true +@@ -324,9 +333,9 @@ kratool.ldif.namingContext._037=## uid ## + kratool.ldif.namingContext._038=## uniqueMember ## + kratool.ldif.namingContext._039=## ## + kratool.ldif.namingContext._040=## If '-source_naming_context ## +-kratool.ldif.namingContext._041=## original source KRA naming context' ## ++kratool.ldif.namingContext._041=## ' ## + kratool.ldif.namingContext._042=## and '-target_naming_context ## +-kratool.ldif.namingContext._043=## renamed target KRA naming context' ## ++kratool.ldif.namingContext._043=## ' ## + kratool.ldif.namingContext._044=## options are specified, ALWAYS ## + kratool.ldif.namingContext._045=## require 'KRATOOL' to change the ## + kratool.ldif.namingContext._046=## KRA 'naming context' data in ALL of ## +@@ -355,6 +364,10 @@ kratool.ldif.namingContext._068=## tpsNetkeyKeygenRequest: ## + kratool.ldif.namingContext._069=## ## + kratool.ldif.namingContext._070=## dn ## + kratool.ldif.namingContext._071=## ## ++kratool.ldif.namingContext._072=## tpsNetkeyKeyRecoveryRequest: ## ++kratool.ldif.namingContext._073=## ## ++kratool.ldif.namingContext._074=## dn ## ++kratool.ldif.namingContext._075=## ## + kratool.ldif.namingContext._072=############################################ + kratool.ldif.recoveryRequest._000=##################################### + kratool.ldif.recoveryRequest._001=## KRA CA / TPS Recovery Request ## +@@ -401,6 +414,23 @@ kratool.ldif.tpsNetkeyKeygenRequest.extdata.keyRecord=true + kratool.ldif.tpsNetkeyKeygenRequest.extdata.requestId=true + kratool.ldif.tpsNetkeyKeygenRequest.extdata.requestNotes=true + kratool.ldif.tpsNetkeyKeygenRequest.requestId=true ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._000=######################################## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._001=## KRA TPS Netkey Keyrecovery Request ## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._002=######################################## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._003=## ## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._004=## NEVER allow 'KRATOOL' the ability ## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._005=## to change the TPS 'naming context'## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._006=## data in the following fields: ## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._007=## ## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._008=## extdata-updatedby ## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._009=## ## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._010=######################################## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest.cn=true ++kratool.ldif.tpsNetkeyKeyRecoveryRequest.requestId=true ++kratool.ldif.tpsNetkeyKeyRecoveryRequest.dn=true ++kratool.ldif.tpsNetkeyKeyRecoveryRequest.dateOfModify=true ++kratool.ldif.tpsNetkeyKeyRecoveryRequest.extdata.requestId=true ++kratool.ldif.tpsNetkeyKeyRecoveryRequest.extdata.requestNotes=true + .if + + .SH EXAMPLES +@@ -448,10 +478,10 @@ KRATool -kratool_config_file "/usr/share/pki/java-tools/KRATool.cfg" -source_ldi + .if + + .SH AUTHORS +-Matthew Harmsen . ++Matthew Harmsen and Dinesh Prasanth M K + + .SH COPYRIGHT +-Copyright (c) 2016 Red Hat, Inc. This is licensed under the GNU General Public ++Copyright (c) 2019 Red Hat, Inc. This is licensed under the GNU General Public + License, version 2 (GPLv2). A copy of this license is available at + http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + +diff --git a/base/java-tools/src/com/netscape/cmstools/KRATool.cfg b/base/java-tools/src/com/netscape/cmstools/KRATool.cfg +index cad2bf4..b2a4892 100644 +--- a/base/java-tools/src/com/netscape/cmstools/KRATool.cfg ++++ b/base/java-tools/src/com/netscape/cmstools/KRATool.cfg +@@ -111,6 +111,10 @@ kratool.ldif.namingContext._068=## tpsNetkeyKeygenRequest: ## + kratool.ldif.namingContext._069=## ## + kratool.ldif.namingContext._070=## dn ## + kratool.ldif.namingContext._071=## ## ++kratool.ldif.namingContext._072=## tpsNetkeyKeyRecoveryRequest: ## ++kratool.ldif.namingContext._073=## ## ++kratool.ldif.namingContext._074=## dn ## ++kratool.ldif.namingContext._075=## ## + kratool.ldif.namingContext._072=############################################ + kratool.ldif.recoveryRequest._000=##################################### + kratool.ldif.recoveryRequest._001=## KRA CA / TPS Recovery Request ## +@@ -157,4 +161,21 @@ kratool.ldif.tpsNetkeyKeygenRequest.extdata.keyRecord=true + kratool.ldif.tpsNetkeyKeygenRequest.extdata.requestId=true + kratool.ldif.tpsNetkeyKeygenRequest.extdata.requestNotes=true + kratool.ldif.tpsNetkeyKeygenRequest.requestId=true ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._000=######################################## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._001=## KRA TPS Netkey Keyrecovery Request ## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._002=######################################## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._003=## ## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._004=## NEVER allow 'KRATOOL' the ability ## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._005=## to change the TPS 'naming context'## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._006=## data in the following fields: ## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._007=## ## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._008=## extdata-updatedby ## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._009=## ## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest._010=######################################## ++kratool.ldif.tpsNetkeyKeyRecoveryRequest.cn=true ++kratool.ldif.tpsNetkeyKeyRecoveryRequest.requestId=true ++kratool.ldif.tpsNetkeyKeyRecoveryRequest.dn=true ++kratool.ldif.tpsNetkeyKeyRecoveryRequest.dateOfModify=true ++kratool.ldif.tpsNetkeyKeyRecoveryRequest.extdata.requestId=true ++kratool.ldif.tpsNetkeyKeyRecoveryRequest.extdata.requestNotes=true + +diff --git a/base/java-tools/src/com/netscape/cmstools/KRATool.java b/base/java-tools/src/com/netscape/cmstools/KRATool.java +index 74e5a6a..e4b9ae8 100644 +--- a/base/java-tools/src/com/netscape/cmstools/KRATool.java ++++ b/base/java-tools/src/com/netscape/cmstools/KRATool.java +@@ -699,6 +699,7 @@ public class KRATool { + private static final String KRATOOL_CFG_RECOVERY = "recoveryRequest"; + private static final String KRATOOL_CFG_TPS_KEY_RECORD = "tpsKeyRecord"; + private static final String KRATOOL_CFG_KEYGEN = "tpsNetkeyKeygenRequest"; ++ private static final String KRATOOL_CFG_KEYRECOVERY = "tpsNetkeyKeyRecoveryRequest"; + + // Constants: KRATOOL Config File (KRA CA Enrollment Request Fields) + private static final String KRATOOL_CFG_ENROLLMENT_CN = KRATOOL_CFG_PREFIX +@@ -860,6 +861,42 @@ public class KRATool { + + DOT + + "requestId"; + ++ private static final String KRATOOL_CFG_KEYRECOVERY_REQUEST_ID = KRATOOL_CFG_PREFIX ++ + DOT ++ + KRATOOL_CFG_KEYRECOVERY ++ + DOT ++ + "requestId"; ++ ++ private static final String KRATOOL_CFG_KEYRECOVERY_DN = KRATOOL_CFG_PREFIX ++ + DOT ++ + KRATOOL_CFG_KEYRECOVERY ++ + DOT ++ + "dn"; ++ ++ private static final String KRATOOL_CFG_KEYRECOVERY_DATE_OF_MODIFY = KRATOOL_CFG_PREFIX ++ + DOT ++ + KRATOOL_CFG_KEYRECOVERY ++ + DOT ++ + "dateOfModify"; ++ ++ private static final String KRATOOL_CFG_KEYRECOVERY_EXTDATA_REQUEST_ID = KRATOOL_CFG_PREFIX ++ + DOT ++ + KRATOOL_CFG_KEYRECOVERY ++ + DOT ++ + "extdata.requestId"; ++ ++ private static final String KRATOOL_CFG_KEYRECOVERY_CN = KRATOOL_CFG_PREFIX ++ + DOT ++ + KRATOOL_CFG_KEYRECOVERY ++ + DOT ++ + "cn"; ++ ++ private static final String KRATOOL_CFG_KEYRECOVERY_EXTDATA_REQUEST_NOTES = KRATOOL_CFG_PREFIX ++ + DOT ++ + KRATOOL_CFG_KEYRECOVERY ++ + DOT ++ + "extdata.requestNotes"; ++ + // Constants: Target Certificate Information + private static final String HEADER = "-----BEGIN"; + private static final String TRAILER = "-----END"; +@@ -892,6 +929,7 @@ public class KRATool { + private static final String KRA_LDIF_KEYGEN = "netkeyKeygen"; + private static final String KRA_LDIF_RECOVERY = "recovery"; + private static final String KRA_LDIF_TPS_KEY_RECORD = "TPS"; ++ private static final String KRA_LDIF_KEYRECOVERY = "netkeyKeyRecovery"; + + // Constants: KRA LDIF Record Messages + private static final String KRA_LDIF_REWRAP_MESSAGE = "REWRAPPED the '" +@@ -2334,6 +2372,15 @@ public class KRATool { + } else { + output = line; + } ++ } else if (record_type.equals( KRA_LDIF_KEYRECOVERY ) ) { ++ if( kratoolCfg.get(KRATOOL_CFG_KEYRECOVERY_CN ) ) { ++ output = compose_numeric_line(KRA_LDIF_CN, ++ SPACE, ++ line, ++ false ); ++ } else { ++ output = line; ++ } + } else if (record_type.equals(KRA_LDIF_RECORD)) { + // Non-Request / Non-Key Record: + // Pass through the original +@@ -2439,6 +2486,21 @@ public class KRATool { + } else { + output = line; + } ++ } else if (record_type.equals( KRA_LDIF_KEYRECOVERY ) ) { ++ if( kratoolCfg.get( KRATOOL_CFG_KEYRECOVERY_DATE_OF_MODIFY ) ) { ++ output = KRA_LDIF_DATE_OF_MODIFY ++ + SPACE ++ + mDateOfModify; ++ ++ log( "Changed '" ++ + line ++ + "' to '" ++ + output ++ + "'." ++ + NEWLINE, false ); ++ } else { ++ output = line; ++ } + } else { + log("ERROR: Mismatched record field='" + + KRA_LDIF_DATE_OF_MODIFY +@@ -2657,6 +2719,44 @@ public class KRATool { + } else { + output = line; + } ++ } else if (record_type.equals( KRA_LDIF_KEYRECOVERY ) ) { ++ if( kratoolCfg.get( KRATOOL_CFG_KEYRECOVERY_DN ) ) { ++ // First check for an embedded "cn=" ++ // name-value pair ++ if( line.startsWith( KRA_LDIF_DN_EMBEDDED_CN_DATA ) ) { ++ // At this point, always extract ++ // the embedded "cn=" name-value pair ++ // which will ALWAYS be the first ++ // portion of the "dn: " attribute ++ embedded_cn_data = line.split( COMMA, 2 ); ++ ++ embedded_cn_output = compose_numeric_line( ++ KRA_LDIF_DN_EMBEDDED_CN_DATA, ++ EQUAL_SIGN, ++ embedded_cn_data[0], ++ false ); ++ ++ input = embedded_cn_output ++ + COMMA ++ + embedded_cn_data[1]; ++ } else { ++ input = line; ++ } ++ ++ // Since "-source_kra_naming_context", and ++ // "-target_kra_naming_context" are OPTIONAL ++ // parameters, ONLY process this portion of the field ++ // if both of these options have been selected ++ if( mKraNamingContextsFlag ) { ++ output = input.replace( mSourceKraNamingContext, ++ mTargetKraNamingContext ); ++ } else { ++ output = input; ++ } ++ ++ } else { ++ output = line; ++ } + } else if (record_type.equals(KRA_LDIF_RECORD)) { + // Non-Request / Non-Key Record: + // Pass through the original +@@ -2771,6 +2871,15 @@ public class KRATool { + } else { + output = line; + } ++ } else if (record_type.equals( KRA_LDIF_KEYRECOVERY ) ) { ++ if( kratoolCfg.get(KRATOOL_CFG_KEYRECOVERY_EXTDATA_REQUEST_ID ) ) { ++ output = compose_numeric_line(KRA_LDIF_EXTDATA_REQUEST_ID, ++ SPACE, ++ line, ++ false ); ++ } else { ++ output = line; ++ } + } else { + log("ERROR: Mismatched record field='" + + KRA_LDIF_EXTDATA_REQUEST_ID +@@ -3307,6 +3416,167 @@ public class KRATool { + } else { + output = line; + } ++ } else if (record_type.equals( KRA_LDIF_KEYRECOVERY ) ) { ++ if( kratoolCfg.get( KRATOOL_CFG_KEYRECOVERY_EXTDATA_REQUEST_NOTES ) ) { ++ // write out a revised 'extdata-requestnotes' line ++ if( mRewrapFlag && mAppendIdOffsetFlag ) { ++ data = input ++ + SPACE ++ + LEFT_BRACE ++ + mDateOfModify ++ + RIGHT_BRACE ++ + COLON + SPACE ++ + KRA_LDIF_REWRAP_MESSAGE ++ + mPublicKeySize ++ + KRA_LDIF_RSA_MESSAGE ++ + mSourcePKISecurityDatabasePwdfileMessage ++ + SPACE ++ + PLUS + SPACE ++ + KRA_LDIF_APPENDED_ID_OFFSET_MESSAGE ++ + SPACE ++ + TIC ++ + mAppendIdOffset.toString() ++ + TIC ++ + mKraNamingContextMessage ++ + mProcessRequestsAndKeyRecordsOnlyMessage; ++ ++ // Unformat the data ++ unformatted_data = stripEOL( data ); ++ ++ // Format the unformatted_data ++ // to match the desired LDIF format ++ output = KRA_LDIF_EXTDATA_REQUEST_NOTES ++ + SPACE ++ + format_ldif_data( ++ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH, ++ unformatted_data ); ++ } else if( mRewrapFlag && mRemoveIdOffsetFlag ) { ++ data = input ++ + SPACE ++ + LEFT_BRACE ++ + mDateOfModify ++ + RIGHT_BRACE ++ + COLON + SPACE ++ + KRA_LDIF_REWRAP_MESSAGE ++ + mPublicKeySize ++ + KRA_LDIF_RSA_MESSAGE ++ + mSourcePKISecurityDatabasePwdfileMessage ++ + SPACE ++ + PLUS + SPACE ++ + KRA_LDIF_REMOVED_ID_OFFSET_MESSAGE ++ + SPACE ++ + TIC ++ + mRemoveIdOffset.toString() ++ + TIC ++ + mKraNamingContextMessage ++ + mProcessRequestsAndKeyRecordsOnlyMessage; ++ ++ // Unformat the data ++ unformatted_data = stripEOL( data ); ++ ++ // Format the unformatted_data ++ // to match the desired LDIF format ++ output = KRA_LDIF_EXTDATA_REQUEST_NOTES ++ + SPACE ++ + format_ldif_data( ++ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH, ++ unformatted_data ); ++ } else if( mRewrapFlag ) { ++ data = input ++ + SPACE ++ + LEFT_BRACE ++ + mDateOfModify ++ + RIGHT_BRACE ++ + COLON + SPACE ++ + KRA_LDIF_REWRAP_MESSAGE ++ + mPublicKeySize ++ + KRA_LDIF_RSA_MESSAGE ++ + mSourcePKISecurityDatabasePwdfileMessage ++ + mKraNamingContextMessage ++ + mProcessRequestsAndKeyRecordsOnlyMessage; ++ ++ // Unformat the data ++ unformatted_data = stripEOL( data ); ++ ++ // Format the unformatted_data ++ // to match the desired LDIF format ++ output = KRA_LDIF_EXTDATA_REQUEST_NOTES ++ + SPACE ++ + format_ldif_data( ++ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH, ++ unformatted_data ); ++ } else if( mAppendIdOffsetFlag ) { ++ data = input ++ + SPACE ++ + LEFT_BRACE ++ + mDateOfModify ++ + RIGHT_BRACE ++ + COLON + SPACE ++ + KRA_LDIF_APPENDED_ID_OFFSET_MESSAGE ++ + SPACE ++ + TIC ++ + mAppendIdOffset.toString() ++ + TIC ++ + mKraNamingContextMessage ++ + mProcessRequestsAndKeyRecordsOnlyMessage; ++ ++ // Unformat the data ++ unformatted_data = stripEOL( data ); ++ ++ // Format the unformatted_data ++ // to match the desired LDIF format ++ output = KRA_LDIF_EXTDATA_REQUEST_NOTES ++ + SPACE ++ + format_ldif_data( ++ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH, ++ unformatted_data ); ++ } else if( mRemoveIdOffsetFlag ) { ++ data = input ++ + SPACE ++ + LEFT_BRACE ++ + mDateOfModify ++ + RIGHT_BRACE ++ + COLON + SPACE ++ + KRA_LDIF_REMOVED_ID_OFFSET_MESSAGE ++ + SPACE ++ + TIC ++ + mRemoveIdOffset.toString() ++ + TIC ++ + mKraNamingContextMessage ++ + mProcessRequestsAndKeyRecordsOnlyMessage; ++ ++ // Unformat the data ++ unformatted_data = stripEOL( data ); ++ ++ // Format the unformatted_data ++ // to match the desired LDIF format ++ output = KRA_LDIF_EXTDATA_REQUEST_NOTES ++ + SPACE ++ + format_ldif_data( ++ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH, ++ unformatted_data ); ++ } ++ ++ // log this information ++ log( "Changed:" ++ + NEWLINE ++ + TIC ++ + KRA_LDIF_EXTDATA_REQUEST_NOTES ++ + SPACE ++ + format_ldif_data( ++ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH, ++ input.toString() ) ++ + TIC ++ + NEWLINE ++ + "--->" ++ + NEWLINE ++ + TIC ++ + output ++ + TIC ++ + NEWLINE, false ); ++ } else { ++ output = line; ++ } + } else { + log("ERROR: Mismatched record field='" + + KRA_LDIF_EXTDATA_REQUEST_NOTES +@@ -3634,6 +3904,153 @@ public class KRATool { + System.out.print("."); + } + } ++ } else if (record_type.equals(KRA_LDIF_KEYRECOVERY)) { ++ if( kratoolCfg.get( KRATOOL_CFG_KEYRECOVERY_EXTDATA_REQUEST_NOTES ) ) { ++ if(!previous_line.startsWith( KRA_LDIF_EXTDATA_REQUEST_NOTES)) { ++ // write out the missing 'extdata-requestnotes' line ++ if( mRewrapFlag && mAppendIdOffsetFlag ) { ++ data = LEFT_BRACE ++ + mDateOfModify ++ + RIGHT_BRACE ++ + COLON + SPACE ++ + KRA_LDIF_REWRAP_MESSAGE ++ + mPublicKeySize ++ + KRA_LDIF_RSA_MESSAGE ++ + mSourcePKISecurityDatabasePwdfileMessage ++ + SPACE ++ + PLUS + SPACE ++ + KRA_LDIF_APPENDED_ID_OFFSET_MESSAGE ++ + SPACE ++ + TIC ++ + mAppendIdOffset.toString() ++ + TIC ++ + mKraNamingContextMessage ++ + mProcessRequestsAndKeyRecordsOnlyMessage; ++ ++ // Unformat the data ++ unformatted_data = stripEOL( data ); ++ ++ // Format the unformatted_data ++ // to match the desired LDIF format ++ output = KRA_LDIF_EXTDATA_REQUEST_NOTES ++ + SPACE ++ + format_ldif_data( ++ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH, ++ unformatted_data ); ++ } else if( mRewrapFlag && mRemoveIdOffsetFlag ) { ++ data = LEFT_BRACE ++ + mDateOfModify ++ + RIGHT_BRACE ++ + COLON + SPACE ++ + KRA_LDIF_REWRAP_MESSAGE ++ + mPublicKeySize ++ + KRA_LDIF_RSA_MESSAGE ++ + mSourcePKISecurityDatabasePwdfileMessage ++ + SPACE ++ + PLUS + SPACE ++ + KRA_LDIF_REMOVED_ID_OFFSET_MESSAGE ++ + SPACE ++ + TIC ++ + mRemoveIdOffset.toString() ++ + TIC ++ + mKraNamingContextMessage ++ + mProcessRequestsAndKeyRecordsOnlyMessage; ++ ++ // Unformat the data ++ unformatted_data = stripEOL( data ); ++ ++ // Format the unformatted_data ++ // to match the desired LDIF format ++ output = KRA_LDIF_EXTDATA_REQUEST_NOTES ++ + SPACE ++ + format_ldif_data( ++ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH, ++ unformatted_data ); ++ } else if( mRewrapFlag ) { ++ data = LEFT_BRACE ++ + mDateOfModify ++ + RIGHT_BRACE ++ + COLON + SPACE ++ + KRA_LDIF_REWRAP_MESSAGE ++ + mPublicKeySize ++ + KRA_LDIF_RSA_MESSAGE ++ + mSourcePKISecurityDatabasePwdfileMessage ++ + mKraNamingContextMessage ++ + mProcessRequestsAndKeyRecordsOnlyMessage; ++ ++ // Unformat the data ++ unformatted_data = stripEOL( data ); ++ ++ // Format the unformatted_data ++ // to match the desired LDIF format ++ output = KRA_LDIF_EXTDATA_REQUEST_NOTES ++ + SPACE ++ + format_ldif_data( ++ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH, ++ unformatted_data ); ++ } else if( mAppendIdOffsetFlag ) { ++ data = LEFT_BRACE ++ + mDateOfModify ++ + RIGHT_BRACE ++ + COLON + SPACE ++ + KRA_LDIF_APPENDED_ID_OFFSET_MESSAGE ++ + SPACE ++ + TIC ++ + mAppendIdOffset.toString() ++ + TIC ++ + mKraNamingContextMessage ++ + mProcessRequestsAndKeyRecordsOnlyMessage; ++ ++ // Unformat the data ++ unformatted_data = stripEOL( data ); ++ ++ // Format the unformatted_data ++ // to match the desired LDIF format ++ output = KRA_LDIF_EXTDATA_REQUEST_NOTES ++ + SPACE ++ + format_ldif_data( ++ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH, ++ unformatted_data ); ++ } else if( mRemoveIdOffsetFlag ) { ++ data = LEFT_BRACE ++ + mDateOfModify ++ + RIGHT_BRACE ++ + COLON + SPACE ++ + KRA_LDIF_REMOVED_ID_OFFSET_MESSAGE ++ + SPACE ++ + TIC ++ + mRemoveIdOffset.toString() ++ + TIC ++ + mKraNamingContextMessage ++ + mProcessRequestsAndKeyRecordsOnlyMessage; ++ ++ // Unformat the data ++ unformatted_data = stripEOL( data ); ++ ++ // Format the unformatted_data ++ // to match the desired LDIF format ++ output = KRA_LDIF_EXTDATA_REQUEST_NOTES ++ + SPACE ++ + format_ldif_data( ++ EXTDATA_REQUEST_NOTES_FIRST_LINE_DATA_LENGTH, ++ unformatted_data ); ++ } ++ ++ // log this information ++ log( "Created:" ++ + NEWLINE ++ + TIC ++ + output ++ + TIC ++ + NEWLINE, false ); ++ ++ // Write out this revised line ++ // and flush the buffer ++ writer.write( output + NEWLINE ); ++ writer.flush(); ++ System.out.print( "." ); ++ } ++ } + } + } + +@@ -3897,6 +4314,15 @@ public class KRATool { + } else { + output = line; + } ++ } else if ( record_type.equals( KRA_LDIF_KEYRECOVERY ) ) { ++ if ( kratoolCfg.get( KRATOOL_CFG_KEYRECOVERY_REQUEST_ID ) ) { ++ output = compose_numeric_line(KRA_LDIF_REQUEST_ID, ++ SPACE, ++ line, ++ true); ++ } else { ++ output = line; ++ } + } else { + log("ERROR: Mismatched record field='" + + KRA_LDIF_REQUEST_ID +@@ -4115,7 +4541,8 @@ public class KRATool { + ).trim(); + if (!record_type.equals(KRA_LDIF_ENROLLMENT) && + !record_type.equals(KRA_LDIF_KEYGEN) && +- !record_type.equals(KRA_LDIF_RECOVERY)) { ++ !record_type.equals(KRA_LDIF_RECOVERY) && ++ !record_type.equals( KRA_LDIF_KEYRECOVERY)) { + log("ERROR: Unknown LDIF record type='" + + record_type + + "'!" +@@ -4398,7 +4825,13 @@ public class KRATool { + || name.equals(KRATOOL_CFG_KEYGEN_EXTDATA_KEY_RECORD) + || name.equals(KRATOOL_CFG_KEYGEN_EXTDATA_REQUEST_ID) + || name.equals(KRATOOL_CFG_KEYGEN_EXTDATA_REQUEST_NOTES) +- || name.equals(KRATOOL_CFG_KEYGEN_REQUEST_ID)) { ++ || name.equals(KRATOOL_CFG_KEYGEN_REQUEST_ID) ++ || name.equals(KRATOOL_CFG_KEYRECOVERY_REQUEST_ID ) ++ || name.equals(KRATOOL_CFG_KEYRECOVERY_DN ) ++ || name.equals(KRATOOL_CFG_KEYRECOVERY_DATE_OF_MODIFY) ++ || name.equals(KRATOOL_CFG_KEYRECOVERY_EXTDATA_REQUEST_ID) ++ || name.equals(KRATOOL_CFG_KEYRECOVERY_CN) ++ || name.equals(KRATOOL_CFG_KEYRECOVERY_EXTDATA_REQUEST_NOTES) ) { + kratoolCfg.put(name, value); + System.out.print("."); + } +@@ -4496,6 +4929,7 @@ public class KRATool { + (args.length != (REWRAP_AND_ID_OFFSET_ARGS + 5)) && + (args.length != (REWRAP_AND_ID_OFFSET_ARGS + 6)) && + (args.length != (REWRAP_AND_ID_OFFSET_ARGS + 7)) && ++ (args.length != (REWRAP_AND_ID_OFFSET_ARGS + 8)) && + (args.length != (REWRAP_AND_ID_OFFSET_ARGS + 9))) { + System.err.println("ERROR: Incorrect number of arguments!" + + NEWLINE); +@@ -4892,16 +5326,18 @@ public class KRATool { + } + + // Check for the Key Unwrap Algorithm provided by user. +- // If unprovided, choose DES3 as the default (to maintain consistency with old code) +- if (keyUnwrapAlgorithmName.equalsIgnoreCase("DES3")) { +- keyUnwrapAlgorithm = SymmetricKey.DES3; +- } else if (keyUnwrapAlgorithmName.equalsIgnoreCase("AES")) { +- keyUnwrapAlgorithm = SymmetricKey.AES; +- } else { +- System.err.println("ERROR: Unsupported key unwrap algorithm '" +- + keyUnwrapAlgorithmName + "'" +- + NEWLINE); +- System.exit(1); ++ // If unprovided, DES3 is chosen as the default (to maintain consistency with old code) ++ if (keyUnwrapAlgorithmName != null) { ++ if (keyUnwrapAlgorithmName.equalsIgnoreCase("DES3")) { ++ keyUnwrapAlgorithm = SymmetricKey.DES3; ++ } else if (keyUnwrapAlgorithmName.equalsIgnoreCase("AES")) { ++ keyUnwrapAlgorithm = SymmetricKey.AES; ++ } else { ++ System.err.println("ERROR: Unsupported key unwrap algorithm '" ++ + keyUnwrapAlgorithmName + "'" ++ + NEWLINE); ++ System.exit(1); ++ } + } + + // Check for OPTIONAL "Process Requests and Key Records ONLY" option +-- +1.8.3.1 + + +From b8f619e12ac90aab1ad845bffbdefffcb1e9229d Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Thu, 19 Sep 2019 15:41:40 +1000 +Subject: [PATCH 05/14] SecurityDataProcess.archive: log decryption failure + +(cherry picked from commit df26b7e86b3341c2cc7c0d5d9c3d9f680496a071) +--- + base/kra/src/com/netscape/kra/SecurityDataProcessor.java | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/base/kra/src/com/netscape/kra/SecurityDataProcessor.java b/base/kra/src/com/netscape/kra/SecurityDataProcessor.java +index 5a64530..05e73ce 100644 +--- a/base/kra/src/com/netscape/kra/SecurityDataProcessor.java ++++ b/base/kra/src/com/netscape/kra/SecurityDataProcessor.java +@@ -208,6 +208,8 @@ public class SecurityDataProcessor { + KeyRequestService.SYMKEY_TYPES.get(algorithm), + strength); + } catch (Exception e) { ++ CMS.debug("Can't decrypt symmetric key:"); ++ CMS.debug(e); + throw new EBaseException("Can't decrypt symmetric key.", e); + } + } +@@ -222,6 +224,8 @@ public class SecurityDataProcessor { + secdata, + null); + } catch (Exception e) { ++ CMS.debug("Can't decrypt passphrase."); ++ CMS.debug(e); + throw new EBaseException("Can't decrypt passphrase.", e); + } + +-- +1.8.3.1 + + +From 38a8d9d7fb4e18027c763a553c5ab20cfe709a76 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Thu, 19 Sep 2019 17:17:24 +1000 +Subject: [PATCH 06/14] CryptoUtil: include OID in NoSuchAlgorithmException + +(cherry picked from commit c08b0cdbf069033d7ddc4e769890bf6281200659) +--- + base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java +index 083b9f2..e9bc0dd 100644 +--- a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java ++++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java +@@ -3114,7 +3114,7 @@ public class CryptoUtil { + if (oid.equals(KeyWrapAlgorithm.DES_CBC_PAD_OID)) + return KeyWrapAlgorithm.DES3_CBC_PAD; + +- throw new NoSuchAlgorithmException(); ++ throw new NoSuchAlgorithmException(wrapOID); + } + + } +-- +1.8.3.1 + + +From 4ade0812dac8bebb81500ea74641f3bf79548f42 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Thu, 19 Sep 2019 20:54:17 +1000 +Subject: [PATCH 07/14] CryptoUtil.getKeywrapAlgorithmFromOID: Fix DES-EDE3-CBC + selection + +Commit dbd2d9b587f46b8af2f78b73d62715c1fd3344fc contained the edit: + +- if (oid.equals(KW_DES_CBC_PAD)) ++ if (oid.equals(KeyWrapAlgorithm.DES_CBC_PAD_OID)) + +KW_DES_CBC_PAD was 1.2.840.113549.3.7 (DES-EDE3-CBC; this definition +was removed in the same commit). But +KeyWrapAlgorithm.DES_CBC_PAD_OID is 1.3.14.3.2.7. This is a +behaviour change that breaks KRA archival (possibly recovery too). + +Test equality to KeyWrapAlgorithm.DES3_CBC_PAD_OID to restore the +correct behaviour. Also fix a similar error in WrappingParams.java. + +Related: https://bugzilla.redhat.com/show_bug.cgi?id=1709585 +(cherry picked from commit 4d9b4f23d761621073eb7f858e654fc7aceb406d) +--- + base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java | 2 +- + base/util/src/netscape/security/util/WrappingParams.java | 2 +- + 2 files changed, 2 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 e9bc0dd..3d85a14 100644 +--- a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java ++++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java +@@ -3111,7 +3111,7 @@ public class CryptoUtil { + if (oid.equals(KeyWrapAlgorithm.AES_CBC_PAD_OID)) + return KeyWrapAlgorithm.AES_CBC_PAD; + +- if (oid.equals(KeyWrapAlgorithm.DES_CBC_PAD_OID)) ++ if (oid.equals(KeyWrapAlgorithm.DES3_CBC_PAD_OID)) + return KeyWrapAlgorithm.DES3_CBC_PAD; + + throw new NoSuchAlgorithmException(wrapOID); +diff --git a/base/util/src/netscape/security/util/WrappingParams.java b/base/util/src/netscape/security/util/WrappingParams.java +index f1ebc95..b0d4600 100644 +--- a/base/util/src/netscape/security/util/WrappingParams.java ++++ b/base/util/src/netscape/security/util/WrappingParams.java +@@ -67,7 +67,7 @@ public class WrappingParams { + // New clients set this correctly. + // We'll assume the old DES3 wrapping here. + encrypt = EncryptionAlgorithm.DES_CBC_PAD; +- } else if (encryptOID.equals(KeyWrapAlgorithm.DES_CBC_PAD_OID.toString())) { ++ } else if (encryptOID.equals(KeyWrapAlgorithm.DES3_CBC_PAD_OID.toString())) { + encrypt = EncryptionAlgorithm.DES3_CBC_PAD; + } else if (encryptOID.equals(KeyWrapAlgorithm.AES_CBC_PAD_OID.toString())) { + encrypt = EncryptionAlgorithm.AES_128_CBC_PAD; +-- +1.8.3.1 + + +From 78c8448064afddeefea8938f01100a03f6a10d2d Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Wed, 29 Aug 2018 16:55:31 +1000 +Subject: [PATCH 08/14] getTheSerialNumber: only return null if next range not + available + +When cloning, if the master's current number range has been depleted +due to a previous UpdateNumberRange request, +Repository.getTheSerialNumber() returns null because the next serial +number is out of the current range, but the next range has not been +activated yet. NullPointerException ensues. + +Update getTheSerialNumber() to return the next serial number even +when it exceeds the current number range, as long as there is a next +range. If there is no next range, return null (as before). It is +assumed that the next range is non-empty + +Also do a couple of drive-by method extractions to improve +readability. + +Part of: https://pagure.io/dogtagpki/issue/3055 + +(cherry picked from commit f1615df509053a8f474b82ea6a2fa0883ab06d09) +--- + .../src/com/netscape/cmscore/dbs/Repository.java | 61 ++++++++++++++++------ + 1 file changed, 44 insertions(+), 17 deletions(-) + +diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java +index afe9013..c5120c4 100644 +--- a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java ++++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java +@@ -317,7 +317,15 @@ public abstract class Repository implements IRepository { + } + + /** +- * get the next serial number in cache ++ * Peek at the next serial number in cache (does not consume the ++ * number). ++ * ++ * The returned number is not necessarily the previously emitted ++ * serial number plus one, i.e. if we are going to roll into the ++ * next range. This method does not actually switch the range. ++ * ++ * Returns null if the next number exceeds the current range and ++ * there is not a next range. + */ + public BigInteger getTheSerialNumber() throws EBaseException { + +@@ -327,7 +335,7 @@ public abstract class Repository implements IRepository { + BigInteger serial = mLastSerialNo.add(BigInteger.ONE); + + if (mMaxSerialNo != null && serial.compareTo(mMaxSerialNo) > 0) +- return null; ++ return hasNextRange() ? mNextMinSerialNo : null; + else + return serial; + } +@@ -390,9 +398,13 @@ public abstract class Repository implements IRepository { + } + + /** +- * Checks to see if range needs to be switched. ++ * Checks if the given number is in the current range. ++ * If it does not exceed the current range, return cleanly. ++ * If it exceeds the given range, and there is a next range, switch the range. ++ * If it exceeds the given range, and there is not a next range, throw EDBException. + * +- * @exception EBaseException thrown when next range is not allocated ++ * @exception EDBException thrown when range switch is needed ++ * but next range is not allocated + */ + protected void checkRange() throws EBaseException + { +@@ -413,7 +425,7 @@ public abstract class Repository implements IRepository { + + if (mDB.getEnableSerialMgmt()) { + CMS.debug("Reached the end of the range. Attempting to move to next range"); +- if ((mNextMinSerialNo == null) || (mNextMaxSerialNo == null)) { ++ if (!hasNextRange()) { + if (rangeLength != null && mCounter.compareTo(rangeLength) < 0) { + return; + } else { +@@ -421,18 +433,7 @@ public abstract class Repository implements IRepository { + mLastSerialNo.toString())); + } + } +- mMinSerialNo = mNextMinSerialNo; +- mMaxSerialNo = mNextMaxSerialNo; +- mLastSerialNo = mMinSerialNo; +- mNextMinSerialNo = null; +- mNextMaxSerialNo = null; +- mCounter = BigInteger.ZERO; +- +- // persist the changes +- mDB.setMinSerialConfig(mRepo, mMinSerialNo.toString(mRadix)); +- mDB.setMaxSerialConfig(mRepo, mMaxSerialNo.toString(mRadix)); +- mDB.setNextMinSerialConfig(mRepo, null); +- mDB.setNextMaxSerialConfig(mRepo, null); ++ switchToNextRange(); + } else { + throw new EDBException(CMS.getUserMessage("CMS_DBS_LIMIT_REACHED", + mLastSerialNo.toString())); +@@ -441,6 +442,32 @@ public abstract class Repository implements IRepository { + } + + /** ++ * Return true iff there is a next range ready to go. ++ */ ++ private boolean hasNextRange() { ++ return (mNextMinSerialNo != null) && (mNextMaxSerialNo != null); ++ } ++ ++ /** ++ * Switch to the next range and persist the changes. ++ */ ++ private void switchToNextRange() ++ throws EBaseException { ++ mMinSerialNo = mNextMinSerialNo; ++ mMaxSerialNo = mNextMaxSerialNo; ++ mLastSerialNo = mMinSerialNo; ++ mNextMinSerialNo = null; ++ mNextMaxSerialNo = null; ++ mCounter = BigInteger.ZERO; ++ ++ // persist the changes ++ mDB.setMinSerialConfig(mRepo, mMinSerialNo.toString(mRadix)); ++ mDB.setMaxSerialConfig(mRepo, mMaxSerialNo.toString(mRadix)); ++ mDB.setNextMinSerialConfig(mRepo, null); ++ mDB.setNextMaxSerialConfig(mRepo, null); ++ } ++ ++ /** + * Checks to see if a new range is needed, or if we have reached the end of the + * current range, or if a range conflict has occurred. + * +-- +1.8.3.1 + + +From 30fa68e6241763c5c117014e9e5cacc410cc3a56 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Mon, 3 Sep 2018 15:55:35 +1000 +Subject: [PATCH 09/14] Repository: handle depleted range in initCache() + +Repository.initCache() does not handle the case where the current +range has been fully depleted, but the switch to the next range has +not occurred yet. This situation arises when the range has been +fully depleted by servicing UpdateNumberRange requests for clones. + +Detect this situation and handle it by switching to the next range +(when available). + +Part of: https://pagure.io/dogtagpki/issue/3055 + +(cherry picked from commit 2fb3611db5145dbdd5e7e14daaad1470691494f0) +--- + .../src/com/netscape/cmscore/dbs/Repository.java | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java +index c5120c4..828217c 100644 +--- a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java ++++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java +@@ -298,6 +298,25 @@ public abstract class Repository implements IRepository { + BigInteger theSerialNo = null; + theSerialNo = getLastSerialNumberInRange(mMinSerialNo, mMaxSerialNo); + ++ if (theSerialNo == null) { ++ // This arises when range has been depleted by servicing ++ // UpdateNumberRange requests for clones. Attempt to ++ // move to next range. ++ CMS.debug( ++ "Repository: failed to get last serial number in range " ++ + mMinSerialNo + ".." + mMaxSerialNo); ++ ++ if (hasNextRange()) { ++ CMS.debug("Repository: switching to next range."); ++ switchToNextRange(); ++ CMS.debug("Repository: new range: " + mMinSerialNo + ".." + mMaxSerialNo); ++ // try again with updated range ++ theSerialNo = getLastSerialNumberInRange(mMinSerialNo, mMaxSerialNo); ++ } else { ++ CMS.debug("Repository: next range not available."); ++ } ++ } ++ + if (theSerialNo != null) { + + mLastSerialNo = new BigInteger(theSerialNo.toString()); +-- +1.8.3.1 + + +From 920187e48e4971069ac114a3a41a5be79578f17c Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Wed, 29 Aug 2018 17:31:34 +1000 +Subject: [PATCH 10/14] rename method getTheSerialNumber -> + peekNextSerialNumber + +Rename Repository.getTheSerialNumber -> peekNextSerialNumber to more +accurately reflect what it does: peek at the next serial number +without actually consuming it. + +Part of: https://pagure.io/dogtagpki/issue/3055 + +(cherry picked from commit 85e356580f64f87c0b01736b71dc3d385db0bcba) +--- + base/ca/src/com/netscape/ca/CertificateAuthority.java | 2 +- + base/common/src/com/netscape/certsrv/dbs/repository/IRepository.java | 2 +- + .../cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java | 2 +- + base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java | 2 +- + 4 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java +index 0281db0..f414628 100644 +--- a/base/ca/src/com/netscape/ca/CertificateAuthority.java ++++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java +@@ -1077,7 +1077,7 @@ public class CertificateAuthority + public String getStartSerial() { + try { + BigInteger serial = +- mCertRepot.getTheSerialNumber(); ++ mCertRepot.peekNextSerialNumber(); + + if (serial == null) + return ""; +diff --git a/base/common/src/com/netscape/certsrv/dbs/repository/IRepository.java b/base/common/src/com/netscape/certsrv/dbs/repository/IRepository.java +index 39744ac..d0b6135 100644 +--- a/base/common/src/com/netscape/certsrv/dbs/repository/IRepository.java ++++ b/base/common/src/com/netscape/certsrv/dbs/repository/IRepository.java +@@ -50,7 +50,7 @@ public interface IRepository { + * @return serial number + * @exception EBaseException failed to retrieve next serial number + */ +- public BigInteger getTheSerialNumber() throws EBaseException; ++ public BigInteger peekNextSerialNumber() throws EBaseException; + + /** + * Set the maximum serial number. +diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java +index 2586da2..e5b5168 100644 +--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java ++++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java +@@ -187,7 +187,7 @@ public class UpdateNumberRange extends CMSServlet { + BigInteger decrement = new BigInteger(decrementStr, radix); + beginNum = endNum.subtract(decrement).add(oneNum); + +- if (beginNum.compareTo(repo.getTheSerialNumber()) < 0) { ++ if (beginNum.compareTo(repo.peekNextSerialNumber()) < 0) { + String nextEndNumStr = cs.getString(nextEndConfig, ""); + BigInteger endNum2 = new BigInteger(nextEndNumStr, radix); + CMS.debug("Transferring from the end of on-deck range"); +diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java +index 828217c..55068ea 100644 +--- a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java ++++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java +@@ -346,7 +346,7 @@ public abstract class Repository implements IRepository { + * Returns null if the next number exceeds the current range and + * there is not a next range. + */ +- public BigInteger getTheSerialNumber() throws EBaseException { ++ public BigInteger peekNextSerialNumber() throws EBaseException { + + CMS.debug("Repository:In getTheSerialNumber "); + if (mLastSerialNo == null) +-- +1.8.3.1 + + +From 60e78b19edb91b5d7130f591dec5232f30877871 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Wed, 29 Aug 2018 21:42:40 +1000 +Subject: [PATCH 11/14] checkRange: small refactor and add commentary + +Add some commentary about the behaviour and proper usage of +Repository.checkRange(). Also perform a small refactor, avoiding +a redundant stringify and parse. + +Part of: https://pagure.io/dogtagpki/issue/3055 + +(cherry picked from commit 5a606e83719272fb488047b28a9ca7d5ce2ea30b) +--- + .../src/com/netscape/cmscore/dbs/Repository.java | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java +index 55068ea..9bc7e2a 100644 +--- a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java ++++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java +@@ -406,14 +406,17 @@ public abstract class Repository implements IRepository { + throw new EBaseException("mLastSerialNo is null"); + } + ++ /* Advance the serial number. checkRange() will check if it exceeds ++ * the current range and, if so, rolls to the next range and resets ++ * mLastSerialNo to the start of the new range. Hence we return ++ * mLastSerialNo below, after the call to checkRange(). ++ */ + mLastSerialNo = mLastSerialNo.add(BigInteger.ONE); + + checkRange(); + +- BigInteger retSerial = new BigInteger(mLastSerialNo.toString()); +- +- CMS.debug("Repository: getNextSerialNumber: returning retSerial " + retSerial); +- return retSerial; ++ CMS.debug("Repository: getNextSerialNumber: returning " + mLastSerialNo); ++ return mLastSerialNo; + } + + /** +@@ -422,6 +425,14 @@ public abstract class Repository implements IRepository { + * If it exceeds the given range, and there is a next range, switch the range. + * If it exceeds the given range, and there is not a next range, throw EDBException. + * ++ * Precondition: the serial number should already have been advanced. ++ * This method will detect that and switch to the next range, including ++ * resetting mLastSerialNo to the start of the new (now current) range. ++ * ++ * Postcondition: the caller should again read mLastSerialNo after ++ * calling checkRange(), in case checkRange switched the range and the ++ * new range is not adjacent to the current range. ++ * + * @exception EDBException thrown when range switch is needed + * but next range is not allocated + */ +-- +1.8.3.1 + + +From a2c05cef94753ee1914aeb9c1b88789a322d4015 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Wed, 29 Aug 2018 22:22:10 +1000 +Subject: [PATCH 12/14] Add missing synchronisation for range management + +Several methods in Repository (and CertificateRepository) need +synchronisation on the intrisic lock. Make these methods +synchronised. + +Also take the lock in UpdateNumberRange so that no serial numbers +can be handed out in other threads between peekNextSerialNumber() +and set(Next)?MaxSerial(). Without this synchronisation, it is +possible that the master instance will use some of the serial +numbers it transfers to the clone. + +Fixes: https://pagure.io/dogtagpki/issue/3055 +(cherry picked from commit 851a0bdd79c12c627a04cfc376338c1727cd50d9) +--- + .../cms/servlet/csadmin/UpdateNumberRange.java | 35 +++++++----- + .../cmscore/dbs/CertificateRepository.java | 62 ++++++++++------------ + .../src/com/netscape/cmscore/dbs/Repository.java | 6 +-- + 3 files changed, 53 insertions(+), 50 deletions(-) + +diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java +index e5b5168..c2ff7ed 100644 +--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java ++++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/UpdateNumberRange.java +@@ -187,20 +187,27 @@ public class UpdateNumberRange extends CMSServlet { + BigInteger decrement = new BigInteger(decrementStr, radix); + beginNum = endNum.subtract(decrement).add(oneNum); + +- if (beginNum.compareTo(repo.peekNextSerialNumber()) < 0) { +- String nextEndNumStr = cs.getString(nextEndConfig, ""); +- BigInteger endNum2 = new BigInteger(nextEndNumStr, radix); +- CMS.debug("Transferring from the end of on-deck range"); +- String newValStr = endNum2.subtract(decrement).toString(radix); +- repo.setNextMaxSerial(newValStr); +- cs.putString(nextEndConfig, newValStr); +- beginNum = endNum2.subtract(decrement).add(oneNum); +- endNum = endNum2; +- } else { +- CMS.debug("Transferring from the end of the current range"); +- String newValStr = beginNum.subtract(oneNum).toString(radix); +- repo.setMaxSerial(newValStr); +- cs.putString(endNumConfig, newValStr); ++ /* We need to synchronise on repo because we peek the next ++ * serial number, then set the max serial of the current or ++ * next range. If we don't synchronize, we could end up ++ * using serial numbers that were transferred. ++ */ ++ synchronized (repo) { ++ if (beginNum.compareTo(repo.peekNextSerialNumber()) < 0) { ++ String nextEndNumStr = cs.getString(nextEndConfig, ""); ++ BigInteger endNum2 = new BigInteger(nextEndNumStr, radix); ++ CMS.debug("Transferring from the end of on-deck range"); ++ String newValStr = endNum2.subtract(decrement).toString(radix); ++ repo.setNextMaxSerial(newValStr); ++ cs.putString(nextEndConfig, newValStr); ++ beginNum = endNum2.subtract(decrement).add(oneNum); ++ endNum = endNum2; ++ } else { ++ CMS.debug("Transferring from the end of the current range"); ++ String newValStr = beginNum.subtract(oneNum).toString(radix); ++ repo.setMaxSerial(newValStr); ++ cs.putString(endNumConfig, newValStr); ++ } + } + + if (beginNum == null) { +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 367917f..94087c8 100644 +--- a/base/server/cmscore/src/com/netscape/cmscore/dbs/CertificateRepository.java ++++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/CertificateRepository.java +@@ -251,49 +251,45 @@ public class CertificateRepository extends Repository + return nextSerialNumber; + } + +- private Object nextSerialNumberMonitor = new Object(); +- +- public BigInteger getNextSerialNumber() throws ++ public synchronized BigInteger getNextSerialNumber() throws + EBaseException { + + BigInteger nextSerialNumber = null; + BigInteger randomNumber = null; + +- synchronized (nextSerialNumberMonitor) { +- super.initCacheIfNeeded(); +- CMS.debug("CertificateRepository: getNextSerialNumber mEnableRandomSerialNumbers="+mEnableRandomSerialNumbers); ++ super.initCacheIfNeeded(); ++ CMS.debug("CertificateRepository: getNextSerialNumber mEnableRandomSerialNumbers="+mEnableRandomSerialNumbers); + +- if (mEnableRandomSerialNumbers) { +- int i = 0; +- do { +- if (i > 0) { +- CMS.debug("CertificateRepository: getNextSerialNumber regenerating serial number"); +- } +- randomNumber = getRandomNumber(); +- nextSerialNumber = getRandomSerialNumber(randomNumber); +- nextSerialNumber = checkSerialNumbers(randomNumber, nextSerialNumber); +- i++; +- } while (nextSerialNumber == null && i < mMaxCollisionRecoveryRegenerations); +- +- if (nextSerialNumber == null) { +- CMS.debug("CertificateRepository: in getNextSerialNumber nextSerialNumber is null"); +- throw new EBaseException( "nextSerialNumber is null" ); ++ if (mEnableRandomSerialNumbers) { ++ int i = 0; ++ do { ++ if (i > 0) { ++ CMS.debug("CertificateRepository: getNextSerialNumber regenerating serial number"); + } ++ randomNumber = getRandomNumber(); ++ nextSerialNumber = getRandomSerialNumber(randomNumber); ++ nextSerialNumber = checkSerialNumbers(randomNumber, nextSerialNumber); ++ i++; ++ } while (nextSerialNumber == null && i < mMaxCollisionRecoveryRegenerations); + +- if (mCounter.compareTo(BigInteger.ZERO) >= 0 && +- mMinSerialNo != null && mMaxSerialNo != null && +- nextSerialNumber != null && +- nextSerialNumber.compareTo(mMinSerialNo) >= 0 && +- nextSerialNumber.compareTo(mMaxSerialNo) <= 0) { +- mCounter = mCounter.add(BigInteger.ONE); +- } +- CMS.debug("CertificateRepository: getNextSerialNumber nextSerialNumber="+ +- nextSerialNumber+" mCounter="+mCounter); ++ if (nextSerialNumber == null) { ++ CMS.debug("CertificateRepository: in getNextSerialNumber nextSerialNumber is null"); ++ throw new EBaseException( "nextSerialNumber is null" ); ++ } + +- super.checkRange(); +- } else { +- nextSerialNumber = super.getNextSerialNumber(); ++ if (mCounter.compareTo(BigInteger.ZERO) >= 0 && ++ mMinSerialNo != null && mMaxSerialNo != null && ++ nextSerialNumber != null && ++ nextSerialNumber.compareTo(mMinSerialNo) >= 0 && ++ nextSerialNumber.compareTo(mMaxSerialNo) <= 0) { ++ mCounter = mCounter.add(BigInteger.ONE); + } ++ CMS.debug("CertificateRepository: getNextSerialNumber nextSerialNumber="+ ++ nextSerialNumber+" mCounter="+mCounter); ++ ++ super.checkRange(); ++ } else { ++ nextSerialNumber = super.getNextSerialNumber(); + } + + return nextSerialNumber; +diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java +index 9bc7e2a..c31d376 100644 +--- a/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java ++++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/Repository.java +@@ -185,7 +185,7 @@ public abstract class Repository implements IRepository { + * @param serial maximum number + * @exception EBaseException failed to set maximum serial number + */ +- public void setMaxSerial(String serial) throws EBaseException { ++ public synchronized void setMaxSerial(String serial) throws EBaseException { + BigInteger maxSerial = null; + CMS.debug("Repository:setMaxSerial " + serial); + +@@ -211,7 +211,7 @@ public abstract class Repository implements IRepository { + * @param serial maximum number in next range + * @exception EBaseException failed to set maximum serial number in next range + */ +- public void setNextMaxSerial(String serial) throws EBaseException { ++ public synchronized void setNextMaxSerial(String serial) throws EBaseException { + BigInteger maxSerial = null; + CMS.debug("Repository:setNextMaxSerial " + serial); + +@@ -346,7 +346,7 @@ public abstract class Repository implements IRepository { + * Returns null if the next number exceeds the current range and + * there is not a next range. + */ +- public BigInteger peekNextSerialNumber() throws EBaseException { ++ public synchronized BigInteger peekNextSerialNumber() throws EBaseException { + + CMS.debug("Repository:In getTheSerialNumber "); + if (mLastSerialNo == null) +-- +1.8.3.1 + + +From 2fb237853c3f730f4f96141d9710d1394de5649d Mon Sep 17 00:00:00 2001 +From: "Endi S. Dewata" +Date: Fri, 20 Sep 2019 10:59:07 -0500 +Subject: [PATCH 13/14] Replaced "Advanced Search" with "Filter" in TPS UI + +(cherry picked from commit df3ece37320c2de7db025aa172c2344b07a55483) +--- + base/tps/shared/webapps/tps/ui/tokens.html | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/base/tps/shared/webapps/tps/ui/tokens.html b/base/tps/shared/webapps/tps/ui/tokens.html +index c2f6227..41d8d94 100644 +--- a/base/tps/shared/webapps/tps/ui/tokens.html ++++ b/base/tps/shared/webapps/tps/ui/tokens.html +@@ -30,7 +30,7 @@ + + + +- Advanced Search ++ Filter + + + +-- +1.8.3.1 + + +From f2186a497978b778a808e6ad892bfd4180acf8a6 Mon Sep 17 00:00:00 2001 +From: Jack Magne +Date: Fri, 20 Sep 2019 20:20:13 -0400 +Subject: [PATCH 14/14] Fix Bug 1534013 - Attempting to add new keys using a + PUT KEY APDU to a token that is loaded only with the default/factory keys + (Key Version Number 0xFF) returns an APDU with error code 0x6A88. + +The token returns 0x6A88 (Referenced data not found) because sending it a key version number of 1, implies that the token already has a key with key version 1. In the case of a token with only default/factory keys with version 0xFF, the key with version #1 is not present. + +Giving zero as the key version number in the APDU specifically tells the token to add a new key, with a new key version number. A non-zero key version number instructs the card to replace an existing key. If the existing key is not present then an error occurs. + +(cherry picked from commit 19bb64a98881e4651126bcdc544e3fa04ea989ea) +--- + base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java b/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java +index cb08970..7369e58 100644 +--- a/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java ++++ b/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java +@@ -1558,8 +1558,8 @@ public class SecureChannel { + byte keyVersion = curVersion; + + if (curVersion == (byte) 0xff) { +- CMS.debug("Setting keyVersion to 1"); +- keyVersion = 0x1; ++ CMS.debug("Setting keyVersion to 0"); ++ keyVersion = 0x0; + } + + CMS.debug("keyVersion now set to: " + keyVersion); +-- +1.8.3.1 + diff --git a/SOURCES/pki-core-rhel-7-8-rhcs-9-6-snapshot-2.patch b/SOURCES/pki-core-rhel-7-8-rhcs-9-6-snapshot-2.patch new file mode 100644 index 0000000..0b1ac4b --- /dev/null +++ b/SOURCES/pki-core-rhel-7-8-rhcs-9-6-snapshot-2.patch @@ -0,0 +1,104 @@ +From 6c199b8882fa1b2cb07f911d29d2a7eccf7e99c7 Mon Sep 17 00:00:00 2001 +From: Christina Fu +Date: Fri, 22 Nov 2019 13:03:18 -0500 +Subject: [PATCH 1/2] Bug 1723008 - ECC Key recovery failure with + CKR_TEMPLATE_INCONSISTENT + +The current settings irt key wrapping parameters were depending on the +expection that the revised sw version for the nCipher HSM would be capable +of handling the key wrapping/unwrapping algorithm "AES KeyWrap/Padding"; +As it turned out it did not completely do that. +This patch changes the default setting in the KRA CS.cfg as well as +CRMFPopClient to that of a supported wrapping algorithm: AES/CBC/PKCS5Padding + +Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1723008 + +(cherry picked from commit 06fdf41b2f5947f90d84b3fc32def4c8346c9601) +--- + base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java | 6 +++--- + base/kra/shared/conf/CS.cfg | 3 ++- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java +index 72eca3e..4caf92f 100644 +--- a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java ++++ b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java +@@ -224,8 +224,8 @@ public class CRMFPopClient { + System.out.println(" - POP_SUCCESS: with valid POP"); + System.out.println(" - POP_FAIL: with invalid POP (for testing)"); + System.out.println(" -w Algorithm to use for key wrapping"); +- System.out.println(" - default: \"AES KeyWrap/Padding\""); +- System.out.println(" - \"AES/CBC/PKCS5Padding\""); ++ System.out.println(" - default: \"AES/CBC/PKCS5Padding\""); ++ System.out.println(" - \"AES KeyWrap/Padding\""); + System.out.println(" - \"DES3/CBC/Pad\""); + System.out.println(" -b PEM transport certificate (default: transport.txt)"); + System.out.println(" -v, --verbose Run in verbose mode."); +@@ -324,7 +324,7 @@ public class CRMFPopClient { + + // get the keywrap algorithm + KeyWrapAlgorithm keyWrapAlgorithm = null; +- String kwAlg = KeyWrapAlgorithm.AES_KEY_WRAP_PAD.toString(); ++ String kwAlg = KeyWrapAlgorithm.AES_CBC_PAD.toString(); + if (cmd.hasOption("w")) { + kwAlg = cmd.getOptionValue("w"); + } else { +diff --git a/base/kra/shared/conf/CS.cfg b/base/kra/shared/conf/CS.cfg +index f21f305..9f54c40 100644 +--- a/base/kra/shared/conf/CS.cfg ++++ b/base/kra/shared/conf/CS.cfg +@@ -286,7 +286,8 @@ kra.storageUnit.wrapping.1.sessionKeyKeyGenAlgorithm=AES + kra.storageUnit.wrapping.1.payloadEncryptionAlgorithm=AES + kra.storageUnit.wrapping.1.payloadEncryptionMode=CBC + kra.storageUnit.wrapping.1.payloadEncryptionIVLen=16 +-kra.storageUnit.wrapping.1.payloadWrapAlgorithm=AES KeyWrap/Padding ++kra.storageUnit.wrapping.1.payloadWrapAlgorithm=AES/CBC/PKCS5Padding ++kra.storageUnit.wrapping.1.payloadWrapIVLen=16 + kra.storageUnit.wrapping.1.sessionKeyType=AES + kra.storageUnit.wrapping.choice=1 + kra.storageUnit.nickName=storageCert cert-[PKI_INSTANCE_NAME] +-- +1.8.3.1 + + +From 90105b85df48b2035e8c5fa1f0982f631964b011 Mon Sep 17 00:00:00 2001 +From: Alexander Scheel +Date: Wed, 20 Nov 2019 09:10:02 -0500 +Subject: [PATCH 2/2] Remove non-breaking space from pki-server-nuxwdog + +In pki-server-nuxwdog, we had a non-breaking space at the end of a +quoted string, causing the resulting directory to end with a +non-breaking space. + +This results in paths with incorrect names: + +/var/log/pki/$INSTANCE/pids / + +instead of + +/var/log/pki/$INSTANCE/pids/ + +Resolves: rhbz#1774282 + +Signed-off-by: Alexander Scheel +(cherry picked from commit 4f2b8aaf13b488558b7718d7967d42db4d23d172) +--- + base/server/sbin/pki-server-nuxwdog | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/base/server/sbin/pki-server-nuxwdog b/base/server/sbin/pki-server-nuxwdog +index ffdbc33..5244d57 100755 +--- a/base/server/sbin/pki-server-nuxwdog ++++ b/base/server/sbin/pki-server-nuxwdog +@@ -43,7 +43,7 @@ chown ${TOMCAT_USER}: ${nux_fname} + + echo "ExeFile ${JAVA_HOME}/bin/java" > $nux_fname + echo "ExeArgs ${JAVA_HOME}/bin/java ${JAVACMD_OPTS} ${FLAGS} -classpath ${CLASSPATH} ${OPTIONS} ${MAIN_CLASS} start" >> $nux_fname +-echo "TmpDir ${CATALINA_BASE}/logs/pids" >> $nux_fname ++echo "TmpDir ${CATALINA_BASE}/logs/pids" >> $nux_fname + echo "ChildSecurity 1" >> $nux_fname + echo "ExeOut ${CATALINA_BASE}/logs/catalina.out" >> $nux_fname + echo "ExeErr ${CATALINA_BASE}/logs/catalina.out" >> $nux_fname +-- +1.8.3.1 + diff --git a/SPECS/pki-core.spec b/SPECS/pki-core.spec index 59f156f..b413d4c 100644 --- a/SPECS/pki-core.spec +++ b/SPECS/pki-core.spec @@ -13,7 +13,7 @@ %global package_rhel_packages 1 # Package RHCS-specific RPMS Only %global package_rhcs_packages 0 -%define pki_core_rhel_version 10.5.16 +%define pki_core_rhel_version 10.5.17 %else # Fedora always packages all RPMS %global package_fedora_packages 1 @@ -64,13 +64,13 @@ Name: pki-core %if 0%{?rhel} -Version: 10.5.16 +Version: 10.5.17 %define redhat_release 6 %define redhat_stage 0 #%define default_release %{redhat_release}.%{redhat_stage} %define default_release %{redhat_release} %else -Version: 10.5.16 +Version: 10.5.17 %define fedora_release 6 %define fedora_stage 0 #%define default_release %{fedora_release}.%{fedora_stage} @@ -78,11 +78,9 @@ Version: 10.5.16 %endif %if 0%{?use_pki_release} -#Release: %{pki_release}%{?dist} -Release: %{pki_release}.el7_7 +Release: %{pki_release}%{?dist} %else -#Release: %{default_release}%{?dist} -Release: %{default_release}.el7_7 +Release: %{default_release}%{?dist} %endif Summary: Certificate System - PKI Core Components @@ -111,7 +109,7 @@ BuildRequires: nspr-devel BuildRequires: nss-devel >= 3.28.3 %if 0%{?rhel} && 0%{?rhel} <= 7 -BuildRequires: nuxwdog-client-java >= 1.0.3-8 +BuildRequires: nuxwdog-client-java >= 1.0.5-1 %else BuildRequires: nuxwdog-client-java >= 1.0.3-14 %endif @@ -168,9 +166,9 @@ BuildRequires: policycoreutils-python-utils BuildRequires: python-ldap BuildRequires: junit BuildRequires: jpackage-utils >= 0:1.7.5-10 -BuildRequires: jss >= 4.4.6-1 +BuildRequires: jss >= 4.4.7-1 %if 0%{?rhel} && 0%{?rhel} <= 7 -BuildRequires: tomcatjss >= 7.2.1-8 +BuildRequires: tomcatjss >= 7.2.5-1 %else BuildRequires: tomcatjss >= 7.2.4-4 %endif @@ -208,11 +206,10 @@ Source0: http://pki.fedoraproject.org/pki/sources/%{name}/%{version}/%{ Source0: http://pki.fedoraproject.org/pki/sources/%{name}/%{version}/%{release}/%{name}-%{version}%{?prerel}.tar.gz %endif -Patch0: pki-core-Add-Subject-Key-ID-to-CSR.patch -Patch1: pki-core-PKI-startup-init-LDAP-operation-attr-independence.patch -Patch2: pki-core-Fixed-Missing-SAN-extension-for-CA-Clone.patch -Patch3: pki-core-Internal-LDAP-Server-goes-down-Audit-Event.patch -Patch4: pki-core-Fixed-Number-Range-Depletion-Issue.patch +Patch0: pki-core-rhel-7-8-rhcs-9-6-alpha.patch +Patch1: pki-core-rhel-7-8-rhcs-9-6-beta.patch +Patch2: pki-core-Fixed-missing-audit-event.patch +Patch3: pki-core-rhel-7-8-rhcs-9-6-snapshot-2.patch # Obtain version phase number (e. g. - used by "alpha", "beta", etc.) # @@ -312,7 +309,7 @@ Group: System Environment/Libraries Requires: java-1.8.0-openjdk-headless Requires: jpackage-utils >= 0:1.7.5-10 -Requires: jss >= 4.4.6-1 +Requires: jss >= 4.4.7-1 Requires: nss >= 3.28.3 Provides: symkey = %{version}-%{release} @@ -391,7 +388,7 @@ Requires: slf4j-jdk14 %endif Requires: javassist Requires: jpackage-utils >= 0:1.7.5-10 -Requires: jss >= 4.4.6-1 +Requires: jss >= 4.4.7-1 Requires: ldapjdk >= 4.19-5 Requires: pki-base = %{version}-%{release} @@ -502,7 +499,7 @@ Requires: hostname Requires: net-tools %if 0%{?rhel} && 0%{?rhel} <= 7 -Requires: nuxwdog-client-java >= 1.0.3-8 +Requires: nuxwdog-client-java >= 1.0.5-1 %else Requires: nuxwdog-client-java >= 1.0.3-14 %endif @@ -544,7 +541,7 @@ Requires(preun): systemd-units Requires(postun): systemd-units Requires(pre): shadow-utils %if 0%{?rhel} && 0%{?rhel} <= 7 -Requires: tomcatjss >= 7.2.1-8 +Requires: tomcatjss >= 7.2.5-1 %else Requires: tomcatjss >= 7.2.4-4 %endif @@ -810,7 +807,6 @@ This package is a part of the PKI Core used by the Certificate System. %patch1 -p1 %patch2 -p1 %patch3 -p1 -%patch4 -p1 %clean %{__rm} -rf %{buildroot} @@ -1156,6 +1152,7 @@ fi %doc base/native-tools/LICENSE base/native-tools/doc/README %{_bindir}/pki %{_bindir}/p7tool +%{_bindir}/pistool %{_bindir}/revoker %{_bindir}/setpin %{_bindir}/sslget @@ -1347,41 +1344,88 @@ fi %endif # %{with server} %changelog -* Mon Oct 14 2019 Dogtag Team 10.5.16-6 +* Mon Dec 2 2019 Dogtag Team 10.5.17-6 - ########################################################################## -- # RHEL 7.7: +- # RHEL 7.8: +- ########################################################################## +- Bugzilla Bug #1723008 - ECC Key recovery failure with + CKR_TEMPLATE_INCONSISTENT (cfu) +- Bugzilla Bug #1774282 - pki-server-nuxwdog template has pid file name with + non-breakable space char encoded instead of 0x20 space char (ascheel) +- ########################################################################## +- # RHCS 9.6: +- ########################################################################## +- # Bugzilla Bug #1733588 - Rebase redhat-pki, redhat-pki-theme, pki-core, and + # pki-console to 10.5.17 in RHCS 9.6 + +* Thu Oct 24 2019 Dogtag Team 10.5.17-5 +- ########################################################################## +- # RHEL 7.8: +- ########################################################################## +- Bugzilla Bug #1523330 - CC: missing audit event for CS acting as TLS client + (cfu) +- ########################################################################## +- # RHCS 9.6: +- ########################################################################## +- # Bugzilla Bug #1733588 - Rebase redhat-pki, redhat-pki-theme, pki-core, and + # pki-console to 10.5.17 in RHCS 9.6 + +* Mon Sep 30 2019 Dogtag Team 10.5.17-4 +- Include 'pistool' in the 'pki-tools' package + +* Mon Sep 23 2019 Dogtag Team 10.5.17-3 +- ########################################################################## +- # RHEL 7.8: - ########################################################################## -- Bugzilla Bug #1754845 - number range depletion when multiple clones +- Bugzilla Bug #1445479 - KRATool does not support netkeyKeyRecovery + attribute (dmoluguw) +- Bugzilla Bug #1534013 - Attempting to add new keys using a PUT KEY APDU + to a token that is loaded only with the default/factory keys (Key Version + Number 0xFF) returns an APDU with error code 0x6A88. (jmagne) +- Bugzilla Bug #1709585 - PKI (test support) for PKCS#11 standard + AES KeyWrap for HSM support (cfu, ftweedal) +- Bugzilla Bug #1748766 - number range depletion when multiple clones created from same master (ftweedal) - ########################################################################## -- # RHCS 9.5: +- # RHCS 9.6: - ########################################################################## -- # Bugzilla Bug #1633423 - Rebase redhat-pki, redhat-pki-theme, pki-core, and - # pki-console to 10.5.16 in RHCS 9.5 +- # Bugzilla Bug #1520258 - TPS token search fails to find entries , LDAP filter + # on cn and tokenUserID with wildchar too broad in some cases (rhcs-maint) +- # Bugzilla Bug #1535671 - RFE to have the users be able to use the + # "Advanced Search" option on the TPS UI (edewata) -* Mon Sep 9 2019 Dogtag Team 10.5.16-5 +* Mon Sep 9 2019 Dogtag Team 10.5.17-2 - ########################################################################## -- # RHEL 7.7: +- # RHEL 7.8: - ########################################################################## -- Bugzilla Bug #1750277 - CC: missing audit event for CS acting as TLS client - [rhel-7.7.z] (cfu) +- Bugzilla Bug #1523330 - CC: missing audit event for CS acting as TLS + client (cfu) +- Bugzilla Bug #1597727 - CA - Unable to change a certificate’s revocation + reason from superceded to key_compromised (rhcs-maint) - ########################################################################## -- # RHCS 9.5: +- # RHCS 9.6: - ########################################################################## -- # Bugzilla Bug #1633423 - Rebase redhat-pki, redhat-pki-theme, pki-core, and - # pki-console to 10.5.16 in RHCS 9.5 +- # Bugzilla Bug #1470410 - TPS doesn't update revocation status when + # certificate already marked as unformatted/terminated/damaged (rhcs-maint) +- # Bugzilla Bug #1470433 - Add supported transitions to TPS (rhcs-maint) +- # Bugzilla Bug #1585722 - TMS - PKISocketFactory – Modify Logging to Allow + # External Use of class to work like CS8 (rhcs-maint) +- # Bugzilla Bug #1642577 - TPS – Revoked Encryption Certificates Marked as + # Active in TPS Cert LDAP During Token Key Recovery (rhcs-maint) -* Mon Aug 19 2019 Dogtag Team 10.5.16-4 +* Tue Aug 13 2019 Dogtag Team 10.5.17-1 +- Updated jss, nuxwdog, and tomcatjss dependencies - ########################################################################## -- # RHEL 7.7: +- # RHEL 7.8: - ########################################################################## -- Bugzilla Bug #1743122 - RHCS-9 CA clone SSL server cert not issued with its - custom SAN extension, RHEL-7.6 and HSM [rhel-7.7.z] (edewata) +- Bugzilla Bug #1733586 - Rebase pki-core from 10.5.16 to 10.5.17 (RHEL) - ########################################################################## -- # RHCS 9.5: +- # RHCS 9.6: - ########################################################################## -- # Bugzilla Bug #1633423 - Rebase redhat-pki, redhat-pki-theme, pki-core, and - # pki-console to 10.5.16 in RHCS 9.5 +- # Bugzilla Bug #1718418 - Update RHCS version of CA, KRA, OCSP, and TKS so + # that it can be identified using a browser [RHCS] +- # Bugzilla Bug #1733588 - Rebase redhat-pki, redhat-pki-theme, pki-core, and + # pki-console to 10.5.17 in RHCS 9.6 * Thu Jun 20 2019 Dogtag Team 10.5.16-3 - ########################################################################## @@ -1392,8 +1436,8 @@ fi - ########################################################################## - # RHCS 9.5: - ########################################################################## -- Bugzilla Bug #1633423 - Rebase redhat-pki, redhat-pki-theme, pki-core, and - pki-console to 10.5.16 in RHCS 9.5 +- # Bugzilla Bug #1633423 - Rebase redhat-pki, redhat-pki-theme, pki-core, and + # pki-console to 10.5.16 in RHCS 9.5 * Thu Apr 4 2019 Dogtag Team 10.5.16-2 - ##########################################################################