Skip to content

A feature to check enabled/disabled PQC signature algorithms, key exchange groups considering OpenSSL config #1075

Open

Description

@junaruga

This issue comes from ruby/rubygems#9643 (comment).

In Fedora/RHEL, the OpenSSL config is below.

$ /bin/ruby -r openssl -e 'puts OpenSSL::Config::DEFAULT_CONFIG_FILE'
/etc/pki/tls/openssl.cnf

/etc/pki/tls/openssl.cnf

...
[ crypto_policy ]

.include = /etc/crypto-policies/back-ends/opensslcnf.config
...

RHEL 9.x (>= 9.7) has security policy DEFAULT and DEFAULT:PQ, the content of the /etc/crypto-policies/back-ends/opensslcnf.config changes by the security policies.

In security policy DEFAULT, the content is below.

# update-crypto-policies --show
DEFAULT

/etc/crypto-policies/back-ends/opensslcnf.config

CipherString = @SECLEVEL=2:kEECDH:kRSA:kEDH:kPSK:kDHEPSK:kECDHEPSK:kRSAPSK:-aDSS:-3DES:!DES:!RC4:!RC2:!IDEA:-SEED:!eNULL:!aNULL:!MD5:-SHA384:-CAMELLIA:-ARIA:-AESCCM8
Ciphersuites = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256
TLS.MinProtocol = TLSv1.2
TLS.MaxProtocol = TLSv1.3
DTLS.MinProtocol = DTLSv1.2
DTLS.MaxProtocol = DTLSv1.2
SignatureAlgorithms = ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:ed25519:ed448:rsa_pss_pss_sha256:rsa_pss_pss_sha384:rsa_pss_pss_sha512:rsa_pss_rsae_sha256:rsa_pss_rsae_sha384:rsa_pss_rsae_sha512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:RSA+SHA224
Groups = *X25519:secp256r1:X448:secp521r1:secp384r1:ffdhe2048:ffdhe3072:ffdhe4096:ffdhe6144:ffdhe8192

In security policy DEFAULT:PQ: the content is below.

# update-crypto-policies --show
DEFAULT:PQ

/etc/crypto-policies/back-ends/opensslcnf.config

CipherString = @SECLEVEL=2:kEECDH:kRSA:kEDH:kPSK:kDHEPSK:kECDHEPSK:kRSAPSK:-aDSS:-3DES:!DES:!RC4:!RC2:!IDEA:-SEED:!eNULL:!aNULL:!MD5:-SHA384:-CAMELLIA:-ARIA:-AESCCM8
Ciphersuites = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256
TLS.MinProtocol = TLSv1.2
TLS.MaxProtocol = TLSv1.3
DTLS.MinProtocol = DTLSv1.2
DTLS.MaxProtocol = DTLSv1.2
SignatureAlgorithms = ?mldsa44:?mldsa65:?mldsa87:ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:ed25519:ed448:rsa_pss_pss_sha256:rsa_pss_pss_sha384:rsa_pss_pss_sha512:rsa_pss_rsae_sha256:rsa_pss_rsae_sha384:rsa_pss_rsae_sha512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:RSA+SHA224
Groups = *?X25519MLKEM768:?x25519_mlkem768:?SecP256r1MLKEM768:?p256_mlkem768:?SecP384r1MLKEM1024:?p384_mlkem1024/*X25519:secp256r1:X448:secp521r1:secp384r1:ffdhe2048:ffdhe3072:ffdhe4096:ffdhe6144:ffdhe8192

The difference of the opensslcnf.txt between security policy DEFAULT and DEFAULT:PQ is below.

$ diff -u opensslcnf.txt.default opensslcnf.txt.default_pq
--- opensslcnf.txt.default	2026-03-04 10:13:14.000000000 +0000
+++ opensslcnf.txt.default_pq	2026-06-26 15:50:55.000000000 +0100
@@ -4,5 +4,5 @@
 TLS.MaxProtocol = TLSv1.3
 DTLS.MinProtocol = DTLSv1.2
 DTLS.MaxProtocol = DTLSv1.2
-SignatureAlgorithms = ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:ed25519:ed448:rsa_pss_pss_sha256:rsa_pss_pss_sha384:rsa_pss_pss_sha512:rsa_pss_rsae_sha256:rsa_pss_rsae_sha384:rsa_pss_rsae_sha512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:RSA+SHA224
-Groups = *X25519:secp256r1:X448:secp521r1:secp384r1:ffdhe2048:ffdhe3072:ffdhe4096:ffdhe6144:ffdhe8192
+SignatureAlgorithms = ?mldsa44:?mldsa65:?mldsa87:ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:ed25519:ed448:rsa_pss_pss_sha256:rsa_pss_pss_sha384:rsa_pss_pss_sha512:rsa_pss_rsae_sha256:rsa_pss_rsae_sha384:rsa_pss_rsae_sha512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:RSA+SHA224
+Groups = *?X25519MLKEM768:?x25519_mlkem768:?SecP256r1MLKEM768:?p256_mlkem768:?SecP384r1MLKEM1024:?p384_mlkem1024/*X25519:secp256r1:X448:secp521r1:secp384r1:ffdhe2048:ffdhe3072:ffdhe4096:ffdhe6144:ffdhe8192

In security policy DEFAULT:PQ, signature algorithms, ML-DSA-NN (mldsa44, mldsa65 and mldsa87) are added.

SignatureAlgorithms = ?mldsa44:?mldsa65:?mldsa87: ...

In security policy DEFAULT:PQ, the groups, ML-KEM groups (X25519MLKEM768, x25519_mlkem768, SecP256r1MLKEM768, p256_mlkem768, SecP384r1MLKEM1024, p384_mlkem1024) are also added.

Groups = *?X25519MLKEM768:?x25519_mlkem768:?SecP256r1MLKEM768:?p256_mlkem768:?SecP384r1MLKEM1024:?p384_mlkem1024/ ...

Is there a way to check the used PQC signature algorithms and groups easily to skip PQC tests in a portable way which is not platform-specific, if these signature algorithms and groups are disabled in the OpenSSL config? This logic can be used for ruby/* repositories that have PQC tests. Or are there OpenSSL C APIs to do this?

ruby/rubygems#9643 is a possible implementation to do this. However, I want to find an easier way.

I want this feature if there is not such as feature in Ruby OpenSSL. If we have such a feature, maybe we can also enable specific signature algorithms and key exchange groups to be used in the PQC tests, by overriding the OpenSSL config if these are disabled in the config.

What do you think?

Activity

  1. changed the title [-]A feature to check enabled/disabled PQC signature algorithms, key exchange groups consideirng OpenSSL config[/-] [+]A feature to check enabled/disabled PQC signature algorithms, key exchange groups considering OpenSSL config[/+] on Jun 26, 2026
  2. rhenium commented on Jun 27, 2026

    @rhenium
    Member

    The current OpenSSL C API doesn't appear to expose the corresponding getters for SSL_CTX_set1_sigalgs() and SSL_CTX_set1_groups(). If they were available, I think we could expose them, similar to how we do for SSL options and TLS 1.2 cipher suites.

    If the intent of the test is to "test PQC algorithms whenever the system supports them", then I think ruby/rubygems#9643 would be the most straightforward option at the moment. Alternatively, I think it could just special-case RHEL >= 9.7, < 10.1(?) since other distros are unlikely to do the same.

  3. junaruga commented on Jun 29, 2026

    @junaruga
    MemberAuthor

    Alternatively, I think it could just special-case RHEL >= 9.7, < 10.1(?) since other distros are unlikely to do the same.

    I investigated the case of RHEL 10.0. RHEL 10.0 is a unique feature for PQC[1] before RHEL 10.1 supports PQC by DEFAULT security policy[2].

    You are right. In RHEL 10.0, PQC is also disabled by default.

    Below is my command log in RHEL 10.0. OpenSSL version is 3.2.2.

    # cat /etc/redhat-release
    Red Hat Enterprise Linux release 10.0 (Coughlan)
    
    # rpm -q openssl
    openssl-3.2.2-16.el10.x86_64
    
    # openssl list -providers
    Providers:
      default
        name: OpenSSL Default Provider
        version: 3.2.2
        status: active
    

    However, when installing the following RPM packages, oqsprovider (PQC provider)[3] RPM is installed as a dependency of crypto-policies-pq-preview RPM package.

    # dnf install crypto-policies-pq-preview crypto-policies-scripts
    
    # rpm -q oqsprovider
    oqsprovider-0.8.0-5.el10.x86_64
    

    Then oqsprovider provider appeared. OpenSSL doesn't enable PQC yet at this moment.

    # openssl list -providers
    Providers:
      default
        name: OpenSSL Default Provider
        version: 3.2.2
        status: active
      oqsprovider
        name: OpenSSL OQS Provider
        version: 0.8.0
        status: active
    

    But after running the following command, PQC is enabled in /etc/crypto-policies/back-ends/opensslcnf.config.

    # update-crypto-policies --set DEFAULT:TEST-PQ
    
    # cat /etc/crypto-policies/back-ends/opensslcnf.config
    CipherString = @SECLEVEL=2:kEECDH:kEDH:kPSK:kDHEPSK:kECDHEPSK:kRSAPSK:-kRSA:-aDSS:-3DES:!DES:!RC4:!RC2:!IDEA:-SEED:!eNULL:!aNULL:!MD5:-SHA384:-CAMELLIA:-ARIA:-AESCCM8
    Ciphersuites = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256
    TLS.MinProtocol = TLSv1.2
    TLS.MaxProtocol = TLSv1.3
    DTLS.MinProtocol = DTLSv1.2
    DTLS.MaxProtocol = DTLSv1.2
    SignatureAlgorithms = ?mldsa44:?p256_mldsa44:?rsa3072_mldsa44:?mldsa44_pss2048:?mldsa44_rsa2048:?mldsa44_ed25519:?mldsa44_p256:?mldsa65:?p384_mldsa65:?mldsa65_pss3072:?mldsa65_rsa3072:?mldsa65_p256:?mldsa65_ed25519:?mldsa87:?p521_mldsa87:?mldsa87_p384:?mldsa87_ed448:ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:ed25519:ed448:rsa_pss_pss_sha256:rsa_pss_pss_sha384:rsa_pss_pss_sha512:rsa_pss_rsae_sha256:rsa_pss_rsae_sha384:rsa_pss_rsae_sha512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:RSA+SHA224
    Groups = ?mlkem512:?p256_mlkem512:?x25519_mlkem512:?mlkem768:?p384_mlkem768:?x448_mlkem768:?X25519MLKEM768:?x25519_mlkem768:?SecP256r1MLKEM768:?p256_mlkem768:?mlkem1024:?p521_mlkem1024:?SecP384r1MLKEM1024:?p384_mlkem1024:X25519:secp256r1:X448:secp521r1:secp384r1:ffdhe2048:ffdhe3072:ffdhe4096:ffdhe6144:ffdhe8192
    

    References

  4. junaruga commented on Jun 30, 2026

    @junaruga
    MemberAuthor

    The current OpenSSL C API doesn't appear to expose the corresponding getters for SSL_CTX_set1_sigalgs() and SSL_CTX_set1_groups(). If they were available, I think we could expose them, similar to how we do for SSL options and TLS 1.2 cipher suites.

    Right. This sounds good idea to me. If we have such getters, we can implement the logic to check if used PQC signature algorithms and key exchange groups are available in OpenSSL. The example is below.

    def pqc_available?
      ctx = OpenSSL::SSL::SSLContext.new
      # ctx.sigalgs # => ["mldsa44", "mldsa65", ..]
      # ctx.groups # => ["X25519MLKEM768", "x25519_mlkem768", ..]
      return ctx.sigalgs.include?("mldsa65") && ctx.groups.include?("X25519MLKEM768")
    end
    

    And I confirmed such pattern was already used for OpenSSL::SSL::SSLContext#options (SSL_CTX_get_options) and OpenSSL::SSL::SSLContext#ciphers (SSL_CTX_get_ciphers).

    If the intent of the test is to "test PQC algorithms whenever the system supports them", then I think ruby/rubygems#9643 would be the most straightforward option at the moment. Alternatively, I think it could just special-case RHEL >= 9.7, < 10.1(?) since other distros are unlikely to do the same.

    Yes, my motivation of this feature is to "test PQC algorithms whenever the system supports them". The current implementation TestGemRemoteFetcherLocalSSLServer.support_pqc_handshake? is okay when it is used in ruby/rubygems repository. But it is not convenient if the method is used in all the ruby/* repositories or generally in user's Ruby program. I am thinking that moving such logic to test-unit-ruby-core gem to be used from ruby/* repositories. But TestGemRemoteFetcherLocalSSLServer.support_pqc_handshake? needs mldsa65_ssl_cert.pem and mldsa65_ssl_key.pem files.

  5. junaruga commented on Jun 30, 2026

    @junaruga
    MemberAuthor

    I opened feature request issue ticket openssl/openssl#31804 for openssl/openssl.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions