From d5d7aed46cc34dfbba521dc216f6f75a4309de10 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Mon, 21 Jan 2019 02:07:22 +0100 Subject: client: poll order URL instead of each authz URL successively. We were blocking on https://github.com/letsencrypt/boulder/issues/3530 . --- Changelog | 6 ++++ INSTALL | 10 ++++++- client | 100 ++++++++++++++++++++++++++++++++++++++------------------------ 3 files changed, 76 insertions(+), 40 deletions(-) diff --git a/Changelog b/Changelog index 633222a..31ad97d 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,9 @@ +lacme (0.6) UNRELEASED + + + client: poll order URL instead of each authz URL successively. + + -- Guilhem Moulin Mon, 21 Jan 2019 02:07:58 +0100 + lacme (0.5) upstream; + Use ACME v2 endpoints (update protocol to the last draft of the spec diff --git a/INSTALL b/INSTALL index 82de279..155c7aa 100644 --- a/INSTALL +++ b/INSTALL @@ -20,6 +20,7 @@ lacme depends on OpenSSL and the following Perl modules: - Config::Tiny - Digest::SHA (core module) + - Date::Parse - Errno (core module) - Fcntl (core module) - File::Temp (core module) @@ -37,7 +38,14 @@ lacme depends on OpenSSL and the following Perl modules: On Debian GNU/Linux systems, these dependencies can be installed with the following command: - apt-get install openssl libconfig-tiny-perl libjson-perl libwww-perl liblwp-protocol-https-perl libnet-ssleay-perl libtypes-serialiser-perl + apt-get install openssl \ + libconfig-tiny-perl \ + libtimedate-perl \ + libjson-perl \ + libwww-perl \ + liblwp-protocol-https-perl \ + libnet-ssleay-perl \ + libtypes-serialiser-perl However Debian GNU/Linux users can also use gbp(1) from git-buildpackage to build their own package: diff --git a/client b/client index 838b184..9ce52a0 100755 --- a/client +++ b/client @@ -142,6 +142,22 @@ sub request_status_line($) { return $msg; } +# The request's Retry-After header (RFC 7231 sec. 7.1.3), converted to +# waiting time in seconds. +sub request_retry_after($) { + my $r = shift; + my $v = $r->header('Retry-After'); + if (defined $v and $v !~ /\A\d+\z/) { + require 'Date/Parse.pm'; + $v = Date::Parse::str2time($v); + if (defined $v) { + $v = $v - time; + undef $v if $v <= 0; + } + } + return $v; +} + # Parse and return the request's decoded content as JSON; or print the # Status Line and fail if the request failed. # If $dump is set, also pretty-print the decoded content. @@ -262,6 +278,7 @@ elsif ($COMMAND eq 'newOrder') { my @identifiers = map {{ type => 'dns', value => $_ }} @ARGV; my $r = acme_resource('newOrder', identifiers => \@identifiers); my $order = request_json_decode($r); + my $orderurl = $r->header('Location'); foreach (@{$order->{authorizations}}) { my $authz = request_json_decode(request(GET => $_)); @@ -287,52 +304,57 @@ elsif ($COMMAND eq 'newOrder') { } else { die "Can't open $challenge->{token}: $!"; } - - $r = acme($challenge->{url}); - - # poll until the status become 'valid' - # XXX poll the order URL instead, to get the status of all - # challenges at once - # https://github.com/letsencrypt/boulder/issues/3530 - for ( my $i = 0, my $resp, my $status; - $resp = request_json_decode($r), - $status = $resp->{status} // 'pending', - $status ne 'valid'; - $r = request('GET' => $challenge->{url})) { - if (defined (my $problem = $resp->{error})) { # problem document (RFC 7807) - my $msg = $problem->{status}; - $msg .= " " .$problem->{title} if defined $problem->{title}; - $msg .= " (".$problem->{detail}.")" if defined $problem->{detail}; - die $msg, "\n"; - } - die "Error: Invalid challenge for $identifier (status: ".$status.")\n" - if $status ne 'pending'; - - my $sleep = 1; - if (defined (my $retry_after = $r->header('Retry-After'))) { - print STDERR "Retrying after $retry_after seconds...\n"; - $sleep = $retry_after; - } - - $i += $sleep; - die "Timeout exceeded while waiting for challenges to pass ($identifier)\n" - if $timeout > 0 and $i >= $timeout; - sleep $sleep; - } + my $r = acme($challenge->{url}); + request_json_decode($r); } - $r = acme($order->{finalize}, csr => encode_base64url($csr)); - my $resp = request_json_decode($r); + # poll the order URL (to get the status of all challenges at once) + # until the status become 'valid' + my $orderstr = join(', ', map {uc($_->{type}) .":". $_->{value}} @identifiers); + my $certuri; + for (my $i = 0;;) { + my $r = request('GET' => $orderurl); + my $resp = request_json_decode($r); + if (defined (my $problem = $resp->{error})) { # problem document (RFC 7807) + my $msg = $problem->{status}; + $msg .= " " .$problem->{title} if defined $problem->{title}; + $msg .= " (".$problem->{detail}.")" if defined $problem->{detail}; + die $msg, "\n"; + } + 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") { + $certuri = $resp->{certificate} // + die "Error: Missing \"certificate\" field in \"valid\" order\n"; + last; + } + elsif ($status ne "pending" and $status ne "processing") { + warn "Unknown order status: $status\n"; + } - my $uri = $resp->{certificate}; - print STDERR "Certificate URI: $uri\n"; + my $retry_after = request_retry_after($r) // 1; + print STDERR "Retrying after $retry_after seconds...\n"; + $i += $retry_after; + die "Timeout exceeded while waiting for challenges to pass ($orderstr)\n" + if $timeout > 0 and $i >= $timeout; + sleep $retry_after; + } - # pool until the cert is available + # poll until the cert is available + print STDERR "Certificate URI: $certuri\n"; for (my $i = 0;;) { - $r = request('GET' => $uri); + $r = request('GET' => $certuri); die request_status_line($r), "\n" unless $r->is_success(); last unless $r->code == 202; # Accepted - my $retry_after = $r->header('Retry-After') // 1; + my $retry_after = request_retry_after($r) // 1; print STDERR "Retrying after $retry_after seconds...\n"; $i += $retry_after; die "Timeout exceeded while waiting for certificate\n" if $timeout > 0 and $i >= $timeout; -- cgit v1.2.3 From 57ddc5ca505adeb3e44542335b01a6f0e8887ddc Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Mon, 21 Jan 2019 02:13:06 +0100 Subject: lacme, client: new dependency Date::Parse. --- Changelog | 2 ++ client | 2 +- lacme | 29 ++--------------------------- 3 files changed, 5 insertions(+), 28 deletions(-) diff --git a/Changelog b/Changelog index 31ad97d..43265ce 100644 --- a/Changelog +++ b/Changelog @@ -1,6 +1,8 @@ lacme (0.6) UNRELEASED + client: poll order URL instead of each authz URL successively. + - lacme, client: new dependency Date::Parse, don't parse RFC 3339 + datetime strings from X.509 certs manually. -- Guilhem Moulin Mon, 21 Jan 2019 02:07:58 +0100 diff --git a/client b/client index 9ce52a0..c152e30 100755 --- a/client +++ b/client @@ -50,6 +50,7 @@ use Fcntl qw/O_CREAT O_EXCL O_WRONLY/; use Digest::SHA qw/sha256 sha256_hex/; use MIME::Base64 qw/encode_base64 encode_base64url/; +use Date::Parse (); use LWP::UserAgent (); use Types::Serialiser (); use JSON (); @@ -148,7 +149,6 @@ sub request_retry_after($) { my $r = shift; my $v = $r->header('Retry-After'); if (defined $v and $v !~ /\A\d+\z/) { - require 'Date/Parse.pm'; $v = Date::Parse::str2time($v); if (defined $v) { $v = $v - time; diff --git a/lacme b/lacme index 3e5347d..cc94149 100755 --- a/lacme +++ b/lacme @@ -36,6 +36,7 @@ use Socket 1.95 qw/AF_UNIX AF_INET AF_INET6 PF_UNIX PF_INET PF_INET6 PF_UNSPEC SOCK_STREAM SOL_SOCKET SO_REUSEADDR SHUT_RDWR/; use Config::Tiny (); +use Date::Parse (); use Net::SSLeay (); # Clean up PATH @@ -199,33 +200,7 @@ sub x509_enddate($) { $time = Net::SSLeay::X509_get_notAfter($x509) if defined $x509; $dt = Net::SSLeay::P_ASN1_TIME_get_isotime($time) if defined $time; - my $t; - if (defined $dt and $dt =~ s/\A(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})//) { - # RFC3339 datetime strings; assume epoch is on January 1 of $epoch_year - my ($y, $m, $d, $h, $min, $s) = ($1, $2, $3, $4, $5, $6); - my (undef,undef,undef,undef,undef,$epoch_year,undef,undef,undef) = gmtime(0); - $t = 0; - foreach (($epoch_year+1900) .. $y-1) { - $t += 365*86400; - $t += 86400 if ($_ % 4 == 0 and $_ % 100 != 0) or ($_ % 400 == 0); # leap - } - - if ($m > 1) { - my @m = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); - $m[1]++ if ($y % 4 == 0 and $y % 100 != 0) or ($y % 400 == 0); # leap - $t += 86400*$m[$_] for (0 .. $m-2); - } - - $t += 86400*($d-1); - $t += $s + 60*($min + 60*$h); - - $dt =~ s/\A\.(\d{1,9})\d*//; # ignore nanosecs - - if ($dt =~ /\A([+-])(\d{2}):(\d{2})\z/) { - my $tz = 60*($3 + 60*$2); - $t = $1 eq '-' ? ($t+$tz) : ($t-$tz); - } - } + my $t = Date::Parse::str2time($dt) if defined $dt; Net::SSLeay::X509_free($x509) if defined $x509; Net::SSLeay::BIO_free($bio) if defined $bio; -- cgit v1.2.3 From ad62d6421fcee63de6b3b0673e84eb93a996cc42 Mon Sep 17 00:00:00 2001 From: Benjamin Tietz Date: Wed, 28 Nov 2018 17:47:13 +0100 Subject: [git] ignore vims' swapfiles --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..813d896 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# vim swapfiles +.*.sw[po] + +# generated man-pages +*.1 -- cgit v1.2.3 From 8be2500f35f2edb3db51f6f48ce70d6cfcee24df Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Wed, 21 Aug 2019 16:54:10 +0200 Subject: Call iptables binaries from /usr/sbin not /sbin. As of Buster this is the case, and the maintainer plans to drop compatibility symlinks once Bullseye is released. See /usr/share/doc/iptables/NEWS.Debian.gz . --- Changelog | 3 +++ lacme | 12 ++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Changelog b/Changelog index 43265ce..27b93de 100644 --- a/Changelog +++ b/Changelog @@ -3,6 +3,9 @@ lacme (0.6) UNRELEASED + client: poll order URL instead of each authz URL successively. - lacme, client: new dependency Date::Parse, don't parse RFC 3339 datetime strings from X.509 certs manually. + - lacme: assume that the iptables(1) binaries are under /usr/sbin not + /sbin. As of Buster this is the case, and the maintainer plans to + drop compatibility symlinks once Bullseye is released. -- Guilhem Moulin Mon, 21 Jan 2019 02:07:58 +0100 diff --git a/lacme b/lacme index cc94149..1c5761c 100755 --- a/lacme +++ b/lacme @@ -399,10 +399,10 @@ sub iptables_save($@) { open STDIN, '<', '/dev/null' or die "Can't open /dev/null: $!"; open STDOUT, '>&', $iptables_tmp or die "Can't dup: $!"; $| = 1; # turn off buffering for STDOUT - exec "/sbin/$iptables_bin-save", "-c" or die; + exec "/usr/sbin/$iptables_bin-save", "-c" or die; } waitpid $pid => 0; - die "Error: /sbin/$iptables_bin-save exited with value ".($? >> 8) if $? > 0; + die "Error: /usr/sbin/$iptables_bin-save exited with value ".($? >> 8) if $? > 0; # seek back to the begining, as we'll restore directly from the # handle and not from the file. XXX if there was a way in Perl to @@ -416,10 +416,10 @@ sub iptables_save($@) { unless ($pid) { open STDIN, '<&', $iptables_tmp or die "Can't dup: $!"; open STDOUT, '>', '/dev/null' or die "Can't open /dev/null: $!"; - exec "/sbin/$iptables_bin-restore", "-c" or die; + exec "/usr/sbin/$iptables_bin-restore", "-c" or die; } waitpid $pid => 0; - warn "Warning: /sbin/$iptables_bin-restore exited with value ".($? >> 8) if $? > 0; + warn "Warning: /usr/sbin/$iptables_bin-restore exited with value ".($? >> 8) if $? > 0; }; @@ -437,10 +437,10 @@ sub iptables_save($@) { } my $dest = Socket::inet_ntop($domain, $addr) .'/'. $mask; - system ("/sbin/$iptables_bin", qw/-I INPUT -p tcp -m tcp -m state/, + system ("/usr/sbin/$iptables_bin", qw/-I INPUT -p tcp -m tcp -m state/, '-d', $dest, '--dport', $port, '--state', 'NEW,ESTABLISHED', '-j', 'ACCEPT') == 0 or die; - system ("/sbin/$iptables_bin", qw/-I OUTPUT -p tcp -m tcp -m state/, + system ("/usr/sbin/$iptables_bin", qw/-I OUTPUT -p tcp -m tcp -m state/, '-s', $dest, '--sport', $port, '--state', 'ESTABLISHED', '-j', 'ACCEPT') == 0 or die; } -- cgit v1.2.3 From a3978219bab85e650d963276823cb142ecde6a21 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Wed, 21 Aug 2019 17:19:59 +0200 Subject: Link to RFC 8555 instead of the ACME I-D URL. --- Changelog | 2 ++ client | 2 +- lacme-accountd.md | 2 +- lacme.md | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Changelog b/Changelog index 27b93de..948b3f4 100644 --- a/Changelog +++ b/Changelog @@ -6,6 +6,8 @@ lacme (0.6) UNRELEASED - lacme: assume that the iptables(1) binaries are under /usr/sbin not /sbin. As of Buster this is the case, and the maintainer plans to drop compatibility symlinks once Bullseye is released. + - Link to RFC 8555 instead of the + ACME I-D URL. -- Guilhem Moulin Mon, 21 Jan 2019 02:07:58 +0100 diff --git a/client b/client index c152e30..9dbcc3f 100755 --- a/client +++ b/client @@ -181,7 +181,7 @@ sub request_json_decode($;$$) { ############################################################################# # JSON-encode the hash reference $h and send it to the ACME server $uri # encapsulated it in a JSON Web Signature (JWS). -# https://tools.ietf.org/html/draft-ietf-acme-acme-12 +# https://tools.ietf.org/html/rfc8555 # sub acme($@) { my $uri = shift; diff --git a/lacme-accountd.md b/lacme-accountd.md index 59d9bd9..403c68c 100644 --- a/lacme-accountd.md +++ b/lacme-accountd.md @@ -135,7 +135,7 @@ See also [`lacme`(1)], [`ssh`(1)] -[ACME]: https://tools.ietf.org/html/draft-ietf-acme-acme-02 +[ACME]: https://tools.ietf.org/html/rfc8555 [`lacme`(1)]: lacme.1.html [`signal`(7)]: http://linux.die.net/man/7/signal [`gpg`(1)]: https://www.gnupg.org/documentation/manpage.en.html diff --git a/lacme.md b/lacme.md index 2d70c49..ca9a6a9 100644 --- a/lacme.md +++ b/lacme.md @@ -406,7 +406,7 @@ See also [`lacme-accountd`(1)] -[ACME]: https://tools.ietf.org/html/draft-ietf-acme-acme-12 +[ACME]: https://tools.ietf.org/html/rfc8555 [`lacme-accountd`(1)]: lacme-accountd.1.html [`iptables`(8)]: http://linux.die.net/man/8/iptables [`ciphers`(1ssl)]: https://www.openssl.org/docs/manmaster/apps/ciphers.html -- cgit v1.2.3 From f9d5e53cac1c002e5983efc18e42f5a21444b182 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Wed, 21 Aug 2019 17:29:19 +0200 Subject: Issue GET and POST-as-GET requests (RFC 8555 sec. 6.3) For the authorizations, order and certificate URLs. See RFC 8555 sec. 7.1. --- Changelog | 2 ++ client | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Changelog b/Changelog index 948b3f4..0f74a85 100644 --- a/Changelog +++ b/Changelog @@ -8,6 +8,8 @@ lacme (0.6) UNRELEASED drop compatibility symlinks once Bullseye is released. - Link to RFC 8555 instead of the ACME I-D URL. + - Issue GET and POST-as-GET requests (RFC 8555 sec. 6.3) for the + authorizations, order and certificate URLs. -- Guilhem Moulin Mon, 21 Jan 2019 02:07:58 +0100 diff --git a/client b/client index 9dbcc3f..b567516 100755 --- a/client +++ b/client @@ -183,14 +183,14 @@ sub request_json_decode($;$$) { # encapsulated it in a JSON Web Signature (JWS). # https://tools.ietf.org/html/rfc8555 # -sub acme($@) { - my $uri = shift; +sub acme($;$) { + my ($uri, $h) = @_; die "Missing nonce\n" unless defined $NONCE; # Produce the JSON Web Signature: RFC 7515 section 5 my %header = ( alg => 'RS256', nonce => $NONCE, url => $uri ); defined $KID ? ($header{kid} = $KID) : ($header{jwk} = $JWK); - my $payload = encode_base64url(json()->encode({ @_ })); + my $payload = defined $h ? encode_base64url(json()->encode($h)) : ""; my $protected = encode_base64url(json()->encode(\%header)); my $data = $protected .'.'. $payload; $S->printflush($data, "\r\n"); @@ -220,7 +220,7 @@ sub acme_resource($%) { request(HEAD => $RES{newNonce}); } my $uri = $RES{$r} // die "Unknown resource '$r'\n"; - acme($uri, @_); + acme($uri, {@_}); } # Set the key ID (registration URI) @@ -253,7 +253,7 @@ if ($COMMAND eq 'account') { if ($r->is_success()) { $KID = $r->header('Location'); - $r = acme($KID, %h); + $r = acme($KID, \%h); request_json_decode($r, 1, \*STDOUT) if $r->is_success() and $r->content_type() eq 'application/json'; } @@ -281,7 +281,7 @@ elsif ($COMMAND eq 'newOrder') { my $orderurl = $r->header('Location'); foreach (@{$order->{authorizations}}) { - my $authz = request_json_decode(request(GET => $_)); + my $authz = request_json_decode(acme($_)); next unless $authz->{status} eq 'pending'; my $identifier = $authz->{identifier}->{value}; @@ -304,7 +304,7 @@ elsif ($COMMAND eq 'newOrder') { } else { die "Can't open $challenge->{token}: $!"; } - my $r = acme($challenge->{url}); + my $r = acme($challenge->{url}, {}); request_json_decode($r); } @@ -313,7 +313,7 @@ elsif ($COMMAND eq 'newOrder') { my $orderstr = join(', ', map {uc($_->{type}) .":". $_->{value}} @identifiers); my $certuri; for (my $i = 0;;) { - my $r = request('GET' => $orderurl); + my $r = acme($orderurl); my $resp = request_json_decode($r); if (defined (my $problem = $resp->{error})) { # problem document (RFC 7807) my $msg = $problem->{status}; @@ -326,7 +326,7 @@ elsif ($COMMAND eq 'newOrder') { die "Error: Invalid order $orderstr\n"; } elsif ($status eq "ready") { - my $r = acme($order->{finalize}, csr => encode_base64url($csr)); + my $r = acme($order->{finalize}, {csr => encode_base64url($csr)}); my $resp = request_json_decode($r); $certuri = $resp->{certificate}; last; @@ -351,7 +351,7 @@ elsif ($COMMAND eq 'newOrder') { # poll until the cert is available print STDERR "Certificate URI: $certuri\n"; for (my $i = 0;;) { - $r = request('GET' => $certuri); + $r = acme($certuri); die request_status_line($r), "\n" unless $r->is_success(); last unless $r->code == 202; # Accepted my $retry_after = request_retry_after($r) // 1; -- cgit v1.2.3 From 8a2d319476dbcd7840893616b1399658ddd71b27 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Wed, 21 Aug 2019 17:57:15 +0200 Subject: lacme: new option 'account --deactivate' For client-initiated account deactivation. See RFC 8555 sec. 7.3.6. --- Changelog | 2 ++ client | 1 + lacme | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 0f74a85..2ede6b7 100644 --- a/Changelog +++ b/Changelog @@ -1,6 +1,8 @@ lacme (0.6) UNRELEASED + client: poll order URL instead of each authz URL successively. + + lacme: new option 'account --deactivate' for client-initiated account + deactivation, see RFC 8555 sec. 7.3.6. - lacme, client: new dependency Date::Parse, don't parse RFC 3339 datetime strings from X.509 certs manually. - lacme: assume that the iptables(1) binaries are under /usr/sbin not diff --git a/client b/client index b567516..2eebbf0 100755 --- a/client +++ b/client @@ -244,6 +244,7 @@ if ($COMMAND eq 'account') { my %h = ( contact => \@ARGV ) if @ARGV; $h{onlyReturnExisting} = Types::Serialiser::true unless $flags & 0x01; $h{termsOfServiceAgreed} = Types::Serialiser::true if $flags & 0x02; + $h{status} = "deactivated" if $flags & 0x04; print STDERR "Requesting new registration ".(@ARGV ? ("for ".join(', ', @ARGV)) : "")."\n" if $flags & 0x01; diff --git a/lacme b/lacme index 1c5761c..d5e8933 100755 --- a/lacme +++ b/lacme @@ -63,7 +63,7 @@ sub usage(;$$) { } exit $rv; } -usage(1) unless GetOptions(\%OPTS, qw/config=s config-certs=s@ socket=s register tos-agreed min-days=i quiet|q debug help|h/); +usage(1) unless GetOptions(\%OPTS, qw/config=s config-certs=s@ socket=s register tos-agreed deactivate min-days=i quiet|q debug help|h/); usage(0) if $OPTS{help}; $COMMAND = shift(@ARGV) // usage(1, "Missing command"); @@ -625,6 +625,7 @@ if ($COMMAND eq 'account') { my $flags = 0; $flags |= 1 if $OPTS{'register'}; $flags |= 2 if $OPTS{'tos-agreed'}; + $flags |= 4 if $OPTS{'deactivate'}; exit acme_client({out => \*STDOUT}, $flags, @ARGV); } -- cgit v1.2.3 From 454b29d61daaba8f19f0d890d59d259ef1416907 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Wed, 21 Aug 2019 18:24:21 +0200 Subject: New release 0.6. --- Changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 2ede6b7..c7cc0b3 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,4 @@ -lacme (0.6) UNRELEASED +lacme (0.6) upstream; + client: poll order URL instead of each authz URL successively. + lacme: new option 'account --deactivate' for client-initiated account @@ -13,7 +13,7 @@ lacme (0.6) UNRELEASED - Issue GET and POST-as-GET requests (RFC 8555 sec. 6.3) for the authorizations, order and certificate URLs. - -- Guilhem Moulin Mon, 21 Jan 2019 02:07:58 +0100 + -- Guilhem Moulin Wed, 21 Aug 2019 18:23:50 +0200 lacme (0.5) upstream; -- cgit v1.2.3