[pve-devel] [PATCH v2 proxmox-acme] support downloading alternate chains
Stoiko Ivanov
s.ivanov at proxmox.com
Fri Oct 8 10:52:40 CEST 2021
Tested again against LE production endpoint - LGTM :)
Thanks!
Reviewed-By: Stoiko Ivanov <s.ivanov at proxmox.com>
Tested-By: Stoiko Ivanov <s.ivanov at proxmox.com>
On Fri, 8 Oct 2021 10:18:21 +0200
Fabian Grünbichler <f.gruenbichler at proxmox.com> wrote:
> the current default chains end with an expired root certificate for
> maximum compatibility with old Android versions. this breaks some other
> older clients (openssl, gnutls) which don't expect chains to contain any
> expired certificates, even if they are 'above' the trust anchor.
>
> by setting $root, it is possible to specify which root the ACME provided
> certificate chain should end with, downloading alternate chains as
> necessary.
>
> Signed-off-by: Fabian Grünbichler <f.gruenbichler at proxmox.com>
> ---
>
> Notes:
> v2:
> - only check issuer
> - also check default chain
> - add 'i' to RE check
>
> only tested with pebble
>
> src/PVE/ACME.pm | 35 ++++++++++++++++++++++++++++++++++-
> 1 file changed, 34 insertions(+), 1 deletion(-)
>
> diff --git a/src/PVE/ACME.pm b/src/PVE/ACME.pm
> index 265482d..57578d7 100644
> --- a/src/PVE/ACME.pm
> +++ b/src/PVE/ACME.pm
> @@ -442,17 +442,50 @@ sub deactivate_authorization {
>
> # Get certificate
> # GET-as-POST to order's certificate URL
> +# if $root is specified, attempts to find a matching (alternate) chain
> # Expects a '200 OK' reply
> # returns certificate chain in PEM format
> sub get_certificate {
> - my ($self, $order) = @_;
> + my ($self, $order, $root) = @_;
>
> $self->fatal("no certificate URL available (yet?)", $order)
> if !$order->{certificate};
>
> + my $check_root = sub {
> + my ($chain) = @_;
> +
> + my @certs = PVE::Certificate::split_pem($chain);
> + my $root_pem = $certs[-1];
> +
> + my ($file, $fh) = PVE::Tools::tempfile_contents($root_pem);
> + my $info = PVE::Certificate::get_certificate_info($file);
> +
> + return defined($info->{issuer}) && $info->{issuer} =~ m/\Q$root\E/i;
> + };
> +
> my $r = $self->do(POST => $order->{certificate}, '');
> my $return = eval {
> + # default chain
> my $res = __get_result($r, 200, 1);
> + if ($root && !$check_root->($res)) {
> + # alternate chains if requested and default didn't match
> + $res = undef;
> + my @links = $r->header('link');
> + for my $link (@links) {
> + if ($link =~ /^<(.*)>;rel="alternate"$/) {
> + my $url = $1;
> + my $chain = eval { __get_result($self->do(POST => $url, ''), 200, 1); };
> + die "failed to retrieve alternate chain from '$url' - $@\n" if $@;
> + if ($check_root->($chain)) {
> + $res = $chain;
> + last;
> + }
> + }
> + }
> + die "no matching alternate chain for '$root' returned by server\n"
> + if !defined($res);
> + }
> +
> if ($res =~ /^(-----BEGIN CERTIFICATE-----)(.+)(-----END CERTIFICATE-----)$/s) { # untaint
> return $1 . $2 . $3;
> }
More information about the pve-devel
mailing list