Module Name: src Committed By: riastradh Date: Sat Aug 26 05:27:15 UTC 2023
Modified Files: src/distrib/sets/lists/base: mi src/distrib/sets/lists/man: mi src/distrib/sets/lists/tests: mi src/etc: Makefile src/etc/mtree: NetBSD.dist.tests src/tests/usr.sbin: Makefile src/usr.sbin: Makefile Added Files: src/tests/usr.sbin/certctl: Makefile Makefile.inc t_certctl.sh src/tests/usr.sbin/certctl/certs1: DigiCert_Global_Root_CA.pem Explicitly_Distrust_DigiNotar_Root_CA.pem Makefile src/tests/usr.sbin/certctl/certs2: GTS_Root_R1.pem GlobalSign_Root_CA_-_R3.pem Makefile src/tests/usr.sbin/certctl/certs3: Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.1.pem Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.pem Makefile src/tests/usr.sbin/certctl/certs4: AC_RAIZ_FNMT-RCM.pem DigiCert_Global_Root_CA.pem Makefile src/usr.sbin/certctl: Makefile certctl.8 certctl.sh certs.conf Log Message: certctl(8): New tool for managing OpenSSL CA certificates. Same command-line syntax as FreeBSD, clearer semantics about which parts are config and which parts are cache. To generate a diff of this commit: cvs rdiff -u -r1.1325 -r1.1326 src/distrib/sets/lists/base/mi cvs rdiff -u -r1.1763 -r1.1764 src/distrib/sets/lists/man/mi cvs rdiff -u -r1.1291 -r1.1292 src/distrib/sets/lists/tests/mi cvs rdiff -u -r1.466 -r1.467 src/etc/Makefile cvs rdiff -u -r1.199 -r1.200 src/etc/mtree/NetBSD.dist.tests cvs rdiff -u -r1.7 -r1.8 src/tests/usr.sbin/Makefile cvs rdiff -u -r0 -r1.1 src/tests/usr.sbin/certctl/Makefile \ src/tests/usr.sbin/certctl/Makefile.inc \ src/tests/usr.sbin/certctl/t_certctl.sh cvs rdiff -u -r0 -r1.1 \ src/tests/usr.sbin/certctl/certs1/DigiCert_Global_Root_CA.pem \ src/tests/usr.sbin/certctl/certs1/Explicitly_Distrust_DigiNotar_Root_CA.pem \ src/tests/usr.sbin/certctl/certs1/Makefile cvs rdiff -u -r0 -r1.1 src/tests/usr.sbin/certctl/certs2/GTS_Root_R1.pem \ src/tests/usr.sbin/certctl/certs2/GlobalSign_Root_CA_-_R3.pem \ src/tests/usr.sbin/certctl/certs2/Makefile cvs rdiff -u -r0 -r1.1 \ src/tests/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.1.pem \ src/tests/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.pem \ src/tests/usr.sbin/certctl/certs3/Makefile cvs rdiff -u -r0 -r1.1 src/tests/usr.sbin/certctl/certs4/AC_RAIZ_FNMT-RCM.pem \ src/tests/usr.sbin/certctl/certs4/DigiCert_Global_Root_CA.pem \ src/tests/usr.sbin/certctl/certs4/Makefile cvs rdiff -u -r1.291 -r1.292 src/usr.sbin/Makefile cvs rdiff -u -r0 -r1.1 src/usr.sbin/certctl/Makefile \ src/usr.sbin/certctl/certctl.8 src/usr.sbin/certctl/certctl.sh \ src/usr.sbin/certctl/certs.conf Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/distrib/sets/lists/base/mi diff -u src/distrib/sets/lists/base/mi:1.1325 src/distrib/sets/lists/base/mi:1.1326 --- src/distrib/sets/lists/base/mi:1.1325 Tue Aug 1 06:35:55 2023 +++ src/distrib/sets/lists/base/mi Sat Aug 26 05:27:13 2023 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.1325 2023/08/01 06:35:55 mrg Exp $ +# $NetBSD: mi,v 1.1326 2023/08/26 05:27:13 riastradh Exp $ # # Note: Don't delete entries from here - mark them as "obsolete" instead, # unless otherwise stated below. @@ -114,6 +114,7 @@ ./etc/openldap base-ldap-root ./etc/openssl base-crypto-root ./etc/openssl/certs base-crypto-root +./etc/openssl/certs.conf base-sysutil-bin ./etc/openssl/misc base-crypto-root ./etc/openssl/private base-crypto-root ./etc/pam.d base-sys-root @@ -1457,6 +1458,7 @@ ./usr/sbin/btpand base-sysutil-bin ./usr/sbin/btuartd base-obsolete obsolete ./usr/sbin/catman base-man-bin +./usr/sbin/certctl base-sysutil-bin ./usr/sbin/chat base-ppp-bin ./usr/sbin/chown base-sysutil-bin ./usr/sbin/chroot base-sysutil-bin Index: src/distrib/sets/lists/man/mi diff -u src/distrib/sets/lists/man/mi:1.1763 src/distrib/sets/lists/man/mi:1.1764 --- src/distrib/sets/lists/man/mi:1.1763 Fri Aug 11 23:04:29 2023 +++ src/distrib/sets/lists/man/mi Sat Aug 26 05:27:13 2023 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.1763 2023/08/11 23:04:29 christos Exp $ +# $NetBSD: mi,v 1.1764 2023/08/26 05:27:13 riastradh Exp $ # # Note: don't delete entries from here - mark them as "obsolete" instead. # @@ -2648,6 +2648,7 @@ ./usr/share/man/cat8/ccdconfig.0 man-sysutil-catman .cat ./usr/share/man/cat8/cesfic/MAKEDEV.0 man-obsolete obsolete ./usr/share/man/cat8/cesfic/makedev.0 man-obsolete obsolete +./usr/share/man/cat8/certctl.0 man-sysutil-catman .cat ./usr/share/man/cat8/cgdconfig.0 man-sysutil-catman .cat ./usr/share/man/cat8/chat.0 man-ppp-catman .cat ./usr/share/man/cat8/chown.0 man-sysutil-catman .cat @@ -5902,6 +5903,7 @@ ./usr/share/man/html8/canconfig.html man-netutil-htmlman html ./usr/share/man/html8/catman.html man-man-htmlman html ./usr/share/man/html8/ccdconfig.html man-sysutil-htmlman html +./usr/share/man/html8/certctl.html man-sysutil-htmlman html ./usr/share/man/html8/cgdconfig.html man-sysutil-htmlman html ./usr/share/man/html8/chat.html man-ppp-htmlman html ./usr/share/man/html8/chown.html man-sysutil-htmlman html @@ -9203,6 +9205,7 @@ ./usr/share/man/man8/ccdconfig.8 man-sysutil-man .man ./usr/share/man/man8/cesfic/MAKEDEV.8 man-obsolete obsolete ./usr/share/man/man8/cesfic/makedev.8 man-obsolete obsolete +./usr/share/man/man8/certctl.8 man-sysutil-man .man ./usr/share/man/man8/cgdconfig.8 man-sysutil-man .man ./usr/share/man/man8/chat.8 man-ppp-man .man ./usr/share/man/man8/chown.8 man-sysutil-man .man Index: src/distrib/sets/lists/tests/mi diff -u src/distrib/sets/lists/tests/mi:1.1291 src/distrib/sets/lists/tests/mi:1.1292 --- src/distrib/sets/lists/tests/mi:1.1291 Sun Aug 20 19:36:56 2023 +++ src/distrib/sets/lists/tests/mi Sat Aug 26 05:27:14 2023 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.1291 2023/08/20 19:36:56 riastradh Exp $ +# $NetBSD: mi,v 1.1292 2023/08/26 05:27:14 riastradh Exp $ # # Note: don't delete entries from here - mark them as "obsolete" instead. # @@ -7564,6 +7564,22 @@ ./usr/tests/usr.sbin tests-usr.sbin-tests compattestfile,atf ./usr/tests/usr.sbin/Atffile tests-usr.sbin-tests compattestfile,atf ./usr/tests/usr.sbin/Kyuafile tests-usr.sbin-tests compattestfile,atf,kyua +./usr/tests/usr.sbin/certctl tests-usr.sbin-tests compattestfile,atf +./usr/tests/usr.sbin/certctl/Atffile tests-usr.sbin-tests compattestfile,atf +./usr/tests/usr.sbin/certctl/Kyuafile tests-usr.sbin-tests compattestfile,atf,kyua +./usr/tests/usr.sbin/certctl/certs1 tests-usr.sbin-tests compattestfile,atf +./usr/tests/usr.sbin/certctl/certs1/DigiCert_Global_Root_CA.pem tests-usr.sbin-tests compattestfile,atf +./usr/tests/usr.sbin/certctl/certs1/Explicitly_Distrust_DigiNotar_Root_CA.pem tests-usr.sbin-tests compattestfile,atf +./usr/tests/usr.sbin/certctl/certs2 tests-usr.sbin-tests compattestfile,atf +./usr/tests/usr.sbin/certctl/certs2/GTS_Root_R1.pem tests-usr.sbin-tests compattestfile,atf +./usr/tests/usr.sbin/certctl/certs2/GlobalSign_Root_CA_-_R3.pem tests-usr.sbin-tests compattestfile,atf +./usr/tests/usr.sbin/certctl/certs3 tests-usr.sbin-tests compattestfile,atf +./usr/tests/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.1.pem tests-usr.sbin-tests compattestfile,atf +./usr/tests/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.pem tests-usr.sbin-tests compattestfile,atf +./usr/tests/usr.sbin/certctl/certs4 tests-usr.sbin-tests compattestfile,atf +./usr/tests/usr.sbin/certctl/certs4/AC_RAIZ_FNMT-RCM.pem tests-usr.sbin-tests compattestfile,atf +./usr/tests/usr.sbin/certctl/certs4/DigiCert_Global_Root_CA.pem tests-usr.sbin-tests compattestfile,atf +./usr/tests/usr.sbin/certctl/t_certctl tests-usr.sbin-tests compattestfile,atf ./usr/tests/usr.sbin/cpuctl tests-usr.sbin-tests compattestfile,atf ./usr/tests/usr.sbin/cpuctl/Atffile tests-usr.sbin-tests compattestfile,atf ./usr/tests/usr.sbin/cpuctl/Kyuafile tests-usr.sbin-tests compattestfile,atf,kyua Index: src/etc/Makefile diff -u src/etc/Makefile:1.466 src/etc/Makefile:1.467 --- src/etc/Makefile:1.466 Sun Aug 21 07:10:03 2022 +++ src/etc/Makefile Sat Aug 26 05:27:14 2023 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.466 2022/08/21 07:10:03 lukem Exp $ +# $NetBSD: Makefile,v 1.467 2023/08/26 05:27:14 riastradh Exp $ # from: @(#)Makefile 8.7 (Berkeley) 5/25/95 # Environment variables without default values: @@ -348,6 +348,7 @@ install-etc-files: .PHONY .MAKE check_DE .endfor ${MAKEDIRTARGET} ${NETBSDSRCDIR}/external/bsd/dhcpcd/sbin/dhcpcd configinstall ${MAKEDIRTARGET} ${NETBSDSRCDIR}/usr.bin/mail configinstall + ${MAKEDIRTARGET} ${NETBSDSRCDIR}/usr.sbin/certctl configinstall .if (${MKPF} != "no") ${MAKEDIRTARGET} ${NETBSDSRCDIR}/usr.sbin/pf configinstall .endif Index: src/etc/mtree/NetBSD.dist.tests diff -u src/etc/mtree/NetBSD.dist.tests:1.199 src/etc/mtree/NetBSD.dist.tests:1.200 --- src/etc/mtree/NetBSD.dist.tests:1.199 Sun Aug 20 10:27:11 2023 +++ src/etc/mtree/NetBSD.dist.tests Sat Aug 26 05:27:14 2023 @@ -1,4 +1,4 @@ -# $NetBSD: NetBSD.dist.tests,v 1.199 2023/08/20 10:27:11 riastradh Exp $ +# $NetBSD: NetBSD.dist.tests,v 1.200 2023/08/26 05:27:14 riastradh Exp $ ./usr/libdata/debug/usr/tests ./usr/libdata/debug/usr/tests/atf @@ -486,6 +486,11 @@ ./usr/tests/usr.bin/xlint/xlint ./usr/tests/usr.bin/ztest ./usr/tests/usr.sbin +./usr/tests/usr.sbin/certctl +./usr/tests/usr.sbin/certctl/certs1 +./usr/tests/usr.sbin/certctl/certs2 +./usr/tests/usr.sbin/certctl/certs3 +./usr/tests/usr.sbin/certctl/certs4 ./usr/tests/usr.sbin/cpuctl ./usr/tests/usr.sbin/execsnoop ./usr/tests/usr.sbin/inetd Index: src/tests/usr.sbin/Makefile diff -u src/tests/usr.sbin/Makefile:1.7 src/tests/usr.sbin/Makefile:1.8 --- src/tests/usr.sbin/Makefile:1.7 Sun Aug 29 09:54:18 2021 +++ src/tests/usr.sbin/Makefile Sat Aug 26 05:27:14 2023 @@ -1,8 +1,9 @@ -# $NetBSD: Makefile,v 1.7 2021/08/29 09:54:18 christos Exp $ +# $NetBSD: Makefile,v 1.8 2023/08/26 05:27:14 riastradh Exp $ .include <bsd.own.mk> TESTSDIR= ${TESTSBASE}/usr.sbin +TESTS_SUBDIRS+= certctl TESTS_SUBDIRS+= cpuctl TESTS_SUBDIRS+= execsnoop TESTS_SUBDIRS+= inetd Index: src/usr.sbin/Makefile diff -u src/usr.sbin/Makefile:1.291 src/usr.sbin/Makefile:1.292 --- src/usr.sbin/Makefile:1.291 Mon Jun 6 10:56:29 2022 +++ src/usr.sbin/Makefile Sat Aug 26 05:27:15 2023 @@ -1,11 +1,11 @@ -# $NetBSD: Makefile,v 1.291 2022/06/06 10:56:29 nia Exp $ +# $NetBSD: Makefile,v 1.292 2023/08/26 05:27:15 riastradh Exp $ # from: @(#)Makefile 5.20 (Berkeley) 6/12/93 .include <bsd.own.mk> SUBDIR= ac accton acpitools altq apm apmd arp autofs \ bad144 bootp bta2dpd btattach btconfig btdevctl bthcid btpand catman \ - chroot cnwctl cpuctl crash \ + certctl chroot cnwctl cpuctl crash \ dev_mkdb diskpart dumpfs dumplfs \ edquota eeprom envstat etcupdate extattrctl \ flashctl fssconfig fstyp fusermount fwctl \ Added files: Index: src/tests/usr.sbin/certctl/Makefile diff -u /dev/null src/tests/usr.sbin/certctl/Makefile:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/tests/usr.sbin/certctl/Makefile Sat Aug 26 05:27:14 2023 @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.1 2023/08/26 05:27:14 riastradh Exp $ +# + +.include "Makefile.inc" # TESTSDIR + +SUBDIR= certs1 certs2 certs3 certs4 + +TESTS_SH= t_certctl + +.include <bsd.test.mk> Index: src/tests/usr.sbin/certctl/Makefile.inc diff -u /dev/null src/tests/usr.sbin/certctl/Makefile.inc:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/tests/usr.sbin/certctl/Makefile.inc Sat Aug 26 05:27:14 2023 @@ -0,0 +1,6 @@ +# $NetBSD: Makefile.inc,v 1.1 2023/08/26 05:27:14 riastradh Exp $ +# + +TESTSDIR= ${TESTSBASE}/usr.sbin/certctl + +.include <bsd.own.mk> Index: src/tests/usr.sbin/certctl/t_certctl.sh diff -u /dev/null src/tests/usr.sbin/certctl/t_certctl.sh:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/tests/usr.sbin/certctl/t_certctl.sh Sat Aug 26 05:27:14 2023 @@ -0,0 +1,333 @@ +#!/bin/sh + +# $NetBSD: t_certctl.sh,v 1.1 2023/08/26 05:27:14 riastradh Exp $ +# +# Copyright (c) 2023 The NetBSD Foundation, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``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 FOUNDATION OR CONTRIBUTORS +# 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. +# + +CERTCTL="certctl -C certs.conf -c certs -u untrusted" + +# setupconf <subdir>... +# +# Create certs/ and set up certs.conf to search the specified +# subdirectories of the source directory. +# +setupconf() +{ + local sep subdir dir + + mkdir certs + cat <<EOF >certs.conf +netbsd-certctl 20230816 + +# comment at line start + # comment not at line start, plus some intentional whitespace + +# THE WHITESPACE ABOVE IS INTENTIONAL, DO NOT DELETE +EOF + # Start with a continuation line separator; then switch to + # non-continuation lines. + sep=$(printf ' \\\n\t') + for subdir; do + dir=$(atf_get_srcdir)/$subdir + cat <<EOF >>certs.conf +path$sep$(printf '%s' "$dir" | vis -M) +EOF + sep=' ' + done +} + +# check_empty +# +# Verify the certs directory is empty after dry runs or after +# clearing the directory. +# +check_empty() +{ + local why + + why=${1:-dry run} + for x in certs/*; do + if [ -e "$x" -o -h "$x" ]; then + atf_fail "certs/ should be empty after $why" + fi + done +} + +# check_nonempty +# +# Verify the certs directory is nonempty. +# +check_nonempty() +{ + for x in certs/*.0; do + test -e "$x" && test -h "$x" && return + done + atf_fail "certs/ should be nonempty" +} + +# checks <certsN>... +# +# Run various checks with certctl. +# +checks() +{ + local certs1 diginotar_base diginotar diginotar_hash subdir srcdir + + certs1=$(atf_get_srcdir)/certs1 + diginotar_base=Explicitly_Distrust_DigiNotar_Root_CA.pem + diginotar=$certs1/$diginotar_base + diginotar_hash=$(openssl x509 -hash -noout <$diginotar) + + # Do a dry run of rehash and make sure the directory is still + # empty. + atf_check -s exit:0 $CERTCTL -n rehash + check_empty + + # Distrust and trust one CA, as a dry run. The trust should + # fail because it's not currently distrusted. + atf_check -s exit:0 $CERTCTL -n untrust "$diginotar" + check_empty + atf_check -s not-exit:0 -e match:currently \ + $CERTCTL -n trust "$diginotar" + check_empty + + # Do a real rehash, not a dry run. + atf_check -s exit:0 $CERTCTL rehash + + # Make sure all the certificates are trusted. + for subdir; do + case $subdir in + /*) srcdir=$subdir;; + *) srcdir=$(atf_get_srcdir)/$subdir;; + esac + for cert in "$srcdir"/*.pem; do + # Verify the certificate is linked by its base name. + certbase=$(basename "$cert") + atf_check -s exit:0 -o inline:"$cert" \ + readlink -n "certs/$certbase" + + # Verify the certificate is linked by a hash. + hash=$(openssl x509 -hash -noout <$cert) + counter=0 + found=false + while [ $counter -lt 10 ]; do + if cmp -s "certs/$hash.$counter" "$cert"; then + found=true + break + fi + counter=$((counter + 1)) + done + if ! $found; then + atf_fail "missing $cert" + fi + + # Delete both links. + rm "certs/$certbase" + rm "certs/$hash.$counter" + done + done + + # Verify the certificate bundle is there and delete it. + # + # XXX Verify its content. + atf_check -s exit:0 test -f certs/ca-certificates.crt + atf_check -s exit:0 test ! -h certs/ca-certificates.crt + rm certs/ca-certificates.crt + + # Make sure after deleting everything there's nothing left. + check_empty "removing all expected certificates" + + # Distrust, trust, and re-distrust one CA, and verify that it + # ceases to appear, reappears, and again ceases to appear. + # (This one has no subject hash collisions to worry about, so + # we hard-code the `.0' suffix.) + atf_check -s exit:0 $CERTCTL untrust "$diginotar" + atf_check -s exit:0 test -e "untrusted/$diginotar_base" + atf_check -s exit:0 test -h "untrusted/$diginotar_base" + atf_check -s exit:0 test ! -e "certs/$diginotar_base" + atf_check -s exit:0 test ! -h "certs/$diginotar_base" + atf_check -s exit:0 test ! -e "certs/$diginotar_hash.0" + atf_check -s exit:0 test ! -h "certs/$diginotar_hash.0" + check_nonempty + + atf_check -s exit:0 $CERTCTL trust "$diginotar" + atf_check -s exit:0 test ! -e "untrusted/$diginotar_base" + atf_check -s exit:0 test ! -h "untrusted/$diginotar_base" + atf_check -s exit:0 test -e "certs/$diginotar_base" + atf_check -s exit:0 test -h "certs/$diginotar_base" + atf_check -s exit:0 test -e "certs/$diginotar_hash.0" + atf_check -s exit:0 test -h "certs/$diginotar_hash.0" + rm "certs/$diginotar_base" + rm "certs/$diginotar_hash.0" + check_nonempty + + atf_check -s exit:0 $CERTCTL untrust "$diginotar" + atf_check -s exit:0 test -e "untrusted/$diginotar_base" + atf_check -s exit:0 test -h "untrusted/$diginotar_base" + atf_check -s exit:0 test ! -e "certs/$diginotar_base" + atf_check -s exit:0 test ! -h "certs/$diginotar_base" + atf_check -s exit:0 test ! -e "certs/$diginotar_hash.0" + atf_check -s exit:0 test ! -h "certs/$diginotar_hash.0" + check_nonempty +} + +atf_test_case empty +empty_head() +{ + atf_set "descr" "Test empty certificates store" +} +empty_body() +{ + setupconf # no directories + check_empty "empty cert path" + atf_check -s exit:0 $CERTCTL -n rehash + check_empty + atf_check -s exit:0 $CERTCTL rehash + atf_check -s exit:0 test -f certs/ca-certificates.crt + atf_check -s exit:0 test \! -h certs/ca-certificates.crt + atf_check -s exit:0 test \! -s certs/ca-certificates.crt + atf_check -s exit:0 rm certs/ca-certificates.crt + check_empty "empty cert path" +} + +atf_test_case onedir +onedir_head() +{ + atf_set "descr" "Test one certificates directory" +} +onedir_body() +{ + setupconf certs1 + checks certs1 +} + +atf_test_case twodir +twodir_head() +{ + atf_set "descr" "Test two certificates directories" +} +twodir_body() +{ + setupconf certs1 certs2 + checks certs1 certs2 +} + +atf_test_case collidehash +collidehash_head() +{ + atf_set "descr" "Test colliding hashes" +} +collidehash_body() +{ + # certs3 has two certificates with the same subject hash + setupconf certs1 certs3 + checks certs1 certs3 +} + +atf_test_case collidebase +collidebase_head() +{ + atf_set "descr" "Test colliding base names" +} +collidebase_body() +{ + # certs1 and certs4 both have DigiCert_Global_Root_CA.pem, + # which should cause list and rehash to fail and mention + # duplicates. + setupconf certs1 certs4 + atf_check -s not-exit:0 -o ignore -e match:duplicate $CERTCTL list + atf_check -s not-exit:0 -o ignore -e match:duplicate $CERTCTL rehash +} + +atf_test_case manual +manual_head() +{ + atf_set "descr" "Test manual operation" +} +manual_body() +{ + local certs1 diginotar_base diginotar diginotar_hash + + certs1=$(atf_get_srcdir)/certs1 + diginotar_base=Explicitly_Distrust_DigiNotar_Root_CA.pem + diginotar=$certs1/$diginotar_base + diginotar_hash=$(openssl x509 -hash -noout <$diginotar) + + setupconf certs1 certs2 + cat <<EOF >>certs.conf +manual +EOF + touch certs/bogus.pem + ln -s bogus.pem certs/0123abcd.0 + + # Listing shouldn't mention anything in the certs/ cache. + atf_check -s exit:0 -o not-match:bogus $CERTCTL list + atf_check -s exit:0 -o not-match:bogus $CERTCTL untrusted + + # Rehashing and changing the configuration should succeed, but + # mention `manual' in a warning message and should not touch + # the cache. + atf_check -s exit:0 -e match:manual $CERTCTL rehash + atf_check -s exit:0 -e match:manual $CERTCTL untrust "$diginotar" + atf_check -s exit:0 -e match:manual $CERTCTL trust "$diginotar" + + # The files we created should still be there. + atf_check -s exit:0 test -f certs/bogus.pem + atf_check -s exit:0 test -h certs/0123abcd.0 +} + +atf_test_case evilpath +evilpath_head() +{ + atf_set "descr" "Test certificate paths with evil characters" +} +evilpath_body() +{ + local evildir + + evildir="$(printf 'evil\n.')" + evildir=${evildir%.} + mkdir "$evildir" + + cp -p "$(atf_get_srcdir)/certs2"/*.pem "$evildir"/ + + setupconf certs1 + cat <<EOF >>certs.conf +path $(printf '%s' "$(pwd)/$evildir" | vis -M) +EOF + checks certs1 "$(pwd)/$evildir" +} + +atf_init_test_cases() +{ + atf_add_test_case collidebase + atf_add_test_case collidehash + atf_add_test_case empty + atf_add_test_case evilpath + atf_add_test_case manual + atf_add_test_case onedir + atf_add_test_case twodir +} Index: src/tests/usr.sbin/certctl/certs1/DigiCert_Global_Root_CA.pem diff -u /dev/null src/tests/usr.sbin/certctl/certs1/DigiCert_Global_Root_CA.pem:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/tests/usr.sbin/certctl/certs1/DigiCert_Global_Root_CA.pem Sat Aug 26 05:27:14 2023 @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- Index: src/tests/usr.sbin/certctl/certs1/Explicitly_Distrust_DigiNotar_Root_CA.pem diff -u /dev/null src/tests/usr.sbin/certctl/certs1/Explicitly_Distrust_DigiNotar_Root_CA.pem:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/tests/usr.sbin/certctl/certs1/Explicitly_Distrust_DigiNotar_Root_CA.pem Sat Aug 26 05:27:14 2023 @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFijCCA3KgAwIBAgIQD////////////////////zANBgkqhkiG9w0BAQUFADBf +MQswCQYDVQQGEwJOTDESMBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdp +Tm90YXIgUm9vdCBDQTEgMB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmww +HhcNMDcwNzI3MTcxOTM3WhcNMjUwMzMxMTgxOTIyWjBfMQswCQYDVQQGEwJOTDES +MBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdpTm90YXIgUm9vdCBDQTEg +MB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmwwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCssFjBAL3YIQgLK5r+blYwBZ8bd5AQQVzDDYcRd46B +8cp86Yxq7Th0Nbva3/m7wAk3tJZzgX0zGpg595NvlX89ubF1h7pRSOiLcD6VBMXY +tsMW2YiwsYcdcNqGtA8Ui3rPENF0NqISe3eGSnnme98CEWilToauNFibJBN4ViIl +HgGLS1Fx+4LMWZZpiFpoU8W5DQI3y0u8ZkqQfioLBQftFl9VkHXYRskbg+IIvvEj +zJkd1ioPgyAVWCeCLvriIsJJsbkBgWqdbZ1Ad2h2TiEqbYRAhU52mXyC8/O3AlnU +JgEbjt+tUwbRrhjd4rI6y9eIOI6sWym5GdOY+RgDz0iChmYLG2kPyes4iHomGgVM +ktck1JbyrFIto0fVUvY//s6EBnCmqj6i8rZWNBhXouSBbefK8GrTx5FrAoNBfBXv +a5pkXuPQPOWx63tdhvvL5ndJzaNl3Pe5nLjkC1+Tz8wwGjIczhxjlaX56uF0i57p +K6kwe6AYHw4YC+VbqdPRbB4HZ4+RS6mKvNJmqpMBiLKR+jFc1abBUggJzQpjotMi +puih2TkGl/VujQKQjBR7P4DNG5y6xFhyI6+2Vp/GekIzKQc/gsnmHwUNzUwoNovT +yD4cxojvXu6JZOkd69qJfjKmadHdzIif0dDJZiHcBmfFlHqabWJMfczgZICynkeO +owIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUiGi/4I41xDs4a2L3KDuEgcgM100wDQYJKoZIhvcNAQEFBQADggIBADsC +jcs8MOhuoK3yc7NfniUTBAXT9uOLuwt5zlPe5JbF0a9zvNXD0EBVfEB/zRtfCdXy +fJ9oHbtdzno5wozWmHvFg1Wo1X1AyuAe94leY12hE8JdiraKfADzI8PthV9xdvBo +Y6pFITlIYXg23PFDk9Qlx/KAZeFTAnVR/Ho67zerhChXDNjU1JlWbOOi/lmEtDHo +M/hklJRRl6s5xUvt2t2AC298KQ3EjopyDedTFLJgQT2EkTFoPSdE2+Xe9PpjRchM +Ppj1P0G6Tss3DbpmmPHdy59c91Q2gmssvBNhl0L4eLvMyKKfyvBovWsdst+Nbwed +2o5nx0ceyrm/KkKRt2NTZvFCo+H0Wk1Ya7XkpDOtXHAd3ODy63MUkZoDweoAZbwH +/M8SESIsrqC9OuCiKthZ6SnTGDWkrBFfGbW1G/8iSlzGeuQX7yCpp/Q/rYqnmgQl +nQ7KN+ZQ/YxCKQSa7LnPS3K94gg2ryMvYuXKAdNw23yCIywWMQzGNgeQerEfZ1jE +O1hZibCMjFCz2IbLaKPECudpSyDOwR5WS5WpI2jYMNjD67BVUc3l/Su49bsRn1NU +9jQZjHkJNsphFyUXC4KYcwx3dMPVDceoEkzHp1RxRy4sGn3J4ys7SN4nhKdjNrN9 +j6BkOSQNPXuHr2ZcdBtLc7LljPCGmbjlxd+Ewbfr +-----END CERTIFICATE----- Index: src/tests/usr.sbin/certctl/certs1/Makefile diff -u /dev/null src/tests/usr.sbin/certctl/certs1/Makefile:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/tests/usr.sbin/certctl/certs1/Makefile Sat Aug 26 05:27:14 2023 @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.1 2023/08/26 05:27:14 riastradh Exp $ +# + +FILESDIR= ${TESTSDIR}/certs1 + +FILES+= DigiCert_Global_Root_CA.pem +FILES+= Explicitly_Distrust_DigiNotar_Root_CA.pem + +.include <bsd.files.mk> +.include <bsd.inc.mk> Index: src/tests/usr.sbin/certctl/certs2/GTS_Root_R1.pem diff -u /dev/null src/tests/usr.sbin/certctl/certs2/GTS_Root_R1.pem:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/tests/usr.sbin/certctl/certs2/GTS_Root_R1.pem Sat Aug 26 05:27:14 2023 @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo +27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w +Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw +TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl +qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH +szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 +Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk +MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p +aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN +VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb +C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy +h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 +7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J +ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef +MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ +Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT +6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ +0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm +2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb +bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c +-----END CERTIFICATE----- Index: src/tests/usr.sbin/certctl/certs2/GlobalSign_Root_CA_-_R3.pem diff -u /dev/null src/tests/usr.sbin/certctl/certs2/GlobalSign_Root_CA_-_R3.pem:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/tests/usr.sbin/certctl/certs2/GlobalSign_Root_CA_-_R3.pem Sat Aug 26 05:27:14 2023 @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- Index: src/tests/usr.sbin/certctl/certs2/Makefile diff -u /dev/null src/tests/usr.sbin/certctl/certs2/Makefile:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/tests/usr.sbin/certctl/certs2/Makefile Sat Aug 26 05:27:14 2023 @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.1 2023/08/26 05:27:14 riastradh Exp $ +# + +FILESDIR= ${TESTSDIR}/certs2 + +FILES+= GTS_Root_R1.pem +FILES+= GlobalSign_Root_CA_-_R3.pem + +.include <bsd.files.mk> +.include <bsd.inc.mk> Index: src/tests/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.1.pem diff -u /dev/null src/tests/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.1.pem:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/tests/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.1.pem Sat Aug 26 05:27:14 2023 @@ -0,0 +1,35 @@ +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1 +MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc +tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd +IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j +b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC +AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw +ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m +iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF +Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ +hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P +Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE +EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV +1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t +CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR +5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw +f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9 +ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK +GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV +-----END CERTIFICATE----- Index: src/tests/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.pem diff -u /dev/null src/tests/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.pem:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/tests/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.pem Sat Aug 26 05:27:14 2023 @@ -0,0 +1,35 @@ +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy +MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD +VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv +ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl +AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF +661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 +am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 +ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 +PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS +3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k +SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF +3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM +ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g +StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz +Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB +jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- Index: src/tests/usr.sbin/certctl/certs3/Makefile diff -u /dev/null src/tests/usr.sbin/certctl/certs3/Makefile:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/tests/usr.sbin/certctl/certs3/Makefile Sat Aug 26 05:27:14 2023 @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.1 2023/08/26 05:27:14 riastradh Exp $ +# + +FILESDIR= ${TESTSDIR}/certs3 + +FILES+= Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.1.pem +FILES+= Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.pem + +.include <bsd.files.mk> +.include <bsd.inc.mk> Index: src/tests/usr.sbin/certctl/certs4/AC_RAIZ_FNMT-RCM.pem diff -u /dev/null src/tests/usr.sbin/certctl/certs4/AC_RAIZ_FNMT-RCM.pem:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/tests/usr.sbin/certctl/certs4/AC_RAIZ_FNMT-RCM.pem Sat Aug 26 05:27:14 2023 @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx +CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ +WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ +BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG +Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ +yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf +BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz +WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF +tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z +374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC +IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL +mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 +wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS +MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 +ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet +UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H +YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 +LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 +RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM +LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf +77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N +JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm +fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp +6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp +1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B +9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok +RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv +uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- Index: src/tests/usr.sbin/certctl/certs4/DigiCert_Global_Root_CA.pem diff -u /dev/null src/tests/usr.sbin/certctl/certs4/DigiCert_Global_Root_CA.pem:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/tests/usr.sbin/certctl/certs4/DigiCert_Global_Root_CA.pem Sat Aug 26 05:27:15 2023 @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- Index: src/tests/usr.sbin/certctl/certs4/Makefile diff -u /dev/null src/tests/usr.sbin/certctl/certs4/Makefile:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/tests/usr.sbin/certctl/certs4/Makefile Sat Aug 26 05:27:15 2023 @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.1 2023/08/26 05:27:15 riastradh Exp $ +# + +FILESDIR= ${TESTSDIR}/certs4 + +FILES+= AC_RAIZ_FNMT-RCM.pem +FILES+= DigiCert_Global_Root_CA.pem + +.include <bsd.files.mk> +.include <bsd.inc.mk> Index: src/usr.sbin/certctl/Makefile diff -u /dev/null src/usr.sbin/certctl/Makefile:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/usr.sbin/certctl/Makefile Sat Aug 26 05:27:15 2023 @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.1 2023/08/26 05:27:15 riastradh Exp $ +# + +MAN= certctl.8 +SCRIPTS= certctl.sh + +FILESDIR= /etc/openssl +CONFIGFILES= certs.conf + +.include <bsd.prog.mk> Index: src/usr.sbin/certctl/certctl.8 diff -u /dev/null src/usr.sbin/certctl/certctl.8:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/usr.sbin/certctl/certctl.8 Sat Aug 26 05:27:15 2023 @@ -0,0 +1,337 @@ +.\" $NetBSD: certctl.8,v 1.1 2023/08/26 05:27:15 riastradh Exp $ +.\" +.\" Copyright (c) 2023 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``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 FOUNDATION OR CONTRIBUTORS +.\" 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. +.\" +.Dd August 16, 2023 +.Dt CERTCTL 8 +.Os +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Sh NAME +.Nm certctl +.Nd configure OpenSSL certificate trust anchors +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Sh SYNOPSIS +.Nm +.Op Fl nv +.Op Fl C Ar config +.Op Fl c Ar certsdir +.Op Fl u Ar distrustdir +.Ar cmd +.Op Ar args... +.\"""""""""""""""""" +.Nm +.Oo Ar options Oc Cm list +.Nm +.Oo Ar options Oc Cm rehash +.Nm +.Oo Ar options Oc Cm trust Ar cert +.Nm +.Oo Ar options Oc Cm untrust Ar cert +.Nm +.Oo Ar options Oc Cm untrusted +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Sh DESCRIPTION +The +.Nm +utility manages certificates used by OpenSSL-based applications as +trust anchors for certificate validation in HTTPS or other purposes. +.Nm +allows configuring the set of certificates and persistently excluding +individual certificates. +.Pp +For HTTPS certificate validation, OpenSSL applications typically +use either a directory at +.Pa /etc/openssl/certs +of hashed certificates in PEM format, with names like +.Pa "3513523f.0" +used for lookup +.Pq see Xr openssl_rehash 1 , +or a single-file bundle at +.Pa /etc/openssl/certs/ca-certificates.crt +concatenating all the certificates in PEM format. +.Pp +.Nm +scans all directories in the certificate search path specified by the +configuration file +.Ar config +.Pq default: Pa /etc/openssl/certs.conf +for files called +.Pa *.cer , +.Pa *.crt , +or +.Pa *.pem +in PEM format, except for those that have been excluded by +.Nm Cm untrust , +and keeps +.Ar certsdir +.Pq default: Pa /etc/openssl/certs +populated with symlinks to them. +.Pp +.Nm +treats +.Ar config +and +.Ar distrustdir +as configuration, and +.Ar certsdir +strictly as a cache that can be safely deleted and rebuilt with +.Nm Cm rehash . +.Nm +can also be instructed not to touch +.Ar certsdir +at all by putting +.Cm manual +in +.Ar config . +. +.\"""""""""""""""""""""""""""""""""""""" +.Ss Commands +.Bl -tag -width Cm +.\"""""""""""""""""" +.It Cm list +List absolute paths to trusted certificates, one per line, in +.Xr vis 1 +format to encode any shell metacharacters, that +.Nm Cm rehash +would use to populate the +.Ar certsdir +cache. +.\"""""""""""""""""" +.It Cm rehash +Populate +.Ar certsdir +with all trusted certificates, excluding any from +.Nm Cm untrust . +.\"""""""""""""""""" +.It Cm trust Ar cert +Allow +.Ar cert +to be included in the certificate cache if it is in the certificate +search path, and rehash the certificate cache. +In other words, reverse the persistent effect of +.Nm Cm untrust Ar cert . +.Pp +.Ar cert +must be the full absolute path to a certificate that has been excluded +by +.Nm Cm untrust Ar cert . +.Pp +This does not add a new certificate which is not in the search path. +To do that, you can create a directory to hold it and put that +directory in the search path. +.\"""""""""""""""""" +.It Cm untrust Ar cert +Persistently prevent +.Ar +from being included in the certificate cache, and rehash the +certificate cache. +.Pp +.Ar cert +must be the full absolute path to a certificate that is in the +certificate search path. +.\"""""""""""""""""" +.It Cm untrusted +List absolute paths to untrusted certificates, one per line, in +.Xr vis 1 +format to encode any shell metacharacters, that have been excluded by +.Nm Cm untrust +so that +.Nm Cm rehash +will not put them in +.Ar certsdir . +.\"""""""""""""""""" +.El +.\"""""""""""""""""""""""""""""""""""""" +.Ss Configuration file +The configuration file is a plain text file of lines separated by +.Tn US-ASCII +line feeds. +.Pp +.Pp +The first line must be: +.Dl netbsd-certctl 20230816 +.Pp +Lines with only whitespace, or whitespace followed by the comment +character +.Ql # +are ignored. +Each line has a directive and arguments separated by whitespace, and +may be extended by +.Ql \e +to continuation lines. +.Bl -tag -width Cm +.\"""""""""""""""""" +.It Cm path Ar dir +Add +.Ar dir +to the certificate search path. +.Ar dir +must be an absolute pathname, +.Xr vis 3 Ns -encoded . +.Pp +All certificates must have unique base names across all directories +in the certificate search path. +.\"""""""""""""""""" +.It Cm manual +Manual override. +If specified, +.Nm +will +.Em not +modify +.Ar certsdir , +but may still check consistency of the configuration when run and +update +.Ar distrustdir . +.\"""""""""""""""""" +.El +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Sh FILES +.Bl -tag -width Pa +.It Pa /etc/openssl/certs +Default directory of hashed HTTPS CA certificates. +.It Pa /etc/openssl/certs/ca-certificates.crt +Default single-file HTTPS CA certificate bundle. +.It Pa /etc/openssl/certs.conf +Default configuration file for HTTPS CA certificates. +.It Pa /etc/openssl/untrusted +Default +.Ar untrusted +directory of excluded HTTPS CA certificates. +.It Pa /usr/share/certs/mozilla/all +All root CA certificates published by Mozilla, including untrustworthy +certificates. +.It Pa /usr/share/certs/mozilla/code +All root CA certificates published by Mozilla for use in code-signing. +.It Pa /usr/share/certs/mozilla/email +All root CA certificates published by Mozilla for use in email +authentication. +.It Pa /usr/share/certs/mozilla/server +All root CA certificates published by Mozilla for use in HTTPS server +authentication. +.El +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Sh EXAMPLES +Example configuration file +.Pq Pa /etc/openssl/certs.conf : +.Bd -literal -offset indent +netbsd-certctl 20230816 + +# Blank lines and comments are ignored. +# Comments begin with a `#' sign. + +# Gather certificates from files called *.cer, *.crt, and *.pem +# under these directories. +path /usr/share/certs/mozilla/server +path /usr/pkg/share/chromium-cacerts + +# If the next line is uncommented, certctl(8) will decline to +# touch /etc/openssl/certs. +#manual +.Ed +.Pp +Exclude a certificate: +.Bd -literal -offset indent +$ certctl untrust /usr/share/certs/mozilla/server/GTS_Root_R1.pem +.Ed +.Pp +There is no need to run +.Nm Cm rehash +explicitly after +.Nm Cm untrust , +but if you do, the setting will persist. +.Pp +Rebuild the hashed certificate cache at +.Pa /etc/myapplication/certs +from +.Pa /etc/myapplication/certs.conf +and +.Pa /etc/myapplication/untrusted : +.Bd -literal -offset indent +$ certctl -c /etc/myapplication/certs \e + -C /etc/myapplication/certs.conf \e + -u /etc/myapplication/untrusted +.Ed +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Sh DIAGNOSTICS +.Ex -std +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Sh COMPATIBILITY +The +.Nm +utility is mostly compatible with a utility of the same name in +.Fx . +Differences: +.Bl -enum +.\"""""""""""""""""" +.It +.Fx Nm +supports destdir/metalog handling; +.Nx Nm +does not. +.\"""""""""""""""""" +.It +.Fx Nm +treats +.Pa /etc/ssl/certs +and +.Pa /etc/ssl/untrusted +both as configuration +.Em and +as caches; +.Nx Nm +treats +.Pa /etc/openssl/certs.conf +and +.Pa /etc/openssl/untrusted +as configuration, and treats +.Pa /etc/openssl/certs +strictly as a cache. +.Fx Nm +will forget any +.Nm Cm untrust +settings on +.Nm Cm rehash , +but +.Nx Nm +will remember them. +.\"""""""""""""""""" +.It +.Fx Nm +takes configuration through environment variables; +.Nx Nm +takes configuration through a file and command-line arguments. +.El +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Sh SEE ALSO +.Xr openssl 1 , +.Xr openssl_rehash 1 +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Sh HISTORY +.Nm +first appeared in +.Nx 10.0 . +A utility of the same name previously appeared in +.Fx 12.2 . Index: src/usr.sbin/certctl/certctl.sh diff -u /dev/null src/usr.sbin/certctl/certctl.sh:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/usr.sbin/certctl/certctl.sh Sat Aug 26 05:27:15 2023 @@ -0,0 +1,658 @@ +#!/bin/sh + +# $NetBSD: certctl.sh,v 1.1 2023/08/26 05:27:15 riastradh Exp $ +# +# Copyright (c) 2023 The NetBSD Foundation, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``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 FOUNDATION OR CONTRIBUTORS +# 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 -o pipefail +set -Ceu + +progname=$(basename -- "$0") + +### Options and arguments + +usage() +{ + exec >&2 + printf 'Usage: %s %s\n' \ + "$progname" \ + "[-nv] [-C <config>] [-c <certsdir>] [-u <untrusted>]" + printf ' <cmd> <args>...\n' + printf ' %s list\n' "$progname" + printf ' %s rehash\n' "$progname" + printf ' %s trust <cert>\n' "$progname" + printf ' %s untrust <cert>\n' "$progname" + printf ' %s untrusted\n' "$progname" + exit 1 +} + +certsdir=/etc/openssl/certs +config=/etc/openssl/certs.conf +distrustdir=/etc/openssl/untrusted +nflag=false # dry run +vflag=false # verbose + +# Options used by FreeBSD: +# +# -D destdir +# -M metalog +# -U (unprivileged) +# -d distbase +# +while getopts C:c:nu:v f; do + case $f in + C) config=$OPTARG;; + c) certsdir=$OPTARG;; + n) nflag=true;; + u) distrustdir=$OPTARG;; + v) vflag=true;; + \?) usage;; + esac +done +shift $((OPTIND - 1)) + +if [ $# -lt 1 ]; then + usage +fi +cmd=$1 + +### Global state + +config_paths= +config_manual=false +tmpfile= + +# If tmpfile is set to nonempty, clean it up on exit. + +trap 'test -n "$tmpfile" && rm -f "$tmpfile"' EXIT HUP INT TERM + +### Subroutines + +# error <msg> ... +# +# Print an error message to stderr. +# +# Does not exit the process. +# +error() +{ + echo "$progname:" "$@" >&2 +} + +# run <cmd> <args>... +# +# Print a command if verbose, and run it unless it's a dry run. +# +run() +{ + local t q cmdline + + if $vflag; then # print command if verbose + for t; do + case $t in + ''|*[^[:alnum:]+,-./:=_@]*) + # empty or unsafe -- quotify + ;; + *) + # nonempty and safe-only -- no quotify + cmdline="${cmdline:+$cmdline }$t" + continue + ;; + esac + q=$(printf '%s' "$t" | sed -e "s/'/'\\\''/g'") + cmdline="${cmdline:+$cmdline }'$q'" + done + printf '%s\n' "$cmdline" + fi + if ! $nflag; then # skip command if dry run + "$@" + fi +} + +# configure +# +# Parse the configuration file, initializing config_*. +# +configure() +{ + local lineno status formatok vconfig line contline op path vpath vop + + # Count line numbers, record a persistent error status to + # return at the end, and record whether we got a format line. + lineno=0 + status=0 + formatok=false + + # vis the config name for terminal-safe error messages. + vconfig=$(printf '%s' "$config" | vis -M) + + # Read and process each line of the config file. + while read -r line; do + lineno=$((lineno + 1)) + + # If the line ends in an odd number of backslashes, it + # has a continuation line, so read on. + while expr "$line" : '^\(\\\\\)*\\' >/dev/null || + expr "$line" : '^.*[^\\]\(\\\\\)*\\$' >/dev/null; do + if ! read -r contline; then + error "$vconfig:$lineno: premature end of file" + return 1 + fi + line="$line$contline" + done + + # Skip blank lines and comments. + case $line in + ''|'#'*) + continue + ;; + esac + + # Require the first non-blank/comment line to identify + # the config file format. + if ! $formatok; then + if [ "$line" = "netbsd-certctl 20230816" ]; then + formatok=true + continue + else + error "$vconfig:$lineno: missing format line" + status=1 + break + fi + fi + + # Split the line into words and dispatch on the first. + set -- $line + op=$1 + case $op in + manual) + config_manual=true + ;; + path) + if [ $# -lt 2 ]; then + error "$vconfig:$lineno: missing path" + status=1 + continue + fi + if [ $# -gt 3 ]; then + error "$vconfig:$lineno: excess args" + status=1 + continue + fi + + # Unvis the path. Hack: if the user has had + # the audacity to choose a path ending in + # newlines, prevent the shell from consuming + # them so we don't choke on their subterfuge. + path=$(printf '%s.' "$2" | unvis) + path=${path%.} + + # Ensure the path is absolute. It is unclear + # what directory it should be relative to if + # not. + case $path in + /*) + ;; + *) + error "$vconfig:$lineno:" \ + "relative path forbidden" + status=1 + continue + ;; + esac + + # Record the vis-encoded path in a + # space-separated list. + vpath=$(printf '%s' "$path" | vis -M) + config_paths="$config_paths $vpath" + ;; + *) + vop=$(printf '%s' "$op" | vis -M) + error "$vconfig:$lineno: unknown command: $vop" + ;; + esac + done <$config + + return $status +} + +# list_default_trusted +# +# List the vis-encoded certificate paths and their base names, +# separated by a space, for the certificates that are trusted by +# default according to the configuration. +# +# No order guaranteed; caller must sort. +# +list_default_trusted() +{ + local vpath path cert base vcert vbase + + for vpath in $config_paths; do + path=$(printf '%s.' "$vpath" | unvis) + path=${path%.} + + # Enumerate the .pem, .cer, and .crt files. + for cert in "$path"/*.pem "$path"/*.cer "$path"/*.crt; do + # vis the certificate path. + vcert=$(printf '%s' "$cert" | vis -M) + + # If the file doesn't exist, then either: + # + # (a) it's a broken symlink, so fail; + # or + # (b) the shell glob failed to match, + # so ignore it and move on. + if [ ! -e "$cert" ]; then + if [ -h "$cert" ]; then + error "broken symlink: $vcert" + status=1 + fi + continue + fi + + # Print the vis-encoded absolute path to the + # certificate and base name on a single line. + vbase=$(basename -- "$vcert.") + vbase=${vbase%.} + printf '%s %s\n' "$vcert" "$vbase" + done + done +} + +# list_distrusted +# +# List the vis-encoded certificate paths and their base names, +# separated by a space, for the certificates that have been +# distrusted by the user. +# +# No order guaranteed; caller must sort. +# +list_distrusted() +{ + local status link vlink cert vcert + + status=0 + + for link in "$distrustdir"/*; do + # vis the link for terminal-safe error messages. + vlink=$(printf '%s' "$link" | vis -M) + + # The distrust directory must only have symlinks to + # certificates. If we find a non-symlink, print a + # warning and arrange to fail. + if [ ! -h "$link" ]; then + if [ ! -e "$link" ] && \ + [ "$link" = "$distrustdir/*" ]; then + # Shell glob matched nothing -- just + # ignore it. + break + fi + error "distrusted non-symlink: $vlink" + status=1 + continue + fi + + # Read the target of the symlink, nonrecursively. If + # the user has had the audacity to make a symlink whose + # target ends in newline, prevent the shell from + # consuming them so we don't choke on their subterfuge. + cert=$(readlink -n -- "$link" && printf .) + cert=${cert%.} + + # Warn if the target is relative. Although it is clear + # what directory it would be relative to, there might + # be issues with canonicalization. + case $cert in + /*) + ;; + *) + vlink=$(printf '%s' "$link" | vis -M) + vcert=$(printf '%s' "$cert" | vis -M) + error "distrusted relative symlink: $vlink -> $vcert" + ;; + esac + + # Print the vis-encoded absolute path to the + # certificate and base name on a single line. + vcert=$(printf '%s' "$cert" | vis -M) + vbase=$(basename -- "$vcert.") + vbase=${vbase%.} + printf '%s %s\n' "$vcert" "$vbase" + done + + return $status +} + +# list_trusted +# +# List the trusted certificates, excluding the distrusted one, as +# one vis(3) line per certificate. Reject duplicate base names, +# since we will be creating symlinks to the same base names in +# the certsdir. Sorted lexicographically by vis-encoding. +# +list_trusted() +{ + + # XXX Use dev/ino to match files instead of symlink targets? + + { + list_default_trusted \ + | while read -r vcert vbase; do + printf 'trust %s %s\n' "$vcert" "$vbase" + done + + # XXX Find a good way to list the default-untrusted + # certificates, so if you have already distrusted one + # and it is removed from default-trust on update, + # nothing warns about this. + + # list_default_untrusted \ + # | while read -r vcert vbase; do + # printf 'distrust %s %s\n' "$vcert" "$vbase" + # done + + list_distrusted \ + | while read -r vcert vbase; do + printf 'distrust %s %s\n' "$vcert" "$vbase" + done + } | awk -v progname="$progname" ' + BEGIN { status = 0 } + $1 == "trust" && $3 in trust && $2 != trust[$3] { + printf "%s: duplicate base name %s\n %s\n %s\n", \ + progname, $3, trust[$3], $2 >"/dev/stderr" + status = 1 + next + } + $1 == "trust" { trust[$3] = $2 } + $1 == "distrust" && !trust[$3] && !distrust[$3] { + printf "%s: distrusted certificate not found: %s\n", \ + progname, $3 >"/dev/stderr" + status = 1 + } + $1 == "distrust" && $2 in trust && $2 != trust[$3] { + printf "%s: distrusted certificate %s" \ + " has multiple paths\n" \ + " %s\n %s\n", + progname, $3, trust[$3], $2 >"/dev/stderr" + status = 1 + } + $1 == "distrust" { distrust[$3] = 1 } + END { + for (vbase in trust) { + if (!distrust[vbase]) + print trust[vbase] + } + exit status + } + ' | sort -u +} + +# rehash +# +# Delete and rebuild certsdir. +# +rehash() +{ + local vcert cert certbase hash counter bundle vbundle + + # If manual operation is enabled, refuse to rehash the + # certsdir, but succeed anyway so this can safely be used in + # automated scripts. + if $config_manual; then + error "manual certificates enabled, not rehashing" + return + fi + + # Delete the active certificates symlink cache. + run rm -rf "$certsdir" + run mkdir "$certsdir" + + # Create a temporary file for the single-file bundle. This + # will be automatically deleted on normal exit or + # SIGHUP/SIGINT/SIGTERM. + if ! $nflag; then + tmpfile=$(mktemp -t "$progname.XXXXXX") + fi + + # Recreate symlinks for all of the trusted certificates. + list_trusted \ + | while read -r vcert; do + cert=$(printf '%s.' "$vcert" | unvis) + cert=${cert%.} + run ln -s -- "$cert" "$certsdir" + + # Add the certificate to the single-file bundle. + if ! $nflag; then + cat -- "$cert" >>$tmpfile + fi + done + + # Hash the directory with openssl. + # + # XXX Pass `-v' to openssl in a way that doesn't mix with our + # shell-safe verbose commands? (Need to handle `-n' too.) + run openssl rehash -- "$certsdir" + + # Install the single-file bundle. + bundle=$certsdir/ca-certificates.crt + vbundle=$(printf '%s' "$bundle" | vis -M) + $vflag && printf '# create %s\n' "$vbundle" + if ! $nflag; then + cp -- "$tmpfile" "$bundle" + rm -f -- "$tmpfile" + tmpfile= + fi +} + +### Commands + +usage_list() +{ + exec >&2 + printf 'Usage: %s list\n' "$progname" + exit 1 +} +cmd_list() +{ + test $# -eq 1 || usage_list + + configure + + list_trusted \ + | while read -r vcert vbase; do + printf '%s\n' "$vcert" + done +} + +usage_rehash() +{ + exec >&2 + printf 'Usage: %s rehash\n' "$progname" + exit 1 +} +cmd_rehash() +{ + test $# -eq 1 || usage_rehash + + configure + + rehash +} + +usage_trust() +{ + exec >&2 + printf 'Usage: %s trust <cert>\n' "$progname" + exit 1 +} +cmd_trust() +{ + local cert vcert certbase vcertbase + + test $# -eq 2 || usage_trust + cert=$2 + + configure + + # XXX Accept base name. + + # vis the certificate path for terminal-safe error messages. + vcert=$(printf '%s' "$cert" | vis -M) + + # Verify the certificate actually exists. + if [ ! -f "$cert" ]; then + error "no such certificate: $vcert" + return 1 + fi + + # Verify we currently distrust a certificate by this base name. + certbase=$(basename -- "$cert.") + certbase=${certbase%.} + if [ ! -h "$distrustdir/$certbase" ]; then + error "not currently distrusted: $vcert" + return 1 + fi + + # Verify the certificate we distrust by this base name is the + # same one. + target=$(readlink -n -- "$distrustdir/$certbase" && printf .) + target=${target%.} + if [ "$cert" != "$target" ]; then + vcertbase=$(basename -- "$vcert") + error "distrusted $vcertbase does not point to $vcert" + return 1 + fi + + # Remove the link from the distrusted directory, and rehash -- + # quietly, so verbose output emphasizes the distrust part and + # not the whole certificate set. + run rm -- "$distrustdir/$certbase" + $vflag && echo '# rehash' + vflag=false + rehash +} + +usage_untrust() +{ + exec >&2 + printf 'Usage: %s untrust <cert>\n' "$progname" + exit 1 +} +cmd_untrust() +{ + local cert vcert certbase vcertbase target vtarget + + test $# -eq 2 || usage_untrust + cert=$2 + + configure + + # vis the certificate path for terminal-safe error messages. + vcert=$(printf '%s' "$cert" | vis -M) + + # Verify the certificate actually exists. Otherwise, you might + # fail to distrust a certificate you intended to distrust, + # e.g. if you made a typo in its path. + if [ ! -f "$cert" ]; then + error "no such certificate: $vcert" + return 1 + fi + + # Check whether this certificate is already distrusted. + # - If the same base name points to the same path, stop here. + # - Otherwise, fail noisily. + certbase=$(basename "$cert.") + certbase=${certbase%.} + if [ -h "$distrustdir/$certbase" ]; then + target=$(readlink -n -- "$distrustdir/$certbase" && printf .) + target=${target%.} + if [ "$target" = "$cert" ]; then + $vflag && echo '# already distrusted' + return + fi + vcertbase=$(printf '%s' "$certbase" | vis -M) + vtarget=$(printf '%s' "$target" | vis -M) + error "distrusted $vcertbase at different path $vtarget" + return 1 + fi + + # Create the distrustdir if needed, create a symlink in it, and + # rehash -- quietly, so verbose output emphasizes the distrust + # part and not the whole certificate set. + test -d "$distrustdir" || run mkdir -- "$distrustdir" + run ln -s -- "$cert" "$distrustdir" + $vflag && echo '# rehash' + vflag=false + rehash +} + +usage_untrusted() +{ + exec >&2 + printf 'Usage: %s untrusted\n' "$progname" + exit 1 +} +cmd_untrusted() +{ + test $# -eq 1 || usage_untrusted + + configure + + list_distrusted \ + | while read -r vcert vbase; do + printf '%s\n' "$vcert" + done +} + +### Main + +# We accept the following aliases for user interface compatibility with +# FreeBSD: +# +# blacklist = untrust +# blacklisted = untrusted +# unblacklist = trust + +case $cmd in +list) cmd_list "$@" + ;; +rehash) cmd_rehash "$@" + ;; +trust|unblacklist) + cmd_trust "$@" + ;; +untrust|blacklist) + cmd_untrust "$@" + ;; +untrusted|blacklisted) + cmd_untrusted "$@" + ;; +*) vcmd=$(printf '%s' "$cmd" | vis -M) + printf '%s: unknown command: %s\n' "$progname" "$vcmd" >&2 + usage + ;; +esac Index: src/usr.sbin/certctl/certs.conf diff -u /dev/null src/usr.sbin/certctl/certs.conf:1.1 --- /dev/null Sat Aug 26 05:27:15 2023 +++ src/usr.sbin/certctl/certs.conf Sat Aug 26 05:27:15 2023 @@ -0,0 +1,13 @@ +netbsd-certctl 20230816 + +# $NetBSD: certs.conf,v 1.1 2023/08/26 05:27:15 riastradh Exp $ +# +# Configuration file for certctl(8) to manage HTTPS root CA +# certificates in /etc/openssl/certs. +# + +path /usr/share/certs/mozilla/server + +# For manual control over /etc/openssl/certs, e.g. if you want to +# install a separate CA bundle from pkgsrc, uncomment the next line: +#manual