]> git.proxmox.com Git - proxmox-acme.git/blobdiff - src/PVE/ACME.pm
support downloading alternate chains
[proxmox-acme.git] / src / PVE / ACME.pm
index 265482d8bc6434b2db94d1025ccd204cd487abfc..57578d7eda8a3a05df1da02cad33b0b3d125ab50 100644 (file)
@@ -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;
        }