Browse Source

Issue 51042 - try to use both c_rehash and openssl rehash

Bug Description:
    It's not possible to fully migrate to openssl rehash, since it is
    not available everywhere. And versions of openssl which don't have
    rehash, also cannot check if rehash is available, or try running it
    at all as a fallback, because the return value is meaningless.

Fix Description:
    Add a utility function that checks the openssl version and parses it
    into a LegacyVersion class. `openssl version` should work
    everywhere, despite being unfriendly to parse. On versions of
    openssl >= 1.1.0a (LegacyVersion also considers 1.1.0 > 1.1.0a), use
    openssl rehash, otherwise fall back to c_rehash.

Fixes https://pagure.io/389-ds-base/issue/51042

Author: eschwartz
Eli Schwartz 5 years ago
parent
commit
151a96785d

+ 2 - 0
rpm/389-ds-base.spec.in

@@ -289,6 +289,8 @@ BuildArch:        noarch
 Group:            Development/Libraries
 Requires: krb5-workstation
 Requires: openssl
+# This is for /usr/bin/c_rehash tool, only needed for openssl < 1.1.0
+Requires: openssl-perl
 Requires: iproute
 Requires: python%{python3_pkgversion}
 Requires: python%{python3_pkgversion}-distro

+ 4 - 0
src/lib389/lib389/cli_idm/client_config.py

@@ -40,6 +40,8 @@ ldap_uri = {ldap_uri}
 ldap_tls_reqcert = demand
 # To use cacert dir, place *.crt files in this path then run:
 # /usr/bin/openssl rehash /etc/openldap/certs
+# or (for older versions of openssl)
+# /usr/bin/c_rehash /etc/openldap/certs
 ldap_tls_cacertdir = /etc/openldap/certs
 
 # Path to the cacert
@@ -124,6 +126,8 @@ URI     {ldap_uri}
 DEREF   never
 # To use cacert dir, place *.crt files in this path then run:
 # /usr/bin/openssl rehash /etc/openldap/certs
+# or (for older versions of openssl)
+# /usr/bin/c_rehash /etc/openldap/certs
 TLS_CACERTDIR /etc/openldap/certs
 # TLS_CACERT /etc/openldap/certs/ca.crt
 

+ 28 - 9
src/lib389/lib389/nss_ssl.py

@@ -25,6 +25,13 @@ from lib389.lint import DSCERTLE0001, DSCERTLE0002
 from lib389.utils import ensure_str, format_cmd_list
 import uuid
 
+# Setuptools ships with 'packaging' module, let's use it from there
+try:
+    from pkg_resources.extern.packaging.version import LegacyVersion
+# Fallback to a normal 'packaging' module in case 'setuptools' is stripped
+except:
+    from packaging.version import LegacyVersion
+
 KEYBITS = 4096
 CA_NAME = 'Self-Signed-CA'
 CERT_NAME = 'Server-Cert'
@@ -218,6 +225,24 @@ only.
         assert not self._db_exists()
         return True
 
+    def openssl_rehash(self, certdir):
+        """
+        Compatibly run c_rehash (on old openssl versions) or openssl rehash (on
+        new ones). Prefers openssl rehash, because openssl on versions where
+        the rehash command doesn't exist, also doesn't correctly set the return
+        code. Instead, we parse the output of `openssl version` and try to
+        figure out if we have a new enough version to unconditionally run rehash.
+        """
+        openssl_version = check_output(['/usr/bin/openssl', 'version']).decode('utf-8').strip()
+        rehash_available = LegacyVersion(openssl_version.split(' ')[1]) >= LegacyVersion('1.1.0')
+
+        if rehash_available:
+            cmd = ['/usr/bin/openssl', 'rehash', certdir]
+        else:
+            cmd = ['/usr/bin/c_rehash', certdir]
+        self.log.debug("nss cmd: %s", format_cmd_list(cmd))
+        check_output(cmd, stderr=subprocess.STDOUT)
+
     def create_rsa_ca(self, months=VALID):
         """
         Create a self signed CA.
@@ -271,9 +296,7 @@ only.
         certdetails = check_output(cmd, stderr=subprocess.STDOUT)
         with open('%s/ca.crt' % self._certdb, 'w') as f:
             f.write(ensure_str(certdetails))
-        cmd = ['/usr/bin/openssl', 'rehash', self._certdb]
-        self.log.debug("nss cmd: %s", format_cmd_list(cmd))
-        check_output(cmd, stderr=subprocess.STDOUT)
+        self.openssl_rehash(self._certdb)
         return True
 
     def rsa_ca_needs_renew(self):
@@ -353,9 +376,7 @@ only.
         self.log.debug("nss cmd: %s", format_cmd_list(cmd))
         check_output(cmd, stderr=subprocess.STDOUT)
 
-        cmd = ['/usr/bin/openssl', 'rehash', self._certdb]
-        self.log.debug("nss cmd: %s", format_cmd_list(cmd))
-        check_output(cmd, stderr=subprocess.STDOUT)
+        self.openssl_rehash(self._certdb)
 
         # Import the new CA to our DB instead of the old CA
         cmd = [
@@ -611,9 +632,7 @@ only.
 
         if ca is not None:
             shutil.copyfile(ca, '%s/ca.crt' % self._certdb)
-            cmd = ['/usr/bin/openssl', 'rehash', self._certdb]
-            self.log.debug("nss cmd: %s", format_cmd_list(cmd))
-            check_output(cmd, stderr=subprocess.STDOUT)
+            self.openssl_rehash(self._certdb)
             cmd = [
                 '/usr/bin/certutil',
                 '-A',