1ccdcb388SKyle Evans#!/bin/sh 2ccdcb388SKyle Evans#- 3ccdcb388SKyle Evans# SPDX-License-Identifier: BSD-2-Clause-FreeBSD 4ccdcb388SKyle Evans# 5ccdcb388SKyle Evans# Copyright 2018 Allan Jude <allanjude@freebsd.org> 6ccdcb388SKyle Evans# 7ccdcb388SKyle Evans# Redistribution and use in source and binary forms, with or without 8ccdcb388SKyle Evans# modification, are permitted providing that the following conditions 9ccdcb388SKyle Evans# are met: 10ccdcb388SKyle Evans# 1. Redistributions of source code must retain the above copyright 11ccdcb388SKyle Evans# notice, this list of conditions and the following disclaimer. 12ccdcb388SKyle Evans# 2. Redistributions in binary form must reproduce the above copyright 13ccdcb388SKyle Evans# notice, this list of conditions and the following disclaimer in the 14ccdcb388SKyle Evans# documentation and/or other materials provided with the distribution. 15ccdcb388SKyle Evans# 16ccdcb388SKyle Evans# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17ccdcb388SKyle Evans# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18ccdcb388SKyle Evans# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19ccdcb388SKyle Evans# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20ccdcb388SKyle Evans# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21ccdcb388SKyle Evans# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22ccdcb388SKyle Evans# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23ccdcb388SKyle Evans# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24ccdcb388SKyle Evans# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25ccdcb388SKyle Evans# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26ccdcb388SKyle Evans# POSSIBILITY OF SUCH DAMAGE. 27ccdcb388SKyle Evans# 28ccdcb388SKyle Evans# $FreeBSD$ 29ccdcb388SKyle Evans 30ccdcb388SKyle Evans############################################################ CONFIGURATION 31ccdcb388SKyle Evans 32ccdcb388SKyle Evans: ${DESTDIR:=} 33ccdcb388SKyle Evans: ${TRUSTPATH:=${DESTDIR}/usr/share/certs/trusted:${DESTDIR}/usr/local/share/certs:${DESTDIR}/usr/local/etc/ssl/certs} 34ccdcb388SKyle Evans: ${BLACKLISTPATH:=${DESTDIR}/usr/share/certs/blacklisted:${DESTDIR}/usr/local/etc/ssl/blacklisted} 35ccdcb388SKyle Evans: ${CERTDESTDIR:=${DESTDIR}/etc/ssl/certs} 36ccdcb388SKyle Evans: ${BLACKLISTDESTDIR:=${DESTDIR}/etc/ssl/blacklisted} 37ccdcb388SKyle Evans: ${EXTENSIONS:="*.pem *.crt *.cer *.crl *.0"} 38ccdcb388SKyle Evans: ${VERBOSE:=0} 39ccdcb388SKyle Evans 40ccdcb388SKyle Evans############################################################ GLOBALS 41ccdcb388SKyle Evans 42ccdcb388SKyle EvansSCRIPTNAME="${0##*/}" 43ccdcb388SKyle EvansERRORS=0 44ccdcb388SKyle EvansNOOP=0 45ccdcb388SKyle Evans 46ccdcb388SKyle Evans############################################################ FUNCTIONS 47ccdcb388SKyle Evans 48ccdcb388SKyle Evansdo_hash() 49ccdcb388SKyle Evans{ 50ccdcb388SKyle Evans local hash 51ccdcb388SKyle Evans 52ccdcb388SKyle Evans if hash=$( openssl x509 -noout -subject_hash -in "$1" ); then 53ccdcb388SKyle Evans echo "$hash" 54ccdcb388SKyle Evans return 0 55ccdcb388SKyle Evans else 56ccdcb388SKyle Evans echo "Error: $1" >&2 57ccdcb388SKyle Evans ERRORS=$(( $ERRORS + 1 )) 58ccdcb388SKyle Evans return 1 59ccdcb388SKyle Evans fi 60ccdcb388SKyle Evans} 61ccdcb388SKyle Evans 62ccdcb388SKyle Evanscreate_trusted_link() 63ccdcb388SKyle Evans{ 64ccdcb388SKyle Evans local hash 65ccdcb388SKyle Evans 66ccdcb388SKyle Evans hash=$( do_hash "$1" ) || return 67ccdcb388SKyle Evans if [ -e "$BLACKLISTDESTDIR/$hash.0" ]; then 68ccdcb388SKyle Evans echo "Skipping blacklisted certificate $1 ($BLACKLISTDESTDIR/$hash.0)" 69ccdcb388SKyle Evans return 1 70ccdcb388SKyle Evans fi 71ccdcb388SKyle Evans [ $VERBOSE -gt 0 ] && echo "Adding $hash.0 to trust store" 72946966d1SKyle Evans [ $NOOP -eq 0 ] && install -lrs $(realpath "$1") "$CERTDESTDIR/$hash.0" 73ccdcb388SKyle Evans} 74ccdcb388SKyle Evans 75ccdcb388SKyle Evanscreate_blacklisted() 76ccdcb388SKyle Evans{ 7794a5245cSKyle Evans local hash srcfile filename 78ccdcb388SKyle Evans 7994a5245cSKyle Evans # If it exists as a file, we'll try that; otherwise, we'll scan 8094a5245cSKyle Evans if [ -e "$1" ]; then 81ccdcb388SKyle Evans hash=$( do_hash "$1" ) || return 8294a5245cSKyle Evans srcfile=$(realpath "$1") 8394a5245cSKyle Evans filename="$hash.0" 8494a5245cSKyle Evans elif [ -e "${CERTDESTDIR}/$1" ]; then 8594a5245cSKyle Evans srcfile=$(realpath "${CERTDESTDIR}/$1") 8694a5245cSKyle Evans filename="$1" 8794a5245cSKyle Evans else 8894a5245cSKyle Evans return 8994a5245cSKyle Evans fi 9094a5245cSKyle Evans [ $VERBOSE -gt 0 ] && echo "Adding $filename to blacklist" 91946966d1SKyle Evans [ $NOOP -eq 0 ] && install -lrs "$srcfile" "$BLACKLISTDESTDIR/$filename" 92ccdcb388SKyle Evans} 93ccdcb388SKyle Evans 94ccdcb388SKyle Evansdo_scan() 95ccdcb388SKyle Evans{ 96ccdcb388SKyle Evans local CFUNC CSEARCH CPATH CFILE 97ccdcb388SKyle Evans local oldIFS="$IFS" 98ccdcb388SKyle Evans CFUNC="$1" 99ccdcb388SKyle Evans CSEARCH="$2" 100ccdcb388SKyle Evans 101ccdcb388SKyle Evans IFS=: 102ccdcb388SKyle Evans set -- $CSEARCH 103ccdcb388SKyle Evans IFS="$oldIFS" 104ccdcb388SKyle Evans for CPATH in "$@"; do 105ccdcb388SKyle Evans [ -d "$CPATH" ] || continue 106ccdcb388SKyle Evans echo "Scanning $CPATH for certificates..." 107ccdcb388SKyle Evans cd "$CPATH" 108ccdcb388SKyle Evans for CFILE in $EXTENSIONS; do 109ccdcb388SKyle Evans [ -e "$CFILE" ] || continue 110ccdcb388SKyle Evans [ $VERBOSE -gt 0 ] && echo "Reading $CFILE" 111ccdcb388SKyle Evans "$CFUNC" "$CPATH/$CFILE" 112ccdcb388SKyle Evans done 113ccdcb388SKyle Evans cd - 114ccdcb388SKyle Evans done 115ccdcb388SKyle Evans} 116ccdcb388SKyle Evans 117ccdcb388SKyle Evansdo_list() 118ccdcb388SKyle Evans{ 119ccdcb388SKyle Evans local CFILE subject 120ccdcb388SKyle Evans 121ccdcb388SKyle Evans if [ -e "$1" ]; then 122ccdcb388SKyle Evans cd "$1" 123ccdcb388SKyle Evans for CFILE in *.0; do 124ccdcb388SKyle Evans if [ ! -s "$CFILE" ]; then 125ccdcb388SKyle Evans echo "Unable to read $CFILE" >&2 126ccdcb388SKyle Evans ERRORS=$(( $ERRORS + 1 )) 127ccdcb388SKyle Evans continue 128ccdcb388SKyle Evans fi 129ccdcb388SKyle Evans subject= 130ccdcb388SKyle Evans if [ $VERBOSE -eq 0 ]; then 131ccdcb388SKyle Evans subject=$( openssl x509 -noout -subject -nameopt multiline -in "$CFILE" | 132ccdcb388SKyle Evans sed -n '/commonName/s/.*= //p' ) 133ccdcb388SKyle Evans fi 134ccdcb388SKyle Evans [ "$subject" ] || 135ccdcb388SKyle Evans subject=$( openssl x509 -noout -subject -in "$CFILE" ) 136ccdcb388SKyle Evans printf "%s\t%s\n" "$CFILE" "$subject" 137ccdcb388SKyle Evans done 138ccdcb388SKyle Evans cd - 139ccdcb388SKyle Evans fi 140ccdcb388SKyle Evans} 141ccdcb388SKyle Evans 142ccdcb388SKyle Evanscmd_rehash() 143ccdcb388SKyle Evans{ 144ccdcb388SKyle Evans 145bb33c910SKyle Evans if [ $NOOP -eq 0 ]; then 146*5e6c628eSKyle Evans if [ -e "$CERTDESTDIR" ]; then 147*5e6c628eSKyle Evans find "$CERTDESTDIR" -type link -delete 148*5e6c628eSKyle Evans else 149bb33c910SKyle Evans mkdir -p "$CERTDESTDIR" 150*5e6c628eSKyle Evans fi 151*5e6c628eSKyle Evans if [ -e "$BLACKLISTDESTDIR" ]; then 152*5e6c628eSKyle Evans find "$BLACKLISTDESTDIR" -type link -delete 153*5e6c628eSKyle Evans else 154bb33c910SKyle Evans mkdir -p "$BLACKLISTDESTDIR" 155bb33c910SKyle Evans fi 156*5e6c628eSKyle Evans fi 157ccdcb388SKyle Evans 158ccdcb388SKyle Evans do_scan create_blacklisted "$BLACKLISTPATH" 159ccdcb388SKyle Evans do_scan create_trusted_link "$TRUSTPATH" 160ccdcb388SKyle Evans} 161ccdcb388SKyle Evans 162ccdcb388SKyle Evanscmd_list() 163ccdcb388SKyle Evans{ 164ccdcb388SKyle Evans echo "Listing Trusted Certificates:" 165ccdcb388SKyle Evans do_list "$CERTDESTDIR" 166ccdcb388SKyle Evans} 167ccdcb388SKyle Evans 168ccdcb388SKyle Evanscmd_blacklist() 169ccdcb388SKyle Evans{ 170ccdcb388SKyle Evans local BPATH 171ccdcb388SKyle Evans 172ccdcb388SKyle Evans shift # verb 173ccdcb388SKyle Evans [ $NOOP -eq 0 ] && mkdir -p "$BLACKLISTDESTDIR" 174ccdcb388SKyle Evans for BFILE in "$@"; do 175ccdcb388SKyle Evans echo "Adding $BFILE to blacklist" 176ccdcb388SKyle Evans create_blacklisted "$BFILE" 177ccdcb388SKyle Evans done 178ccdcb388SKyle Evans} 179ccdcb388SKyle Evans 180ccdcb388SKyle Evanscmd_unblacklist() 181ccdcb388SKyle Evans{ 182ccdcb388SKyle Evans local BFILE hash 183ccdcb388SKyle Evans 184ccdcb388SKyle Evans shift # verb 185ccdcb388SKyle Evans for BFILE in "$@"; do 186ccdcb388SKyle Evans if [ -s "$BFILE" ]; then 187ccdcb388SKyle Evans hash=$( do_hash "$BFILE" ) 188ccdcb388SKyle Evans echo "Removing $hash.0 from blacklist" 189ccdcb388SKyle Evans [ $NOOP -eq 0 ] && rm -f "$BLACKLISTDESTDIR/$hash.0" 190ccdcb388SKyle Evans elif [ -e "$BLACKLISTDESTDIR/$BFILE" ]; then 191ccdcb388SKyle Evans echo "Removing $BFILE from blacklist" 192ccdcb388SKyle Evans [ $NOOP -eq 0 ] && rm -f "$BLACKLISTDESTDIR/$BFILE" 193ccdcb388SKyle Evans else 194ccdcb388SKyle Evans echo "Cannot find $BFILE" >&2 195ccdcb388SKyle Evans ERRORS=$(( $ERRORS + 1 )) 196ccdcb388SKyle Evans fi 197ccdcb388SKyle Evans done 198ccdcb388SKyle Evans} 199ccdcb388SKyle Evans 200ccdcb388SKyle Evanscmd_blacklisted() 201ccdcb388SKyle Evans{ 202ccdcb388SKyle Evans echo "Listing Blacklisted Certificates:" 203ccdcb388SKyle Evans do_list "$BLACKLISTDESTDIR" 204ccdcb388SKyle Evans} 205ccdcb388SKyle Evans 206ccdcb388SKyle Evansusage() 207ccdcb388SKyle Evans{ 208ccdcb388SKyle Evans exec >&2 209ccdcb388SKyle Evans echo "Manage the TLS trusted certificates on the system" 210ccdcb388SKyle Evans echo " $SCRIPTNAME [-v] list" 211ccdcb388SKyle Evans echo " List trusted certificates" 212ccdcb388SKyle Evans echo " $SCRIPTNAME [-v] blacklisted" 213ccdcb388SKyle Evans echo " List blacklisted certificates" 214ccdcb388SKyle Evans echo " $SCRIPTNAME [-nv] rehash" 215ccdcb388SKyle Evans echo " Generate hash links for all certificates" 216ccdcb388SKyle Evans echo " $SCRIPTNAME [-nv] blacklist <file>" 217ccdcb388SKyle Evans echo " Add <file> to the list of blacklisted certificates" 218ccdcb388SKyle Evans echo " $SCRIPTNAME [-nv] unblacklist <file>" 219ccdcb388SKyle Evans echo " Remove <file> from the list of blacklisted certificates" 220ccdcb388SKyle Evans exit 64 221ccdcb388SKyle Evans} 222ccdcb388SKyle Evans 223ccdcb388SKyle Evans############################################################ MAIN 224ccdcb388SKyle Evans 225ccdcb388SKyle Evanswhile getopts nv flag; do 226ccdcb388SKyle Evans case "$flag" in 227ccdcb388SKyle Evans n) NOOP=1 ;; 228ccdcb388SKyle Evans v) VERBOSE=$(( $VERBOSE + 1 )) ;; 229ccdcb388SKyle Evans esac 230ccdcb388SKyle Evansdone 231ccdcb388SKyle Evansshift $(( $OPTIND - 1 )) 232ccdcb388SKyle Evans 233ccdcb388SKyle Evans[ $# -gt 0 ] || usage 234ccdcb388SKyle Evanscase "$1" in 235ccdcb388SKyle Evanslist) cmd_list ;; 236ccdcb388SKyle Evansrehash) cmd_rehash ;; 237ccdcb388SKyle Evansblacklist) cmd_blacklist "$@" ;; 238ccdcb388SKyle Evansunblacklist) cmd_unblacklist "$@" ;; 239ccdcb388SKyle Evansblacklisted) cmd_blacklisted ;; 240ccdcb388SKyle Evans*) usage # NOTREACHED 241ccdcb388SKyle Evansesac 242ccdcb388SKyle Evans 243ccdcb388SKyle Evansretval=$? 244ccdcb388SKyle Evans[ $ERRORS -gt 0 ] && echo "Encountered $ERRORS errors" >&2 245ccdcb388SKyle Evansexit $retval 246ccdcb388SKyle Evans 247ccdcb388SKyle Evans################################################################################ 248ccdcb388SKyle Evans# END 249ccdcb388SKyle Evans################################################################################ 250