aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog17
-rw-r--r--Makefile6
-rwxr-xr-xclient39
-rwxr-xr-xlacme28
-rwxr-xr-xlacme-accountd2
-rwxr-xr-xtest2
-rw-r--r--tests/account-encrypted-gpg2
-rw-r--r--tests/account-encrypted-openssl1
-rw-r--r--tests/accountd1
-rw-r--r--tests/accountd-kid4
-rw-r--r--tests/cert-revoke4
-rw-r--r--tests/cert-verify2
-rw-r--r--tests/drop-privileges4
-rw-r--r--tests/old-accountd3
-rw-r--r--tests/old-lacme1
15 files changed, 70 insertions, 46 deletions
diff --git a/Changelog b/Changelog
index d63c754..2863d18 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,14 @@
+lacme (0.8.2) upstream;
+
+ + client: Handle "ready" → "processing" → "valid" status change during
+ newOrder, instead of just "ready" → "valid". The latter may be what
+ we observe when the server is fast enough, but according to RFC 8555
+ sec. 7.1.6 the state actually transitions via "processing" state and
+ we need to account for that.
+ - Test suite: Point stretch's archive URL to archive.d.o.
+
+ -- Guilhem Moulin <guilhem@fripost.org> Tue, 25 Apr 2023 20:06:22 +0200
+
lacme (0.8.1) upstream;
+ lacme-accountd: improve log messages and refactor logging logic.
@@ -11,6 +22,8 @@ lacme (0.8.1) upstream;
'chmod'.
+ lacme: split certificates using Net::SSLeay::PEM_* instead of calling
openssl.
+ + lacme: pass a temporary JSON file with the client configuration to
+ the internal client, so it doesn't have to parse the INI file again.
- lacme: in the [accountd] config, let lacme-accountd(1) do the
%-expansion for 'config', not lacme(8) when building the command.
- lacme-accountd: don't log debug messages unless --debug is set.
@@ -23,8 +36,10 @@ lacme (0.8.1) upstream;
- lacme: ignore empty values in settings 'chown', 'chmod', 'certificate'
and 'certificate-chain'.
- lacme: return an error when the 'mode'/'chown' isn't a number.
+ - Makefile: replace '$(dir $@)' with '$(@D)'.
+ - Test suite: Adjust against current Let's Encrypt staging environment.
- -- Guilhem Moulin <guilhem@fripost.org> Mon, 22 Feb 2021 12:04:28 +0100
+ -- Guilhem Moulin <guilhem@fripost.org> Wed, 25 Jan 2023 03:23:51 +0100
lacme (0.8.0) upstream;
diff --git a/Makefile b/Makefile
index 16ac04e..10e55c5 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ $(BUILDDIR)/certs/ca-certificates.crt: \
certs/isrg-root-x2.pem \
certs/lets-encrypt-r[34].pem \
certs/lets-encrypt-e[12].pem
- mkdir -pv -- $(dir $@)
+ mkdir -pv -- $(@D)
cat -- $^ >$@
# Staging Environment for tests, see https://letsencrypt.org/docs/staging-environment/
@@ -27,7 +27,7 @@ $(BUILDDIR)/certs-staging/ca-certificates.crt: \
certs-staging/letsencrypt-stg-root-x[12].pem \
certs-staging/letsencrypt-stg-int-r[34].pem \
certs-staging/letsencrypt-stg-int-e[12].pem
- mkdir -pv -- $(dir $@)
+ mkdir -pv -- $(@D)
cat -- $^ >$@
prefix ?= $(DESTDIR)
@@ -52,7 +52,7 @@ lacme_client_group ?= nogroup
acmeapi_server ?= https://acme-v02.api.letsencrypt.org/directory
$(BUILDDIR)/%: %
- mkdir -pv -- $(dir $@)
+ mkdir -pv -- $(@D)
cp --no-dereference --preserve=mode,links,xattr -vfT -- "$<" "$@"
sed -i "s#@@bindir@@#$(bindir)#g; \
s#@@sbindir@@#$(sbindir)#g; \
diff --git a/client b/client
index 33189d3..d993518 100755
--- a/client
+++ b/client
@@ -43,7 +43,7 @@ use warnings;
# instance own by another user and created with umask 0177) is not a
# problem since SOCKET_FD can be bound as root prior to the execve(2).
-our $VERSION = '0.8.0';
+our $VERSION = '0.8.2';
my $PROTOCOL_VERSION = 1;
my $NAME = 'lacme-client';
@@ -56,8 +56,6 @@ use Date::Parse ();
use LWP::UserAgent ();
use JSON ();
-use Config::Tiny ();
-
# Clean up PATH
$ENV{PATH} = join ':', qw{/usr/bin /bin};
delete @ENV{qw/IFS CDPATH ENV BASH_ENV/};
@@ -107,11 +105,7 @@ do {
my $CONFIG = do {
my $conf = do { local $/ = undef; <$CONFFILE> };
- close $CONFFILE or die "close: $!";
- my $h = Config::Tiny::->read_string($conf) or die Config::Tiny::->errstr()."\n";
- $h->{_} //= {};
- $h->{client}->{$_} //= $h->{_}->{$_} foreach keys %{$h->{_}}; # add defaults
- $h->{client};
+ JSON::->new->decode($conf);
};
my $UA = do {
my %args = %$CONFIG;
@@ -352,11 +346,12 @@ elsif ($COMMAND eq 'newOrder') {
}
# poll the order URL (to get the status of all challenges at once)
- # until the status become 'valid'
+ # until the status become 'valid'; see RFC 8555 sec. 7.1.6 for the
+ # the status change flow
my $orderstr = join(', ', map {uc($_->{type}) .":". $_->{value}} @identifiers);
my $certuri;
- for (my $i = 0;;) {
- my $r = acme($orderurl);
+ for (my $i = 0, my $url = $orderurl, my $payload;;) {
+ my $r = acme($url => $payload);
my $resp = request_json_decode($r);
if (defined (my $problem = $resp->{error})) { # problem document (RFC 7807)
my $msg = $problem->{status};
@@ -367,19 +362,21 @@ elsif ($COMMAND eq 'newOrder') {
my $status = $resp->{status};
if (!defined $status or $status eq "invalid") {
die "Error: Invalid order $orderstr\n";
- }
- elsif ($status eq "ready") {
- my $r = acme($order->{finalize}, {csr => encode_base64url($csr)});
- my $resp = request_json_decode($r);
- $certuri = $resp->{certificate};
- last;
- }
- elsif ($status eq "valid") {
+ } elsif ($status eq "pending") {
+ # keep retrying
+ } elsif ($status eq "ready") {
+ $url = $order->{finalize};
+ $payload = {csr => encode_base64url($csr)};
+ # retry after moving to "processing" or "valid" state
+ next;
+ } elsif ($status eq "processing") {
+ $url = $orderurl;
+ undef $payload;
+ } elsif ($status eq "valid") {
$certuri = $resp->{certificate} //
die "Error: Missing \"certificate\" field in \"valid\" order\n";
last;
- }
- elsif ($status ne "pending" and $status ne "processing") {
+ } else {
warn "Unknown order status: $status\n";
}
diff --git a/lacme b/lacme
index 13c2ef5..6284c66 100755
--- a/lacme
+++ b/lacme
@@ -22,7 +22,7 @@ use v5.14.2;
use strict;
use warnings;
-our $VERSION = '0.8.0';
+our $VERSION = '0.8.2';
my $NAME = 'lacme';
use Errno 'EINTR';
@@ -37,13 +37,14 @@ use Socket 1.95 qw/AF_UNIX AF_INET AF_INET6 PF_UNIX PF_INET PF_INET6 PF_UNSPEC
use Config::Tiny ();
use Date::Parse ();
+use JSON ();
use Net::SSLeay 1.46 ();
# Clean up PATH
$ENV{PATH} = join ':', qw{/usr/bin /bin};
delete @ENV{qw/IFS CDPATH ENV BASH_ENV/};
-my ($COMMAND, %OPTS, $CONFFILE, $CONFIG, @CLEANUP);
+my ($COMMAND, %OPTS, $CONFIG, @CLEANUP);
$SIG{$_} = sub() { exit 1 } foreach qw/INT TERM/; # run the END block upon SIGINT/SIGTERM
@@ -99,14 +100,12 @@ sub spec_expand($) {
return $str;
}
-sub set_FD_CLOEXEC($$);
my $CONFFILENAME = spec_expand($OPTS{config} // "%E/lacme/$NAME.conf");
do {
print STDERR "Using configuration file: $CONFFILENAME\n" if $OPTS{debug};
- open $CONFFILE, '<', $CONFFILENAME or die "Can't open $CONFFILENAME: $!\n";
- my $conf = do { local $/ = undef; <$CONFFILE> };
- # don't close $CONFFILE so we can pass it to the client
- set_FD_CLOEXEC($CONFFILE, 1);
+ open my $fh, '<', $CONFFILENAME or die "Can't open $CONFFILENAME: $!\n";
+ my $conf = do { local $/ = undef; <$fh> };
+ close $fh or die "close: $!";
my $h = Config::Tiny::->read_string($conf) or die Config::Tiny::->errstr()."\n";
my $defaults = delete $h->{_} // {};
@@ -573,19 +572,26 @@ sub acme_client($@) {
die "connect: $!";
}
}
+ set_FD_CLOEXEC($client, 1);
+
+ my $client_config;
+ do {
+ my $tmp = File::Temp::->new(TMPDIR => 1, TEMPLATE => "lacme-client.conf.json-XXXXXXXXXX", UNLINK => 1) // die;
+ print $tmp JSON::->new->encode($conf);
+ open $client_config, "<", $tmp->filename() or die "open: $!";
+ };
# use execve(2) rather than a Perl pseudo-process to ensure that the
# child doesn't have access to the parent's memory
my ($cmd, @args2) = split(/\s+/, $conf->{command}) or die "Empty client command\n";
- my @fileno = map { fileno($_) =~ /^(\d+)$/ ? $1 : die } ($CONFFILE, $client); # untaint fileno
- set_FD_CLOEXEC($client, 1);
+ my @fileno = map { fileno($_) =~ /^(\d+)$/ ? $1 : die } ($client_config, $client); # untaint fileno
my $rv = spawn({in => $args->{in}, out => $args->{out}, child => sub() {
drop_privileges($conf->{user}, $conf->{group}, $args->{chdir} // '/');
umask(0022) // die;
- set_FD_CLOEXEC($_, 0) foreach ($CONFFILE, $client);
- seek($CONFFILE, SEEK_SET, 0) or die "seek: $!";
+ set_FD_CLOEXEC($_, 0) for ($client_config, $client);
$ENV{DEBUG} = $OPTS{debug} // 0;
}}, $cmd, @args2, $COMMAND, @fileno, @args);
+ close $client_config or die "close: $!\n";
if (defined $cleanup) {
@CLEANUP = grep { $_ ne $cleanup } @CLEANUP;
diff --git a/lacme-accountd b/lacme-accountd
index 98c11ad..8d2c599 100755
--- a/lacme-accountd
+++ b/lacme-accountd
@@ -23,7 +23,7 @@ use v5.14.2;
use strict;
use warnings;
-our $VERSION = '0.8.0';
+our $VERSION = '0.8.2';
my $PROTOCOL_VERSION = 1;
my $NAME = 'lacme-accountd';
diff --git a/test b/test
index 5200974..1606151 100755
--- a/test
+++ b/test
@@ -67,7 +67,7 @@ else
if [ -f "tests/$t" ]; then
TESTS+=( "$t" )
else
- echo "Error: '$1': no such test" >&2
+ echo "Error: '$t': no such test" >&2
exit 1
fi
done
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.key >/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 :
diff --git a/tests/accountd b/tests/accountd
index 7e8fd4c..433f8ad 100644
--- a/tests/accountd
+++ b/tests/accountd
@@ -65,6 +65,7 @@ grep -F "Error: " ~lacme-account/.local/share/lacme/accountd.log
# rotate the log and start accountd
rm -f ~lacme-account/.local/share/lacme/accountd.log
runuser -u lacme-account -- lacme-accountd --socket="$SOCKET" --quiet & PID=$!
+sleep 1
# run lacme(8) multiple times using that single lacme-accountd(1) instance
lacme --socket="$SOCKET" --debug account 2>"$STDERR" || fail
diff --git a/tests/accountd-kid b/tests/accountd-kid
index 1f282fd..8a4b53c 100644
--- a/tests/accountd-kid
+++ b/tests/accountd-kid
@@ -23,6 +23,7 @@ EOF
SOCKET=~lacme-account/S.lacme
runuser -u lacme-account -- lacme-accountd --socket="$SOCKET" --quiet & PID=$!
+sleep 1
# newAccount resource fails as per RFC 8555 sec. 6.2 it requires a JWK
! lacme --socket="$SOCKET" account 2>"$STDERR" || fail
@@ -37,6 +38,7 @@ wait
rm ~lacme-account/.local/share/lacme/accountd.log
runuser -u lacme-account -- lacme-accountd --socket="$SOCKET" --quiet & PID=$!
+sleep 1
# newOrder works fine without JWK
lacme --socket="$SOCKET" newOrder
@@ -46,7 +48,7 @@ test /etc/lacme/simpletest.rsa.crt -nt /etc/lacme/simpletest.rsa.key
lacme --socket="$SOCKET" revokeCert /etc/lacme/simpletest.rsa.crt
! lacme --socket="$SOCKET" revokeCert /etc/lacme/simpletest.rsa.crt 2>"$STDERR" || fail
grepstderr -Fxq "Revoking /etc/lacme/simpletest.rsa.crt"
-grepstderr -Fxq "400 Bad Request (Certificate already revoked)"
+grepstderr -Fq "400 Bad Request (unable to revoke"
grepstderr -Fxq "Warning: Couldn't revoke /etc/lacme/simpletest.rsa.crt"
kill $PID
diff --git a/tests/cert-revoke b/tests/cert-revoke
index f3d585e..179ccba 100644
--- a/tests/cert-revoke
+++ b/tests/cert-revoke
@@ -18,7 +18,7 @@ test /etc/lacme/simpletest.ecdsa.crt -nt /etc/lacme/simpletest.ecdsa.key
lacme revokeCert /etc/lacme/simpletest.ecdsa.crt
! lacme revokeCert /etc/lacme/simpletest.ecdsa.crt 2>"$STDERR" || fail
grepstderr -Fxq "Revoking /etc/lacme/simpletest.ecdsa.crt"
-grepstderr -Fxq "400 Bad Request (Certificate already revoked)"
+grepstderr -Fq "400 Bad Request (unable to revoke"
grepstderr -Fxq "Warning: Couldn't revoke /etc/lacme/simpletest.ecdsa.crt"
# and the RSA certificate using the service key
@@ -26,7 +26,7 @@ mv -vfT /etc/lacme/simpletest.rsa.key /etc/lacme/account.key
lacme revokeCert /etc/lacme/simpletest.rsa.crt
! lacme revokeCert /etc/lacme/simpletest.rsa.crt 2>"$STDERR" || fail
grepstderr -Fxq "Revoking /etc/lacme/simpletest.rsa.crt"
-grepstderr -Fxq "400 Bad Request (Certificate already revoked)"
+grepstderr -Fq "400 Bad Request (unable to revoke"
grepstderr -Fxq "Warning: Couldn't revoke /etc/lacme/simpletest.rsa.crt"
# vim: set filetype=sh :
diff --git a/tests/cert-verify b/tests/cert-verify
index 49629f2..4d254c6 100644
--- a/tests/cert-verify
+++ b/tests/cert-verify
@@ -14,7 +14,7 @@ openssl verify -no-CApath -CAfile /etc/ssl/certs/ca-certificates.crt -show_chain
mv /usr/share/lacme/ca-certificates.crt /usr/share/lacme/ca-certificates.crt.back
! lacme newOrder 2>"$STDERR" || fail
-grepstderr -Fxq "Can't open /usr/share/lacme/ca-certificates.crt for reading, No such file or directory"
+grepstderr -Fxq "Could not open file or uri for loading certs of 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
diff --git a/tests/drop-privileges b/tests/drop-privileges
index fd432d9..8deb8f1 100644
--- a/tests/drop-privileges
+++ b/tests/drop-privileges
@@ -123,8 +123,8 @@ check_client() {
grep -Exq "[0-9]+ 0700 $UID:$GID socket:\[[0-9]+\]" "$prefix/fd" || return 1
sed -ri '0,\#^[0-9]+ .* socket:\[[0-9]+\]$# {//d}' "$prefix/fd"
- grep -Exq "[0-9]+ 0500 $UID:$GID /etc/lacme/lacme\.conf" "$prefix/fd" || return 1
- sed -ri '0,\#^[0-9]+ .* /etc/lacme/lacme\.conf$# {//d}' "$prefix/fd"
+ grep -Eq "^[0-9]+ 0500 $UID:$GID /tmp/lacme-client.conf\.json-" "$prefix/fd" || return 1
+ sed -ri '0,\#^[0-9]+ .* /tmp/lacme-client.conf\.json-# {//d}' "$prefix/fd"
! test -s "$prefix/fd" || return 1
}
check_webserver() {
diff --git a/tests/old-accountd b/tests/old-accountd
index b44f7ec..3ad4b31 100644
--- a/tests/old-accountd
+++ b/tests/old-accountd
@@ -12,7 +12,7 @@ cat >~lacme-account/.config/lacme/lacme-accountd.conf <<-EOF
privkey = file:/etc/lacme/account.key
EOF
-echo "deb http://deb.debian.org/debian stretch main" >>/etc/apt/sources.list
+echo "deb http://archive.debian.org/debian stretch main" >>/etc/apt/sources.list
DEBIAN_FRONTEND="noninteractive" apt update
DEBIAN_FRONTEND="noninteractive" apt install -y --no-install-recommends \
--reinstall --allow-downgrades \
@@ -21,6 +21,7 @@ DEBIAN_FRONTEND="noninteractive" apt install -y --no-install-recommends \
SOCKET=~lacme-account/S.lacme
runuser -u lacme-account -- lacme-accountd --socket="$SOCKET" & PID=$!
+sleep 1
lacme --socket="$SOCKET" account
lacme --socket="$SOCKET" newOrder
diff --git a/tests/old-lacme b/tests/old-lacme
index fa7d827..b1c9f88 100644
--- a/tests/old-lacme
+++ b/tests/old-lacme
@@ -26,6 +26,7 @@ mv -f /usr/share/lacme/ca-certificates.crt.back /usr/share/lacme/ca-certificates
SOCKET=~lacme-account/S.lacme
runuser -u lacme-account -- lacme-accountd --socket="$SOCKET" & PID=$!
+sleep 1
sed -ri "s/^\[accountd]$/#&/" /etc/lacme/lacme.conf # https://bugs.debian.org/955767
lacme --socket="$SOCKET" account
lacme --socket="$SOCKET" newOrder