Commit fc9a497df1 for openssl.org

commit fc9a497df11bcc1210ff640be072c06f927a8675
Author: Shreenidhi Shedi <yesshedi@gmail.com>
Date:   Thu Jul 9 16:23:41 2026 +0530

    apps/tsget: switch WWW::Curl::Easy to Net::Curl::Easy

    Minimal module swap: replace WWW::Curl::Easy with Net::Curl::Easy.
    Update callback signatures (Net::Curl passes the easy handle as the
    first argument), replace error-code-based perform() with eval/die,
    and drop cleanup() which Net::Curl does not require.

    Assisted-by: Claude:claude-sonnet-4-6
    Signed-off-by: Shreenidhi Shedi <yesshedi@gmail.com>

    Reviewed-by: Andrew Dinh <andrewd@openssl.org>
    Reviewed-by: Matt Caswell <matt@openssl.foundation>
    MergeDate: Fri Aug  7 13:29:35 2026
    (Merged from https://github.com/openssl/openssl/pull/31445)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a80ea66b29..80ad2cd7ef 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -89,6 +89,17 @@ jobs:
       run: sudo locale-gen tr_TR.UTF-8
     - name: cmocka
       run: sudo apt-get -y install libcmocka-dev
+    - name: install dependencies for perl Net::Curl
+      run: |
+        sudo apt-get update
+        sudo apt-get -y install libcurl4-openssl-dev cpanminus build-essential
+    - name: install Net::Curl
+      run: |
+        url=https://cpan.metacpan.org/authors/id/S/SY/SYP/Net-Curl-0.58.tar.gz
+        sha=37c1585cc70e21579c7c733e306e97a46adc093a3777af6d8ba37d73986d7f5a
+        curl -fsSL "$url" -o Net-Curl.tar.gz
+        echo "$sha  Net-Curl.tar.gz" | sha256sum -c -
+        sudo cpanm --notest ./Net-Curl.tar.gz
     - name: fipsvendor
       # Make one fips build use a customized FIPS vendor
       run: echo "FIPS_VENDOR=CI" >> VERSION.dat
diff --git a/CHANGES.md b/CHANGES.md
index fb46f8afea..139bacbbc4 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -31,6 +31,12 @@ OpenSSL Releases

 ### Changes between 4.0 and 4.1 [xx XXX xxxx]

+ * The `tsget` utility now uses `Net::Curl::Easy` (from the `Net-Curl` CPAN
+   distribution) instead of the abandoned `WWW::Curl::Easy`.  Users who relied
+   on `tsget` must install `Net::Curl::Easy` before upgrading.
+
+   *Shreenidhi Shedi*
+
  * Added `CMS_add_standard_smimecap_ex()`, which populates an SMIMECapabilities
    list using `EVP_CIPHER_fetch()` and `EVP_MD_fetch()` so that only algorithms
    available in the active providers are advertised.  `PKCS7_sign_add_signer()`
diff --git a/apps/tsget.in b/apps/tsget.in
index 8eab6a8f1f..0bd35dbfb4 100644
--- a/apps/tsget.in
+++ b/apps/tsget.in
@@ -11,13 +11,13 @@ use strict;
 use IO::Handle;
 use Getopt::Std;
 use File::Basename;
-use WWW::Curl::Easy;
+use Net::Curl::Easy qw(:constants);

 use vars qw(%options);

 # Callback for reading the body.
 sub read_body {
-    my ($maxlength, $state) = @_;
+    my ($easy, $maxlength, $state) = @_;
     my $return_data = "";
     my $data_len = length ${$state->{data}};
     if ($state->{bytes} < $data_len) {
@@ -31,7 +31,7 @@ sub read_body {

 # Callback for writing the body into a variable.
 sub write_body {
-    my ($data, $pointer) = @_;
+    my ($easy, $data, $pointer) = @_;
     ${$pointer} .= $data;
     return length($data);
 }
@@ -41,7 +41,7 @@ sub create_curl {
     my $url = shift;

     # Create Curl object.
-    my $curl = WWW::Curl::Easy::new();
+    my $curl = Net::Curl::Easy->new();

     # Error-handling related options.
     $curl->setopt(CURLOPT_VERBOSE, 1) if $options{d};
@@ -56,7 +56,7 @@ sub create_curl {
         ["Content-Type: application/timestamp-query",
         "Accept: application/timestamp-reply,application/timestamp-response"]);
     $curl->setopt(CURLOPT_READFUNCTION, \&read_body);
-    $curl->setopt(CURLOPT_HEADERFUNCTION, sub { return length($_[0]); });
+    $curl->setopt(CURLOPT_HEADERFUNCTION, sub { return length($_[1]); });

     # Options for getting the result.
     $curl->setopt(CURLOPT_WRITEFUNCTION, \&write_body);
@@ -84,10 +84,6 @@ sub get_timestamp {
     my $curl = shift;
     my $body = shift;
     my $ts_body;
-    local $::error_buf;
-
-    # Error-handling related options.
-    $curl->setopt(CURLOPT_ERRORBUFFER, "::error_buf");

     # Options for POST method.
     $curl->setopt(CURLOPT_INFILE, {data => $body, bytes => 0});
@@ -97,14 +93,13 @@ sub get_timestamp {
     $curl->setopt(CURLOPT_FILE, \$ts_body);

     # Send the request...
-    my $error_code = $curl->perform();
     my $error_string;
-    if ($error_code != 0) {
+    eval { $curl->perform(); };
+    if ($@) {
         my $http_code = $curl->getinfo(CURLINFO_HTTP_CODE);
         $error_string = "could not get timestamp";
         $error_string .= ", http code: $http_code" unless $http_code == 0;
-        $error_string .= ", curl code: $error_code";
-        $error_string .= " ($::error_buf)" if defined($::error_buf);
+        $error_string .= ": $@";
     } else {
         my $ct = $curl->getinfo(CURLINFO_CONTENT_TYPE);
         if (lc($ct) ne "application/timestamp-reply"
@@ -197,4 +192,3 @@ REQUEST: foreach (@ARGV) {
     }
     STDERR->printflush(", $output written.\n") if $options{v};
 }
-$curl->cleanup();