Skip to content

Add post-quantum cryptography (PQC) support to SSLConfig - #53

Open
junaruga wants to merge 3 commits into
ruby:masterfrom
junaruga:wip/support-pqc
Open

Add post-quantum cryptography (PQC) support to SSLConfig#53
junaruga wants to merge 3 commits into
ruby:masterfrom
junaruga:wip/support-pqc

Conversation

@junaruga

@junaruga junaruga commented Jul 29, 2026

Copy link
Copy Markdown
Member

This PR is related to #52.

Proof of concept

I prepared proof-of-concept scripts for this PR.

The document (drb/README.md) is here. A list of the sections in the drb/README.md is below. The sections without "(development)" test with the current master branch. These work. The sections with "(development)" test with this PR.

$ grep ^## drb/README.md
## druby (non-SSL)
## drbssl (SSL) auto-generated RSA cert
## drbssl (SSL) pre-generated RSA cert
## drbssl (SSL) pre-generated ML-DSA-65 cert
## drbssl (SSL) pre-generated RSA cert with client cert
## drbssl (SSL) pre-generated ML-DSA-65 cert with client cert
## drbssl (SSL) auto-generated ML-DSA-65 cert (development)
## drbssl (SSL) auto-generated ML-DSA-65/RSA multi cert (development)
## drbssl (SSL) pre-generated ML-DSA-65/RSA multi cert (development)
## drbssl (SSL) pre-generated ML-DSA-65/RSA multi cert with client cert (development)

The script is here. The CI result is here.

Commit message

DRb::DRbSSLSocket::SSLConfig already works
with pre-generated ML-DSA cert/key by
:SSLCertificate and :SSLPrivateKey config options.

This commit adds the following features in PQC use cases to #setup_certificate and #setup_ssl_context.

  • Add :SSLCertificates config option accepting an Array of [certificate, private_key] pairs for dual/multiple certificate support via OpenSSL::SSL::SSLContext#add_certificate changing from OpenSSL::SSL::SSLContext#cert and #key. Because an SSL server that accepts clients with either ML-DSA-NN or RSA certificates is useful in the use case of PQC migration from RSA (non-PQC) to ML-DSA (PQC). :SSLCertificate and :SSLPrivateKey are available for backward compatibility. But use OpenSSL::SSL::SSLContext#add_certificate internally. This is a behavior change.
  • Add :SSLPrivateKeyAlgorithms option accepting an Array of key algorithms (RSA, ML-DSA-44, ML-DSA-65, ML-DSA-87) for multi-certificate generation, defaulting to ["RSA"] for backward compatibility.
  • Add :SSLGroups option to control key exchange group such as ML-KEM in PQC.
  • Add :SSLSignatureAlgorithms, :SSLClientSignatureAlgorithms to control signature algorithms such as ML-DSA-NN in PQC, and RSA in non-PQC.
  • Add tool/create_certs.sh to generate test/drb/fixtures/*.{crt,key} to test with pre-generated certs/keys and add DRbTests::Fixtures module to read the certs/keys.
  • Add test/drb/test_ssl.rb to test lib/drb/ssl.rb as an unit test level. This approach aligns with test/drb/test_acl.rb to test lib/drb/acl.rb as an unit test level.
  • Add TestDRbSSLPQC, TestDRbSSLPQCMultiCertMLDSA65, TestDRbSSLPQCMultiCertRSA in test/drb/test_drbssl.rb. TestDRbSSLPQC is to test single PQC ML-KEM/ML-DSA server via test/drb/ut_drb_drbssl_pqc.rb. The testing class is inspired by TestDRbSSLCore. TestDRbSSLPQCMultiCertMLDSA65 and TestDRbSSLPQCMultiCertRSA are to test ML-DSA-65 (PQC) and RSA (non-PQC) dual (multiple) certificate server with client certificate via test/drb/ut_drb_drbssl_pqc_multi_cert.rb. The test is designed for a high-security use case with :SSLVerifyMode OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT.

Assisted-by: Claude:claude-opus-4-6[1m]

Notes

CI cases supporting PQC

PQC (ML-KEM/ML-DSA) works in OpenSSL >= 3.5. OpenSSL 3.5 added the feature. And works in Ruby OpenSSL >= 4.0. Ruby OpenSSL 4.0.0 added some functions in PQC use cases, and fixed a bug.

The .github/workflows/test.yml uses runner ubuntu-latest, macos-latest, windows-latest.

According to https://github.com/actions/runner-images, ubuntu-latest is ubuntu-24.04, macos-latest is macOS-26-arm64, windows-latest is windows-2025-vs2026.

The ubuntu-24.04 uses OpenSSL 3.0.13 which doesn't support PQC. The windows-2025-vs2026 uses OpenSSL 3.6.3 which supports PQC. The macos-26 uses OpenSSL 3.6.2 which supports PQC. The new PQC tests should be executed on the macos-latest and windows-latest CI cases.

test/drb/test_ssl.rb testing lib/drb/ssl.rb as an unit test level

I checked all the existing test/drb/test_*.rb files.

  • test/drb/test_acl.rb tests drb/acl.rb as an unit test level.
  • test/drb/test_drbobject.rb tests DRbObject class as an unit test level.
  • test/drb/test_drb.rb tests druby protocol as an integration test level.
  • test/drb/test_drbssl.rb tests drbssl protocol as an integration test level.
  • test/drb/test_drbunix.rb is tests drbunix protocol as an integration test level.

So, I created test/drb/test_ssl.rb to test DRb::DRbSSLSocket::SSLConfig in lib/drb/ssl.rb as an unit test level.

tool/create_certs.sh design decisions

The tool/create_certs.sh is inspired by ruby/rubygems#9678. The directory test/drb/fixtures to manage SSL key/cert files is inspired by ruby/openssl managing SSL keys in test/openssl/fixtures/pkey directory. ruby/openssl manages only key files, not certificate files. ruby/openssl is generating testing certificates from the keys in tests.

Testing in RubyCI servers

I plan to test this PR with RHEL 9 server (OpenSSL version is >= 3.5, but OpenSSL config disables PQC by default), which is the case of support_pqc_handshake? is false ,and OpenBSD server as I saw the following logic in DRbSSLService, test/drb/test_drbssl.rb.

    if RUBY_PLATFORM.match?(/openbsd/)
      config[:SSLMinVersion] = OpenSSL::SSL::TLS1_2_VERSION
      config[:SSLMaxVersion] = OpenSSL::SSL::TLS1_2_VERSION
    end

Edited: I confirmed the tests passed in RubyCI RHEL 9 and OpenBSD servers.

drbssl PQC tests

Single cert tests ML-DSA-65

This test with TestDRbSSLPQC and DRbSSLPQCService is inspired by my proof-of-concept "## drbssl (SSL) auto-generated ML-DSA-65 cert". Also closed to the TestDRbSSLCore and DRbSSLService.

Multi cert tests ML-DSA-65/RSA

This test is inspired by my proof-of-concept "drbssl (SSL) pre-generated ML-DSA-65/RSA multi cert with client cert" case, and also inspired by ruby/openssl test/openssl/test_ssl.rb test_pqc_sigalg (https://github.com/ruby/openssl/blob/9796ee8f47003ec78fd8e052bc8dd6d1fcb0ae2b/test/openssl/test_ssl.rb#L2097).

PQC multi cert tests are executed via the following classes.

  • test/drb/test_drbssl.rb
    • TestDRbSSLPQCMultiCertMLDSA65, DRbSSLPQCMultiCertMLDSA65Service
    • TestDRbSSLPQCMultiCertRSA, DRbSSLPQCMultiCertRSAService
  • test/drb/ut_drb_drbssl_pqc_multi_cert.rb

It is hard to understand the testing framework in test/drb.

In DRbSSLPQCMultiCertMLDSA65Service, there are manager_config and client_config. manager_config is to manage the config used in manager to manage a child process ut_drb_drbssl_pqc_multi_cert.rb in this case. The main test workflow is between the server test/drb/ut_drb_drbssl_pqc_multi_cert.rb and client with client_config part. Client with client_config connects to the server ut_drb_drbssl_pqc_multi_cert.rb. However, it seems the ut_drb_drbssl_pqc_multi_cert.rb's config is also used as a client to connect to the server manager_config.

@junaruga

Copy link
Copy Markdown
Member Author

I see the following CI failure. Let me fix it.

https://github.com/ruby/drb/actions/runs/30444292244/job/90550763624?pr=53

@junaruga
junaruga marked this pull request as draft July 29, 2026 10:40
Comment thread lib/drb/ssl.rb Outdated
@junaruga

Copy link
Copy Markdown
Member Author

I see the following CI failure. Let me fix it.

https://github.com/ruby/drb/actions/runs/30444292244/job/90550763624?pr=53

The cause of the CI failure was that OpenSSL::PKey::PKey#public_to_der didn't exist in openssl gem included in Ruby 2.7.0. It seems the method was added in openssl gem 2.2.0. I am not sure what the openssl gem version is in Ruby 2.7.0, as I couldn't find constant variable OpenSSL::VERSION in the openssl gem.

https://github.com/ruby/openssl/blob/v2.2.0/History.md?plain=1#L72-L75

Now use OpenSSL::PKey::RSA#public_key as before in RSA case.

cert.public_key = pkey.public_key

And use the following logic in ML-DSA-NN case.

cert.public_key = OpenSSL::PKey.read(pkey.public_to_der)

@junaruga

junaruga commented Jul 30, 2026

Copy link
Copy Markdown
Member Author

I plan to test this PR with RHEL 9 server (OpenSSL version is >= 3.5, but OpenSSL config disables PQC by default), which is the case of support_pqc_handshake? is false ,and OpenBSD server as I saw the following logic in DRbSSLService, test/drb/test_drbssl.rb.

I tested this PR in RubyCI's RHEL 9 and OpenBSD servers.

In RHEL 9 server, I confirmed the tests passed. The ML-DSA tests are successfully omitted by support_pqc_handshake? in test/drb/drbtest.rb.

In OpenBSD server, I confirmed the tests passed as well. The used OpenSSL version was LibreSSL 4.3.0.

In DRbSSLService#start, test/drb/test_drbssl.rb, there is the following logic as I mentioned.

    if RUBY_PLATFORM.match?(/openbsd/)
      config[:SSLMinVersion] = OpenSSL::SSL::TLS1_2_VERSION
      config[:SSLMaxVersion] = OpenSSL::SSL::TLS1_2_VERSION
    end

I was not sure if DRbSSLPQCService#start, DRbSSLPQCMultiCertMLDSA65Service#start and DRbSSLPQCMultiCertRSAService#start needs the openbsd guard logic as well.

However, TestDRbSSLPQC, TestDRbSSLPQCMultiCertMLDSA65 and TestDRbSSLPQCMultiCertRSA skip OpenBSD's LibreSSL case by omit_unless_support_pqc in #setup before executing DRbSSLPQCService#start, DRbSSLPQCMultiCertMLDSA65Service#start and DRbSSLPQCMultiCertRSAService#start. So, we don't need the openbsd guard to these new 3 classes, DRbSSLPQCService, DRbSSLPQCMultiCertMLDSA65Service and DRbSSLPQCMultiCertRSAService.

@junaruga
junaruga marked this pull request as ready for review July 30, 2026 19:41
@junaruga

junaruga commented Jul 30, 2026

Copy link
Copy Markdown
Member Author

@seki or other maintainers, I updated notes section on the first comment. This PR is ready to review. I would appreciate your reviews.

@junaruga

Copy link
Copy Markdown
Member Author

@rhenium I would appreciate your review for this PR as Ruby OpenSSL (openssl gem) maintainer.

Comment thread test/drb/ut_drb_drbssl_pqc_multi_cert.rb Outdated
@junaruga

Copy link
Copy Markdown
Member Author

I added and updated the code comments.

Comment thread test/drb/test_drbssl.rb
Comment thread lib/drb/ssl.rb Outdated
Comment thread lib/drb/ssl.rb Outdated
Comment thread lib/drb/ssl.rb Outdated
@rhenium

rhenium commented Aug 1, 2026

Copy link
Copy Markdown
Member
  • Add :SSLPrivateKeyAlgorithms option accepting an Array of key algorithms (RSA, ML-DSA-44, ML-DSA-65, ML-DSA-87) for multi-certificate generation, defaulting to ["RSA"] for backward compatibility.

I won't be the one deciding whether to merge this, but I'm not really convinced there's much value in being able to set up a server with multiple self-signed certificates.

@hsbt

hsbt commented Aug 6, 2026

Copy link
Copy Markdown
Member

@kou Could you review this? @junaruga introduced this work at today's Dev meeting.

I would appreciate it if you could review this, especially regarding the API changes such as the multiple certificates feature that was added in this PR.

Comment thread lib/drb/ssl.rb Outdated
Comment thread lib/drb/ssl.rb Outdated
Comment thread lib/drb/ssl.rb
Comment thread lib/drb/drb.rb Outdated
Comment thread tool/create_certs.sh Outdated
Comment thread lib/drb/ssl.rb Outdated
Comment thread lib/drb/ssl.rb Outdated
@junaruga

Copy link
Copy Markdown
Member Author

Sorry for my late response. Thanks for your reviews. I will check the reviews and fix for them.

This commit fixes the following CI failures in Windows.
I don't know why this change fixed. Perhaps Bundler's handling with git
repository is different.

https://github.com/ruby/drb/actions/runs/32029577375/job/95386338154?pr=54
```
D:/a/drb/drb/test/lib/helper.rb:2:in 'Kernel#require': cannot load such file -- core_assertions (LoadError)
	from D:/a/drb/drb/test/lib/helper.rb:2:in '<top (required)>'
	from <internal:D:/rubyinstaller-head-x64/lib/ruby/4.1.0+4/rubygems/core_ext/kernel_require.rb>:139:in 'Kernel#require'
rake aborted!
Command failed with status (1)
D:/a/drb/drb/vendor/bundle/ruby/4.1.0+4/gems/rake-13.4.2/exe/rake:27:in '<top (required)>'
D:/rubyinstaller-head-x64/bin/bundle:33:in '<main>'
Tasks: TOP => default => test
(See full trace by running task with --trace)
Error: Process completed with exit code 1.
```
OpenSSL::PKey::RSA#public_key is obsolete according to ruby/openssl#1092.
@junaruga

junaruga commented Aug 18, 2026

Copy link
Copy Markdown
Member Author

I rebased this PR, fixing the things mentioned by reviews.

First, I backed up the initial PR into my fork repository's wip/support-pqc-pr1 branch.

Now this PR has 3 commits.

The 1st commit is the same with #54 to pass the CI. I will remove this commit on this PR after #54 is merged or someone fixed the issue causing failing Windows CI cases.

The 2nd commit is for refactoring, which was mentioned in the review. But it is not related to this PR.

The 3rd commit is the main commit. I simplified the tests in test/drb/test_drbssl.rb without new service classes and test/drb/ut_*.rb files. I also simplified the omit_unless_support_pqc method in test/drb/drbtest.rb to align with the updated omit logic in the test/rubygems/pqc_utilities.rb.

Commit messages

The 2nd commit

Remove OpenSSL::PKey::RSA#public_key

OpenSSL::PKey::RSA#public_key is obsolete according to ruby/openssl#1092.

The 3rd commit (main commit)

Add post-quantum cryptography (PQC) support to SSLConfig

DRb::DRbSSLSocket::SSLConfig already works with pre-generated ML-DSA cert/key by
:SSLCertificate and :SSLPrivateKey config options.

This commit adds the following features in PQC use cases to #setup_certificate
and #setup_ssl_context.

  • Add :SSLCertificates config option accepting an Array of
    [certificate, private_key] pairs for multiple certificate
    support via OpenSSL::SSL::SSLContext#add_certificate
    changing from OpenSSL::SSL::SSLContext#cert and #key.
    Because an SSL server that accepts clients with either ML-DSA-NN
    or RSA certificates is useful in the use case of PQC migration from RSA
    (non-PQC) to ML-DSA (PQC).
    :SSLCertificate and :SSLPrivateKey are available for backward compatibility.
    But use OpenSSL::SSL::SSLContext#add_certificate internally.
    This is a behavior change.
  • Add :SSLPrivateKeyAlgorithms option accepting an Array of key
    algorithms (RSA, ML-DSA-44, ML-DSA-65, ML-DSA-87) for
    multi-certificate generation, defaulting to ["RSA"] for backward
    compatibility.
  • Add :SSLGroups option to control key exchange group such as ML-KEM in PQC.
  • Add :SSLSignatureAlgorithms, :SSLClientSignatureAlgorithms to control
    signature algorithms such as ML-DSA-NN in PQC, and RSA in non-PQC.
  • Add tool/create_certs.rb to generate test/drb/fixtures/*.{crt,key}
    to test with pre-generated certs/keys and add DRbTests::Fixtures module
    to read the certs/keys.
  • Add test/drb/test_ssl.rb to test lib/drb/ssl.rb at the unit test level.
    This approach aligns with test/drb/test_acl.rb to test lib/drb/acl.rb
    at the unit test level.
  • Add TestDRbSSLPQC, TestDRbSSLPQCMultipleCert in test/drb/test_drbssl.rb.
    TestDRbSSLPQC is to test single PQC ML-KEM/ML-DSA server and client.
    TestDRbSSLPQCMultipleCert is to test ML-DSA-65 (PQC) and RSA (non-PQC)
    multiple certificate server with client certificate verification.
    The test is designed for a high-security use case with :SSLVerifyMode
    OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT.

Assisted-by: Claude:claude-opus-4-6[1m]

@junaruga

Copy link
Copy Markdown
Member Author

@kou Could you review again? Thanks.
@rhenium Could you review again especially for OpenSSL logic parts? Thanks.

@junaruga

junaruga commented Aug 19, 2026

Copy link
Copy Markdown
Member Author
  • Add :SSLPrivateKeyAlgorithms option accepting an Array of key algorithms (RSA, ML-DSA-44, ML-DSA-65, ML-DSA-87) for multi-certificate generation, defaulting to ["RSA"] for backward compatibility.

I won't be the one deciding whether to merge this, but I'm not really convinced there's much value in being able to set up a server with multiple self-signed certificates.

This is a valid point. I believe multiple (dual) certification server accepting both non-PQC (RSA) and PQC (ML-DSA) is useful in the process of migrating the server from non-PQC to PQC. But the :SSLPrivateKeyAlgorithms option creates self-signed certificates. Maybe this feature is not used in production.

I think as setup_certificate already has auto-generated self-signed RSA certificate, adding SSLPrivateKeyAlgorithms option is a natural path to extend when supporting multiple certificates. Maybe this may be useful when running multiple certification server in testing environment before running multiple certification server in production. They don't need to create SSL key/cert manually in the testing environment. When they are not familiar with how to create SSL key/cert, this auto-generated key/cert feature looks helpful for them to try drbssl protocol server.

DRb::DRbSSLSocket::SSLConfig already works with pre-generated ML-DSA cert/key by
:SSLCertificate and :SSLPrivateKey config options.

This commit adds the following features in PQC use cases to #setup_certificate
and #setup_ssl_context.

* Add :SSLCertificates config option accepting an Array of
  [certificate, private_key] pairs for multiple certificate
  support via OpenSSL::SSL::SSLContext#add_certificate
  changing from OpenSSL::SSL::SSLContext#cert and #key.
  Because an SSL server that accepts clients with either ML-DSA-NN
  or RSA certificates is useful in the use case of PQC migration from RSA
  (non-PQC) to ML-DSA (PQC).
  :SSLCertificate and :SSLPrivateKey are available for backward compatibility.
  But use OpenSSL::SSL::SSLContext#add_certificate internally.
  This is a behavior change.
* Add :SSLPrivateKeyAlgorithms option accepting an Array of key
  algorithms (RSA, ML-DSA-44, ML-DSA-65, ML-DSA-87) for
  multi-certificate generation, defaulting to ["RSA"] for backward
  compatibility.
* Add :SSLGroups option to control key exchange group such as ML-KEM in PQC.
* Add :SSLSignatureAlgorithms, :SSLClientSignatureAlgorithms to control
  signature algorithms such as ML-DSA-NN in PQC, and RSA in non-PQC.
* Add tool/create_certs.rb to generate test/drb/fixtures/*.{crt,key}
  to test with pre-generated certs/keys and add DRbTests::Fixtures module
  to read the certs/keys.
* Add test/drb/test_ssl.rb to test lib/drb/ssl.rb at the unit test level.
  This approach aligns with test/drb/test_acl.rb to test lib/drb/acl.rb
  at the unit test level.
* Add TestDRbSSLPQC, TestDRbSSLPQCMultipleCert in test/drb/test_drbssl.rb.
  TestDRbSSLPQC is to test single PQC ML-KEM/ML-DSA server and client.
  TestDRbSSLPQCMultipleCert is to test ML-DSA-65 (PQC) and RSA (non-PQC)
  multiple certificate server with client certificate verification.
  The test is designed for a high-security use case with :SSLVerifyMode
  OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT.

Assisted-by: Claude:claude-opus-4-6[1m]

@kou kou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you review auto generated code including tests carefully before you request a review by maintainers...?

Comment thread lib/drb/ssl.rb
Comment thread lib/drb/ssl.rb
# Establish the OpenSSL::SSL::SSLContext with the configuration
# parameters provided.
def setup_ssl_context
ctx = ::OpenSSL::SSL::SSLContext.new

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ctx = ::OpenSSL::SSL::SSLContext.new
ctx = OpenSSL::SSL::SSLContext.new

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This :: has already existed on the master branch before this PR. But as this line is included in this PR's change, I will fix it.

ctx = ::OpenSSL::SSL::SSLContext.new

Comment thread lib/drb/ssl.rb
# parameters provided.
def setup_ssl_context
ctx = ::OpenSSL::SSL::SSLContext.new
@certs&.each do |cert, pkey|

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need & here? setup_certificate ensures @certs, right?

@junaruga junaruga Aug 21, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think we need & here. Because there is the case that @certs is nil in the following part, when the config have neither :SSLCertificates, and :SSLCertificate and :SSLPrivateKey.

      def initialize(config)
        ...
        @certs = if config.key?(:SSLCertificates)
                   config[:SSLCertificates]
                 elsif config[:SSLCertificate] && config[:SSLPrivateKey]
                   [[config[:SSLCertificate], config[:SSLPrivateKey]]]
                 end

One case @certs is nil is for example below.

config = {
  SSLCertName: CERT_NAME
}
ssl_conf = DRb::DRbSSLSocket::SSLConfig.new(config)
ssl_conf.setup_certificate

We may want to write explicitly the nil case as follows. However, rubocop deals with this as style error. So, I removed the else nil part.

diff --git a/lib/drb/ssl.rb b/lib/drb/ssl.rb
index 3f46d09..6e923d4 100644
--- a/lib/drb/ssl.rb
+++ b/lib/drb/ssl.rb
@@ -169,6 +169,8 @@ module DRb
                    config[:SSLCertificates]
                  elsif config[:SSLCertificate] && config[:SSLPrivateKey]
                    [[config[:SSLCertificate], config[:SSLPrivateKey]]]
+                 else
+                   nil
                  end
         @pkey_algs = self[:SSLPrivateKeyAlgorithms]
         @ssl_ctx  = nil

Comment thread lib/drb/ssl.rb

private

def setup_certificate_one(pkey_alg)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you rename this to generate_certificate or something? This doesn't set generated cert to any instance variables.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The used term in setup_certificate_one is not set but setup. In my understanding, this doesn't mean setter method to set something to instance variables. For example Test::Unit::TestCase#setup is not a setter method. The term setup is like prepare. So, the setup_certificate_one means prepare one certificate. But if this method name confuses you, I will rename this method to generate_certificate.

Comment thread test/drb/drbtest.rb
end

def probe_pqc_handshake
server = TCPServer.new('127.0.0.1', 0)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use TCPServer.open do ... end instead?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created the probe_pqc_handshake based on the content of probe_pqc_handshake in ruby/rubygems. Because I wanted to align with the content between rubygems and drb. I am considering moving these PQC related methods into test-unit-ruby-core gem in the future if more ruby/* projects uses these methods.

On the other hand, I can understand a merit of applying the TCPServer.open do ... end.

This is a trade-off. And I will fix on your way.

Comment thread test/drb/test_ssl.rb
ssl_conf.setup_ssl_context
ssl_ctx = ssl_conf.instance_variable_get(:@ssl_ctx)

assert_instance_of(OpenSSL::SSL::SSLContext, ssl_ctx)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is tested in this test?

@junaruga junaruga Aug 21, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following lines in lib/drb/ssl.rb are tested in this test test_setup_ssl_context_sigalgs in the case of non-PQC (RSA) with SSLSignatureAlgorithms: 'rsa_pss_rsae_sha256'. The reason why I added this test is because I believe that increasing the testing coverage rate is better.

      def setup_ssl_context
...
        if self[:SSLSignatureAlgorithms]
          ctx.sigalgs = self[:SSLSignatureAlgorithms]
        end
...

Comment thread test/drb/test_ssl.rb
ssl_conf.setup_ssl_context
ssl_ctx = ssl_conf.instance_variable_get(:@ssl_ctx)

assert_instance_of(OpenSSL::SSL::SSLContext, ssl_ctx)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again the following lines in lib/drb/ssl.rb are tested in this test test_setup_ssl_context_sigalgs_pqc in the case of PQC with SSLSignatureAlgorithms: 'mldsa65:rsa_pss_rsae_sha256'. The ctx.sigalgs to set 'mldsa65:rsa_pss_rsae_sha256' means the signature algorithm accepts mldsa65 (ML-DSA-65) which is a typical PQC supported signature algorithm and rsa_pss_rsae_sha256 (RSA) which is also a typical non-PQC signature algorithm. I think that the dual PQC, non-PQC certificates case is typical in PQC case in the process of migration from non-PQC to PQC.

The reason why I added this test is because I believe that increasing the testing coverage rate is better.

      def setup_ssl_context
...
        if self[:SSLSignatureAlgorithms]
          ctx.sigalgs = self[:SSLSignatureAlgorithms]
        end
...

I am inspired by the ruby/openssl's test_pqc_sigalg test using ctx.sigalgs = "rsa_pss_rsae_sha256:mldsa65" which I added there in the past.

https://github.com/ruby/openssl/blob/2c109b23dfca1d2ddabddfebbfe1b2397aea59e3/test/openssl/test_ssl.rb#L2112

The dual PQC, non-PQC certificate server is encouraged in PQC case. Below is my company Red Hat's blog showing ML-DSA, RSA dual certificate server in PQC as a reference.

https://www.redhat.com/en/blog/post-quantum-cryptography-red-hat-enterprise-linux-10

$ openssl s_server
-cert localhost-mldsa.crt -key localhost-mldsa.key
-dcert localhost-rsa.crt -dkey localhost-rsa.key >/dev/null &

Comment thread test/drb/test_ssl.rb
Comment on lines +210 to +234
def test_setup_ssl_context_sigalgs_method_not_supported
ctx_class = OpenSSL::SSL::SSLContext
unless ctx_class.method_defined?(:sigalgs=)
omit 'sigalgs= already not supported'
end

orig = ctx_class.instance_method(:sigalgs=)
ctx_class.undef_method(:sigalgs=)
begin
config = {
SSLCertificate: Fixtures.read_cert('rsa_server.crt'),
SSLPrivateKey: Fixtures.read_pkey('rsa_server.key'),
SSLSignatureAlgorithms: 'rsa_pss_rsae_sha256'
}
ssl_conf = DRb::DRbSSLSocket::SSLConfig.new(config)
error = assert_raise(NoMethodError) do
ssl_conf.setup_ssl_context
end
assert_equal("undefined method 'sigalgs=' for "\
"an instance of OpenSSL::SSL::SSLContext",
error.message)
ensure
ctx_class.define_method(:sigalgs=, orig)
end
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need this test?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The answer is similar with my response for test_setup_certificate_unsupported_mldsa.

#53 (comment)

I originally created the test_setup_ssl_context_sigalgs_method_not_supported is to test the following part. After initial reviews, I removed the unless ... raise ... end part. However I still thought the test might be useful because OpenSSL::SSL::SSLContext#sigalgs= doesn't exist in majority of the cases on Ruby OpenSSL < 4.0.0. However, I will remove it.

      def setup_ssl_context
...
        if self[:SSLSignatureAlgorithms]
          # OpenSSL::SSL::SSLContext#sigalgs=, #client_sigalgs=, #groups= were
          # added in openssl gem 4.0.0.
          # https://github.com/ruby/openssl/blob/v4.0.0/History.md?plain=1#L25-L31
          # OpenSSL::SSL::SSLContext#sigalgs= is supported in OpenSSL >= 1.0.2.
          # https://github.com/ruby/openssl/blob/v4.0.0/ext/openssl/extconf.rb#L142-L143
          unless ctx.respond_to?(:sigalgs=)
            raise(DRbBadConfig,
                  unsupported_message(
                    ':SSLSignatureAlgorithms', '4.0.0', '1.0.2'
                  ))
          end
          ctx.sigalgs = self[:SSLSignatureAlgorithms]
        end
...

Comment thread test/drb/test_ssl.rb
Comment on lines +236 to +252
def test_setup_ssl_context_client_sigalgs
ctx_class = OpenSSL::SSL::SSLContext
unless ctx_class.method_defined?(:client_sigalgs=)
omit 'client_sigalgs= not supported'
end

config = {
SSLCertificate: Fixtures.read_cert('rsa_server.crt'),
SSLPrivateKey: Fixtures.read_pkey('rsa_server.key'),
SSLClientSignatureAlgorithms: 'rsa_pss_rsae_sha256'
}
ssl_conf = DRb::DRbSSLSocket::SSLConfig.new(config)
ssl_conf.setup_ssl_context
ssl_ctx = ssl_conf.instance_variable_get(:@ssl_ctx)

assert_instance_of(OpenSSL::SSL::SSLContext, ssl_ctx)
end

@kou kou Aug 20, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a similar topic with https://github.com/ruby/drb/pull/53/changes#r3817894245. I assume your question here is do we need the assignment for ctx_class = OpenSSL::SSL::SSLContext?

And I think we need this assignment ctx_class = OpenSSL::SSL::SSLContext. The reason is

DRb::DRbSSLSocket::SSLConfig#setup_ssl_context uses OpenSSL::SSL::SSLContext#client_sigalgs internally in the test if the :SLClientSignatureAlgorithms config option is set. And OpenSSL::SSL::SSLContext#client_sigalgs was dded in Ruby OpenSSL (openssl gem) 4.0.0. Only Ruby 4.0.x uses Ruby OpenSSL version 4.0.x.

https://github.com/ruby/openssl/blob/v4.0.0/History.md?plain=1#L25-L27

      def setup_ssl_context
...
        if self[:SSLClientSignatureAlgorithms]
          ctx.client_sigalgs = self[:SSLClientSignatureAlgorithms]
        end
...

I think without this assignment and omit logic, the test raises NoMethodError.

Comment thread test/drb/test_ssl.rb
Comment on lines +254 to +271
def test_setup_ssl_context_client_sigalgs_pqc
ctx_class = OpenSSL::SSL::SSLContext
unless ctx_class.method_defined?(:client_sigalgs=)
omit 'client_sigalgs= not supported'
end
omit_unless_support_pqc

config = {
SSLCertificate: Fixtures.read_cert('mldsa65_server.crt'),
SSLPrivateKey: Fixtures.read_pkey('mldsa65_server.key'),
SSLClientSignatureAlgorithms: 'mldsa44:mldsa65:mldsa87'
}
ssl_conf = DRb::DRbSSLSocket::SSLConfig.new(config)
ssl_conf.setup_ssl_context
ssl_ctx = ssl_conf.instance_variable_get(:@ssl_ctx)

assert_instance_of(OpenSSL::SSL::SSLContext, ssl_ctx)
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too many ditto... I give up reviewing this...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume your question is do we need the assignment ctx_class = OpenSSL::SSL::SSLContext. And my answer is yes I think we need the assignment. The test test_setup_ssl_context_client_sigalgs is for a non-PQC case with SSLClientSignatureAlgorithms: 'rsa_pss_rsae_sha256', and this test test_setup_ssl_context_client_sigalgs_pqc is for a PQC case with SSLClientSignatureAlgorithms: 'mldsa44:mldsa65:mldsa87'.

Comment thread tool/create_certs.rb
Comment on lines +22 to +23
sh 'openssl', 'genpkey', *genpkey_args,
'-out', File.join(dir, 'ca.key')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really think that this .sh -> .rb conversion meaningful...? Could you use openssl gem instead of opnessl command?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you expected I would use openssl gem here. But I did implement differently against your expectation.

Because when I saw your suggestion to change the tool/create_certs.sb to tool/create_certs.rb. I assumed you didn't like the syntax of sh/bash, because of lower maintainability. And the openssl command is already used and verified in ruby/rubygems in tool/create_certs.sb. I would prioritized the alignment with ruby/rubygems repository over effectiveness or Ruby friendly code.

The merits of create_certs.rb with opessl gem

  • Ruby friendly. It's good for people who are familiar with openssl gem.
  • Effective without calling sub process

The merits of create_certs.rb with openssl command

  • Consistency with ruby/rubygems's tool/create_certs.sh.
  • We don't need to create new logic with openssl gem
  • The openssl commands are good for people who are more familiar with openssl commands than openssl gem like me.

I think our 2 different design decisions comes from different priorities here.

As I understood your preference now, I will use openssl gem in tool/create_cert.rb.

I understand you are busy across ruby/* libraries. Some contexts and reasons might be obvious in your mind, and you might think you didn't have to say the contexts and reasons. But it would be helpful if you would tel me the context and why reasons for your suggestion.

@junaruga

junaruga commented Aug 21, 2026

Copy link
Copy Markdown
Member Author

Could you review auto generated code including tests carefully before you request a review by maintainers...?

@kou Where did you see the code where the code is generated and but not carefully reviewed by me in this PR? I uses Claude Code as I added the text Assisted-by: Claude:claude-opus-4-6[1m]. But I think I have reviewed every lines, every characters carefully, and edited necessary parts in changed code generated by Claude Code. I write commit messages from scratch by myself. I understand some changes are against your expectations. But I think the differences of the changed code between your expectation and my actual change comes from the different design decisions and different priorities. I wrote my design decisions and priorities for every your review comments. So far I see every changes in this PR is as my intention. As this was my first big PR to the ruby/drb, I didn't understand the maintainer (you)'s preference. Now I know your reference better after your reviews.

I understand you are busy across ruby/* projects and you are experienced developer. I would appreciate your reviews. Perhaps you might have bad experiences for PRs using Claude Code. But I don't want you to see me as a lazy person here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants