Identify ML-DSA by OID and gate ML-DSA tests on the capability they need - #9853
Identify ML-DSA by OID and gate ML-DSA tests on the capability they need#9853justsmth wants to merge 2 commits into
Conversation
The ML-DSA support checks assume an SSL library either supports ML-DSA completely or not at all, and identify ML-DSA keys by the name OpenSSL 3.5 registers. Both break on libraries that implement ML-DSA differently: AWS-LC loads ML-DSA keys and certificates and signs and verifies with them, but has no keygen by algorithm name, and names OID 2.16.840.1.101.3.4.3.18 "MLDSA65". ml_dsa_key? matches ML_DSA_NAMES against ObjectId#ln, so it fails to recognise a valid ML-DSA key when the library spells the name differently, and digest_required? then raises "unsupported key algorithm" for a key RubyGems does support, making ML-DSA signed gems unusable there. Match the SubjectPublicKeyInfo OID instead, which is identical on every library. ML_DSA_NAMES becomes unused and is removed; the individual name constants stay, since create_key still passes them to OpenSSL::PKey.generate_key. support_ml_dsa_key? probes key generation but gates tests that only need loading. Four tests assert the "no ML-DSA support" path for a key or certificate read from disk, and run on a false premise where loading works but generation does not: two raise nothing and two raise a different error. Ten more use only the checked-in ML-DSA fixtures, yet are skipped for want of a capability they never exercise. Add support_ml_dsa_key_load? and gate those fourteen on it. test_gem_security.rb is unchanged, since its ML-DSA tests build keys with Gem::Security.create_key and do need the generation gate. Continues 9a43535, which separated generation from nil-digest certificate signing but not generation from loading.
|
@justsmth It seems the ruby/rubygems repository doesn't have the GitHub Actions CI case for Ruby with ruby/openssl built with AWS-LC right now. Perhaps, adding the AWS-LC latest stable version case to GitHub Actions to this repository may be helpful if we consider AWS-LC case. I haven't checked if this PR's modified tests pass for RubyGems with Ruby OpenSSL built with AWS-LC. As a reference, ruby/openssl repository has the AWS-LC latest stable version case on the CI. There is a trade-off about adding the AWS-LC case to the CI. Pros:
Cons:
I am not a maintainer of the ruby/rubygems. So, consider my opinion as assumption which may not happen. If you work on this before maintainers agree the direction, you may waste your time. The steps can be as follows.
The candidate GitHub Actions yml file to add this case is Until ruby/rubygems maintainers comment on this PR, I don't have anything to comment on this PR. I pend my approval for this PR for now, while I saw you requested a review from me using the PR's function. Let's wait for the maintainer's reviews. |
|
About the AWS-LC job, I am ok to add it. But I do not want to build AWS-LC on every run. If we can cache the build like your step 1, the job is worth it. @junaruga For the change itself, could you review this? |
What was the end-user or developer problem that led to this PR?
RubyGems currently assumes an SSL library either supports all ML-DSA operations or none of them:
Gem::Security.ml_dsa_key?identifies ML-DSA using OpenSSL 3.5 algorithm names such asML-DSA-65. Those names are library-specific; AWS-LC registers the same standard OID asMLDSA65, so RubyGems rejects a valid ML-DSA key as unsupported and cannot verify ML-DSA signed gems.Gem::PQCUtilities.support_ml_dsa_key?probes key generation but gates tests that only load checked-in keys and certificates. AWS-LC loads, signs, and verifies with ML-DSA, but does not generate an ML-DSA key by algorithm name. This causes four incorrect test failures and skips ten positive tests that AWS-LC can run.What is your fix for the problem, implemented in this PR?
ml_dsa_key?now identifies ML-DSA using the three standard SubjectPublicKeyInfo OIDs rather than library-specific display names.The tests gain a separate
support_ml_dsa_key_load?probe. Four negative tests that assert loading failure, plus ten positive fixture-based tests, now use the load capability instead of the generation capability. Tests that callGem::Security.create_keykeep the existing generation gate.These changes are combined because they test each other: re-gating the positive tests without the OID fix exposes four failures in
digest_required?, while the OID fix alone would remain untested on libraries that can load but not generate ML-DSA keys.This continues 9a43535, which separated key generation from certificate signing but not key generation from key loading.
Testing
Using Ruby master built against AWS-LC 5.7.0:
masterThe net omission change reflects ten newly exercised positive tests and four negative tests now correctly omitted.
Gem::Security::Policy#check_dataverifies an ML-DSA signature and rejects a tampered payload with this change.Using OpenSSL 3.0.13, which has no ML-DSA support, all five affected test files produce identical results before and after. The full RubyGems test suite passes, and
bin/rubocopreports no offenses on the seven changed files.I did not have an OpenSSL 3.5 build available locally. On 3.5 both capability probes remain true, and the OIDs matched here are the same OIDs exposed by its existing ML-DSA keys.
Make sure the following tasks are checked