mirror of
https://github.com/opnsense/src.git
synced 2026-06-11 09:41:03 -04:00
Revert certctl reimplementation and follow-ups
The reimplementation of certctl, while much needed, broke the release build and 72 hours later corrections are still under review (D51896). This revert should be reverted once that is ready to land; I just need this out of the tree temporarily because breakage is interfering with release engineering for the upcoming 15.0-RELEASE. Unsquashed reversions: Revert "etc: add missing mtree entry for certctl tests" This reverts commitf751757259. Revert "certctl: Fix bootstrap build" This reverts commitc989e3cc3d. Revert "certctl: Reimplement in C" This reverts commit81d8827ad8. With hat: re@
This commit is contained in:
parent
939fec44a7
commit
31ac42b486
9 changed files with 414 additions and 1415 deletions
|
|
@ -1021,7 +1021,8 @@ IMAKE_MTREE= MTREE_CMD="${MTREE_CMD} ${MTREEFLAGS}"
|
|||
.endif
|
||||
|
||||
.if make(distributeworld)
|
||||
CERTCTLDESTDIR= ${DESTDIR}/${DISTDIR}/base
|
||||
CERTCTLDESTDIR= ${DESTDIR}/${DISTDIR}
|
||||
CERTCTLFLAGS+= -d /base
|
||||
.else
|
||||
CERTCTLDESTDIR= ${DESTDIR}
|
||||
.endif
|
||||
|
|
@ -1541,10 +1542,14 @@ distributeworld installworld stageworld: _installcheck_world .PHONY
|
|||
.endif # make(distributeworld)
|
||||
${_+_}cd ${.CURDIR}; ${IMAKE} re${.TARGET:S/world$//}; \
|
||||
${IMAKEENV} rm -rf ${INSTALLTMP}
|
||||
.if !make(packageworld) && ${MK_CAROOT} != "no" && ${MK_OPENSSL} != "no"
|
||||
PATH=${TMPPATH:Q}:${PATH:Q} \
|
||||
LOCALBASE=${LOCALBASE:Q} \
|
||||
certctl ${CERTCTLFLAGS} rehash
|
||||
.if !make(packageworld) && ${MK_CAROOT} != "no"
|
||||
@if which openssl>/dev/null; then \
|
||||
PATH=${TMPPATH:Q}:${PATH:Q} \
|
||||
LOCALBASE=${LOCALBASE:Q} \
|
||||
sh ${SRCTOP}/usr.sbin/certctl/certctl.sh ${CERTCTLFLAGS} rehash; \
|
||||
else \
|
||||
echo "No openssl on the host, not rehashing certificates target -- /etc/ssl may not be populated."; \
|
||||
fi
|
||||
.endif
|
||||
.if make(distributeworld)
|
||||
.for dist in ${EXTRA_DISTRIBUTIONS}
|
||||
|
|
@ -2708,11 +2713,6 @@ _basic_bootstrap_tools+=sbin/md5
|
|||
_basic_bootstrap_tools+=usr.sbin/tzsetup
|
||||
.endif
|
||||
|
||||
# certctl is needed as an install tool
|
||||
.if ${MK_CAROOT} != "no" && ${MK_OPENSSL} != "no"
|
||||
_certctl=usr.sbin/certctl
|
||||
.endif
|
||||
|
||||
.if defined(BOOTSTRAP_ALL_TOOLS)
|
||||
_other_bootstrap_tools+=${_basic_bootstrap_tools}
|
||||
.for _subdir _links in ${_basic_bootstrap_tools_multilink}
|
||||
|
|
@ -2776,7 +2776,6 @@ bootstrap-tools: ${_bt}-links .PHONY
|
|||
${_strfile} \
|
||||
usr.bin/dtc \
|
||||
${_cat} \
|
||||
${_certctl} \
|
||||
${_kbdcontrol} \
|
||||
${_elftoolchain_libs} \
|
||||
${_libkldelf} \
|
||||
|
|
|
|||
|
|
@ -1255,8 +1255,6 @@
|
|||
..
|
||||
..
|
||||
usr.sbin
|
||||
certctl
|
||||
..
|
||||
chown
|
||||
..
|
||||
ctladm
|
||||
|
|
|
|||
|
|
@ -1,14 +1,5 @@
|
|||
.include <src.opts.mk>
|
||||
|
||||
PACKAGE= certctl
|
||||
PROG= certctl
|
||||
SCRIPTS=certctl.sh
|
||||
MAN= certctl.8
|
||||
LIBADD= crypto
|
||||
HAS_TESTS=
|
||||
SUBDIR.${MK_TESTS}= tests
|
||||
|
||||
.ifdef BOOTSTRAPPING
|
||||
CFLAGS+=-DBOOTSTRAPPING
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd August 11, 2025
|
||||
.Dd July 17, 2025
|
||||
.Dt CERTCTL 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
|
@ -32,83 +32,63 @@
|
|||
.Nd "tool for managing trusted and untrusted TLS certificates"
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl lv
|
||||
.Op Fl v
|
||||
.Ic list
|
||||
.Nm
|
||||
.Op Fl lv
|
||||
.Op Fl v
|
||||
.Ic untrusted
|
||||
.Nm
|
||||
.Op Fl BnUv
|
||||
.Op Fl cnUv
|
||||
.Op Fl D Ar destdir
|
||||
.Op Fl M Ar metalog
|
||||
.Ic rehash
|
||||
.Nm
|
||||
.Op Fl nv
|
||||
.Ic untrust Ar
|
||||
.Op Fl cnv
|
||||
.Ic untrust Ar file
|
||||
.Nm
|
||||
.Op Fl nv
|
||||
.Ic trust Ar
|
||||
.Op Fl cnv
|
||||
.Ic trust Ar file
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility manages the list of TLS Certificate Authorities that are trusted by
|
||||
applications that use OpenSSL.
|
||||
.Pp
|
||||
The following options are available:
|
||||
Flags:
|
||||
.Bl -tag -width 4n
|
||||
.It Fl B
|
||||
Do not generate a bundle.
|
||||
This option is only valid in conjunction with the
|
||||
.Ic rehash
|
||||
command.
|
||||
.It Fl c
|
||||
Copy certificates instead of linking to them.
|
||||
.It Fl D Ar destdir
|
||||
Specify the DESTDIR (overriding values from the environment).
|
||||
.It Fl l
|
||||
When listing installed (trusted or untrusted) certificates, show the
|
||||
full path and distinguished name for each certificate.
|
||||
.It Fl d Ar distbase
|
||||
Specify the DISTBASE (overriding values from the environment).
|
||||
.It Fl M Ar metalog
|
||||
Specify the path of the METALOG file
|
||||
.Po
|
||||
default:
|
||||
.Pa ${DESTDIR}/METALOG
|
||||
.Pc .
|
||||
This option is only valid in conjunction with the
|
||||
.Ic rehash
|
||||
command.
|
||||
Specify the path of the METALOG file (default: $DESTDIR/METALOG).
|
||||
.It Fl n
|
||||
Dry-run mode.
|
||||
Do not actually perform any actions except write the metalog.
|
||||
No-Op mode, do not actually perform any actions.
|
||||
.It Fl v
|
||||
Verbose mode.
|
||||
Print detailed information about each action taken.
|
||||
Be verbose, print details about actions before performing them.
|
||||
.It Fl U
|
||||
Unprivileged mode.
|
||||
Do not attempt to set the ownership of created files.
|
||||
This option is only valid in conjunction with the
|
||||
.Fl M
|
||||
option and the
|
||||
.Ic rehash
|
||||
command.
|
||||
Unprivileged mode, do not change the ownership of created links.
|
||||
Do record the ownership in the METALOG file.
|
||||
.El
|
||||
.Pp
|
||||
Primary command functions:
|
||||
.Bl -tag -width untrusted
|
||||
.It Ic list
|
||||
List all currently trusted certificates.
|
||||
List all currently trusted certificate authorities.
|
||||
.It Ic untrusted
|
||||
List all currently untrusted certificates.
|
||||
.It Ic rehash
|
||||
Rebuild the list of trusted certificates by scanning all directories
|
||||
Rebuild the list of trusted certificate authorities by scanning all directories
|
||||
in
|
||||
.Ev TRUSTPATH
|
||||
and all untrusted certificates in
|
||||
.Ev UNTRUSTPATH .
|
||||
A copy of each trusted certificate is placed in
|
||||
A symbolic link to each trusted certificate is placed in
|
||||
.Ev CERTDESTDIR
|
||||
and each untrusted certificate in
|
||||
.Ev UNTRUSTDESTDIR .
|
||||
In addition, a bundle containing the trusted certificates is placed in
|
||||
.Ev BUNDLEFILE .
|
||||
.It Ic untrust
|
||||
Add the specified file to the untrusted list.
|
||||
.It Ic trust
|
||||
|
|
@ -118,6 +98,8 @@ Remove the specified file from the untrusted list.
|
|||
.Bl -tag -width UNTRUSTDESTDIR
|
||||
.It Ev DESTDIR
|
||||
Alternate destination directory to operate on.
|
||||
.It Ev DISTBASE
|
||||
Additional path component to include when operating on certificate directories.
|
||||
.It Ev LOCALBASE
|
||||
Location for local programs.
|
||||
Defaults to the value of the user.localbase sysctl which is usually
|
||||
|
|
@ -125,34 +107,32 @@ Defaults to the value of the user.localbase sysctl which is usually
|
|||
.It Ev TRUSTPATH
|
||||
List of paths to search for trusted certificates.
|
||||
Default:
|
||||
.Pa ${DESTDIR}/usr/share/certs/trusted
|
||||
.Pa ${DESTDIR}${LOCALBASE}/share/certs/trusted
|
||||
.Pa ${DESTDIR}${LOCALBASE}/share/certs
|
||||
.Pa <DESTDIR><DISTBASE>/usr/share/certs/trusted
|
||||
.Pa <DESTDIR><DISTBASE>/usr/local/share/certs
|
||||
.Pa <DESTDIR><DISTBASE><LOCALBASE>/etc/ssl/certs
|
||||
.It Ev UNTRUSTPATH
|
||||
List of paths to search for untrusted certificates.
|
||||
Default:
|
||||
.Pa ${DESTDIR}/usr/share/certs/untrusted
|
||||
.Pa ${DESTDIR}${LOCALBASE}/share/certs/untrusted
|
||||
.It Ev TRUSTDESTDIR
|
||||
.Pa <DESTDIR><DISTBASE>/usr/share/certs/untrusted
|
||||
.Pa <DESTDIR><DISTBASE><LOCALBASE>/etc/ssl/untrusted
|
||||
.Pa <DESTDIR><DISTBASE><LOCALBASE>/etc/ssl/blacklisted
|
||||
.It Ev CERTDESTDIR
|
||||
Destination directory for symbolic links to trusted certificates.
|
||||
Default:
|
||||
.Pa ${DESTDIR}/etc/ssl/certs
|
||||
.Pa <DESTDIR><DISTBASE>/etc/ssl/certs
|
||||
.It Ev UNTRUSTDESTDIR
|
||||
Destination directory for symbolic links to untrusted certificates.
|
||||
Default:
|
||||
.Pa ${DESTDIR}/etc/ssl/untrusted
|
||||
.It Ev BUNDLE
|
||||
File name of bundle to produce.
|
||||
.Pa <DESTDIR><DISTBASE>/etc/ssl/untrusted
|
||||
.It Ev EXTENSIONS
|
||||
List of file extensions to read as certificate files.
|
||||
Default: *.pem *.crt *.cer *.crl *.0
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr openssl 1
|
||||
.Sh HISTORY
|
||||
.Nm
|
||||
first appeared in
|
||||
.Fx 12.2 .
|
||||
.Fx 12.2
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
The original shell implementation was written by
|
||||
.An Allan Jude Aq Mt allanjude@FreeBSD.org .
|
||||
The current C implementation was written by
|
||||
.An Dag-Erling Sm\(/orgrav Aq Mt des@FreeBSD.org .
|
||||
.An Allan Jude Aq Mt allanjude@freebsd.org
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
366
usr.sbin/certctl/certctl.sh
Executable file
366
usr.sbin/certctl/certctl.sh
Executable file
|
|
@ -0,0 +1,366 @@
|
|||
#!/bin/sh
|
||||
#-
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright 2018 Allan Jude <allanjude@freebsd.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted providing that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
set -u
|
||||
|
||||
############################################################ CONFIGURATION
|
||||
|
||||
: ${DESTDIR:=}
|
||||
: ${DISTBASE:=}
|
||||
|
||||
############################################################ GLOBALS
|
||||
|
||||
SCRIPTNAME="${0##*/}"
|
||||
LINK=-lrs
|
||||
ERRORS=0
|
||||
NOOP=false
|
||||
UNPRIV=false
|
||||
VERBOSE=false
|
||||
|
||||
############################################################ FUNCTIONS
|
||||
|
||||
info()
|
||||
{
|
||||
echo "${0##*/}: $@" >&2
|
||||
}
|
||||
|
||||
verbose()
|
||||
{
|
||||
if "${VERBOSE}" ; then
|
||||
info "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
perform()
|
||||
{
|
||||
if ! "${NOOP}" ; then
|
||||
"$@"
|
||||
fi
|
||||
}
|
||||
|
||||
cert_files_in()
|
||||
{
|
||||
find -L "$@" -type f \( \
|
||||
-name '*.pem' -or \
|
||||
-name '*.crt' -or \
|
||||
-name '*.cer' \
|
||||
\) 2>/dev/null
|
||||
}
|
||||
|
||||
eolcvt()
|
||||
{
|
||||
cat "$@" | tr -s '\r' '\n'
|
||||
}
|
||||
|
||||
do_hash()
|
||||
{
|
||||
local hash
|
||||
|
||||
if hash=$(openssl x509 -noout -subject_hash -in "$1") ; then
|
||||
echo "$hash"
|
||||
return 0
|
||||
else
|
||||
info "Error: $1"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
return 1
|
||||
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()
|
||||
{
|
||||
local hash certhash otherfile otherhash
|
||||
local suffix
|
||||
|
||||
hash=$(do_hash "$1") || return
|
||||
certhash=$(openssl x509 -sha1 -in "$1" -noout -fingerprint)
|
||||
for otherfile in $(find $UNTRUSTDESTDIR -name "$hash.*") ; do
|
||||
otherhash=$(openssl x509 -sha1 -in "$otherfile" -noout -fingerprint)
|
||||
if [ "$certhash" = "$otherhash" ] ; then
|
||||
info "Skipping untrusted certificate $hash ($otherfile)"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
for otherfile in $(find $CERTDESTDIR -name "$hash.*") ; do
|
||||
otherhash=$(openssl x509 -sha1 -in "$otherfile" -noout -fingerprint)
|
||||
if [ "$certhash" = "$otherhash" ] ; then
|
||||
verbose "Skipping duplicate entry for certificate $hash"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
suffix=$(get_decimal "$CERTDESTDIR" "$hash")
|
||||
verbose "Adding $hash.$suffix to trust store"
|
||||
perform install ${INSTALLFLAGS} -m 0444 ${LINK} \
|
||||
"$(realpath "$1")" "$CERTDESTDIR/$hash.$suffix"
|
||||
}
|
||||
|
||||
# Accepts either dot-hash form from `certctl list` or a path to a valid cert.
|
||||
resolve_certname()
|
||||
{
|
||||
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")
|
||||
suffix=$(get_decimal "$UNTRUSTDESTDIR" "$hash")
|
||||
filename="$hash.$suffix"
|
||||
echo "$srcfile" "$hash.$suffix"
|
||||
elif [ -e "${CERTDESTDIR}/$1" ] ; then
|
||||
srcfile=$(realpath "${CERTDESTDIR}/$1")
|
||||
hash=$(echo "$1" | sed -Ee 's/\.([0-9])+$//')
|
||||
suffix=$(get_decimal "$UNTRUSTDESTDIR" "$hash")
|
||||
filename="$hash.$suffix"
|
||||
echo "$srcfile" "$hash.$suffix"
|
||||
fi
|
||||
}
|
||||
|
||||
create_untrusted()
|
||||
{
|
||||
local srcfile filename
|
||||
|
||||
set -- $(resolve_certname "$1")
|
||||
srcfile=$1
|
||||
filename=$2
|
||||
|
||||
if [ -z "$srcfile" -o -z "$filename" ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
verbose "Adding $filename to untrusted list"
|
||||
perform install ${INSTALLFLAGS} -m 0444 ${LINK} \
|
||||
"$srcfile" "$UNTRUSTDESTDIR/$filename"
|
||||
}
|
||||
|
||||
do_scan()
|
||||
{
|
||||
local CFUNC CSEARCH CPATH CFILE CERT SPLITDIR
|
||||
local oldIFS="$IFS"
|
||||
CFUNC="$1"
|
||||
CSEARCH="$2"
|
||||
|
||||
IFS=:
|
||||
set -- $CSEARCH
|
||||
IFS="$oldIFS"
|
||||
for CFILE in $(cert_files_in "$@") ; do
|
||||
verbose "Reading $CFILE"
|
||||
case $(eolcvt "$CFILE" | egrep -c '^-+BEGIN CERTIFICATE-+$') in
|
||||
0)
|
||||
;;
|
||||
1)
|
||||
"$CFUNC" "$CFILE"
|
||||
;;
|
||||
*)
|
||||
verbose "Multiple certificates found, splitting..."
|
||||
SPLITDIR=$(mktemp -d)
|
||||
eolcvt "$CFILE" | egrep '^(---|[0-9A-Za-z/+=]+$)' | \
|
||||
split -p '^-+BEGIN CERTIFICATE-+$' - "$SPLITDIR/x"
|
||||
for CERT in $(find "$SPLITDIR" -type f) ; do
|
||||
"$CFUNC" "$CERT"
|
||||
done
|
||||
rm -rf "$SPLITDIR"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
do_list()
|
||||
{
|
||||
local CFILE subject
|
||||
|
||||
for CFILE in $(find "$@" \( -type f -or -type l \) -name '*.[0-9]') ; do
|
||||
if [ ! -s "$CFILE" ] ; then
|
||||
info "Unable to read $CFILE"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
continue
|
||||
fi
|
||||
subject=
|
||||
if ! "$VERBOSE" ; then
|
||||
subject=$(openssl x509 -noout -subject -nameopt multiline -in "$CFILE" | sed -n '/commonName/s/.*= //p')
|
||||
fi
|
||||
if [ -z "$subject" ] ; then
|
||||
subject=$(openssl x509 -noout -subject -in "$CFILE")
|
||||
fi
|
||||
printf "%s\t%s\n" "${CFILE##*/}" "$subject"
|
||||
done
|
||||
}
|
||||
|
||||
cmd_rehash()
|
||||
{
|
||||
|
||||
if [ -e "$CERTDESTDIR" ] ; then
|
||||
perform find "$CERTDESTDIR" \( -type f -or -type l \) -delete
|
||||
else
|
||||
perform install -d -m 0755 "$CERTDESTDIR"
|
||||
fi
|
||||
if [ -e "$UNTRUSTDESTDIR" ] ; then
|
||||
perform find "$UNTRUSTDESTDIR" \( -type f -or -type l \) -delete
|
||||
else
|
||||
perform install -d -m 0755 "$UNTRUSTDESTDIR"
|
||||
fi
|
||||
|
||||
do_scan create_untrusted "$UNTRUSTPATH"
|
||||
do_scan create_trusted "$TRUSTPATH"
|
||||
}
|
||||
|
||||
cmd_list()
|
||||
{
|
||||
info "Listing Trusted Certificates:"
|
||||
do_list "$CERTDESTDIR"
|
||||
}
|
||||
|
||||
cmd_untrust()
|
||||
{
|
||||
local UTFILE
|
||||
|
||||
shift # verb
|
||||
perform install -d -m 0755 "$UNTRUSTDESTDIR"
|
||||
for UTFILE in "$@"; do
|
||||
info "Adding $UTFILE to untrusted list"
|
||||
create_untrusted "$UTFILE"
|
||||
done
|
||||
}
|
||||
|
||||
cmd_trust()
|
||||
{
|
||||
local UTFILE untrustedhash certhash hash
|
||||
|
||||
shift # verb
|
||||
for UTFILE in "$@"; do
|
||||
if [ -s "$UTFILE" ] ; then
|
||||
hash=$(do_hash "$UTFILE")
|
||||
certhash=$(openssl x509 -sha1 -in "$UTFILE" -noout -fingerprint)
|
||||
for UNTRUSTEDFILE in $(find $UNTRUSTDESTDIR -name "$hash.*") ; do
|
||||
untrustedhash=$(openssl x509 -sha1 -in "$UNTRUSTEDFILE" -noout -fingerprint)
|
||||
if [ "$certhash" = "$untrustedhash" ] ; then
|
||||
info "Removing $(basename "$UNTRUSTEDFILE") from untrusted list"
|
||||
perform rm -f $UNTRUSTEDFILE
|
||||
fi
|
||||
done
|
||||
elif [ -e "$UNTRUSTDESTDIR/$UTFILE" ] ; then
|
||||
info "Removing $UTFILE from untrusted list"
|
||||
perform rm -f "$UNTRUSTDESTDIR/$UTFILE"
|
||||
else
|
||||
info "Cannot find $UTFILE"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
cmd_untrusted()
|
||||
{
|
||||
info "Listing Untrusted Certificates:"
|
||||
do_list "$UNTRUSTDESTDIR"
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
exec >&2
|
||||
echo "Manage the TLS trusted certificates on the system"
|
||||
echo " $SCRIPTNAME [-v] list"
|
||||
echo " List trusted certificates"
|
||||
echo " $SCRIPTNAME [-v] untrusted"
|
||||
echo " List untrusted certificates"
|
||||
echo " $SCRIPTNAME [-cnUv] [-D <destdir>] [-d <distbase>] [-M <metalog>] rehash"
|
||||
echo " Rehash all trusted and untrusted certificates"
|
||||
echo " $SCRIPTNAME [-cnv] untrust <file>"
|
||||
echo " Add <file> to the list of untrusted certificates"
|
||||
echo " $SCRIPTNAME [-cnv] trust <file>"
|
||||
echo " Remove <file> from the list of untrusted certificates"
|
||||
exit 64
|
||||
}
|
||||
|
||||
############################################################ MAIN
|
||||
|
||||
while getopts cD:d:M:nUv flag; do
|
||||
case "$flag" in
|
||||
c) LINK=-c ;;
|
||||
D) DESTDIR=${OPTARG} ;;
|
||||
d) DISTBASE=${OPTARG} ;;
|
||||
M) METALOG=${OPTARG} ;;
|
||||
n) NOOP=true ;;
|
||||
U) UNPRIV=true ;;
|
||||
v) VERBOSE=true ;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
DESTDIR=${DESTDIR%/}
|
||||
|
||||
if ! [ -z "${CERTCTL_VERBOSE:-}" ] ; then
|
||||
VERBOSE=true
|
||||
fi
|
||||
: ${METALOG:=${DESTDIR}/METALOG}
|
||||
INSTALLFLAGS=
|
||||
if "$UNPRIV" ; then
|
||||
INSTALLFLAGS="-U -M ${METALOG} -D ${DESTDIR:-/} -o root -g wheel"
|
||||
fi
|
||||
: ${LOCALBASE:=$(sysctl -n user.localbase)}
|
||||
: ${TRUSTPATH:=${DESTDIR}${DISTBASE}/usr/share/certs/trusted:${DESTDIR}${LOCALBASE}/share/certs:${DESTDIR}${LOCALBASE}/etc/ssl/certs}
|
||||
: ${UNTRUSTPATH:=${DESTDIR}${DISTBASE}/usr/share/certs/untrusted:${DESTDIR}${LOCALBASE}/etc/ssl/untrusted:${DESTDIR}${LOCALBASE}/etc/ssl/blacklisted}
|
||||
: ${CERTDESTDIR:=${DESTDIR}${DISTBASE}/etc/ssl/certs}
|
||||
: ${UNTRUSTDESTDIR:=${DESTDIR}${DISTBASE}/etc/ssl/untrusted}
|
||||
|
||||
[ $# -gt 0 ] || usage
|
||||
case "$1" in
|
||||
list) cmd_list ;;
|
||||
rehash) cmd_rehash ;;
|
||||
blacklist) cmd_untrust "$@" ;;
|
||||
untrust) cmd_untrust "$@" ;;
|
||||
trust) cmd_trust "$@" ;;
|
||||
unblacklist) cmd_trust "$@" ;;
|
||||
untrusted) cmd_untrusted ;;
|
||||
blacklisted) cmd_untrusted ;;
|
||||
*) usage # NOTREACHED
|
||||
esac
|
||||
|
||||
retval=$?
|
||||
if [ $ERRORS -gt 0 ] ; then
|
||||
info "Encountered $ERRORS errors"
|
||||
fi
|
||||
exit $retval
|
||||
|
||||
################################################################################
|
||||
# END
|
||||
################################################################################
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
PACKAGE= tests
|
||||
ATF_TESTS_SH= certctl_test
|
||||
${PACKAGE}FILES+= certctl.subr
|
||||
|
||||
.include <bsd.test.mk>
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2025 Dag-Erling Smørgrav <des@FreeBSD.org>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
|
||||
# Generate a random name
|
||||
rand_name() {
|
||||
local length=${1:-32}
|
||||
|
||||
jot -r -c -s '' ${length} A Z
|
||||
}
|
||||
|
||||
# Generate a subject for a given name
|
||||
subject() {
|
||||
local crtname=$1
|
||||
|
||||
echo "/CN=${crtname}/O=FreeBSD/OU=Test/"
|
||||
}
|
||||
|
||||
# Generate a key
|
||||
gen_key() {
|
||||
local keyname=$1
|
||||
|
||||
env -i PATH="${PATH}" OPENSSL_CONF=/dev/null \
|
||||
openssl genrsa -out ${keyname}.key
|
||||
}
|
||||
|
||||
# Generate a certificate for a given name, key, and serial number
|
||||
gen_crt() {
|
||||
local crtname=$1
|
||||
local keyname=${2:-${crtname}}
|
||||
local serial=${3:-1}
|
||||
|
||||
if ! [ -f "${keyname}".key ]; then
|
||||
gen_key "${keyname}"
|
||||
fi
|
||||
env -i PATH="${PATH}" OPENSSL_CONF=/dev/null \
|
||||
openssl req -x509 -new \
|
||||
-subj="$(subject ${crtname})" \
|
||||
-set_serial ${serial} \
|
||||
-key ${keyname}.key \
|
||||
-out ${crtname}.crt
|
||||
}
|
||||
|
|
@ -1,221 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2025 Dag-Erling Smørgrav <des@FreeBSD.org>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
|
||||
. $(atf_get_srcdir)/certctl.subr
|
||||
|
||||
# Random sets of eight non-colliding names
|
||||
set1()
|
||||
{
|
||||
cat <<EOF
|
||||
AVOYKJHSLFHWPVQMKBHENUAHJTEGMCCB 0ca83bbe
|
||||
UYSYXKDNNJTYOQPBGIKQDHRJYZHTDPKK 0d9a6512
|
||||
LODHGFXMZYKGOKAYGWTMMYQJYHDATDDM 4e6219f5
|
||||
NBBTQHJLHKBFFFWJTHHSNKOQYMGLHLPW 5dd76abc
|
||||
BJFAQZXZHYQLIDDPCAQFPDMNXICUXBXW ad68573d
|
||||
IOKNTHVEVVIJMNMYAVILMEMQQWLVRESN b577803d
|
||||
BHGMAJJGNJPIVMHMFCUTJLGFROJICEKN c98a6338
|
||||
HCRFQMGDQJALMLUQNXMPGLXFLLJRODJW f50c6379
|
||||
EOF
|
||||
}
|
||||
|
||||
set2()
|
||||
{
|
||||
cat <<EOF
|
||||
GOHKZTSKIPDSYNLMGYXGLROPTATELXIU 30789c88
|
||||
YOOTYHEGHZIYFXOBLNKENPSJUDGOPJJU 7fadbc13
|
||||
ETRINNYBGKIENAVGOKVJYFSSHFZIJZRH 8ed664af
|
||||
DBFGMFFMRNLPQLQPOLXOEUVLCRXLRSWT 8f34355e
|
||||
WFOPBQPLQFHDHZOUQFEIDGSYDUOTSNDQ ac0471df
|
||||
HMNETZMGNIWRGXQCVZXVZGWSGFBRRDQC b32f1472
|
||||
SHFYBXDVAUACBFPPAIGDAQIAGYOYGMQE baca75fa
|
||||
PCBGDNVPYCDGNRQSGRSLXFHYKXLAVLHW ddeeae01
|
||||
EOF
|
||||
}
|
||||
|
||||
set3()
|
||||
{
|
||||
cat <<EOF
|
||||
NJWIRLPWAIICVJBKXXHFHLCPAERZATRL 000aa2e5
|
||||
RJAENDPOCZQEVCPFUWOWDXPCSMYJPVYC 021b95a3
|
||||
PQUQDSWHBNVLBTNBGONYRLGZZVEFXVLO 071e8c50
|
||||
VZEXRKJUPZSFBDWBOLUZXOGLNTEAPCZM 3af7bb9b
|
||||
ZXOWOXQTXNZMAMZIWVFDZDJEWOOAGAOH 48d5c7cc
|
||||
KQSFQYVJMFTMADIHJIWGSQISWKSHRYQO 509f5ba1
|
||||
AIECYSLWZOIEPJWWUTWSQXCNCIHHZHYI 8cb0c503
|
||||
RFHWDJZEPOFLMPGXAHVEJFHCDODAPVEV 9ae4e049
|
||||
EOF
|
||||
}
|
||||
|
||||
# Random set of three colliding names
|
||||
collhash=f2888ce3
|
||||
coll()
|
||||
{
|
||||
cat <<EOF
|
||||
EJFTZEOANQLOYPEHWWXBWEWEFVKHMSNA $collhash
|
||||
LEMRWZAZLKZLPPSFLNLQZVGKKBEOFYWG $collhash
|
||||
ZWUPHYWKKTVEFBJOLLPDAIKGRDFVXZID $collhash
|
||||
EOF
|
||||
}
|
||||
|
||||
certctl_setup()
|
||||
{
|
||||
export DESTDIR="$PWD"
|
||||
|
||||
# Create input directories
|
||||
mkdir -p usr/share/certs/trusted
|
||||
mkdir -p usr/share/certs/untrusted
|
||||
mkdir -p usr/local/share/certs
|
||||
|
||||
# Create output directories
|
||||
mkdir -p etc/ssl/certs
|
||||
mkdir -p etc/ssl/untrusted
|
||||
|
||||
# Generate a random key
|
||||
keyname="testkey"
|
||||
gen_key ${keyname}
|
||||
|
||||
# Generate certificates
|
||||
set1 | while read crtname hash ; do
|
||||
gen_crt ${crtname} ${keyname}
|
||||
mv ${crtname}.crt usr/share/certs/trusted
|
||||
done
|
||||
coll | while read crtname hash ; do
|
||||
gen_crt ${crtname} ${keyname}
|
||||
mv ${crtname}.crt usr/share/certs/trusted
|
||||
done
|
||||
set2 | while read crtname hash ; do
|
||||
gen_crt ${crtname} ${keyname}
|
||||
openssl x509 -in ${crtname}.crt
|
||||
rm ${crtname}.crt
|
||||
done >usr/local/share/certs/bundle.crt
|
||||
set3 | while read crtname hash ; do
|
||||
gen_crt ${crtname} ${keyname}
|
||||
mv ${crtname}.crt usr/share/certs/untrusted
|
||||
done
|
||||
}
|
||||
|
||||
check_trusted() {
|
||||
local crtname=$1
|
||||
local subject="$(subject ${crtname})"
|
||||
local c=${2:-1}
|
||||
|
||||
atf_check -o match:"found: ${c}\$" \
|
||||
openssl storeutl -noout -subject "${subject}" \
|
||||
etc/ssl/certs
|
||||
atf_check -o match:"found: 0\$" \
|
||||
openssl storeutl -noout -subject "${subject}" \
|
||||
etc/ssl/untrusted
|
||||
}
|
||||
|
||||
check_untrusted() {
|
||||
local crtname=$1
|
||||
local subject="$(subject ${crtname})"
|
||||
local c=${2:-1}
|
||||
|
||||
atf_check -o match:"found: 0\$" \
|
||||
openssl storeutl -noout -subject "${subject}" \
|
||||
etc/ssl/certs
|
||||
atf_check -o match:"found: ${c}\$" \
|
||||
openssl storeutl -noout -subject "${subject}" \
|
||||
etc/ssl/untrusted
|
||||
}
|
||||
|
||||
check_in_bundle() {
|
||||
local crtfile=$1
|
||||
local line
|
||||
|
||||
line=$(tail +5 "${crtfile}" | head -1)
|
||||
atf_check grep -q "${line}" etc/ssl/cert.pem
|
||||
}
|
||||
|
||||
check_not_in_bundle() {
|
||||
local crtfile=$1
|
||||
local line
|
||||
|
||||
line=$(tail +5 "${crtfile}" | head -1)
|
||||
atf_check -s exit:1 grep -q "${line}" etc/ssl/cert.pem
|
||||
}
|
||||
|
||||
atf_test_case rehash
|
||||
rehash_head()
|
||||
{
|
||||
atf_set "descr" "Test the rehash command"
|
||||
}
|
||||
rehash_body()
|
||||
{
|
||||
certctl_setup
|
||||
atf_check certctl rehash
|
||||
|
||||
# Verify non-colliding trusted certificates
|
||||
(set1 ; set2) > trusted
|
||||
while read crtname hash ; do
|
||||
check_trusted "${crtname}"
|
||||
done <trusted
|
||||
|
||||
# Verify colliding trusted certificates
|
||||
coll >coll
|
||||
while read crtname hash ; do
|
||||
check_trusted "${crtname}" $(wc -l <coll)
|
||||
done <coll
|
||||
|
||||
# Verify untrusted certificates
|
||||
set3 >untrusted
|
||||
while read crtname hash ; do
|
||||
check_untrusted "${crtname}"
|
||||
done <untrusted
|
||||
|
||||
# Verify bundle; storeutl is no help here
|
||||
for f in etc/ssl/certs/*.? ; do
|
||||
check_in_bundle "${f}"
|
||||
done
|
||||
for f in etc/ssl/untrusted/*.? ; do
|
||||
check_not_in_bundle "${f}"
|
||||
done
|
||||
}
|
||||
|
||||
atf_test_case trust
|
||||
trust_head()
|
||||
{
|
||||
atf_set "descr" "Test the trust command"
|
||||
}
|
||||
trust_body()
|
||||
{
|
||||
certctl_setup
|
||||
atf_check certctl rehash
|
||||
crtname=NJWIRLPWAIICVJBKXXHFHLCPAERZATRL
|
||||
crtfile=usr/share/certs/untrusted/${crtname}.crt
|
||||
check_untrusted ${crtname}
|
||||
check_not_in_bundle ${crtfile}
|
||||
atf_check -e match:"was previously untrusted" \
|
||||
certctl trust ${crtfile}
|
||||
check_trusted ${crtname}
|
||||
check_in_bundle ${crtfile}
|
||||
}
|
||||
|
||||
atf_test_case untrust
|
||||
untrust_head()
|
||||
{
|
||||
atf_set "descr" "Test the untrust command"
|
||||
}
|
||||
untrust_body()
|
||||
{
|
||||
certctl_setup
|
||||
atf_check certctl rehash
|
||||
crtname=AVOYKJHSLFHWPVQMKBHENUAHJTEGMCCB
|
||||
crtfile=usr/share/certs/trusted/${crtname}.crt
|
||||
check_trusted "${crtname}"
|
||||
check_in_bundle ${crtfile}
|
||||
atf_check certctl untrust "${crtfile}"
|
||||
check_untrusted "${crtname}"
|
||||
check_not_in_bundle ${crtfile}
|
||||
}
|
||||
|
||||
atf_init_test_cases()
|
||||
{
|
||||
atf_add_test_case rehash
|
||||
atf_add_test_case trust
|
||||
atf_add_test_case untrust
|
||||
}
|
||||
Loading…
Reference in a new issue