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 commit f751757259.
Revert "certctl: Fix bootstrap build"
This reverts commit c989e3cc3d.
Revert "certctl: Reimplement in C"
This reverts commit 81d8827ad8.

With hat:	re@
This commit is contained in:
Colin Percival 2025-08-16 17:17:03 -07:00
parent 939fec44a7
commit 31ac42b486
9 changed files with 414 additions and 1415 deletions

View file

@ -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} \

View file

@ -1255,8 +1255,6 @@
..
..
usr.sbin
certctl
..
chown
..
ctladm

View file

@ -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>

View file

@ -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
View 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
################################################################################

View file

@ -1,5 +0,0 @@
PACKAGE= tests
ATF_TESTS_SH= certctl_test
${PACKAGE}FILES+= certctl.subr
.include <bsd.test.mk>

View file

@ -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
}

View file

@ -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
}