public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Mark Atwood <mark@wolfssl.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH common 2/2] ticket: sign RSA tickets with SHA-256
Date: Fri, 23 Oct 2026 11:57:49 -0700	[thread overview]
Message-ID: <20261023185749.509347-2-mark@wolfssl.com> (raw)
In-Reply-To: <CALkZksWBSdQa5AsvhmANGAJigcZ7FHPtgRgdu3JsRt9NX6vwSg@mail.gmail.com>

Crypt::OpenSSL::RSA signs with SHA-1 unless told otherwise. NIST SP
800-131A Rev. 2 no longer allows SHA-1 for creating digital signatures,
and a FIPS provider that enforces this makes assemble_rsa_ticket die, so
no ticket can be issued.

Select SHA-256 explicitly before signing. The signature length only
depends on the RSA key size, so tickets keep their size.

Nodes with the previous commit accept both hashes. Nodes running an
older version only verify SHA-1, so in a cluster with mixed versions a
ticket issued by an updated node is rejected by a not yet updated one,
for example on API requests that the updated node proxies to it. This
change should thus only roll out once the verification side has been
available for a while.

Extend the test to check, against the RSA primitive with an explicitly
chosen hash, that issued tickets carry a SHA-256 signature, also when
the key object was last used with SHA-1.

Signed-off-by: Mark Atwood <mark@wolfssl.com>
---
 src/PVE/Ticket.pm   |  4 ++++
 test/ticket_test.pl | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+)

diff --git a/src/PVE/Ticket.pm b/src/PVE/Ticket.pm
index f700f39..86dfd5a 100644
--- a/src/PVE/Ticket.pm
+++ b/src/PVE/Ticket.pm
@@ -66,6 +66,10 @@ sub assemble_rsa_ticket {
 
     my $full = defined($secret_data) ? "$plain:$secret_data" : $plain;
 
+    # Crypt::OpenSSL::RSA signs with SHA-1 unless told otherwise. NIST SP 800-131A no longer
+    # allows SHA-1 for creating signatures, and FIPS providers may refuse to.
+    $rsa_priv->use_sha256_hash();
+
     my $ticket = $plain . "::" . encode_base64($rsa_priv->sign($full), '');
 
     return $ticket;
diff --git a/test/ticket_test.pl b/test/ticket_test.pl
index 37e30b4..503c421 100755
--- a/test/ticket_test.pl
+++ b/test/ticket_test.pl
@@ -65,4 +65,38 @@ for my $hash (qw(sha256 sha1)) {
     );
 }
 
+# check what PVE::Ticket signs against the RSA primitive with an explicitly chosen hash
+sub signature_hash($pub, $ticket, $secret_data = undef) {
+    my ($plain, $sig) = $ticket =~ m/^(\S+)::([^:\s]+)$/ or return undef;
+    my $full = defined($secret_data) ? "$plain:$secret_data" : $plain;
+    my $raw_sig = decode_base64($sig);
+    my @matching;
+    for my $hash (qw(sha256 sha1)) {
+        my $use_hash = "use_${hash}_hash";
+        push @matching, $hash if eval { $pub->$use_hash(); $pub->verify($full, $raw_sig) };
+    }
+    return join(',', @matching);
+}
+
+my $ticket = PVE::Ticket::assemble_rsa_ticket($rsa_priv, 'PVE', 'root@pam');
+is(signature_hash($rsa_pub, $ticket), 'sha256', "ticket is signed with SHA-256 only");
+is(
+    scalar(PVE::Ticket::verify_rsa_ticket($rsa_pub, 'PVE', $ticket, undef, -1, 60, 1)),
+    'root@pam',
+    "signed ticket is accepted",
+);
+
+# a key object that was last used with SHA-1 must still sign with SHA-256
+$rsa_priv->use_sha1_hash();
+$ticket = PVE::Ticket::assemble_rsa_ticket($rsa_priv, 'PVEVNC', undef, 'vnc-secret');
+is(
+    signature_hash($rsa_pub, $ticket, 'vnc-secret'),
+    'sha256',
+    "ticket with secret data is signed with SHA-256",
+);
+ok(
+    PVE::Ticket::verify_rsa_ticket($rsa_pub, 'PVEVNC', $ticket, 'vnc-secret', -20, 40, 1),
+    "signed ticket with secret data is accepted",
+);
+
 done_testing();
-- 
2.55.0




      parent reply	other threads:[~2026-10-23 18:58 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-23 18:36 [PATCH common 0/2] ticket: sign RSA tickets with SHA-256 Mark Atwood
2026-10-23 18:57 ` [PATCH common 1/2] ticket: accept RSA tickets signed " Mark Atwood
2026-10-23 18:57 ` Mark Atwood [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261023185749.509347-2-mark@wolfssl.com \
    --to=mark@wolfssl.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal