TPM2 ignores EVP_PKEY_CTX_set_rsa_pss_saltlen and always uses max salt
I've noticed that when I use TPM2 provider the implementation will ignore EVP_PKEY_CTX_set_rsa_pss_saltlen setting and will always use max salt length instead.
Some implementations don't allow changing or detecting salt length and will always use hLen=sLen as recommended by spec (i.e. .NET) and make the signature not possible to validate there.
Note that this is true regardless if I use placeholder value RSA_PSS_SALTLEN_DIGEST or 32 explicitly (=hLen because I'm using SHA256).
If you validate that with OpenSSL it will accept the signature though because by default it will detect salt length. If you manually change it to RSA_PSS_SALTLEN_DIGEST then it won't verify it.
I believe this might be related to following issues:
- https://github.com/OpenVPN/openvpn/issues/505
- https://github.com/tpm2-software/tpm2-openssl/issues/75
- possibly also: https://github.com/tpm2-software/tpm2-openssl/issues/114
also related issue on .NET:
- https://github.com/dotnet/runtime/issues/104080
Hmm. I would love to fix this, but the TPM2.0 specification doesn't seem to allow salt values shorter than the maximum. The TPM seems to have no salt len parameter. The TCG specification Part 1, section B.7 says For both restricted and unrestricted signing keys, the random salt length will be the largest size allowed by the key size and message digest size. If the TPM implementation is required to be compliant with FIPS 186-4, then the random salt length will be the largest size allowed by that specification. Similarly in Part 2, Section 11.2.1.2: For the TPM_ALG_RSAPSS signing scheme [...] salt size is always the largest salt value that will fit into the available space.
@gotthardp I'm a bit confused now.
Latest TPM 2.0 spec part 1 B.7 says this:
For both restricted and unrestricted signing keys, the random salt length is the largest size allowed by FIPS 186-5.
FIPS 186-5, section 5.4.g claims this:
For RSASSA-PSS, the length (in bytes) of the salt (sLen) shall saitisfy 0 <= sLen <= hLen where hLen is the length of the hash function output block (in bytes). This inequality shall also be checked during the signature verification process, where hLen is determined by the expected (approved) hash function, and sLen is the actual byte length of the byte string following the leftmost (most significant) nonzero byte (which should be 0x01) in the recovered DB.
I understand "largest size allowed by the key size and message digest size" as largest meeting "0 <= sLen <= hLen" criteria which ends up being just sLen == hLen.
see also @vcsjones response here: https://github.com/dotnet/runtime/issues/104080#issuecomment-2197173656
There is also a note on TPM 2.0:
The TPM2.0 specification has changed in this respect, see Change History, Revision 163.
The TPM has no way of setting it, but uses either the max length or the hash-size length (up to the vendor). By now, I would assume that implementations have switched to the hash-size based salt length following FIPS 186-4, but the only way to know is to check databooks or test. https://lore.kernel.org/tpm2/[email protected]/T/#mbfddc5d6b7359fc0996686c19aa5b7c4bbceabd1
Hence, the tpm2-openssl cannot implement the EVP_PKEY_CTX_set_rsa_pss_saltlen, because the RSA PSS salt length depends on the TPM2 chip implementation and cannot be set.
The latest standard is 01.83, but I would expect that many TPM2 chips on the market will conform to some older specification. For example, the most recent ST STSAFE-TPM as well as Infineon OPTIGA TPM follow TPM2.0 revision 1.59 and FIPS 140-3, i.e. the one prior the specification change.
Would it at least be possible to show some error code when that API is called? Currently it silently ignores and reports back what was set (don't know the implementation details if that is handled on OpenSsl or tpm2 side) - you can only figure out what happens when you put restrictions on the verification side