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