certctl: fix hashed link generation with duplicate subjects

Currently, certctl rehash will just keep clobbering .0 rather than
incrementing the suffix upon encountering a duplicate. Do this, and do it
for blacklisted certs as well.

This also improves the situation with the blacklist to be a little less
flakey, comparing cert fingerprints for all certs with a matching subject
hash in the blacklist to determine if the cert we're looking at can be
installed.

Future work needs to completely revamp the blacklist to align more with how
it's described in PR 246614. In particular, /etc/ssl/blacklisted should go
away to avoid potential confusion -- OpenSSL will not read it, it's
basically certctl internal.

PR:		246614
Reviewed by:	Michael Osipov <michael.osipov siemens com>
Tested by:	Michael Osipov
With suggestions from:	Michael Osipov
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D26167
This commit is contained in:
Kyle Evans 2020-09-09 09:08:09 +00:00
parent 110d525ec6
commit 05a16147fb
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=365500

View File

@ -30,7 +30,7 @@
############################################################ CONFIGURATION
: ${DESTDIR:=}
: ${FILEPAT:="\.pem$|\.crt$|\.cer$|\.crl$|\.0$"}
: ${FILEPAT:="\.pem$|\.crt$|\.cer$|\.crl$"}
: ${VERBOSE:=0}
############################################################ GLOBALS
@ -56,31 +56,58 @@ do_hash()
fi
}
get_decimal()
{
local checkdir hash decimal
checkdir=$1
hash=$2
decimal=0
while [ -e "$checkdir/$hash.$decimal" ]; do
decimal=$((decimal + 1))
done
echo ${decimal}
return 0
}
create_trusted_link()
{
local hash
local blisthash certhash hash
local suffix
hash=$( do_hash "$1" ) || return
if [ -e "$BLACKLISTDESTDIR/$hash.0" ]; then
echo "Skipping blacklisted certificate $1 ($BLACKLISTDESTDIR/$hash.0)"
return 1
fi
[ $VERBOSE -gt 0 ] && echo "Adding $hash.0 to trust store"
[ $NOOP -eq 0 ] && install ${INSTALLFLAGS} -lrs $(realpath "$1") "$CERTDESTDIR/$hash.0"
certhash=$( openssl x509 -sha1 -in "$1" -noout -fingerprint )
for blistfile in $(find $BLACKLISTDESTDIR -name "$hash.*"); do
blisthash=$( openssl x509 -sha1 -in "$blistfile" -noout -fingerprint )
if [ "$certhash" = "$blisthash" ]; then
echo "Skipping blacklisted certificate $1 ($blistfile)"
return 1
fi
done
suffix=$(get_decimal "$CERTDESTDIR" "$hash")
[ $VERBOSE -gt 0 ] && echo "Adding $hash.$suffix to trust store"
[ $NOOP -eq 0 ] && \
install ${INSTALLFLAGS} -lrs $(realpath "$1") "$CERTDESTDIR/$hash.$suffix"
}
create_blacklisted()
{
local hash srcfile filename
local suffix
# If it exists as a file, we'll try that; otherwise, we'll scan
if [ -e "$1" ]; then
hash=$( do_hash "$1" ) || return
srcfile=$(realpath "$1")
filename="$hash.0"
suffix=$(get_decimal "$BLACKLISTDESTDIR" "$hash")
filename="$hash.$suffix"
elif [ -e "${CERTDESTDIR}/$1" ]; then
srcfile=$(realpath "${CERTDESTDIR}/$1")
filename="$1"
hash=$(echo "$1" | sed -Ee 's/\.([0-9])+$//')
suffix=$(get_decimal "$BLACKLISTDESTDIR" "$hash")
filename="$hash.$suffix"
else
return
fi
@ -115,7 +142,7 @@ do_list()
if [ -e "$1" ]; then
cd "$1"
for CFILE in *.0; do
for CFILE in *.[0-9]; do
if [ ! -s "$CFILE" ]; then
echo "Unable to read $CFILE" >&2
ERRORS=$(( $ERRORS + 1 ))
@ -174,14 +201,20 @@ cmd_blacklist()
cmd_unblacklist()
{
local BFILE hash
local BFILE blisthash certhash hash
shift # verb
for BFILE in "$@"; do
if [ -s "$BFILE" ]; then
hash=$( do_hash "$BFILE" )
echo "Removing $hash.0 from blacklist"
[ $NOOP -eq 0 ] && rm -f "$BLACKLISTDESTDIR/$hash.0"
certhash=$( openssl x509 -sha1 -in "$BFILE" -noout -fingerprint )
for BLISTEDFILE in $(find $BLACKLISTDESTDIR -name "$hash.*"); do
blisthash=$( openssl x509 -sha1 -in "$BLISTEDFILE" -noout -fingerprint )
if [ "$certhash" = "$blisthash" ]; then
echo "Removing $(basename "$BLISTEDFILE") from blacklist"
[ $NOOP -eq 0 ] && rm -f $BLISTEDFILE
fi
done
elif [ -e "$BLACKLISTDESTDIR/$BFILE" ]; then
echo "Removing $BFILE from blacklist"
[ $NOOP -eq 0 ] && rm -f "$BLACKLISTDESTDIR/$BFILE"