From f84716c064312dd9dc0d149f0ec7a12f5c88c3af Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Wed, 26 Apr 2023 17:41:24 +0200 Subject: tests/account-encrypted-*: Set TERM="linux". --- tests/account-encrypted-gpg | 2 +- tests/account-encrypted-openssl | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/account-encrypted-gpg b/tests/account-encrypted-gpg index fd1e4ac..7cb978d 100644 --- a/tests/account-encrypted-gpg +++ b/tests/account-encrypted-gpg @@ -9,7 +9,7 @@ keyid="$(gpg --list-secret-key --with-colons | grep -m1 ^fpr: | cut -sd: -f10)" gpg --encrypt -r "$keyid" /etc/lacme/account.key sed -ri '0,\|^#?privkey\s*=.*| {s||privkey = gpg:/etc/lacme/account.key.gpg|}' /etc/lacme/lacme-accountd.conf -export GPG_TTY="$(tty)" +export GPG_TTY="$(tty)" TERM="linux" lacme account # vim: set filetype=sh : diff --git a/tests/account-encrypted-openssl b/tests/account-encrypted-openssl index e79a528..a3ad707 100644 --- a/tests/account-encrypted-openssl +++ b/tests/account-encrypted-openssl @@ -5,6 +5,7 @@ PASSPHRASE="test" openssl rsa -aes128 -passout pass:"$PASSPHRASE" /etc/lacme/account.enc.key sed -ri '0,\|^#?privkey\s*=.*| {s||privkey = file:/etc/lacme/account.enc.key|}' /etc/lacme/lacme-accountd.conf +export TERM="linux" lacme account # vim: set filetype=sh : -- cgit v1.2.3 From a41444b8b1fe5349a4a33c45f1e96036845609bb Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 13 Jun 2024 03:33:11 +0200 Subject: t/cert-install: Ensure the subjectName is lowercase. Domain names are case insensitive so it shouldn't matter, but Let's Encrypt (staging) ACME server fails with 400 Bad Request (Invalid identifiers requested :: Cannot issue for "YXJCTT7S6K2RQLVO.lacme-test.guilhem.org": Domain name contains an invalid character) if the sub-domain part of the subjectName is left all-caps. --- tests/cert-install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/cert-install b/tests/cert-install index 4b3e820..4182790 100644 --- a/tests/cert-install +++ b/tests/cert-install @@ -30,7 +30,7 @@ grepstderr -Fxq "[bad3] Warning: Couldn't generate CSR, skipping" # 'certificate' installs only the leaf certificate openssl genpkey -algorithm RSA -out /etc/lacme/test1.key -subject="/CN=$(head -c10 /dev/urandom | base32 -w0).$DOMAINNAME" +subject="/CN=$(head -c10 /dev/urandom | base32 -w0 | tr "A-Z" "a-z").$DOMAINNAME" cat >"/etc/lacme/lacme-certs.conf.d/test1.conf" <<- EOF [test1] certificate-key = /etc/lacme/test1.key -- cgit v1.2.3 From 568656b1fcb60d451b4a5313876ef0b96ae8bbfd Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 13 Jun 2024 14:30:30 +0200 Subject: t/cert-extensions: Fix tr(1) range syntax. --- tests/cert-extensions | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/tests/cert-extensions b/tests/cert-extensions index a397ee5..bc40298 100644 --- a/tests/cert-extensions +++ b/tests/cert-extensions @@ -10,7 +10,7 @@ x509_check() { # default settings (the ACME server adds a subjectAltName with the Common Name) openssl genpkey -algorithm RSA -out /etc/lacme/test1.key -commonName="$(head -c10 /dev/urandom | base32 -w0 | tr "[A-Z]" "[a-z]").$DOMAINNAME" +commonName="$(head -c10 /dev/urandom | base32 -w0 | tr "A-Z" "a-z").$DOMAINNAME" cat >"/etc/lacme/lacme-certs.conf.d/test1.conf" <<- EOF [test1] certificate-key = /etc/lacme/test1.key @@ -34,10 +34,10 @@ EOF # subjectAltName openssl genpkey -algorithm RSA -out /etc/lacme/test2.key -commonName="$(head -c10 /dev/urandom | base32 -w0 | tr "[A-Z]" "[a-z]").$DOMAINNAME" +commonName="$(head -c10 /dev/urandom | base32 -w0 | tr "A-Z" "a-z").$DOMAINNAME" subjectAltName="" for i in $(seq 1 8); do - subjectAltName="${subjectAltName:+"$subjectAltName "}$(head -c10 /dev/urandom | base32 -w0 | tr "[A-Z]" "[a-z]").$DOMAINNAME" + subjectAltName="${subjectAltName:+"$subjectAltName "}$(head -c10 /dev/urandom | base32 -w0 | tr "A-Z" "a-z").$DOMAINNAME" done cat >"/etc/lacme/lacme-certs.conf.d/test2.conf" <<- EOF [test2] @@ -63,7 +63,7 @@ EOF # tlsfeature openssl genpkey -algorithm RSA -out /etc/lacme/test3.key -commonName="$(head -c10 /dev/urandom | base32 -w0 | tr "[A-Z]" "[a-z]").$DOMAINNAME" +commonName="$(head -c10 /dev/urandom | base32 -w0 | tr "A-Z" "a-z").$DOMAINNAME" cat >"/etc/lacme/lacme-certs.conf.d/test3.conf" <<- EOF [test3] certificate-key = /etc/lacme/test3.key -- cgit v1.2.3 From bf4d2d13ffcd894c6e7765dbd366f1163c69c9e1 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 13 Jun 2024 03:33:20 +0200 Subject: Pass `-in /dev/stdin` option to openssl(1) to avoid warning with recent versions. OpenSSL 3.2 from Debian sid spews Warning: Reading certificate from stdin since no -in or -new option is given without an explicit `-in /dev/stdin`. --- tests/account-encrypted-openssl | 2 +- tests/cert-extensions | 2 +- tests/cert-install | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/tests/account-encrypted-openssl b/tests/account-encrypted-openssl index a3ad707..1f97fd0 100644 --- a/tests/account-encrypted-openssl +++ b/tests/account-encrypted-openssl @@ -2,7 +2,7 @@ PASSPHRASE="test" -openssl rsa -aes128 -passout pass:"$PASSPHRASE" /etc/lacme/account.enc.key +openssl rsa -in /etc/lacme/account.key -out /etc/lacme/account.enc.key -aes128 -passout pass:"$PASSPHRASE" sed -ri '0,\|^#?privkey\s*=.*| {s||privkey = file:/etc/lacme/account.enc.key|}' /etc/lacme/lacme-accountd.conf export TERM="linux" diff --git a/tests/cert-extensions b/tests/cert-extensions index bc40298..d7e7855 100644 --- a/tests/cert-extensions +++ b/tests/cert-extensions @@ -4,7 +4,7 @@ x509_check() { local cert="$1" ext out out="$(mktemp --tmpdir)" ext="basicConstraints,subjectAltName,keyUsage,extendedKeyUsage,tlsfeature" - openssl x509 -noout -subject -ext "$ext" -nameopt compat <"$cert" >"$out" + openssl x509 -in "$cert" -noout -subject -ext "$ext" -nameopt compat >"$out" diff --unified --color=auto -b --label="a/${cert#/}" --label="b/${cert#/}" -- - "$out" } diff --git a/tests/cert-install b/tests/cert-install index 4182790..e24fe34 100644 --- a/tests/cert-install +++ b/tests/cert-install @@ -46,9 +46,9 @@ diff --unified /etc/lacme/test1.crt /etc/lacme/test1.pem check_hash() { local p1="$1" p2 s1 s2 - s1="$(openssl x509 -noout -hash <"$p1")" + s1="$(openssl x509 -in "$p1" -noout -hash)" for p2 in /usr/share/lacme/ca-certificates.pem.*; do - s2="$(openssl x509 -noout -hash <"$p2")" + s2="$(openssl x509 -in "$p2" -noout -hash)" if [ "$s1" = "$s2" ]; then return 0 fi -- cgit v1.2.3 From 9cb882a468843bf8ce9598de8769d5baaaaae3ea Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 13 Jun 2024 03:32:04 +0200 Subject: Fix post-issuance validation logic. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than adding intermediates in the certificate bundle we now validate the leaf certificate with intermediates as untrusted (used for chain building only). Only the root certificates are used as trust anchor. Not pining intermediate certificates anymore is in line with Let's Encrypt's latest recommendations: Rotating the set of intermediates we issue from helps keep the Internet agile and more secure. It encourages automation and efficiency, and discourages outdated practices like key pinning. “Key Pinning” is a practice in which clients — either ACME clients getting certificates for their site, or apps connecting to their own backend servers — decide to trust only a single issuing intermediate certificate rather than delegating trust to the system trust store. Updating pinned keys is a manual process, which leads to an increased risk of errors and potential business continuity failures. — https://letsencrypt.org/2024/03/19/new-intermediate-certificates: --- tests/cert-install | 82 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 29 deletions(-) (limited to 'tests') diff --git a/tests/cert-install b/tests/cert-install index e24fe34..279309f 100644 --- a/tests/cert-install +++ b/tests/cert-install @@ -28,6 +28,55 @@ EOF grepstderr -Fxq "[bad3] Warning: Couldn't generate CSR, skipping" +check_spki() { + local p1="$1" p2="$2" s1 s2 + s1="$(openssl x509 -in "$p1" -noout -pubkey \ + | openssl pkey -pubin -outform DER \ + | openssl dgst -sha256 \ + | sed 's/.*=\s*//')" + s2="$(openssl pkey -in "$p2" -pubout -outform DER \ + | openssl dgst -sha256 \ + | sed 's/.*=\s*//')" + if [ -n "$s1" ] && [ "$s1" = "$s2" ]; then + return 0 + else + printf "%s != %s\\n" "$s1" "$s2" >&2 + return 1 + fi +} +check_chain() { + local priv="$1" chain="$2" leaf="${3-}" pem0 + + csplit -f "${chain%.crt}.chain.pem" "$chain" \ + "/-----BEGIN CERTIFICATE-----/" "{*}" + + pem0="${chain%.crt}.chain.pem00" + if [ ! -s "$pem0" ]; then + # 00 is empty, leaf cert is at 01 + rm -f -- "$pem0" + pem0="${chain%.crt}.chain.pem01" + fi + test -s "$pem0" || return 1 + check_spki "$pem0" "$priv" + + if [ -n "$leaf" ]; then + diff --ignore-blank-lines --unified "$pem0" "$leaf" || return 1 + fi + + leaf="${chain%.crt}.leaf.pem" + mv -T -- "$pem0" "$leaf" + + intermediates="${chain%.crt}.intermediates.pem" + sed "/^$/d" "${chain%.crt}.chain.pem"[0-9]* >"$intermediates" + test -s "$intermediates" || return 1 # ensure there is at least one intermediate + + openssl verify -trusted /usr/share/lacme/ca-certificates.crt \ + -untrusted "$intermediates" \ + -purpose sslserver -x509_strict \ + -show_chain \ + -- "$leaf" || return 1 +} + # 'certificate' installs only the leaf certificate openssl genpkey -algorithm RSA -out /etc/lacme/test1.key subject="/CN=$(head -c10 /dev/urandom | base32 -w0 | tr "A-Z" "a-z").$DOMAINNAME" @@ -42,23 +91,9 @@ lacme newOrder test1 2>"$STDERR" || fail newOrder test1 test /etc/lacme/test1.crt -nt /etc/lacme/test1.key sed -n "0,/^-----END CERTIFICATE-----$/ p" /etc/lacme/test1.crt >/etc/lacme/test1.pem diff --unified /etc/lacme/test1.crt /etc/lacme/test1.pem +check_spki /etc/lacme/test1.crt /etc/lacme/test1.key -check_hash() { - local p1="$1" p2 s1 s2 - s1="$(openssl x509 -in "$p1" -noout -hash)" - for p2 in /usr/share/lacme/ca-certificates.pem.*; do - s2="$(openssl x509 -in "$p2" -noout -hash)" - if [ "$s1" = "$s2" ]; then - return 0 - fi - done - return 1 -} -csplit -f /usr/share/lacme/ca-certificates.pem. /usr/share/lacme/ca-certificates.crt \ - "/-----BEGIN CERTIFICATE-----/" "{*}" -rm -f /usr/share/lacme/ca-certificates.pem.00 - # 'certificate-chain' appends the chain of trust openssl genpkey -algorithm RSA -out /etc/lacme/test2.key cat >"/etc/lacme/lacme-certs.conf.d/test2.conf" <<- EOF @@ -70,16 +105,7 @@ EOF lacme newOrder test2 2>"$STDERR" || fail newOrder test2 test /etc/lacme/test2.crt -nt /etc/lacme/test2.key -csplit -f /etc/lacme/test2.chain.pem /etc/lacme/test2.crt \ - "/-----BEGIN CERTIFICATE-----/" "{*}" -test -s /etc/lacme/test2.chain.pem01 # leaf cert (00 is empty) -rm -f /etc/lacme/test2.chain.pem0[01] -test -s /etc/lacme/test2.chain.pem02 # depth 1 - -# all certificates at depth >=1 must be in our CA bundle -for p in /etc/lacme/test2.chain.pem*; do - check_hash "$p" -done +check_chain /etc/lacme/test2.key /etc/lacme/test2.crt # 'certificate' + 'certificate-chain' openssl genpkey -algorithm RSA -out /etc/lacme/test3.key @@ -94,10 +120,8 @@ EOF lacme newOrder test3 2>"$STDERR" || fail newOrder test3 test /etc/lacme/test3.pem -nt /etc/lacme/test3.key test /etc/lacme/test3.crt -nt /etc/lacme/test3.key -csplit -f /etc/lacme/test3.chain.pem /etc/lacme/test3.crt \ - "/-----BEGIN CERTIFICATE-----/" "{*}" -sed -i "/^$/d" /etc/lacme/test3.chain.pem* -diff -q /etc/lacme/test3.chain.pem01 /etc/lacme/test3.pem +check_chain /etc/lacme/test3.key /etc/lacme/test3.crt /etc/lacme/test3.pem + st="$(stat -c "%U:%G %#a" /etc/lacme/test3.pem)" [ "$st" = "root:root 0644" ] st="$(stat -c "%U:%G %#a" /etc/lacme/test3.crt)" -- cgit v1.2.3 From 98e4397f5330245cb7f8a21054ab078c4d0bba82 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 13 Jun 2024 15:54:11 +0200 Subject: Fix test suite. Since we don't pin staging intermediate certificates anymore we drop the test where the CA bundle contains only intermediates. --- tests/cert-verify | 22 +++++----------------- tests/old-lacme | 9 +++++---- 2 files changed, 10 insertions(+), 21 deletions(-) (limited to 'tests') diff --git a/tests/cert-verify b/tests/cert-verify index 4d254c6..a6cd336 100644 --- a/tests/cert-verify +++ b/tests/cert-verify @@ -8,31 +8,19 @@ for ca in /usr/share/lacme/letsencrypt-stg-root-*.pem; do done update-ca-certificates -# test (modified) trust store for intermediate certificates -openssl verify -no-CAfile -CApath /etc/ssl/certs -show_chain /usr/share/lacme/letsencrypt-stg-int-*.pem -openssl verify -no-CApath -CAfile /etc/ssl/certs/ca-certificates.crt -show_chain /usr/share/lacme/letsencrypt-stg-int-*.pem +# test (modified) trust store +openssl verify -no-CAfile -CApath /etc/ssl/certs -show_chain /usr/share/lacme/letsencrypt-stg-root-x1.pem +openssl verify -no-CApath -CAfile /etc/ssl/certs/ca-certificates.crt -show_chain /usr/share/lacme/letsencrypt-stg-root-x1.pem mv /usr/share/lacme/ca-certificates.crt /usr/share/lacme/ca-certificates.crt.back ! lacme newOrder 2>"$STDERR" || fail -grepstderr -Fxq "Could not open file or uri for loading certs of trusted certificates from /usr/share/lacme/ca-certificates.crt" +grepstderr -Fq "Could not open file or uri for loading trusted certificates from /usr/share/lacme/ca-certificates.crt:" grepstderr -Fxq "[simpletest-rsa] Error: Received invalid X.509 certificate from ACME server!" # verification error for unrelated CA bundle cat /etc/ssl/certs/ssl-cert-snakeoil.pem >/usr/share/lacme/ca-certificates.crt ! lacme newOrder 2>"$STDERR" || fail -grepstderr -Fxq "error 20 at 0 depth lookup: unable to get local issuer certificate" -grepstderr -Fxq "[simpletest-rsa] Error: Received invalid X.509 certificate from ACME server!" - -# verification error when the CA bundle contains only the root certificates -cat /usr/share/lacme/letsencrypt-stg-root-*.pem >/usr/share/lacme/ca-certificates.crt -! lacme newOrder 2>"$STDERR" || fail -grepstderr -Fxq "error 20 at 0 depth lookup: unable to get local issuer certificate" -grepstderr -Fxq "[simpletest-rsa] Error: Received invalid X.509 certificate from ACME server!" - -# verification error when the CA bundle contains only the intermediate certificates -cat /usr/share/lacme/letsencrypt-stg-int-*.pem >/usr/share/lacme/ca-certificates.crt -! lacme newOrder 2>"$STDERR" || fail -grepstderr -Fxq "error 2 at 1 depth lookup: unable to get issuer certificate" +grepstderr -Fxq "error 20 at 1 depth lookup: unable to get local issuer certificate" grepstderr -Fxq "[simpletest-rsa] Error: Received invalid X.509 certificate from ACME server!" # use saved bundle as custom CAfile diff --git a/tests/old-lacme b/tests/old-lacme index b1c9f88..278a705 100644 --- a/tests/old-lacme +++ b/tests/old-lacme @@ -1,5 +1,6 @@ -# IPC test between recent lacme-accountd(1) and ancient lacme(8) 0.5 from Debian buster -# (we don't try earlier versions as we need v2 support of the ACME API) +# IPC test between recent lacme-accountd(1) and ancient lacme(8) 0.8 from Debian Bullseye +# (we don't try earlier versions as we need v2 support of the ACME API +# and non-pinned intermediates) adduser --disabled-password \ --home /home/lacme-account \ @@ -14,12 +15,12 @@ cat >~lacme-account/.config/lacme/lacme-accountd.conf <<-EOF privkey = file:/etc/lacme/account.key EOF -echo "deb http://deb.debian.org/debian buster main" >>/etc/apt/sources.list +echo "deb http://deb.debian.org/debian bullseye main" >>/etc/apt/sources.list DEBIAN_FRONTEND="noninteractive" apt update DEBIAN_FRONTEND="noninteractive" apt install -y --no-install-recommends \ --reinstall --allow-downgrades \ -oDPkg::Options::="--force-confdef" -oDPkg::Options::="--force-overwrite" \ - lacme/buster + lacme/bullseye # restore staging environment mv -f /usr/share/lacme/ca-certificates.crt.back /usr/share/lacme/ca-certificates.crt -- cgit v1.2.3