]> git.puffer.fish Git - mirror/pve-network.git/commitdiff
api request helper: enforce TLS cert-check and add cert-fingerprint option
authorHannes Duerr <h.duerr@proxmox.com>
Mon, 10 Feb 2025 14:19:25 +0000 (15:19 +0100)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Thu, 6 Mar 2025 09:00:21 +0000 (10:00 +0100)
Currently, we do not verify the TLS certificate for API requests
external IPAM and DNS integration. This could allow man-in-the-middle
attacks, albeit most IPAM infrastructure is on controlled and isolated
LANs, so it's not something that should frequently happen; and
technically our IPAM integration is still marked as tech-preview,
which had its reasons.

Enforce verification, and allow users to pass a cert SHA256
fingerprint to ensure a certificates validity if it's not trusted by
the system trust store, as it's, e.g., the case for self-signed certs.

The code was adapted from the one in pve-apiclient, which we cannot
reuse directly as it is only implemented for requests against PVE
nodes, not as a generic HTTP client request helper.

Add the new dependency `libio-socket-ssl-perl` required to get the
verify callback for the TLS certificate used for cert-fingerprint
checking.

Signed-off-by: Hannes Duerr <h.duerr@proxmox.com>
Tested-by: Stefan Hanreich <s.hanreich@proxmox.com>
 [TL: return valid for non-leaf certs and rewrite commit message]
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
debian/control
src/PVE/Network/SDN.pm

index bb8cef9e98ac2ba9bcad3de1924a24b0b4a769da..34b7366767666e240b2f6f363dda6992df806bf4 100644 (file)
@@ -19,6 +19,7 @@ Package: libpve-network-perl
 Architecture: all
 Depends: libpve-common-perl (>= 5.0-45),
          pve-cluster (>= 8.0.10),
+         libio-socket-ssl-perl,
          libnet-subnet-perl,
          libnet-ip-perl,
          libnetaddr-ip-perl,
index 1186d9e0591df2dff1231d0f811bdc3bbdb50148..8cd9ad827aa9c6e561fba512d49b5db6ce6efb0a 100644 (file)
@@ -3,7 +3,9 @@ package PVE::Network::SDN;
 use strict;
 use warnings;
 
+use IO::Socket::SSL; # important for SSL_verify_callback
 use JSON;
+use Net::SSLeay;
 
 use PVE::INotify;
 
@@ -256,7 +258,7 @@ sub encode_value {
 
 #helpers
 sub api_request {
-    my ($method, $url, $headers, $data) = @_;
+    my ($method, $url, $headers, $data, $expected_fingerprint) = @_;
 
     my $encoded_data = to_json($data) if $data;
 
@@ -270,7 +272,24 @@ sub api_request {
        $ua->env_proxy;
     }
 
-    $ua->ssl_opts(verify_hostname => 0, SSL_verify_mode => 0x00);
+    if (defined($expected_fingerprint)) {
+       my $ssl_verify_callback = sub {
+           my (undef, undef, undef, undef, $cert, $depth) = @_;
+
+           # we don't care about intermediate or root certificates, always return as valid as the
+           # callback will be executed for all levels and all must be valid.
+           return 1 if $depth != 0;
+
+           my $fingerprint = Net::SSLeay::X509_get_fingerprint($cert, 'sha256');
+
+           return $fingerprint eq $expected_fingerprint ? 1 : 0;
+       };
+       $ua->ssl_opts(
+           verify_hostname => 0,
+           SSL_verify_mode => SSL_VERIFY_PEER,
+           SSL_verify_callback => $ssl_verify_callback,
+       );
+    }
 
     my $response = $ua->request($req);