From 6d93f20bd206a024b0aedd57ce97a36160c67146 Mon Sep 17 00:00:00 2001 From: Lars Kanis Date: Thu, 18 Dec 2025 16:40:08 +0100 Subject: [PATCH] Extend c_rehash and README-SSL reg. new CA paths RubyInstaller-3.4 changed how the builtin libssl library is used. It is only used together with the builtin openssl gem. The buildin openssl gem has it's own CA certificates path. When a source gem is linked to libssl, then the MSYS2 provided libssl and it's CA certificates are used. Moreover the MSYS2 tools like pacman or curl use a separate file named `ca-bundle.crt`. All three diretories are now filled by the `c_rehash.rb` helper script. And the `README-SSL` describes the paths. --- resources/ssl/README-SSL.md | 8 ++--- resources/ssl/c_rehash.rb | 67 ++++++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/resources/ssl/README-SSL.md b/resources/ssl/README-SSL.md index bd5540f4..c199d7fe 100644 --- a/resources/ssl/README-SSL.md +++ b/resources/ssl/README-SSL.md @@ -30,9 +30,11 @@ Addition of certificate to the Ruby default CA list ---------------------------------------------- Additional certificates shall be stored in `/ssl/certs/.pem` in pem format. +This directory is checked by the builtin openssl gem for certificate verification. +When the openssl gem is installed via source gem, then the directory `\\etc\ssl\certs` is used instead. Each pem file may contain several certificates. The pem files must be activated for CA lookup by using a OpenSSL-hashed filename. -There is a helper script in `/ssl/certs/c_rehash.rb` to generate these hash files. +There is a helper script in `/ssl/certs/c_rehash.rb` to generate these hash files in both directories and in the `ca-bundle.crt` described below. Just double click `c_rehash.rb` to activate all pem files in the directory. Addition of certificates to the Devkit/MSYS2 CA list @@ -41,7 +43,3 @@ MSYS2 has its own CA list which is maintained by [the MSYS2 project](http://msys This CA list is used by all MSYS2 tools like pacman, wget or curl. In order to add an additional CA certificate for MSYS2, you have to append it to `\usr\ssl\certs\ca-bundle.crt` in PEM format. In a default Rubyinstaller-Devkit-2.5-x64 setup this file is here: `c:\Ruby25-x64\msys64\usr\ssl\certs\ca-bundle.crt` - -Please also note, that pacman's builtin HTTP client doesn't work well with proxies. -You probably have to enable `wget` in `\etc\pacman.conf`. -It also respects `http_proxy` and `https_proxy` environment variables set in Windows system settings. diff --git a/resources/ssl/c_rehash.rb b/resources/ssl/c_rehash.rb index a1a16f85..dd8debd4 100644 --- a/resources/ssl/c_rehash.rb +++ b/resources/ssl/c_rehash.rb @@ -1,5 +1,8 @@ #!/usr/bin/env ruby +# This is a helper script to add trusted CA certificates to RubyInstaller. +# See README-SSL.md for more details. + require 'openssl' class CHashDir @@ -74,12 +77,34 @@ def crl_filename(crl) def do_hash_dir Dir.chdir(@dirpath) do - delete_symlink + delete_symlink(".") + + begin + msys = RubyInstaller::Runtime.msys2_installation + mingw_certs = File.expand_path("../etc/ssl/certs", msys.mingw_bin_path) + msys_bundle = File.expand_path("usr/ssl/certs/ca-bundle.crt", msys.msys_path) + rescue RubyInstaller::Runtime::Msys2Installation::MsysNotFound + else + delete_symlink(mingw_certs) + delete_from_bundle(msys_bundle) + end + Dir.glob('*.pem') do |pemfile| load_pem_file(pemfile).each do |cert| case cert when OpenSSL::X509::Certificate - link_hash_cert(cert) + # Create hash file in rubyinstallers's ssl directory + # This is used by builtin openssl.gem + link_hash_cert(cert, ".") + + # Create hash file in msys2/mingw's ssl directory + # This is used when openssl.gem is built from sources + link_hash_cert(cert, mingw_certs) if mingw_certs + + # Create hash file in msys2/mingw's ssl directory + # This is used by MSYS2 tools like curl and pacman + add_to_bundle(cert, msys_bundle) if msys_bundle + when OpenSSL::X509::CRL link_hash_crl(cert) else @@ -90,19 +115,43 @@ def do_hash_dir end end - def delete_symlink - Dir.entries(".").each do |entry| + def delete_symlink(hashdir) + Dir.entries(hashdir).each do |entry| next unless /^[\da-f]+\.r{0,1}\d+$/ =~ entry - File.unlink(entry) if FileTest.symlink?(entry) or FileTest.file?(entry) + epath = File.join(hashdir, entry) + File.unlink(epath) if FileTest.symlink?(epath) or FileTest.file?(epath) end end - def link_hash_cert(cert) + def delete_from_bundle(bundle_fname) + fc = File.read(bundle_fname) + + # Create a bak file before modification + fname_bak = bundle_fname + ".bak-ruby" + File.write(fname_bak, fc) unless File.exist?(fname_bak) + + # Remove all certs inserted by RubyInstaller + fc = fc.gsub(/# RubyInstaller: [^\n]*\n-----BEGIN CERTIFICATE-----[^-]*-----END CERTIFICATE-----\n*/m, "") + File.write(bundle_fname, fc) + end + + def add_to_bundle(cert, bundle_fname) + fc = File.read(bundle_fname) + ct = <<~EOT + # RubyInstaller: #{cert.subject} + #{cert.to_pem} + EOT + fc = ct + fc + File.write(bundle_fname, fc) + STDOUT.puts("#{cert.subject} => #{bundle_fname}") unless @silent + end + + def link_hash_cert(cert, hashdir) name_hash = hash_name(cert.subject) fingerprint = fingerprint(cert.to_der) - filepath = link_hash(cert, name_hash, fingerprint) { |idx| - "#{name_hash}.#{idx}" - } + filepath = link_hash(cert, name_hash, fingerprint) do |idx| + File.join(hashdir, "#{name_hash}.#{idx}") + end unless filepath unless @silent STDERR.puts("WARNING: Skipping duplicate certificate #{cert.subject}")