Blob Blame History Raw
From ab570231ef3f63712cf7404ca2171cbea0ae0f92 Mon Sep 17 00:00:00 2001
From: Jack Magne <jmagne@dhcp-16-206.sjc.redhat.com>
Date: Tue, 16 Aug 2016 16:58:49 -0700
Subject: [PATCH 1/7] Authentication Instance Id PinDirEnrollment with authType
 value as SslclientAuth is not working.

Ticket #1578

The fixing of this problem required the following:

1. Hook up a java callback that is designed to allow the selection of a candidate
client auth cert to be sent to Ldap in the LdapSSLSocket factory object.

Previously we simply manually set the desired client auth cert nickname, which is provided
by the console interface when cofiguring the "removePin" portion of the UidPinDir Authentication method.

Doing it this way has the benefit of giving us some logging to show when the actual client auth cert is being
requested by the server. We get to see the list of candidate certs and when we match one of those with the requested
cert name, established by the console.

This client auth problem applies ONLY to the connection pool that is used to remove the pin attribute from
an external authentication directory.

2. Previously the code, when setting up client auth for "removePin", would make one single call to create the SSL socket
to connect to ldap over client auth. Now, based on some code I saw in the JSS test suite, the socket is constructed in two
steps. Doing this causes things to work. Further investigation down the line could figure out what is going on at the lower level.

3. Was able to test this to work with the reported problem directory server provided by QE. Note: for pin removal to work, we must also
make sure that the user we authenticating to (through client auth) has the power to actually remove the pin attribute from various users.

(cherry picked from commit a4d726098458225a0605faca9f11ebaa4dab036f)
---
 .../cmscore/ldapconn/LdapJssSSLSocketFactory.java  | 70 ++++++++++++++++++++--
 1 file changed, 65 insertions(+), 5 deletions(-)

diff --git a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/LdapJssSSLSocketFactory.java b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/LdapJssSSLSocketFactory.java
index 182812c..b54d1e2 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/ldapconn/LdapJssSSLSocketFactory.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/ldapconn/LdapJssSSLSocketFactory.java
@@ -18,9 +18,16 @@
 package com.netscape.cmscore.ldapconn;
 
 import java.io.IOException;
+import java.net.InetAddress;
 import java.net.Socket;
 import java.net.UnknownHostException;
+import java.util.Iterator;
+import java.util.Vector;
 
+import netscape.ldap.LDAPException;
+import netscape.ldap.LDAPSSLSocketFactoryExt;
+
+import org.mozilla.jss.ssl.SSLClientCertificateSelectionCallback;
 import org.mozilla.jss.ssl.SSLHandshakeCompletedEvent;
 import org.mozilla.jss.ssl.SSLHandshakeCompletedListener;
 import org.mozilla.jss.ssl.SSLSocket;
@@ -28,9 +35,6 @@ import org.mozilla.jss.ssl.SSLSocket;
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.logging.ILogger;
 
-import netscape.ldap.LDAPException;
-import netscape.ldap.LDAPSSLSocketFactoryExt;
-
 /**
  * Uses HCL ssl socket.
  *
@@ -54,7 +58,22 @@ public class LdapJssSSLSocketFactory implements LDAPSSLSocketFactoryExt {
             /*
              * let inherit TLS range and cipher settings
              */
-            s = new SSLSocket(host, port);
+
+            if (mClientAuthCertNickname == null) {
+                s = new SSLSocket(host, port);
+            }
+            else {
+                //Let's create a selection callback in the case the client auth
+                //No longer manually set the cert name.
+                //This two step process, used in the JSS client auth test suite,
+                //appears to be needed to get this working.
+
+                Socket js = new Socket(InetAddress.getByName(host), port);
+                s = new SSLSocket(js, host,
+                        null,
+                        new SSLClientCertificateSelectionCB(mClientAuthCertNickname));
+            }
+
             s.setUseClientMode(true);
             s.enableV2CompatibleHello(false);
 
@@ -67,7 +86,9 @@ public class LdapJssSSLSocketFactory implements LDAPSSLSocketFactoryExt {
                 mClientAuth = true;
                 CMS.debug("LdapJssSSLSocket: set client auth cert nickname " +
                         mClientAuthCertNickname);
-                s.setClientCertNickname(mClientAuthCertNickname);
+
+                //We have already established the manual cert selection callback
+                //Doing it this way will provide some debugging info on the candidate certs
             }
             s.forceHandshake();
 
@@ -114,4 +135,43 @@ public class LdapJssSSLSocketFactory implements LDAPSSLSocketFactoryExt {
             CMS.debug("SSL handshake happened");
         }
     }
+
+    static class SSLClientCertificateSelectionCB implements SSLClientCertificateSelectionCallback {
+        String desiredCertName = null;
+
+        public SSLClientCertificateSelectionCB(String clientAuthCertNickname) {
+            CMS.debug("SSLClientCertificateSelectionCB: Setting desired cert nickname to: " + clientAuthCertNickname);
+            desiredCertName = clientAuthCertNickname;
+        }
+
+        @Override
+        public String select(Vector certs) {
+
+            CMS.debug("SSLClientCertificatSelectionCB: Entering!");
+
+            if(desiredCertName == null) {
+                return null;
+            }
+
+            @SuppressWarnings("unchecked")
+            Iterator<String> itr = certs.iterator();
+            String selection = null;
+
+            while(itr.hasNext()){
+                String candidate = itr.next();
+                CMS.debug("Candidate cert: " + candidate);
+                if(desiredCertName.equalsIgnoreCase(candidate)) {
+                    selection = candidate;
+                    CMS.debug("SSLClientCertificateSelectionCB: desired cert found in list: " + desiredCertName);
+                    break;
+                }
+            }
+
+            CMS.debug("SSLClientCertificateSelectionCB: returning: " + selection);
+            return selection;
+
+        }
+
+    }
+
 }
-- 
2.7.4


From b6a038a81c6f69e636822d7615e97d591c244aa1 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Wed, 24 Aug 2016 18:42:05 +0200
Subject: [PATCH 2/7] Added upgrade script to fix deployment descriptors.

An upgrade script has been added to fix missing deployment
descriptors or deployment descriptors that are pointing to
non-existent or empty folders.

https://fedorahosted.org/pki/ticket/2439
(cherry picked from commit b8094e82c46f8d5f18d362404582304ad28407da)
---
 .../upgrade/10.3.5/03-FixDeploymentDescriptor      | 110 +++++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100644 base/server/upgrade/10.3.5/03-FixDeploymentDescriptor

diff --git a/base/server/upgrade/10.3.5/03-FixDeploymentDescriptor b/base/server/upgrade/10.3.5/03-FixDeploymentDescriptor
new file mode 100644
index 0000000..27c8959
--- /dev/null
+++ b/base/server/upgrade/10.3.5/03-FixDeploymentDescriptor
@@ -0,0 +1,110 @@
+#!/usr/bin/python
+# Authors:
+#     Endi S. Dewata <edewata@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2016 Red Hat, Inc.
+# All rights reserved.
+
+from __future__ import absolute_import
+from lxml import etree
+import os
+import shutil
+
+import pki.server.upgrade
+
+
+class FixDeploymentDescriptor(pki.server.upgrade.PKIServerUpgradeScriptlet):
+
+    def __init__(self):
+        super(FixDeploymentDescriptor, self).__init__()
+        self.message = 'Fix deployment descriptor'
+        self.parser = etree.XMLParser(remove_blank_text=True)
+
+    def upgrade_instance(self, instance):
+
+        self.fix_webapp(instance, 'ROOT.xml')
+        self.fix_webapp(instance, 'pki#admin.xml')
+        self.fix_webapp(instance, 'pki#js.xml')
+
+        self.fix_theme(instance, 'pki.xml')
+
+    def fix_webapp(self, instance, context_xml):
+
+        source_xml = pki.SHARE_DIR + '/server/conf/Catalina/localhost/' + context_xml
+        target_xml = instance.conf_dir + '/Catalina/localhost/' + context_xml
+
+        # if deployment descriptor doesn't exist, install the default
+        if not os.path.exists(target_xml):
+            self.copy_file(instance, source_xml, target_xml)
+            return
+
+        # get docBase from deployment descriptor
+        document = etree.parse(target_xml, self.parser)
+        context = document.getroot()
+        docBase = context.get('docBase')
+
+        # if docBase is absolute and pointing to non-empty folder, ignore
+        if docBase.startswith('/') and \
+                os.path.exists(docBase) and \
+                os.listdir(docBase):
+            return
+
+        # if docBase is relative and pointing to non-empty folder, ignore
+        if not docBase.startswith('/') and \
+                os.path.exists(instance.base_dir + '/webapps/' + docBase) and \
+                os.listdir(instance.base_dir + '/webapps/' + docBase):
+            return
+
+        # docBase is pointing to non-existent/empty folder, replace with default
+        self.copy_file(instance, source_xml, target_xml)
+
+    def fix_theme(self, instance, context_xml):
+
+        source_xml = pki.SHARE_DIR + '/server/conf/Catalina/localhost/' + context_xml
+        target_xml = instance.conf_dir + '/Catalina/localhost/' + context_xml
+
+        # if deployment descriptor doesn't exist, ignore (no theme)
+        if not os.path.exists(target_xml):
+            return
+
+        # get docBase from deployment descriptor
+        document = etree.parse(target_xml, self.parser)
+        context = document.getroot()
+        docBase = context.get('docBase')
+
+        # if docBase is absolute and pointing to non-empty folder, ignore
+        if docBase.startswith('/') and \
+                os.path.exists(docBase) and \
+                os.listdir(docBase):
+            return
+
+        # if docBase is relative and pointing to non-empty folder, ignore
+        if not docBase.startswith('/') and \
+                os.path.exists(instance.base_dir + '/webapps/' + docBase) and \
+                os.listdir(instance.base_dir + '/webapps/' + docBase):
+            return
+
+        # docBase is pointing to non-existent/empty folder
+
+        # if theme package is installed, replace deployment descriptor
+        if os.path.exists(pki.SHARE_DIR + '/common-ui'):
+            self.copy_file(instance, source_xml, target_xml)
+
+    def copy_file(self, instance, source, target):
+
+        self.backup(target)
+        shutil.copyfile(source, target)
+        os.chown(target, instance.uid, instance.gid)
-- 
2.7.4


From b4d5fcc5a30a11ed5e84ca835aea733a5d5bbfb6 Mon Sep 17 00:00:00 2001
From: Abhijeet Kasurde <akasurde@redhat.com>
Date: Wed, 10 Aug 2016 11:58:49 +0530
Subject: [PATCH 4/7] Added check for pki-server-nuxwdog parameter

Partially fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1353245

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit c79371fdc667e6acfcae7255f144e63cd60bf0f9)
---
 base/server/sbin/pki-server-nuxwdog | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/base/server/sbin/pki-server-nuxwdog b/base/server/sbin/pki-server-nuxwdog
index 31fff5e..ead9253 100755
--- a/base/server/sbin/pki-server-nuxwdog
+++ b/base/server/sbin/pki-server-nuxwdog
@@ -1,8 +1,18 @@
 #!/bin/sh
 
+if [ "$#" -ne 1 ]; then
+    echo "ERROR: $0 requires parameter"
+    exit 1
+fi
+
 . /etc/tomcat/tomcat.conf
 NAME=$1
-. /etc/sysconfig/$NAME
+if [ -f /etc/sysconfig/$NAME ]; then
+    . /etc/sysconfig/$NAME
+else
+    echo "ERROR: Unable to find /etc/sysconfig/$NAME file"
+    exit 1
+fi
 . /usr/libexec/tomcat/preamble
 
 NUXWDOG_PID=${CATALINA_BASE}/logs/wd-$NAME.pid
-- 
2.7.4


From 92b6378053ef427b3a73866dbee415f7ee32d5ae Mon Sep 17 00:00:00 2001
From: Geetika Kapoor <gkapoor@redhat.com>
Date: Fri, 12 Aug 2016 05:35:58 -0400
Subject: [PATCH 5/7] Fix for BZ 1358462

(cherry picked from commit 4b48187b744f1cff2a64c4c5eb00866875a1f99d)
---
 base/util/src/netscape/security/pkcs/PKCS12.java | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/base/util/src/netscape/security/pkcs/PKCS12.java b/base/util/src/netscape/security/pkcs/PKCS12.java
index 6c7880a..e05d4b5 100644
--- a/base/util/src/netscape/security/pkcs/PKCS12.java
+++ b/base/util/src/netscape/security/pkcs/PKCS12.java
@@ -192,10 +192,14 @@ public class PKCS12 {
         return result;
     }
 
-    public void removeCertInfoByNickname(String nickname) {
+    public void removeCertInfoByNickname(String nickname) throws Exception {
 
         Collection<PKCS12CertInfo> result = getCertInfosByNickname(nickname);
 
+        if (result.isEmpty()) {
+            throw new Exception("Certificate not found: " + nickname);
+        }
+
         for (PKCS12CertInfo certInfo : result) {
             // remove cert and key
             certInfosByID.remove(certInfo.getID());
-- 
2.7.4


From f4f62162f16da41a74328889bf2e0d17c223d48d Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Sun, 28 Aug 2016 20:38:48 +0200
Subject: [PATCH 6/7] Fixed default token name for system certificates.

Previously when installing with HSM the token name has to be
specified for each system certificate in the pki_<cert>_token
parameters. The deployment tool has been modified such that by
default it will use the token name specified in pki_token_name.

https://fedorahosted.org/pki/ticket/2423
(cherry picked from commit 389420ad4ea9994fb54132454a14abbb83c2c35d)
---
 base/server/etc/default.cfg                        | 16 +++++------
 .../python/pki/server/deployment/pkiparser.py      | 33 ++++++++++++++++++++--
 2 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/base/server/etc/default.cfg b/base/server/etc/default.cfg
index cfbd289..f759dba 100644
--- a/base/server/etc/default.cfg
+++ b/base/server/etc/default.cfg
@@ -78,7 +78,7 @@ pki_audit_signing_key_algorithm=SHA256withRSA
 pki_audit_signing_key_size=2048
 pki_audit_signing_key_type=rsa
 pki_audit_signing_signing_algorithm=SHA256withRSA
-pki_audit_signing_token=Internal Key Storage Token
+pki_audit_signing_token=
 pki_backup_keys=False
 pki_backup_password=
 pki_ca_hostname=%(pki_security_domain_hostname)s
@@ -125,13 +125,13 @@ pki_ssl_server_key_size=2048
 pki_ssl_server_key_type=rsa
 pki_ssl_server_nickname=Server-Cert cert-%(pki_instance_name)s
 pki_ssl_server_subject_dn=cn=%(pki_hostname)s,o=%(pki_security_domain_name)s
-pki_ssl_server_token=Internal Key Storage Token
+pki_ssl_server_token=
 pki_subsystem_key_algorithm=SHA256withRSA
 pki_subsystem_key_size=2048
 pki_subsystem_key_type=rsa
 pki_subsystem_nickname=subsystemCert cert-%(pki_instance_name)s
 pki_subsystem_subject_dn=cn=Subsystem Certificate,o=%(pki_security_domain_name)s
-pki_subsystem_token=Internal Key Storage Token
+pki_subsystem_token=
 pki_theme_enable=True
 pki_theme_server_dir=/usr/share/pki/common-ui
 pki_token_name=internal
@@ -293,7 +293,7 @@ pki_ca_signing_key_type=rsa
 pki_ca_signing_nickname=caSigningCert cert-%(pki_instance_name)s CA
 pki_ca_signing_signing_algorithm=SHA256withRSA
 pki_ca_signing_subject_dn=cn=CA Signing Certificate,o=%(pki_security_domain_name)s
-pki_ca_signing_token=Internal Key Storage Token
+pki_ca_signing_token=
 pki_ca_signing_csr_path=
 pki_ca_signing_cert_path=
 pki_ca_starting_crl_number=0
@@ -317,7 +317,7 @@ pki_ocsp_signing_key_type=rsa
 pki_ocsp_signing_nickname=ocspSigningCert cert-%(pki_instance_name)s CA
 pki_ocsp_signing_signing_algorithm=SHA256withRSA
 pki_ocsp_signing_subject_dn=cn=CA OCSP Signing Certificate,o=%(pki_security_domain_name)s
-pki_ocsp_signing_token=Internal Key Storage Token
+pki_ocsp_signing_token=
 pki_profiles_in_ldap=False
 pki_random_serial_numbers_enable=False
 pki_subordinate=False
@@ -405,14 +405,14 @@ pki_storage_key_type=rsa
 pki_storage_nickname=storageCert cert-%(pki_instance_name)s KRA
 pki_storage_signing_algorithm=SHA256withRSA
 pki_storage_subject_dn=cn=DRM Storage Certificate,o=%(pki_security_domain_name)s
-pki_storage_token=Internal Key Storage Token
+pki_storage_token=
 pki_transport_key_algorithm=SHA256withRSA
 pki_transport_key_size=2048
 pki_transport_key_type=rsa
 pki_transport_nickname=transportCert cert-%(pki_instance_name)s KRA
 pki_transport_signing_algorithm=SHA256withRSA
 pki_transport_subject_dn=cn=DRM Transport Certificate,o=%(pki_security_domain_name)s
-pki_transport_token=Internal Key Storage Token
+pki_transport_token=
 pki_admin_email=%(pki_admin_name)s@%(pki_dns_domainname)s
 pki_admin_name=%(pki_admin_uid)s
 pki_admin_nickname=PKI Administrator for %(pki_dns_domainname)s
@@ -474,7 +474,7 @@ pki_ocsp_signing_key_type=rsa
 pki_ocsp_signing_nickname=ocspSigningCert cert-%(pki_instance_name)s OCSP
 pki_ocsp_signing_signing_algorithm=SHA256withRSA
 pki_ocsp_signing_subject_dn=cn=OCSP Signing Certificate,o=%(pki_security_domain_name)s
-pki_ocsp_signing_token=Internal Key Storage Token
+pki_ocsp_signing_token=
 pki_admin_email=%(pki_admin_name)s@%(pki_dns_domainname)s
 pki_admin_name=%(pki_admin_uid)s
 pki_admin_nickname=PKI Administrator for %(pki_dns_domainname)s
diff --git a/base/server/python/pki/server/deployment/pkiparser.py b/base/server/python/pki/server/deployment/pkiparser.py
index 115f3ca..6e922cf 100644
--- a/base/server/python/pki/server/deployment/pkiparser.py
+++ b/base/server/python/pki/server/deployment/pkiparser.py
@@ -564,6 +564,24 @@ class PKIConfigParser:
         root = ET.fromstring(response)
         return root.findtext("Status")
 
+    def normalize_cert_token(self, name):
+
+        # get cert token
+        token = self.mdict.get(name)
+
+        # if not specified, get default token name
+        if not token:
+            token = self.mdict.get('pki_token_name')
+
+        # normalize internal token name
+        if not token or \
+                token.lower() == 'internal' or \
+                token.lower() == 'internal key storage token':
+            token = 'Internal Key Storage Token'
+
+        # update cert token
+        self.mdict[name] = token
+
     def compose_pki_master_dictionary(self):
         """
         Create a single master PKI dictionary from the
@@ -595,11 +613,11 @@ class PKIConfigParser:
             instance = pki.server.PKIInstance(self.mdict['pki_instance_name'])
             instance.load()
 
-            internal_password = self.mdict['pki_self_signed_token']
+            internal_token = self.mdict['pki_self_signed_token']
 
             # if instance already exists and has password, reuse the password
-            if internal_password in instance.passwords:
-                self.mdict['pki_pin'] = instance.passwords.get(internal_password)
+            if internal_token in instance.passwords:
+                self.mdict['pki_pin'] = instance.passwords.get(internal_token)
 
             # otherwise, use user-provided password if specified
             elif 'pki_pin' in self.mdict:
@@ -1207,6 +1225,15 @@ class PKIConfigParser:
                 # always normalize 'default' softokn name
                 self.mdict['pki_token_name'] = "internal"
 
+            # normalize cert tokens
+            self.normalize_cert_token('pki_audit_signing_token')
+            self.normalize_cert_token('pki_ssl_server_token')
+            self.normalize_cert_token('pki_subsystem_token')
+            self.normalize_cert_token('pki_ca_signing_token')
+            self.normalize_cert_token('pki_ocsp_signing_token')
+            self.normalize_cert_token('pki_storage_token')
+            self.normalize_cert_token('pki_transport_token')
+
             # if security domain user is not defined
             if not len(self.mdict['pki_security_domain_user']):
 
-- 
2.7.4


From 465bf002c0671e7251738ce9a4e54bba9853780a Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Sat, 27 Aug 2016 00:07:08 +0200
Subject: [PATCH 7/7] Moved subsystem initialization after database
 initialization.

Previously issues with system certificates that happen during
subsystem initialization were reported as database initialization
error. Database initialization actually does not depend on
subsystem initialization, so to avoid confusion and to simplify the
code the reInitSubsystem() in SystemConfigService is now invoked
after the initializeDatabase() is complete.

https://fedorahosted.org/pki/ticket/2423
(cherry picked from commit 9f954fda5fdeda229662a466e645561639ac8402)
---
 base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java b/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
index 95afa4c..9d7c176 100644
--- a/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
+++ b/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
@@ -178,6 +178,8 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
         }
         initializeDatabase(data);
 
+        ConfigurationUtils.reInitSubsystem(csType);
+
         configureCACertChain(data, domainXML);
 
         Collection<Cert> certs = new ArrayList<Cert>();
@@ -777,7 +779,6 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
                     ConfigurationUtils.setupReplication();
                 }
 
-                ConfigurationUtils.reInitSubsystem(csType);
                 ConfigurationUtils.populateDBManager();
                 ConfigurationUtils.populateVLVIndexes();
             }
-- 
2.7.4