From 1eb8b1632599fd62a9afbac8d3d4383d77f60aff Mon Sep 17 00:00:00 2001
From: Adam Williamson <awilliam@redhat.com>
Date: Wed, 3 May 2017 12:32:43 -0700
Subject: [PATCH] Handle curl using libnssckbi for TLS (RHBZ #1447777)

curl in Fedora recently changed its default CA trust store. The
Fedora package no longer specifies an OpenSSL-format bundle file
during build, and curl itself has been patched to use an NSS
plugin called libnssckbi.so when no bundle file or directory is
specified. There are (at present) two possible providers of the
libnssckbi.so module: the original NSS implementation, which
uses a trust bundle built in at build time, and a compatible
implementation from the p11-kit project, which reads a trust
bundle at run time. So if we find a string in libcurl.so that
suggests libnssckbi might be in use, we must both install it and
make an effort to install any trust bundle files it may use.

The p11-kit libnssckbi implementation does include a string that
lists the top-level trust directories it will use, so we try to
find that string, though the best effort I can come up with will
also find many false positives too. To weed out the false
positives, we check whether the matches actually exist as dirs,
and if so, whether they contain some specific subdirectories we
know p11-kit trust dirs must have (thanks, @kaie). For the NSS
libnssckbi implementation, we will likely wind up not finding any
dirs that match the requirements, so we will simply install the
libnssckbi.so file itself, which is the correct action.

This fixes TLS transactions in the initramfs environment when
using a curl that's built this new way; it's significant for
use of kickstarts and update images with the Fedora / RHEL
installer, as these are retrieved in the initramfs environment,
and are frequently retrieved via HTTPS.

(cherry picked from commit 892b1fe6b74a04e7901db306231136a430326ee3)
---
 modules.d/45url-lib/module-setup.sh | 38 +++++++++++++++++++++++++++++++++++--
 1 file changed, 36 insertions(+), 2 deletions(-)

diff --git a/modules.d/45url-lib/module-setup.sh b/modules.d/45url-lib/module-setup.sh
index 1ece400f..b3fe55a6 100755
--- a/modules.d/45url-lib/module-setup.sh
+++ b/modules.d/45url-lib/module-setup.sh
@@ -15,7 +15,7 @@ depends() {
 
 # called by dracut
 install() {
-    local _dir _crt _found _lib
+    local _dir _crt _found _lib _nssckbi _p11roots _p11root _p11item
     inst_simple "$moddir/url-lib.sh" "/lib/url-lib.sh"
     inst_multiple -o ctorrent
     inst_multiple curl
@@ -29,6 +29,7 @@ install() {
 	[[ -d $_dir ]] || continue
         for _lib in $_dir/libcurl.so.*; do
 	    [[ -e $_lib ]] || continue
+            [[ $_nssckbi ]] || _nssckbi=$(grep -F --binary-files=text -z libnssckbi $_lib)
             _crt=$(grep -F --binary-files=text -z .crt $_lib)
             [[ $_crt ]] || continue
             [[ $_crt == /*/* ]] || continue
@@ -39,6 +40,39 @@ install() {
             _found=1
         done
     done
-    [[ $_found ]] || dwarn "Couldn't find SSL CA cert bundle; HTTPS won't work."
+    # If we found no cert bundle files referenced in libcurl but we
+    # *did* find a mention of libnssckbi (checked above), install it.
+    # If its truly NSS libnssckbi, it includes its own trust bundle,
+    # but if it's really p11-kit-trust.so, we need to find the dirs
+    # where it will look for a trust bundle and install them too.
+    if ! [[ $_found ]] && [[ $_nssckbi ]] ; then
+        _found=1
+        inst_libdir_file "libnssckbi.so*" || _found=
+        for _dir in $libdirs; do
+            [[ -e $_dir/libnssckbi.so ]] || continue
+            # this looks for directory-ish strings in the file
+            for _p11roots in $(grep -o --binary-files=text "/[[:alpha:]][[:print:]]*" $_dir/libnssckbi.so) ; do
+                # the string can be a :-separated list of dirs
+                for _p11root in $(echo "$_p11roots" | tr ':' '\n') ; do
+                    # check if it's actually a directory (there are
+                    # several false positives in the results)
+                    [[ -d "$_p11root" ]] || continue
+                    # check if it has some specific subdirs that all
+                    # p11-kit trust dirs have
+                    [[ -d "${_p11root}/anchors" ]] || continue
+                    [[ -d "${_p11root}/blacklist" ]] || continue
+                    # so now we know it's really a p11-kit trust dir;
+                    # install everything in it
+                    for _p11item in $(find "$_p11root") ; do
+                        if ! inst "$_p11item" ; then
+                            dwarn "Couldn't install '$_p11item' from p11-kit trust dir '$_p11root'; HTTPS might not work."
+                            continue
+                        fi
+                    done
+                done
+            done
+        done
+    fi
+    [[ $_found ]] || dwarn "Couldn't find SSL CA cert bundle or libnssckbi.so; HTTPS won't work."
 }
 
