-
Notifications
You must be signed in to change notification settings - Fork 386
Added ML-DSA support #809
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Added ML-DSA support #809
Conversation
WalkthroughAdds gated ML‑DSA support: build/config options and detection, core ML‑DSA types and utilities, OpenSSL-backed ML‑DSA backend and wrappers, PKCS#11 attributes/mechanisms and SoftHSM integration (generate/sign/verify/wrap/unwrap), CI job for OpenSSL 3.5.4, and unit tests. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant SoftHSM
participant CryptoFactory
participant OSSLMLDSA
participant OpenSSL
Client->>SoftHSM: C_GenerateKeyPair(CKM_ML_DSA_KEY_PAIR_GEN, params)
SoftHSM->>CryptoFactory: getAsymmetricAlgorithm(MLDSA)
CryptoFactory-->>OSSLMLDSA: instantiate MLDSA backend
SoftHSM->>OSSLMLDSA: generateKeyPair(parameters)
OSSLMLDSA->>OpenSSL: EVP_PKEY_CTX / EVP_PKEY_fromdata (provider)
OpenSSL-->>OSSLMLDSA: EVP_PKEY (keypair)
OSSLMLDSA-->>SoftHSM: AsymmetricKeyPair (pub/priv wrappers)
SoftHSM->>SoftHSM: create PKCS#11 objects (CKA_PARAMETER_SET, CKA_VALUE, CKA_SEED)
Client->>SoftHSM: C_SignInit(..., SIGN_ADDITIONAL_CONTEXT)
SoftHSM->>SoftHSM: store SIGN_ADDITIONAL_CONTEXT in session
Client->>SoftHSM: C_Sign(...)
SoftHSM->>OSSLMLDSA: sign(privateKey, data, mechanism, context)
OSSLMLDSA->>OpenSSL: EVP_DigestSign* with hedge/context params
OpenSSL-->>OSSLMLDSA: signature
OSSLMLDSA-->>SoftHSM: signature bytes
SoftHSM-->>Client: signature
Client->>SoftHSM: C_Verify(...)
SoftHSM->>OSSLMLDSA: verify(publicKey, data, signature, mechanism, context)
OSSLMLDSA->>OpenSSL: EVP_DigestVerify* with hedge/context params
OpenSSL-->>OSSLMLDSA: verification result
OSSLMLDSA-->>SoftHSM: OK / FAIL
SoftHSM-->>Client: CKR_OK or CKR_SIGNATURE_INVALID
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Focus areas that need careful review:
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
kalvdans
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code is marked with "Copyright (c) 2010 SURFnet bv". Since you wrote it yourself, you own the copyright to the code, so remove the incorrect copyright statement.
More comments when you undraft :)
|
Copyright banners on new code have been removed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 34
🔭 Outside diff range comments (3)
src/lib/SoftHSM.cpp (3)
6731-6736: Wrap/unwarp mechanism parity + DES3 key type check is always true
- Parity: C_WrapKey allows AES_CBC/_PAD but C_UnwrapKey doesn’t allow AES_CBC at all. Either remove AES_CBC wrapping or add AES_CBC unwrapping. Same for DES3_CBC: WrapKeySym supports it but C_WrapKey rejects it due to a logic bug (see below) and C_UnwrapKey lacks a corresponding case.
- Logic bug: The DES3 key-type check uses “!= DES2 || != DES3” which is tautologically true; it should be “&&”.
case CKM_AES_CBC: case CKM_AES_CBC_PAD: if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != 16) return CKR_ARGUMENTS_BAD; break; + case CKM_DES3_CBC: + case CKM_DES3_CBC_PAD: + if (pMechanism->pParameter == NULL_PTR || + pMechanism->ulParameterLen != 8) + return CKR_ARGUMENTS_BAD; + break; @@ - if (pMechanism->mechanism == CKM_DES3_CBC && (wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 || - wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) + if (pMechanism->mechanism == CKM_DES3_CBC && + (wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 && + wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT;Follow-up: see UnwrapKeySym and C_UnwrapKey changes below to restore symmetry.
Also applies to: 6776-6779
7015-7024: Add AES_CBC/DES3_CBC support in UnwrapKeySym to match wrappingCurrently only PAD variants are supported. Either drop non-PAD wrapping or add non-PAD unwrapping. Here is the latter:
case CKM_AES_CBC_PAD: algo = SymAlgo::AES; blocksize = 16; break; + case CKM_AES_CBC: + algo = SymAlgo::AES; + blocksize = 16; + break; @@ case CKM_DES3_CBC_PAD: algo = SymAlgo::DES3; blocksize = 8; break; + case CKM_DES3_CBC: + algo = SymAlgo::DES3; + blocksize = 8; + break; @@ - case CKM_AES_CBC_PAD: - case CKM_DES3_CBC_PAD: + case CKM_AES_CBC_PAD: + case CKM_DES3_CBC_PAD: { iv.resize(blocksize); memcpy(&iv[0], pMechanism->pParameter, blocksize); @@ keydata += decryptedFinal; if(!RFC5652Unpad(keydata,blocksize)) { cipher->recycleKey(unwrappingkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); return CKR_GENERAL_ERROR; // TODO should be another error } break; + } + case CKM_AES_CBC: + case CKM_DES3_CBC: + { + iv.resize(blocksize); + memcpy(&iv[0], pMechanism->pParameter, blocksize); + + if (!cipher->decryptInit(unwrappingkey, SymMode::CBC, iv, false)) + { + cipher->recycleKey(unwrappingkey); + CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); + return CKR_MECHANISM_INVALID; + } + if (!cipher->decryptUpdate(wrapped, keydata)) + { + cipher->recycleKey(unwrappingkey); + CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); + return CKR_GENERAL_ERROR; + } + // Finalize decryption + if (!cipher->decryptFinal(decryptedFinal)) + { + cipher->recycleKey(unwrappingkey); + CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); + return CKR_GENERAL_ERROR; + } + keydata += decryptedFinal; + break; }Also applies to: 7051-7083
7361-7374: C_UnwrapKey parity with wrapping + fix DES3 key-type checkAllow non-PAD AES_CBC/DES3_CBC with proper IV length checks and fix the DES3 key-type check.
case CKM_RSA_AES_KEY_WRAP: rv = MechParamCheckRSAAESKEYWRAP(pMechanism); if (rv != CKR_OK) return rv; break; case CKM_AES_CBC: + if (pMechanism->pParameter == NULL_PTR || + pMechanism->ulParameterLen != 16) + return CKR_ARGUMENTS_BAD; + break; + case CKM_DES3_CBC: + if (pMechanism->pParameter == NULL_PTR || + pMechanism->ulParameterLen != 8) + return CKR_ARGUMENTS_BAD; + break; case CKM_AES_CBC_PAD: // TODO check block length if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != 16) return CKR_ARGUMENTS_BAD; break; @@ - if (pMechanism->mechanism == CKM_DES3_CBC && (unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 || - unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) + if (pMechanism->mechanism == CKM_DES3_CBC && + (unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 && + unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT;Also applies to: 7415-7417
♻️ Duplicate comments (1)
src/lib/SoftHSM.cpp (1)
13004-13005: Re: make helper methods static or move them out of the class (still applicable)The previous remark about marking these helpers static or moving them out applies here as well; the implicit ‘this’ is not used.
If you want, I can prepare a follow-up patch to make all get/set*Key helpers static free functions for consistency.
🧹 Nitpick comments (60)
src/lib/crypto/test/CMakeLists.txt (1)
25-25: Guard MLDSATests.cpp behind ENABLE_MLDSAML-DSA tests are currently always compiled, even when the feature is disabled; wrapping them in the existing
ENABLE_MLDSAoption prevents needless builds and keeps backend-only configurations working.• File:
src/lib/crypto/test/CMakeLists.txt(around line 25)Apply this diff to remove the unconditional entry and append it only when
ENABLE_MLDSAis on:--- a/src/lib/crypto/test/CMakeLists.txt +++ b/src/lib/crypto/test/CMakeLists.txt @@ –22,7 +22,10 @@ set(SOURCES PKCS11ModuleTests.cpp PKCS11SessionTests.cpp PKCS11ObjectTests.cpp - MLDSATests.cpp ) +# Only build ML-DSA tests when the feature is enabled +if(ENABLE_MLDSA) + list(APPEND SOURCES MLDSATests.cpp) +endif()README.md (2)
85-85: Replace hard tab with spaces (MD010) on the new option linemarkdownlint flagged a hard tab on this newly added line. Use spaces for indentation to satisfy MD010.
Apply this diff:
- --enable-mldsa Enable support for ML-DSA (default detect) + --enable-mldsa Enable support for ML-DSA (default detect)
85-85: Clarify minimum OpenSSL version required for ML-DSASince ML-DSA support is only available with OpenSSL >= 3.5 (per the PR description), it would help users if we document this requirement alongside the flag or in the Dependencies section.
Proposed wording to add under “Dependencies” or as a parenthetical on the option line:
- “ML-DSA requires OpenSSL 3.5 or newer when using the OpenSSL backend.”
src/lib/crypto/CMakeLists.txt (2)
75-78: Gate ML-DSA sources on ENABLE_MLDSA in CMakeTo avoid compiling empty or unsupported ML-DSA wrappers when the feature is disabled (or OpenSSL lacks ML-DSA), wrap the four OSSLMLDSA source files in the existing
WITH_OPENSSLblock under anENABLE_MLDSAguard, and defineWITH_ML_DSAwhen enabled.• File:
src/lib/crypto/CMakeLists.txt(around lines 75–78)if(WITH_OPENSSL) list(APPEND SOURCES OSSLCryptoFactory.cpp OSSLEDDSA.cpp - OSSLMLDSA.cpp - OSSLMLDSAKeyPair.cpp - OSSLMLDSAPrivateKey.cpp - OSSLMLDSAPublicKey.cpp ) + + if(ENABLE_MLDSA) + list(APPEND SOURCES + OSSLMLDSA.cpp + OSSLMLDSAKeyPair.cpp + OSSLMLDSAPrivateKey.cpp + OSSLMLDSAPublicKey.cpp + ) + target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_ML_DSA) + endif() endif()• This matches the existing
#ifdef WITH_ML_DSAusage throughout the code (e.g., inOSSLMLDSA*.cppandSoftHSM.cpp), ensuring ML-DSA files are only built—and the macro only defined—when the feature is explicitly enabled.
31-33: Only compile ML-DSA sources when ENABLE_MLDSA is ONCurrently, the three ML-DSA files are unconditionally appended to the SOURCES list in
src/lib/crypto/CMakeLists.txt, which defeats the purpose of theENABLE_MLDSAoption defined at the project root (CMakeLists.txt:11). Wrapping them in anif(ENABLE_MLDSA)both avoids unnecessary compile costs and keeps the build graph consistent with other algorithm flags.Location
• src/lib/crypto/CMakeLists.txt: lines 31–33Suggested diff
- MLDSAParameters.cpp - MLDSAPrivateKey.cpp - MLDSAPublicKey.cppInsert after the main
list(APPEND SOURCES …)block:# ML-DSA core sources if(ENABLE_MLDSA) list(APPEND SOURCES MLDSAParameters.cpp MLDSAPrivateKey.cpp MLDSAPublicKey.cpp ) endif()Verify that
ENABLE_MLDSAis declared (found in root CMakeLists.txt at line 11)..github/workflows/ci.yml (3)
90-101: Make OpenSSL 3.5.2 discoverable at runtime; avoid brittle symlink hacks.Relying on a lib64→lib symlink is fragile. Prefer registering the library path with ldconfig, or export LD_LIBRARY_PATH for the build/test steps.
For a robust setup, append after “sudo make install”:
sudo make install > install.log - cd ${{ env.OPENSSL_INSTALL_DIR }} - sudo ln -s lib64 lib + echo "${{ env.OPENSSL_INSTALL_DIR }}/lib64" | sudo tee /etc/ld.so.conf.d/openssl-3.5.conf + sudo ldconfigAlternatively (if avoiding system config changes), export LD_LIBRARY_PATH in Build/Test steps:
- name: Build env: # Once all OpenSSL deprecations fixed, uncomment this # CXXFLAGS: -Werror OPENSSL_INSTALL_DIR: /usr/local/openssl-3.5 - LDFLAGS: "-Wl,-R/usr/local/openssl-3.5/lib64 -L/usr/local/openssl-3.5/lib64" + LDFLAGS: "-Wl,-rpath,/usr/local/openssl-3.5/lib64 -L/usr/local/openssl-3.5/lib64" + LD_LIBRARY_PATH: "/usr/local/openssl-3.5/lib64:${LD_LIBRARY_PATH}"
97-99: Surface build/install logs on failure for faster debugging.Currently build/install logs are redirected to files and lost on failure.
Emit the tail of the logs on failure:
- make -j$(nproc) > build.log - sudo make install > install.log + set -e + make -j"$(nproc)" > build.log || { echo '--- build.log (tail) ---'; tail -n +1 build.log; exit 1; } + sudo make install > install.log || { echo '--- install.log (tail) ---'; tail -n +1 install.log; exit 1; }
91-91: Trim unnecessary packages to speed up CI.checkinstall and sudo are not needed on GitHub-hosted Ubuntu runners for this build. Consider dropping them.
- sudo apt-get install -y libcppunit-dev p11-kit build-essential checkinstall zlib1g-dev sudo autoconf libtool git + sudo apt-get install -y libcppunit-dev p11-kit zlib1g-dev autoconf libtool gitsrc/lib/pkcs11/pkcs11.h (1)
1706-1751: PQ context structs and parameter-set enums: align comment and ensure ABI expectations.
- Minor: Comments say “CKA_PARAMETER_SETS” while the attribute is singular CKA_PARAMETER_SET.
- Struct field naming matches PKCS #11 style. Ensure no packing/alignment directives are needed beyond the existing header guarantees.
Apply this cosmetic comment fix:
-/* ML-DSA values for CKA_PARAMETER_SETS */ +/* ML-DSA values for CKA_PARAMETER_SET */ ... -/* SLH-DSA values for CKA_PARAMETER_SETS */ +/* SLH-DSA values for CKA_PARAMETER_SET */ ... -/* ML-KEM values for CKA_PARAMETER_SETS */ +/* ML-KEM values for CKA_PARAMETER_SET */src/bin/dump/tables.h (2)
483-485: Add mappings for ML-DSA mechanisms: good start; consider extending to hash variants.CKM_ML_DSA[_KEY_PAIR_GEN] are mapped. For completeness, you may also add the CKM_HASH_ML_DSA* entries so dumps display those by name when encountered.
I can prepare a patch adding the CKM_HASH_ML_DSA* identifiers if you want to include them now.
551-551: CKK_ML_DSA mapping is fine; optionally add CKK_ML_KEM while you're here.Even if KEM isn’t enabled yet, mapping the constant improves dump readability.
For example:
t[CKK_EC_EDWARDS] = "CKK_EC_EDWARDS"; + t[CKK_ML_KEM] = "CKK_ML_KEM"; t[CKK_ML_DSA] = "CKK_ML_DSA";CMAKE-WIN-NOTES.md (1)
55-55: Replace hard tab with spaces to satisfy markdownlint (MD010).The linter flags a hard tab on this line.
- -DENABLE_MLDSA=ON Enable support for ML-DSA + -DENABLE_MLDSA=ON Enable support for ML-DSAsrc/lib/crypto/test/Makefile.am (1)
27-27: Ensure MLDSATests.cpp is gated when ML-DSA is disabled/backends lack support.If MLDSATests.cpp compiles conditionally with #if defined(WITH_ML_DSA), you’re fine. If not, the OpenSSL 1.1.1/Botan jobs may fail to build tests.
Option A (preferred, if configure.ac defines AM_CONDITIONAL WITH_ML_DSA):
- MLDSATests.cpp \ +if WITH_ML_DSA + MLDSATests.cpp \ +endifOption B: Keep file listed but guard its contents with preprocessor in MLDSATests.cpp:
#if defined(WITH_ML_DSA) // existing tests #else // compile an empty test suite or nothing #endifWould you like me to prepare the corresponding configure.ac change to define WITH_ML_DSA for Automake?
src/lib/crypto/Makefile.am (1)
31-33: Gate ML-DSA sources behind WITH_ML_DSAThe Autotools setup already provides
AC_ARG_ENABLE(mldsa)andAM_CONDITIONAL([WITH_ML_DSA], …), so you can mirror the CMakeENABLE_MLDSAflag and avoid unconditionally compiling the ML-DSA .cpp files.Locations to update:
- src/lib/crypto/Makefile.am (around lines 31–33)
Suggested diff:
--- a/src/lib/crypto/Makefile.am +++ b/src/lib/crypto/Makefile.am @@ -28,10 +28,6 @@ libsofthsm_crypto_la_SOURCES = \ <other sources> \ - MLDSAParameters.cpp \ - MLDSAPrivateKey.cpp \ - MLDSAPublicKey.cpp - -# (previous unconditional inclusion) +# ML-DSA core sources are added only when enabled if WITH_ML_DSA libsofthsm_crypto_la_SOURCES += \ MLDSAParameters.cpp \ MLDSAPrivateKey.cpp \ MLDSAPublicKey.cpp endifCMAKE-NOTES.md (1)
14-14: Fix markdownlint: replace hard tab with spaces; optionally note OpenSSL ≥ 3.5 for ML-DSA.The linter flags a hard tab on this newly added line. Replace with spaces. Consider documenting the OpenSSL ≥ 3.5 requirement for ML-DSA builds.
Apply this diff:
- -DENABLE_MLDSA=ON Enable support for ML-DSA + -DENABLE_MLDSA=ON Enable support for ML-DSAOptionally append a note under Configure:
Note: ML-DSA requires OpenSSL 3.5 or newer when building with the OpenSSL backend.src/lib/crypto/OSSLUtil.cpp (2)
42-49: Make the parameter-set mapping const and file-local.The mapping is immutable; marking it const avoids accidental mutation and enables better optimization.
Apply this diff:
-#ifdef WITH_ML_DSA -static std::map<unsigned long, const char*> mldsaAlgNameFromParameterSet { +#ifdef WITH_ML_DSA +static const std::map<unsigned long, const char*> mldsaAlgNameFromParameterSet{ {MLDSAParameters::ML_DSA_44_PARAMETER_SET, "ML-DSA-44"}, {MLDSAParameters::ML_DSA_65_PARAMETER_SET, "ML-DSA-65"}, {MLDSAParameters::ML_DSA_87_PARAMETER_SET, "ML-DSA-87"} }; #endif
223-231: Useconst auto(orconst_iterator) for the map lookupNo mutation occurs; tightening the iterator type improves safety if
mldsaAlgNameFromParameterSetever becomesconst.
- Verified that
mldsaParameterSet2Nameis declared under#ifdef WITH_ML_DSAinOSSLUtil.h, matching the definition.Apply this diff:
-const char* OSSL::mldsaParameterSet2Name(unsigned long parameterSet) { - - std::map<unsigned long, const char*>::iterator it = mldsaAlgNameFromParameterSet.find(parameterSet); - - if (it != mldsaAlgNameFromParameterSet.end()) { - return it->second; - } +const char* OSSL::mldsaParameterSet2Name(unsigned long parameterSet) +{ + const auto it = mldsaAlgNameFromParameterSet.find(parameterSet); + if (it != mldsaAlgNameFromParameterSet.end()) + { + return it->second; + } return NULL; }src/lib/crypto/MLDSAPrivateKey.cpp (3)
27-29: Fix misleading comment.The comment says “Get the bit length” but this function returns the parameter set.
Apply this diff:
-// Get the bit length +// Get the ML-DSA parameter set from the private key length
41-42: Tighten wording in comment.Minor nit on phrasing.
Apply this diff:
-// Get the signatureLength length +// Get the signature length
82-97: Avoid shadowing and optionally validate the private key size on deserialisation.
- Local variables ‘seed’ and ‘value’ shadow members; rename for clarity.
- Optionally, reject deserialised keys with unknown private-key length to prevent invalid state early.
Apply this diff:
-bool MLDSAPrivateKey::deserialise(ByteString& serialised) -{ - ByteString seed = ByteString::chainDeserialise(serialised); - ByteString value = ByteString::chainDeserialise(serialised); - - if ((seed.size() == 0) || - (value.size() == 0)) - { - return false; - } - - setSeed(seed); - setValue(value); - - return true; -} +bool MLDSAPrivateKey::deserialise(ByteString& serialised) +{ + ByteString seedBS = ByteString::chainDeserialise(serialised); + ByteString valueBS = ByteString::chainDeserialise(serialised); + + if (seedBS.size() == 0 || valueBS.size() == 0) + { + return false; + } + + // Optional: ensure private key length matches a known ML-DSA parameter set + switch (valueBS.size()) + { + case MLDSAParameters::ML_DSA_44_PRIV_LENGTH: + case MLDSAParameters::ML_DSA_65_PRIV_LENGTH: + case MLDSAParameters::ML_DSA_87_PRIV_LENGTH: + break; + default: + return false; + } + + setSeed(seedBS); + setValue(valueBS); + return true; +}src/lib/crypto/test/MLDSATests.h (3)
7-12: Consider guarding the test with WITH_ML_DSA to avoid build issues when disabled.If the test sources are compiled unconditionally, include guards prevent build failures when ML-DSA is not enabled.
Apply this diff:
+#ifdef WITH_ML_DSA #include <cppunit/extensions/HelperMacros.h> #include "AsymmetricAlgorithm.h" +// Forward declarations if desired: +// class AsymmetricAlgorithm;And add at file end (see separate comment) a matching #endif.
--- `31-34`: **Member layout is fine; prefer forward-declare AsymmetricAlgorithm in headers to reduce coupling.** This avoids pulling extra headers into test compilations. Example: ```diff -#include "AsymmetricAlgorithm.h" +class AsymmetricAlgorithm;--- `36-36`: **Fix incorrect header-guard end comment and optionally close the WITH_ML_DSA.** The comment says EDDSATESTS while this is MLDSATests. Also close the optional WITH_ML_DSA guard. ```diff -#endif // !_SOFTHSM_V2_EDDSATESTS_H +#endif // !_SOFTHSM_V2_MLDSATESTS_H +#ifdef WITH_ML_DSA +#endifIf you adopt the earlier WITH_ML_DSA guard, ensure exactly one #endif closes it here.
</blockquote></details> <details> <summary>src/lib/P11Attributes.h (1)</summary><blockquote> `1151-1163`: **P11AttrParameterSet checks: consider requiring or allowing during GenerateKeyPair.** For key generation, parameter set typically must be provided or derived from templates/params. Using only ck1 (CreateObject) may be too permissive/ambiguous for GenerateKeyPair. Consider including ck3 if you want to enforce it at generation time, or ensure setDefault() derives it reliably. Would you like me to align this with existing parameter attributes (e.g., EC params) and update setDefault()/updateAttr() in P11Attributes.cpp accordingly? </blockquote></details> <details> <summary>m4/acx_crypto_backend.m4 (2)</summary><blockquote> `113-121`: **OpenSSL backend check wires correctly; ensure macro is available in all configure paths.** The flow matches ECC/EDDSA. Make sure m4/acx_openssl_mldsa.m4 is included by aclocal/ACLOCAL_AMFLAGS so the macro is found at autoconf time. If not already, add it to EXTRA_DIST or ensure m4/ is scanned. --- `261-273`: **Consider disallowing ML-DSA in FIPS mode (policy alignment with GOST).** You already block GOST when FIPS=yes. Given ML-DSA is not FIPS-approved, you may want to error when enable_fips=yes and enable_mldsa=yes to avoid misconfigured builds. Example: ```diff AC_MSG_CHECKING(for ML-DSA support) if test "x${enable_mldsa}" = "xyes"; then + if test "x${enable_fips}" = "xyes"; then + AC_MSG_ERROR([ML-DSA is not FIPS approved]) + fi AC_MSG_RESULT(yes) AC_DEFINE_UNQUOTED( [WITH_ML_DSA], [], [Compile with ML-DSA support] )src/lib/crypto/OSSLMLDSAPublicKey.h (3)
15-23: Constructors/destructor are fine; ensure pkey lifetime semantics are documented.No changes needed; destructor frees pkey. If getOSSLKey hands out the internal pointer for use by OpenSSL calls, document that callers must not free it.
Add a short note in the header comment for getOSSLKey().
37-39: getOSSLKey() returns non-const EVP_PKEY; consider const-correctness if mutation isn’t intended.*If callers should not modify pkey, return const EVP_PKEY* (and add a non-const overload only where needed).
-EVP_PKEY* getOSSLKey(); +const EVP_PKEY* getOSSLKey() const;And adjust the .cpp accordingly.
48-48: Fix the trailing header-guard comment.The guard is _SOFTHSM_V2_OSSLMLDSAPUBLICKEY_H but the comment says OSSLDSAPUBLICKEY.
-#endif // !_SOFTHSM_V2_OSSLDSAPUBLICKEY_H +#endif // !_SOFTHSM_V2_OSSLMLDSAPUBLICKEY_Hsrc/lib/crypto/test/MLDSATests.cpp (3)
1-6: Fix copy/paste header: EDDSA → MLDSAThe file banner still references EDDSA and EDDSATests.cpp. It should reflect MLDSA to avoid confusion.
Apply:
/***************************************************************************** - EDDSATests.cpp + MLDSATests.cpp - Contains test cases to test the EDDSA class + Contains test cases to test the MLDSA class *****************************************************************************/
33-35: Comment nit: “EDDSA object” → “MLDSA object”Align the inline comment with the class under test.
- // Check the EDDSA object + // Check the MLDSA object
164-196: Signing/verification test is effective; consider adding a negative checkEnd-to-end sign/verify with random data is covered. Consider an additional negative test (e.g., verify with a different public key or modified data) to ensure failure paths behave correctly.
src/lib/crypto/MLDSAParameters.cpp (3)
28-31: Minor: areOfType could be const (if interface allows)If AsymmetricParameters::areOfType permits const, marking this method const improves const-correctness. Skip if the base interface is non-const.
39-50: Optional validation: reject unsupported parameter sets on deserialiseCurrently any unsigned long is accepted. If only {1,2,3} are supported, reject others early to avoid propagating invalid state.
bool MLDSAParameters::deserialise(ByteString& serialised) { - if (serialised.size() == 0) + if (serialised.size() == 0) { return false; } - setParameterSet(serialised.long_val()); + const unsigned long ps = serialised.long_val(); + switch (ps) + { + case 1UL: + case 2UL: + case 3UL: + break; + default: + return false; + } + setParameterSet(ps); return true; }
7-11: Nit: unused includelog.h appears unused in this TU. Consider dropping it to keep includes minimal.
src/lib/crypto/OSSLMLDSAKeyPair.h (1)
24-31: Optional: mark overrides explicitlyAdding override clarifies intent and helps catch signature mismatches.
- virtual PublicKey* getPublicKey(); - virtual const PublicKey* getConstPublicKey() const; + virtual PublicKey* getPublicKey() override; + virtual const PublicKey* getConstPublicKey() const override; @@ - virtual PrivateKey* getPrivateKey(); - virtual const PrivateKey* getConstPrivateKey() const; + virtual PrivateKey* getPrivateKey() override; + virtual const PrivateKey* getConstPrivateKey() const override;src/lib/crypto/OSSLMLDSAKeyPair.cpp (1)
9-11: Remove unused includelog.h is not used here.
Apply this diff:
-#include "log.h" #include "OSSLMLDSAKeyPair.h"src/lib/crypto/OSSLMLDSAPrivateKey.h (3)
13-14: Drop unnecessary header from a public header to reduce coupling<openssl/bn.h> is not used in this header. Remove it to keep the header lean.
Apply this diff:
-#include <openssl/bn.h> #include <openssl/evp.h>
58-59: Fix header guard commentTrailing comment references a different class name.
Apply this diff:
-#endif // !_SOFTHSM_V2_OSSLECPRIVATEKEY_H +#endif // !_SOFTHSM_V2_OSSLMLDSAPRIVATEKEY_H
20-25: Consider defining safe copy semantics (optional)Given this class owns an EVP_PKEY*, the default copy/assignment will shallow-copy the pointer and double-free on destruction. Either delete copy/assignment or implement them to duplicate/reset pkey based on ByteString value. Not strictly required if all call sites avoid copying, but it’s safer.
I can provide a patch to delete copy/assignment or to implement them by rebuilding pkey from getValue().
src/lib/crypto/MLDSAPublicKey.cpp (3)
8-12: Remove unused includelog.h isn’t used in this unit.
Apply this diff:
-#include "log.h" #include "MLDSAParameters.h" #include "MLDSAPublicKey.h"
27-39: Comment mismatchThe block header says “Get the bit length” but this method returns the parameter set. Update the comment for clarity.
Apply this diff:
-// Get the bit length +// Get the parameter set
41-53: Typo in comment“Get the signatureLength length” → “Get the signature length”.
Apply this diff:
-// Get the signatureLength length +// Get the signature lengthsrc/lib/crypto/MLDSAPublicKey.h (1)
22-27: Fix comment labelsThese comment headers are misleading. Adjust to match the methods’ purpose.
Apply this diff:
-// Get the bit length +// Get the parameter set virtual unsigned long getParameterSet() const; -// Get the signature length +// Get the signature length virtual unsigned long getOutputLength() const;src/lib/P11Attributes.cpp (1)
2564-2597: Optional: validate and protect CKA_SEED more strictly
- Consider enforcing expected lengths when applicable (e.g., ML-DSA seeds are typically 32 bytes).
- Ensure P11AttrSeed has ck7 in its checks to block retrieval when sensitive/unextractable, aligning with base retrieve() semantics.
Can you confirm P11AttrSeed’s checks include ck7 in P11Attributes.h so that retrieval is blocked when appropriate?
src/lib/crypto/MLDSAParameters.h (2)
69-69: Initialize parameterSet to a safe defaultAvoid using an uninitialized value if getParameterSet() is called before setParameterSet(). Initialize to 0.
- unsigned long parameterSet; + unsigned long parameterSet = 0UL;
10-11: Remove unused includesand are not used in this header; dropping them reduces compile time and dependencies.
-#include <tuple> -#include <stdexcept>src/lib/crypto/MLDSAPrivateKey.h (1)
15-21: Add a virtual destructorPrivateKey already has a virtual destructor, but explicitly providing one here improves clarity and helps prevent potential slicing/warnings when extending further.
public: // The type static const char* type; + // Destructor + virtual ~MLDSAPrivateKey() { } + // Check if the key is of the given type virtual bool isOfType(const char* inType);src/lib/crypto/OSSLMLDSAPrivateKey.cpp (3)
151-167: Guard against unsupported/unknown parameter set namesIf mldsaParameterSet2Name() returns NULL (e.g., unexpected key length), creating the context will fail. Add an explicit check with a clear error.
const char* name = OSSL::mldsaParameterSet2Name(getParameterSet()); int selection = 0; EVP_PKEY_CTX *ctx = NULL; OSSL_PARAM params[3], *p = params; + if (name == NULL) { + ERROR_MSG("Unsupported ML-DSA parameter set (value: %lu)", getParameterSet()); + return; + }
13-15: Remove unused include and add cleansing support (optional)<openssl/bn.h> isn’t used here. If you choose to cleanse stack buffers, include <openssl/crypto.h>.
-#include <openssl/bn.h> #include <openssl/core_names.h> #include <openssl/x509.h> +#include <openssl/crypto.h>
46-69: Optional: cleanse sensitive stack buffersSeed and private key material temporarily reside on the stack. Cleanse after use to reduce exposure.
if(rv && seed_len == 32) { // seed is not mandatory for OSSL key reconstruction ByteString seedBS = ByteString(seed, seed_len); setSeed(seedBS); } + OPENSSL_cleanse(seed, sizeof(seed)); @@ ByteString valueBS = ByteString(priv, priv_len); setValue(valueBS); + OPENSSL_cleanse(priv, sizeof(priv));src/lib/crypto/OSSLMLDSAPublicKey.cpp (4)
52-54: Fix log message: it’s a public keyThe error message incorrectly mentions “private key”. Make it clear this is extracting the public key.
- ERROR_MSG("Could not get private key private, rv: %d", rv); + ERROR_MSG("Could not get public key data, rv: %d", rv);
95-111: Guard against unknown parameter set nameAdd an explicit check for NULL algorithm name with a clear error log.
const char* name = OSSL::mldsaParameterSet2Name(getParameterSet()); int selection = 0; EVP_PKEY_CTX *ctx = NULL; OSSL_PARAM params[3], *p = params; + if (name == NULL) { + ERROR_MSG("Unsupported ML-DSA parameter set (value: %lu)", getParameterSet()); + return; + }
13-16: Optional: add cleansing support for pubkey bufferIf you prefer to cleanse stack buffers, include <openssl/crypto.h>.
#include <openssl/evp.h> #include <openssl/core_names.h> #include <string.h> +#include <openssl/crypto.h>
57-60: Optional: cleanse temporary pubkey bufferThe public key is not secret in most contexts, but if you want consistent hygiene:
ByteString pubBS = ByteString(localPub, pub_len); setValue(pubBS); - + OPENSSL_cleanse(localPub, sizeof(localPub));src/lib/crypto/OSSLMLDSA.h (1)
10-50: Consider guarding the header with WITH_ML_DSAImplementations are compiled under WITH_ML_DSA; exposing this header unconditionally can lead to accidental references when ML-DSA is disabled. Guarding the declarations as well reduces accidental link/ODR issues.
src/lib/SoftHSM.cpp (1)
13539-13556: Remove unused variable‘parameterSet’ local ByteString is declared but never used in setMLDSAPrivateKey.
- ByteString parameterSet; ByteString seed; ByteString value;src/lib/crypto/OSSLMLDSA.cpp (3)
67-69: Right-size the signature buffer after signingEVP_DigestSign updates the out length. If it’s ever shorter than the pre-sized buffer, the trailing bytes remain zeroed. Resize to the actual produced length.
Apply this diff:
- signature.resize(len); - memset(&signature[0], 0, len); + signature.resize(len); + memset(&signature[0], 0, len); @@ - if (!EVP_DigestSign(ctx, &signature[0], &len, dataToSign.const_byte_str(), dataToSign.size())) + if (!EVP_DigestSign(ctx, &signature[0], &len, dataToSign.const_byte_str(), dataToSign.size())) { ERROR_MSG("ML-DSA sign failed (0x%08X)", ERR_get_error()); EVP_MD_CTX_free(ctx); return false; } + // Trim to the actual signature size (defensive) + signature.resize(len);Also applies to: 77-84
138-141: Fix comment typo and duplicationThe block has duplicate/mismatched comments (“Perform the verify operation” and “Perform the signature operation”). Clean this up for clarity.
Apply this diff:
- // Perform the verify operation - // Perform the signature operation + // Perform the verify operation
73-74: Use correct printf specifier for ERR_get_error() (unsigned long)ERR_get_error() returns unsigned long. Using %08X may truncate on LP64 platforms. Prefer %08lX (or cast to unsigned int with care).
Example fixes:
- ERROR_MSG("ML-DSA sign init failed (0x%08X)", ERR_get_error()); + ERROR_MSG("ML-DSA sign init failed (0x%08lX)", ERR_get_error());Apply similarly to other ERR_get_error() logs in this file.
Also applies to: 79-81, 156-157, 164-166, 171-175, 181-183, 272-279, 284-286
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🔭 Outside diff range comments (2)
src/lib/SoftHSM.cpp (2)
7001-7024: UnwrapKeySym lacks AES_CBC/DES3_CBC (non-PAD) support → cannot unwrap what WrapKeySym can wrapWrapKeySym supports CKM_AES_CBC and CKM_DES3_CBC, but UnwrapKeySym only supports the PAD variants. This asymmetry prevents unwrapping CBC-wrapped blobs (non-PAD).
Apply:
switch(pMechanism->mechanism) { @@ +#ifdef HAVE_AES_KEY_WRAP case CKM_AES_KEY_WRAP: @@ #endif #ifdef HAVE_AES_KEY_WRAP_PAD case CKM_AES_KEY_WRAP_PAD: @@ #endif + case CKM_AES_CBC: + algo = SymAlgo::AES; + blocksize = 16; + break; case CKM_AES_CBC_PAD: algo = SymAlgo::AES; blocksize = 16; break; + case CKM_DES3_CBC: + algo = SymAlgo::DES3; + blocksize = 8; + break; case CKM_DES3_CBC_PAD: algo = SymAlgo::DES3; blocksize = 8; break; @@ - case CKM_AES_CBC_PAD: - case CKM_DES3_CBC_PAD: + case CKM_AES_CBC: + case CKM_AES_CBC_PAD: + case CKM_DES3_CBC: + case CKM_DES3_CBC_PAD: iv.resize(blocksize); memcpy(&iv[0], pMechanism->pParameter, blocksize);Also ensure the C_UnwrapKey mechanism validation accepts CKM_AES_CBC (IV len 16) and CKM_DES3_CBC (IV len 8); see next comment.
Also applies to: 7047-7055
7361-7374: Accept non-PAD CBC in C_UnwrapKey and fix IV length checksCurrently only CKM_AES_CBC_PAD is accepted; add CKM_AES_CBC and CKM_DES3_CBC to keep the unwrap path aligned with WrapKeySym/UnwrapKeySym.
Apply:
- case CKM_AES_CBC_PAD: - // TODO check block length - if (pMechanism->pParameter == NULL_PTR || - pMechanism->ulParameterLen != 16) - return CKR_ARGUMENTS_BAD; - break; + case CKM_AES_CBC: + case CKM_AES_CBC_PAD: + if (pMechanism->pParameter == NULL_PTR || + pMechanism->ulParameterLen != 16) + return CKR_ARGUMENTS_BAD; + break; @@ - case CKM_DES3_CBC_PAD: - // TODO check block length - if (pMechanism->pParameter == NULL_PTR || - pMechanism->ulParameterLen != 8) - return CKR_ARGUMENTS_BAD; - break; + case CKM_DES3_CBC: + case CKM_DES3_CBC_PAD: + if (pMechanism->pParameter == NULL_PTR || + pMechanism->ulParameterLen != 8) + return CKR_ARGUMENTS_BAD; + break;Additionally, in the “Check unwrapping key class and type” section just below (Lines 7413–7417), the error code uses CKR_WRAPPING_KEY_TYPE_INCONSISTENT for unwrap — change to CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT. Same applies to the DES3 clause. Example:
- return CKR_WRAPPING_KEY_TYPE_INCONSISTENT → return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT
♻️ Duplicate comments (10)
src/lib/crypto/MLDSAPublicKey.h (1)
10-12: Resolved: explicit ByteString dependency includedIncluding ByteString.h directly removes reliance on transitive includes and avoids brittle builds. Good fix.
src/lib/P11Attributes.cpp (1)
2230-2260: CKA_PARAMETER_SET default type and update path look correct
- Default is now CK_ULONG (0) instead of ByteString. Matches the update path and OSAttribute usage.
- Update restricted to GENERATE/CREATE and enforces sizeof(CK_ULONG). Solid.
Optional: consider validating values against the allowed PKCS#11 enumerants (e.g., CKP_ML_DSA_44/65/87), rejecting unknown non-zero sets. This catches template errors early.
CMakeLists.txt (1)
11-11: Wire ENABLE_MLDSA → WITH_ML_DSA and enforce OpenSSL ≥ 3.5The
ENABLE_MLDSAoption is currently inert: it neither defines theWITH_ML_DSAmacro nor checks your OpenSSL version, so all#ifdef WITH_ML_DSAblocks remain disabled. To activate ML-DSA support only when OpenSSL ≥ 3.5:• In CMakeLists.txt (around the existing
option(ENABLE_MLDSA…)on line 11):
- Add a
find_package(OpenSSL REQUIRED)- Gate on
OpenSSL_VERSION_MAJOR/MINORto setWITH_ML_DSAfromENABLE_MLDSAor force it OFF with a warning- Propagate
WITH_ML_DSAviaadd_compile_definitions• In your CMake config-header template (e.g.
config.h.in.cmakeor equivalent):
- Add
#cmakedefine WITH_ML_DSA @WITH_ML_DSA@Suggested patch:
option(ENABLE_EDDSA "Enable support for EDDSA" ON) option(ENABLE_MLDSA "Enable support for ML-DSA" OFF) option(ENABLE_GOST "Enable support for GOST" OFF) +# Locate OpenSSL and enforce version gate for ML-DSA +find_package(OpenSSL REQUIRED) +if(OPENSSL_VERSION_MAJOR GREATER 3 + OR (OPENSSL_VERSION_MAJOR EQUAL 3 AND OPENSSL_VERSION_MINOR GREATER_EQUAL 5)) + set(WITH_ML_DSA ${ENABLE_MLDSA} + CACHE BOOL "Enable ML-DSA support (OpenSSL ≥ 3.5)" FORCE) +else() + set(WITH_ML_DSA OFF + CACHE BOOL "ML-DSA disabled: requires OpenSSL ≥ 3.5" FORCE) + if(ENABLE_MLDSA) + message(WARNING + "ENABLE_MLDSA requested but OpenSSL ${OPENSSL_VERSION} < 3.5; ML-DSA disabled") + endif() +endif() +# Define macro for sources +if(WITH_ML_DSA) + add_compile_definitions(WITH_ML_DSA) +endif()And in your config header template:
#cmakedefine WITH_ML_DSA @WITH_ML_DSA@src/lib/crypto/OSSLUtil.cpp (1)
37-39: Resolved: added missing includesIncluding MLDSAParameters.h and fixes the prior compile issue on stricter toolchains when using std::map.
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (1)
120-133: Resolved: EVP_PKEY leak fixed in PKCS8Decode()Freeing localPKey after setFromOSSL avoids a leak. Thanks for addressing this.
src/lib/crypto/OSSLMLDSA.cpp (1)
48-56: Remove redundant NULL-check on pk after a non-NULL check of privateKey
pkis a direct cast ofprivateKey, which you already validated as non-NULL (Line 34). Thepk == NULLbranch is dead code; drop it.OSSLMLDSAPrivateKey *pk = (OSSLMLDSAPrivateKey *)privateKey; - - if (pk == NULL) - { - ERROR_MSG("Could not get the SoftHSM private key"); - - return false; - }src/lib/SoftHSM.cpp (4)
13001-13006: These helpers don’t use ‘this’ — consider making them static methods or free functionsgetMLDSAPrivateKey, getMLDSAPublicKey, and setMLDSAPrivateKey can be marked static (or moved out of the class) to reduce coupling, consistent with prior review discussion.
Also applies to: 13033-13038, 13518-13522
6414-6422: AES_CBC/DES3_CBC blocksize remains 0 in WrapKeySym (IV becomes empty) — set blocksize for non-PAD modesFor non-PAD CBC modes, blocksize is left as 0, so iv.resize(0) and memcpy with 0 bytes occurs; encryptInit then runs with an empty IV. This is a functional bug that breaks wrapping and is inconsistent with PAD cases.
Apply:
case CKM_AES_CBC: - algo = SymAlgo::AES; + algo = SymAlgo::AES; + blocksize = 16; break; @@ case CKM_DES3_CBC: - algo = SymAlgo::DES3; + algo = SymAlgo::DES3; + blocksize = 8; break; @@ - iv.resize(blocksize); - memcpy(&iv[0], pMechanism->pParameter, blocksize); + iv.resize(blocksize); + memcpy(&iv[0], pMechanism->pParameter, blocksize);Optional hardening (recommended): also validate pMechanism->ulParameterLen == blocksize before memcpy to fail fast on malformed IV.
Also applies to: 6423-6431, 6460-6463
13027-13031: Populate parameter set on ML‑DSA private key (required for backend context)getMLDSAPrivateKey sets value/seed but not the parameter set; the backend may need it to sign correctly.
Apply:
privateKey->setValue(value); privateKey->setSeed(seed); + // Ensure parameter set is conveyed to the runtime key + unsigned long parameterSet = key->getUnsignedLongValue(CKA_PARAMETER_SET, 0); + privateKey->setParameterSet(parameterSet);
13056-13058: Populate parameter set on ML‑DSA public keySame rationale as private: set the parameter set on the runtime object.
Apply:
publicKey->setValue(value); + unsigned long parameterSet = key->getUnsignedLongValue(CKA_PARAMETER_SET, 0); + publicKey->setParameterSet(parameterSet);
🧹 Nitpick comments (15)
m4/acx_botan_mldsa.m4 (2)
2-2: Drop AC_MSG_CHECKING when using AC_CACHE_CHECKAC_CACHE_CHECK emits both the checking message and the final result. Keeping AC_MSG_CHECKING here will duplicate or misalign output.
- AC_MSG_CHECKING(for Botan ML-DSA support) + # AC_CACHE_CHECK will print the check and result
5-8: Nit: LIBS mangling is unnecessary for a compile-only probeAC_COMPILE_IFELSE doesn’t link, so LIBS changes are unused. Dropping them reduces side effects in configure logs.
- tmp_LIBS=$LIBS ... - LIBS="$CRYPTO_LIBS $LIBS" ... - LIBS=$tmp_LIBSAlso applies to: 30-31
src/lib/crypto/MLDSAPublicKey.h (1)
23-31: Fix mislabeled comment for getParameterSet()The comment above getParameterSet() says "Get the bit length". It should describe the parameter set. Minor, but prevents confusion when skimming headers.
Apply:
- // Get the bit length + // Get the parameter set virtual unsigned long getParameterSet() const; - // Get the signature length + // Get the signature length virtual unsigned long getOutputLength() const; // Get the bit length virtual unsigned long getBitLength() const;src/lib/crypto/OSSLUtil.cpp (1)
43-49: Prefer a simple switch over a global std::map for 3 constantsA switch avoids static initialization, reduces code size, and removes an otherwise unnecessary dependency. Functionally identical here.
Apply:
-#ifdef WITH_ML_DSA -static std::map<unsigned long, const char*> mldsaAlgNameFromParameterSet { - {MLDSAParameters::ML_DSA_44_PARAMETER_SET, "ML-DSA-44"}, - {MLDSAParameters::ML_DSA_65_PARAMETER_SET, "ML-DSA-65"}, - {MLDSAParameters::ML_DSA_87_PARAMETER_SET, "ML-DSA-87"} -}; -#endif +#ifdef WITH_ML_DSA +#endifAnd rewrite the function:
#ifdef WITH_ML_DSA const char* OSSL::mldsaParameterSet2Name(unsigned long parameterSet) { - - std::map<unsigned long, const char*>::iterator it = mldsaAlgNameFromParameterSet.find(parameterSet); - - if (it != mldsaAlgNameFromParameterSet.end()) { - return it->second; - } - - return NULL; + switch (parameterSet) { + case MLDSAParameters::ML_DSA_44_PARAMETER_SET: return "ML-DSA-44"; + case MLDSAParameters::ML_DSA_65_PARAMETER_SET: return "ML-DSA-65"; + case MLDSAParameters::ML_DSA_87_PARAMETER_SET: return "ML-DSA-87"; + default: return NULL; + } } #endifIf you take this, you can also drop the include.
Also applies to: 223-234
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (2)
7-16: Include <stdint.h> for uint8_tuint8_t is used; include <stdint.h>/ explicitly to avoid relying on transitive includes.
#include "OSSLUtil.h" +#include <stdint.h> #include <openssl/bn.h> #include <openssl/core_names.h> #include <openssl/x509.h>
60-63: Minor: clarify error messageTypo/redundant wording in the log.
- ERROR_MSG("Could not get private key private, rv: %d", rv); + ERROR_MSG("Could not get private key value, rv: %d", rv);src/lib/crypto/OSSLMLDSA.h (4)
10-13: Avoid exposing OpenSSL in the public header; include cstddef for size_tThis header doesn’t use any OpenSSL types/macros directly; only the .cpp needs <openssl/evp.h>. Also, this header uses size_t in method signatures; relying on transitive includes for size_t can be brittle.
- Remove <openssl/evp.h> from the header to reduce compile dependencies.
- Add so size_t is always defined here.
Apply:
#include "config.h" #include "AsymmetricAlgorithm.h" -#include <openssl/evp.h> +#include <cstddef>And ensure the implementation file includes OpenSSL:
// In src/lib/crypto/OSSLMLDSA.cpp #include <openssl/evp.h>
16-50: Add override specifiers to catch signature drift; modernize destructorMarking overrides explicitly improves safety (compiler checks exact signature matches) and readability. It would also immediately flag any mismatch with the base AsymmetricAlgorithm interface (e.g., missing const qualifiers or differing parameter lists).
Apply:
// Destructor - virtual ~OSSLMLDSA() { } + virtual ~OSSLMLDSA() override = default; // Signing functions - virtual bool sign(PrivateKey* privateKey, const ByteString& dataToSign, ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0); - virtual bool signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0); - virtual bool signUpdate(const ByteString& dataToSign); - virtual bool signFinal(ByteString& signature); + virtual bool sign(PrivateKey* privateKey, const ByteString& dataToSign, ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0) override; + virtual bool signInit(PrivateKey* privateKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0) override; + virtual bool signUpdate(const ByteString& dataToSign) override; + virtual bool signFinal(ByteString& signature) override; // Verification functions - virtual bool verify(PublicKey* publicKey, const ByteString& originalData, const ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0); - virtual bool verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0); - virtual bool verifyUpdate(const ByteString& originalData); - virtual bool verifyFinal(const ByteString& signature); + virtual bool verify(PublicKey* publicKey, const ByteString& originalData, const ByteString& signature, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0) override; + virtual bool verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism, const void* param = NULL, const size_t paramLen = 0) override; + virtual bool verifyUpdate(const ByteString& originalData) override; + virtual bool verifyFinal(const ByteString& signature) override; // Encryption functions - virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding); + virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding) override; // Decryption functions - virtual bool checkEncryptedDataSize(PrivateKey* privateKey, const ByteString& encryptedData, int* errorCode); - virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding); - virtual unsigned long getMinKeySize(); - virtual unsigned long getMaxKeySize(); + virtual bool checkEncryptedDataSize(PrivateKey* privateKey, const ByteString& encryptedData, int* errorCode) override; + virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding) override; + virtual unsigned long getMinKeySize() override; + virtual unsigned long getMaxKeySize() override; // Key factory - virtual bool generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* rng = NULL); - virtual bool reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData); - virtual bool reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData); - virtual bool reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData); - virtual bool reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData); - virtual PublicKey* newPublicKey(); - virtual PrivateKey* newPrivateKey(); - virtual AsymmetricParameters* newParameters(); + virtual bool generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* rng = NULL) override; + virtual bool reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData) override; + virtual bool reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData) override; + virtual bool reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData) override; + virtual bool reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData) override; + virtual PublicKey* newPublicKey() override; + virtual PrivateKey* newPrivateKey() override; + virtual AsymmetricParameters* newParameters() override;Note: If the base class marks any of these as const (e.g., getMinKeySize() const), the compiler will help you align signatures once override is added.
32-37: Clarify that ML-DSA does not support encryption/decryptionThese methods purposely return false in the implementation. A short note in the header helps prevent confusion for future readers.
Apply:
- // Encryption functions + // Encryption functions (ML-DSA does not support encryption; methods return false) virtual bool encrypt(PublicKey* publicKey, const ByteString& data, ByteString& encryptedData, const AsymMech::Type padding); - // Decryption functions + // Decryption functions (ML-DSA does not support decryption; methods return false) virtual bool checkEncryptedDataSize(PrivateKey* privateKey, const ByteString& encryptedData, int* errorCode); virtual bool decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding);
51-52: Optional: remove empty private sectionThere are no private members. Consider removing the empty private: block to reduce noise, unless you plan to add members imminently.
src/lib/crypto/OSSLMLDSA.cpp (2)
138-141: Fix comment: it’s a public key type check, not privateSmall clarity nit.
- // Check if the private key is the right type + // Check if the public key is the right type
164-168: Improve error message with expected vs actual signature lengthsThis aids operators and test triage.
- ERROR_MSG("Invalid buffer length"); + ERROR_MSG("Invalid signature length: got %zu, expected %zu", signature.size(), len);src/lib/SoftHSM.cpp (3)
10064-10067: Prefer standard error code and fix format specifier for paramSet diagnostics
- Use CKR_MECHANISM_PARAM_INVALID instead of CKR_PARAMETER_SET_NOT_SUPPORTED (unless you explicitly want to expose that code).
- paramSet is CK_ULONG; use %lu and cast to unsigned long for portability.
Apply:
- if (paramSet != 1UL && paramSet != 2UL && paramSet != 3UL) { - INFO_MSG("Wrong parameterSet: %ld", paramSet); - return CKR_PARAMETER_SET_NOT_SUPPORTED; + if (paramSet != 1UL && paramSet != 2UL && paramSet != 3UL) { + INFO_MSG("Unsupported parameter set: %lu", (unsigned long)paramSet); + return CKR_MECHANISM_PARAM_INVALID; }Nit: if your PKCS#11 headers define CKP_ML_DSA_* constants for parameter sets, prefer those symbolic constants over raw numerics to align with project conventions.
10215-10217: Remove unused variable ‘parameterSet’Local ‘parameterSet’ is never used.
Apply:
- // MLDSA Private Key Attributes - ByteString parameterSet; - ByteString value; + // MLDSA Private Key Attributes + ByteString value; ByteString seed;
13536-13539: Remove unused ‘parameterSet’ variable in setMLDSAPrivateKeyIt’s not used; the attribute is set directly from priv->getParameterSet().
Apply:
- // ML-DSA Private Key Attributes - ByteString parameterSet; + // ML-DSA Private Key Attributes ByteString seed; ByteString value;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (14)
.github/workflows/ci.yml(1 hunks)CMakeLists.txt(1 hunks)m4/acx_botan_mldsa.m4(1 hunks)src/lib/P11Attributes.cpp(2 hunks)src/lib/SoftHSM.cpp(35 hunks)src/lib/SoftHSM.h(4 hunks)src/lib/crypto/MLDSAPublicKey.h(1 hunks)src/lib/crypto/OSSLMLDSA.cpp(1 hunks)src/lib/crypto/OSSLMLDSA.h(1 hunks)src/lib/crypto/OSSLMLDSAKeyPair.cpp(1 hunks)src/lib/crypto/OSSLMLDSAKeyPair.h(1 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.cpp(1 hunks)src/lib/crypto/OSSLMLDSAPublicKey.cpp(1 hunks)src/lib/crypto/OSSLUtil.cpp(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- src/lib/crypto/OSSLMLDSAPublicKey.cpp
- src/lib/crypto/OSSLMLDSAKeyPair.cpp
- src/lib/crypto/OSSLMLDSAKeyPair.h
- src/lib/SoftHSM.h
- .github/workflows/ci.yml
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-18T17:54:37.601Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: m4/acx_openssl_mldsa.m4:10-35
Timestamp: 2025-08-18T17:54:37.601Z
Learning: For OpenSSL feature detection in autoconf macros, prefer functional tests (like EVP_PKEY_CTX_new_from_name) over version number checks, as the functional approach directly tests the actual capability and is more reliable across different OpenSSL builds where features may be backported or disabled.
Applied to files:
m4/acx_botan_mldsa.m4
📚 Learning: 2025-08-18T17:59:30.642Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.642Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Applied to files:
src/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLUtil.cppsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/MLDSAPublicKey.h
🧬 Code Graph Analysis (4)
src/lib/crypto/OSSLMLDSA.h (6)
src/lib/crypto/AsymmetricAlgorithm.h (2)
AsymmetricAlgorithm(116-185)AsymmetricAlgorithm(123-123)src/lib/crypto/OSSLMLDSA.cpp (42)
sign(24-97)sign(24-26)signInit(99-105)signInit(99-100)signUpdate(107-112)signUpdate(107-107)signFinal(114-119)signFinal(114-114)verify(122-222)verify(122-124)verifyInit(224-230)verifyInit(224-225)verifyUpdate(232-237)verifyUpdate(232-232)verifyFinal(239-244)verifyFinal(239-239)encrypt(247-253)encrypt(247-248)checkEncryptedDataSize(274-279)checkEncryptedDataSize(274-274)decrypt(256-262)decrypt(256-257)getMinKeySize(264-267)getMinKeySize(264-264)getMaxKeySize(269-272)getMaxKeySize(269-269)generateKeyPair(282-345)generateKeyPair(282-282)reconstructKeyPair(347-383)reconstructKeyPair(347-347)reconstructPublicKey(385-406)reconstructPublicKey(385-385)reconstructPrivateKey(408-429)reconstructPrivateKey(408-408)reconstructParameters(446-466)reconstructParameters(446-446)newPublicKey(431-434)newPublicKey(431-431)newPrivateKey(436-439)newPrivateKey(436-436)newParameters(441-444)newParameters(441-441)src/lib/crypto/AsymmetricKeyPair.h (1)
AsymmetricKeyPair(42-55)src/lib/crypto/AsymmetricParameters.h (1)
AsymmetricParameters(40-45)src/lib/crypto/PublicKey.h (1)
PublicKey(40-54)src/lib/crypto/PrivateKey.h (1)
PrivateKey(41-58)
src/lib/crypto/OSSLMLDSA.cpp (1)
src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(224-233)mldsaParameterSet2Name(224-224)
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (4)
src/lib/crypto/OSSLMLDSAPrivateKey.h (1)
OSSLMLDSAPrivateKey(16-56)src/lib/crypto/MLDSAPrivateKey.cpp (10)
setSeed(65-68)setSeed(65-65)setValue(55-58)setValue(55-55)isOfType(17-20)isOfType(17-17)getValue(60-63)getValue(60-60)getParameterSet(28-39)getParameterSet(28-28)src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(224-233)mldsaParameterSet2Name(224-224)src/lib/crypto/MLDSAParameters.cpp (2)
getParameterSet(22-25)getParameterSet(22-22)
src/lib/crypto/MLDSAPublicKey.h (4)
src/lib/crypto/PublicKey.h (1)
PublicKey(40-54)src/lib/crypto/OSSLMLDSAPublicKey.cpp (4)
isOfType(63-66)isOfType(63-63)setValue(68-76)setValue(68-68)src/lib/crypto/MLDSAPublicKey.cpp (16)
isOfType(17-20)isOfType(17-17)getParameterSet(28-39)getParameterSet(28-28)getOutputLength(42-53)getOutputLength(42-42)getBitLength(22-25)getBitLength(22-22)setValue(60-63)setValue(60-60)getValue(55-58)getValue(55-55)serialise(66-69)serialise(66-66)deserialise(71-83)deserialise(71-71)src/lib/crypto/MLDSAParameters.cpp (6)
getParameterSet(22-25)getParameterSet(22-22)serialise(34-37)serialise(34-34)deserialise(39-50)deserialise(39-39)
🔇 Additional comments (16)
m4/acx_botan_mldsa.m4 (2)
4-11: Good hygiene: language push/pop and CPPFLAGS save/restoreThe macro correctly switches to C++ and restores CPPFLAGS/LIBS afterward, and exposes have_lib_botan_mldsa_support for downstream logic.
Also applies to: 28-33
32-33: ML-DSA detection is properly propagatedThe
have_lib_botan_mldsa_supportvariable is indeed consumed downstream in m4/acx_crypto_backend.m4, influencing the build via the case dispatch:
- m4/acx_crypto_backend.m4:191-194 –
case "${enable_mldsa}-${have_lib_botan_mldsa_support}" in yes-no) AC_MSG_ERROR([Botan library has no ML-DSA support]);; detect-*) enable_mldsa="${have_lib_botan_mldsa_support}";; esacNo further AC_SUBST or AM_CONDITIONAL is required, as the m4 dispatch already covers propagation.
src/lib/crypto/MLDSAPublicKey.h (1)
18-21: Static ‘type’ definition confirmed
- Definition found once in
src/lib/crypto/MLDSAPublicKey.cpp:14:/*static*/ const char* MLDSAPublicKey::type = "Abstract ML-DSA public key";No further action required.
src/lib/P11Attributes.cpp (1)
2558-2596: CKA_SEED handling is secure and consistent
- No plaintext logging; encryption pathways mirror existing sensitive attributes.
- Accepts 0-length with NULL pointer via upstream checks. Stores as-is for public objects, encrypted for private ones.
Looks good.
src/lib/crypto/OSSLMLDSA.h (2)
7-9: Include guard mismatch is resolved — LGTMThe opening and closing guards consistently use _SOFTHSM_V2_OSSLMLDSA_H now. Thanks for fixing the earlier mismatch.
Also applies to: 54-54
21-40: All OSSLMLDSA method signatures match the AsymmetricAlgorithm base class – you can safely addoverride.I’ve confirmed that for each of these methods in
src/lib/crypto/OSSLMLDSA.h, the parameter lists and return types are identical to the declarations insrc/lib/crypto/AsymmetricAlgorithm.h:
- sign, signInit, signUpdate, signFinal
- verify, verifyInit, verifyUpdate, verifyFinal
- encrypt, decrypt
- checkEncryptedDataSize
- getMinKeySize, getMaxKeySize
Feel free to annotate each with
overrideto prevent any silent non-override errors in the future.src/lib/crypto/OSSLMLDSA.cpp (7)
76-82: Good: EVP_MD_CTX_new() NULL-checkedPrevents a potential crash on allocation failure. Nicely handled.
181-186: Good: explicit guard for unknown/unsupported parameter setsFail-fast with a clear diagnostic and clean-up. This improves debuggability significantly.
205-217: Good: distinguish invalid signatures from OpenSSL errorsCorrect handling: 0 => invalid signature; <0 => provider error via ERR_get_error(). Clean and accurate.
302-307: Good: keygen explicitly rejects unknown parameter setsNice early error with a clear message before context creation.
331-342: Good: proper EVP_PKEY refcounting to avoid UAF/double-freeUsing EVP_PKEY_up_ref before handing the same pkey to both wrappers and freeing the original reference is the correct ownership model.
246-279: Clear unsupported-operation messaging (encrypt/decrypt/checkEncryptedDataSize)Explicit “not supported” errors are fine and consistent with signature-only algorithms.
264-272: Units confirmed as bits—no change neededThe constants ML_DSA_44_PRIV_LENGTH (2560) and ML_DSA_87_PRIV_LENGTH (4896) in MLDSAParameters.h represent key lengths in bits, matching the bit‐based values returned by all other
getMinKeySize/getMaxKeySizeimplementations (e.g., RSA: 1024–4096, ECDSA: 112–521). Your use of these named constants is correct and requires no adjustment.src/lib/SoftHSM.cpp (3)
146-148: ML‑DSA P11 object wiring (public key) looks correctnewP11Object correctly recognizes CKK_ML_DSA and instantiates P11MLDSAPublicKeyObj.
165-167: ML‑DSA P11 object wiring (private key) looks correctnewP11Object correctly recognizes CKK_ML_DSA and instantiates P11MLDSAPrivateKeyObj.
830-833: Mechanism table and info for ML‑DSA: LGTM
- CKM_ML_DSA[_KEY_PAIR_GEN] added under WITH_ML_DSA.
- Min/max sizes obtained from CryptoFactory and exposed in C_GetMechanismInfo.
- Flags CKF_GENERATE_KEY_PAIR and CKF_SIGN|CKF_VERIFY are consistent.
No issues spotted.
Also applies to: 938-941, 1038-1049, 1336-1346
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🔭 Outside diff range comments (2)
src/lib/SoftHSM.cpp (2)
7005-7026: Unwrap path does not support non-PAD CBC and has two critical bugs
- Unwrap only handles CKM_AES_CBC_PAD/CKM_DES3_CBC_PAD; the wrap path now accepts non-PAD CKM_AES_CBC/CKM_DES3_CBC (once fixed above). Add symmetric support here.
- Wrong return code and logic in key-type checks:
- Returning CKR_WRAPPING_KEY_TYPE_INCONSISTENT in Unwrap; should be CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT.
- The DES3 check uses “!= DES2 || != DES3” which is always true. Use &&.
Apply to UnwrapKeySym to accept non-PAD CBC:
switch(pMechanism->mechanism) { @@ - case CKM_AES_CBC_PAD: + case CKM_AES_CBC: + algo = SymAlgo::AES; + blocksize = 16; + break; + case CKM_AES_CBC_PAD: algo = SymAlgo::AES; blocksize = 16; break; @@ - case CKM_DES3_CBC_PAD: + case CKM_DES3_CBC: + algo = SymAlgo::DES3; + blocksize = 8; + break; + case CKM_DES3_CBC_PAD: algo = SymAlgo::DES3; blocksize = 8; break;Apply to C_UnwrapKey mechanism validation to accept non-PAD CBC with IV length checks:
- case CKM_AES_CBC_PAD: + case CKM_AES_CBC: + if (pMechanism->pParameter == NULL_PTR || + pMechanism->ulParameterLen != 16) + return CKR_ARGUMENTS_BAD; + break; + case CKM_AES_CBC_PAD: // TODO check block length if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != 16) return CKR_ARGUMENTS_BAD; break; @@ - case CKM_DES3_CBC_PAD: + case CKM_DES3_CBC: + if (pMechanism->pParameter == NULL_PTR || + pMechanism->ulParameterLen != 8) + return CKR_ARGUMENTS_BAD; + break; + case CKM_DES3_CBC_PAD: // TODO check block length if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != 8) return CKR_ARGUMENTS_BAD; break;Fix the unwrapping key-type checks:
- if ((pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CBC_PAD) && unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES) - return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; + if ((pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CBC_PAD) && + unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES) + return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; @@ - if (pMechanism->mechanism == CKM_DES3_CBC && (unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 || - unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) - return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; + if (pMechanism->mechanism == CKM_DES3_CBC && + (unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 && + unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) + return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT;Note: Consider making the analogous DES3 check fix in C_WrapKey too (same ‘||’ issue) for consistency.
Also applies to: 7051-7086, 7364-7377, 7416-7421
7416-7421: Fix two typos in Unwrap key-type check (return code and logic)
- Use UNWRAPPING in the error code for Unwrap path.
- Correct the boolean logic so the check does not always fail.
Apply:
- if ((pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CBC_PAD) && unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES) - return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; + if ((pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CBC_PAD) && + unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES) + return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; @@ - if (pMechanism->mechanism == CKM_DES3_CBC && (unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 || - unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) - return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; + if (pMechanism->mechanism == CKM_DES3_CBC && + (unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 && + unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) + return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT;
♻️ Duplicate comments (1)
src/lib/SoftHSM.cpp (1)
4190-4191: Populate ML-DSA parameter set on runtime key objectsThe runtime MLDSA{Private,Public}Key instances created via MLDSAUtil currently only set value/seed. Parameter set is required for the backend to know which ML-DSA variant to use.
Please extend MLDSAUtil::{getMLDSAPrivateKey,getMLDSAPublicKey} to set the parameter set read from the OSObject:
Outside this file (src/lib/crypto/MLDSAUtil.cpp), apply:
--- a/src/lib/crypto/MLDSAUtil.cpp +++ b/src/lib/crypto/MLDSAUtil.cpp @@ CK_RV MLDSAUtil::getMLDSAPrivateKey(MLDSAPrivateKey* privateKey, Token* token, OSObject* key) @@ - privateKey->setValue(value); - privateKey->setSeed(seed); + privateKey->setValue(value); + privateKey->setSeed(seed); + // Parameter set is required + CK_ULONG paramSet = key->getUnsignedLongValue(CKA_PARAMETER_SET, 0); + privateKey->setParameterSet(paramSet); @@ CK_RV MLDSAUtil::getMLDSAPublicKey(MLDSAPublicKey* publicKey, Token* token, OSObject* key) @@ - publicKey->setValue(value); + publicKey->setValue(value); + CK_ULONG paramSet = key->getUnsignedLongValue(CKA_PARAMETER_SET, 0); + publicKey->setParameterSet(paramSet);Would you like me to open a follow-up PR for this?
Also applies to: 4434-4439, 4527-4546, 5199-5200, 5441-5446, 5534-5553
🧹 Nitpick comments (6)
src/lib/crypto/MLDSAUtil.h (2)
29-30: Fix mismatched/end-if comments for clarityThe nesting is correct (#ifdef WITH_ML_DSA closes before the include guard), but the comments are swapped and confusing. Align comments with the blocks they close.
-#endif // !_SOFTHSM_V2_MLDSAUTIL_H -#endif +#endif // WITH_ML_DSA +#endif // _SOFTHSM_V2_MLDSAUTIL_H
14-15: Trim unused includes from the header to reduce transitive dependenciesAsymmetricAlgorithm.h and CryptoFactory.h are not needed for the declarations in this header (they’re only used in the .cpp). Removing them will reduce rebuilds and header coupling.
-#include "AsymmetricAlgorithm.h" -#include "CryptoFactory.h"Add them in the implementation file instead (see suggested change in MLDSAUtil.cpp).
src/lib/crypto/MLDSAUtil.cpp (3)
52-54: Fix copy/paste comment (EC → ML-DSA)Minor correctness/clarity tweak.
- // EC Public Key Attributes + // ML-DSA Public Key Attributes
89-89: Remove unused variableparameterSet is declared but never used; drop it to avoid warnings.
- ByteString parameterSet;
7-10: Move algorithm/factory includes from header into the implementationTo support the header cleanup, include what you use here.
#include "config.h" #ifdef WITH_ML_DSA #include "MLDSAUtil.h" +#include "AsymmetricAlgorithm.h" +#include "CryptoFactory.h"src/lib/SoftHSM.cpp (1)
6734-6739: Symmetry: consider allowing DES3_CBC in C_WrapKeyYou support CKM_DES3_CBC in WrapKeySym but the top-level C_WrapKey switch does not accept CKM_DES3_CBC. Add a branch with IV length 8 for consistency with the unwrap side.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (7)
src/lib/SoftHSM.cpp(34 hunks)src/lib/SoftHSM.h(2 hunks)src/lib/crypto/CMakeLists.txt(2 hunks)src/lib/crypto/MLDSAUtil.cpp(1 hunks)src/lib/crypto/MLDSAUtil.h(1 hunks)src/lib/crypto/Makefile.am(3 hunks)src/lib/crypto/OSSLComp.cpp(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- src/lib/crypto/OSSLComp.cpp
🚧 Files skipped from review as they are similar to previous changes (2)
- src/lib/crypto/CMakeLists.txt
- src/lib/crypto/Makefile.am
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-18T17:59:30.642Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.642Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Applied to files:
src/lib/crypto/MLDSAUtil.hsrc/lib/crypto/MLDSAUtil.cppsrc/lib/SoftHSM.cppsrc/lib/SoftHSM.h
🧬 Code Graph Analysis (2)
src/lib/crypto/MLDSAUtil.h (1)
src/lib/crypto/MLDSAUtil.cpp (6)
getMLDSAPrivateKey(11-41)getMLDSAPrivateKey(11-11)getMLDSAPublicKey(43-69)getMLDSAPublicKey(43-43)setMLDSAPrivateKey(71-111)setMLDSAPrivateKey(71-71)
src/lib/SoftHSM.cpp (2)
src/lib/crypto/MLDSAUtil.cpp (6)
getMLDSAPrivateKey(11-41)getMLDSAPrivateKey(11-11)getMLDSAPublicKey(43-69)getMLDSAPublicKey(43-43)setMLDSAPrivateKey(71-111)setMLDSAPrivateKey(71-71)src/lib/P11Objects.cpp (2)
isPrivate(303-311)isPrivate(303-303)
🔇 Additional comments (11)
src/lib/crypto/MLDSAUtil.h (1)
23-27: API shape looks good and consistentThe utility provides a minimal and focused surface for ML-DSA key get/set, taking Token and OSObject as inputs and respecting privacy. Signature choices (CK_RV for getters, bool for setter) match existing patterns.
src/lib/SoftHSM.h (2)
55-58: Good: MLDSA includes correctly gatedWrapping MLDSA key includes with WITH_ML_DSA prevents builds from breaking when ML-DSA is disabled or OpenSSL < 3.5.
378-393: Good: MLDSA generator declaration properly feature-gatedThe generateMLDSA() declaration matches the conditional compilation used elsewhere, avoiding undefined references when ML-DSA is not enabled.
src/lib/crypto/MLDSAUtil.cpp (2)
94-105: I’ve confirmed that Token::encrypt returns a bool and that the MLDSAUtil method itself returns a bool status. Integrating encryption failures into the overall success flag and switching to static_cast is both safe and consistent with existing patterns in P11Attributes.cpp and SoftHSM.cpp.Refactor MLDSAUtil to check encrypt() results and use static_cast
• In
src/lib/crypto/MLDSAUtil.cpp, lines 93–105:
– Wrap the twotoken->encrypt(...)calls in a boolean check (e.g.encOK)
– On failure, recycle the private key and algorithm, then returnfalseimmediately
– Replace all C–style casts onprivwithstatic_cast<MLDSAPrivateKey*>• Downstream code already combines
bOKfromsetAttribute; no change needed there beyond using the safer cast forgetParameterSet().Revised snippet:
- if (isPrivate) - { - token->encrypt(((MLDSAPrivateKey*)priv)->getSeed(), seed); - token->encrypt(((MLDSAPrivateKey*)priv)->getValue(), value); - } + if (isPrivate) + { + bool encOK = true; + auto mlpriv = static_cast<MLDSAPrivateKey*>(priv); + encOK = encOK && token->encrypt(mlpriv->getSeed(), seed); + encOK = encOK && token->encrypt(mlpriv->getValue(), value); + if (!encOK) + { + mldsa->recyclePrivateKey(priv); + CryptoFactory::i()->recycleAsymmetricAlgorithm(mldsa); + return false; + } + } else { - seed = ((MLDSAPrivateKey*)priv)->getSeed(); - value = ((MLDSAPrivateKey*)priv)->getValue(); + auto mlpriv = static_cast<MLDSAPrivateKey*>(priv); + seed = mlpriv->getSeed(); + value = mlpriv->getValue(); } bool bOK = true; - bOK = bOK && key->setAttribute(CKA_PARAMETER_SET, ((MLDSAPrivateKey*)priv)->getParameterSet()); + bOK = bOK && key->setAttribute(CKA_PARAMETER_SET, + static_cast<MLDSAPrivateKey*>(priv)->getParameterSet()); bOK = bOK && key->setAttribute(CKA_SEED, seed); bOK = bOK && key->setAttribute(CKA_VALUE, value);This aligns MLDSAUtil with existing encrypt()–error–handling patterns and uses modern C++ casts.
71-111: Ignore the parameter-set setter suggestionAfter reviewing the code:
- MLDSAUtil::setMLDSAPrivateKey already writes CKA_PARAMETER_SET to the token object.
- MLDSAPrivateKey and MLDSAPublicKey only expose getParameterSet(), which computes the domain parameters from the key’s value size—there is no setParameterSet() on those classes.
- A manual setter on the in-memory key isn’t available or needed.
No changes required.
Likely an incorrect or invalid review comment.
src/lib/SoftHSM.cpp (6)
65-70: ML-DSA headers are correctly gatedIncludes for ML-DSA are properly hidden behind WITH_ML_DSA. No concerns here.
832-836: Mechanism table extended for ML-DSACKM_ML_DSA_KEY_PAIR_GEN and CKM_ML_DSA added and gated. Looks good.
941-944: Mechanism info for ML-DSA is consistent and gated
- Min/max sizes are queried via CryptoFactory behind WITH_ML_DSA.
- CKM_ML_DSA and KEY_PAIR_GEN expose sensible flags (SIGN/VERIFY and GENERATE_KEY_PAIR).
LGTM.
Also applies to: 1041-1052, 1339-1349
6167-6170: Key-pair generation flow and ML-DSA routingC_GenerateKeyPair integration (mechanism dispatch and routing to generateMLDSA) looks correct and gated via WITH_ML_DSA. No issues.
Also applies to: 6198-6200, 6224-6225, 6298-6305
5672-5673: Minor: Debug output is fineExtra DEBUG_MSG with sizes only (no sensitive data) is acceptable.
Also applies to: 5856-5856
149-151: Wrap ML-DSA support in WITH_ML_DSA guardsThe ML-DSA key-object classes and their use in SoftHSM.cpp aren’t currently wrapped in
#ifdef WITH_ML_DSA, so they’ll always be compiled—even when ML-DSA support is disabled. We need to guard both the class definitions and theCKK_ML_DSAbranches.Locations to fix:
- src/lib/P11Objects.h
- Line 201:
class P11MLDSAPublicKeyObj- Line 303:
class P11MLDSAPrivateKeyObj
Wrap each definition in:#ifdef WITH_ML_DSA class P11MLDSAPublicKeyObj : public P11PublicKeyObj { … }; // … class P11MLDSAPrivateKeyObj : public P11PrivateKeyObj { … }; #endif // WITH_ML_DSA- src/lib/SoftHSM.cpp
- Lines 149–151 and 169–170: the
else if (keyType == CKK_ML_DSA)branches
Wrap these cases in the same guard, for example:#ifdef WITH_ML_DSA- else if (keyType == CKK_ML_DSA)
*p11object = new P11MLDSAPublicKeyObj();
- else if (keyType == CKK_ML_DSA) {
*p11object = new P11MLDSAPublicKeyObj();- }
#endif // WITH_ML_DSA<details> <summary>⛔ Skipped due to learnings</summary>Learnt from: antoinelochet
PR: #809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.642Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.</details> </details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
3bf81b0 to
54e8ee0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🔭 Outside diff range comments (1)
src/lib/SoftHSM.cpp (1)
5445-5556: ML-DSA verify path: propagate parameter set to MLDSAPublicKeyAfter calling
MLDSAUtil::getMLDSAPublicKey((MLDSAPublicKey*)publicKey, token, key)in the CKM_ML_DSA branch (src/lib/SoftHSM.cpp around lines 5445–5556), you must also read the CKA_PARAMETER_SET from the OSObject and apply it to the in-memory public key so the backend has the full context for verification. For example:
Suggested diff (around line 5550):
if (MLDSAUtil::getMLDSAPublicKey((MLDSAPublicKey*)publicKey, token, key) != CKR_OK) { asymCrypto->recyclePublicKey(publicKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_GENERAL_ERROR; } + // Apply parameter set for ML-DSA verify context + { + CK_ULONG paramSet = key->getUnsignedLongValue(CKA_PARAMETER_SET); + ((MLDSAPublicKey*)publicKey)->setParameterSet(paramSet); + }This mirrors the sign path and ensures the verifier knows which ML-DSA parameters to use.
♻️ Duplicate comments (2)
src/lib/SoftHSM.cpp (2)
10020-10277: generateMLDSA: overall solid, but remove an unused variable and consider return code convention
The flow for extracting CKA_PARAMETER_SET, parameter validation, keypair generation, and attribute population is consistent with the project style (using CKP_ML_DSA_* and returning CKR_PARAMETER_SET_NOT_SUPPORTED). Keeping that is fine given the current repository convention.
There’s an unused variable in the private key block:
- ByteString parameterSet; is declared but never used.
Apply this small cleanup:
@@ - // MLDSA Private Key Attributes - ByteString parameterSet; - ByteString value; - ByteString seed; + // MLDSA Private Key Attributes + ByteString value; + ByteString seed;
6421-6439: CBC wrap bug: empty IV used for non-PAD modes (AES_CBC/DES3_CBC) and missing input size checksFor CKM_AES_CBC and CKM_DES3_CBC you never set blocksize. Consequently:
- iv.resize(blocksize) yields a 0-length IV
- memcpy copies 0 bytes
- encryptInit gets an empty IV for CBC, which will fail or be unsafe
Additionally, for non-PAD modes the input must be a multiple of the block size.
Fix by setting blocksize, validating IV length, and (recommended) enforcing block-aligned input when no padding:
@@ - case CKM_AES_CBC: - algo = SymAlgo::AES; - break; + case CKM_AES_CBC: + algo = SymAlgo::AES; + blocksize = 16; + if (wrappedlen % blocksize != 0) return CKR_KEY_SIZE_RANGE; + break; @@ - case CKM_DES3_CBC: - algo = SymAlgo::DES3; - break; + case CKM_DES3_CBC: + algo = SymAlgo::DES3; + blocksize = 8; + if (wrappedlen % blocksize != 0) return CKR_KEY_SIZE_RANGE; + break; @@ - case CKM_AES_CBC: - case CKM_AES_CBC_PAD: - case CKM_DES3_CBC: - case CKM_DES3_CBC_PAD: - iv.resize(blocksize); - memcpy(&iv[0], pMechanism->pParameter, blocksize); + case CKM_AES_CBC: + case CKM_AES_CBC_PAD: + case CKM_DES3_CBC: + case CKM_DES3_CBC_PAD: + if (pMechanism->pParameter == NULL_PTR || + pMechanism->ulParameterLen != blocksize) { + cipher->recycleKey(wrappingkey); + CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); + return CKR_ARGUMENTS_BAD; + } + iv.resize(blocksize); + memcpy(&iv[0], pMechanism->pParameter, blocksize);This mirrors the already-correct PAD paths and prevents empty-IV CBC usage.
Also applies to: 6463-6470
🧹 Nitpick comments (5)
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (5)
61-63: Fix typo in error message"Could not get private key private" → "Could not get private key".
Apply this diff:
- ERROR_MSG("Could not get private key private, rv: %d", rv); + ERROR_MSG("Could not get private key, rv: %d", rv);
127-132: Harden PKCS#8 decode by checking the key algorithm is ML-DSAGuard against mis-decoding a different algorithm into this class.
Apply this diff:
EVP_PKEY* localPKey = EVP_PKCS82PKEY(p8); PKCS8_PRIV_KEY_INFO_free(p8); if (localPKey == NULL) return false; + // Ensure the decoded key is ML-DSA + if (!EVP_PKEY_is_a(localPKey, "ML-DSA")) { + EVP_PKEY_free(localPKey); + return false; + } setFromOSSL(localPKey); EVP_PKEY_free(localPKey); return true;
122-126: Avoid potential size truncation when converting BER lengthber.size() is size_t; storing into int risks truncation for very large inputs.
Apply this diff:
- int len = ber.size(); - if (len <= 0) return false; + if (ber.size() == 0) return false; + if (ber.size() > LONG_MAX) return false; + long len = static_cast<long>(ber.size());Additionally, ensure LONG_MAX is available by including climits at the top of the file:
// add near other includes #include <climits>
13-15: Remove unused include to keep build surface minimalopenssl/bn.h isn't used here.
Apply this diff:
-#include <openssl/bn.h>
44-69: Zeroize stack buffers holding sensitive material before returnSeed and private-key buffers remain on the stack; zeroizing is a small hardening win. Consider wiping in both success and error paths.
Apply this diff to wipe on the success path:
ByteString valueBS = ByteString(priv, priv_len); setValue(valueBS); +OPENSSL_cleanse(priv, sizeof(priv)); +OPENSSL_cleanse(seed, sizeof(seed));And in the error branch before returning:
- if(!rv) { - ERROR_MSG("Could not get private key, rv: %d", rv); - return; - } + if(!rv) { + ERROR_MSG("Could not get private key, rv: %d", rv); + OPENSSL_cleanse(priv, sizeof(priv)); + OPENSSL_cleanse(seed, sizeof(seed)); + return; + }Add the necessary include:
// near other includes #include <openssl/crypto.h> // for OPENSSL_cleanse
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
src/lib/SoftHSM.cpp(34 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.cpp(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-18T17:59:30.642Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.642Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Applied to files:
src/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cpp
📚 Learning: 2025-08-18T19:46:46.645Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.645Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Applied to files:
src/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cpp
🧬 Code Graph Analysis (2)
src/lib/SoftHSM.cpp (1)
src/lib/crypto/MLDSAUtil.cpp (6)
getMLDSAPrivateKey(11-41)getMLDSAPrivateKey(11-11)getMLDSAPublicKey(43-69)getMLDSAPublicKey(43-43)setMLDSAPrivateKey(71-111)setMLDSAPrivateKey(71-71)
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (3)
src/lib/crypto/OSSLMLDSAPublicKey.cpp (10)
setFromOSSL(44-60)setFromOSSL(44-44)setValue(68-76)setValue(68-68)isOfType(63-66)isOfType(63-63)getOSSLKey(79-84)getOSSLKey(79-79)createOSSLKey(87-125)createOSSLKey(87-87)src/lib/crypto/MLDSAPrivateKey.cpp (10)
setSeed(65-68)setSeed(65-65)setValue(55-58)setValue(55-55)isOfType(17-20)isOfType(17-17)getValue(60-63)getValue(60-60)getParameterSet(28-39)getParameterSet(28-28)src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(224-233)mldsaParameterSet2Name(224-224)
🔇 Additional comments (12)
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (6)
31-38: Proper pkey lifecycle management in destructor — LGTMDestructor correctly frees pkey and nulls it, preventing leaks/double-frees.
44-55: Seed retrieval handled correctly — LGTMOptional seed is read and applied only when present and of expected length.
98-117: PKCS#8 encode path frees resources on all branches — LGTMHappy path and error paths release PKCS8_PRIV_KEY_INFO correctly; der consistency check is good.
120-133: Memory leak from earlier revision is resolved — LGTMEVP_PKEY from PKCS#8 gets freed after setFromOSSL(localPKey); good catch and fix.
150-160: Good defensive checks for unknown parameter set and empty keyFail-fast with clear logs prevents undefined behavior when building EVP_PKEY.
172-191: Provider-based key creation path looks correct — LGTMNo pre-allocation of pkey before EVP_PKEY_fromdata, proper ctx cleanup on all paths.
src/lib/SoftHSM.cpp (6)
65-70: Good encapsulation: ML-DSA headers are properly compiled behind WITH_ML_DSAThe conditional includes keep non-ML builds unaffected. No issues.
149-152: P11 ML-DSA objects are correctly gated with WITH_ML_DSAAdding P11MLDSAPublicKeyObj and P11MLDSAPrivateKeyObj under the compile guard prevents build breaks on non-ML configurations. Looks good.
Also applies to: 171-173
837-840: Mechanism registry updated for ML-DSACKM_ML_DSA_KEY_PAIR_GEN and CKM_ML_DSA are registered under WITH_ML_DSA. This aligns with the overall gating strategy.
945-947: Mechanism info: ML-DSA min/max sizes wired through CryptoFactoryRetrieval and propagation of key sizes for CKM_ML_DSA(_KEY_PAIR_GEN) are consistent with the rest of the codebase and guarded behind WITH_ML_DSA. Flags are appropriate (generate/sign/verify).
Also applies to: 1045-1056, 1343-1353
6171-6174: Keygen dispatch and template validation for ML-DSA
- CKM_ML_DSA_KEY_PAIR_GEN is correctly integrated into dispatch.
- Template consistency checks mirror other mechanisms.
- Dispatch to generateMLDSA is straightforward.
All good.
Also applies to: 6202-6204, 6227-6229, 6302-6309
6899-6902: Wrap/unwrap integration for ML-DSA private keys looks correct
- Wrap path maps CKK_ML_DSA to AsymAlgo::MLDSA and uses MLDSAUtil::getMLDSAPrivateKey before PKCS8 encoding; good.
- Unwrap path stores ML-DSA private key with MLDSAUtil::setMLDSAPrivateKey; good.
Assuming MLDSAUtil is updated to also carry the parameter set on runtime key objects (see other comments), this integration is sound.
Also applies to: 6943-6946, 7624-7627
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/lib/SoftHSM.cpp (1)
12423-12454: Bug: CKA_NEVER_EXTRACTABLE assignment uses CKA_ALWAYS_SENSITIVEIn the CKM_CONCATENATE_BASE_AND_KEY derivation path, the computed bNeverExtractable is assigned to CKA_ALWAYS_SENSITIVE, which is incorrect. It should set CKA_NEVER_EXTRACTABLE.
Apply:
- bool bNeverExtractable = baseKey->getBooleanValue(CKA_NEVER_EXTRACTABLE, false) && - otherKey->getBooleanValue(CKA_NEVER_EXTRACTABLE, false); - bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE, bNeverExtractable); + bool bNeverExtractable = baseKey->getBooleanValue(CKA_NEVER_EXTRACTABLE, false) && + otherKey->getBooleanValue(CKA_NEVER_EXTRACTABLE, false); + bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE, bNeverExtractable);
🧹 Nitpick comments (1)
src/lib/SoftHSM.cpp (1)
10223-10241: Remove unused local ‘parameterSet’ in ML-DSA private-key attributes‘ByteString parameterSet;’ is unused in this block.
Apply:
- // MLDSA Private Key Attributes - ByteString parameterSet; - ByteString value; - ByteString seed; + // MLDSA Private Key Attributes + ByteString value; + ByteString seed;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
src/lib/SoftHSM.cpp(34 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.386Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
📚 Learning: 2025-08-19T09:23:25.386Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.386Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Applied to files:
src/lib/SoftHSM.cpp
📚 Learning: 2025-08-18T19:46:46.645Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.645Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Applied to files:
src/lib/SoftHSM.cpp
📚 Learning: 2025-08-18T17:59:30.642Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.642Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Applied to files:
src/lib/SoftHSM.cpp
🧬 Code Graph Analysis (1)
src/lib/SoftHSM.cpp (2)
src/lib/crypto/CryptoFactory.cpp (4)
i(43-46)i(43-43)i(59-62)i(59-59)src/lib/crypto/MLDSAUtil.cpp (6)
getMLDSAPrivateKey(11-41)getMLDSAPrivateKey(11-11)getMLDSAPublicKey(43-69)getMLDSAPublicKey(43-43)setMLDSAPrivateKey(71-111)setMLDSAPrivateKey(71-71)
🔇 Additional comments (11)
src/lib/SoftHSM.cpp (11)
65-70: LGTM: ML-DSA headers are correctly feature-gatedIncluding ML-DSA headers under WITH_ML_DSA keeps non-ML builds clean.
149-152: LGTM: P11MLDSA object creation is behind WITH_ML_DSA*The new P11 object branches for CKK_ML_DSA are correctly wrapped with the feature guard.
Also applies to: 171-173
836-840: LGTM: Mechanism map extended with ML-DSACKM_ML_DSA_KEY_PAIR_GEN and CKM_ML_DSA added consistently with existing style.
945-948: LGTM: Mechanism info for ML-DSA added
- Min/max key sizes are fetched via CryptoFactory and recycled properly.
- Mechanism flags for keygen and sign/verify look correct.
Also applies to: 1045-1056, 1343-1353
1147-1147: Confirm reduced CKM_GENERIC_SECRET_KEY_GEN max size (0x8000000)You’ve reduced ulMaxKeySize from 0x80000000 to 0x8000000. This matches the check in generateGeneric (CKA_VALUE_LEN upper bound). Please confirm this change is intentional and won’t break existing clients depending on larger generic secret sizes.
4194-4443: LGTM: ML-DSA sign path integration
- Proper mechanism flagging, bAllowMultiPartOp=false, and use of MLDSAUtil for runtime key hydration.
- Parameter-set inference via key material length (no explicit setter) is consistent with the ML-DSA key types design.
Also applies to: 4531-4550
5203-5450: LGTM: ML-DSA verify path integration
- Mechanism mapping and object instantiation are consistent with the sign path.
- Uses MLDSAUtil for public key material.
Also applies to: 5538-5556
6739-6743: Wrap supports AES_CBC, but unwrap only supports AES_CBC_PAD — clarify intentC_WrapKey permits CKM_AES_CBC while UnwrapKeySym only implements PAD modes (CKM_AES_CBC_PAD/CKM_DES3_CBC_PAD). This asymmetry may surprise users.
- Either disallow CKM_AES_CBC in C_WrapKey, or add the corresponding non-PAD CBC path in UnwrapKeySym (with strict block/IV validation).
Also applies to: 7009-7035
10049-10076: LGTM: CKA_PARAMETER_SET parsing and validation
- Length check against sizeof(CK_ULONG) is correct.
- Using CKP_ML_DSA_44/65/87 constants improves clarity.
- Return code on unsupported set is CKR_PARAMETER_SET_NOT_SUPPORTED (assumed intentionally defined).
6890-6903: LGTM: ML-DSA integrated in wrap/unwrap flows
- Correct keyType routing to MLDSA for wrapping/unwrapping private keys.
- Uses MLDSAUtil for extracting/setting key material.
Also applies to: 6944-6947, 7625-7628
10099-10109: LGTM: ML-DSA key objects persist parameter set + seed/value
- Public key stores CKA_PARAMETER_SET and CKA_VALUE (optionally encrypted).
- Private key stores CKA_PARAMETER_SET, CKA_VALUE, and CKA_SEED (optionally encrypted).
No secret material is logged — good.Also applies to: 10156-10166, 10200-10210, 10238-10241
5fac462 to
c0ed069
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
src/lib/SoftHSM.cpp (1)
6421-6440: CBC wrap uses zero-length IV for non‑PAD modes — functional bug and potential UBFor CKM_AES_CBC and CKM_DES3_CBC, blocksize isn’t set, but you later do iv.resize(blocksize) and memcpy(..., blocksize). This yields a zero-length IV and memcpy with 0 bytes; accessing &iv[0] when size() == 0 is undefined behavior. Result: encryption init may use an empty IV or crash.
Fix by:
- Setting blocksize for non‑PAD modes (16 for AES, 8 for 3DES).
- Validating pParameter is non‑NULL and ulParameterLen equals blocksize for all CBC cases before memcpy/encryptInit.
Apply:
@@ - case CKM_AES_CBC: - algo = SymAlgo::AES; - break; + case CKM_AES_CBC: + algo = SymAlgo::AES; + blocksize = 16; + break; @@ - case CKM_DES3_CBC: - algo = SymAlgo::DES3; - break; + case CKM_DES3_CBC: + algo = SymAlgo::DES3; + blocksize = 8; + break; @@ - case CKM_AES_CBC: - case CKM_AES_CBC_PAD: - case CKM_DES3_CBC: - case CKM_DES3_CBC_PAD: - iv.resize(blocksize); - memcpy(&iv[0], pMechanism->pParameter, blocksize); + case CKM_AES_CBC: + case CKM_AES_CBC_PAD: + case CKM_DES3_CBC: + case CKM_DES3_CBC_PAD: + if (pMechanism->pParameter == NULL_PTR || + pMechanism->ulParameterLen != blocksize) { + cipher->recycleKey(wrappingkey); + CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); + return CKR_ARGUMENTS_BAD; + } + iv.resize(blocksize); + memcpy(&iv[0], pMechanism->pParameter, blocksize);Optional (recommended): for non‑PAD modes also check keydata.size() is a multiple of blocksize before encrypting.
This is a correctness issue that can break CBC wrapping at runtime.
Also applies to: 6464-6470
🧹 Nitpick comments (2)
src/lib/SoftHSM.cpp (2)
10021-10279: Consider adding targeted tests for ML‑DSA generation/sign/verifyNew surface area merits basic tests to catch regressions:
- C_GenerateKeyPair with CKA_PARAMETER_SET = CKP_ML_DSA_44/65/87
- C_SignInit/C_Sign and C_VerifyInit/C_Verify with CKM_ML_DSA
- Attribute persistence: CKA_PARAMETER_SET, CKA_SEED, CKA_VALUE (private), CKA_VALUE (public)
I can draft unit/integration tests for these flows if helpful.
10223-10227: Remove unused local variable ‘parameterSet’‘ByteString parameterSet;’ is declared but never used in generateMLDSA’s private-key block. Clean it up to avoid warnings.
- // MLDSA Private Key Attributes - ByteString parameterSet; - ByteString value; - ByteString seed; + // MLDSA Private Key Attributes + ByteString value; + ByteString seed;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
src/lib/SoftHSM.cpp(34 hunks)src/lib/crypto/OSSLUtil.cpp(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/lib/crypto/OSSLUtil.cpp
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.386Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
📚 Learning: 2025-08-19T09:23:25.386Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.386Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Applied to files:
src/lib/SoftHSM.cpp
📚 Learning: 2025-08-18T17:59:30.642Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.642Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Applied to files:
src/lib/SoftHSM.cpp
📚 Learning: 2025-08-18T19:46:46.645Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.645Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Applied to files:
src/lib/SoftHSM.cpp
🧬 Code Graph Analysis (1)
src/lib/SoftHSM.cpp (1)
src/lib/crypto/MLDSAUtil.cpp (6)
getMLDSAPrivateKey(11-41)getMLDSAPrivateKey(11-11)getMLDSAPublicKey(43-69)getMLDSAPublicKey(43-43)setMLDSAPrivateKey(71-111)setMLDSAPrivateKey(71-71)
🔇 Additional comments (8)
src/lib/SoftHSM.cpp (8)
65-70: Correctly gated ML‑DSA headersIncluding ML‑DSA headers behind WITH_ML_DSA is consistent with the project’s feature-gating approach. LGTM.
149-152: P11 ML‑DSA object creation properly feature‑gatedThe new CKK_ML_DSA branches for P11 public/private objects are correctly wrapped in WITH_ML_DSA. Prevents non-ML builds from referencing unknown symbols. LGTM.
Also applies to: 171-173
837-840: Mechanism registration for ML‑DSA addedCKM_ML_DSA_KEY_PAIR_GEN and CKM_ML_DSA are registered under WITH_ML_DSA. Good integration with supportedMechanisms and config filtering.
945-947: Mechanism info wiring for ML‑DSA is consistent
- Min/max key sizes fetched via CryptoFactory (mirrors other algos).
- Flags for keypair gen and sign/verify are set appropriately.
LGTM.Also applies to: 1044-1056, 1343-1353
4438-4443: Sign path: ML‑DSA integration via MLDSAUtilCKM_ML_DSA routed to AsymMech::MLDSA; key material loaded using MLDSAUtil. Parameter set is inferred from key length in MLDSA key classes, so no explicit setParameterSet is needed. Looks correct.
Also applies to: 4531-4550
5445-5450: Verify path: ML‑DSA integration via MLDSAUtilCKM_ML_DSA routed to AsymMech::MLDSA; MLDSAPublicKey populated via MLDSAUtil. Parameter set inference by key size keeps this path simple. LGTM.
Also applies to: 5538-5556
6171-6174: Key-pair generation: ML‑DSA routing and template checks
- CKM_ML_DSA_KEY_PAIR_GEN mapped to CKK_ML_DSA in both public/private template checks.
- generateMLDSA() invoked under WITH_ML_DSA.
Template consistency handling is aligned with other key types. LGTM.Also applies to: 6202-6204, 6228-6229, 6303-6311
10049-10076: CKA_PARAMETER_SET handling: length check and constants are correct
- Validates ulValueLen == sizeof(CK_ULONG) before reading.
- Uses CKP_ML_DSA_44/65/87 constants (consistent with project preference).
- Returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets (as per current codebase semantics).
LGTM.
bukka
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks pretty good from the initial look. Just few things but I haven't checked to logic too deeply and haven't tested it either.
@jschlyter It would be great if the workflow could be enabled so pipeline can run.
c0ed069 to
71b03bc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/lib/SoftHSM.cpp (2)
7070-7092: If keeping non-PAD CBC wrap, add the matching unwrap pathCurrently only PAD cases are implemented. Add CKM_AES_CBC and CKM_DES3_CBC here with blocksize set and padding=false, plus IV length validation, to make wrap/unwrap symmetric.
Happy to provide a full patch if you choose Option B (support non-PAD).
Also applies to: 7116-7151
6799-6804: Align AES‑CBC wrap/unwrap: disallow CKM_AES_CBC (non‑PAD) or implement non‑PAD unwrapC_WrapKey currently accepts CKM_AES_CBC but UnwrapKeySym only implements CKM_AES_CBC_PAD — pick one approach:
- Option A (restrict wrap to PAD): change C_WrapKey to accept only CKM_AES_CBC_PAD (src/lib/SoftHSM.cpp around lines 6753–6804).
- Option B (implement non‑PAD unwrap): add CKM_AES_CBC (no‑pad) handling inside UnwrapKeySym (implementation starts ~7054; current cases at 7083/7118/7429).
Option A (recommended small-scope fix):
- case CKM_AES_CBC: - case CKM_AES_CBC_PAD: + case CKM_AES_CBC_PAD: if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != 16) return CKR_ARGUMENTS_BAD; break;
♻️ Duplicate comments (4)
src/lib/crypto/OSSLMLDSAPublicKey.h (1)
29-31: Polymorphic type check LGTM.The .cpp now returns true for both this class’s type and MLDSAPublicKey::type. This resolves the earlier concern.
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (1)
119-133: PKCS#8 decode leak fixedEVP_PKEY is now freed after setFromOSSL(); good catch.
src/lib/crypto/OSSLMLDSA.h (1)
7-9: Include guard consistency: fixedGuard now matches; all good.
Also applies to: 54-54
src/lib/SoftHSM.cpp (1)
6481-6500: CBC wrap bug: zero-length IV used for AES_CBC/DES3_CBC (non-PAD)blocksize remains 0 for CKM_AES_CBC and CKM_DES3_CBC; you then copy a 0-byte IV and call encryptInit with an empty IV. This will fail or be incorrect. Please either set blocksize and validate IV length, or reject non-PAD modes.
Minimal fix:
- case CKM_AES_CBC: - algo = SymAlgo::AES; - break; + case CKM_AES_CBC: + algo = SymAlgo::AES; + blocksize = 16; + break; @@ - case CKM_DES3_CBC: - algo = SymAlgo::DES3; - break; + case CKM_DES3_CBC: + algo = SymAlgo::DES3; + blocksize = 8; + break; @@ - case CKM_AES_CBC: - case CKM_AES_CBC_PAD: - case CKM_DES3_CBC: - case CKM_DES3_CBC_PAD: - iv.resize(blocksize); - memcpy(&iv[0], pMechanism->pParameter, blocksize); + case CKM_AES_CBC: + case CKM_AES_CBC_PAD: + case CKM_DES3_CBC: + case CKM_DES3_CBC_PAD: + if (pMechanism->pParameter == NULL_PTR || + pMechanism->ulParameterLen != blocksize) { + cipher->recycleKey(wrappingkey); + CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); + return CKR_ARGUMENTS_BAD; + } + iv.resize(blocksize); + memcpy(&iv[0], pMechanism->pParameter, blocksize);Optional: enforce wrappedlen % blocksize == 0 for non-PAD modes before encrypting.
Also applies to: 6524-6531
🧹 Nitpick comments (15)
src/lib/crypto/OSSLMLDSAPublicKey.h (5)
21-21: Parameter name consistency (+make ctor explicit).Align with the .cpp and avoid implicit conversions.
- OSSLMLDSAPublicKey(const EVP_PKEY* inMLDSAKEY); + explicit OSSLMLDSAPublicKey(const EVP_PKEY* inEVPPKEY);Mirror the rename in OSSLMLDSAPublicKey.cpp constructor signature. Also consider renaming the setFromOSSL parameter for consistency (see below).
29-33: Add override specifiers for safer vtable checks.Marking overrides helps catch signature drift at compile time.
- virtual bool isOfType(const char* inType); + virtual bool isOfType(const char* inType) override; - virtual void setValue(const ByteString& value); + virtual void setValue(const ByteString& value) override;
34-36: Rename param to match OpenSSL type; fix error message in .cpp.Minor consistency: use inEVPPKEY here, matching the type and the ctor.
Also, in OSSLMLDSAPublicKey.cpp inside setFromOSSL(), the error string says “private key private” while fetching OSSL_PKEY_PARAM_PUB_KEY; change to “public key”.
Header tweak:
- virtual void setFromOSSL(const EVP_PKEY* inMLDSAKEY); + virtual void setFromOSSL(const EVP_PKEY* inEVPPKEY);CPP tweak (not in this hunk):
- ERROR_MSG("Could not get private key private, rv: %d", rv); + ERROR_MSG("Could not get public key, rv: %d", rv);
13-13: Reduce header coupling: forward-declare EVP_PKEY.To limit transitive includes from a widely included header, forward-declare EVP_PKEY here and include <openssl/evp.h> in the .cpp.
-#include <openssl/evp.h> +// Forward declaration to decouple header from OpenSSL headers +typedef struct evp_pkey_st EVP_PKEY;Ensure OSSLMLDSAPublicKey.cpp retains
#include <openssl/evp.h>.
48-49: Fix include-guard trailing comment typo.The guard name includes “ML”. Update the trailing comment to match.
-#endif // !_SOFTHSM_V2_OSSLDSAPUBLICKEY_H +#endif // !_SOFTHSM_V2_OSSLMLDSAPUBLICKEY_HREADME.md (1)
85-85: Documented option looks good; fix hard tab to satisfy markdownlint (MD010).Replace the tab(s) on this new line with spaces, or fence the whole options block to silence the linter.
- --enable-mldsa Enable support for ML-DSA (default detect) + --enable-mldsa Enable support for ML-DSA (default detect)src/lib/crypto/OSSLMLDSAPrivateKey.h (2)
13-15: Trim header includes; forward-declare EVP_PKEY to reduce compile surface.-#include <openssl/bn.h> -#include <openssl/evp.h> +// Forward declaration; include <openssl/evp.h> in the .cpp +typedef struct evp_pkey_st EVP_PKEY;
58-58: Fix end-guard comment typo.-#endif // !_SOFTHSM_V2_OSSLECPRIVATEKEY_H +#endif // !_SOFTHSM_V2_OSSLMLDSAPRIVATEKEY_Hsrc/lib/crypto/OSSLUtil.cpp (1)
43-49: Optional: replace the map with a switch to drop and constexpr-initialize.-#ifdef WITH_ML_DSA -static const std::map<unsigned long, const char*> mldsaAlgNameFromParameterSet { - {MLDSAParameters::ML_DSA_44_PARAMETER_SET, "ML-DSA-44"}, - {MLDSAParameters::ML_DSA_65_PARAMETER_SET, "ML-DSA-65"}, - {MLDSAParameters::ML_DSA_87_PARAMETER_SET, "ML-DSA-87"} -}; -#endif +#ifdef WITH_ML_DSA +#include <openssl/core_names.h> +#endifAnd:
-const char* OSSL::mldsaParameterSet2Name(unsigned long parameterSet) { - - std::map<unsigned long, const char*>::const_iterator it = mldsaAlgNameFromParameterSet.find(parameterSet); - - if (it != mldsaAlgNameFromParameterSet.end()) { - return it->second; - } - - return NULL; -} +const char* OSSL::mldsaParameterSet2Name(unsigned long parameterSet) { + switch (parameterSet) { + case MLDSAParameters::ML_DSA_44_PARAMETER_SET: return "ML-DSA-44"; + case MLDSAParameters::ML_DSA_65_PARAMETER_SET: return "ML-DSA-65"; + case MLDSAParameters::ML_DSA_87_PARAMETER_SET: return "ML-DSA-87"; + default: return NULL; + } +}m4/acx_crypto_backend.m4 (1)
188-191: Handle --enable-mldsa=detect on Botan path explicitlyFor symmetry with ECC/EDDSA handling, set detect→no on Botan to make logs deterministic and avoid leaving "detect" dangling.
Apply:
- if test "x${enable_mldsa}" = "xyes"; then - AC_MSG_ERROR([Botan does not support ML-DSA]) - fi + case "${enable_mldsa}" in + yes) AC_MSG_ERROR([Botan does not support ML-DSA]);; + detect) enable_mldsa="no";; + esacsrc/lib/crypto/OSSLMLDSAPrivateKey.cpp (3)
23-29: Guard against NULL EVP_PKEY in ctor-from-OSSLDefensive check avoids accidental nullptr deref if misused.
OSSLMLDSAPrivateKey::OSSLMLDSAPrivateKey(const EVP_PKEY* inMLDSAKEY) { pkey = NULL; - setFromOSSL(inMLDSAKEY); + if (inMLDSAKEY == NULL) { + ERROR_MSG("NULL EVP_PKEY passed to OSSLMLDSAPrivateKey ctor"); + return; + } + setFromOSSL(inMLDSAKEY); }
46-54: Zeroise temporary key buffers after useWipe seed/priv stack buffers after copying to ByteString to reduce leakage surface.
#include "OSSLUtil.h" #include <openssl/bn.h> #include <openssl/core_names.h> +#include <openssl/crypto.h> #include <openssl/x509.h> @@ if(rv && seed_len == 32) { // seed is not mandatory for OSSL key reconstruction ByteString seedBS = ByteString(seed, seed_len); setSeed(seedBS); } + OPENSSL_cleanse(seed, sizeof(seed)); @@ ByteString valueBS = ByteString(priv, priv_len); setValue(valueBS); + OPENSSL_cleanse(priv, sizeof(priv));Also applies to: 56-69
59-65: Fix log message typo“private key private” → “private key value”.
- if(!rv) { - ERROR_MSG("Could not get private key private, rv: %d", rv); + if(!rv) { + ERROR_MSG("Could not get private key value, rv: %d", rv); return; }src/lib/crypto/OSSLMLDSA.h (1)
10-13: Gate header contents under WITH_ML_DSA to avoid OpenSSL header requirements in non-ML-DSA buildsPrevents accidental inclusion on Botan-only builds.
#ifndef _SOFTHSM_V2_OSSLMLDSA_H #define _SOFTHSM_V2_OSSLMLDSA_H #include "config.h" -#include "AsymmetricAlgorithm.h" -#include <openssl/evp.h> +#ifdef WITH_ML_DSA +#include "AsymmetricAlgorithm.h" +#include <openssl/evp.h> @@ private: }; -#endif // !_SOFTHSM_V2_OSSLMLDSA_H +#endif // WITH_ML_DSA +#endif // !_SOFTHSM_V2_OSSLMLDSA_HAlso applies to: 14-52
src/lib/SoftHSM.cpp (1)
10284-10286: Remove unused local variable in ML-DSA private-key blockByteString parameterSet is unused; trim to avoid warnings.
- // MLDSA Private Key Attributes - ByteString parameterSet; - ByteString value; - ByteString seed; + // MLDSA Private Key Attributes + ByteString value; + ByteString seed;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (44)
.github/workflows/ci.yml(1 hunks)CMAKE-NOTES.md(1 hunks)CMAKE-WIN-NOTES.md(1 hunks)CMakeLists.txt(1 hunks)README.md(1 hunks)config.h.in.cmake(1 hunks)m4/acx_crypto_backend.m4(4 hunks)m4/acx_openssl_mldsa.m4(1 hunks)src/bin/dump/tables.h(3 hunks)src/lib/P11Attributes.cpp(2 hunks)src/lib/P11Attributes.h(2 hunks)src/lib/P11Objects.cpp(2 hunks)src/lib/P11Objects.h(2 hunks)src/lib/SoftHSM.cpp(34 hunks)src/lib/SoftHSM.h(2 hunks)src/lib/crypto/AsymmetricAlgorithm.h(2 hunks)src/lib/crypto/CMakeLists.txt(2 hunks)src/lib/crypto/MLDSAParameters.cpp(1 hunks)src/lib/crypto/MLDSAParameters.h(1 hunks)src/lib/crypto/MLDSAPrivateKey.cpp(1 hunks)src/lib/crypto/MLDSAPrivateKey.h(1 hunks)src/lib/crypto/MLDSAPublicKey.cpp(1 hunks)src/lib/crypto/MLDSAPublicKey.h(1 hunks)src/lib/crypto/MLDSAUtil.cpp(1 hunks)src/lib/crypto/MLDSAUtil.h(1 hunks)src/lib/crypto/Makefile.am(3 hunks)src/lib/crypto/OSSLComp.cpp(1 hunks)src/lib/crypto/OSSLCryptoFactory.cpp(2 hunks)src/lib/crypto/OSSLMLDSA.cpp(1 hunks)src/lib/crypto/OSSLMLDSA.h(1 hunks)src/lib/crypto/OSSLMLDSAKeyPair.cpp(1 hunks)src/lib/crypto/OSSLMLDSAKeyPair.h(1 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.cpp(1 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.h(1 hunks)src/lib/crypto/OSSLMLDSAPublicKey.cpp(1 hunks)src/lib/crypto/OSSLMLDSAPublicKey.h(1 hunks)src/lib/crypto/OSSLUtil.cpp(2 hunks)src/lib/crypto/OSSLUtil.h(1 hunks)src/lib/crypto/test/CMakeLists.txt(1 hunks)src/lib/crypto/test/MLDSATests.cpp(1 hunks)src/lib/crypto/test/MLDSATests.h(1 hunks)src/lib/crypto/test/Makefile.am(1 hunks)src/lib/object_store/DBObject.cpp(1 hunks)src/lib/pkcs11/pkcs11.h(5 hunks)
✅ Files skipped from review due to trivial changes (3)
- CMAKE-NOTES.md
- CMAKE-WIN-NOTES.md
- src/lib/crypto/OSSLComp.cpp
🚧 Files skipped from review as they are similar to previous changes (31)
- src/lib/crypto/OSSLUtil.h
- src/lib/crypto/test/CMakeLists.txt
- CMakeLists.txt
- src/lib/crypto/MLDSAPrivateKey.h
- m4/acx_openssl_mldsa.m4
- src/lib/crypto/MLDSAPublicKey.h
- src/lib/crypto/test/MLDSATests.cpp
- src/lib/crypto/test/MLDSATests.h
- src/lib/crypto/test/Makefile.am
- src/lib/crypto/MLDSAParameters.h
- src/lib/crypto/MLDSAParameters.cpp
- src/lib/crypto/MLDSAPrivateKey.cpp
- src/lib/crypto/OSSLCryptoFactory.cpp
- src/bin/dump/tables.h
- src/lib/crypto/CMakeLists.txt
- src/lib/crypto/AsymmetricAlgorithm.h
- src/lib/P11Attributes.h
- src/lib/crypto/MLDSAPublicKey.cpp
- src/lib/P11Objects.h
- src/lib/crypto/Makefile.am
- src/lib/P11Objects.cpp
- src/lib/crypto/OSSLMLDSA.cpp
- src/lib/crypto/OSSLMLDSAKeyPair.h
- src/lib/P11Attributes.cpp
- src/lib/crypto/OSSLMLDSAKeyPair.cpp
- config.h.in.cmake
- src/lib/crypto/OSSLMLDSAPublicKey.cpp
- src/lib/crypto/MLDSAUtil.h
- .github/workflows/ci.yml
- src/lib/crypto/MLDSAUtil.cpp
- src/lib/pkcs11/pkcs11.h
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: bukka
PR: softhsm/SoftHSMv2#815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.347Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
📚 Learning: 2025-08-19T09:23:25.434Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Applied to files:
src/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/OSSLUtil.cppsrc/lib/SoftHSM.cppsrc/lib/SoftHSM.h
📚 Learning: 2025-08-18T17:59:30.693Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.693Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Applied to files:
src/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/OSSLUtil.cppsrc/lib/SoftHSM.cppsrc/lib/SoftHSM.h
📚 Learning: 2025-08-18T19:46:46.659Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Applied to files:
src/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/OSSLUtil.cppsrc/lib/SoftHSM.cppsrc/lib/SoftHSM.h
📚 Learning: 2025-09-11T16:54:00.347Z
Learnt from: bukka
PR: softhsm/SoftHSMv2#815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.347Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Applied to files:
src/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/SoftHSM.cppsrc/lib/SoftHSM.h
📚 Learning: 2025-08-18T17:54:37.645Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: m4/acx_openssl_mldsa.m4:10-35
Timestamp: 2025-08-18T17:54:37.645Z
Learning: For OpenSSL feature detection in autoconf macros, prefer functional tests (like EVP_PKEY_CTX_new_from_name) over version number checks, as the functional approach directly tests the actual capability and is more reliable across different OpenSSL builds where features may be backported or disabled.
Applied to files:
m4/acx_crypto_backend.m4
🧬 Code graph analysis (6)
src/lib/crypto/OSSLMLDSAPublicKey.h (3)
src/lib/crypto/OSSLMLDSAPublicKey.cpp (13)
OSSLMLDSAPublicKey(18-21)OSSLMLDSAPublicKey(23-28)OSSLMLDSAPublicKey(31-38)isOfType(63-66)isOfType(63-63)setValue(68-76)setValue(68-68)setFromOSSL(44-60)setFromOSSL(44-44)getOSSLKey(79-84)getOSSLKey(79-79)createOSSLKey(87-125)createOSSLKey(87-87)src/lib/crypto/MLDSAPublicKey.h (1)
MLDSAPublicKey(14-45)src/lib/crypto/MLDSAPublicKey.cpp (4)
isOfType(17-20)isOfType(17-17)setValue(60-63)setValue(60-60)
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (4)
src/lib/crypto/OSSLMLDSAPrivateKey.h (1)
OSSLMLDSAPrivateKey(16-56)src/lib/crypto/OSSLMLDSAPublicKey.cpp (10)
setFromOSSL(44-60)setFromOSSL(44-44)setValue(68-76)setValue(68-68)isOfType(63-66)isOfType(63-63)getOSSLKey(79-84)getOSSLKey(79-79)createOSSLKey(87-125)createOSSLKey(87-87)src/lib/crypto/MLDSAPrivateKey.cpp (10)
setSeed(65-68)setSeed(65-65)setValue(55-58)setValue(55-55)isOfType(17-20)isOfType(17-17)getValue(60-63)getValue(60-60)getParameterSet(28-39)getParameterSet(28-28)src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(224-233)mldsaParameterSet2Name(224-224)
src/lib/crypto/OSSLMLDSA.h (2)
src/lib/crypto/AsymmetricAlgorithm.h (2)
AsymmetricAlgorithm(121-190)AsymmetricAlgorithm(128-128)src/lib/crypto/OSSLMLDSA.cpp (40)
sign(24-97)sign(24-26)signInit(99-105)signInit(99-100)signUpdate(107-112)signUpdate(107-107)signFinal(114-119)signFinal(114-114)verify(122-222)verify(122-124)verifyInit(224-230)verifyInit(224-225)verifyUpdate(232-237)verifyUpdate(232-232)verifyFinal(239-244)verifyFinal(239-239)encrypt(247-253)encrypt(247-248)decrypt(256-262)decrypt(256-257)getMinKeySize(264-267)getMinKeySize(264-264)getMaxKeySize(269-272)getMaxKeySize(269-269)generateKeyPair(282-345)generateKeyPair(282-282)reconstructKeyPair(347-383)reconstructKeyPair(347-347)reconstructPublicKey(385-406)reconstructPublicKey(385-385)reconstructPrivateKey(408-429)reconstructPrivateKey(408-408)reconstructParameters(446-466)reconstructParameters(446-446)newPublicKey(431-434)newPublicKey(431-431)newPrivateKey(436-439)newPrivateKey(436-436)newParameters(441-444)newParameters(441-441)
src/lib/crypto/OSSLMLDSAPrivateKey.h (3)
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (19)
OSSLMLDSAPrivateKey(18-21)OSSLMLDSAPrivateKey(23-28)OSSLMLDSAPrivateKey(31-38)isOfType(72-75)isOfType(72-72)setValue(77-85)setValue(77-77)setSeed(87-95)setSeed(87-87)PKCS8Encode(98-117)PKCS8Encode(98-98)PKCS8Decode(120-133)PKCS8Decode(120-120)setFromOSSL(44-69)setFromOSSL(44-44)getOSSLKey(136-141)getOSSLKey(136-136)createOSSLKey(144-192)createOSSLKey(144-144)src/lib/crypto/MLDSAPrivateKey.h (1)
MLDSAPrivateKey(13-47)src/lib/crypto/MLDSAPrivateKey.cpp (6)
isOfType(17-20)isOfType(17-17)setValue(55-58)setValue(55-55)setSeed(65-68)setSeed(65-65)
src/lib/SoftHSM.cpp (1)
src/lib/crypto/MLDSAUtil.cpp (6)
getMLDSAPrivateKey(11-41)getMLDSAPrivateKey(11-11)getMLDSAPublicKey(43-69)getMLDSAPublicKey(43-43)setMLDSAPrivateKey(71-111)setMLDSAPrivateKey(71-71)
src/lib/SoftHSM.h (1)
src/lib/SoftHSM.cpp (2)
generateMLDSA(10083-10339)generateMLDSA(10083-10094)
🪛 markdownlint-cli2 (0.17.2)
README.md
85-85: Hard tabs
Column: 1
(MD010, no-hard-tabs)
85-85: Hard tabs
Column: 16
(MD010, no-hard-tabs)
🔇 Additional comments (17)
src/lib/SoftHSM.h (2)
55-58: Good: ML-DSA headers are correctly feature-gated.
378-393: Good: generateMLDSA() is declared under WITH_ML_DSA, matching the implementation.src/lib/crypto/OSSLUtil.cpp (1)
223-234: Declaration exists and is correctly guarded.
Header src/lib/crypto/OSSLUtil.h already declaresconst char* mldsaParameterSet2Name(unsigned long)inside#ifdef WITH_ML_DSA(lines ~76–78).m4/acx_crypto_backend.m4 (3)
31-39: ML-DSA configure flag: LGTMOption wiring and help text look consistent with ECC/EDDSA.
257-269: WITH_ML_DSA define/conditional: LGTMConsistent with existing feature toggles; no issues.
113-121: Resolve: ACX_OPENSSL_MLDSA uses capability-based detectionConfirmed — the macro performs a functional check calling EVP_PKEY_CTX_new_from_name("ML-DSA-44") in m4/acx_openssl_mldsa.m4; no version-gate change required.
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (1)
150-160: Early guards on param-set/name and empty key: LGTMPrevents undefined provider behavior on bad inputs.
src/lib/crypto/OSSLMLDSA.h (1)
32-39: Resolved — ML-DSA encrypt/decrypt/checkEncryptedDataSize are already stubbedImplementations in src/lib/crypto/OSSLMLDSA.cpp (≈ lines 247–276) log "ML-DSA does not support encryption" and act as stubs — no change required.
src/lib/SoftHSM.cpp (9)
65-70: ML-DSA includes and guard look goodHeaders are properly gated under WITH_ML_DSA.
149-152: Correct feature-gating for ML-DSA P11 objectsnewP11Object branches are properly wrapped; avoids non-ML builds breaking.
Also applies to: 171-173
842-846: Mechanism registration: OKCKM_ML_DSA and KEY_PAIR_GEN added as expected.
950-953: C_GetMechanismInfo wiring for ML-DSA: OKMin/max are pulled from CryptoFactory and flags are set appropriately.
Also applies to: 1049-1061, 1353-1363
4204-4205: Sign init path for ML-DSA: OKUsing MLDSAUtil and relying on parameter-set inference is consistent with project preference.
Also applies to: 4473-4478, 4566-4584
5238-5239: Verify init path for ML-DSA: OKMirrors sign path; no explicit setParameterSet required.
Also applies to: 5505-5510, 5598-5616
6231-6234: Key-pair gen plumbing for ML-DSA: OKMechanism switch, template checks, and dispatch to generateMLDSA are sound.
Also applies to: 6262-6264, 6288-6289, 6362-6371
10099-10121: generateMLDSA: robust template parsing and validationCKA_PARAMETER_SET length checked, CKP_ML_DSA_* constants used, and “unsupported” path logged consistently.
Also applies to: 10133-10136
1152-1152: Confirm CKM_GENERIC_SECRET_KEY_GEN max size changeulMaxKeySize = 0x08000000 (134,217,728) — intentional? It differs from other “unbounded” caps used elsewhere.
|
Very cool. Did some manual test. I checked out this branch and tested with our p11ng-cli from EJBCA (Java code using Bouncy Castle). Generating keys, listing keys, signing (and verifying the signatures with Bouncy Castle code). I have PKCS#11v3.2 draft implemented and it worked out-of-the-box. Works well with all variants ML-DSA-44, ML-DSA-65 and ML-DSA-87. |
Thank you very much ! |
|
Nice work! I'll ask @bjosv to review before merge. |
jschlyter
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please address and resolve all comments. If you believe the rabbit is out of line, do tell it.
|
Not sure if it's helpful, but have an implementation of it working here: |
All resolved :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/lib/crypto/OSSLMLDSAPublicKey.cpp(1 hunks)src/lib/crypto/OSSLMLDSAPublicKey.h(1 hunks)src/lib/crypto/OSSLUtil.cpp(2 hunks)src/lib/object_store/DBObject.cpp(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/lib/object_store/DBObject.cpp
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-08-19T09:23:25.434Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Applied to files:
src/lib/crypto/OSSLUtil.cppsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSAPublicKey.cpp
📚 Learning: 2025-08-18T17:59:30.693Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.693Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Applied to files:
src/lib/crypto/OSSLUtil.cpp
📚 Learning: 2025-08-18T19:46:46.659Z
Learnt from: antoinelochet
PR: softhsm/SoftHSMv2#809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Applied to files:
src/lib/crypto/OSSLUtil.cpp
🧬 Code graph analysis (2)
src/lib/crypto/OSSLMLDSAPublicKey.h (3)
src/lib/crypto/OSSLMLDSAPublicKey.cpp (14)
OSSLMLDSAPublicKey(18-21)OSSLMLDSAPublicKey(23-28)OSSLMLDSAPublicKey(31-38)OSSLMLDSAPublicKey(40-44)isOfType(84-87)isOfType(84-84)setValue(89-97)setValue(89-89)setFromOSSL(65-81)setFromOSSL(65-65)getOSSLKey(100-105)getOSSLKey(100-100)createOSSLKey(108-146)createOSSLKey(108-108)src/lib/crypto/MLDSAPublicKey.h (1)
MLDSAPublicKey(14-45)src/lib/crypto/MLDSAPublicKey.cpp (4)
isOfType(17-20)isOfType(17-17)setValue(60-63)setValue(60-60)
src/lib/crypto/OSSLMLDSAPublicKey.cpp (4)
src/lib/crypto/OSSLMLDSAPublicKey.h (1)
OSSLMLDSAPublicKey(15-54)src/lib/crypto/OSSLMLDSAPrivateKey.cpp (10)
setFromOSSL(44-69)setFromOSSL(44-44)setValue(77-85)setValue(77-77)isOfType(72-75)isOfType(72-72)getOSSLKey(136-141)getOSSLKey(136-136)createOSSLKey(144-192)createOSSLKey(144-144)src/lib/crypto/MLDSAPublicKey.cpp (8)
setValue(60-63)setValue(60-60)isOfType(17-20)isOfType(17-17)getValue(55-58)getValue(55-55)getParameterSet(28-39)getParameterSet(28-28)src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(226-235)mldsaParameterSet2Name(226-226)
|
I found an issue. It does not handle signing with a provided ML-DSA context. I.e. PKCS11v3.2 section 6.67.5.
Referring to section 6.67.1: This is needed for Composite certificates as a domain separator is used as specified in composite draft 12 section 7. |
I think there is (was?) an issue with OpenSSL. I will have to check. |
|
Sorry I haven't found time for a proper testing yet. I wanted to do it today I got a bit stuck on those Windows failures ( #826 and #828 ) that will be failing here as well (2 independent issues on Win). What I at least managed to do is to create update of the pkcs11.h from p11kit (which finally added 3.2.0 version) with some extra updates: #827 . That seems to work (except those 2 unrelated failures on Windows) so I think it should be merged first and this should be rebased on it so we don't do those mini updates to that header... Hopefully next time I will have more time on this and we will get pipeline to a better state. I think it's quite important to have a green CI for this as trying to fix regressions later is quite pain (especially on Windows that I don't normally use...). |
I can definitely do that :) |
49b2f4f to
dd80081
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (4)
src/lib/crypto/Makefile.am (1)
85-88: Wrap OpenSSL ML-DSA sources with WITH_ML_DSA conditional.The four OSSL ML-DSA source files (OSSLMLDSA.cpp, OSSLMLDSAKeyPair.cpp, OSSLMLDSAPrivateKey.cpp, OSSLMLDSAPublicKey.cpp) should be conditionally compiled only when ML-DSA support is enabled. Without this guard, builds with OpenSSL < 3.5 or with ML-DSA explicitly disabled will encounter compilation errors.
This requires:
- Adding
AM_CONDITIONAL([WITH_ML_DSA], ...)in configure.ac after the ML-DSA detection logic- Wrapping these four files in an
if WITH_ML_DSA ... endifblockApply this pattern:
OSSLMD5.cpp \ +if WITH_ML_DSA OSSLMLDSA.cpp \ OSSLMLDSAKeyPair.cpp \ OSSLMLDSAPrivateKey.cpp \ OSSLMLDSAPublicKey.cpp \ +endif OSSLRNG.cpp \And ensure the corresponding
AM_CONDITIONALis defined in configure.ac based on the ML-DSA detection results fromm4/acx_crypto_backend.m4andm4/acx_openssl_mldsa.m4.src/lib/SoftHSM.cpp (2)
4205-4208: Zero‑initialize and fully defineSIGN_ADDITIONAL_CONTEXTfor ML‑DSA sign initWhen
CKM_ML_DSAis used with a non‑NULLpParameterbutulContextLen == 0,additionalContext.contextAsCharandadditionalContext.contextLengthremain uninitialized and are still copied into the session viasetParameters. The ML‑DSA backend will then read indeterminate pointer/length values, which is undefined behavior and can lead to invalid memory access.Fix by value‑initializing the struct and explicitly setting pointer/length before the length check, e.g.:
#ifdef WITH_ML_DSA - bool isMLDSA = false; - SIGN_ADDITIONAL_CONTEXT additionalContext; + bool isMLDSA = false; + SIGN_ADDITIONAL_CONTEXT additionalContext = {}; #endif @@ #ifdef WITH_ML_DSA case CKM_ML_DSA: mechanism = AsymMech::MLDSA; bAllowMultiPartOp = false; isMLDSA = true; if (pMechanism->pParameter != NULL_PTR) { @@ - else - { + else + { const CK_SIGN_ADDITIONAL_CONTEXT* ckSignAdditionalContext = (const CK_SIGN_ADDITIONAL_CONTEXT*) pMechanism->pParameter; @@ - if (ckSignAdditionalContext->ulContextLen > 0) - { + additionalContext.contextAsChar = NULL; + additionalContext.contextLength = 0; + if (ckSignAdditionalContext->ulContextLen > 0) + { @@ - additionalContext.contextAsChar = (unsigned char*) ckSignAdditionalContext->pContext; - additionalContext.contextLength = ckSignAdditionalContext->ulContextLen; + additionalContext.contextAsChar = (unsigned char*) ckSignAdditionalContext->pContext; + additionalContext.contextLength = ckSignAdditionalContext->ulContextLen; @@ - param = &additionalContext; - paramLen = sizeof(SIGN_ADDITIONAL_CONTEXT); + param = &additionalContext; + paramLen = sizeof(SIGN_ADDITIONAL_CONTEXT); } } } break;This guarantees deterministic fields (NULL/0) when no context is supplied while preserving the existing validation and hedgeVariant mapping.
Also applies to: 4476-4521, 4611-4629
5283-5285: Apply the sameSIGN_ADDITIONAL_CONTEXTinitialization fix in verify init
AsymVerifyInitmirrors the ML‑DSA handling fromAsymSignInitand has the same issue:additionalContextis stack‑allocated and not zero‑initialized; withulContextLen == 0but non‑NULLpParameter, pointer/length remain indeterminate whilehedgeTypeis set and the struct is passed into the session.Mirror the sign‑side fix here:
#ifdef WITH_ML_DSA - bool isMLDSA = false; - SIGN_ADDITIONAL_CONTEXT additionalContext; + bool isMLDSA = false; + SIGN_ADDITIONAL_CONTEXT additionalContext = {}; #endif @@ #ifdef WITH_ML_DSA case CKM_ML_DSA: mechanism = AsymMech::MLDSA; bAllowMultiPartOp = false; isMLDSA = true; if (pMechanism->pParameter != NULL_PTR) { @@ - else - { + else + { const CK_SIGN_ADDITIONAL_CONTEXT* ckSignAdditionalContext = (const CK_SIGN_ADDITIONAL_CONTEXT*) pMechanism->pParameter; @@ - if (ckSignAdditionalContext->ulContextLen > 0) { + additionalContext.contextAsChar = NULL; + additionalContext.contextLength = 0; + if (ckSignAdditionalContext->ulContextLen > 0) { @@ - additionalContext.contextAsChar = (unsigned char*) ckSignAdditionalContext->pContext; - additionalContext.contextLength = ckSignAdditionalContext->ulContextLen; + additionalContext.contextAsChar = (unsigned char*) ckSignAdditionalContext->pContext; + additionalContext.contextLength = ckSignAdditionalContext->ulContextLen; @@ - param = &additionalContext; - paramLen = sizeof(SIGN_ADDITIONAL_CONTEXT); + param = &additionalContext; + paramLen = sizeof(SIGN_ADDITIONAL_CONTEXT); } } } break;This keeps the sign/verify behavior symmetric and prevents undefined behavior in the verify path as well.
Also applies to: 5551-5595, 5684-5702
src/lib/crypto/OSSLMLDSA.cpp (1)
291-310: API pairing: verify_message_init with EVP_PKEY_verify.This was previously flagged as mixing APIs incorrectly. However, PR testing (per primetomas) confirms signing and verification work correctly with OpenSSL 3.5. The message-based init API followed by
EVP_PKEY_verifyappears to be the correct pattern for pure signature algorithms like ML-DSA in OpenSSL 3.5.Please confirm this API pairing is documented/supported in OpenSSL 3.5 for ML-DSA:
OpenSSL 3.5 EVP_PKEY_verify_message_init EVP_PKEY_verify ML-DSA usage
🧹 Nitpick comments (6)
src/lib/crypto/OSSLUtil.cpp (1)
37-51: LGTM: ML-DSA utility additions are properly guarded.The conditional includes and static map are correctly wrapped with
WITH_ML_DSA. The implementation correctly maps parameter set constants to OpenSSL algorithm names.Note: A past reviewer suggested moving
mldsaAlgNameFromParameterSetinsidemldsaParameterSet2Name()since it's the only consumer. This is optional but would improve encapsulation.m4/acx_openssl_mldsa.m4 (1)
17-24: Minor: Test program leaks EVP_PKEY_CTX.The test snippet creates an
EVP_PKEY_CTXbut doesn't free it before returning. While this is just a configure-time test and the leak is inconsequential in practice, addingEVP_PKEY_CTX_free(pctx)would be cleaner.int main() { EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name(NULL, "ML-DSA-44", NULL); - if (pctx == NULL) - return 1; - return 0; + if (pctx == NULL) + return 1; + EVP_PKEY_CTX_free(pctx); + return 0; }Also note the inconsistent indentation in the original (lines 21-23 are over-indented).
src/lib/crypto/OSSLMLDSAKeyPair.cpp (1)
13-25: Setter semantics look correct; consider tightening const-correctnessCopying only seed/value into the internal keys avoids shallow-copying OpenSSL handles and double‑free issues. You can safely change the parameters to
const OSSLMLDSAPublicKey&/const OSSLMLDSAPrivateKey&since they are not modified.src/lib/SoftHSM.h (1)
55-58: Unify ML-DSA key includes with existing include policyOther algorithm key headers (RSA, DSA, EC, ED, GOST) are included unconditionally here; feature gating happens via mechanism tables and backend wiring. To keep SoftHSM.h consistent with that pattern and the later SLH include policy, consider dropping the
#ifdef WITH_ML_DSAaroundMLDSAPublicKey.h/MLDSAPrivateKey.hand letting them always be available.Based on learnings, algorithm key/parameter headers are intended to be unguarded.
m4/acx_crypto_backend.m4 (1)
31-39: Configure-time ML-DSA wiring is correct; consider normalizingenable_mldsaunder BotanOpenSSL handling mirrors ECC/EDDSA: feature probing via
ACX_OPENSSL_MLDSA, hard error on--enable-mldsa=yeswithout support, and mappingdetect→ yes/no. For the Botan backend you currently only error onenable_mldsa=yes; with the defaultdetectyou effectively treat ML‑DSA as disabled. For clarity, you could explicitly setenable_mldsa=noin the Botan branch when ML‑DSA isn’t available so the later summary andAM_CONDITIONAL([WITH_ML_DSA], …)are based on a strict yes/no state rather thandetect.Also applies to: 113-121, 188-191, 257-269
src/lib/crypto/MLDSAPublicKey.cpp (1)
13-83: MLDSAPublicKey mapping and (de)serialisation align with MLDSA designType checking, bit-length calculation, parameter-set inference from
value.size(), and output-length mapping all mirror the private-key side and the MLDSAParameters constants. Serialisation as a single ByteString plus the simple empty-check on deserialise are appropriate for this key type. Only minor nit: the comments abovegetParameterSet/getOutputLengthstill mention “bit length”/“signatureLength length”, but that doesn’t affect behaviour.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (46)
.github/workflows/ci.yml(1 hunks)CMAKE-NOTES.md(1 hunks)CMAKE-WIN-NOTES.md(1 hunks)CMakeLists.txt(1 hunks)README.md(1 hunks)config.h.in.cmake(1 hunks)m4/acx_crypto_backend.m4(4 hunks)m4/acx_openssl_mldsa.m4(1 hunks)src/bin/dump/tables.h(3 hunks)src/lib/P11Attributes.cpp(2 hunks)src/lib/P11Attributes.h(2 hunks)src/lib/P11Objects.cpp(2 hunks)src/lib/P11Objects.h(2 hunks)src/lib/SoftHSM.cpp(34 hunks)src/lib/SoftHSM.h(2 hunks)src/lib/crypto/AsymmetricAlgorithm.h(3 hunks)src/lib/crypto/CMakeLists.txt(2 hunks)src/lib/crypto/MLDSAParameters.cpp(1 hunks)src/lib/crypto/MLDSAParameters.h(1 hunks)src/lib/crypto/MLDSAPrivateKey.cpp(1 hunks)src/lib/crypto/MLDSAPrivateKey.h(1 hunks)src/lib/crypto/MLDSAPublicKey.cpp(1 hunks)src/lib/crypto/MLDSAPublicKey.h(1 hunks)src/lib/crypto/MLDSAUtil.cpp(1 hunks)src/lib/crypto/MLDSAUtil.h(1 hunks)src/lib/crypto/Makefile.am(3 hunks)src/lib/crypto/OSSLComp.cpp(1 hunks)src/lib/crypto/OSSLCryptoFactory.cpp(2 hunks)src/lib/crypto/OSSLMLDSA.cpp(1 hunks)src/lib/crypto/OSSLMLDSA.h(1 hunks)src/lib/crypto/OSSLMLDSAKeyPair.cpp(1 hunks)src/lib/crypto/OSSLMLDSAKeyPair.h(1 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.cpp(1 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.h(1 hunks)src/lib/crypto/OSSLMLDSAPublicKey.cpp(1 hunks)src/lib/crypto/OSSLMLDSAPublicKey.h(1 hunks)src/lib/crypto/OSSLUtil.cpp(2 hunks)src/lib/crypto/OSSLUtil.h(1 hunks)src/lib/crypto/test/CMakeLists.txt(1 hunks)src/lib/crypto/test/MLDSATests.cpp(1 hunks)src/lib/crypto/test/MLDSATests.h(1 hunks)src/lib/crypto/test/Makefile.am(1 hunks)src/lib/object_store/DBObject.cpp(1 hunks)src/lib/session_mgr/Session.cpp(1 hunks)src/lib/test/SignVerifyTests.cpp(2 hunks)src/lib/test/SignVerifyTests.h(3 hunks)
✅ Files skipped from review due to trivial changes (2)
- src/lib/crypto/OSSLComp.cpp
- src/lib/crypto/MLDSAUtil.cpp
🚧 Files skipped from review as they are similar to previous changes (14)
- src/bin/dump/tables.h
- src/lib/crypto/test/CMakeLists.txt
- src/lib/crypto/OSSLMLDSAPublicKey.h
- CMakeLists.txt
- src/lib/object_store/DBObject.cpp
- src/lib/crypto/CMakeLists.txt
- src/lib/P11Objects.h
- src/lib/crypto/OSSLMLDSAPublicKey.cpp
- src/lib/crypto/OSSLMLDSA.h
- src/lib/crypto/OSSLUtil.h
- src/lib/crypto/test/MLDSATests.h
- src/lib/crypto/OSSLMLDSAPrivateKey.h
- src/lib/crypto/MLDSAUtil.h
- src/lib/crypto/MLDSAPrivateKey.h
🧰 Additional context used
🧠 Learnings (15)
📓 Common learnings
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.370Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:5550-5596
Timestamp: 2025-10-27T16:44:57.865Z
Learning: SoftHSM ML‑DSA additional context: avoid transient malloc in SoftHSM::{AsymSignInit, AsymVerifyInit}; let Session::setParameters deep‑copy SIGN_ADDITIONAL_CONTEXT by allocating one buffer for struct + context bytes and fixing the stored pointer; Session::resetOp frees m_pParameters so both struct and context are released.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.693Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:13265-13282
Timestamp: 2025-10-13T09:43:45.885Z
Learning: SoftHSM OAEP policy: In SoftHSM::MechParamCheckRSAPKCSOAEP (src/lib/SoftHSM.cpp), enforce that the MGF1 variant must correspond to the selected hashAlg (e.g., SHA-256 -> CKG_MGF1_SHA256). Mismatches should return CKR_ARGUMENTS_BAD with "Hash and MGF don't match". This mirrors the existing PSS enforcement.
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:3238-3266
Timestamp: 2025-10-13T09:42:31.270Z
Learning: In src/lib/SoftHSM.cpp, SoftHSM::AsymDecryptInit should use MechParamCheckRSAPKCSOAEP for CKM_RSA_PKCS_OAEP to keep OAEP parameter validation identical to AsymEncryptInit, and avoid redundant manual checks for pMechanism->pParameter and MGF allowlists.
Learnt from: JoaoHenrique12
Repo: softhsm/SoftHSMv2 PR: 823
File: src/lib/SoftHSM.cpp:58-58
Timestamp: 2025-11-11T19:42:46.886Z
Learning: SoftHSM include policy: Algorithm key/parameter headers (e.g., SLHParameters, SLH*Key) are included unconditionally in SoftHSM.cpp/SoftHSM.h; feature gating is handled in mechanism tables and CryptoFactory (WITH_*). Avoid wrapping such includes in WITH_* guards.
📚 Learning: 2025-08-18T17:54:37.645Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: m4/acx_openssl_mldsa.m4:10-35
Timestamp: 2025-08-18T17:54:37.645Z
Learning: For OpenSSL feature detection in autoconf macros, prefer functional tests (like EVP_PKEY_CTX_new_from_name) over version number checks, as the functional approach directly tests the actual capability and is more reliable across different OpenSSL builds where features may be backported or disabled.
Applied to files:
m4/acx_openssl_mldsa.m4.github/workflows/ci.ymlm4/acx_crypto_backend.m4src/lib/crypto/Makefile.amsrc/lib/crypto/OSSLMLDSA.cpp
📚 Learning: 2025-10-27T16:44:57.865Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:5550-5596
Timestamp: 2025-10-27T16:44:57.865Z
Learning: SoftHSM ML‑DSA additional context: avoid transient malloc in SoftHSM::{AsymSignInit, AsymVerifyInit}; let Session::setParameters deep‑copy SIGN_ADDITIONAL_CONTEXT by allocating one buffer for struct + context bytes and fixing the stored pointer; Session::resetOp frees m_pParameters so both struct and context are released.
Applied to files:
m4/acx_openssl_mldsa.m4src/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLUtil.cppm4/acx_crypto_backend.m4src/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/SoftHSM.hsrc/lib/crypto/Makefile.amsrc/lib/test/SignVerifyTests.cppsrc/lib/test/SignVerifyTests.hsrc/lib/crypto/OSSLCryptoFactory.cppsrc/lib/crypto/MLDSAParameters.cppsrc/lib/crypto/OSSLMLDSAKeyPair.cppsrc/lib/P11Objects.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/MLDSAPublicKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-10-13T09:42:31.270Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:3238-3266
Timestamp: 2025-10-13T09:42:31.270Z
Learning: In src/lib/SoftHSM.cpp, SoftHSM::AsymDecryptInit should use MechParamCheckRSAPKCSOAEP for CKM_RSA_PKCS_OAEP to keep OAEP parameter validation identical to AsymEncryptInit, and avoid redundant manual checks for pMechanism->pParameter and MGF allowlists.
Applied to files:
m4/acx_openssl_mldsa.m4src/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLUtil.cppsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/SoftHSM.hsrc/lib/crypto/Makefile.amsrc/lib/test/SignVerifyTests.cppsrc/lib/test/SignVerifyTests.hsrc/lib/crypto/OSSLCryptoFactory.cppsrc/lib/crypto/OSSLMLDSAKeyPair.cppsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/P11Attributes.cppsrc/lib/SoftHSM.cpp
📚 Learning: 2025-09-11T16:54:00.370Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.370Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Applied to files:
m4/acx_openssl_mldsa.m4src/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/OSSLUtil.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/SoftHSM.hsrc/lib/crypto/Makefile.amsrc/lib/P11Attributes.hsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/P11Attributes.cppsrc/lib/SoftHSM.cpp
📚 Learning: 2025-08-18T19:46:46.659Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Applied to files:
m4/acx_openssl_mldsa.m4src/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLUtil.cppsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/SoftHSM.hsrc/lib/crypto/Makefile.amsrc/lib/test/SignVerifyTests.cppsrc/lib/test/SignVerifyTests.hsrc/lib/crypto/OSSLCryptoFactory.cppsrc/lib/crypto/MLDSAParameters.cppconfig.h.in.cmakesrc/lib/P11Attributes.hsrc/lib/crypto/OSSLMLDSAKeyPair.cppsrc/lib/crypto/MLDSAPublicKey.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/P11Attributes.cppsrc/lib/crypto/MLDSAPublicKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-10-13T09:43:45.885Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:13265-13282
Timestamp: 2025-10-13T09:43:45.885Z
Learning: SoftHSM OAEP policy: In SoftHSM::MechParamCheckRSAPKCSOAEP (src/lib/SoftHSM.cpp), enforce that the MGF1 variant must correspond to the selected hashAlg (e.g., SHA-256 -> CKG_MGF1_SHA256). Mismatches should return CKR_ARGUMENTS_BAD with "Hash and MGF don't match". This mirrors the existing PSS enforcement.
Applied to files:
m4/acx_openssl_mldsa.m4src/lib/crypto/OSSLUtil.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/SoftHSM.hsrc/lib/crypto/Makefile.amsrc/lib/test/SignVerifyTests.hsrc/lib/P11Attributes.hsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/P11Attributes.cppsrc/lib/SoftHSM.cpp
📚 Learning: 2025-08-18T17:59:30.693Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.693Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Applied to files:
m4/acx_openssl_mldsa.m4src/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLUtil.cppCMAKE-WIN-NOTES.mdsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/SoftHSM.hsrc/lib/crypto/Makefile.amsrc/lib/test/SignVerifyTests.cppsrc/lib/test/SignVerifyTests.hsrc/lib/crypto/OSSLCryptoFactory.cppsrc/lib/crypto/MLDSAParameters.cppconfig.h.in.cmakesrc/lib/P11Attributes.hsrc/lib/crypto/OSSLMLDSAKeyPair.cppsrc/lib/crypto/MLDSAPublicKey.cppsrc/lib/P11Objects.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/P11Attributes.cppsrc/lib/crypto/MLDSAPublicKey.hsrc/lib/SoftHSM.cppCMAKE-NOTES.md
📚 Learning: 2025-08-19T09:23:25.434Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Applied to files:
m4/acx_openssl_mldsa.m4src/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLUtil.cppm4/acx_crypto_backend.m4CMAKE-WIN-NOTES.mdsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/SoftHSM.hsrc/lib/crypto/Makefile.amsrc/lib/test/SignVerifyTests.cppsrc/lib/test/SignVerifyTests.hsrc/lib/crypto/OSSLCryptoFactory.cppsrc/lib/crypto/MLDSAParameters.cppconfig.h.in.cmakesrc/lib/crypto/OSSLMLDSAKeyPair.cppsrc/lib/crypto/MLDSAPublicKey.cppsrc/lib/P11Objects.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/MLDSAPublicKey.hsrc/lib/SoftHSM.cppREADME.md
📚 Learning: 2025-08-12T13:25:41.715Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 806
File: .github/workflows/ci.yml:66-66
Timestamp: 2025-08-12T13:25:41.715Z
Learning: Ubuntu 24.04 (ubuntu-24.04 GitHub Actions runner image) comes with OpenSSL 3.0 and development headers (libssl-dev equivalent) pre-installed, so explicit installation of libssl-dev is not required for OpenSSL builds in CI workflows using this image.
Applied to files:
.github/workflows/ci.yml
📚 Learning: 2025-08-12T13:25:41.715Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 806
File: .github/workflows/ci.yml:66-66
Timestamp: 2025-08-12T13:25:41.715Z
Learning: GitHub Actions ubuntu-24.04 runner image comes with OpenSSL 3.0 and development headers pre-installed by default, so explicit installation of libssl-dev is not required for OpenSSL builds in workflows using this runner image.
Applied to files:
.github/workflows/ci.yml
📚 Learning: 2025-08-12T13:25:41.715Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 806
File: .github/workflows/ci.yml:66-66
Timestamp: 2025-08-12T13:25:41.715Z
Learning: The GitHub Actions ubuntu-24.04 runner image includes OpenSSL and libssl-dev pre-installed by default, as documented in the official actions/runner-images repository. Explicit installation of libssl-dev is not required for OpenSSL builds using this runner image.
Applied to files:
.github/workflows/ci.yml
📚 Learning: 2025-11-11T19:42:46.886Z
Learnt from: JoaoHenrique12
Repo: softhsm/SoftHSMv2 PR: 823
File: src/lib/SoftHSM.cpp:58-58
Timestamp: 2025-11-11T19:42:46.886Z
Learning: SoftHSM include policy: Algorithm key/parameter headers (e.g., SLHParameters, SLH*Key) are included unconditionally in SoftHSM.cpp/SoftHSM.h; feature gating is handled in mechanism tables and CryptoFactory (WITH_*). Avoid wrapping such includes in WITH_* guards.
Applied to files:
src/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLUtil.cppsrc/lib/SoftHSM.hsrc/lib/crypto/Makefile.amsrc/lib/crypto/OSSLCryptoFactory.cppsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-08-18T19:35:33.938Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/OSSLMLDSA.cpp:195-204
Timestamp: 2025-08-18T19:35:33.938Z
Learning: In OpenSSL, EVP_PKEY_verify_message does not exist. EVP_PKEY_verify_message_init is designed for streaming verification and should be paired with EVP_PKEY_CTX_set_signature, EVP_PKEY_verify_message_update, and EVP_PKEY_verify_message_final - not with EVP_PKEY_verify.
Applied to files:
src/lib/crypto/OSSLMLDSA.cpp
📚 Learning: 2025-08-11T16:42:23.012Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 806
File: src/lib/test/p11test.cpp:81-84
Timestamp: 2025-08-11T16:42:23.012Z
Learning: In SoftHSM test files (like p11test.cpp and cryptotest.cpp), error handling for OSSL_PROVIDER_load() calls for "legacy" and "default" providers is intentionally omitted because these providers won't fail in practice and the test code is kept deliberately simple.
Applied to files:
src/lib/SoftHSM.cpp
🧬 Code graph analysis (11)
src/lib/crypto/test/MLDSATests.cpp (2)
src/lib/crypto/test/MLDSATests.h (1)
MLDSATests(13-52)src/lib/crypto/OSSLCryptoFactory.cpp (2)
i(287-295)i(287-287)
src/lib/SoftHSM.h (2)
src/lib/SoftHSM.cpp (2)
generateMLDSA(10169-10424)generateMLDSA(10169-10180)src/lib/test/SignVerifyTests.cpp (2)
generateMLDSA(232-271)generateMLDSA(232-232)
src/lib/test/SignVerifyTests.cpp (1)
src/lib/SoftHSM.cpp (4)
generateMLDSA(10169-10424)generateMLDSA(10169-10180)C_GenerateKeyPair(6264-6459)C_GenerateKeyPair(6264-6274)
src/lib/test/SignVerifyTests.h (2)
src/lib/test/SignVerifyTests.cpp (4)
testMLDSASignVerify(850-937)testMLDSASignVerify(850-850)generateMLDSA(232-271)generateMLDSA(232-232)src/lib/SoftHSM.cpp (2)
generateMLDSA(10169-10424)generateMLDSA(10169-10180)
src/lib/P11Attributes.h (2)
src/lib/P11Attributes.cpp (34)
P11Attribute(43-49)P11Attribute(52-54)setDefault(503-507)setDefault(503-503)setDefault(532-536)setDefault(532-532)setDefault(563-567)setDefault(563-563)setDefault(592-596)setDefault(592-592)setDefault(630-634)setDefault(630-630)setDefault(668-672)setDefault(668-668)setDefault(706-710)setDefault(706-706)setDefault(717-721)setDefault(717-717)updateAttr(56-70)updateAttr(56-56)updateAttr(510-525)updateAttr(510-510)updateAttr(539-554)updateAttr(539-539)updateAttr(570-585)updateAttr(570-570)updateAttr(599-623)updateAttr(599-599)updateAttr(637-661)updateAttr(637-637)updateAttr(675-699)updateAttr(675-675)updateAttr(724-751)updateAttr(724-724)src/lib/object_store/OSObject.h (1)
OSObject(42-92)
src/lib/crypto/MLDSAPublicKey.cpp (2)
src/lib/crypto/MLDSAPrivateKey.cpp (16)
isOfType(17-20)isOfType(17-17)getBitLength(22-25)getBitLength(22-22)getValue(60-63)getValue(60-60)getParameterSet(28-39)getParameterSet(28-28)getOutputLength(42-53)getOutputLength(42-42)setValue(55-58)setValue(55-55)serialise(76-80)serialise(76-76)deserialise(82-97)deserialise(82-82)src/lib/crypto/MLDSAParameters.cpp (6)
getParameterSet(22-25)getParameterSet(22-22)serialise(34-37)serialise(34-34)deserialise(39-50)deserialise(39-39)
src/lib/P11Objects.cpp (2)
src/lib/P11Objects.h (2)
P11MLDSAPublicKeyObj(201-212)P11MLDSAPrivateKeyObj(303-314)src/lib/P11Attributes.cpp (2)
init(109-120)init(109-109)
src/lib/crypto/MLDSAPrivateKey.cpp (2)
src/lib/crypto/MLDSAPublicKey.cpp (14)
isOfType(17-20)isOfType(17-17)getBitLength(22-25)getBitLength(22-22)getValue(55-58)getValue(55-55)getParameterSet(28-39)getParameterSet(28-28)getOutputLength(42-53)getOutputLength(42-42)serialise(66-69)serialise(66-66)deserialise(71-83)deserialise(71-71)src/lib/crypto/MLDSAParameters.cpp (6)
getParameterSet(22-25)getParameterSet(22-22)serialise(34-37)serialise(34-34)deserialise(39-50)deserialise(39-39)
src/lib/crypto/OSSLMLDSA.cpp (1)
src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(226-235)mldsaParameterSet2Name(226-226)
src/lib/P11Attributes.cpp (2)
src/lib/data_mgr/ByteString.cpp (5)
ByteString(49-51)ByteString(53-59)ByteString(61-80)ByteString(82-107)ByteString(109-112)src/lib/data_mgr/ByteString.h (1)
ByteString(64-64)
src/lib/SoftHSM.cpp (1)
src/lib/crypto/MLDSAUtil.cpp (6)
getMLDSAPrivateKey(11-41)getMLDSAPrivateKey(11-11)getMLDSAPublicKey(43-69)getMLDSAPublicKey(43-43)setMLDSAPrivateKey(71-111)setMLDSAPrivateKey(71-71)
🪛 markdownlint-cli2 (0.18.1)
CMAKE-NOTES.md
14-14: Hard tabs
Column: 1
(MD010, no-hard-tabs)
README.md
85-85: Hard tabs
Column: 1
(MD010, no-hard-tabs)
85-85: Hard tabs
Column: 16
(MD010, no-hard-tabs)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Linux with OpenSSL 3.0
- GitHub Check: Linux with OpenSSL 3.5.4
- GitHub Check: Linux with OpenSSL 1.1.1
- GitHub Check: Linux with Botan
- GitHub Check: Windows (x64, openssl)
- GitHub Check: Windows (x86, openssl)
- GitHub Check: macOS (openssl)
- GitHub Check: Windows (x64, botan)
- GitHub Check: macOS (botan)
🔇 Additional comments (64)
.github/workflows/ci.yml (1)
79-115: ✓ Past review suggestions correctly applied; OpenSSL 3.5.4 CI job is well-structured.The new
linux_ossl_35job correctly addresses the earlier feedback:
- Lines 88, 107–108: LDFLAGS now uses
-Wl,-rpath(not-R), and PKG_CONFIG_PATH is properly set to guide OpenSSL detection.- Lines 90–101: OpenSSL 3.5.4 source build with appropriate config options (
shared,zlib, cipher hardening),sudo make install, and thelib64 → libsymlink.- Line 111:
--with-openssl=${{ env.OPENSSL_INSTALL_DIR }}correctly passes the built OpenSSL to./configure.- Line 104–105: CXXFLAGS
-Werroris gated as a comment pending deprecation fixes—appropriate for a new OpenSSL major version.- Line 112: Parallel
make -j$(nproc)accelerates CI runtime.Environment variables are properly scoped to steps where they apply: Prepare (OpenSSL build) and Build (SoftHSM configure).
config.h.in.cmake (1)
154-156: LGTM!The WITH_ML_DSA macro definition follows the established pattern for cryptographic feature flags and is correctly placed alongside similar options.
src/lib/test/SignVerifyTests.cpp (3)
231-272: LGTM!The
generateMLDSAfunction correctly follows the established pattern for key generation test helpers and properly configures ML-DSA-specific attributes.
279-279: Appropriate buffer size for ML-DSA signatures.The increase from 256 bytes to 64 KB correctly accommodates ML-DSA signature sizes, which can reach up to 4595 bytes for ML-DSA-87.
849-938: Comprehensive ML-DSA test coverage.The test function properly exercises all hedge types (PREFERRED, REQUIRED, DETERMINISTIC_REQUIRED) both with and without additional context, across all key storage scenarios. The previous review concerns about memory leaks and const correctness have been resolved.
CMAKE-WIN-NOTES.md (1)
55-55: LGTM!The ENABLE_MLDSA documentation entry follows the established format and is correctly positioned alongside similar cryptographic feature flags.
src/lib/crypto/test/Makefile.am (1)
27-27: LGTM!The addition of MLDSATests.cpp to the test sources is straightforward and correct.
README.md (1)
85-85: LGTM!The
--enable-mldsadocumentation entry is correctly formatted and positioned alongside other cryptographic feature options.src/lib/crypto/OSSLCryptoFactory.cpp (2)
61-63: LGTM!The OSSLMLDSA header inclusion follows the established pattern for optional cryptographic algorithms and is properly guarded with WITH_ML_DSA.
354-357: LGTM!The ML-DSA algorithm instantiation correctly follows the factory pattern and is properly feature-gated, consistent with other optional algorithms like EDDSA.
CMAKE-NOTES.md (1)
14-14: LGTM!The ENABLE_MLDSA option documentation is correctly formatted and positioned alongside other build configuration options.
src/lib/crypto/Makefile.am (2)
6-7: LGTM!The additional include paths for slot_mgr and object_store are appropriate for ML-DSA integration.
33-36: LGTM!The ML-DSA core source files are appropriately added to the common (non-backend-specific) sources. Based on learnings, algorithm headers and parameter classes are included unconditionally, with feature gating handled in mechanism tables and CryptoFactory.
src/lib/crypto/OSSLUtil.cpp (1)
225-236: LGTM: Parameter set lookup is correctly implemented.The function properly handles the lookup and returns
NULLfor unknown parameter sets, allowing callers to handle unsupported cases appropriately.src/lib/P11Attributes.cpp (2)
2235-2260: LGTM: CKA_PARAMETER_SET attribute handling is correct.The implementation properly:
- Defaults to
unsigned long(0), consistent with the update path- Restricts modification to
OBJECT_OP_GENERATEandOBJECT_OP_CREATEoperations only- Validates
ulValueLenmatchessizeof(CK_ULONG)This aligns with the ML-DSA key generation flow where parameter set is specified at creation time.
2563-2596: LGTM: CKA_SEED attribute handling follows established patterns.The implementation correctly:
- Initializes to an empty
ByteStringas default- Encrypts the seed value when the object is private (matching
P11AttrValuebehavior)- Validates the encrypted value size before storing
This properly protects ML-DSA seed material for private key objects.
src/lib/test/SignVerifyTests.h (2)
52-54: LGTM: ML-DSA test registration follows established patterns.The parameterized test approach mirrors the EdDSA pattern and efficiently tests all three ML-DSA parameter sets (ML-DSA-44, ML-DSA-65, ML-DSA-87) with a single test function.
66-80: LGTM: Test and helper function declarations are properly guarded.The declarations are consistent with other algorithm-specific test functions in the class and correctly wrapped with
WITH_ML_DSAguards.src/lib/session_mgr/Session.cpp (1)
355-388: Deep-copy implementation is correct, but interface design concern remains.The implementation correctly:
- Validates NULL context pointer when
contextLength > 0(Line 360-363)- Allocates a single contiguous buffer for struct + context bytes
- Updates the stored pointer to reference the embedded context data
- Returns early to avoid the generic
memcpypathHowever, the previous reviewer's concern about fragile interface design (determining struct type solely by
inParamLen == sizeof(SIGN_ADDITIONAL_CONTEXT)) remains valid. If another mechanism uses a struct of the same size, this could cause incorrect handling.Consider adding an explicit flag or enum parameter to indicate when
SIGN_ADDITIONAL_CONTEXThandling is required, rather than relying on size matching. This could be addressed in a follow-up.Based on learnings, the deep-copy approach is the agreed-upon solution.
m4/acx_openssl_mldsa.m4 (1)
32-35: Cross-compilation defaults to disabled ML-DSA.When cross-compiling,
AC_RUN_IFELSEcannot execute the test program, so ML-DSA support defaults to "no". This is a conservative approach but may be limiting for cross-compilation scenarios targeting OpenSSL 3.5+.Per retrieved learnings, functional tests are preferred over version checks, so this trade-off is acceptable. Users cross-compiling for targets with ML-DSA support can override via
--enable-mldsaor similar configure flags if needed.Based on learnings, functional test approach is the agreed-upon solution.
src/lib/SoftHSM.h (1)
378-392: ML-DSA generator declaration guarding matches existing patternsWrapping
generateMLDSAin#ifdef WITH_ML_DSAaligns with how ECC/EDDSA helpers are guarded and keeps declarations in sync with the implementation when ML-DSA is disabled.src/lib/P11Attributes.h (1)
1151-1163: New CKA_PARAMETER_SET / CKA_SEED attribute wrappers are consistent with existing patternsThe constructors and check flags for
P11AttrParameterSetandP11AttrSeedmirror how other ULONG/sensitive key attributes are modeled (e.g., key type, private exponent, primes), so they should integrate cleanly into the existing attribute framework once wired up in P11Attributes.cpp.Also applies to: 1282-1298
src/lib/crypto/MLDSAParameters.cpp (1)
12-50: MLDSAParameters storage and (de)serialisation look soundType tagging, simple getter/setter, and the
ByteString-based serialise/deserialise flow are in line with how other parameter classes are implemented. Range checking of the parameter set is correctly left to higher-level code (e.g., generateMLDSA).src/lib/crypto/test/MLDSATests.cpp (1)
46-122: Comprehensive ML-DSA tests; structure and lifetimes look correctThe fixture exercises key generation, (de)serialisation, PKCS#8, and the various hedge/deterministic/context combinations with both success and failure paths. Object lifetimes (keys, parameters, RNG, additional context strings) are handled safely across all tests.
Also applies to: 163-518
src/lib/crypto/MLDSAPublicKey.h (1)
10-45: MLDSAPublicKey interface is well-formed and self-containedThe header now explicitly includes
ByteString.h, and the virtual interface (type check, parameter/output length queries, value accessors, serialisation) matches the implementation and existing key classes. No ABI or ownership issues are apparent.src/lib/P11Objects.cpp (2)
933-976: LGTM: P11MLDSAPublicKeyObj follows established pattern correctly.The implementation mirrors existing public key objects (EC, ED, DSA) with appropriate attribute flags: ParameterSet (ck3 for generate), Value (ck1|ck4 for create/unwrap).
1383-1430: LGTM: P11MLDSAPrivateKeyObj follows established pattern correctly.The implementation mirrors existing private key objects (EC, ED, DSA) with appropriate attribute flags: ParameterSet (ck4|ck6), Seed (optional), Value (ck1|ck4|ck6|ck7). Attribute flag combination matches other private key types.
src/lib/crypto/AsymmetricAlgorithm.h (3)
45-99: LGTM: Enum additions are clean and consistent.MLDSA and EDDSA added to both AsymAlgo::Type and AsymMech::Type enums following the established pattern.
121-129: LGTM: Hedge type definition is clean.Simple enum wrapper for ML-DSA signing modes (hedged vs deterministic) per FIPS 204.
131-153: LGTM: SIGN_ADDITIONAL_CONTEXT design is sound.Copy operations deleted to prevent shallow-copy issues, const pointer signals non-ownership, and documentation clarifies Session::setParameters handles deep-copy. This addresses all previous review concerns.
Based on learnings, Session::setParameters performs the deep-copy allocation.
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (8)
18-38: LGTM: Constructor/destructor memory management is correct.Default initialization to NULL, proper EVP_PKEY_free in destructor with NULL check.
44-69: LGTM: setFromOSSL correctly handles optional seed and mandatory private key.Seed extraction is conditional (only if present and length==32), private key extraction has error handling, and buffer sizing accommodates all ML-DSA variants.
72-75: Acknowledged: isOfType only checks concrete type.This design choice (not chaining to parent) was previously discussed and author chose current implementation.
77-95: LGTM: setValue and setSeed correctly invalidate cached OpenSSL key.Both methods update parent state then free pkey to force reconstruction, with proper NULL checks.
98-117: LGTM: PKCS8Encode has complete error handling and memory management.All OpenSSL resources properly freed, error conditions checked, empty ByteString returned on failure.
120-133: LGTM: PKCS8Decode correctly frees EVP_PKEY after setFromOSSL.Memory leak concern from previous review addressed. All OpenSSL resources properly managed.
136-141: LGTM: getOSSLKey implements standard lazy initialization.Creates key on-demand if not present, simple and correct.
144-192: LGTM: createOSSLKey properly guards against invalid state and handles OpenSSL API correctly.Guards for unknown parameter set and empty value added per previous review. EVP_PKEY_fromdata used correctly without pre-allocation. All error paths free EVP_PKEY_CTX.
src/lib/crypto/OSSLMLDSAKeyPair.h (1)
16-39: LGTM: Class structure follows established key pair pattern.OSSLMLDSAKeyPair correctly derives from AsymmetricKeyPair with appropriate virtual overrides and concrete member types.
src/lib/crypto/MLDSAPrivateKey.cpp (8)
14-20: LGTM: Type identification follows standard pattern.Static type string and isOfType comparison consistent with other key classes.
22-25: LGTM: getBitLength correctly delegates to ByteString.Simple and correct implementation.
28-39: LGTM: getParameterSet correctly infers from key material length.Maps private key sizes to parameter sets per FIPS 204, returns 0 for unknown. Matches project design per learnings.
42-53: LGTM: getOutputLength correctly maps to signature lengths.Infers signature size from private key length per FIPS 204 Table 2.
55-63: LGTM: setValue/getValue are straightforward accessors.Simple and correct.
65-73: LGTM: setSeed/getSeed are straightforward accessors.Simple and correct.
76-80: LGTM: serialise concatenates seed and value.Simple serialization using ByteString::serialise(), matches deserialise order.
82-97: Verify seed requirement in deserialise.The code requires both seed and value to be non-empty (lines 87-91), but OSSLMLDSAPrivateKey::setFromOSSL indicates "seed is not mandatory for OSSL key reconstruction." If a key without a seed is serialized, deserialization will fail.
Confirm whether:
- All ML-DSA private keys in SoftHSM are guaranteed to have seeds, or
- deserialise should accept empty seeds
If empty seeds should be allowed:
- if ((seed.size() == 0) || - (value.size() == 0)) + if (value.size() == 0) { return false; } setSeed(seed); setValue(value);src/lib/crypto/MLDSAParameters.h (3)
7-34: LGTM: Header structure and class declaration are correct.Proper includes, derives from AsymmetricParameters, standard method declarations.
36-44: LGTM: Parameter set constants use PKCS#11 macros per project preference.Per learnings, the author prefers PKCS#11 constant references for clarity. Comment documents the values.
46-65: LGTM: Length constants match FIPS 204 specification.Private key, public key, and signature lengths for ML-DSA-44/65/87 correctly match FIPS 204 Table 2 as documented in comments.
src/lib/SoftHSM.cpp (5)
65-70: ML-DSA headers and P11 object wiring look consistent and safely gatedIncluding MLDSAParameters/Key/Util under
WITH_ML_DSAand guarding theP11MLDSA*branches innewP11Objectkeeps non-ML builds compiling while cleanly integrating ML-DSA objects into the existing factory. No issues here.Also applies to: 149-152, 170-173
841-845: Mechanism table and C_GetMechanismInfo integration for ML-DSA is coherentExposing
CKM_ML_DSA_KEY_PAIR_GENandCKM_ML_DSAinprepareSupportedMechanismsand wiring their min/max key sizes and flags inC_GetMechanismInfoviaAsymAlgo::MLDSAmatches the patterns used for RSA/DSA/ECDSA/EDDSA. The use ofCKF_GENERATE_KEY_PAIRfor keygen andCKF_SIGN | CKF_VERIFYforCKM_ML_DSAis appropriate.Also applies to: 950-952, 1051-1063, 1353-1365
471-472: ML‑DSA sign/verify flow (mech mapping, session parameters, key loading) looks correctThe ML‑DSA additions in
AsymSignInit/AsymVerifyInitand the correspondingAsymSign/AsymVerifypaths integrate cleanly:
- Mechanism mapping (
CKM_ML_DSA→AsymMech::MLDSA) andbAllowMultiPartOp = falseenforce single‑part sign/verify, which matches how ML‑DSA is used here.- ML‑DSA keys are obtained via
MLDSAUtil::getMLDSAPrivateKey/getMLDSAPublicKey, which handles encrypted attributes and matches the provided MLDSAUtil snippets.- Passing the additional context via
session->setParametersand reading it back inAsymSign/AsymVerifythroughsession->getParametersis consistent with the project’s parameter‑passing convention (and with the Session‑side deep‑copying of SIGN_ADDITIONAL_CONTEXT from the learnings).Once the
SIGN_ADDITIONAL_CONTEXTinit issue is fixed, this pipeline looks solid.Also applies to: 4655-4675, 5728-5742, 5802-5809
6317-6374: ML‑DSA key‑pair generation and storage are correctly parameterized and aligned with MLDSAUtil
generateMLDSAand its call sites look consistent and robust:
CKA_PARAMETER_SETis validated for correct length (sizeof(CK_ULONG)), required (non‑zero), and checked againstCKP_ML_DSA_44/65/87before proceeding. Unsupported values returnCKR_PARAMETER_SET_NOT_SUPPORTED, matching the preferred style in this PR.MLDSAParameters::setParameterSet(paramSet)is used instead of magic numbers, aligning with the project preference to keep PKCS#11 constants in code.- Public and private OSObjects persist:
CKA_PARAMETER_SETfrompub->getParameterSet()/priv->getParameterSet()CKA_VALUE(public value / private value)CKA_SEED(private seed)
with encryption guarded by theis*KeyPrivateflags.C_GenerateKeyPairroutesCKM_ML_DSA_KEY_PAIR_GENtogenerateMLDSAonly when both templates advertiseCKK_ML_DSA, so template/mechanism consistency is enforced.Given MLDSAUtil::{get,set}MLDSAPrivateKey uses the same attributes, this round‑trip (generate → store → load) should be interoperable.
Also applies to: 6448-6457, 10167-10227, 10242-10315, 10370-10387
7036-7048: ML‑DSA wrap/unwrap integration via MLDSAUtil is coherent and consistent with other algorithmsFor private keys:
C_WrapKey’sCKK_ML_DSAbranch callsMLDSAUtil::getMLDSAPrivateKey, then wraps the PKCS#8‑encoded key via the existing private‑key PKCS#8 path.C_UnwrapKey’sCKK_ML_DSAbranch delegates toMLDSAUtil::setMLDSAPrivateKeyto decode the PKCS#8 and populateCKA_PARAMETER_SET,CKA_VALUE, andCKA_SEEDon the OSObject, mirroring how other asymmetric algorithms are handled.This matches the MLDSAUtil contract in the snippets and keeps ML‑DSA key transport behavior aligned with RSA/DSA/EC/EDDSA.
Also applies to: 7080-7093, 7771-7775
src/lib/crypto/OSSLMLDSA.cpp (9)
1-25: Includes and constants are appropriate.The include set covers all necessary OpenSSL headers and internal dependencies. The static hedge mode constants are correctly defined.
27-157: Sign function implementation is well-structured with comprehensive error handling.Good implementation with:
- Proper NULL checks for private key and OpenSSL key pointer
- Parameter validation for context length and pointer
- Proper resource cleanup on all error paths (both
sctxandsig_algfreed)- Unknown parameter set detection before OpenSSL calls
159-179: Multi-part signing stubs correctly reject unsupported operations.Appropriate behavior per ML-DSA specification which requires single-shot signing.
321-341: Multi-part verification stubs correctly reject unsupported operations.Consistent with the sign stubs and ML-DSA specification.
343-376: Encrypt/decrypt stubs and size queries are appropriate.Correctly rejects encryption operations (ML-DSA is signature-only) and returns valid size bounds.
378-442: Key generation implementation is correct with proper reference counting.Good implementation addressing the previous EVP_PKEY ownership concern:
EVP_PKEY_up_refis called before eachsetFromOSSL(lines 429, 431)- Original reference is released with
EVP_PKEY_free(line 439)- Error paths properly clean up context
This ensures each wrapper owns its reference and prevents UAF/double-free.
444-480: Key pair reconstruction follows standard pattern.Proper cleanup on deserialization failure.
482-526: Public and private key reconstruction implementations are correct.Consistent pattern with proper resource cleanup.
528-563: Factory methods and parameter reconstruction are correct.Standard factory pattern implementations consistent with the codebase.
dd80081 to
324066f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/lib/SoftHSM.cpp (1)
6884-6889: DES3_CBC wrap/unwarp key‑type check is logically always failingIn both
C_WrapKeyandC_UnwrapKeyyou have:if (pMechanism->mechanism == CKM_DES3_CBC && (wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 || wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT;(and the analogous check for
unwrapKey).Because a key type can never be both
CKK_DES2andCKK_DES3simultaneously, the!= ... || != ...condition is always true: for any key type, at least one side of the||is non‑zero. As a result, DES3_CBC wrapping/unwrapping is effectively always rejected.This is a straight logic bug; it should be “not DES2 and not DES3”.
Suggested fix (for both wrap and unwrap paths):
- if (pMechanism->mechanism == CKM_DES3_CBC && (wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 || - wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) + if (pMechanism->mechanism == CKM_DES3_CBC) { + CK_KEY_TYPE t = wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED); + if (t != CKK_DES2 && t != CKK_DES3) + return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; + }and similarly for
unwrapKey.Also applies to: 6930-6933, 7515-7527, 7569-7571
♻️ Duplicate comments (7)
src/lib/crypto/OSSLMLDSA.cpp (4)
291-305: Replace verify_message_init with verify_init_ex to match EVP_PKEY_verify.The code at lines 293 and 297 calls
EVP_PKEY_verify_message_initbut then invokesEVP_PKEY_verifyat line 306—the same forbidden API mix as insign(). The_message_initvariant requires paired calls toEVP_PKEY_verify_message_updateandEVP_PKEY_verify_message_final, not the monolithicEVP_PKEY_verify. UseEVP_PKEY_verify_init_ex:- int initRv; - if (param != NULL) { - initRv = EVP_PKEY_verify_message_init(vctx, sig_alg, params); - } - else - { - initRv = EVP_PKEY_verify_message_init(vctx, sig_alg, NULL); - } + int initRv = (param != NULL) + ? EVP_PKEY_verify_init_ex(vctx, sig_alg, params) + : EVP_PKEY_verify_init_ex(vctx, sig_alg, NULL);This matches the monolithic
EVP_PKEY_verifycall at line 306.Based on learnings.
198-204: Fix comment: says "private key" but checks public key.Line 198 incorrectly refers to "private key" while the code validates the public key type.
- // Check if the private key is the right type + // Check if the public key is the right type if (!publicKey->isOfType(OSSLMLDSAPublicKey::type))
216-217: Remove duplicate/incorrect comment.Line 217 incorrectly says "signature operation" in the verify function.
// Perform the verify operation - // Perform the signature operation size_t len = pk->getOutputLength();
124-137: Replace sign_message_init with sign_init_ex to match EVP_PKEY_sign.The code calls
EVP_PKEY_sign_message_init(lines 126, 130) but then invokesEVP_PKEY_sign(lines 139, 146)—a forbidden API mix. The_message_initvariant is designed for streaming operations and requires paired calls toEVP_PKEY_sign_message_updateandEVP_PKEY_sign_message_final, not the monolithicEVP_PKEY_sign. Since this codebase targets OpenSSL 3.0+ for ML-DSA, useEVP_PKEY_sign_init_exinstead:- int initRv; - if (param != NULL) { - initRv = EVP_PKEY_sign_message_init(sctx, sig_alg, params); - } - else - { - initRv = EVP_PKEY_sign_message_init(sctx, sig_alg, NULL); - } + int initRv = (param != NULL) + ? EVP_PKEY_sign_init_ex(sctx, sig_alg, params) + : EVP_PKEY_sign_init_ex(sctx, sig_alg, NULL);This matches the monolithic
EVP_PKEY_signcalls at lines 139 and 146.Based on learnings.
src/lib/SoftHSM.cpp (3)
842-845: CKA_PARAMETER_SET semantics are consistent between mech info and keygenMinor consistency note:
C_GetMechanismInforeports ML‑DSA key size bounds based on the backend;generateMLDSAenforcesCKA_PARAMETER_SETviaCKP_ML_DSA_*and stores it on both public and private objects. That aligns with the convention captured in the learnings: parameter sets are expressed via PKCS#11 constants and persisted on the OSObject, even though the runtime keys can infer the set from key length.No changes needed; just calling out that this is internally coherent.
Also applies to: 10167-10227
4205-4208: Uninitialized SIGN_ADDITIONAL_CONTEXT causes UB for ML‑DSA sign/verify when ulContextLen == 0
additionalContextis stack‑allocated and never zero‑initialized in bothAsymSignInitandAsymVerifyInit. WhenpMechanism->pParameteris non‑NULL butulContextLen == 0, you:
- Set
param = &additionalContextandparamLen = sizeof(SIGN_ADDITIONAL_CONTEXT).- Never write
contextLength/contextAsCharfor the zero‑context case.- Let
Session::setParametersdeep‑copy this struct and later pass it down to the ML‑DSA backend.This means
contextLength(and possibly the pointer) are indeterminate, so the deep copy and backend may read an uninitialized length and/or pointer, which is undefined behaviour and can lead to bogus allocations or crashes.This is the same issue that was previously flagged for this block and is still present. Initializing the struct and explicitly zeroing the context fields fixes it.
Suggested fix (applies symmetrically to both
AsymSignInitandAsymVerifyInit):-#ifdef WITH_ML_DSA - bool isMLDSA = false; - SIGN_ADDITIONAL_CONTEXT additionalContext; -#endif +#ifdef WITH_ML_DSA + bool isMLDSA = false; + // Ensure all fields (including context length/pointer) are well-defined + SIGN_ADDITIONAL_CONTEXT additionalContext = {}; +#endif @@ case CKM_ML_DSA: // in AsymSignInit - isMLDSA = true; + isMLDSA = true; if (pMechanism->pParameter != NULL_PTR) { @@ - if (ckSignAdditionalContext->ulContextLen > 0) - { - if (ckSignAdditionalContext->pContext == NULL) - { - ERROR_MSG("ML-DSA: Invalid parameters, pContext is NULL"); - return CKR_ARGUMENTS_BAD; - } - additionalContext.contextAsChar = (unsigned char*) ckSignAdditionalContext->pContext; - additionalContext.contextLength = ckSignAdditionalContext->ulContextLen; - } + // Default to “no context” + additionalContext.contextAsChar = NULL; + additionalContext.contextLength = 0; + if (ckSignAdditionalContext->ulContextLen > 0) + { + if (ckSignAdditionalContext->pContext == NULL) + { + ERROR_MSG("ML-DSA: Invalid parameters, pContext is NULL"); + return CKR_ARGUMENTS_BAD; + } + additionalContext.contextAsChar = + (unsigned char*) ckSignAdditionalContext->pContext; + additionalContext.contextLength = + ckSignAdditionalContext->ulContextLen; + } @@ - param = &additionalContext; - paramLen = sizeof(SIGN_ADDITIONAL_CONTEXT); + param = &additionalContext; + paramLen = sizeof(SIGN_ADDITIONAL_CONTEXT);Apply the same pattern in the
CKM_ML_DSAcase inAsymVerifyInit(zero‑init the struct and setcontextAsChar/contextLengthdefaults before theulContextLen > 0branch).Based on learnings about Session::setParameters deep‑copying ML‑DSA additional context.
Also applies to: 4476-4520, 4610-4629, 5282-5285, 5550-5595, 5683-5702
6567-6585: CBC wrap/unwap: non‑PAD modes still use blocksize==0 and empty IVFor
CKM_AES_CBCandCKM_DES3_CBCinWrapKeySym,blocksizeremains 0, yet later you:
- Resize
ivtoblocksize(so zero bytes) and memcpy 0 bytes frompMechanism->pParameter.- Call
encryptInit(..., SymMode::CBC, iv, false)with an empty IV.
C_WrapKeynow enforcesulParameterLen == 16/8for AES/DES3 CBC, but that IV isn’t actually consumed here. If the CBC backend expects an IV of block size, this will fail at runtime or silently use a default IV, which is not what PKCS#11 callers would expect.On the unwrap side, only the PAD variants are implemented in
UnwrapKeySym; non‑PAD CBC is not handled, so AES/DES3 CBC wrap is asymmetric.I’d recommend either:
- Treating non‑PAD CBC wrapping as unsupported (return
CKR_MECHANISM_INVALIDfor these mechs inWrapKeySym), or- Setting
blocksizeforCKM_AES_CBC/CKM_DES3_CBCand validatingulParameterLen == blocksizebefore using the IV, and implementing the matching non‑PAD cases inUnwrapKeySym.Also applies to: 6610-6617, 7155-7177, 7201-7208
🧹 Nitpick comments (2)
src/lib/crypto/OSSLMLDSAPrivateKey.h (1)
50-52: Consider deleting copy operations for rawEVP_PKEY*member.The class manages a raw
EVP_PKEY*pointer. Without explicit copy constructor/assignment deletion, default shallow copies would cause double-free. Following the Rule of Three/Five:private: // The internal OpenSSL representation EVP_PKEY* pkey; + + // Prevent shallow copies + OSSLMLDSAPrivateKey(const OSSLMLDSAPrivateKey&) = delete; + OSSLMLDSAPrivateKey& operator=(const OSSLMLDSAPrivateKey&) = delete; // Create the OpenSSL representation of the key void createOSSLKey();src/lib/SoftHSM.cpp (1)
10167-10424: generateMLDSA: parameter handling and object population are solid
- Reads
CKA_PARAMETER_SETasCK_ULONG, validatesulValueLen == sizeof(CK_ULONG), and requires it to be non‑zero, returningCKR_TEMPLATE_INCOMPLETEif missing.- Enforces the supported sets via
CKP_ML_DSA_44/65/87and returnsCKR_PARAMETER_SET_NOT_SUPPORTEDwith a clear log message for anything else, which matches the established policy for ML‑DSA parameter sets. Based on learnings.- Uses
MLDSAParameters+CryptoFactory::getAsymmetricAlgorithm(AsymAlgo::MLDSA)and frees the algorithm on failure paths.- Stores:
- Public:
CKA_PARAMETER_SETandCKA_VALUE(encrypted whenCKA_PRIVATEis true).- Private:
CKA_PARAMETER_SET,CKA_VALUE, andCKA_SEED(encrypted when private).- Error handling and cleanup (transactions,
destroyObject, handle reset, keypair/algorithm recycling) follow the existing RSA/EC/EDDSA patterns.Only a tiny nit (optional): you could cast via
CK_ULONG_PTRinstead of(CK_ULONG*)for slightly clearer intent, but that’s style, not correctness.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
.github/workflows/ci.yml(1 hunks)src/lib/SoftHSM.cpp(34 hunks)src/lib/crypto/AsymmetricAlgorithm.h(3 hunks)src/lib/crypto/MLDSAPrivateKey.cpp(1 hunks)src/lib/crypto/OSSLMLDSA.cpp(1 hunks)src/lib/crypto/OSSLMLDSA.h(1 hunks)src/lib/crypto/OSSLMLDSAKeyPair.h(1 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.h(1 hunks)src/lib/crypto/OSSLMLDSAPublicKey.h(1 hunks)src/lib/crypto/test/MLDSATests.cpp(1 hunks)src/lib/crypto/test/MLDSATests.h(1 hunks)src/lib/session_mgr/Session.cpp(1 hunks)src/lib/test/SignVerifyTests.cpp(2 hunks)src/lib/test/SignVerifyTests.h(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
- src/lib/crypto/test/MLDSATests.cpp
- src/lib/session_mgr/Session.cpp
- src/lib/crypto/OSSLMLDSAPublicKey.h
- src/lib/test/SignVerifyTests.cpp
- .github/workflows/ci.yml
- src/lib/test/SignVerifyTests.h
🧰 Additional context used
🧠 Learnings (12)
📓 Common learnings
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.370Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:5550-5596
Timestamp: 2025-10-27T16:44:57.865Z
Learning: SoftHSM ML‑DSA additional context: avoid transient malloc in SoftHSM::{AsymSignInit, AsymVerifyInit}; let Session::setParameters deep‑copy SIGN_ADDITIONAL_CONTEXT by allocating one buffer for struct + context bytes and fixing the stored pointer; Session::resetOp frees m_pParameters so both struct and context are released.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.693Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Learnt from: JoaoHenrique12
Repo: softhsm/SoftHSMv2 PR: 823
File: src/lib/SoftHSM.cpp:58-58
Timestamp: 2025-11-11T19:42:46.886Z
Learning: SoftHSM include policy: Algorithm key/parameter headers (e.g., SLHParameters, SLH*Key) are included unconditionally in SoftHSM.cpp/SoftHSM.h; feature gating is handled in mechanism tables and CryptoFactory (WITH_*). Avoid wrapping such includes in WITH_* guards.
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:3238-3266
Timestamp: 2025-10-13T09:42:31.270Z
Learning: In src/lib/SoftHSM.cpp, SoftHSM::AsymDecryptInit should use MechParamCheckRSAPKCSOAEP for CKM_RSA_PKCS_OAEP to keep OAEP parameter validation identical to AsymEncryptInit, and avoid redundant manual checks for pMechanism->pParameter and MGF allowlists.
📚 Learning: 2025-08-19T09:23:25.434Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Applied to files:
src/lib/SoftHSM.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/test/MLDSATests.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.h
📚 Learning: 2025-10-27T16:44:57.865Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:5550-5596
Timestamp: 2025-10-27T16:44:57.865Z
Learning: SoftHSM ML‑DSA additional context: avoid transient malloc in SoftHSM::{AsymSignInit, AsymVerifyInit}; let Session::setParameters deep‑copy SIGN_ADDITIONAL_CONTEXT by allocating one buffer for struct + context bytes and fixing the stored pointer; Session::resetOp frees m_pParameters so both struct and context are released.
Applied to files:
src/lib/SoftHSM.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/test/MLDSATests.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.h
📚 Learning: 2025-08-18T19:46:46.659Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Applied to files:
src/lib/SoftHSM.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/test/MLDSATests.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.h
📚 Learning: 2025-08-18T17:59:30.693Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.693Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Applied to files:
src/lib/SoftHSM.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/test/MLDSATests.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.h
📚 Learning: 2025-11-11T19:42:46.886Z
Learnt from: JoaoHenrique12
Repo: softhsm/SoftHSMv2 PR: 823
File: src/lib/SoftHSM.cpp:58-58
Timestamp: 2025-11-11T19:42:46.886Z
Learning: SoftHSM include policy: Algorithm key/parameter headers (e.g., SLHParameters, SLH*Key) are included unconditionally in SoftHSM.cpp/SoftHSM.h; feature gating is handled in mechanism tables and CryptoFactory (WITH_*). Avoid wrapping such includes in WITH_* guards.
Applied to files:
src/lib/SoftHSM.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.h
📚 Learning: 2025-09-11T16:54:00.370Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.370Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Applied to files:
src/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.h
📚 Learning: 2025-10-13T09:42:31.270Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:3238-3266
Timestamp: 2025-10-13T09:42:31.270Z
Learning: In src/lib/SoftHSM.cpp, SoftHSM::AsymDecryptInit should use MechParamCheckRSAPKCSOAEP for CKM_RSA_PKCS_OAEP to keep OAEP parameter validation identical to AsymEncryptInit, and avoid redundant manual checks for pMechanism->pParameter and MGF allowlists.
Applied to files:
src/lib/SoftHSM.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/test/MLDSATests.hsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.h
📚 Learning: 2025-10-13T09:43:45.885Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:13265-13282
Timestamp: 2025-10-13T09:43:45.885Z
Learning: SoftHSM OAEP policy: In SoftHSM::MechParamCheckRSAPKCSOAEP (src/lib/SoftHSM.cpp), enforce that the MGF1 variant must correspond to the selected hashAlg (e.g., SHA-256 -> CKG_MGF1_SHA256). Mismatches should return CKR_ARGUMENTS_BAD with "Hash and MGF don't match". This mirrors the existing PSS enforcement.
Applied to files:
src/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAKeyPair.h
📚 Learning: 2025-08-11T16:42:23.012Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 806
File: src/lib/test/p11test.cpp:81-84
Timestamp: 2025-08-11T16:42:23.012Z
Learning: In SoftHSM test files (like p11test.cpp and cryptotest.cpp), error handling for OSSL_PROVIDER_load() calls for "legacy" and "default" providers is intentionally omitted because these providers won't fail in practice and the test code is kept deliberately simple.
Applied to files:
src/lib/SoftHSM.cppsrc/lib/crypto/test/MLDSATests.h
📚 Learning: 2025-08-18T19:35:33.938Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/OSSLMLDSA.cpp:195-204
Timestamp: 2025-08-18T19:35:33.938Z
Learning: In OpenSSL, EVP_PKEY_verify_message does not exist. EVP_PKEY_verify_message_init is designed for streaming verification and should be paired with EVP_PKEY_CTX_set_signature, EVP_PKEY_verify_message_update, and EVP_PKEY_verify_message_final - not with EVP_PKEY_verify.
Applied to files:
src/lib/crypto/OSSLMLDSA.cpp
📚 Learning: 2025-08-18T17:54:37.645Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: m4/acx_openssl_mldsa.m4:10-35
Timestamp: 2025-08-18T17:54:37.645Z
Learning: For OpenSSL feature detection in autoconf macros, prefer functional tests (like EVP_PKEY_CTX_new_from_name) over version number checks, as the functional approach directly tests the actual capability and is more reliable across different OpenSSL builds where features may be backported or disabled.
Applied to files:
src/lib/crypto/OSSLMLDSA.cpp
🧬 Code graph analysis (4)
src/lib/SoftHSM.cpp (1)
src/lib/crypto/MLDSAUtil.cpp (6)
getMLDSAPrivateKey(11-41)getMLDSAPrivateKey(11-11)getMLDSAPublicKey(43-69)getMLDSAPublicKey(43-43)setMLDSAPrivateKey(71-111)setMLDSAPrivateKey(71-71)
src/lib/crypto/test/MLDSATests.h (1)
src/lib/crypto/test/MLDSATests.cpp (4)
setUp(26-34)setUp(26-26)tearDown(36-44)tearDown(36-36)
src/lib/crypto/OSSLMLDSA.h (5)
src/lib/crypto/AsymmetricAlgorithm.cpp (1)
AsymmetricAlgorithm(38-45)src/lib/crypto/OSSLMLDSA.cpp (24)
sign(27-157)sign(27-29)verify(182-319)verify(182-184)getMinKeySize(361-364)getMinKeySize(361-361)getMaxKeySize(366-369)getMaxKeySize(366-366)generateKeyPair(379-442)generateKeyPair(379-379)reconstructKeyPair(444-480)reconstructKeyPair(444-444)reconstructPublicKey(482-503)reconstructPublicKey(482-482)reconstructPrivateKey(505-526)reconstructPrivateKey(505-505)reconstructParameters(543-563)reconstructParameters(543-543)newPublicKey(528-531)newPublicKey(528-528)newPrivateKey(533-536)newPrivateKey(533-533)newParameters(538-541)newParameters(538-538)src/lib/crypto/AsymmetricKeyPair.h (1)
AsymmetricKeyPair(42-55)src/lib/crypto/PublicKey.h (1)
PublicKey(40-54)src/lib/crypto/PrivateKey.h (1)
PrivateKey(41-58)
src/lib/crypto/OSSLMLDSA.cpp (1)
src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(226-235)mldsaParameterSet2Name(226-226)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Windows (x86, openssl)
- GitHub Check: Windows (x64, openssl)
- GitHub Check: Windows (x64, botan)
- GitHub Check: macOS (botan)
- GitHub Check: macOS (openssl)
- GitHub Check: Linux with OpenSSL 3.5.4
- GitHub Check: Linux with OpenSSL 3.0
- GitHub Check: Linux with Botan
- GitHub Check: Linux with OpenSSL 1.1.1
🔇 Additional comments (14)
src/lib/crypto/OSSLMLDSAKeyPair.h (1)
16-39: LGTM!The class structure follows the existing pattern for key pair wrappers, with appropriate virtual accessors and private member composition.
src/lib/crypto/AsymmetricAlgorithm.h (2)
121-153: LGTM! Past review concerns addressed.The
SIGN_ADDITIONAL_CONTEXTstruct now:
- Deletes copy constructor and copy assignment (preventing shallow-copy issues)
- Uses
const unsigned char*forcontextAsChar(signaling non-ownership)- Provides sensible default initialization
The
Hedgeenum aligns with PKCS#11 v3.2 ML-DSA signing requirements.
56-57: LGTM!The
MLDSAenum value is appropriately added toAsymAlgo::Type, maintaining consistency with the existing algorithm enumeration pattern.src/lib/crypto/test/MLDSATests.h (1)
7-54: LGTM! Comprehensive test coverage.The test suite covers key generation, serialization, PKCS#8 handling, and all signing/verification variants (hedge preferred/required/deterministic, with/without context, context boundary conditions). The structure follows existing test patterns in the codebase.
src/lib/crypto/OSSLMLDSA.h (2)
22-24: Multi-part signing declared but noted as incomplete in PR discussion.Per PR comments from xipki, multi-part signing (
signInit/signUpdate/signFinal) doesn't work yet, and the author indicated this could be addressed in a follow-up PR. Consider adding a comment in the header or implementation to clarify the current limitation.
32-37: Encryption methods inherited from base class; MLDSA is signature-only.These methods are declared due to pure virtual requirements from
AsymmetricAlgorithm. The implementation should returnfalsesince ML-DSA doesn't support encryption. This is expected.src/lib/crypto/MLDSAPrivateKey.cpp (1)
1-98: LGTM!The implementation correctly follows the established pattern from
MLDSAPublicKey.cpp. Key aspects are well-handled:
- Parameter set inference from key material size (lines 28-39)
- Output length mapping (lines 42-53)
- Serialization concatenates seed + value (lines 76-80)
- Deserialization validates non-empty seed and value (lines 82-97)
The parameter set inference approach aligns with the project's design as documented in learnings.
Based on learnings.
src/lib/SoftHSM.cpp (7)
65-70: ML‑DSA headers are correctly gated behind WITH_ML_DSAIncluding
MLDSAParameters.h,MLDSAPublicKey.h,MLDSAPrivateKey.h, andMLDSAUtil.honly underWITH_ML_DSAkeeps non‑ML builds compiling cleanly where these headers may not exist. This is consistent with how P11MLDSA types are guarded later in the file.
149-152: P11MLDSA object wiring looks correct*The new
CKK_ML_DSAbranches innewP11Objectfor both public and private keys are properly wrapped in#ifdef WITH_ML_DSAand mirror the existing RSA/DSA/EC/EDDSA wiring. This keeps non‑ML builds safe while enabling PKCS#11 object instantiation for ML‑DSA keys.Also applies to: 171-173
842-845: Mechanism exposure and info for ML‑DSA are consistent with other asym algorithms
prepareSupportedMechanismsnow exportsCKM_ML_DSA_KEY_PAIR_GENandCKM_ML_DSAonly whenWITH_ML_DSAis defined, so config‑based filtering viaslots.mechanismsworks as for other mechs.C_GetMechanismInfo:
- Initializes
mldsaMinSize/mldsaMaxSizefromAsymAlgo::MLDSAand returnsCKR_GENERAL_ERRORif the backend isn’t available, matching the existing RSA/DSA/EDDSA pattern.- Reports
CKF_GENERATE_KEY_PAIRforCKM_ML_DSA_KEY_PAIR_GENandCKF_SIGN | CKF_VERIFYforCKM_ML_DSA, which fits the PKCS#11 usage for this mech.No changes needed here.
Also applies to: 950-952, 1051-1063, 1354-1364
1154-1154: Generic secret mech max size aligned with generateGeneric limits
CKM_GENERIC_SECRET_KEY_GENnow reportsulMaxKeySize = 0x8000000, which matches the upper bound enforced ingenerateGeneric(keyLen < 1 || keyLen > 0x8000000). This avoids advertising a size the generator would later reject.
5822-5822: Extra DEBUG on signature length mismatch is fineThe added
DEBUG_MSG("size: %lu, ulSignatureLen: %lu", ...)in bothAsymVerifyandAsymVerifyFinallogs only lengths, not key or signature material, and is emitted only on error. That’s useful diagnostics without leaking secrets.Also applies to: 6006-6006
6316-6320: ML‑DSA key‑pair generation is properly integrated into C_GenerateKeyPair
CKM_ML_DSA_KEY_PAIR_GENnow maps toCKK_ML_DSAin both public and private templates, and template consistency checks mirror the other key types.- The new branch under
#ifdef WITH_ML_DSAcallsgenerateMLDSAwith the right token/on‑token/privacy flags.- This keeps the public PKCS#11 surface uniform for ML‑DSA vs RSA/DSA/EC/EDDSA.
Looks good.
Also applies to: 6348-6349, 6373-6374, 6448-6457
7036-7038: EDDSA/ML‑DSA private‑key wrap/unwarp via PKCS#8 is consistent with other algorithms
- In
C_WrapKey, addingCKK_EC_EDWARDS→AsymAlgo::EDDSAandCKK_ML_DSA→AsymAlgo::MLDSA, and then usinggetEDPrivateKey/MLDSAUtil::getMLDSAPrivateKeybeforePKCS8Encode(), matches the existing RSA/EC/GOST pattern.- In
C_UnwrapKey, the newCKK_ML_DSAbranch callingMLDSAUtil::setMLDSAPrivateKeyis symmetric with the generation and wrap paths.No issues here.
Also applies to: 7046-7049, 7080-7093, 7090-7093, 7771-7774
324066f to
e5810ba
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (4)
src/lib/crypto/OSSLMLDSAPrivateKey.h (1)
60-60: Fix closing guard comment: copy-paste artifact.Line 60 references
OSSLECPRIVATEKEY_Hinstead ofOSSLMLDSAPRIVATEKEY_H.Apply this diff:
#endif // WITH_ML_DSA -#endif // !_SOFTHSM_V2_OSSLECPRIVATEKEY_H +#endif // !_SOFTHSM_V2_OSSLMLDSAPRIVATEKEY_Hsrc/lib/crypto/OSSLMLDSA.cpp (3)
198-204: Fix comment: says "private key" but checks public key.Minor copy-paste error in the comment.
- // Check if the private key is the right type + // Check if the public key is the right type if (!publicKey->isOfType(OSSLMLDSAPublicKey::type))
216-217: Remove duplicate/incorrect comment.Line 217 says "signature operation" but this is the verify function.
// Perform the verify operation - // Perform the signature operation size_t len = pk->getOutputLength();
291-298: Replace verify_message_init with verify_init_ex to match EVP_PKEY_verify.The code calls
EVP_PKEY_verify_message_initat lines 293/297 but then invokesEVP_PKEY_verifyat line 306—a forbidden API mix. Message init requires paired calls toEVP_PKEY_verify_message_updateandEVP_PKEY_verify_message_final, not the monolithicEVP_PKEY_verify. Since the codebase targets OpenSSL 3.0+ for ML-DSA, useEVP_PKEY_verify_init_ex:- int initRv; - if (param != NULL) { - initRv = EVP_PKEY_verify_message_init(vctx, sig_alg, params); - } - else - { - initRv = EVP_PKEY_verify_message_init(vctx, sig_alg, NULL); - } + int initRv = (param != NULL) + ? EVP_PKEY_verify_init_ex(vctx, sig_alg, params) + : EVP_PKEY_verify_init_ex(vctx, sig_alg, NULL);Note: The sign function (lines 124-131) has the identical issue—
EVP_PKEY_sign_message_initfollowed byEVP_PKEY_sign—and requires the same fix usingEVP_PKEY_sign_init_ex.Based on learnings, ML-DSA requires proper OpenSSL 3.x API pairing.
Also applies to: 306-307
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
.github/workflows/ci.yml(1 hunks)src/lib/SoftHSM.cpp(34 hunks)src/lib/crypto/AsymmetricAlgorithm.h(3 hunks)src/lib/crypto/MLDSAPrivateKey.cpp(1 hunks)src/lib/crypto/OSSLMLDSA.cpp(1 hunks)src/lib/crypto/OSSLMLDSA.h(1 hunks)src/lib/crypto/OSSLMLDSAKeyPair.h(1 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.h(1 hunks)src/lib/crypto/OSSLMLDSAPublicKey.h(1 hunks)src/lib/crypto/test/MLDSATests.cpp(1 hunks)src/lib/crypto/test/MLDSATests.h(1 hunks)src/lib/session_mgr/Session.cpp(1 hunks)src/lib/test/SignVerifyTests.cpp(2 hunks)src/lib/test/SignVerifyTests.h(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
- src/lib/crypto/test/MLDSATests.h
- .github/workflows/ci.yml
- src/lib/crypto/OSSLMLDSAPublicKey.h
- src/lib/session_mgr/Session.cpp
- src/lib/crypto/OSSLMLDSA.h
- src/lib/crypto/OSSLMLDSAKeyPair.h
🧰 Additional context used
🧠 Learnings (12)
📓 Common learnings
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.370Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:5550-5596
Timestamp: 2025-10-27T16:44:57.865Z
Learning: SoftHSM ML‑DSA additional context: avoid transient malloc in SoftHSM::{AsymSignInit, AsymVerifyInit}; let Session::setParameters deep‑copy SIGN_ADDITIONAL_CONTEXT by allocating one buffer for struct + context bytes and fixing the stored pointer; Session::resetOp frees m_pParameters so both struct and context are released.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Learnt from: JoaoHenrique12
Repo: softhsm/SoftHSMv2 PR: 823
File: src/lib/SoftHSM.cpp:58-58
Timestamp: 2025-11-11T19:42:46.886Z
Learning: SoftHSM include policy: Algorithm key/parameter headers (e.g., SLHParameters, SLH*Key) are included unconditionally in SoftHSM.cpp/SoftHSM.h; feature gating is handled in mechanism tables and CryptoFactory (WITH_*). Avoid wrapping such includes in WITH_* guards.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.693Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:13265-13282
Timestamp: 2025-10-13T09:43:45.885Z
Learning: SoftHSM OAEP policy: In SoftHSM::MechParamCheckRSAPKCSOAEP (src/lib/SoftHSM.cpp), enforce that the MGF1 variant must correspond to the selected hashAlg (e.g., SHA-256 -> CKG_MGF1_SHA256). Mismatches should return CKR_ARGUMENTS_BAD with "Hash and MGF don't match". This mirrors the existing PSS enforcement.
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:3238-3266
Timestamp: 2025-10-13T09:42:31.270Z
Learning: In src/lib/SoftHSM.cpp, SoftHSM::AsymDecryptInit should use MechParamCheckRSAPKCSOAEP for CKM_RSA_PKCS_OAEP to keep OAEP parameter validation identical to AsymEncryptInit, and avoid redundant manual checks for pMechanism->pParameter and MGF allowlists.
📚 Learning: 2025-08-19T09:23:25.434Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Applied to files:
src/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/test/SignVerifyTests.hsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-08-18T17:59:30.693Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.693Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Applied to files:
src/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/test/SignVerifyTests.hsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-08-18T19:46:46.659Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Applied to files:
src/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/test/SignVerifyTests.hsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-10-27T16:44:57.865Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:5550-5596
Timestamp: 2025-10-27T16:44:57.865Z
Learning: SoftHSM ML‑DSA additional context: avoid transient malloc in SoftHSM::{AsymSignInit, AsymVerifyInit}; let Session::setParameters deep‑copy SIGN_ADDITIONAL_CONTEXT by allocating one buffer for struct + context bytes and fixing the stored pointer; Session::resetOp frees m_pParameters so both struct and context are released.
Applied to files:
src/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/test/SignVerifyTests.hsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-09-11T16:54:00.370Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.370Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Applied to files:
src/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-10-13T09:42:31.270Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:3238-3266
Timestamp: 2025-10-13T09:42:31.270Z
Learning: In src/lib/SoftHSM.cpp, SoftHSM::AsymDecryptInit should use MechParamCheckRSAPKCSOAEP for CKM_RSA_PKCS_OAEP to keep OAEP parameter validation identical to AsymEncryptInit, and avoid redundant manual checks for pMechanism->pParameter and MGF allowlists.
Applied to files:
src/lib/crypto/test/MLDSATests.cppsrc/lib/test/SignVerifyTests.hsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-11-11T19:42:46.886Z
Learnt from: JoaoHenrique12
Repo: softhsm/SoftHSMv2 PR: 823
File: src/lib/SoftHSM.cpp:58-58
Timestamp: 2025-11-11T19:42:46.886Z
Learning: SoftHSM include policy: Algorithm key/parameter headers (e.g., SLHParameters, SLH*Key) are included unconditionally in SoftHSM.cpp/SoftHSM.h; feature gating is handled in mechanism tables and CryptoFactory (WITH_*). Avoid wrapping such includes in WITH_* guards.
Applied to files:
src/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-10-13T09:43:45.885Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:13265-13282
Timestamp: 2025-10-13T09:43:45.885Z
Learning: SoftHSM OAEP policy: In SoftHSM::MechParamCheckRSAPKCSOAEP (src/lib/SoftHSM.cpp), enforce that the MGF1 variant must correspond to the selected hashAlg (e.g., SHA-256 -> CKG_MGF1_SHA256). Mismatches should return CKR_ARGUMENTS_BAD with "Hash and MGF don't match". This mirrors the existing PSS enforcement.
Applied to files:
src/lib/test/SignVerifyTests.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/SoftHSM.cpp
📚 Learning: 2025-08-18T19:35:33.938Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/OSSLMLDSA.cpp:195-204
Timestamp: 2025-08-18T19:35:33.938Z
Learning: In OpenSSL, EVP_PKEY_verify_message does not exist. EVP_PKEY_verify_message_init is designed for streaming verification and should be paired with EVP_PKEY_CTX_set_signature, EVP_PKEY_verify_message_update, and EVP_PKEY_verify_message_final - not with EVP_PKEY_verify.
Applied to files:
src/lib/crypto/OSSLMLDSA.cpp
📚 Learning: 2025-08-18T17:54:37.645Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: m4/acx_openssl_mldsa.m4:10-35
Timestamp: 2025-08-18T17:54:37.645Z
Learning: For OpenSSL feature detection in autoconf macros, prefer functional tests (like EVP_PKEY_CTX_new_from_name) over version number checks, as the functional approach directly tests the actual capability and is more reliable across different OpenSSL builds where features may be backported or disabled.
Applied to files:
src/lib/crypto/OSSLMLDSA.cpp
📚 Learning: 2025-08-11T16:42:23.012Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 806
File: src/lib/test/p11test.cpp:81-84
Timestamp: 2025-08-11T16:42:23.012Z
Learning: In SoftHSM test files (like p11test.cpp and cryptotest.cpp), error handling for OSSL_PROVIDER_load() calls for "legacy" and "default" providers is intentionally omitted because these providers won't fail in practice and the test code is kept deliberately simple.
Applied to files:
src/lib/SoftHSM.cpp
🧬 Code graph analysis (5)
src/lib/crypto/MLDSAPrivateKey.cpp (2)
src/lib/crypto/MLDSAPublicKey.cpp (16)
isOfType(17-20)isOfType(17-17)getBitLength(22-25)getBitLength(22-22)getValue(55-58)getValue(55-55)getParameterSet(28-39)getParameterSet(28-28)getOutputLength(42-53)getOutputLength(42-42)setValue(60-63)setValue(60-60)serialise(66-69)serialise(66-66)deserialise(71-83)deserialise(71-71)src/lib/crypto/MLDSAParameters.cpp (6)
getParameterSet(22-25)getParameterSet(22-22)serialise(34-37)serialise(34-34)deserialise(39-50)deserialise(39-39)
src/lib/test/SignVerifyTests.cpp (2)
src/lib/SoftHSM.cpp (15)
generateMLDSA(10169-10424)generateMLDSA(10169-10180)C_GenerateKeyPair(6264-6459)C_GenerateKeyPair(6264-6274)data(2632-2632)data(2790-2790)data(3540-3540)data(3788-3788)data(3835-3835)data(4715-4715)data(5778-5778)signature(5788-5788)signature(5836-5836)signature(5975-5975)signature(6012-6012)src/lib/object_store/DB.cpp (1)
rv(234-249)
src/lib/crypto/OSSLMLDSA.cpp (1)
src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(226-235)mldsaParameterSet2Name(226-226)
src/lib/crypto/OSSLMLDSAPrivateKey.h (3)
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (19)
OSSLMLDSAPrivateKey(18-21)OSSLMLDSAPrivateKey(23-28)OSSLMLDSAPrivateKey(31-38)isOfType(72-75)isOfType(72-72)setValue(77-85)setValue(77-77)setSeed(87-95)setSeed(87-87)PKCS8Encode(98-117)PKCS8Encode(98-98)PKCS8Decode(120-133)PKCS8Decode(120-120)setFromOSSL(44-69)setFromOSSL(44-44)getOSSLKey(136-141)getOSSLKey(136-136)createOSSLKey(144-192)createOSSLKey(144-144)src/lib/crypto/MLDSAPrivateKey.h (1)
MLDSAPrivateKey(13-47)src/lib/crypto/MLDSAPrivateKey.cpp (6)
isOfType(17-20)isOfType(17-17)setValue(55-58)setValue(55-55)setSeed(65-68)setSeed(65-65)
src/lib/SoftHSM.cpp (1)
src/lib/crypto/MLDSAUtil.cpp (6)
getMLDSAPrivateKey(11-41)getMLDSAPrivateKey(11-11)getMLDSAPublicKey(43-69)getMLDSAPublicKey(43-43)setMLDSAPrivateKey(71-111)setMLDSAPrivateKey(71-71)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: macOS (botan)
- GitHub Check: Linux with OpenSSL 1.1.1
- GitHub Check: Windows (x86, openssl)
- GitHub Check: macOS (openssl)
- GitHub Check: Windows (x64, botan)
- GitHub Check: Windows (x64, openssl)
- GitHub Check: Linux with OpenSSL 3.5.4
- GitHub Check: Linux with OpenSSL 3.0
- GitHub Check: Linux with Botan
🔇 Additional comments (9)
src/lib/crypto/AsymmetricAlgorithm.h (1)
56-57: LGTM! ML-DSA integration is well-structured.The additions integrate cleanly:
- MLDSA enum values properly positioned after EDDSA in both AsymAlgo::Type and AsymMech::Type
- Hedge enum provides clear semantics for ML-DSA hedging modes
- SIGN_ADDITIONAL_CONTEXT struct correctly prevents shallow copies via deleted copy operations and uses const pointer for read-only context data
Also applies to: 96-97, 121-153
src/lib/test/SignVerifyTests.cpp (1)
231-272: LGTM! ML-DSA test integration is comprehensive.The test implementation:
- Properly generates ML-DSA keys for all parameter sets (ML_DSA_44, ML_DSA_65, ML_DSA_87)
- Tests across all key storage modes (session/token, public/private)
- Exercises all hedge/deterministic context variants with and without additional context data
- Uses stack-allocated context buffer avoiding previous const-casting issues
- Increased signature buffer to 64KB to accommodate larger ML-DSA signatures
Also applies to: 849-938
src/lib/test/SignVerifyTests.h (1)
52-54: LGTM! ML-DSA test declarations are properly structured.The header cleanly integrates ML-DSA test support:
- Parameterized test registration for all three ML-DSA parameter sets
- Proper WITH_ML_DSA guards throughout
- Consistent with existing EDDSA test patterns
Also applies to: 66-68, 78-80
src/lib/crypto/MLDSAPrivateKey.cpp (1)
28-39: LGTM! Parameter set inference and serialization are correctly implemented.The implementation:
- Properly infers parameter set from private key material length (per learnings about runtime inference)
- Maps to correct signature lengths for each variant (44/65/87)
- Validates both seed and value are non-empty during deserialization
- Parallels the MLDSAPublicKey implementation structure
Based on learnings, parameter set inference from key material length is the intended design pattern for ML-DSA.
Also applies to: 42-53, 82-97
src/lib/SoftHSM.cpp (5)
65-70: ML‑DSA includes and P11 object wiring look consistent and properly gatedThe new ML‑DSA header includes and the
CKK_ML_DSAbranches innewP11Objectmirror the pattern used for other algorithms and are correctly wrapped inWITH_ML_DSA, so non‑ML builds won’t see undefined symbols. No issues here.Also applies to: 149-152, 171-173
842-845: Mechanism table and C_GetMechanismInfo integration for ML‑DSA is soundAdding
CKM_ML_DSA_KEY_PAIR_GEN/CKM_ML_DSAtoprepareSupportedMechanismsand wiring them inC_GetMechanismInfoviaAsymAlgo::MLDSA(withmldsaMinSize/mldsaMaxSizecached like RSA/DSA/ECDSA) lines up cleanly with the existing mechanism plumbing and is safely guarded byWITH_ML_DSA.Also applies to: 950-952, 1051-1063, 1355-1364
6317-6320: ML‑DSA key‑pair generation path is coherent with existing generate helpers*The additions in
C_GenerateKeyPairforCKM_ML_DSA_KEY_PAIR_GEN→CKK_ML_DSAand the newgenerateMLDSAimplementation look consistent with the RSA/DSA/EC/EDDSA patterns:
- Public/private templates are validated to be
CKK_ML_DSA(mirrors other key types).generateMLDSA:
- Reads
CKA_PARAMETER_SETasCK_ULONG, validatesulValueLen, and enforces that it is non‑zero.- Restricts to
CKP_ML_DSA_44,CKP_ML_DSA_65,CKP_ML_DSA_87, returningCKR_PARAMETER_SET_NOT_SUPPORTEDand logging “Unsupported parameter set: %lu” for others, matching the recorded project preference.- Uses
MLDSAParameters::setParameterSet(paramSet)and routes throughCryptoFactory::getAsymmetricAlgorithm(AsymAlgo::MLDSA)to generate the pair.- Populates OSObjects with
CKA_PARAMETER_SET,CKA_VALUE, andCKA_SEED(private) while handling encryption based onCKA_PRIVATE, and wiresCKA_KEY_GEN_MECHANISMandCKA_ALWAYS_SENSITIVE/CKA_NEVER_EXTRACTABLEexactly like the other generate* helpers.Resource management (
recycleKeyPair/recycleAsymmetricAlgorithmand rollback of partially created objects onrv != CKR_OK) also mirrors the existing code and looks correct.Also applies to: 6348-6349, 6373-6374, 6448-6457, 10167-10424
7036-7048: ML‑DSA support in wrap/unwrap (PKCS#8 via MLDSAUtil) is wired correctlyThe new ML‑DSA branches in
C_WrapKeyandC_UnwrapKey:
- Map
CKK_ML_DSAtoAsymAlgo::MLDSAin the private‑key wrapping path and useMLDSAUtil::getMLDSAPrivateKeybeforePKCS8Encode(), in line with how RSA/DSA/EC/EDDSA are handled.- In unwrapping, branch on
keyType == CKK_ML_DSAand callMLDSAUtil::setMLDSAPrivateKey(...), again mirroring the existingset*PrivateKeyhelpers for other algorithms.- Are guarded by
WITH_ML_DSAso non‑ML builds won’t reference ML‑DSA types.This keeps wrap/unwrap semantics for ML‑DSA aligned with the rest of the asymmetric key types.
Also applies to: 7080-7092, 7771-7775
5822-5822: Extra DEBUG logging on signature length mismatch is helpful and safeThe added
DEBUG_MSG("size: %lu, ulSignatureLen: %lu", ...)lines inAsymVerifyandAsymVerifyFinallog only lengths (no secret material) onCKR_SIGNATURE_LEN_RANGE. That’s consistent with existing diagnostics and should aid troubleshooting without leaking sensitive data.Also applies to: 6006-6006
Co-authored-by: kalvdans <[email protected]>
Fixed compilation for mldsaAlgNameFromParameterSet as a constant
08ecff4 to
e9be1d7
Compare
Done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
♻️ Duplicate comments (8)
src/lib/crypto/test/MLDSATests.cpp (1)
1-45: Fix headers:fflush/stdoutandstd::stringneed proper includes.
Relying on transitive includes is brittle and can break CI with different standard library/compile flags.@@ -#include <stdlib.h> +#include <cstdio> // fflush, stdout +#include <cstdlib> // (if you actually need std::malloc/free later; otherwise omit) +#include <string>If
fflush(stdout);isn’t required, I’d remove it and drop<cstdio>entirely.src/lib/crypto/OSSLMLDSAKeyPair.cpp (1)
12-25: Make setters takeconstreferences (no mutation of inputs).
Line 13-25: both setters can beconst OSSLMLDSA{Public,Private}Key&to improve API correctness.-void OSSLMLDSAKeyPair::setPublicKey(OSSLMLDSAPublicKey& publicKey) +void OSSLMLDSAKeyPair::setPublicKey(const OSSLMLDSAPublicKey& publicKey) { // Copy only the public material; avoid sharing OpenSSL handles pubKey.setValue(publicKey.getValue()); } -void OSSLMLDSAKeyPair::setPrivateKey(OSSLMLDSAPrivateKey& privateKey) +void OSSLMLDSAKeyPair::setPrivateKey(const OSSLMLDSAPrivateKey& privateKey) { // Copy only the raw material; avoid sharing OpenSSL handles privKey.setSeed(privateKey.getSeed()); privKey.setValue(privateKey.getValue()); }src/lib/crypto/OSSLMLDSAPublicKey.cpp (1)
112-146: HardencreateOSSLKey()for empty/unknown parameter-set + avoid writing into memberpkeyon failure
This was previously raised and explicitly skipped; re-surfacing only because it still looks like a sharp edge for callers that haven’t setvalueyet.void OSSLMLDSAPublicKey::createOSSLKey() { if (pkey != NULL) return; ByteString localValue = getValue(); + if (localValue.size() == 0) + { + ERROR_MSG("Empty ML-DSA public key value; cannot create EVP_PKEY"); + return; + } const char* name = OSSL::mldsaParameterSet2Name(getParameterSet()); + if (name == NULL) + { + ERROR_MSG("Unknown ML-DSA parameter set (value length: %zu)", localValue.size()); + return; + } int selection = 0; EVP_PKEY_CTX *ctx = NULL; OSSL_PARAM params[3], *p = params; @@ - rv = EVP_PKEY_fromdata(ctx, &pkey, selection, params); + EVP_PKEY* tmp = NULL; + rv = EVP_PKEY_fromdata(ctx, &tmp, selection, params); if (!rv) { ERROR_MSG("Could not EVP_PKEY_fromdata:%d", rv); EVP_PKEY_CTX_free(ctx); return; } + pkey = tmp;src/lib/crypto/OSSLMLDSAPrivateKey.cpp (1)
71-75: (Optional)isOfType()doesn’t acknowledge base MLDSAPrivateKey type
Only mentioning because it can affect polymorphic type checks; I saw this was previously discussed and intentionally ignored.src/lib/crypto/OSSLMLDSAPrivateKey.h (1)
17-61: Delete copy operations (double-free risk) + fix trailing#endifcomment typoclass OSSLMLDSAPrivateKey : public MLDSAPrivateKey { public: // Constructors OSSLMLDSAPrivateKey(); OSSLMLDSAPrivateKey(const EVP_PKEY* inMLDSAKEY); + + // Non-copyable (owns EVP_PKEY*) + OSSLMLDSAPrivateKey(const OSSLMLDSAPrivateKey&) = delete; + OSSLMLDSAPrivateKey& operator=(const OSSLMLDSAPrivateKey&) = delete; + + // Movable + OSSLMLDSAPrivateKey(OSSLMLDSAPrivateKey&& other) noexcept; + OSSLMLDSAPrivateKey& operator=(OSSLMLDSAPrivateKey&& other) noexcept; @@ #endif // WITH_ML_DSA -#endif // !_SOFTHSM_V2_OSSLECPRIVATEKEY_H +#endif // !_SOFTHSM_V2_OSSLMLDSAPRIVATEKEY_Hsrc/lib/SoftHSM.cpp (1)
6573-6592: CBC wrap bug: blocksize stays 0 for CKM_AES_CBC / CKM_DES3_CBC (empty IV)This is the same issue previously flagged:
blocksizeis never set for non-PAD CBC cases, yet it’s used to size/copy the IV. That makesencryptInit(..., iv, ...)receive an empty IV.case CKM_AES_CBC: algo = SymAlgo::AES; + blocksize = 16; break; @@ case CKM_DES3_CBC: algo = SymAlgo::DES3; + blocksize = 8; break; @@ case CKM_AES_CBC: case CKM_AES_CBC_PAD: case CKM_DES3_CBC: case CKM_DES3_CBC_PAD: + if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != blocksize) + return CKR_ARGUMENTS_BAD; iv.resize(blocksize); memcpy(&iv[0], pMechanism->pParameter, blocksize);Also applies to: 6616-6623
src/lib/crypto/MLDSAParameters.h (1)
42-44: EnsureCKP_ML_DSA_*are always defined for includers of this header.
This is the same compile-risk previously flagged: if a TU includesMLDSAParameters.hwithout the PKCS#11 header that definesCKP_ML_DSA_*, it can break builds. (I understand the preference to keep the PKCS#11 constants for clarity — based on learnings.)#!/bin/bash # Verify CKP_ML_DSA_* definitions and include path/ordering rg -n --hidden -S 'CKP_ML_DSA_(44|65|87)\b' . rg -n --hidden -S 'define\s+CKP_ML_DSA_(44|65|87)\b' . rg -n --hidden -S 'MLDSAParameters\.h' -C2 .src/lib/crypto/OSSLMLDSA.cpp (1)
290-317: Correctness: don’t mixEVP_PKEY_verify_message_initwithEVP_PKEY_verify.
This was previously flagged and appears to still be present here. UseEVP_PKEY_verify_init_ex(...)withEVP_PKEY_verify(...), or fully switch to the message API (set_signature + update + final).- if (param != NULL) { - initRv = EVP_PKEY_verify_message_init(vctx, sig_alg, params); - } - else - { - initRv = EVP_PKEY_verify_message_init(vctx, sig_alg, NULL); - } - - if (!initRv) { + initRv = (param != NULL) + ? EVP_PKEY_verify_init_ex(vctx, sig_alg, params) + : EVP_PKEY_verify_init_ex(vctx, sig_alg, NULL); + if (initRv <= 0) { ERROR_MSG("ML-DSA verify init failed (0x%08X)", ERR_get_error()); EVP_PKEY_CTX_free(vctx); EVP_SIGNATURE_free(sig_alg); return false; } @@ - if (verifyRV != 1) + if (verifyRV != 1) { - if (verifyRV != 0) - { - ERROR_MSG("ML-DSA verify error (0x%08X)", ERR_get_error()); - } + if (verifyRV == 0) { + ERROR_MSG("ML-DSA signature invalid"); + } else { + ERROR_MSG("ML-DSA verify error (0x%08X)", ERR_get_error()); + } return false; }OpenSSL 3.5 manpage: EVP_PKEY_verify_message_init correct call sequence, and whether EVP_PKEY_verify_init_ex should be used with EVP_PKEY_verify for one-shot verification.
🧹 Nitpick comments (15)
m4/acx_openssl_mldsa.m4 (1)
10-35: Free the EVP_PKEY_CTX to avoid resource leak in test.The test program creates an EVP_PKEY_CTX but never releases it. While this is configuration-time test code, it should model proper resource management.
Apply this diff to add the cleanup:
int main() { EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name(NULL, "ML-DSA-44", NULL); if (pctx == NULL) return 1; + EVP_PKEY_CTX_free(pctx); return 0; }src/lib/SoftHSM.h (1)
55-58: Consider removing WITH_ML_DSA guards from header includes.Based on learnings, algorithm key/parameter headers are typically included unconditionally in SoftHSM.h, with feature gating handled at runtime in mechanism tables and CryptoFactory. Lines 43-54 show that RSA, DSA, EC, ED, DH, and GOST headers are all included unconditionally, but MLDSA headers are guarded.
For consistency with the established pattern, consider removing the WITH_ML_DSA guards here (though keep them around the generateMLDSA declaration and implementation).
Based on learnings.
src/lib/test/SignVerifyTests.cpp (2)
274-302: Consider avoiding a 64KiB on-stack signature buffer in signVerifySingle.
If these tests ever run under constrained stack sizes, astd::vector<CK_BYTE>(or heap allocation) would be safer while keeping behavior identical.
849-937: Good ML-DSA sign/verify coverage across all hedge/context combinations.
This exercises CK_SIGN_ADDITIONAL_CONTEXT across (preferred/required/deterministic) × (no context/with context) and across key visibility/location permutations—nice regression protection.
One follow-up worth considering: add explicit “multipart is unsupported/expected-failure” tests for ML-DSA (given known multipart reports) to lock in intended behavior.src/lib/P11Attributes.h (1)
1282-1298: MakeP11AttrSeedsize explicitly variable (defensive against ctor defaults).
Line 1282-1298:P11AttrSeeddoesn’t setsize. IfP11Attribute’s ctor ever stops initializingsizeto the “variable” sentinel, this becomes UB.class P11AttrSeed : public P11Attribute { public: // Constructor - P11AttrSeed(OSObject* inobject) : P11Attribute(inobject) { type = CKA_SEED; checks = ck4|ck6|ck7; } + P11AttrSeed(OSObject* inobject) : P11Attribute(inobject) { type = CKA_SEED; size = (CK_ULONG)-1; checks = ck4|ck6|ck7; }src/lib/crypto/OSSLMLDSAPublicKey.h (1)
20-25: Document thatOSSLMLDSAPublicKey(const EVP_PKEY*)andsetFromOSSL()borrow the input key and extract bytes only.The constructor and
setFromOSSL()method takeconst EVP_PKEY*parameters (lines 22 and 44) but currently lack explicit documentation clarifying ownership semantics. Although the implementation correctly borrows the input (extracting bytes viaEVP_PKEY_get_octet_string_param()without storing or incrementing refcount), callers cannot know this from the signature alone. Add a comment clarifying that these methods borrow the inputEVP_PKEY*and do not take ownership, allowing callers to safely manage the input's lifecycle.src/lib/crypto/OSSLMLDSAKeyPair.h (1)
7-39: Preferconst&setters and addoverrideon virtuals
This header is clean and the WITH_ML_DSA/config.h ordering looks correct; the main polish is API ergonomics/safety.class OSSLMLDSAKeyPair : public AsymmetricKeyPair { public: // Set the public key - void setPublicKey(OSSLMLDSAPublicKey& publicKey); + void setPublicKey(const OSSLMLDSAPublicKey& publicKey); // Set the private key - void setPrivateKey(OSSLMLDSAPrivateKey& privateKey); + void setPrivateKey(const OSSLMLDSAPrivateKey& privateKey); // Return the public key - virtual PublicKey* getPublicKey(); - virtual const PublicKey* getConstPublicKey() const; + PublicKey* getPublicKey() override; + const PublicKey* getConstPublicKey() const override; // Return the private key - virtual PrivateKey* getPrivateKey(); - virtual const PrivateKey* getConstPrivateKey() const; + PrivateKey* getPrivateKey() override; + const PrivateKey* getConstPrivateKey() const override;src/lib/SoftHSM.cpp (5)
65-70: Consider making ML-DSA includes unconditional (align with include policy)You’re gating MLDSA headers with
#ifdef WITH_ML_DSA. Repo guidance prefers unconditional algorithm header includes and feature-gating via mechanism tables / CryptoFactory instead. Based on learnings.
4202-4208: ML-DSA CK_SIGN_ADDITIONAL_CONTEXT parsing: good, but don’t silently accept unknown hedgeVariantYou now (a) zero-init
SIGN_ADDITIONAL_CONTEXT, (b) set context fields even whenulContextLen == 0, and (c) validateulContextLen <= 255—all good (and matches the “Session deep-copy owns context” approach). Based on learnings.Suggestion: in both SignInit and VerifyInit, treat unknown
hedgeVariantasCKR_ARGUMENTS_BADrather than defaulting toHEDGE_PREFERRED, so bad inputs don’t get silently accepted.Also applies to: 4476-4526, 4612-4633, 5282-5288, 5553-5602, 5688-5709
5828-5829: Extra debug on signature length mismatch is fine (consider log level/noise)
Logging(expected, provided)sizes can help diagnose caller errors; just ensure this doesn’t become too noisy in common failure paths.Also applies to: 6012-6013
6322-6326: Guard the ML-DSA-specific template consistency checks with WITH_ML_DSAThe
CKM_ML_DSA_KEY_PAIR_GENhandling is gated in the mechanism switch, but the subsequent template consistency checks for ML-DSA are unconditional. It’s safer (and more consistent) to wrap those checks in#ifdef WITH_ML_DSAtoo.Also applies to: 6354-6355, 6379-6380, 6454-6463
7160-7184: UnwrapKeySym: add local parameter validation before memcpy (defensive hardening)
memcpy(..., pMechanism->pParameter, blocksize)assumes the caller already validated pointer/length. Given this is an internal helper, it’s still worth guarding against accidental misuse (NULL/short IV) to avoid UB.Also applies to: 7208-7243
src/lib/crypto/MLDSAPrivateKey.h (1)
13-47: Preferoverrideon all overridden virtuals (type-safety + refactor safety).
This header overridesPrivateKeymethods (and adds more); marking themoverrideavoids silent signature mismatches.- virtual bool isOfType(const char* inType); + bool isOfType(const char* inType) override; - virtual unsigned long getBitLength() const; + unsigned long getBitLength() const override; - virtual unsigned long getOutputLength() const; + unsigned long getOutputLength() const override; - virtual ByteString serialise() const; - virtual bool deserialise(ByteString& serialised); + ByteString serialise() const override; + bool deserialise(ByteString& serialised) override;src/lib/crypto/MLDSAParameters.h (1)
23-35: Consider validating parameter sets insetParameterSet()/deserialise().
Today any value can be stored inparameterSet; failures then occur later (e.g., name lookup returning NULL). Centralizing validation would tighten invariants.Also applies to: 68-71
src/lib/crypto/OSSLMLDSA.cpp (1)
62-71: Minor: avoid the earlysignature.resize()+memset()since you immediately re-query and resize.
This is just extra work and can be removed once you rely on the size-queryEVP_PKEY_sign(..., NULL, &len, ...).Also applies to: 138-151
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (46)
.github/workflows/ci.yml(1 hunks)CMAKE-NOTES.md(1 hunks)CMAKE-WIN-NOTES.md(1 hunks)CMakeLists.txt(1 hunks)README.md(1 hunks)config.h.in.cmake(1 hunks)m4/acx_crypto_backend.m4(4 hunks)m4/acx_openssl_mldsa.m4(1 hunks)src/bin/dump/tables.h(3 hunks)src/lib/P11Attributes.cpp(2 hunks)src/lib/P11Attributes.h(2 hunks)src/lib/P11Objects.cpp(2 hunks)src/lib/P11Objects.h(2 hunks)src/lib/SoftHSM.cpp(34 hunks)src/lib/SoftHSM.h(2 hunks)src/lib/crypto/AsymmetricAlgorithm.h(3 hunks)src/lib/crypto/CMakeLists.txt(2 hunks)src/lib/crypto/MLDSAParameters.cpp(1 hunks)src/lib/crypto/MLDSAParameters.h(1 hunks)src/lib/crypto/MLDSAPrivateKey.cpp(1 hunks)src/lib/crypto/MLDSAPrivateKey.h(1 hunks)src/lib/crypto/MLDSAPublicKey.cpp(1 hunks)src/lib/crypto/MLDSAPublicKey.h(1 hunks)src/lib/crypto/MLDSAUtil.cpp(1 hunks)src/lib/crypto/MLDSAUtil.h(1 hunks)src/lib/crypto/Makefile.am(3 hunks)src/lib/crypto/OSSLComp.cpp(1 hunks)src/lib/crypto/OSSLCryptoFactory.cpp(2 hunks)src/lib/crypto/OSSLMLDSA.cpp(1 hunks)src/lib/crypto/OSSLMLDSA.h(1 hunks)src/lib/crypto/OSSLMLDSAKeyPair.cpp(1 hunks)src/lib/crypto/OSSLMLDSAKeyPair.h(1 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.cpp(1 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.h(1 hunks)src/lib/crypto/OSSLMLDSAPublicKey.cpp(1 hunks)src/lib/crypto/OSSLMLDSAPublicKey.h(1 hunks)src/lib/crypto/OSSLUtil.cpp(2 hunks)src/lib/crypto/OSSLUtil.h(1 hunks)src/lib/crypto/test/CMakeLists.txt(1 hunks)src/lib/crypto/test/MLDSATests.cpp(1 hunks)src/lib/crypto/test/MLDSATests.h(1 hunks)src/lib/crypto/test/Makefile.am(1 hunks)src/lib/object_store/DBObject.cpp(1 hunks)src/lib/session_mgr/Session.cpp(1 hunks)src/lib/test/SignVerifyTests.cpp(2 hunks)src/lib/test/SignVerifyTests.h(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (19)
- .github/workflows/ci.yml
- CMakeLists.txt
- config.h.in.cmake
- src/lib/crypto/OSSLComp.cpp
- src/lib/crypto/test/CMakeLists.txt
- src/lib/crypto/OSSLUtil.cpp
- src/lib/crypto/test/Makefile.am
- src/lib/crypto/OSSLCryptoFactory.cpp
- src/lib/crypto/MLDSAPublicKey.cpp
- src/lib/session_mgr/Session.cpp
- src/lib/crypto/Makefile.am
- m4/acx_crypto_backend.m4
- src/lib/crypto/MLDSAParameters.cpp
- src/lib/object_store/DBObject.cpp
- src/lib/crypto/OSSLMLDSA.h
- src/lib/crypto/MLDSAPrivateKey.cpp
- src/lib/crypto/MLDSAUtil.cpp
- src/lib/test/SignVerifyTests.h
- src/lib/P11Attributes.cpp
🧰 Additional context used
🧠 Learnings (12)
📓 Common learnings
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.370Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:5550-5596
Timestamp: 2025-10-27T16:44:57.865Z
Learning: SoftHSM ML‑DSA additional context: avoid transient malloc in SoftHSM::{AsymSignInit, AsymVerifyInit}; let Session::setParameters deep‑copy SIGN_ADDITIONAL_CONTEXT by allocating one buffer for struct + context bytes and fixing the stored pointer; Session::resetOp frees m_pParameters so both struct and context are released.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.693Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Learnt from: JoaoHenrique12
Repo: softhsm/SoftHSMv2 PR: 823
File: src/lib/SoftHSM.cpp:58-58
Timestamp: 2025-11-11T19:42:46.886Z
Learning: SoftHSM include policy: Algorithm key/parameter headers (e.g., SLHParameters, SLH*Key) are included unconditionally in SoftHSM.cpp/SoftHSM.h; feature gating is handled in mechanism tables and CryptoFactory (WITH_*). Avoid wrapping such includes in WITH_* guards.
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:13265-13282
Timestamp: 2025-10-13T09:43:45.885Z
Learning: SoftHSM OAEP policy: In SoftHSM::MechParamCheckRSAPKCSOAEP (src/lib/SoftHSM.cpp), enforce that the MGF1 variant must correspond to the selected hashAlg (e.g., SHA-256 -> CKG_MGF1_SHA256). Mismatches should return CKR_ARGUMENTS_BAD with "Hash and MGF don't match". This mirrors the existing PSS enforcement.
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:3238-3266
Timestamp: 2025-10-13T09:42:31.270Z
Learning: In src/lib/SoftHSM.cpp, SoftHSM::AsymDecryptInit should use MechParamCheckRSAPKCSOAEP for CKM_RSA_PKCS_OAEP to keep OAEP parameter validation identical to AsymEncryptInit, and avoid redundant manual checks for pMechanism->pParameter and MGF allowlists.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: m4/acx_openssl_mldsa.m4:10-35
Timestamp: 2025-08-18T17:54:37.645Z
Learning: For OpenSSL feature detection in autoconf macros, prefer functional tests (like EVP_PKEY_CTX_new_from_name) over version number checks, as the functional approach directly tests the actual capability and is more reliable across different OpenSSL builds where features may be backported or disabled.
📚 Learning: 2025-08-18T17:59:30.693Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.693Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Applied to files:
src/bin/dump/tables.hm4/acx_openssl_mldsa.m4src/lib/crypto/CMakeLists.txtsrc/lib/crypto/test/MLDSATests.hsrc/lib/crypto/MLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/SoftHSM.hsrc/lib/P11Objects.cppsrc/lib/P11Objects.hsrc/lib/crypto/OSSLUtil.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/MLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/MLDSAUtil.hsrc/lib/crypto/OSSLMLDSAKeyPair.cppsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/SoftHSM.cppsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/P11Attributes.hCMAKE-NOTES.mdCMAKE-WIN-NOTES.md
📚 Learning: 2025-08-19T09:23:25.434Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Applied to files:
src/bin/dump/tables.hm4/acx_openssl_mldsa.m4src/lib/crypto/CMakeLists.txtsrc/lib/crypto/test/MLDSATests.hsrc/lib/crypto/MLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/SoftHSM.hsrc/lib/P11Objects.cppsrc/lib/P11Objects.hsrc/lib/crypto/OSSLUtil.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/MLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/MLDSAUtil.hsrc/lib/crypto/OSSLMLDSAKeyPair.cppsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/SoftHSM.cppsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/OSSLMLDSA.cppCMAKE-WIN-NOTES.mdREADME.md
📚 Learning: 2025-08-18T19:46:46.659Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Applied to files:
src/bin/dump/tables.hm4/acx_openssl_mldsa.m4src/lib/crypto/CMakeLists.txtsrc/lib/crypto/test/MLDSATests.hsrc/lib/crypto/MLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/SoftHSM.hsrc/lib/crypto/OSSLUtil.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/MLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/MLDSAUtil.hsrc/lib/crypto/OSSLMLDSAKeyPair.cppsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/SoftHSM.cppsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/P11Attributes.h
📚 Learning: 2025-08-18T17:54:37.645Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: m4/acx_openssl_mldsa.m4:10-35
Timestamp: 2025-08-18T17:54:37.645Z
Learning: For OpenSSL feature detection in autoconf macros, prefer functional tests (like EVP_PKEY_CTX_new_from_name) over version number checks, as the functional approach directly tests the actual capability and is more reliable across different OpenSSL builds where features may be backported or disabled.
Applied to files:
m4/acx_openssl_mldsa.m4src/lib/crypto/OSSLMLDSA.cpp
📚 Learning: 2025-10-27T16:44:57.865Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:5550-5596
Timestamp: 2025-10-27T16:44:57.865Z
Learning: SoftHSM ML‑DSA additional context: avoid transient malloc in SoftHSM::{AsymSignInit, AsymVerifyInit}; let Session::setParameters deep‑copy SIGN_ADDITIONAL_CONTEXT by allocating one buffer for struct + context bytes and fixing the stored pointer; Session::resetOp frees m_pParameters so both struct and context are released.
Applied to files:
m4/acx_openssl_mldsa.m4src/lib/crypto/CMakeLists.txtsrc/lib/crypto/test/MLDSATests.hsrc/lib/crypto/MLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/SoftHSM.hsrc/lib/P11Objects.cppsrc/lib/P11Objects.hsrc/lib/crypto/OSSLUtil.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/MLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/MLDSAUtil.hsrc/lib/crypto/OSSLMLDSAKeyPair.cppsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/SoftHSM.cppsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/OSSLMLDSA.cpp
📚 Learning: 2025-10-13T09:42:31.270Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:3238-3266
Timestamp: 2025-10-13T09:42:31.270Z
Learning: In src/lib/SoftHSM.cpp, SoftHSM::AsymDecryptInit should use MechParamCheckRSAPKCSOAEP for CKM_RSA_PKCS_OAEP to keep OAEP parameter validation identical to AsymEncryptInit, and avoid redundant manual checks for pMechanism->pParameter and MGF allowlists.
Applied to files:
m4/acx_openssl_mldsa.m4src/lib/crypto/CMakeLists.txtsrc/lib/crypto/test/MLDSATests.hsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/SoftHSM.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/MLDSAUtil.hsrc/lib/crypto/OSSLMLDSAKeyPair.cppsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/SoftHSM.cppsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/OSSLMLDSA.cpp
📚 Learning: 2025-09-11T16:54:00.370Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.370Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Applied to files:
m4/acx_openssl_mldsa.m4src/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/test/MLDSATests.cppsrc/lib/SoftHSM.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/MLDSAUtil.hsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/P11Attributes.h
📚 Learning: 2025-10-13T09:43:45.885Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:13265-13282
Timestamp: 2025-10-13T09:43:45.885Z
Learning: SoftHSM OAEP policy: In SoftHSM::MechParamCheckRSAPKCSOAEP (src/lib/SoftHSM.cpp), enforce that the MGF1 variant must correspond to the selected hashAlg (e.g., SHA-256 -> CKG_MGF1_SHA256). Mismatches should return CKR_ARGUMENTS_BAD with "Hash and MGF don't match". This mirrors the existing PSS enforcement.
Applied to files:
m4/acx_openssl_mldsa.m4src/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/SoftHSM.hsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/P11Attributes.h
📚 Learning: 2025-11-11T19:42:46.886Z
Learnt from: JoaoHenrique12
Repo: softhsm/SoftHSMv2 PR: 823
File: src/lib/SoftHSM.cpp:58-58
Timestamp: 2025-11-11T19:42:46.886Z
Learning: SoftHSM include policy: Algorithm key/parameter headers (e.g., SLHParameters, SLH*Key) are included unconditionally in SoftHSM.cpp/SoftHSM.h; feature gating is handled in mechanism tables and CryptoFactory (WITH_*). Avoid wrapping such includes in WITH_* guards.
Applied to files:
src/lib/crypto/CMakeLists.txtsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/SoftHSM.hsrc/lib/crypto/OSSLUtil.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/MLDSAParameters.hsrc/lib/crypto/MLDSAUtil.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-08-11T16:42:23.012Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 806
File: src/lib/test/p11test.cpp:81-84
Timestamp: 2025-08-11T16:42:23.012Z
Learning: In SoftHSM test files (like p11test.cpp and cryptotest.cpp), error handling for OSSL_PROVIDER_load() calls for "legacy" and "default" providers is intentionally omitted because these providers won't fail in practice and the test code is kept deliberately simple.
Applied to files:
src/lib/crypto/CMakeLists.txtsrc/lib/crypto/test/MLDSATests.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-08-18T19:35:33.938Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/OSSLMLDSA.cpp:195-204
Timestamp: 2025-08-18T19:35:33.938Z
Learning: In OpenSSL, EVP_PKEY_verify_message does not exist. EVP_PKEY_verify_message_init is designed for streaming verification and should be paired with EVP_PKEY_CTX_set_signature, EVP_PKEY_verify_message_update, and EVP_PKEY_verify_message_final - not with EVP_PKEY_verify.
Applied to files:
src/lib/crypto/OSSLMLDSA.cpp
🧬 Code graph analysis (15)
src/lib/crypto/test/MLDSATests.h (1)
src/lib/crypto/test/MLDSATests.cpp (4)
setUp(26-34)setUp(26-26)tearDown(36-44)tearDown(36-36)
src/lib/crypto/OSSLMLDSAKeyPair.h (4)
src/lib/crypto/AsymmetricKeyPair.h (1)
AsymmetricKeyPair(42-55)src/lib/crypto/OSSLMLDSAKeyPair.cpp (12)
setPublicKey(13-17)setPublicKey(13-13)setPrivateKey(20-25)setPrivateKey(20-20)getPublicKey(28-31)getPublicKey(28-28)getConstPublicKey(33-36)getConstPublicKey(33-33)getPrivateKey(39-42)getPrivateKey(39-39)getConstPrivateKey(44-47)getConstPrivateKey(44-44)src/lib/crypto/PublicKey.h (1)
PublicKey(40-54)src/lib/crypto/PrivateKey.h (1)
PrivateKey(41-58)
src/lib/crypto/test/MLDSATests.cpp (1)
src/lib/crypto/test/MLDSATests.h (1)
MLDSATests(13-52)
src/lib/SoftHSM.h (2)
src/lib/SoftHSM.cpp (2)
generateMLDSA(10175-10430)generateMLDSA(10175-10186)src/lib/test/SignVerifyTests.cpp (2)
generateMLDSA(232-271)generateMLDSA(232-232)
src/lib/P11Objects.cpp (2)
src/lib/P11Objects.h (2)
P11MLDSAPublicKeyObj(201-212)P11MLDSAPrivateKeyObj(303-314)src/lib/P11Attributes.cpp (2)
init(109-120)init(109-109)
src/lib/P11Objects.h (1)
src/lib/P11Objects.cpp (19)
P11MLDSAPublicKeyObj(934-937)P11PublicKeyObj(664-667)init(64-114)init(64-64)init(338-383)init(338-338)init(392-459)init(392-392)init(468-536)init(468-468)init(545-597)init(545-545)init(606-661)init(606-606)init(670-739)init(670-670)init(748-788)init(748-748)P11MLDSAPrivateKeyObj(1384-1387)
src/lib/crypto/OSSLUtil.h (1)
src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(226-235)mldsaParameterSet2Name(226-226)
src/lib/crypto/MLDSAParameters.h (4)
src/lib/crypto/AsymmetricParameters.h (1)
AsymmetricParameters(40-45)src/lib/crypto/MLDSAPrivateKey.cpp (6)
getParameterSet(28-39)getParameterSet(28-28)serialise(76-80)serialise(76-76)deserialise(82-97)deserialise(82-82)src/lib/crypto/MLDSAParameters.cpp (10)
getParameterSet(22-25)getParameterSet(22-22)setParameterSet(16-19)setParameterSet(16-16)areOfType(28-31)areOfType(28-28)serialise(34-37)serialise(34-34)deserialise(39-50)deserialise(39-39)src/lib/crypto/MLDSAPublicKey.cpp (6)
getParameterSet(28-39)getParameterSet(28-28)serialise(66-69)serialise(66-66)deserialise(71-83)deserialise(71-71)
src/lib/crypto/MLDSAPrivateKey.h (4)
src/lib/crypto/PrivateKey.h (1)
PrivateKey(41-58)src/lib/crypto/MLDSAPrivateKey.cpp (20)
isOfType(17-20)isOfType(17-17)getParameterSet(28-39)getParameterSet(28-28)getOutputLength(42-53)getOutputLength(42-42)getBitLength(22-25)getBitLength(22-22)setValue(55-58)setValue(55-55)setSeed(65-68)setSeed(65-65)getValue(60-63)getValue(60-60)getSeed(70-73)getSeed(70-70)serialise(76-80)serialise(76-76)deserialise(82-97)deserialise(82-82)src/lib/crypto/MLDSAPublicKey.cpp (16)
isOfType(17-20)isOfType(17-17)getParameterSet(28-39)getParameterSet(28-28)getOutputLength(42-53)getOutputLength(42-42)getBitLength(22-25)getBitLength(22-22)setValue(60-63)setValue(60-60)getValue(55-58)getValue(55-55)serialise(66-69)serialise(66-66)deserialise(71-83)deserialise(71-71)src/lib/crypto/MLDSAParameters.cpp (6)
getParameterSet(22-25)getParameterSet(22-22)serialise(34-37)serialise(34-34)deserialise(39-50)deserialise(39-39)
src/lib/crypto/OSSLMLDSAPublicKey.h (3)
src/lib/crypto/OSSLMLDSAPublicKey.cpp (14)
OSSLMLDSAPublicKey(18-21)OSSLMLDSAPublicKey(23-28)OSSLMLDSAPublicKey(31-38)OSSLMLDSAPublicKey(40-44)isOfType(84-87)isOfType(84-84)setValue(89-97)setValue(89-89)setFromOSSL(65-81)setFromOSSL(65-65)getOSSLKey(100-105)getOSSLKey(100-100)createOSSLKey(108-146)createOSSLKey(108-108)src/lib/crypto/MLDSAPublicKey.h (1)
MLDSAPublicKey(14-45)src/lib/crypto/MLDSAPublicKey.cpp (4)
isOfType(17-20)isOfType(17-17)setValue(60-63)setValue(60-60)
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (3)
src/lib/crypto/MLDSAPrivateKey.cpp (6)
setSeed(65-68)setSeed(65-65)setValue(55-58)setValue(55-55)getParameterSet(28-39)getParameterSet(28-28)src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(226-235)mldsaParameterSet2Name(226-226)src/lib/crypto/MLDSAParameters.cpp (2)
getParameterSet(22-25)getParameterSet(22-22)
src/lib/crypto/MLDSAUtil.h (1)
src/lib/crypto/MLDSAUtil.cpp (6)
getMLDSAPrivateKey(11-41)getMLDSAPrivateKey(11-11)getMLDSAPublicKey(43-69)getMLDSAPublicKey(43-43)setMLDSAPrivateKey(71-111)setMLDSAPrivateKey(71-71)
src/lib/crypto/OSSLMLDSAPublicKey.cpp (4)
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (4)
setFromOSSL(44-69)setFromOSSL(44-44)setValue(77-85)setValue(77-77)src/lib/crypto/MLDSAPublicKey.cpp (4)
setValue(60-63)setValue(60-60)getParameterSet(28-39)getParameterSet(28-28)src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(226-235)mldsaParameterSet2Name(226-226)src/lib/crypto/MLDSAParameters.cpp (2)
getParameterSet(22-25)getParameterSet(22-22)
src/lib/crypto/OSSLMLDSA.cpp (1)
src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(226-235)mldsaParameterSet2Name(226-226)
src/lib/P11Attributes.h (2)
src/lib/P11Attributes.cpp (18)
P11Attribute(43-49)P11Attribute(52-54)updateAttr(56-70)updateAttr(56-56)updateAttr(510-525)updateAttr(510-510)updateAttr(539-554)updateAttr(539-539)updateAttr(570-585)updateAttr(570-570)updateAttr(599-623)updateAttr(599-599)updateAttr(637-661)updateAttr(637-637)updateAttr(675-699)updateAttr(675-675)updateAttr(724-751)updateAttr(724-724)src/lib/object_store/OSObject.h (1)
OSObject(42-92)
🪛 markdownlint-cli2 (0.18.1)
CMAKE-NOTES.md
14-14: Hard tabs
Column: 1
(MD010, no-hard-tabs)
14-14: Hard tabs
Column: 19
(MD010, no-hard-tabs)
CMAKE-WIN-NOTES.md
55-55: Hard tabs
Column: 1
(MD010, no-hard-tabs)
README.md
85-85: Hard tabs
Column: 1
(MD010, no-hard-tabs)
85-85: Hard tabs
Column: 16
(MD010, no-hard-tabs)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Windows (x86, openssl)
- GitHub Check: Windows (x64, botan)
- GitHub Check: Windows (x64, openssl)
- GitHub Check: Linux with OpenSSL 3.5.4
- GitHub Check: macOS (botan)
- GitHub Check: macOS (openssl)
- GitHub Check: Linux with OpenSSL 3.0
- GitHub Check: Linux with OpenSSL 1.1.1
- GitHub Check: Linux with Botan
🔇 Additional comments (25)
src/bin/dump/tables.h (3)
153-154: LGTM: MLDSA attribute constants added.The additions of CKA_PARAMETER_SET and CKA_SEED are correctly placed in the local extensions section and follow the established pattern.
483-484: LGTM: MLDSA mechanism constants added.The ML-DSA mechanisms are correctly placed after the EDDSA entry and follow the same mapping pattern.
551-551: LGTM: MLDSA key type constant added.The CKK_ML_DSA key type is correctly placed and formatted.
src/lib/crypto/OSSLUtil.h (1)
76-78: LGTM: ML-DSA parameter set mapping function added.The declaration is properly guarded with WITH_ML_DSA and follows the same pattern as the WITH_EDDSA block above. The implementation correctly maps PKCS#11 parameter set constants to OpenSSL algorithm names.
src/lib/crypto/CMakeLists.txt (2)
31-34: LGTM: Core ML-DSA sources added.The core ML-DSA classes (parameters, keys, utilities) are correctly added to the main SOURCES list, following the same pattern as other algorithm implementations.
76-79: LGTM: OpenSSL ML-DSA wrappers added.The OpenSSL-specific ML-DSA wrapper classes are correctly added under the WITH_OPENSSL conditional block, following the established pattern for other OpenSSL algorithm implementations.
src/lib/SoftHSM.h (1)
378-393: LGTM: generateMLDSA declaration properly guarded.The function declaration is correctly wrapped in WITH_ML_DSA guards, matching the implementation in SoftHSM.cpp and following the same pattern as WITH_ECC and WITH_EDDSA conditional features.
src/lib/P11Objects.h (2)
201-213: ML-DSA public key object declaration matches existing object patterns.
No concerns with the class shape/signature; consistent with adjacent key-object declarations.
303-315: ML-DSA private key object declaration matches existing object patterns.
No concerns with the class shape/signature; consistent with adjacent key-object declarations.src/lib/test/SignVerifyTests.cpp (1)
231-271: generateMLDSA helper looks consistent with other keypair generators.
Uses CKM_ML_DSA_KEY_PAIR_GEN + CKA_PARAMETER_SET/CKK_ML_DSA appropriately; reads cleanly.src/lib/crypto/test/MLDSATests.cpp (3)
46-67: Key generation test is straightforward and exercises all parameter sets.
Nice to see the full CKP_ML_DSA_{44,65,87} matrix covered.
69-123: Serialisation round-trip coverage is solid (params + keypair).
Checks parameter set, value, and seed equality—good signal for token persistence correctness.
125-161: PKCS#8 encode/decode test covers the right invariants.
Verifies the decoded key preserves parameter set + key material.src/lib/crypto/test/MLDSATests.h (1)
1-55: Test fixture header looks good; keep build gating consistent with the.cpp.
No API issues here—just ensure the build only includes this test suite whenWITH_ML_DSAis enabled to avoid undefined references.src/lib/crypto/MLDSAPublicKey.h (1)
10-12: ExplicitByteString.hinclude is good.
Line 10-12: avoids reliance on transitive includes.src/lib/P11Attributes.h (2)
1147-1163:CKA_PARAMETER_SETattribute wiring looks consistent with other fixed-size attrs.
Line 1147-1163: settingsize = sizeof(CK_ULONG)and providingupdateAttr()override is the right shape for a parameter-set attribute.
1147-1163: PKCS#11 v3.2 expectations forCKA_PARAMETER_SETandCKA_SEEDare correctly implemented.Lines 1147–1163 (P11AttrParameterSet):
checks = ck1|incheckscorrectly enforces that caller must supply the parameter set on C_CreateObject (footnote 1: "MUST be specified when object is created").Lines 1282–1298 (P11AttrSeed):
checks = ck4|ck6|ck7correctly implements that SEED is output-only for C_GenerateKey/GenerateKeyPair (ck4) and C_UnwrapKey (ck6), with sensitivity restrictions (ck7). On C_CreateObject, at least one of CKA_SEED or CKA_VALUE must be provided per spec; the flexible P11AttrValue (which acceptsinchecks) accommodates this mutual constraint.src/lib/P11Objects.cpp (2)
939-976: ML-DSA public key object init matches existing key-object patterns.
Line 939-976: key type defaulting, parent init, attribute creation/init, and cleanup on failure all look solid.
1389-1430: ML-DSA private key object init matches existing key-object patterns.
Line 1389-1430: consistent attribute checks for private material + correct cleanup on failure.src/lib/crypto/OSSLMLDSAKeyPair.cpp (1)
27-47: Key accessors returning internal pointers are consistent with existing keypair interfaces.
Line 27-47: both mutable and const accessors are provided; looks fine.src/lib/crypto/OSSLMLDSAPublicKey.h (1)
27-34: Move-only semantics for rawEVP_PKEY*ownership are the right call.
Line 27-34: deleting copy ops and defining moves prevents accidental double-free/UAF.src/lib/crypto/AsymmetricAlgorithm.h (1)
45-153: ML-DSA enums + SIGN_ADDITIONAL_CONTEXT non-copyable semantics look solid
Deleting copy ops and usingconst unsigned char*aligns with the intended “deep-copy occurs elsewhere” model (based on learnings).src/lib/SoftHSM.cpp (3)
149-152: ML-DSA P11 object creation is correctly feature-gated
The#ifdef WITH_ML_DSAguards prevent non-ML builds from referencingP11MLDSA*symbols.Also applies to: 170-173
841-845: Mechanism exposure is correctly gated by WITH_ML_DSA
MappingCKM_ML_DSA_KEY_PAIR_GENandCKM_ML_DSAinto the supported mechanism set under#ifdef WITH_ML_DSAis consistent with the rest of the file’s feature gating.
950-963: Mechanism info for ML-DSA looks consistent with existing patterns
Fetching min/max sizes viaCryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::MLDSA)and advertising them forCKM_ML_DSA(_KEY_PAIR_GEN)follows the RSA/DSA/ECDSA pattern.Also applies to: 1051-1063, 1354-1365
e9be1d7 to
afc128b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/lib/SoftHSM.cpp (2)
6936-6938: Fix always-true DES3 key-type checks (wrap/unwrap currently always fail).
(A != X || A != Y)is always true; use&&.- if (pMechanism->mechanism == CKM_DES3_CBC && (wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 || - wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) + if (pMechanism->mechanism == CKM_DES3_CBC && + (wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 && + wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; @@ - if (pMechanism->mechanism == CKM_DES3_CBC && (unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 || - unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) + if (pMechanism->mechanism == CKM_DES3_CBC && + (unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 && + unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT;Also applies to: 7575-7577
7147-7250: *Unwrap side is inconsistent with wrap (only _CBC_PAD supported) and lacks IV validation before memcpy.
At minimum, validatepParameter/length inUnwrapKeySymCBC_PAD cases (even if upstream checks exist) to prevent internal misuse. Consider either (a) adding non-PAD CBC unwrap to match WrapKeySym, or (b) removing non-PAD CBC from WrapKeySym and the public whitelist.@@ case CKM_AES_CBC_PAD: case CKM_DES3_CBC_PAD: + if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != blocksize) { + cipher->recycleKey(unwrappingkey); + CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); + return CKR_ARGUMENTS_BAD; + } iv.resize(blocksize); memcpy(&iv[0], pMechanism->pParameter, blocksize);Also applies to: 7521-7534
♻️ Duplicate comments (5)
src/lib/crypto/OSSLMLDSAPublicKey.h (1)
58-58: Fix the trailing include-guard comment typo.The comment references
OSSLDSAPUBLICKEYbut the guard macro isOSSLMLDSAPUBLICKEY. This was flagged in a previous review but appears unresolved.-#endif // !_SOFTHSM_V2_OSSLDSAPUBLICKEY_H +#endif // !_SOFTHSM_V2_OSSLMLDSAPUBLICKEY_Hsrc/lib/crypto/OSSLMLDSAPrivateKey.h (1)
68-68: Fix the closing include-guard comment typo.The comment references
OSSLECPRIVATEKEY(copy-paste from EC key header) but should beOSSLMLDSAPRIVATEKEY. This was flagged in a previous review.-#endif // !_SOFTHSM_V2_OSSLECPRIVATEKEY_H +#endif // !_SOFTHSM_V2_OSSLMLDSAPRIVATEKEY_Hsrc/lib/SoftHSM.cpp (1)
6540-6653: CBC wrap uses unset blocksize (zero-length IV) and can memcpy from NULL.
This is a functional bug forCKM_AES_CBC/CKM_DES3_CBCand a crash risk ifpParameteris NULL.@@ size_t bb = 8; size_t blocksize = 0; @@ case CKM_AES_CBC: algo = SymAlgo::AES; + blocksize = 16; break; @@ case CKM_DES3_CBC: algo = SymAlgo::DES3; + blocksize = 8; + bb = 7; break; @@ switch(pMechanism->mechanism) { @@ case CKM_AES_CBC: case CKM_AES_CBC_PAD: case CKM_DES3_CBC: case CKM_DES3_CBC_PAD: + if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != blocksize) { + cipher->recycleKey(wrappingkey); + CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); + return CKR_ARGUMENTS_BAD; + } iv.resize(blocksize); memcpy(&iv[0], pMechanism->pParameter, blocksize); @@ - if (!cipher->encryptInit(wrappingkey, SymMode::CBC, iv, false)) + if (!cipher->encryptInit(wrappingkey, SymMode::CBC, iv, false))src/lib/crypto/OSSLMLDSA.cpp (2)
27-162: Fix OpenSSL API pairing inOSSLMLDSA::sign()(message-init +EVP_PKEY_signis a mismatch) and checkinitRv <= 0.
Right now you callEVP_PKEY_sign_message_init(...)but then useEVP_PKEY_sign(...)(and also treat negative return values as success viaif (!initRv)). This can break with providers and silently skip errors.Suggested direction (fully use the message API end-to-end):
@@ - int initRv; + int initRv; if (param != NULL) { initRv = EVP_PKEY_sign_message_init(sctx, sig_alg, params); } else { initRv = EVP_PKEY_sign_message_init(sctx, sig_alg, NULL); } - if (!initRv) { + if (initRv <= 0) { ERROR_MSG("ML-DSA sign_message_init failed (0x%08X)", ERR_get_error()); EVP_SIGNATURE_free(sig_alg); EVP_PKEY_CTX_free(sctx); return false; } - /* Calculate the required size for the signature by passing a NULL buffer. */ - if (EVP_PKEY_sign(sctx, NULL, &len, dataToSign.const_byte_str(), dataToSign.size()) <= 0) { - ERROR_MSG("ML-DSA sign size query failed (0x%08X)", ERR_get_error()); - EVP_SIGNATURE_free(sig_alg); - EVP_PKEY_CTX_free(sctx); - return false; - } - signature.resize(len); - if (EVP_PKEY_sign(sctx, &signature[0], &len, dataToSign.const_byte_str(), dataToSign.size()) <= 0) { - ERROR_MSG("ML-DSA sign failed (0x%08X)", ERR_get_error()); - EVP_SIGNATURE_free(sig_alg); - EVP_PKEY_CTX_free(sctx); - return false; - } + if (EVP_PKEY_sign_message_update(sctx, dataToSign.const_byte_str(), dataToSign.size()) <= 0) { + ERROR_MSG("ML-DSA sign update failed (0x%08X)", ERR_get_error()); + EVP_SIGNATURE_free(sig_alg); + EVP_PKEY_CTX_free(sctx); + return false; + } + if (EVP_PKEY_sign_message_final(sctx, NULL, &len) <= 0 || len == 0) { + ERROR_MSG("ML-DSA sign final size query failed (0x%08X)", ERR_get_error()); + EVP_SIGNATURE_free(sig_alg); + EVP_PKEY_CTX_free(sctx); + return false; + } + signature.resize(len); + if (EVP_PKEY_sign_message_final(sctx, &signature[0], &len) <= 0) { + ERROR_MSG("ML-DSA sign final failed (0x%08X)", ERR_get_error()); + EVP_SIGNATURE_free(sig_alg); + EVP_PKEY_CTX_free(sctx); + return false; + } + signature.resize(len);OpenSSL 3.5 documentation: EVP_PKEY_sign_message_init / EVP_PKEY_sign_message_update / EVP_PKEY_sign_message_final usage, and return value semantics (0 vs negative).
186-323: Fix OpenSSL API pairing inOSSLMLDSA::verify()(message-init +EVP_PKEY_verifyis a mismatch) and checkinitRv <= 0.
Same issue as sign():EVP_PKEY_verify_message_init(...)must be paired withEVP_PKEY_CTX_set_signature(...)+EVP_PKEY_verify_message_update(...)+EVP_PKEY_verify_message_final(...)(or switch fully to the non-message init path). Alsoif (!initRv)misses negative error returns.Concrete fix (stay on message API):
@@ - if (!initRv) { + if (initRv <= 0) { ERROR_MSG("ML-DSA verify init failed (0x%08X)", ERR_get_error()); EVP_PKEY_CTX_free(vctx); EVP_SIGNATURE_free(sig_alg); return false; } - int verifyRV = EVP_PKEY_verify(vctx, signature.const_byte_str(), signature.size(), - originalData.const_byte_str(), originalData.size()); + if (EVP_PKEY_CTX_set_signature(vctx, signature.const_byte_str(), signature.size()) <= 0) { + ERROR_MSG("ML-DSA set signature failed (0x%08X)", ERR_get_error()); + EVP_PKEY_CTX_free(vctx); + EVP_SIGNATURE_free(sig_alg); + return false; + } + if (EVP_PKEY_verify_message_update(vctx, originalData.const_byte_str(), originalData.size()) <= 0) { + ERROR_MSG("ML-DSA verify update failed (0x%08X)", ERR_get_error()); + EVP_PKEY_CTX_free(vctx); + EVP_SIGNATURE_free(sig_alg); + return false; + } + int verifyRV = EVP_PKEY_verify_message_final(vctx); EVP_PKEY_CTX_free(vctx); EVP_SIGNATURE_free(sig_alg); if (verifyRV != 1) { - if (verifyRV != 0) - { - ERROR_MSG("ML-DSA verify error (0x%08X)", ERR_get_error()); - } + if (verifyRV < 0) ERROR_MSG("ML-DSA verify error (0x%08X)", ERR_get_error()); return false; }OpenSSL 3.5 documentation: EVP_PKEY_verify_message_init requires EVP_PKEY_CTX_set_signature + EVP_PKEY_verify_message_update + EVP_PKEY_verify_message_final (no EVP_PKEY_verify).
🧹 Nitpick comments (1)
src/lib/crypto/OSSLMLDSA.cpp (1)
79-105: Deduplicate SIGN_ADDITIONAL_CONTEXT →OSSL_PARAMbuilding between sign/verify.
Same validation + param construction appears twice; a tiny helper would reduce drift risk.Also applies to: 241-267
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
.github/workflows/ci.yml(1 hunks)src/lib/SoftHSM.cpp(34 hunks)src/lib/crypto/AsymmetricAlgorithm.h(3 hunks)src/lib/crypto/MLDSAPrivateKey.cpp(1 hunks)src/lib/crypto/MLDSAPublicKey.h(1 hunks)src/lib/crypto/MLDSAUtil.h(1 hunks)src/lib/crypto/OSSLMLDSA.cpp(1 hunks)src/lib/crypto/OSSLMLDSA.h(1 hunks)src/lib/crypto/OSSLMLDSAKeyPair.h(1 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.cpp(1 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.h(1 hunks)src/lib/crypto/OSSLMLDSAPublicKey.h(1 hunks)src/lib/crypto/test/MLDSATests.cpp(1 hunks)src/lib/crypto/test/MLDSATests.h(1 hunks)src/lib/session_mgr/Session.cpp(1 hunks)src/lib/test/SignVerifyTests.cpp(2 hunks)src/lib/test/SignVerifyTests.h(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- .github/workflows/ci.yml
- src/lib/crypto/test/MLDSATests.cpp
- src/lib/crypto/MLDSAPublicKey.h
🧰 Additional context used
🧠 Learnings (12)
📓 Common learnings
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.370Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:5550-5596
Timestamp: 2025-10-27T16:44:57.865Z
Learning: SoftHSM ML‑DSA additional context: avoid transient malloc in SoftHSM::{AsymSignInit, AsymVerifyInit}; let Session::setParameters deep‑copy SIGN_ADDITIONAL_CONTEXT by allocating one buffer for struct + context bytes and fixing the stored pointer; Session::resetOp frees m_pParameters so both struct and context are released.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Learnt from: JoaoHenrique12
Repo: softhsm/SoftHSMv2 PR: 823
File: src/lib/SoftHSM.cpp:58-58
Timestamp: 2025-11-11T19:42:46.886Z
Learning: SoftHSM include policy: Algorithm key/parameter headers (e.g., SLHParameters, SLH*Key) are included unconditionally in SoftHSM.cpp/SoftHSM.h; feature gating is handled in mechanism tables and CryptoFactory (WITH_*). Avoid wrapping such includes in WITH_* guards.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.693Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: m4/acx_openssl_mldsa.m4:10-35
Timestamp: 2025-08-18T17:54:37.645Z
Learning: For OpenSSL feature detection in autoconf macros, prefer functional tests (like EVP_PKEY_CTX_new_from_name) over version number checks, as the functional approach directly tests the actual capability and is more reliable across different OpenSSL builds where features may be backported or disabled.
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:13265-13282
Timestamp: 2025-10-13T09:43:45.885Z
Learning: SoftHSM OAEP policy: In SoftHSM::MechParamCheckRSAPKCSOAEP (src/lib/SoftHSM.cpp), enforce that the MGF1 variant must correspond to the selected hashAlg (e.g., SHA-256 -> CKG_MGF1_SHA256). Mismatches should return CKR_ARGUMENTS_BAD with "Hash and MGF don't match". This mirrors the existing PSS enforcement.
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:3238-3266
Timestamp: 2025-10-13T09:42:31.270Z
Learning: In src/lib/SoftHSM.cpp, SoftHSM::AsymDecryptInit should use MechParamCheckRSAPKCSOAEP for CKM_RSA_PKCS_OAEP to keep OAEP parameter validation identical to AsymEncryptInit, and avoid redundant manual checks for pMechanism->pParameter and MGF allowlists.
📚 Learning: 2025-08-19T09:23:25.434Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Applied to files:
src/lib/crypto/MLDSAUtil.hsrc/lib/test/SignVerifyTests.cppsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/test/SignVerifyTests.hsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/test/MLDSATests.h
📚 Learning: 2025-08-18T17:59:30.693Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.693Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Applied to files:
src/lib/crypto/MLDSAUtil.hsrc/lib/test/SignVerifyTests.cppsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/test/SignVerifyTests.hsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/test/MLDSATests.h
📚 Learning: 2025-11-11T19:42:46.886Z
Learnt from: JoaoHenrique12
Repo: softhsm/SoftHSMv2 PR: 823
File: src/lib/SoftHSM.cpp:58-58
Timestamp: 2025-11-11T19:42:46.886Z
Learning: SoftHSM include policy: Algorithm key/parameter headers (e.g., SLHParameters, SLH*Key) are included unconditionally in SoftHSM.cpp/SoftHSM.h; feature gating is handled in mechanism tables and CryptoFactory (WITH_*). Avoid wrapping such includes in WITH_* guards.
Applied to files:
src/lib/crypto/MLDSAUtil.hsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSA.h
📚 Learning: 2025-10-27T16:44:57.865Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:5550-5596
Timestamp: 2025-10-27T16:44:57.865Z
Learning: SoftHSM ML‑DSA additional context: avoid transient malloc in SoftHSM::{AsymSignInit, AsymVerifyInit}; let Session::setParameters deep‑copy SIGN_ADDITIONAL_CONTEXT by allocating one buffer for struct + context bytes and fixing the stored pointer; Session::resetOp frees m_pParameters so both struct and context are released.
Applied to files:
src/lib/crypto/MLDSAUtil.hsrc/lib/test/SignVerifyTests.cppsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/test/SignVerifyTests.hsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/test/MLDSATests.h
📚 Learning: 2025-08-18T19:46:46.659Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Applied to files:
src/lib/crypto/MLDSAUtil.hsrc/lib/test/SignVerifyTests.cppsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/test/SignVerifyTests.hsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/test/MLDSATests.h
📚 Learning: 2025-09-11T16:54:00.370Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.370Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Applied to files:
src/lib/crypto/MLDSAUtil.hsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSA.h
📚 Learning: 2025-10-13T09:42:31.270Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:3238-3266
Timestamp: 2025-10-13T09:42:31.270Z
Learning: In src/lib/SoftHSM.cpp, SoftHSM::AsymDecryptInit should use MechParamCheckRSAPKCSOAEP for CKM_RSA_PKCS_OAEP to keep OAEP parameter validation identical to AsymEncryptInit, and avoid redundant manual checks for pMechanism->pParameter and MGF allowlists.
Applied to files:
src/lib/crypto/MLDSAUtil.hsrc/lib/test/SignVerifyTests.cppsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/test/SignVerifyTests.hsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/test/MLDSATests.h
📚 Learning: 2025-10-13T09:43:45.885Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:13265-13282
Timestamp: 2025-10-13T09:43:45.885Z
Learning: SoftHSM OAEP policy: In SoftHSM::MechParamCheckRSAPKCSOAEP (src/lib/SoftHSM.cpp), enforce that the MGF1 variant must correspond to the selected hashAlg (e.g., SHA-256 -> CKG_MGF1_SHA256). Mismatches should return CKR_ARGUMENTS_BAD with "Hash and MGF don't match". This mirrors the existing PSS enforcement.
Applied to files:
src/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/test/SignVerifyTests.hsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSA.h
📚 Learning: 2025-08-11T16:42:23.012Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 806
File: src/lib/test/p11test.cpp:81-84
Timestamp: 2025-08-11T16:42:23.012Z
Learning: In SoftHSM test files (like p11test.cpp and cryptotest.cpp), error handling for OSSL_PROVIDER_load() calls for "legacy" and "default" providers is intentionally omitted because these providers won't fail in practice and the test code is kept deliberately simple.
Applied to files:
src/lib/SoftHSM.cpp
📚 Learning: 2025-08-18T19:35:33.938Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/OSSLMLDSA.cpp:195-204
Timestamp: 2025-08-18T19:35:33.938Z
Learning: In OpenSSL, EVP_PKEY_verify_message does not exist. EVP_PKEY_verify_message_init is designed for streaming verification and should be paired with EVP_PKEY_CTX_set_signature, EVP_PKEY_verify_message_update, and EVP_PKEY_verify_message_final - not with EVP_PKEY_verify.
Applied to files:
src/lib/crypto/OSSLMLDSA.cpp
📚 Learning: 2025-08-18T17:54:37.645Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: m4/acx_openssl_mldsa.m4:10-35
Timestamp: 2025-08-18T17:54:37.645Z
Learning: For OpenSSL feature detection in autoconf macros, prefer functional tests (like EVP_PKEY_CTX_new_from_name) over version number checks, as the functional approach directly tests the actual capability and is more reliable across different OpenSSL builds where features may be backported or disabled.
Applied to files:
src/lib/crypto/OSSLMLDSA.cpp
🧬 Code graph analysis (8)
src/lib/test/SignVerifyTests.cpp (1)
src/lib/SoftHSM.cpp (4)
generateMLDSA(10175-10430)generateMLDSA(10175-10186)C_GenerateKeyPair(6270-6465)C_GenerateKeyPair(6270-6280)
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (3)
src/lib/crypto/MLDSAPrivateKey.cpp (2)
getParameterSet(28-39)getParameterSet(28-28)src/lib/crypto/MLDSAPublicKey.cpp (2)
getParameterSet(28-39)getParameterSet(28-28)src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(226-235)mldsaParameterSet2Name(226-226)
src/lib/test/SignVerifyTests.h (2)
src/lib/test/SignVerifyTests.cpp (4)
testMLDSASignVerify(850-937)testMLDSASignVerify(850-850)generateMLDSA(232-271)generateMLDSA(232-232)src/lib/SoftHSM.cpp (2)
generateMLDSA(10175-10430)generateMLDSA(10175-10186)
src/lib/SoftHSM.cpp (1)
src/lib/crypto/MLDSAUtil.cpp (6)
getMLDSAPrivateKey(11-41)getMLDSAPrivateKey(11-11)getMLDSAPublicKey(43-69)getMLDSAPublicKey(43-43)setMLDSAPrivateKey(71-111)setMLDSAPrivateKey(71-71)
src/lib/crypto/MLDSAPrivateKey.cpp (2)
src/lib/crypto/MLDSAPublicKey.cpp (12)
isOfType(17-20)isOfType(17-17)getParameterSet(28-39)getParameterSet(28-28)getOutputLength(42-53)getOutputLength(42-42)setValue(60-63)setValue(60-60)serialise(66-69)serialise(66-66)deserialise(71-83)deserialise(71-71)src/lib/crypto/MLDSAParameters.cpp (6)
getParameterSet(22-25)getParameterSet(22-22)serialise(34-37)serialise(34-34)deserialise(39-50)deserialise(39-39)
src/lib/crypto/OSSLMLDSAPublicKey.h (4)
src/lib/crypto/OSSLMLDSAPublicKey.cpp (14)
OSSLMLDSAPublicKey(18-21)OSSLMLDSAPublicKey(23-28)OSSLMLDSAPublicKey(31-38)OSSLMLDSAPublicKey(40-44)isOfType(84-87)isOfType(84-84)setValue(89-97)setValue(89-89)setFromOSSL(65-81)setFromOSSL(65-65)getOSSLKey(100-105)getOSSLKey(100-100)createOSSLKey(108-146)createOSSLKey(108-108)src/lib/crypto/MLDSAPublicKey.h (1)
MLDSAPublicKey(14-45)src/lib/crypto/MLDSAPrivateKey.cpp (4)
isOfType(17-20)isOfType(17-17)setValue(55-58)setValue(55-55)src/lib/crypto/MLDSAPublicKey.cpp (4)
isOfType(17-20)isOfType(17-17)setValue(60-63)setValue(60-60)
src/lib/crypto/OSSLMLDSA.cpp (1)
src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(226-235)mldsaParameterSet2Name(226-226)
src/lib/crypto/OSSLMLDSA.h (5)
src/lib/crypto/AsymmetricAlgorithm.cpp (1)
AsymmetricAlgorithm(38-45)src/lib/crypto/AsymmetricKeyPair.h (1)
AsymmetricKeyPair(42-55)src/lib/crypto/AsymmetricParameters.h (1)
AsymmetricParameters(40-45)src/lib/crypto/PublicKey.h (1)
PublicKey(40-54)src/lib/crypto/PrivateKey.h (1)
PrivateKey(41-58)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Windows (x64, openssl)
- GitHub Check: Windows (x86, openssl)
- GitHub Check: Windows (x64, botan)
- GitHub Check: Linux with OpenSSL 3.5.4
- GitHub Check: Linux with OpenSSL 1.1.1
- GitHub Check: macOS (openssl)
- GitHub Check: Linux with Botan
- GitHub Check: Linux with OpenSSL 3.0
- GitHub Check: macOS (botan)
🔇 Additional comments (25)
src/lib/test/SignVerifyTests.h (1)
52-54: LGTM! ML-DSA test scaffolding follows established patterns.The parameterized test registration and helper declarations correctly mirror the existing EdDSA test structure, with appropriate
WITH_ML_DSAguards.Also applies to: 66-68, 78-80
src/lib/crypto/OSSLMLDSAPublicKey.h (1)
27-33: LGTM! Non-copyable and movable semantics properly declared.Deleting copy operations and declaring move operations correctly addresses the EVP_PKEY ownership concern.
src/lib/crypto/AsymmetricAlgorithm.h (2)
56-57: LGTM! MLDSA enum values correctly added.The new
MLDSAvalues are properly placed in bothAsymAlgo::TypeandAsymMech::Typeenums, following the existing pattern.Also applies to: 96-97
121-153: LGTM! Well-designed context structure with proper ownership semantics.The
Hedgeenum andSIGN_ADDITIONAL_CONTEXTstruct are well-structured:
const unsigned char*signals non-ownership- Deleted copy operations prevent accidental shallow copies
- Comment documents that
Session::setParametershandles deep-copyThis aligns with the learnings about ML-DSA additional context handling.
src/lib/crypto/OSSLMLDSAPrivateKey.h (1)
28-34: LGTM! Non-copyable and movable semantics properly declared.The ownership model correctly prevents shallow copies of the EVP_PKEY pointer.
src/lib/crypto/OSSLMLDSA.h (2)
14-54: LGTM! Comprehensive ML-DSA algorithm interface.The class correctly derives from
AsymmetricAlgorithmand declares all required virtual methods. The private static flagsOSSL_RANDOMandOSSL_DETERMINISTICsupport the hedge mode implementation.
32-37: The encrypt() and decrypt() implementations correctly returnfalsewith appropriate error logging ("ML-DSA does not support encryption" and "ML-DSA does not support decryption" respectively). Both methods properly block any encryption/decryption operations on ML-DSA keys as expected for a signature-only algorithm.src/lib/crypto/MLDSAUtil.h (2)
20-27: LGTM! Clean utility interface for ML-DSA key operations.The static methods provide a consistent interface for retrieving and setting ML-DSA key material from/to token storage, following the established pattern in the codebase.
29-30: LGTM! Guard comments are now correctly ordered.The
#endifcomments properly match their corresponding directives:WITH_ML_DSAfor the feature guard and_SOFTHSM_V2_MLDSAUTIL_Hfor the include guard.src/lib/session_mgr/Session.cpp (1)
355-389: LGTM! ML-DSA parameter handling correctly implemented.The deep-copy logic for
SIGN_ADDITIONAL_CONTEXTfollows the established pattern: allocates a single contiguous buffer (struct + optional context bytes), validates NULL context pointer whencontextLength > 0, and setsparam/paramLenappropriately.Session::resetOpwill release both struct and context viafree(param).Based on learnings.
src/lib/test/SignVerifyTests.cpp (3)
231-272: LGTM! ML-DSA key generation helper follows established pattern.The
generateMLDSAfunction mirrors the structure of existing key generation helpers (generateRSA,generateEC,generateED), correctly setting up ML-DSA key attributes and invokingC_GenerateKeyPair.
279-279: Good: Signature buffer sized for ML-DSA.Increasing the buffer to 64 KB accommodates ML-DSA signatures (ML-DSA-87 produces up to 4627 bytes).
882-937: Comprehensive ML-DSA test coverage.The test exercises all 6 hedge/context parameter combinations (HEDGE_PREFERRED, HEDGE_REQUIRED, DETERMINISTIC_REQUIRED, each with and without context) across all 4 key storage variants (public/private session/token keys). The context data is correctly declared as a mutable stack array with computed size.
src/lib/crypto/test/MLDSATests.h (1)
1-55: LGTM! Comprehensive ML-DSA test fixture.The test suite declares 13 test methods covering key generation, serialization, PKCS#8 encoding, and signing/verifying across multiple hedge modes (preferred, required, deterministic) with and without context, plus context-too-long error cases. The header structure is standard and include guards are correct.
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (1)
17-210: LGTM! OpenSSL ML-DSA private key implementation is clean.Key aspects:
- Move semantics (lines 40-56) prevent double-free of
pkey.setFromOSSL(lines 62-87) safely extracts optional seed and required private key fromEVP_PKEY.setValue/setSeedoverrides (lines 95-113) correctly invalidate cachedpkey.PKCS8Decode(lines 138-151) now freeslocalPKeyaftersetFromOSSL(previous leak fixed).createOSSLKey(lines 162-210) validates parameter set and value before constructingEVP_PKEY, with proper error handling and resource cleanup.All previously flagged issues (memory leaks, missing NULL guards, pre-allocation) have been addressed.
src/lib/crypto/OSSLMLDSAKeyPair.h (1)
7-42: LGTM! Header structure and guards are correct.The include ordering is proper (
config.hat line 10 beforeWITH_ML_DSAtest at line 11), and the closing guard comments accurately reflect their corresponding opening directives (line 41 closesWITH_ML_DSAfrom line 11; line 42 closes the include guard from line 7). The class interface is straightforward.src/lib/crypto/MLDSAPrivateKey.cpp (1)
17-97: LGTM! ML-DSA private key implementation follows established patterns.The parameter-set and output-length inference (lines 28-53) correctly maps key material length to
CKP_ML_DSA_*constants and signature lengths, returning 0 for unknown sizes. Serialization (lines 76-80) concatenates seed and value, and deserialization (lines 82-97) validates non-empty results before assignment. This mirrors the structure ofMLDSAPublicKey.cppandMLDSAParameters.cpp.Based on learnings.
src/lib/SoftHSM.cpp (4)
65-70: WITH_ML_DSA include gating looks consistent with feature usage.
149-173: ML-DSA P11 object creation is correctly guarded by WITH_ML_DSA.
842-845: Mechanism exposure + mechanism-info wiring for ML-DSA looks coherent.Also applies to: 950-1063, 1354-1365
4205-4526: Good: CK_SIGN_ADDITIONAL_CONTEXT handling is zero-initialized and safely passed for Session deep-copy. (Matches the intended ownership model.)Also applies to: 5286-5602, 4613-4632, 5689-5708
src/lib/crypto/OSSLMLDSA.cpp (4)
164-345: Multipart stubs look consistent with current PKCS#11 expectations (explicitly reject multi-part).
347-380: Clear “not supported” behavior for encrypt/decrypt/checkEncryptedDataSize.
365-373: Key-size min/max wiring toMLDSAParameters::*_PRIV_LENGTHlooks reasonable.
448-567: Key (de)serialization andnew*()factories are straightforward.
7685384 to
ec9c5f2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/lib/SoftHSM.cpp (1)
7521-7533: Fix error codes and DES3 logic in C_UnwrapKey key-type validationTwo issues at lines 7573-7577:
Line 7574 returns
CKR_WRAPPING_KEY_TYPE_INCONSISTENTfor AES_CBC/AES_CBC_PAD, but should returnCKR_UNWRAPPING_KEY_TYPE_INCONSISTENTto match PKCS#11 convention and the rest of the function.Lines 7575-7577 use
!= CKK_DES2 || != CKK_DES3, which is always true for any key type. Should use&&to properly allow DES2 or DES3 keys.if ((pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CBC_PAD) && unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES) - return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; + return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; if (pMechanism->mechanism == CKM_DES3_CBC && (unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES2 && - unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) + unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_DES3)) - return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; + return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT;
♻️ Duplicate comments (2)
src/lib/crypto/test/MLDSATests.cpp (1)
163-518: Verify that MLDSATests.cpp is conditionally compiled only when WITH_ML_DSA is enabled.The file content is guarded by
#ifdef WITH_ML_DSA(line 16) and#endif(line 520), but the past review flagged that CMakeLists.txt and Makefile.am include this file unconditionally. This could cause link errors when WITH_ML_DSA is disabled.#!/bin/bash # Check if MLDSATests.cpp is conditionally compiled in build files echo "=== CMakeLists.txt in src/lib/crypto/test/ ===" cat src/lib/crypto/test/CMakeLists.txt | grep -A5 -B5 "MLDSATests" echo "" echo "=== Makefile.am in src/lib/crypto/test/ ===" cat src/lib/crypto/test/Makefile.am | grep -A5 -B5 "MLDSATests"src/lib/crypto/OSSLMLDSAPrivateKey.h (1)
68-68: Fix the include guard closing comment typo.The closing comment references
OSSLECPRIVATEKEY_Hbut should referenceOSSLMLDSAPRIVATEKEY_Hto match the include guard opened on line 7.Apply this diff:
-#endif // !_SOFTHSM_V2_OSSLECPRIVATEKEY_H +#endif // !_SOFTHSM_V2_OSSLMLDSAPRIVATEKEY_H
🧹 Nitpick comments (4)
.github/workflows/ci.yml (1)
101-114: Build and test configuration looks correct.The Build step correctly re-defines environment variables (env vars are step-scoped in GitHub Actions), and the test step follows the established pattern of other jobs.
Optional: The commented-out
CXXFLAGS: -Werror(lines 103-104) is consistent with thelinux_ossl_30job and intentional during the ML-DSA feature development phase. Consider tracking this as a follow-up task to enable-Werroronce OpenSSL 3.x deprecation warnings are fully addressed across both jobs.src/lib/crypto/OSSLMLDSAPublicKey.cpp (1)
107-146: Consider adding adefaultcase to the switch ingetParameterSet()for defensive coding.The
createOSSLKeyfunction callsOSSL::mldsaParameterSet2Name(getParameterSet())which may returnNULLfor unknown parameter sets (whengetParameterSet()returns 0). PassingNULLtoEVP_PKEY_CTX_new_from_namewill cause it to fail silently with a generic "Could not create context" error.While the author previously chose to skip adding explicit guards here, consider at minimum logging the parameter set value in the error message for easier debugging:
ctx = EVP_PKEY_CTX_new_from_name(NULL, name, NULL); if (ctx == NULL) { - ERROR_MSG("Could not create context"); + ERROR_MSG("Could not create context for ML-DSA (name=%s, valueSize=%zu)", + name ? name : "NULL", localValue.size()); return; }src/lib/crypto/test/MLDSATests.cpp (1)
216-218: Minor: Uninitialized struct members in SIGN_ADDITIONAL_CONTEXT.When only
hedgeTypeis set,contextAsCharandcontextLengthare left uninitialized. This may work in practice due to zero-initialization of the struct, but explicit initialization is safer:SIGN_ADDITIONAL_CONTEXT context = { - Hedge::Type::HEDGE_PREFERRED + Hedge::Type::HEDGE_PREFERRED, + NULL, + 0 };This pattern also appears at lines 323-325.
src/lib/crypto/OSSLMLDSAPrivateKey.h (1)
14-14: Remove unused<openssl/bn.h>include.The header includes
<openssl/bn.h>but does not use any BIGNUM or BN_* functions. The class only requiresEVP_PKEY*from<openssl/evp.h>.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (19)
.github/workflows/ci.yml(1 hunks)src/lib/SoftHSM.cpp(34 hunks)src/lib/SoftHSM.h(1 hunks)src/lib/crypto/AsymmetricAlgorithm.h(3 hunks)src/lib/crypto/MLDSAPrivateKey.cpp(1 hunks)src/lib/crypto/MLDSAPublicKey.h(1 hunks)src/lib/crypto/MLDSAUtil.h(1 hunks)src/lib/crypto/OSSLMLDSA.cpp(1 hunks)src/lib/crypto/OSSLMLDSA.h(1 hunks)src/lib/crypto/OSSLMLDSAKeyPair.h(1 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.cpp(1 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.h(1 hunks)src/lib/crypto/OSSLMLDSAPublicKey.cpp(1 hunks)src/lib/crypto/OSSLMLDSAPublicKey.h(1 hunks)src/lib/crypto/test/MLDSATests.cpp(1 hunks)src/lib/crypto/test/MLDSATests.h(1 hunks)src/lib/session_mgr/Session.cpp(1 hunks)src/lib/test/SignVerifyTests.cpp(2 hunks)src/lib/test/SignVerifyTests.h(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- src/lib/crypto/test/MLDSATests.h
- src/lib/crypto/MLDSAUtil.h
- src/lib/crypto/OSSLMLDSAKeyPair.h
- src/lib/crypto/MLDSAPublicKey.h
- src/lib/crypto/OSSLMLDSAPrivateKey.cpp
🧰 Additional context used
🧠 Learnings (15)
📓 Common learnings
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.370Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:5550-5596
Timestamp: 2025-10-27T16:44:57.865Z
Learning: SoftHSM ML‑DSA additional context: avoid transient malloc in SoftHSM::{AsymSignInit, AsymVerifyInit}; let Session::setParameters deep‑copy SIGN_ADDITIONAL_CONTEXT by allocating one buffer for struct + context bytes and fixing the stored pointer; Session::resetOp frees m_pParameters so both struct and context are released.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Learnt from: JoaoHenrique12
Repo: softhsm/SoftHSMv2 PR: 823
File: src/lib/SoftHSM.cpp:58-58
Timestamp: 2025-11-11T19:42:46.886Z
Learning: SoftHSM include policy: Algorithm key/parameter headers (e.g., SLHParameters, SLH*Key) are included unconditionally in SoftHSM.cpp/SoftHSM.h; feature gating is handled in mechanism tables and CryptoFactory (WITH_*). Avoid wrapping such includes in WITH_* guards.
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:13265-13282
Timestamp: 2025-10-13T09:43:45.885Z
Learning: SoftHSM OAEP policy: In SoftHSM::MechParamCheckRSAPKCSOAEP (src/lib/SoftHSM.cpp), enforce that the MGF1 variant must correspond to the selected hashAlg (e.g., SHA-256 -> CKG_MGF1_SHA256). Mismatches should return CKR_ARGUMENTS_BAD with "Hash and MGF don't match". This mirrors the existing PSS enforcement.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.693Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:3238-3266
Timestamp: 2025-10-13T09:42:31.270Z
Learning: In src/lib/SoftHSM.cpp, SoftHSM::AsymDecryptInit should use MechParamCheckRSAPKCSOAEP for CKM_RSA_PKCS_OAEP to keep OAEP parameter validation identical to AsymEncryptInit, and avoid redundant manual checks for pMechanism->pParameter and MGF allowlists.
📚 Learning: 2025-10-27T16:44:57.865Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:5550-5596
Timestamp: 2025-10-27T16:44:57.865Z
Learning: SoftHSM ML‑DSA additional context: avoid transient malloc in SoftHSM::{AsymSignInit, AsymVerifyInit}; let Session::setParameters deep‑copy SIGN_ADDITIONAL_CONTEXT by allocating one buffer for struct + context bytes and fixing the stored pointer; Session::resetOp frees m_pParameters so both struct and context are released.
Applied to files:
src/lib/SoftHSM.hsrc/lib/test/SignVerifyTests.hsrc/lib/test/SignVerifyTests.cppsrc/lib/session_mgr/Session.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-08-19T09:23:25.434Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Applied to files:
src/lib/SoftHSM.hsrc/lib/test/SignVerifyTests.hsrc/lib/test/SignVerifyTests.cppsrc/lib/session_mgr/Session.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-08-18T19:46:46.659Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Applied to files:
src/lib/SoftHSM.hsrc/lib/test/SignVerifyTests.hsrc/lib/test/SignVerifyTests.cppsrc/lib/session_mgr/Session.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-11-11T19:42:46.886Z
Learnt from: JoaoHenrique12
Repo: softhsm/SoftHSMv2 PR: 823
File: src/lib/SoftHSM.cpp:58-58
Timestamp: 2025-11-11T19:42:46.886Z
Learning: SoftHSM include policy: Algorithm key/parameter headers (e.g., SLHParameters, SLH*Key) are included unconditionally in SoftHSM.cpp/SoftHSM.h; feature gating is handled in mechanism tables and CryptoFactory (WITH_*). Avoid wrapping such includes in WITH_* guards.
Applied to files:
src/lib/SoftHSM.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-08-18T17:59:30.693Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.693Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Applied to files:
src/lib/SoftHSM.hsrc/lib/test/SignVerifyTests.hsrc/lib/test/SignVerifyTests.cppsrc/lib/session_mgr/Session.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-10-13T09:43:45.885Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:13265-13282
Timestamp: 2025-10-13T09:43:45.885Z
Learning: SoftHSM OAEP policy: In SoftHSM::MechParamCheckRSAPKCSOAEP (src/lib/SoftHSM.cpp), enforce that the MGF1 variant must correspond to the selected hashAlg (e.g., SHA-256 -> CKG_MGF1_SHA256). Mismatches should return CKR_ARGUMENTS_BAD with "Hash and MGF don't match". This mirrors the existing PSS enforcement.
Applied to files:
src/lib/SoftHSM.hsrc/lib/test/SignVerifyTests.hsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-09-11T16:54:00.370Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.370Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Applied to files:
src/lib/SoftHSM.hsrc/lib/test/SignVerifyTests.cppsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-10-13T09:42:31.270Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:3238-3266
Timestamp: 2025-10-13T09:42:31.270Z
Learning: In src/lib/SoftHSM.cpp, SoftHSM::AsymDecryptInit should use MechParamCheckRSAPKCSOAEP for CKM_RSA_PKCS_OAEP to keep OAEP parameter validation identical to AsymEncryptInit, and avoid redundant manual checks for pMechanism->pParameter and MGF allowlists.
Applied to files:
src/lib/SoftHSM.hsrc/lib/test/SignVerifyTests.hsrc/lib/test/SignVerifyTests.cppsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/test/MLDSATests.cppsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/OSSLMLDSA.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cpp
📚 Learning: 2025-08-12T13:25:41.715Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 806
File: .github/workflows/ci.yml:66-66
Timestamp: 2025-08-12T13:25:41.715Z
Learning: Ubuntu 24.04 (ubuntu-24.04 GitHub Actions runner image) comes with OpenSSL 3.0 and development headers (libssl-dev equivalent) pre-installed, so explicit installation of libssl-dev is not required for OpenSSL builds in CI workflows using this image.
Applied to files:
.github/workflows/ci.yml
📚 Learning: 2025-08-12T13:25:41.715Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 806
File: .github/workflows/ci.yml:66-66
Timestamp: 2025-08-12T13:25:41.715Z
Learning: GitHub Actions ubuntu-24.04 runner image comes with OpenSSL 3.0 and development headers pre-installed by default, so explicit installation of libssl-dev is not required for OpenSSL builds in workflows using this runner image.
Applied to files:
.github/workflows/ci.yml
📚 Learning: 2025-08-12T13:25:41.715Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 806
File: .github/workflows/ci.yml:66-66
Timestamp: 2025-08-12T13:25:41.715Z
Learning: The GitHub Actions ubuntu-24.04 runner image includes OpenSSL and libssl-dev pre-installed by default, as documented in the official actions/runner-images repository. Explicit installation of libssl-dev is not required for OpenSSL builds using this runner image.
Applied to files:
.github/workflows/ci.yml
📚 Learning: 2025-08-18T17:54:37.645Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: m4/acx_openssl_mldsa.m4:10-35
Timestamp: 2025-08-18T17:54:37.645Z
Learning: For OpenSSL feature detection in autoconf macros, prefer functional tests (like EVP_PKEY_CTX_new_from_name) over version number checks, as the functional approach directly tests the actual capability and is more reliable across different OpenSSL builds where features may be backported or disabled.
Applied to files:
.github/workflows/ci.ymlsrc/lib/crypto/OSSLMLDSA.cpp
📚 Learning: 2025-08-18T19:35:33.938Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/OSSLMLDSA.cpp:195-204
Timestamp: 2025-08-18T19:35:33.938Z
Learning: In OpenSSL, EVP_PKEY_verify_message does not exist. EVP_PKEY_verify_message_init is designed for streaming verification and should be paired with EVP_PKEY_CTX_set_signature, EVP_PKEY_verify_message_update, and EVP_PKEY_verify_message_final - not with EVP_PKEY_verify.
Applied to files:
src/lib/crypto/OSSLMLDSA.cpp
📚 Learning: 2025-08-11T16:42:23.012Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 806
File: src/lib/test/p11test.cpp:81-84
Timestamp: 2025-08-11T16:42:23.012Z
Learning: In SoftHSM test files (like p11test.cpp and cryptotest.cpp), error handling for OSSL_PROVIDER_load() calls for "legacy" and "default" providers is intentionally omitted because these providers won't fail in practice and the test code is kept deliberately simple.
Applied to files:
src/lib/crypto/OSSLMLDSA.cppsrc/lib/SoftHSM.cpp
🧬 Code graph analysis (9)
src/lib/SoftHSM.h (2)
src/lib/SoftHSM.cpp (2)
generateMLDSA(10175-10430)generateMLDSA(10175-10186)src/lib/test/SignVerifyTests.cpp (2)
generateMLDSA(232-271)generateMLDSA(232-232)
src/lib/test/SignVerifyTests.h (1)
src/lib/test/SignVerifyTests.cpp (4)
testMLDSASignVerify(850-937)testMLDSASignVerify(850-850)generateMLDSA(232-271)generateMLDSA(232-232)
src/lib/test/SignVerifyTests.cpp (1)
src/lib/SoftHSM.cpp (4)
generateMLDSA(10175-10430)generateMLDSA(10175-10186)C_GenerateKeyPair(6270-6465)C_GenerateKeyPair(6270-6280)
src/lib/crypto/MLDSAPrivateKey.cpp (2)
src/lib/crypto/MLDSAPublicKey.cpp (12)
getValue(55-58)getValue(55-55)getParameterSet(28-39)getParameterSet(28-28)getOutputLength(42-53)getOutputLength(42-42)setValue(60-63)setValue(60-60)serialise(66-69)serialise(66-66)deserialise(71-83)deserialise(71-71)src/lib/crypto/MLDSAParameters.cpp (6)
getParameterSet(22-25)getParameterSet(22-22)serialise(34-37)serialise(34-34)deserialise(39-50)deserialise(39-39)
src/lib/crypto/OSSLMLDSAPrivateKey.h (4)
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (20)
OSSLMLDSAPrivateKey(18-21)OSSLMLDSAPrivateKey(23-28)OSSLMLDSAPrivateKey(31-38)OSSLMLDSAPrivateKey(40-44)isOfType(90-93)isOfType(90-90)setValue(95-103)setValue(95-95)setSeed(105-113)setSeed(105-105)PKCS8Encode(116-135)PKCS8Encode(116-116)PKCS8Decode(138-151)PKCS8Decode(138-138)setFromOSSL(62-87)setFromOSSL(62-62)getOSSLKey(154-159)getOSSLKey(154-154)createOSSLKey(162-210)createOSSLKey(162-162)src/lib/crypto/MLDSAPrivateKey.h (1)
MLDSAPrivateKey(13-47)src/lib/crypto/MLDSAPrivateKey.cpp (6)
isOfType(17-20)isOfType(17-17)setValue(55-58)setValue(55-55)setSeed(65-68)setSeed(65-65)src/lib/crypto/OSSLMLDSAPublicKey.cpp (10)
isOfType(84-87)isOfType(84-84)setValue(89-97)setValue(89-89)setFromOSSL(65-81)setFromOSSL(65-65)getOSSLKey(100-105)getOSSLKey(100-100)createOSSLKey(108-146)createOSSLKey(108-108)
src/lib/crypto/OSSLMLDSA.cpp (1)
src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(226-235)mldsaParameterSet2Name(226-226)
src/lib/crypto/OSSLMLDSA.h (1)
src/lib/crypto/OSSLMLDSA.cpp (42)
sign(27-162)sign(27-29)signInit(164-170)signInit(164-165)signUpdate(172-177)signUpdate(172-172)signFinal(179-184)signFinal(179-179)verify(187-323)verify(187-189)verifyInit(325-331)verifyInit(325-326)verifyUpdate(333-338)verifyUpdate(333-333)verifyFinal(340-345)verifyFinal(340-340)encrypt(348-354)encrypt(348-349)checkEncryptedDataSize(375-380)checkEncryptedDataSize(375-375)decrypt(357-363)decrypt(357-358)getMinKeySize(365-368)getMinKeySize(365-365)getMaxKeySize(370-373)getMaxKeySize(370-370)generateKeyPair(383-446)generateKeyPair(383-383)reconstructKeyPair(448-484)reconstructKeyPair(448-448)reconstructPublicKey(486-507)reconstructPublicKey(486-486)reconstructPrivateKey(509-530)reconstructPrivateKey(509-509)reconstructParameters(547-567)reconstructParameters(547-547)newPublicKey(532-535)newPublicKey(532-532)newPrivateKey(537-540)newPrivateKey(537-537)newParameters(542-545)newParameters(542-542)
src/lib/crypto/OSSLMLDSAPublicKey.h (3)
src/lib/crypto/OSSLMLDSAPublicKey.cpp (14)
OSSLMLDSAPublicKey(18-21)OSSLMLDSAPublicKey(23-28)OSSLMLDSAPublicKey(31-38)OSSLMLDSAPublicKey(40-44)isOfType(84-87)isOfType(84-84)setValue(89-97)setValue(89-89)setFromOSSL(65-81)setFromOSSL(65-65)getOSSLKey(100-105)getOSSLKey(100-100)createOSSLKey(108-146)createOSSLKey(108-108)src/lib/crypto/MLDSAPublicKey.h (1)
MLDSAPublicKey(14-45)src/lib/crypto/MLDSAPublicKey.cpp (4)
isOfType(17-20)isOfType(17-17)setValue(60-63)setValue(60-60)
src/lib/SoftHSM.cpp (1)
src/lib/crypto/MLDSAUtil.cpp (6)
getMLDSAPrivateKey(11-41)getMLDSAPrivateKey(11-11)getMLDSAPublicKey(43-69)getMLDSAPublicKey(43-43)setMLDSAPrivateKey(71-111)setMLDSAPrivateKey(71-71)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Windows (x64, botan)
- GitHub Check: Windows (x86, openssl)
- GitHub Check: Linux with OpenSSL 3.5.4
- GitHub Check: macOS (openssl)
- GitHub Check: Linux with OpenSSL 3.0
- GitHub Check: Linux with OpenSSL 1.1.1
- GitHub Check: Windows (x64, openssl)
- GitHub Check: Linux with Botan
- GitHub Check: macOS (botan)
🔇 Additional comments (37)
.github/workflows/ci.yml (1)
84-92: LGTM! Environment configuration follows best practices.The LDFLAGS uses the correct
-Wl,-rpath,syntax and PKG_CONFIG_PATH is properly set to ensure the build links against the locally-built OpenSSL 3.5.4 rather than system OpenSSL.src/lib/test/SignVerifyTests.cpp (3)
231-272: LGTM - ML-DSA key generation helper follows established patterns.The
generateMLDSAhelper correctly mirrors the structure ofgenerateECandgenerateED, with appropriate ML-DSA-specific attributes (CKA_PARAMETER_SET,CKK_ML_DSA,CKM_ML_DSA_KEY_PAIR_GEN).
279-279: Appropriate buffer size increase for ML-DSA signatures.ML-DSA signatures are significantly larger than classical signatures (e.g., ML-DSA-87 produces ~4627 byte signatures), so increasing the buffer from 256 bytes to 64KB is necessary.
849-937: Comprehensive ML-DSA test coverage.The test exercises all four key storage combinations (public/private session/token keys) with all six
CK_SIGN_ADDITIONAL_CONTEXTparameter variants (three hedge types, each with and without context). The context buffer issue from previous reviews has been addressed.src/lib/test/SignVerifyTests.h (1)
52-54: ML-DSA test declarations properly guarded.The test registration, public test method, and protected helper are all consistently wrapped with
#ifdef WITH_ML_DSA, matching the pattern used for EdDSA.Also applies to: 66-68, 78-80
src/lib/crypto/AsymmetricAlgorithm.h (2)
56-57: MLDSA enum additions are appropriate.Adding
MLDSAto bothAsymAlgo::TypeandAsymMech::Typeenums follows the established pattern for other algorithms.Also applies to: 96-97
121-153: SIGN_ADDITIONAL_CONTEXT struct properly designed.The struct correctly:
- Uses
const unsigned char*to signal non-ownership of context data- Deletes copy constructor/assignment to prevent shallow copy bugs
- Provides clear documentation comment explaining the design rationale
- Offers flexible constructors for various initialization patterns
Based on learnings,
Session::setParametershandles deep-copy at a higher level.src/lib/crypto/OSSLMLDSA.cpp (4)
27-162: Sign function implementation looks correct.The
sign()function properly:
- Validates mechanism, key type, and parameters
- Handles
SIGN_ADDITIONAL_CONTEXTwith NULL pointer and length validation- Checks
EVP_SIGNATURE_fetchreturn value (line 124)- Checks
EVP_PKEY_sign_message_initreturn value (line 137)- Uses
<= 0forEVP_PKEY_signerror checks (lines 144, 151)- Cleans up resources on all error paths
186-323: Verify function implementation looks correct.The
verify()function properly:
- Validates mechanism, key type, and parameters
- Validates signature length matches expected output length
- Handles
SIGN_ADDITIONAL_CONTEXTwith NULL pointer validation (lines 251-254)- Distinguishes between invalid signature (
verifyRV == 0) and errors (verifyRV < 0) at lines 314-320- Cleans up resources appropriately
383-446: Key generation implementation looks correct.The
generateKeyPair()function properly:
- Uses
<= 0checks forEVP_PKEY_keygen_initandEVP_PKEY_generate(lines 417, 424)- Increments reference count before passing to wrappers (lines 433, 435)
- Frees the original reference after wrappers take ownership (line 443)
129-136: No action required. The code correctly pairsEVP_PKEY_sign_message_initwithEVP_PKEY_signandEVP_PKEY_verify_message_initwithEVP_PKEY_verifyfor one-shot ML-DSA signing and verification in OpenSSL 3.5, as documented in the official OpenSSL specification.src/lib/SoftHSM.h (1)
374-389: ML-DSA generation declaration properly guarded.The
generateMLDSAdeclaration is correctly wrapped with#ifdef WITH_ML_DSA, matching the implementation guard in SoftHSM.cpp and following the pattern of other feature-gated methods likederiveECDHandderiveEDDSA.src/lib/session_mgr/Session.cpp (1)
355-389: LGTM! Deep-copy implementation for ML-DSA context is correct.The implementation correctly:
- Validates NULL context pointer when
ctxLen > 0(line 360-363)- Allocates a single contiguous buffer for struct + context bytes
- Properly repoints
stored->contextAsCharinside the buffer- Sets
paramLentosizeof(SIGN_ADDITIONAL_CONTEXT)for consistent retrievalOne minor observation: there's inconsistent indentation (mix of tabs and spaces at lines 357-363 vs 365-388), but this is a stylistic nitpick.
Based on learnings, this aligns with the agreed approach to avoid transient malloc in SoftHSM and let Session handle the deep-copy.
src/lib/crypto/OSSLMLDSAPublicKey.cpp (2)
17-59: LGTM! Constructors, destructor, and move semantics are well-implemented.The move semantics correctly:
- Transfer ownership of
pkeyand null out the source- Free existing
pkeybefore stealing in move-assignment- Call base class move operations
Copy operations are properly deleted in the header to prevent double-free.
64-97: LGTM! Key extraction and value management are correct.
setFromOSSLproperly extracts the public key using max buffer sizeisOfTypecorrectly chains to base class for polymorphismsetValueinvalidates the cachedpkeyto maintain consistencysrc/lib/crypto/test/MLDSATests.cpp (6)
26-44: LGTM! Test fixture setup and teardown are correct.The setup properly obtains the MLDSA algorithm from CryptoFactory, and teardown correctly recycles it. The
fflush(stdout)ensures test output is visible before potential crashes.
46-67: LGTM! Key generation test covers all parameter sets.The test iterates over all ML-DSA parameter sets (44, 65, 87), generates key pairs, and validates that the parameter set is correctly reflected in both public and private keys. Resources are properly recycled.
69-123: LGTM! Serialization test is thorough.The test validates:
- Parameter serialization/deserialization round-trip
- Key pair generation from deserialized parameters
- Key pair serialization/deserialization round-trip
- Consistency of private key (parameter set, value, seed) and public key (parameter set, value)
125-161: LGTM! PKCS#8 encoding/decoding test is correct.Tests the PKCS8Encode/PKCS8Decode round-trip for private keys across all parameter sets, verifying parameter set and value consistency.
163-194: LGTM! Basic signing/verifying test is correct.Covers all parameter sets with random data, validates sign and verify operations work correctly.
269-302: LGTM! Context-too-long test correctly expects sign failure.The test validates that signing fails when context exceeds the maximum allowed length (255 bytes per ML-DSA spec). Uses
CPPUNIT_ASSERT_EQUAL(false, ...)for clear failure expectation.src/lib/crypto/OSSLMLDSAPublicKey.h (2)
16-55: LGTM! Class declaration is well-structured.The header properly:
- Inherits from
MLDSAPublicKey- Deletes copy constructor and copy assignment (preventing double-free)
- Declares noexcept move operations
- Declares virtual methods matching the implementation
- Keeps
pkeyownership in private scope withcreateOSSLKeyhelper
7-8: LGTM! Include guards are correct and consistent.The guards use
_SOFTHSM_V2_OSSLMLDSAPUBLICKEY_Hconsistently, and the trailing comment at line 58 now correctly matches the guard name.Also applies to: 57-58
src/lib/crypto/MLDSAPrivateKey.cpp (4)
13-20: LGTM! Type identification is correctly implemented.The static type string and
isOfTypeimplementation follow the established pattern in the codebase.
27-53: LGTM! Parameter set and output length inference from key size is correct.The switch statements correctly map private key lengths to parameter sets and signature lengths using
MLDSAParametersconstants. Returning 0 for unknown sizes is a safe fallback. Based on learnings, this inference-based approach is the intended design for runtime MLDSA keys.
75-97: LGTM! Serialization and deserialization are correctly implemented.
serialise()concatenates seed and value in the correct orderdeserialise()validates both seed and value are non-empty before assignment- Uses
ByteString::chainDeserialisefor proper sequential deserialization
1-11: The review comment is incorrect and contradicts the project's established policy.MLDSAPrivateKey.cpp is an abstract base key class that should NOT have WITH_ML_DSA guards. This follows the same pattern as other abstract base classes (RSAPrivateKey.cpp, ECPrivateKey.cpp, DSAPrivateKey.cpp), which are also included unconditionally in SoftHSM.cpp without guards.
Feature gating is handled at the OpenSSL-backed implementation level (OSSLMLDSAPublicKey.cpp) and in the build system via mechanism tables and CryptoFactory—not by wrapping abstract base classes in WITH_* guards. Adding guards to MLDSAPrivateKey.cpp would deviate from this established architecture.
Likely an incorrect or invalid review comment.
src/lib/SoftHSM.cpp (3)
65-70: ML‑DSA integration into object types and mechanism tables looks consistentHeaders, P11 object creation, supported-mechanism registration, and C_GetMechanismInfo wiring for CKM_ML_DSA/CKM_ML_DSA_KEY_PAIR_GEN under WITH_ML_DSA follow the existing patterns used for EDDSA/ECDSA/DSA and respect feature gating via CryptoFactory. No issues from a PKCS#11 or factory-usage perspective.
Based on learnings, this aligns with the preferred CKP_ML_DSA_* usage and mechanism gating.
Also applies to: 149-152, 170-173, 842-845, 950-952, 1051-1063, 1353-1365
4205-4208: ML‑DSA SIGN_ADDITIONAL_CONTEXT handling is well‑defined and symmetric in sign/verifyThe CKM_ML_DSA branches in AsymSignInit/AsymVerifyInit:
- Zero‑initialize SIGN_ADDITIONAL_CONTEXT and explicitly set context pointer/length and hedgeVariant only when parameters are supplied.
- Validate ulContextLen ≤ 255 and pContext != NULL when ulContextLen > 0.
- Treat unknown/omitted hedgeVariant as CKH_HEDGE_PREFERRED, matching the PKCS#11 v3.2 default.
- Pass the struct through Session::setParameters once, keeping stack lifetime safe with the Session deep‑copy pattern from the ML‑DSA additional-context learning.
Sign and verify paths now mirror each other and enforce the same validation, while keeping ML‑DSA single‑part‑only as intended.
Based on learnings, the ownership and defaulting model matches the agreed ML‑DSA convention.
Also applies to: 4476-4525, 4614-4633, 5286-5288, 5554-5600, 5689-5708
6232-6264: ML‑DSA keygen and wrap/unwrap plumbing is coherent with the rest of SoftHSM
- C_GenerateKeyPair routes CKM_ML_DSA_KEY_PAIR_GEN to generateMLDSA only for CKK_ML_DSA and enforces that keyType matches on both public/private templates.
- generateMLDSA reads CKA_PARAMETER_SET as CK_ULONG (with size check), requires it, restricts to CKP_ML_DSA_44/65/87, and logs “Unsupported parameter set: %lu” before returning CKR_PARAMETER_SET_NOT_SUPPORTED, which matches the recorded convention.
- The function stores CKA_PARAMETER_SET, CKA_VALUE, and CKA_SEED on OSObjects, respecting CKA_PRIVATE when encrypting attributes.
- C_WrapKey/C_UnwrapKey hook ML‑DSA private keys via MLDSAUtil::{get,set}MLDSAPrivateKey with AsymAlgo::MLDSA, parallel to the RSA/DSA/EC/EDDSA flows.
The end‑to‑end ML‑DSA lifecycle (generate → store → wrap/unwrap) looks internally consistent and matches the MLDSAParameters/MLDSAUtil patterns in the crypto layer.
Based on learnings, the parameter‑set checks and logging are in the expected form.
Also applies to: 6296-6381, 6454-6463, 7052-7054, 7096-7099, 7777-7780
src/lib/crypto/OSSLMLDSA.h (7)
1-13: LGTM! Header and includes are correct.The include guard mismatch noted in previous reviews has been resolved. The includes are appropriate for an OpenSSL-backed ML-DSA implementation.
14-18: LGTM! Class declaration follows standard pattern.The virtual destructor is appropriate for a polymorphic class.
20-30: LGTM! Signing and verification API follows AsymmetricAlgorithm interface.The multi-part methods (signInit/Update/Final, verifyInit/Update/Final) are declared but return false in the implementation, consistent with ML-DSA being single-part only per PKCS#11 3.2. This pattern aligns with the AsymmetricAlgorithm interface requirements.
32-39: LGTM! Encryption/decryption and key size methods properly declared.The encrypt/decrypt methods are declared but not supported (ML-DSA is signature-only), which is expected for the AsymmetricAlgorithm interface. The key size methods correctly return ML-DSA-44 and ML-DSA-87 private key lengths.
41-49: LGTM! Complete key factory interface.All key lifecycle methods are properly declared and implemented in the corresponding .cpp file.
56-57: LGTM! Include guard properly closed.The closing guard correctly matches the opening
_SOFTHSM_V2_OSSLMLDSA_Hmacro, resolving the issue from previous reviews.
51-53: > Likely an incorrect or invalid review comment.
ec9c5f2 to
16cffe0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (5)
src/lib/crypto/OSSLMLDSAPrivateKey.h (1)
67-68: Fix closing include guard comment typo.Line 68 has a copy-paste error:
OSSLECPRIVATEKEYshould beOSSLMLDSAPRIVATEKEYto match the include guard defined on line 7.Apply this diff:
#endif // WITH_ML_DSA -#endif // !_SOFTHSM_V2_OSSLECPRIVATEKEY_H +#endif // !_SOFTHSM_V2_OSSLMLDSAPRIVATEKEY_Hsrc/lib/SoftHSM.cpp (2)
6573-6591: AES_CBC/DES3_CBC wrap uses a zero‑length IV; AES_CBC wrap is effectively constrained by backend behaviorFor the non‑PAD CBC modes in WrapKeySym,
blocksizeis never set (only the *_CBC_PAD cases assign it), so:
- For CKM_AES_CBC / CKM_DES3_CBC the IV ByteString is resized to 0 and encryptInit is called with an empty IV.
- Whether this works depends entirely on the symmetric backend’s tolerance for a zero‑length IV; many implementations will reject it, making AES_CBC/DES3_CBC wrapping fail with CKR_MECHANISM_INVALID instead of performing a proper CBC wrap.
If you want AES_CBC/DES3_CBC wrapping to be reliably usable (beyond “works as long as the backend happens to ignore IV length”), consider setting
blocksize(16 for AES, 8 for 3DES) in the non‑PAD cases and validatingpMechanism->ulParameterLen == blocksizebefore copying the IV, mirroring the PAD handling. Given earlier discussion where this was intentionally left out, this can be treated as a robustness/behavioral polish rather than a blocker.Also applies to: 6616-6622
10173-10228: generateMLDSA: parameter‑set validation is correct; consider optional NULL‑safety for CKA_PARAMETER_SET
- Reading CKA_PARAMETER_SET as a CK_ULONG, requiring
ulValueLen == sizeof(CK_ULONG), and enforcing membership in {CKP_ML_DSA_44, CKP_ML_DSA_65, CKP_ML_DSA_87} with “Unsupported parameter set: %lu” and CKR_PARAMETER_SET_NOT_SUPPORTED matches the project’s conventions for ML‑DSA parameter sets. Based on learnings.- Public/private key object creation and attribute population (CKA_PARAMETER_SET, CKA_VALUE, CKA_SEED with optional encryption) follow the same template as the other key‑gen helpers and look correct.
One optional hardening point, already discussed earlier: you currently assume
pPublicKeyTemplate[i].pValueis non‑NULL whenulValueLen == sizeof(CK_ULONG)for CKA_PARAMETER_SET. If you ever want to defend more robustly against malformed templates, adding apValue != NULL_PTRcheck here and returning CKR_ATTRIBUTE_VALUE_INVALID on NULL would avoid a possible NULL deref without changing the happy path.Also applies to: 10288-10310, 10369-10392
src/lib/crypto/OSSLMLDSA.cpp (2)
129-156: Critical: Incorrect API pairing and incomplete error checking in sign().Two critical issues:
API mismatch:
EVP_PKEY_sign_message_init(lines 131, 135) is designed for streaming/multi-part signatures and must be paired withEVP_PKEY_sign_message_update+EVP_PKEY_sign_message_final. It should NOT be used with the monolithicEVP_PKEY_sign(lines 144, 151). For one-shot signing, useEVP_PKEY_sign_init_exinstead.Incomplete error check (line 137):
if (!initRv)only catchesinitRv == 0, missing negative error codes (e.g.,-2for unsupported operation). Useif (initRv <= 0)like you correctly do at lines 417, 424.Apply this diff to fix both issues:
EVP_SIGNATURE *sig_alg = EVP_SIGNATURE_fetch(NULL, name, NULL); if (sig_alg == NULL) { ERROR_MSG("ML-DSA EVP_SIGNATURE_fetch failed (0x%08X)", ERR_get_error()); EVP_PKEY_CTX_free(sctx); return false; } - int initRv; - if (param != NULL) { - initRv = EVP_PKEY_sign_message_init(sctx, sig_alg, params); - } - else - { - initRv = EVP_PKEY_sign_message_init(sctx, sig_alg, NULL); - } - if (!initRv) { - ERROR_MSG("ML-DSA sign_message_init failed (0x%08X)", ERR_get_error()); + int initRv = (param != NULL) + ? EVP_PKEY_sign_init_ex(sctx, sig_alg, params) + : EVP_PKEY_sign_init_ex(sctx, sig_alg, NULL); + if (initRv <= 0) { + ERROR_MSG("ML-DSA sign_init_ex failed (0x%08X)", ERR_get_error()); EVP_SIGNATURE_free(sig_alg); EVP_PKEY_CTX_free(sctx); return false; } /* Calculate the required size for the signature by passing a NULL buffer. */ if (EVP_PKEY_sign(sctx, NULL, &len, dataToSign.const_byte_str(), dataToSign.size()) <= 0) { ERROR_MSG("ML-DSA sign size query failed (0x%08X)", ERR_get_error()); EVP_SIGNATURE_free(sig_alg); EVP_PKEY_CTX_free(sctx); return false; } signature.resize(len); if (EVP_PKEY_sign(sctx, &signature[0], &len, dataToSign.const_byte_str(), dataToSign.size()) <= 0) { ERROR_MSG("ML-DSA sign failed (0x%08X)", ERR_get_error()); EVP_SIGNATURE_free(sig_alg); EVP_PKEY_CTX_free(sctx); return false; } + // Trim to actual signature size (len is updated by EVP_PKEY_sign) + signature.resize(len); EVP_SIGNATURE_free(sig_alg); EVP_PKEY_CTX_free(sctx);
295-311: Critical: Incorrect API pairing and incomplete error checking in verify().Same two issues as
sign():
API mismatch:
EVP_PKEY_verify_message_init(lines 297, 301) requiresEVP_PKEY_verify_message_update+EVP_PKEY_verify_message_final, not the monolithicEVP_PKEY_verify(line 310). UseEVP_PKEY_verify_init_exfor one-shot verification.Incomplete error check (line 304):
if (!initRv)misses negative error codes. Useif (initRv <= 0).Apply this diff:
sig_alg = EVP_SIGNATURE_fetch(NULL, name, NULL); if (sig_alg == NULL) { ERROR_MSG("ML-DSA EVP_SIGNATURE_fetch failed (0x%08X)", ERR_get_error()); EVP_PKEY_CTX_free(vctx); return false; } - int initRv; - if (param != NULL) { - initRv = EVP_PKEY_verify_message_init(vctx, sig_alg, params); - } - else - { - initRv = EVP_PKEY_verify_message_init(vctx, sig_alg, NULL); - } + int initRv = (param != NULL) + ? EVP_PKEY_verify_init_ex(vctx, sig_alg, params) + : EVP_PKEY_verify_init_ex(vctx, sig_alg, NULL); - if (!initRv) { + if (initRv <= 0) { ERROR_MSG("ML-DSA verify init failed (0x%08X)", ERR_get_error()); EVP_PKEY_CTX_free(vctx); EVP_SIGNATURE_free(sig_alg); return false; } int verifyRV = EVP_PKEY_verify(vctx, signature.const_byte_str(), signature.size(), originalData.const_byte_str(), originalData.size());
🧹 Nitpick comments (5)
src/lib/crypto/OSSLMLDSAPublicKey.cpp (1)
108-146: Potential nullnamepassed toEVP_PKEY_CTX_new_from_name.If
getParameterSet()returns 0 (unknown parameter set),OSSL::mldsaParameterSet2NamereturnsNULL, andEVP_PKEY_CTX_new_from_name(NULL, NULL, NULL)will fail with a generic "Could not create context" error. This makes debugging harder when an unsupported key length is encountered.Consider adding a diagnostic check before the context creation:
const char* name = OSSL::mldsaParameterSet2Name(getParameterSet()); + if (name == NULL) + { + ERROR_MSG("Unknown ML-DSA parameter set for public key length: %zu", localValue.size()); + return; + } int selection = 0;src/lib/crypto/MLDSAPublicKey.cpp (1)
27-28: Minor: Comment mismatch with function.The comment says "Get the bit length" but the function is
getParameterSet(). The header file has the correct comment.-// Get the bit length +// Get the parameter set unsigned long MLDSAPublicKey::getParameterSet() constsrc/lib/crypto/MLDSAPrivateKey.cpp (1)
41-42: Minor: Typo in comment."signatureLength length" has redundant "length".
-// Get the signatureLength length +// Get the signature length unsigned long MLDSAPrivateKey::getOutputLength() constsrc/lib/SoftHSM.cpp (2)
65-70: ML‑DSA wiring (includes, P11 objects, mechanisms, mechanism info, key‑pair dispatch) looks coherent
- The WITH_ML_DSA‑guarded includes, new P11MLDSA{Public,Private}KeyObj branches, and prepareSupportedMechanisms entries for CKM_ML_DSA_KEY_PAIR_GEN / CKM_ML_DSA are consistent with the existing patterns for EDDSA and GOST.
- C_GetMechanismInfo correctly derives ML‑DSA key size ranges from CryptoFactory and exposes appropriate flags (GENERATE_KEY_PAIR for *_KEY_PAIR_GEN, SIGN|VERIFY for CKM_ML_DSA).
- C_GenerateKeyPair routing for CKM_ML_DSA_KEY_PAIR_GEN → generateMLDSA is clean and matches the validation style used for other key types.
One optional consistency tweak: recent guidance for this file prefers keeping algorithm key/parameter headers unconditionally included and handling feature‑gating only via WITH_* in mechanism tables and CryptoFactory; consider dropping the WITH_ML_DSA guard around the MLDSA* includes in a follow‑up for alignment with that policy. Based on learnings.
Also applies to: 149-152, 171-173, 842-845, 950-952, 1051-1063, 6323-6325, 6354-6355, 6379-6380
4205-4208: ML‑DSA additional‑context handling is sound; multipart sign/verify remains intentionally unsupported
- Zero‑initializing SIGN_ADDITIONAL_CONTEXT and explicitly setting context pointer/length and hedgeVariant in both AsymSignInit and AsymVerifyInit avoids UB and matches the Session::setParameters deep‑copy scheme for ML‑DSA additional context.
- Validation of CK_SIGN_ADDITIONAL_CONTEXT (size check, contextLen ≤ 255, non‑NULL pContext when len > 0) is good and symmetric between sign and verify.
- For CKM_ML_DSA you set
bAllowMultiPartOp = falsein both init paths, so C_SignUpdate/C_SignFinal and the corresponding verify multipart APIs will continue to fail with CKR_OPERATION_NOT_INITIALIZED for ML‑DSA, matching the current behavior xipki reported.If the intent is to support multipart ML‑DSA as per the PKCS#11 v3.2 draft, you will need a follow‑up that enables
bAllowMultiPartOpand wires ML‑DSA into signInit/verifyInit + signUpdate/verifyUpdate/Final; otherwise it would be good to explicitly document that CKM_ML_DSA is single‑part‑only in SoftHSM for now so callers don’t expect multipart to work.Also applies to: 4476-4525, 4614-4632, 5286-5288, 5554-5601, 5690-5708
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (20)
.github/workflows/ci.yml(1 hunks)src/lib/SoftHSM.cpp(35 hunks)src/lib/SoftHSM.h(1 hunks)src/lib/crypto/AsymmetricAlgorithm.h(3 hunks)src/lib/crypto/MLDSAPrivateKey.cpp(1 hunks)src/lib/crypto/MLDSAPublicKey.cpp(1 hunks)src/lib/crypto/MLDSAPublicKey.h(1 hunks)src/lib/crypto/MLDSAUtil.h(1 hunks)src/lib/crypto/OSSLMLDSA.cpp(1 hunks)src/lib/crypto/OSSLMLDSA.h(1 hunks)src/lib/crypto/OSSLMLDSAKeyPair.h(1 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.cpp(1 hunks)src/lib/crypto/OSSLMLDSAPrivateKey.h(1 hunks)src/lib/crypto/OSSLMLDSAPublicKey.cpp(1 hunks)src/lib/crypto/OSSLMLDSAPublicKey.h(1 hunks)src/lib/crypto/test/MLDSATests.cpp(1 hunks)src/lib/crypto/test/MLDSATests.h(1 hunks)src/lib/session_mgr/Session.cpp(1 hunks)src/lib/test/SignVerifyTests.cpp(2 hunks)src/lib/test/SignVerifyTests.h(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- src/lib/crypto/test/MLDSATests.h
- .github/workflows/ci.yml
- src/lib/crypto/OSSLMLDSA.h
🧰 Additional context used
🧠 Learnings (12)
📓 Common learnings
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.370Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:5550-5596
Timestamp: 2025-10-27T16:44:57.865Z
Learning: SoftHSM ML‑DSA additional context: avoid transient malloc in SoftHSM::{AsymSignInit, AsymVerifyInit}; let Session::setParameters deep‑copy SIGN_ADDITIONAL_CONTEXT by allocating one buffer for struct + context bytes and fixing the stored pointer; Session::resetOp frees m_pParameters so both struct and context are released.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:13265-13282
Timestamp: 2025-10-13T09:43:45.885Z
Learning: SoftHSM OAEP policy: In SoftHSM::MechParamCheckRSAPKCSOAEP (src/lib/SoftHSM.cpp), enforce that the MGF1 variant must correspond to the selected hashAlg (e.g., SHA-256 -> CKG_MGF1_SHA256). Mismatches should return CKR_ARGUMENTS_BAD with "Hash and MGF don't match". This mirrors the existing PSS enforcement.
Learnt from: JoaoHenrique12
Repo: softhsm/SoftHSMv2 PR: 823
File: src/lib/SoftHSM.cpp:58-58
Timestamp: 2025-11-11T19:42:46.886Z
Learning: SoftHSM include policy: Algorithm key/parameter headers (e.g., SLHParameters, SLH*Key) are included unconditionally in SoftHSM.cpp/SoftHSM.h; feature gating is handled in mechanism tables and CryptoFactory (WITH_*). Avoid wrapping such includes in WITH_* guards.
📚 Learning: 2025-08-19T09:23:25.434Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:4193-4196
Timestamp: 2025-08-19T09:23:25.434Z
Learning: MLDSA parameter set inference: In src/lib/crypto/MLDSAPrivateKey.{h,cpp} and MLDSAPublicKey.{h,cpp}, getParameterSet() maps key material length to CKP_ML_DSA_44/65/87, and there is no setParameterSet(). Runtime MLDSA keys used by SoftHSM (e.g., in C_SignInit/C_VerifyInit via MLDSAUtil) rely on this inference; no explicit parameter-set assignment is required.
Applied to files:
src/lib/crypto/MLDSAPublicKey.hsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/SoftHSM.hsrc/lib/crypto/MLDSAUtil.hsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/MLDSAPublicKey.cppsrc/lib/test/SignVerifyTests.hsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/test/MLDSATests.cpp
📚 Learning: 2025-08-18T17:59:30.693Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/MLDSAParameters.h:42-44
Timestamp: 2025-08-18T17:59:30.693Z
Learning: In MLDSAParameters.h, the author prefers to keep PKCS#11 constant references (CKP_ML_DSA_*) rather than explicit numeric values for better code clarity and maintainability.
Applied to files:
src/lib/crypto/MLDSAPublicKey.hsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/SoftHSM.hsrc/lib/crypto/MLDSAUtil.hsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/MLDSAPublicKey.cppsrc/lib/test/SignVerifyTests.hsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/test/MLDSATests.cpp
📚 Learning: 2025-08-18T19:46:46.659Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:10044-10055
Timestamp: 2025-08-18T19:46:46.659Z
Learning: In SoftHSM::generateMLDSA (src/lib/SoftHSM.cpp), the project prefers using CKP_ML_DSA_* constants for parameter set checks and logs "Unsupported parameter set: %lu". The code currently returns CKR_PARAMETER_SET_NOT_SUPPORTED for unsupported sets.
Applied to files:
src/lib/crypto/MLDSAPublicKey.hsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/SoftHSM.hsrc/lib/crypto/MLDSAUtil.hsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/MLDSAPublicKey.cppsrc/lib/test/SignVerifyTests.hsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/test/MLDSATests.cpp
📚 Learning: 2025-10-27T16:44:57.865Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/SoftHSM.cpp:5550-5596
Timestamp: 2025-10-27T16:44:57.865Z
Learning: SoftHSM ML‑DSA additional context: avoid transient malloc in SoftHSM::{AsymSignInit, AsymVerifyInit}; let Session::setParameters deep‑copy SIGN_ADDITIONAL_CONTEXT by allocating one buffer for struct + context bytes and fixing the stored pointer; Session::resetOp frees m_pParameters so both struct and context are released.
Applied to files:
src/lib/crypto/MLDSAPublicKey.hsrc/lib/crypto/AsymmetricAlgorithm.hsrc/lib/SoftHSM.hsrc/lib/crypto/MLDSAUtil.hsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/MLDSAPublicKey.cppsrc/lib/test/SignVerifyTests.hsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/MLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/test/MLDSATests.cpp
📚 Learning: 2025-10-13T09:42:31.270Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:3238-3266
Timestamp: 2025-10-13T09:42:31.270Z
Learning: In src/lib/SoftHSM.cpp, SoftHSM::AsymDecryptInit should use MechParamCheckRSAPKCSOAEP for CKM_RSA_PKCS_OAEP to keep OAEP parameter validation identical to AsymEncryptInit, and avoid redundant manual checks for pMechanism->pParameter and MGF allowlists.
Applied to files:
src/lib/crypto/AsymmetricAlgorithm.hsrc/lib/SoftHSM.hsrc/lib/crypto/MLDSAUtil.hsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/test/SignVerifyTests.hsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/test/MLDSATests.cpp
📚 Learning: 2025-11-11T19:42:46.886Z
Learnt from: JoaoHenrique12
Repo: softhsm/SoftHSMv2 PR: 823
File: src/lib/SoftHSM.cpp:58-58
Timestamp: 2025-11-11T19:42:46.886Z
Learning: SoftHSM include policy: Algorithm key/parameter headers (e.g., SLHParameters, SLH*Key) are included unconditionally in SoftHSM.cpp/SoftHSM.h; feature gating is handled in mechanism tables and CryptoFactory (WITH_*). Avoid wrapping such includes in WITH_* guards.
Applied to files:
src/lib/crypto/AsymmetricAlgorithm.hsrc/lib/SoftHSM.hsrc/lib/crypto/MLDSAUtil.hsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cppsrc/lib/crypto/test/MLDSATests.cpp
📚 Learning: 2025-10-13T09:43:45.885Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 818
File: src/lib/SoftHSM.cpp:13265-13282
Timestamp: 2025-10-13T09:43:45.885Z
Learning: SoftHSM OAEP policy: In SoftHSM::MechParamCheckRSAPKCSOAEP (src/lib/SoftHSM.cpp), enforce that the MGF1 variant must correspond to the selected hashAlg (e.g., SHA-256 -> CKG_MGF1_SHA256). Mismatches should return CKR_ARGUMENTS_BAD with "Hash and MGF don't match". This mirrors the existing PSS enforcement.
Applied to files:
src/lib/SoftHSM.hsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/test/SignVerifyTests.hsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSA.cpp
📚 Learning: 2025-09-11T16:54:00.370Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 815
File: src/lib/SoftHSM.cpp:6543-6546
Timestamp: 2025-09-11T16:54:00.370Z
Learning: SoftHSM PR #815 (pkcs11.h 3.1.0 update, CK_RSA_AES_KEY_WRAP_PARAMS fix): Maintainer bukka prefers to keep scope minimal (header sync and param rename only); broader OAEP parameter enforcement or backend plumbing is out of scope for this PR and should be handled in a follow-up issue.
Applied to files:
src/lib/SoftHSM.hsrc/lib/crypto/MLDSAUtil.hsrc/lib/session_mgr/Session.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.cppsrc/lib/crypto/OSSLMLDSAKeyPair.hsrc/lib/crypto/OSSLMLDSAPublicKey.cppsrc/lib/crypto/OSSLMLDSAPrivateKey.hsrc/lib/test/SignVerifyTests.cppsrc/lib/crypto/OSSLMLDSAPublicKey.hsrc/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSA.cppsrc/lib/crypto/test/MLDSATests.cpp
📚 Learning: 2025-08-11T16:42:23.012Z
Learnt from: bukka
Repo: softhsm/SoftHSMv2 PR: 806
File: src/lib/test/p11test.cpp:81-84
Timestamp: 2025-08-11T16:42:23.012Z
Learning: In SoftHSM test files (like p11test.cpp and cryptotest.cpp), error handling for OSSL_PROVIDER_load() calls for "legacy" and "default" providers is intentionally omitted because these providers won't fail in practice and the test code is kept deliberately simple.
Applied to files:
src/lib/SoftHSM.cppsrc/lib/crypto/OSSLMLDSA.cpp
📚 Learning: 2025-08-18T19:35:33.938Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: src/lib/crypto/OSSLMLDSA.cpp:195-204
Timestamp: 2025-08-18T19:35:33.938Z
Learning: In OpenSSL, EVP_PKEY_verify_message does not exist. EVP_PKEY_verify_message_init is designed for streaming verification and should be paired with EVP_PKEY_CTX_set_signature, EVP_PKEY_verify_message_update, and EVP_PKEY_verify_message_final - not with EVP_PKEY_verify.
Applied to files:
src/lib/crypto/OSSLMLDSA.cpp
📚 Learning: 2025-08-18T17:54:37.645Z
Learnt from: antoinelochet
Repo: softhsm/SoftHSMv2 PR: 809
File: m4/acx_openssl_mldsa.m4:10-35
Timestamp: 2025-08-18T17:54:37.645Z
Learning: For OpenSSL feature detection in autoconf macros, prefer functional tests (like EVP_PKEY_CTX_new_from_name) over version number checks, as the functional approach directly tests the actual capability and is more reliable across different OpenSSL builds where features may be backported or disabled.
Applied to files:
src/lib/crypto/OSSLMLDSA.cpp
🧬 Code graph analysis (11)
src/lib/crypto/MLDSAUtil.h (1)
src/lib/crypto/MLDSAUtil.cpp (6)
getMLDSAPrivateKey(11-41)getMLDSAPrivateKey(11-11)getMLDSAPublicKey(43-69)getMLDSAPublicKey(43-43)setMLDSAPrivateKey(71-111)setMLDSAPrivateKey(71-71)
src/lib/crypto/MLDSAPublicKey.cpp (2)
src/lib/crypto/MLDSAPrivateKey.cpp (14)
isOfType(17-20)isOfType(17-17)getValue(60-63)getValue(60-60)getParameterSet(28-39)getParameterSet(28-28)getOutputLength(42-53)getOutputLength(42-42)setValue(55-58)setValue(55-55)serialise(76-80)serialise(76-76)deserialise(82-97)deserialise(82-82)src/lib/crypto/MLDSAParameters.cpp (6)
getParameterSet(22-25)getParameterSet(22-22)serialise(34-37)serialise(34-34)deserialise(39-50)deserialise(39-39)
src/lib/crypto/OSSLMLDSAKeyPair.h (5)
src/lib/crypto/AsymmetricKeyPair.h (1)
AsymmetricKeyPair(42-55)src/lib/session_mgr/Session.cpp (8)
setPublicKey(434-445)setPublicKey(434-434)setPrivateKey(452-463)setPrivateKey(452-452)getPublicKey(447-450)getPublicKey(447-447)getPrivateKey(465-468)getPrivateKey(465-465)src/lib/crypto/OSSLMLDSAKeyPair.cpp (12)
setPublicKey(13-17)setPublicKey(13-13)setPrivateKey(20-25)setPrivateKey(20-20)getPublicKey(28-31)getPublicKey(28-28)getConstPublicKey(33-36)getConstPublicKey(33-33)getPrivateKey(39-42)getPrivateKey(39-39)getConstPrivateKey(44-47)getConstPrivateKey(44-44)src/lib/crypto/PublicKey.h (1)
PublicKey(40-54)src/lib/crypto/PrivateKey.h (1)
PrivateKey(41-58)
src/lib/crypto/OSSLMLDSAPublicKey.cpp (4)
src/lib/crypto/OSSLMLDSAPublicKey.h (1)
OSSLMLDSAPublicKey(16-55)src/lib/crypto/MLDSAPublicKey.cpp (6)
setValue(60-63)setValue(60-60)isOfType(17-20)isOfType(17-17)getParameterSet(28-39)getParameterSet(28-28)src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(226-235)mldsaParameterSet2Name(226-226)src/lib/crypto/MLDSAParameters.cpp (2)
getParameterSet(22-25)getParameterSet(22-22)
src/lib/crypto/OSSLMLDSAPrivateKey.h (4)
src/lib/crypto/OSSLMLDSAPrivateKey.cpp (20)
OSSLMLDSAPrivateKey(18-21)OSSLMLDSAPrivateKey(23-28)OSSLMLDSAPrivateKey(31-38)OSSLMLDSAPrivateKey(40-44)isOfType(90-93)isOfType(90-90)setValue(95-103)setValue(95-95)setSeed(105-113)setSeed(105-105)PKCS8Encode(116-135)PKCS8Encode(116-116)PKCS8Decode(138-151)PKCS8Decode(138-138)setFromOSSL(62-87)setFromOSSL(62-62)getOSSLKey(154-159)getOSSLKey(154-154)createOSSLKey(162-210)createOSSLKey(162-162)src/lib/crypto/MLDSAPrivateKey.h (1)
MLDSAPrivateKey(13-47)src/lib/crypto/MLDSAPrivateKey.cpp (6)
isOfType(17-20)isOfType(17-17)setValue(55-58)setValue(55-55)setSeed(65-68)setSeed(65-65)src/lib/crypto/OSSLMLDSAPublicKey.cpp (10)
isOfType(84-87)isOfType(84-84)setValue(89-97)setValue(89-89)setFromOSSL(65-81)setFromOSSL(65-65)getOSSLKey(100-105)getOSSLKey(100-100)createOSSLKey(108-146)createOSSLKey(108-108)
src/lib/test/SignVerifyTests.cpp (1)
src/lib/SoftHSM.cpp (4)
generateMLDSA(10175-10430)generateMLDSA(10175-10186)C_GenerateKeyPair(6270-6465)C_GenerateKeyPair(6270-6280)
src/lib/crypto/MLDSAPrivateKey.cpp (2)
src/lib/crypto/MLDSAPublicKey.cpp (12)
isOfType(17-20)isOfType(17-17)getParameterSet(28-39)getParameterSet(28-28)getOutputLength(42-53)getOutputLength(42-42)setValue(60-63)setValue(60-60)serialise(66-69)serialise(66-66)deserialise(71-83)deserialise(71-71)src/lib/crypto/MLDSAParameters.cpp (6)
getParameterSet(22-25)getParameterSet(22-22)serialise(34-37)serialise(34-34)deserialise(39-50)deserialise(39-39)
src/lib/crypto/OSSLMLDSAPublicKey.h (3)
src/lib/crypto/OSSLMLDSAPublicKey.cpp (14)
OSSLMLDSAPublicKey(18-21)OSSLMLDSAPublicKey(23-28)OSSLMLDSAPublicKey(31-38)OSSLMLDSAPublicKey(40-44)isOfType(84-87)isOfType(84-84)setValue(89-97)setValue(89-89)setFromOSSL(65-81)setFromOSSL(65-65)getOSSLKey(100-105)getOSSLKey(100-100)createOSSLKey(108-146)createOSSLKey(108-108)src/lib/crypto/MLDSAPublicKey.h (1)
MLDSAPublicKey(14-45)src/lib/crypto/MLDSAPublicKey.cpp (4)
isOfType(17-20)isOfType(17-17)setValue(60-63)setValue(60-60)
src/lib/SoftHSM.cpp (1)
src/lib/crypto/MLDSAUtil.cpp (6)
getMLDSAPrivateKey(11-41)getMLDSAPrivateKey(11-11)getMLDSAPublicKey(43-69)getMLDSAPublicKey(43-43)setMLDSAPrivateKey(71-111)setMLDSAPrivateKey(71-71)
src/lib/crypto/OSSLMLDSA.cpp (1)
src/lib/crypto/OSSLUtil.cpp (2)
mldsaParameterSet2Name(226-235)mldsaParameterSet2Name(226-226)
src/lib/crypto/test/MLDSATests.cpp (1)
src/lib/crypto/test/MLDSATests.h (1)
MLDSATests(13-52)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Windows (x86, openssl)
- GitHub Check: Linux with Botan
- GitHub Check: Windows (x64, openssl)
- GitHub Check: macOS (botan)
- GitHub Check: Linux with OpenSSL 1.1.1
- GitHub Check: Windows (x64, botan)
- GitHub Check: Linux with OpenSSL 3.0
- GitHub Check: macOS (openssl)
- GitHub Check: Linux with OpenSSL 3.5.4
🔇 Additional comments (28)
src/lib/SoftHSM.h (1)
374-389: LGTM!The
generateMLDSAdeclaration is properly guarded with#ifdef WITH_ML_DSAand follows the same signature pattern as other key generation methods (e.g.,generateRSA,generateDSA). The previous review comments about missing guards have been addressed.src/lib/crypto/OSSLMLDSAPublicKey.cpp (2)
18-59: LGTM!Constructor, destructor, and move semantics are correctly implemented:
- Default constructor initializes
pkeytoNULL- Destructor properly frees
pkeywithEVP_PKEY_free- Move constructor and move assignment correctly transfer ownership and null the source
65-81: LGTM!The
setFromOSSLimplementation correctly extracts the public key bytes from the EVP_PKEY usingEVP_PKEY_get_octet_string_paramwith appropriate buffer sizing (max pub length) and error handling.src/lib/session_mgr/Session.cpp (1)
355-388: LGTM!The ML-DSA parameter deep-copy implementation correctly:
- Validates that
contextAsCharis non-NULL whenctxLen > 0- Allocates a single contiguous buffer for the struct plus context bytes
- Copies the struct and context bytes, fixing up the internal pointer
- Handles the zero-context case by setting
contextAsChar = NULLThis follows the agreed pattern from learnings to avoid transient malloc in SoftHSM by having Session::setParameters perform the deep-copy. The buffer is freed by
resetOp()viafree(param).src/lib/crypto/MLDSAUtil.h (1)
1-30: LGTM!The utility header is well-structured:
- Proper include guard with correct
#endifcommentsWITH_ML_DSAguard wraps all MLDSA-specific content- Static utility methods match the implementations in
MLDSAUtil.cppsrc/lib/crypto/test/MLDSATests.cpp (3)
16-44: LGTM!Test setup is correctly structured:
WITH_ML_DSAguard ensures tests only compile when ML-DSA is enabledCPPUNIT_TEST_SUITE_REGISTRATIONis inside the guardsetUpproperly initializes the MLDSA algorithm instance via CryptoFactorytearDowncorrectly recycles the algorithm
46-161: LGTM!Core tests are well-implemented:
testKeyGenerationexercises all three parameter sets (CKP_ML_DSA_44/65/87) and validates parameter set inference from key materialtestSerialisationcovers parameter and key-pair serialization/deserialization with proper equality assertionstestPKCS8tests PKCS8 encoding/decoding of private keysAll tests properly recycle keys and parameters to avoid memory leaks.
163-518: LGTM!Signing/verification tests provide good coverage:
- Basic sign/verify across all parameter sets
- Hedge modes:
HEDGE_PREFERRED,HEDGE_REQUIRED,DETERMINISTIC_REQUIRED- Context string handling with and without context
- Negative tests for too-long contexts (>255 bytes per ML-DSA spec) correctly assert signing failure
The const casts for
contextStr.c_str()now use(const unsigned char *)as suggested in past reviews.src/lib/test/SignVerifyTests.cpp (3)
231-272: LGTM: ML-DSA key generation test helper.The
generateMLDSAfunction follows the established pattern fromgenerateECandgenerateED, correctly setting up ML-DSA key pair generation with the appropriate mechanism, key type, and parameter set attribute.
279-279: Appropriate buffer size increase for ML-DSA signatures.The signature buffer increase from 256 bytes to 64KB accommodates ML-DSA-87's maximum signature length (~4627 bytes). This is a safe, conservative choice.
849-937: Comprehensive ML-DSA sign/verify test coverage.The test exercises all six
CK_SIGN_ADDITIONAL_CONTEXTvariants (hedge modes with/without context) across all four key storage combinations (public/private session/token keys). This addresses the user feedback about context handling for composite certificates.src/lib/crypto/MLDSAPublicKey.cpp (1)
1-84: Clean implementation of MLDSAPublicKey.The implementation correctly infers the parameter set from key material length and provides proper serialization support. The design aligns with the project's established pattern for key classes.
src/lib/test/SignVerifyTests.h (2)
52-54: LGTM: Parameterized ML-DSA test registration.The test registration follows the established pattern (matching
testEdSignVerify) and correctly tests all three ML-DSA parameter sets.
66-68: Proper declarations with WITH_ML_DSA guards.The public test method and protected helper are correctly declared and guarded.
Also applies to: 78-80
src/lib/crypto/OSSLMLDSAPublicKey.h (1)
16-55: LGTM: Well-structured OpenSSL ML-DSA public key class.The class correctly:
- Deletes copy operations to prevent double-free of
EVP_PKEY*- Declares move operations for safe ownership transfer
- Provides proper OpenSSL integration via
setFromOSSL/getOSSLKeysrc/lib/crypto/MLDSAPublicKey.h (1)
14-45: LGTM: Clean ML-DSA public key interface.The class provides a well-designed abstract interface with proper virtual methods for type checking, parameter set inference, and serialization.
src/lib/crypto/MLDSAPrivateKey.cpp (1)
76-97: LGTM: Proper serialization with seed and value.The private key correctly serializes both seed and value, and deserializes with validation that both components are present.
src/lib/crypto/OSSLMLDSAKeyPair.h (1)
16-39: LGTM: Proper key pair wrapper.The class correctly holds
OSSLMLDSAPublicKeyandOSSLMLDSAPrivateKeyby value. Since both member types have deleted copy constructors, this class is implicitly non-copyable, which is the correct behavior for ownership semantics.src/lib/crypto/OSSLMLDSAPrivateKey.cpp (3)
40-56: LGTM: Proper move semantics implementation.The move constructor and move assignment operator correctly transfer ownership of
pkeyand null out the source, preventing double-free.
162-210: LGTM: Robust key creation with proper validation.The
createOSSLKeyfunction correctly validates the parameter set and key material before attempting to create the OpenSSL key, with proper error messages and cleanup on failure.
137-151: LGTM: PKCS#8 decode with proper cleanup.The memory leak from the previous review has been fixed -
localPKeyis now freed aftersetFromOSSLextracts the key material.src/lib/crypto/AsymmetricAlgorithm.h (4)
56-57: LGTM: MLDSA algorithm type added.The addition of MLDSA to the AsymAlgo::Type enum correctly extends the asymmetric algorithm types supported by SoftHSM.
96-97: LGTM: MLDSA mechanism type added.The addition of MLDSA to the AsymMech::Type enum correctly extends the supported asymmetric mechanisms.
121-129: LGTM: Hedge type enum for ML-DSA.The Hedge struct correctly defines the hedging semantics for ML-DSA signing operations per the PKCS#11 v3.2 specification.
131-153: LGTM: Additional context struct properly handles ownership.The SIGN_ADDITIONAL_CONTEXT struct correctly addresses ownership concerns:
- Copy operations are deleted to prevent shallow copies
contextAsCharis a const pointer signaling non-ownership- Comment documents that Session::setParameters handles deep-copy
- All constructors properly initialize members
Based on learnings, this design aligns with the requirement that Session::setParameters performs the deep-copy by allocating a single buffer for both the struct and context bytes.
src/lib/crypto/OSSLMLDSAPrivateKey.h (1)
17-66: LGTM: Class structure follows OpenSSL key wrapper patterns.The OSSLMLDSAPrivateKey class properly:
- Inherits from MLDSAPrivateKey
- Disables copying for safe EVP_PKEY ownership
- Declares move semantics for efficient transfers
- Provides PKCS#8 encoding/decoding
- Exposes OpenSSL conversion methods
src/lib/SoftHSM.cpp (2)
7052-7054: ML‑DSA wrap/unwrap integration via MLDSAUtil is consistent with other asymmetric keys
- In C_WrapKey, mapping CKK_ML_DSA → AsymAlgo::MLDSA and delegating private‑key extraction to MLDSAUtil::getMLDSAPrivateKey before PKCS#8 encoding matches the existing patterns for RSA/DSA/EC/EDDSA/GOST.
- In C_UnwrapKey, the CKK_ML_DSA branch calls MLDSAUtil::setMLDSAPrivateKey, which in turn sets CKA_PARAMETER_SET, CKA_SEED, and CKA_VALUE on the OSObject, aligning attribute layout with generateMLDSA.
This wiring should give you consistent ML‑DSA key material handling across generate, wrap/unwrap, and import.
Also applies to: 7096-7099, 7777-7780
5828-5831: Extra DEBUG logs on signature length mismatch are safe and usefulThe added DEBUG_MSG lines in AsymVerify and AsymVerifyFinal log only public signature lengths (
sizevsulSignatureLen) on mismatch, without exposing key material. That’s a helpful diagnostic for callers seeing CKR_SIGNATURE_LEN_RANGE and doesn’t leak secrets.Also applies to: 6012-6015
Adds ML-DSA support with OpenSSL >= 3.5
Summary by CodeRabbit
New Features
Documentation
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.