From e0b1dae5cd224d1012ec975845e5398a008e822f Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Fri, 16 May 2025 11:32:30 +0200 Subject: [PATCH 01/32] Added support for a custom salt length when using PSS signature validation/generation with RSA keys. #104080 --- .../Interop.EvpPkey.Rsa.cs | 6 +++ .../Windows/BCrypt/Interop.BCryptSignHash.cs | 4 +- .../BCrypt/Interop.BCryptVerifySignature.cs | 6 +-- .../Security/Cryptography/RSAAndroid.cs | 4 +- .../Cryptography/RSACng.SignVerify.cs | 12 ++++- .../Security/Cryptography/RSAOpenSsl.cs | 5 +- .../Cryptography/RSASecurityTransforms.cs | 5 +- .../Cryptography/RsaPaddingProcessor.cs | 23 +++++---- .../System/Security/Cryptography/RSABCrypt.cs | 3 +- .../Cryptography/RSASignaturePadding.cs | 51 ++++++++++++++++--- .../RSAPssX509SignatureGenerator.cs | 8 ++- .../pal_evp_pkey_rsa.c | 10 ++-- .../pal_evp_pkey_rsa.h | 2 + 13 files changed, 99 insertions(+), 40 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs index 8f56e1fa62f67c..3b73be92f61029 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs @@ -124,6 +124,7 @@ private static partial int CryptoNative_RsaSignHash( SafeEvpPKeyHandle pkey, IntPtr extraHandle, RSASignaturePaddingMode paddingMode, + int pssSaltLength, IntPtr digestAlgorithm, ref byte hash, int hashLength, @@ -133,6 +134,7 @@ private static partial int CryptoNative_RsaSignHash( internal static int RsaSignHash( SafeEvpPKeyHandle pkey, RSASignaturePaddingMode paddingMode, + int pssSaltLength, HashAlgorithmName digestAlgorithm, ReadOnlySpan hash, Span destination) @@ -146,6 +148,7 @@ internal static int RsaSignHash( pkey.ExtraHandle, paddingMode, digestAlgorithmPtr, + pssSaltLength, ref MemoryMarshal.GetReference(hash), hash.Length, ref MemoryMarshal.GetReference(destination), @@ -165,6 +168,7 @@ private static partial int CryptoNative_RsaVerifyHash( SafeEvpPKeyHandle pkey, IntPtr extraHandle, RSASignaturePaddingMode paddingMode, + int pssSaltLength, IntPtr digestAlgorithm, ref byte hash, int hashLength, @@ -174,6 +178,7 @@ private static partial int CryptoNative_RsaVerifyHash( internal static bool RsaVerifyHash( SafeEvpPKeyHandle pkey, RSASignaturePaddingMode paddingMode, + int pssSaltLength, HashAlgorithmName digestAlgorithm, ReadOnlySpan hash, ReadOnlySpan signature) @@ -187,6 +192,7 @@ internal static bool RsaVerifyHash( pkey.ExtraHandle, paddingMode, digestAlgorithmPtr, + pssSaltLength, ref MemoryMarshal.GetReference(hash), hash.Length, ref MemoryMarshal.GetReference(signature), diff --git a/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptSignHash.cs b/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptSignHash.cs index c7daa15baaa945..8695bea997a1ac 100644 --- a/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptSignHash.cs +++ b/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptSignHash.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.InteropServices; +using System.Security.Cryptography; using Internal.Cryptography; using Microsoft.Win32.SafeHandles; @@ -53,6 +54,7 @@ internal static unsafe NTSTATUS BCryptSignHashPss( ReadOnlySpan hash, Span destination, string hashAlgorithmName, + int saltLength, out int bytesWritten) { fixed (char* pHashAlgorithmName = hashAlgorithmName) @@ -61,7 +63,7 @@ internal static unsafe NTSTATUS BCryptSignHashPss( { BCRYPT_PSS_PADDING_INFO paddingInfo = default; paddingInfo.pszAlgId = (IntPtr)pHashAlgorithmName; - paddingInfo.cbSalt = hash.Length; + paddingInfo.cbSalt = saltLength; return BCryptSignHash( key, diff --git a/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptVerifySignature.cs b/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptVerifySignature.cs index 02e65df9580963..571d66f128c68a 100644 --- a/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptVerifySignature.cs +++ b/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptVerifySignature.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; - +using System.Security.Cryptography; using Microsoft.Win32.SafeHandles; internal static partial class Interop @@ -59,7 +59,7 @@ internal static unsafe bool BCryptVerifySignaturePss( SafeBCryptKeyHandle key, ReadOnlySpan hash, ReadOnlySpan signature, - string hashAlgorithmName) + string hashAlgorithmName, int saltLength) { NTSTATUS status; @@ -70,7 +70,7 @@ internal static unsafe bool BCryptVerifySignaturePss( { BCRYPT_PSS_PADDING_INFO paddingInfo = default; paddingInfo.pszAlgId = (IntPtr)pHashAlgorithmName; - paddingInfo.cbSalt = hash.Length; + paddingInfo.cbSalt = saltLength; status = BCryptVerifySignature( key, diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs index 1d1c742609d93f..3cc91424420c1a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs @@ -688,7 +688,7 @@ private bool TrySignHash( } else if (padding.Mode == RSASignaturePaddingMode.Pss) { - RsaPaddingProcessor.EncodePss(hashAlgorithm, hash, encodedBytes, KeySize); + RsaPaddingProcessor.EncodePss(hashAlgorithm, hash, encodedBytes, KeySize, padding.CalculatePssSaltLength(KeySize, hashAlgorithm)); } else { @@ -774,7 +774,7 @@ public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan sign } else if (padding == RSASignaturePadding.Pss) { - return RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, KeySize); + return RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, KeySize, padding.CalculatePssSaltLength(KeySize, hashAlgorithm)); } else { diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs b/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs index 8e1b7910d3ca4c..15380844f188ef 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs @@ -104,7 +104,11 @@ public override unsafe bool TrySignHash(ReadOnlySpan hash, Span dest return keyHandle.TrySignHash(hash, destination, AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, &pkcs1PaddingInfo, out bytesWritten); case RSASignaturePaddingMode.Pss: - var pssPaddingInfo = new BCRYPT_PSS_PADDING_INFO() { pszAlgId = namePtr, cbSalt = hash.Length }; + var pssPaddingInfo = new BCRYPT_PSS_PADDING_INFO() + { + pszAlgId = namePtr, + cbSalt = padding.CalculatePssSaltLength(KeySize, hashAlgorithm) + }; return keyHandle.TrySignHash(hash, destination, AsymmetricPaddingMode.NCRYPT_PAD_PSS_FLAG, &pssPaddingInfo, out bytesWritten); default: @@ -152,7 +156,11 @@ public override unsafe bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan hash, ReadOnlySpan sign key, padding.Mode, hashAlgorithm, + padding.Mode == RSASignaturePaddingMode.Pss ? padding.CalculatePssSaltLength(KeySize, hashAlgorithm) : 0, hash, signature); } diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs index aec263855f2864..c7cfc55882560a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs @@ -454,7 +454,7 @@ public override bool TrySignHash(ReadOnlySpan hash, Span destination byte[] rented = CryptoPool.Rent(rsaSize); Span buf = new Span(rented, 0, rsaSize); - RsaPaddingProcessor.EncodePss(hashAlgorithm, hash, buf, keySize); + RsaPaddingProcessor.EncodePss(hashAlgorithm, hash, buf, keySize, padding.PssSaltLength); try { @@ -537,9 +537,8 @@ public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan sign Debug.Fail($"TryRsaVerificationPrimitive with a pre-allocated buffer"); throw new CryptographicException(); } - Debug.Assert(bytesWritten == rsaSize); - return RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, keySize); + return RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, keySize, padding.CalculatePssSaltLength(KeySize, hashAlgorithm)); } finally { diff --git a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs index d4d493f3daca54..ff3a07ed898c49 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs @@ -380,7 +380,7 @@ internal static void PadOaep( } } - internal static void EncodePss(HashAlgorithmName hashAlgorithmName, ReadOnlySpan mHash, Span destination, int keySize) + internal static void EncodePss(HashAlgorithmName hashAlgorithmName, ReadOnlySpan mHash, Span destination, int keySize, int saltLength) { int hLen = HashLength(hashAlgorithmName); @@ -394,7 +394,13 @@ internal static void EncodePss(HashAlgorithmName hashAlgorithmName, ReadOnlySpan } // In this implementation, sLen is restricted to the length of the input hash. - int sLen = hLen; + int sLen = saltLength switch + { + // TODO: set max length + RSASignaturePadding.PssSaltLengthMax => 16, + RSASignaturePadding.PssSaltLengthIsHashLength => hLen, + _ => saltLength + }; // 3. if emLen < hLen + sLen + 2, encoding error. // @@ -469,7 +475,7 @@ internal static void EncodePss(HashAlgorithmName hashAlgorithmName, ReadOnlySpan CryptoPool.Return(dbMaskRented, clearSize: 0); } - internal static bool VerifyPss(HashAlgorithmName hashAlgorithmName, ReadOnlySpan mHash, ReadOnlySpan em, int keySize) + internal static bool VerifyPss(HashAlgorithmName hashAlgorithmName, ReadOnlySpan mHash, ReadOnlySpan em, int keySize, int saltLength) { int hLen = HashLength(hashAlgorithmName); @@ -485,11 +491,8 @@ internal static bool VerifyPss(HashAlgorithmName hashAlgorithmName, ReadOnlySpan Debug.Assert(em.Length >= emLen); - // In this implementation, sLen is restricted to hLen. - int sLen = hLen; - // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. - if (emLen < hLen + sLen + 2) + if (emLen < hLen + saltLength + 2) { return false; } @@ -538,7 +541,7 @@ internal static bool VerifyPss(HashAlgorithmName hashAlgorithmName, ReadOnlySpan // // Since signature verification is a public key operation there's no need to // use fixed time equality checking here. - for (int i = emLen - hLen - sLen - 2 - 1; i >= 0; --i) + for (int i = emLen - hLen - saltLength - 2 - 1; i >= 0; --i) { if (dbMask[i] != 0) { @@ -548,13 +551,13 @@ internal static bool VerifyPss(HashAlgorithmName hashAlgorithmName, ReadOnlySpan // 10 ("b") If the octet at position emLen - hLen - sLen - 1 (under a 1-indexed scheme) // is not 0x01, output "inconsistent" and stop. - if (dbMask[emLen - hLen - sLen - 2] != 0x01) + if (dbMask[emLen - hLen - saltLength - 2] != 0x01) { return false; } // 11. Let salt be the last sLen octets of DB. - ReadOnlySpan salt = dbMask.Slice(dbMask.Length - sLen); + ReadOnlySpan salt = dbMask.Slice(dbMask.Length - saltLength); // 12/13. Let H' = Hash(eight zeros || mHash || salt) hasher.AppendData(EightZeros); diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSABCrypt.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSABCrypt.cs index 6e1fbbdb23d919..4e46eb768ff3fe 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSABCrypt.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSABCrypt.cs @@ -294,6 +294,7 @@ public override bool TrySignHash( hash, destination, hashAlgorithmName, + padding.CalculatePssSaltLength(KeySize, hashAlgorithm), out written); break; @@ -346,7 +347,7 @@ public override bool VerifyHash( key, hash, signature, - hashAlgorithmName); + hashAlgorithmName, padding.CalculatePssSaltLength(KeySize, hashAlgorithm)); default: throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode); } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs index 60ee325a9fccbc..e3655bf6df06d1 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs @@ -6,25 +6,51 @@ namespace System.Security.Cryptography { - // NOTE: This is *currently* 1:1 with the enum, but it exists to reserve room for more options - // such as custom # of PSS salt bytes without having to modify other parts of the API - // surface. - /// /// Specifies the padding mode and parameters to use with RSA signature creation or verification operations. /// public sealed class RSASignaturePadding : IEquatable { + /// + /// Represents a constant value indicating that the salt length should match the hash length. + /// + /// This value is typically used in cryptographic operations where the salt length is required to + /// be the same as the hash length. + public const int PssSaltLengthIsHashLength = -1; + /// + /// Represents the maximum allowable length, in bytes, for a PSS (Probabilistic Signature Scheme) salt. + /// + /// This constant is used to define the upper limit for the salt length in PSS-based + /// cryptographic operations. The maximum length is determined by the hash algorithm's output size. + public const int PssSaltLengthMax = -2; + + public int PssSaltLength + { + get { return _pssSaltLength; } + } + + public static RSASignaturePadding CreatePss(int saltLength) + { + return new RSASignaturePadding(saltLength); + } + private static readonly RSASignaturePadding s_pkcs1 = new RSASignaturePadding(RSASignaturePaddingMode.Pkcs1); - private static readonly RSASignaturePadding s_pss = new RSASignaturePadding(RSASignaturePaddingMode.Pss); + private static readonly RSASignaturePadding s_pss = CreatePss(PssSaltLengthIsHashLength); private readonly RSASignaturePaddingMode _mode; + private readonly int _pssSaltLength; private RSASignaturePadding(RSASignaturePaddingMode mode) { _mode = mode; } + private RSASignaturePadding(int pssSaltLength) + { + _mode = RSASignaturePaddingMode.Pss; + _pssSaltLength = pssSaltLength; + } + /// /// mode. /// @@ -49,9 +75,20 @@ public RSASignaturePaddingMode Mode get { return _mode; } } + internal int CalculatePssSaltLength(int rsaKeySizeInBits, HashAlgorithmName hashAlgorithm) + { + int emLen = (rsaKeySizeInBits + 7) / 8; + int hLen = RsaPaddingProcessor.HashLength(hashAlgorithm); + return PssSaltLength switch + { + PssSaltLengthMax => Math.Max(0, emLen - hLen - 2), + PssSaltLengthIsHashLength => hLen, + _ => PssSaltLength + }; + } public override int GetHashCode() { - return _mode.GetHashCode(); + return HashCode.Combine(_mode, _pssSaltLength); } public override bool Equals([NotNullWhen(true)] object? obj) @@ -61,7 +98,7 @@ public override bool Equals([NotNullWhen(true)] object? obj) public bool Equals([NotNullWhen(true)] RSASignaturePadding? other) { - return other is not null && _mode == other._mode; + return other is not null && _mode == other._mode && _pssSaltLength == other._pssSaltLength; } public static bool operator ==(RSASignaturePadding? left, RSASignaturePadding? right) diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs index c1daad2b756e25..fb1596cdb1b596 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs @@ -26,8 +26,7 @@ internal RSAPssX509SignatureGenerator(RSA key, RSASignaturePadding padding) public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlgorithm) { // If we ever support options in PSS (like MGF-2, if such an MGF is ever invented) - // Or, more reasonably, supporting a custom value for the salt size. - if (_padding != RSASignaturePadding.Pss) + if (_padding.Mode != RSASignaturePaddingMode.Pss) { throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); } @@ -37,17 +36,14 @@ public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlg if (hashAlgorithm == HashAlgorithmName.SHA256) { - cbSalt = SHA256.HashSizeInBytes; digestOid = Oids.Sha256; } else if (hashAlgorithm == HashAlgorithmName.SHA384) { - cbSalt = SHA384.HashSizeInBytes; digestOid = Oids.Sha384; } else if (hashAlgorithm == HashAlgorithmName.SHA512) { - cbSalt = SHA512.HashSizeInBytes; digestOid = Oids.Sha512; } else @@ -58,6 +54,8 @@ public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlg SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name)); } + cbSalt = _padding.CalculatePssSaltLength(_key.KeySize, hashAlgorithm); + // RFC 5754 says that the NULL for SHA2 (256/384/512) MUST be omitted // (https://tools.ietf.org/html/rfc5754#section-2) (and that you MUST // be able to read it even if someone wrote it down) diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c index f4a79df5fa1498..cfc2531efb2fd7 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +++ b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c @@ -213,7 +213,7 @@ int32_t CryptoNative_RsaEncrypt(EVP_PKEY* pkey, return ret; } -static bool ConfigureSignature(EVP_PKEY_CTX* ctx, RsaPaddingMode padding, const EVP_MD* digest) +static bool ConfigureSignature(EVP_PKEY_CTX* ctx, RsaPaddingMode padding, int pssSaltLength, const EVP_MD* digest) { #pragma clang diagnostic push @@ -236,7 +236,7 @@ static bool ConfigureSignature(EVP_PKEY_CTX* ctx, RsaPaddingMode padding, const assert(padding == RsaPaddingOaepOrPss); if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0 || - EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, RSA_PSS_SALTLEN_DIGEST) <= 0) + EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, pssSaltLength) <= 0) { return false; } @@ -248,6 +248,7 @@ static bool ConfigureSignature(EVP_PKEY_CTX* ctx, RsaPaddingMode padding, const int32_t CryptoNative_RsaSignHash(EVP_PKEY* pkey, void* extraHandle, RsaPaddingMode padding, + int pssSaltLength, const EVP_MD* digest, const uint8_t* hash, int32_t hashLen, @@ -270,7 +271,7 @@ int32_t CryptoNative_RsaSignHash(EVP_PKEY* pkey, goto done; } - if (!ConfigureSignature(ctx, padding, digest)) + if (!ConfigureSignature(ctx, padding, pssSaltLength, digest)) { goto done; } @@ -310,6 +311,7 @@ int32_t CryptoNative_RsaSignHash(EVP_PKEY* pkey, int32_t CryptoNative_RsaVerifyHash(EVP_PKEY* pkey, void* extraHandle, RsaPaddingMode padding, + int pssSaltLength, const EVP_MD* digest, const uint8_t* hash, int32_t hashLen, @@ -332,7 +334,7 @@ int32_t CryptoNative_RsaVerifyHash(EVP_PKEY* pkey, goto done; } - if (!ConfigureSignature(ctx, padding, digest)) + if (!ConfigureSignature(ctx, padding, pssSaltLength, digest)) { goto done; } diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h index 7ae93de6cf3553..1ae796b1fecda9 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h +++ b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h @@ -62,6 +62,7 @@ Returns the number of bytes written to destination, -1 on error. PALEXPORT int32_t CryptoNative_RsaSignHash(EVP_PKEY* pkey, void* extraHandle, RsaPaddingMode padding, + int pssSaltLength, const EVP_MD* digest, const uint8_t* hash, int32_t hashLen, @@ -77,6 +78,7 @@ Returns 1 on a verified signature, 0 on a mismatched signature, -1 on error. PALEXPORT int32_t CryptoNative_RsaVerifyHash(EVP_PKEY* pkey, void* extraHandle, RsaPaddingMode padding, + int pssSaltLength, const EVP_MD* digest, const uint8_t* hash, int32_t hashLen, From 05ed28bd413c87e02dda19e749ce2dd544d2a27f Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Fri, 16 May 2025 11:36:27 +0200 Subject: [PATCH 02/32] Review --- .../Cryptography/RSASecurityTransforms.cs | 2 +- .../Security/Cryptography/RsaPaddingProcessor.cs | 15 +++------------ .../Security/Cryptography/RSASignaturePadding.cs | 10 +++++----- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs index c7cfc55882560a..24dcaf00d63f81 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs @@ -454,7 +454,7 @@ public override bool TrySignHash(ReadOnlySpan hash, Span destination byte[] rented = CryptoPool.Rent(rsaSize); Span buf = new Span(rented, 0, rsaSize); - RsaPaddingProcessor.EncodePss(hashAlgorithm, hash, buf, keySize, padding.PssSaltLength); + RsaPaddingProcessor.EncodePss(hashAlgorithm, hash, buf, keySize, padding.CalculatePssSaltLength(KeySize, hashAlgorithm)); try { diff --git a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs index ff3a07ed898c49..ac7da1357192d6 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs @@ -393,20 +393,11 @@ internal static void EncodePss(HashAlgorithmName hashAlgorithmName, ReadOnlySpan throw new CryptographicException(SR.Cryptography_SignHash_WrongSize); } - // In this implementation, sLen is restricted to the length of the input hash. - int sLen = saltLength switch - { - // TODO: set max length - RSASignaturePadding.PssSaltLengthMax => 16, - RSASignaturePadding.PssSaltLengthIsHashLength => hLen, - _ => saltLength - }; - // 3. if emLen < hLen + sLen + 2, encoding error. // // sLen = hLen in this implementation. - if (emLen < 2 + hLen + sLen) + if (emLen < 2 + hLen + saltLength) { throw new CryptographicException(SR.Cryptography_KeyTooSmall); } @@ -432,7 +423,7 @@ internal static void EncodePss(HashAlgorithmName hashAlgorithmName, ReadOnlySpan Debug.Assert(hasher.HashLengthInBytes == hLen); // 4. Generate a random salt of length sLen Debug.Assert(hLen is >= 0 and <= 64); - Span salt = stackalloc byte[sLen]; + Span salt = stackalloc byte[saltLength]; RandomNumberGenerator.Fill(salt); // 5. Let M' = an octet string of 8 zeros concat mHash concat salt @@ -450,7 +441,7 @@ internal static void EncodePss(HashAlgorithmName hashAlgorithmName, ReadOnlySpan // 7. Generate PS as zero-valued bytes of length emLen - sLen - hLen - 2. // 8. Let DB = PS || 0x01 || salt - int psLen = emLen - sLen - hLen - 2; + int psLen = emLen - saltLength - hLen - 2; db.Slice(0, psLen).Clear(); db[psLen] = 0x01; salt.CopyTo(db.Slice(psLen + 1)); diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs index e3655bf6df06d1..d3da560e0764a0 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs @@ -11,11 +11,11 @@ namespace System.Security.Cryptography /// public sealed class RSASignaturePadding : IEquatable { - /// - /// Represents a constant value indicating that the salt length should match the hash length. - /// - /// This value is typically used in cryptographic operations where the salt length is required to - /// be the same as the hash length. + /// + /// Represents a constant value indicating that the salt length should match the hash length. + /// + /// This value is typically used in cryptographic operations where the salt length is required to + /// be the same as the hash length. public const int PssSaltLengthIsHashLength = -1; /// /// Represents the maximum allowable length, in bytes, for a PSS (Probabilistic Signature Scheme) salt. From d7051262aaca5d1ef3222206c29393ea65abdf23 Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Fri, 6 Jun 2025 07:09:00 +0200 Subject: [PATCH 03/32] Review all usages for RSASignaturePadding to check for missing PSS salt customizations --- .../Interop.EvpPkey.Rsa.cs | 4 ++-- .../Cryptography/RSACng.SignVerify.cs | 2 +- .../Security/Cryptography/RSAOpenSsl.cs | 19 ++++++++----------- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs index 3b73be92f61029..40558f63923f2f 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs @@ -147,8 +147,8 @@ internal static int RsaSignHash( pkey, pkey.ExtraHandle, paddingMode, - digestAlgorithmPtr, pssSaltLength, + digestAlgorithmPtr, ref MemoryMarshal.GetReference(hash), hash.Length, ref MemoryMarshal.GetReference(destination), @@ -191,8 +191,8 @@ internal static bool RsaVerifyHash( pkey, pkey.ExtraHandle, paddingMode, - digestAlgorithmPtr, pssSaltLength, + digestAlgorithmPtr, ref MemoryMarshal.GetReference(hash), hash.Length, ref MemoryMarshal.GetReference(signature), diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs b/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs index 15380844f188ef..53e2f9b3f8d1fe 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs @@ -66,7 +66,7 @@ public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RS return keyHandle.SignHash(hash, AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, &pkcsPaddingInfo, estimatedSize); case RSASignaturePaddingMode.Pss: - var pssPaddingInfo = new BCRYPT_PSS_PADDING_INFO() { pszAlgId = namePtr, cbSalt = hash.Length }; + var pssPaddingInfo = new BCRYPT_PSS_PADDING_INFO() { pszAlgId = namePtr, cbSalt = padding.CalculatePssSaltLength(KeySize, hashAlgorithm) }; return keyHandle.SignHash(hash, AsymmetricPaddingMode.NCRYPT_PAD_PSS_FLAG, &pssPaddingInfo, estimatedSize); default: diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index e85c333f07480b..3850841a632863 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -735,7 +735,7 @@ public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RS int bytesRequired = Interop.Crypto.GetEvpPKeySizeBytes(key); byte[] signature = new byte[bytesRequired]; - int written = Interop.Crypto.RsaSignHash(key, padding.Mode, hashAlgorithm, padding.Mode == RSASignaturePaddingMode.Pss ? padding.CalculatePssSaltLength(KeySize, hashAlgorithm) : 0, hash, signature); + int written = Interop.Crypto.RsaSignHash(key, padding.Mode, padding.Mode == RSASignaturePaddingMode.Pss ? padding.CalculatePssSaltLength(KeySize, hashAlgorithm) : 0, hashAlgorithm, hash, signature); if (written != signature.Length) { @@ -766,7 +766,7 @@ public override bool TrySignHash( return false; } - bytesWritten = Interop.Crypto.RsaSignHash(key, padding.Mode, hashAlgorithm, padding.Mode == RSASignaturePaddingMode.Pss ? padding.CalculatePssSaltLength(KeySize, hashAlgorithm) : 0, hash, destination); + bytesWritten = Interop.Crypto.RsaSignHash(key, padding.Mode, padding.Mode == RSASignaturePaddingMode.Pss ? padding.CalculatePssSaltLength(KeySize, hashAlgorithm) : 0, hashAlgorithm, hash, destination); Debug.Assert(bytesWritten == bytesRequired); return true; } @@ -794,8 +794,8 @@ public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan sign return Interop.Crypto.RsaVerifyHash( key, padding.Mode, - hashAlgorithm, padding.Mode == RSASignaturePaddingMode.Pss ? padding.CalculatePssSaltLength(KeySize, hashAlgorithm) : 0, + hashAlgorithm, hash, signature); } @@ -854,20 +854,17 @@ private static void ValidatePadding(RSASignaturePadding padding) { ArgumentNullException.ThrowIfNull(padding); - // RSASignaturePadding currently only has the mode property, so - // there's no need for a runtime check that PKCS#1 doesn't use - // nonsensical options like with RSAEncryptionPadding. - // - // This would change if we supported PSS with an MGF other than MGF-1, - // or with a custom salt size, or with a different MGF digest algorithm - // than the data digest algorithm. + // PKCS#1 does not currently have anything to validate. if (padding.Mode == RSASignaturePaddingMode.Pkcs1) { Debug.Assert(padding == RSASignaturePadding.Pkcs1); } else if (padding.Mode == RSASignaturePaddingMode.Pss) { - Debug.Assert(padding == RSASignaturePadding.Pss); + if (padding.PssSaltLength < RSASignaturePadding.PssSaltLengthIsHashLength) + { + throw PaddingModeNotSupported(); + } } else { From 3c6288c4a774502b701dc7997bde8e97f24f1ebc Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Fri, 6 Jun 2025 11:40:39 +0200 Subject: [PATCH 04/32] Added error handling for apple devices (custom PSS salt length not supported there) Updated reference code --- .../System/Security/Cryptography/RSASecurityTransforms.cs | 8 +++++++- .../ref/System.Security.Cryptography.cs | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs index 24dcaf00d63f81..595311f7fe7f7f 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs @@ -397,6 +397,12 @@ public override bool TrySignHash(ReadOnlySpan hash, Span destination ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm)); ArgumentNullException.ThrowIfNull(padding); + // Apple does not support custom salt length for the PSS padding + if (padding.Mode == RSASignaturePaddingMode.Pss && (padding.PssSaltLength != RSASignaturePadding.PssSaltLengthIsHashLength || padding.PssSaltLength != RsaPaddingProcessor.HashLength(hashAlgorithm))) + { + throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); + } + ThrowIfDisposed(); Interop.AppleCrypto.PAL_SignatureAlgorithm signatureAlgorithm = padding.Mode switch @@ -454,7 +460,7 @@ public override bool TrySignHash(ReadOnlySpan hash, Span destination byte[] rented = CryptoPool.Rent(rsaSize); Span buf = new Span(rented, 0, rsaSize); - RsaPaddingProcessor.EncodePss(hashAlgorithm, hash, buf, keySize, padding.CalculatePssSaltLength(KeySize, hashAlgorithm)); + RsaPaddingProcessor.EncodePss(hashAlgorithm, hash, buf, keySize, hash.Length); try { diff --git a/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs b/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs index 6d176dae329fbd..afd3d7502a1ee9 100644 --- a/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs +++ b/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs @@ -2514,10 +2514,14 @@ public override void SetKey(System.Security.Cryptography.AsymmetricAlgorithm key } public sealed partial class RSASignaturePadding : System.IEquatable { + public const int PssSaltLengthIsHashLength = -1; + public const int PssSaltLengthMax = -2; internal RSASignaturePadding() { } public System.Security.Cryptography.RSASignaturePaddingMode Mode { get { throw null; } } + public int PssSaltLength { get { throw null; } } public static System.Security.Cryptography.RSASignaturePadding Pkcs1 { get { throw null; } } public static System.Security.Cryptography.RSASignaturePadding Pss { get { throw null; } } + public static RSASignaturePadding CreatePss(int saltLength) { throw null;} public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } public bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] System.Security.Cryptography.RSASignaturePadding? other) { throw null; } public override int GetHashCode() { throw null; } From 4d3bd37f537bc184570a2d016aad64c9e5204f2d Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Tue, 10 Jun 2025 08:35:52 +0200 Subject: [PATCH 05/32] Added sign and verify tests for custom salt lengths --- .../RSA/SignVerify.cs | 87 ++++++++++++++----- 1 file changed, 67 insertions(+), 20 deletions(-) diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs index cc4d396d01ffb7..9a4eb5b9a3a715 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs @@ -582,6 +582,48 @@ public void VerifySignature_SHA3_512_RSA2048() VerifySignature(signature, TestData.HelloBytes, HashAlgorithmName.SHA3_512.Name, TestData.RSA2048Params); } + [ConditionalTheory(nameof(SupportsPss))] + [InlineData(true)] + [InlineData(false)] + public void PssSignature_Sha_256_RSA2048_PSS_SaltLength_24(bool validateWithCorrectSaltLength) + { + // echo -n Hello | openssl dgst -sha-256 -binary | openssl pkeyutl -sign -inkey rsa.pem -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha-256 -pkeyopt rsa_pss_saltlen:24 | xxd -i -c 16 + byte[] signature = new byte[] { + 0xad, 0x2e, 0x10, 0x1a, 0xd0, 0xd7, 0x8b, 0x13, 0x88, 0xae, 0x18, 0x93, 0x3a, 0x62, 0x49, 0x3f, + 0xdc, 0x60, 0x64, 0xe3, 0xd8, 0x6f, 0xfa, 0x0c, 0xcb, 0xba, 0x6a, 0x5f, 0x46, 0x16, 0x56, 0x15, + 0x5b, 0x53, 0x80, 0x19, 0xa0, 0x37, 0x8f, 0xd9, 0xe1, 0xb2, 0x83, 0x94, 0x40, 0x77, 0x44, 0x74, + 0x23, 0xd0, 0x28, 0x96, 0x90, 0xa1, 0x90, 0x02, 0x95, 0x2e, 0x0e, 0xae, 0x44, 0x55, 0x94, 0x0a, + 0x58, 0x84, 0x98, 0xec, 0x71, 0xd0, 0xce, 0xaa, 0x35, 0xb0, 0x2d, 0xf2, 0xa5, 0x9f, 0xd0, 0x9a, + 0x9d, 0x23, 0x38, 0xfa, 0xc7, 0xdb, 0xe3, 0xb4, 0x4d, 0x71, 0x12, 0xd7, 0xc1, 0x35, 0x70, 0x41, + 0x01, 0x14, 0xbf, 0x3f, 0x17, 0xad, 0x4d, 0x40, 0x52, 0x03, 0x46, 0x52, 0xee, 0xcb, 0x2f, 0xcc, + 0x79, 0xd3, 0x32, 0xed, 0x64, 0x13, 0x67, 0xd4, 0xb2, 0x6c, 0x12, 0xd8, 0x1d, 0xf5, 0xd5, 0x33, + 0xb9, 0x50, 0x46, 0xa7, 0xf6, 0xe5, 0xc1, 0x65, 0xbd, 0xff, 0x90, 0x69, 0xb1, 0x37, 0xd6, 0x26, + 0xb1, 0xad, 0x77, 0x01, 0x5d, 0xf4, 0xd7, 0xf3, 0x4c, 0xf2, 0xf8, 0x5f, 0x67, 0x5b, 0x0e, 0xb6, + 0x17, 0xcd, 0xc8, 0x61, 0x92, 0xb2, 0xf3, 0xa0, 0xca, 0xbc, 0x7b, 0xc2, 0xac, 0xeb, 0x46, 0xd0, + 0x2f, 0x7c, 0xd8, 0x7d, 0xef, 0x43, 0x8a, 0x64, 0x93, 0x1e, 0xe0, 0xbf, 0x5a, 0x20, 0x6b, 0xb8, + 0xe7, 0x61, 0x7b, 0x67, 0xca, 0xb7, 0xe1, 0x78, 0x48, 0xab, 0xa2, 0xa6, 0x21, 0x3e, 0x50, 0x7b, + 0x49, 0xe0, 0x78, 0x74, 0x46, 0x4a, 0x65, 0xf4, 0x97, 0x52, 0xc7, 0x38, 0xeb, 0x00, 0x05, 0xff, + 0xb5, 0x37, 0xdb, 0x6a, 0xf3, 0x7b, 0x4d, 0x3b, 0x20, 0xa6, 0x7b, 0x6f, 0xcd, 0x34, 0x7c, 0xd3, + 0x83, 0x61, 0x51, 0xcf, 0x67, 0x55, 0x43, 0x2e, 0xd0, 0x73, 0x00, 0xfb, 0xd0, 0x61, 0x36, 0xad + }; + + RSASignaturePadding padding = RSASignaturePadding.CreatePss(validateWithCorrectSaltLength ? 24 : 12); + byte[] data = TestData.HelloBytes; + + using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params)) + { + var signatureIsValid = VerifyData(rsa, data, signature, HashAlgorithmName.SHA256, padding); + if (validateWithCorrectSaltLength) + { + Assert.True(signatureIsValid); + } + else + { + Assert.False(signatureIsValid); + } + } + } + [Theory] [MemberData(nameof(RoundTripTheories))] public void SignAndVerify_Roundtrip(string hashAlgorithm, RSAParameters rsaParameters) @@ -960,8 +1002,8 @@ public void VerifyHashSignature_SHA256_2048() } [Theory] - [MemberData(nameof(HashAlgorithmNames))] - public void PssRoundtrip(string hashAlgorithmName) + [MemberData(nameof(PssRoundTripParameters))] + public void PssRoundtrip(string hashAlgorithmName, RSASignaturePadding padding) { RSAParameters privateParameters = TestData.RSA2048Params; RSAParameters publicParameters = new RSAParameters @@ -978,7 +1020,6 @@ public void PssRoundtrip(string hashAlgorithmName) byte[] data = TestData.RsaBigExponentParams.Modulus; HashAlgorithmName hashAlgorithm = new HashAlgorithmName(hashAlgorithmName); - RSASignaturePadding padding = RSASignaturePadding.Pss; if (RSAFactory.SupportsPss) { @@ -1586,29 +1627,35 @@ private void SignAndVerify(byte[] data, string hashAlgorithmName, RSAParameters } } - public static IEnumerable HashAlgorithmNames + public static IEnumerable PssRoundTripParameters { get { - yield return new object[] { HashAlgorithmName.SHA256.Name }; - yield return new object[] { HashAlgorithmName.SHA384.Name }; - yield return new object[] { HashAlgorithmName.SHA512.Name }; - - if (RSAFactory.SupportsMd5Signatures) + int?[] saltLengths = [null, RSASignaturePadding.PssSaltLengthMax, RSASignaturePadding.PssSaltLengthIsHashLength, 0, 1, 4]; + foreach (var saltLength in saltLengths) { - yield return new object[] { HashAlgorithmName.MD5.Name }; - } + var padding = saltLength is null ? RSASignaturePadding.Pss : RSASignaturePadding.CreatePss(saltLength.Value); - if (RSAFactory.SupportsSha1Signatures) - { - yield return new object[] { HashAlgorithmName.SHA1.Name }; - } + yield return new object[] { HashAlgorithmName.SHA256.Name, padding }; + yield return new object[] { HashAlgorithmName.SHA384.Name, padding }; + yield return new object[] { HashAlgorithmName.SHA512.Name, padding }; - if (RSAFactory.SupportsSha3) - { - yield return new object[] { HashAlgorithmName.SHA3_256.Name }; - yield return new object[] { HashAlgorithmName.SHA3_384.Name }; - yield return new object[] { HashAlgorithmName.SHA3_512.Name }; + if (RSAFactory.SupportsMd5Signatures) + { + yield return new object[] { HashAlgorithmName.MD5.Name, padding }; + } + + if (RSAFactory.SupportsSha1Signatures) + { + yield return new object[] { HashAlgorithmName.SHA1.Name, padding }; + } + + if (RSAFactory.SupportsSha3) + { + yield return new object[] { HashAlgorithmName.SHA3_256.Name, padding }; + yield return new object[] { HashAlgorithmName.SHA3_384.Name, padding }; + yield return new object[] { HashAlgorithmName.SHA3_512.Name, padding }; + } } } } From d19d017cc9ec5e4c3d6188025319b187b010f017 Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Tue, 10 Jun 2025 08:57:23 +0200 Subject: [PATCH 06/32] Added test for max salt length verification --- .../RSA/SignVerify.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs index 9a4eb5b9a3a715..32a58b1200ea02 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs @@ -624,6 +624,48 @@ public void PssSignature_Sha_256_RSA2048_PSS_SaltLength_24(bool validateWithCorr } } + [ConditionalTheory(nameof(SupportsPss))] + [InlineData(true)] + [InlineData(false)] + public void PssSignature_Sha_256_RSA2048_PSS_SaltLength_Max(bool validateWithCorrectSaltLength) + { + // echo -n Hello | openssl dgst -sha-256 -binary | openssl pkeyutl -sign -inkey rsa.pem -pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha-256 -pkeyopt rsa_pss_saltlen:max | xxd -i -c 16 + byte[] signature = new byte[] { + 0x46, 0x31, 0x80, 0x84, 0x97, 0x26, 0x47, 0x7a, 0xb3, 0x61, 0x13, 0x52, 0x51, 0x03, 0x6a, 0x71, + 0x41, 0x89, 0x66, 0xf3, 0xd5, 0xd4, 0xa3, 0x9c, 0x67, 0x87, 0x25, 0x00, 0x6e, 0x93, 0xcc, 0xc0, + 0xd0, 0xe6, 0x34, 0x7c, 0xe4, 0x1a, 0xb9, 0x3b, 0x48, 0xd1, 0xf7, 0x7e, 0x1b, 0x09, 0xa9, 0xd5, + 0x92, 0x74, 0x57, 0x08, 0xcb, 0xfd, 0xc2, 0x75, 0xe8, 0x8c, 0xb5, 0x9c, 0x28, 0xc4, 0x68, 0x40, + 0xe5, 0xa3, 0x1d, 0x29, 0x10, 0x7c, 0x60, 0x82, 0x50, 0xfb, 0xc1, 0x8c, 0x05, 0x23, 0xfb, 0xd5, + 0x3e, 0xf0, 0x6c, 0x36, 0x31, 0xdc, 0x1f, 0xfa, 0xd3, 0xba, 0x99, 0x24, 0x13, 0x06, 0x0b, 0x50, + 0x18, 0xe0, 0x43, 0x8b, 0xed, 0x6c, 0xa5, 0x7b, 0x0b, 0x94, 0xd9, 0x2a, 0x21, 0xd0, 0xe0, 0x58, + 0x31, 0x8b, 0x60, 0x55, 0xa2, 0x10, 0x95, 0xc4, 0xb1, 0x2d, 0x6c, 0x96, 0x0a, 0x61, 0xf2, 0xe7, + 0xd4, 0x5c, 0x5a, 0x8d, 0x4d, 0xd2, 0xe9, 0x2a, 0x34, 0xcb, 0x32, 0xe5, 0xd1, 0x17, 0xb2, 0xd2, + 0x02, 0x47, 0x90, 0xba, 0x69, 0xd5, 0xa3, 0xfe, 0x35, 0xba, 0x0a, 0xb7, 0x35, 0xe2, 0xae, 0xb6, + 0x82, 0xf1, 0xee, 0x72, 0x8e, 0x1e, 0xf9, 0x06, 0xed, 0xd7, 0x09, 0x6d, 0xf2, 0x49, 0x00, 0x3d, + 0x11, 0x8a, 0x1b, 0xb1, 0x9d, 0x6e, 0xd2, 0x49, 0xca, 0xab, 0x6d, 0x6e, 0x13, 0xca, 0xa9, 0x9f, + 0xdf, 0xfb, 0x6b, 0x29, 0xaa, 0x16, 0x54, 0x23, 0x52, 0xa7, 0x69, 0xa2, 0x72, 0xba, 0xc3, 0x07, + 0x3d, 0x60, 0x36, 0xdf, 0xfd, 0x9b, 0x1f, 0x4e, 0x58, 0xd9, 0x65, 0xf0, 0x10, 0xa7, 0x8d, 0x08, + 0xc0, 0x3c, 0xcf, 0x8a, 0x92, 0x2d, 0x9d, 0x75, 0x9b, 0xae, 0x68, 0xd0, 0xda, 0xaa, 0xe2, 0xd2, + 0x11, 0xf2, 0x10, 0xbd, 0x19, 0x47, 0x75, 0x3c, 0x30, 0xc4, 0x0f, 0xd0, 0x7b, 0xc2, 0x6b, 0x4b + }; + + RSASignaturePadding padding = RSASignaturePadding.CreatePss(validateWithCorrectSaltLength ? RSASignaturePadding.PssSaltLengthMax : 2); + byte[] data = TestData.HelloBytes; + + using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params)) + { + var signatureIsValid = VerifyData(rsa, data, signature, HashAlgorithmName.SHA256, padding); + if (validateWithCorrectSaltLength) + { + Assert.True(signatureIsValid); + } + else + { + Assert.False(signatureIsValid); + } + } + } + [Theory] [MemberData(nameof(RoundTripTheories))] public void SignAndVerify_Roundtrip(string hashAlgorithm, RSAParameters rsaParameters) From 20be62b3a844a451cd386926903c4700ebe99693 Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Wed, 11 Jun 2025 07:42:49 +0200 Subject: [PATCH 07/32] Added a test for the RSAPssX509SignatureGenerator --- .../RSAPssX509SignatureGeneratorTests.cs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs index 216bb1ca84cbec..aa102aee4dd5e0 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Formats.Asn1; using Test.Cryptography; using Xunit; @@ -56,6 +57,49 @@ public static void PublicKeyEncoding() } } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] + [InlineData(RSASignaturePadding.PssSaltLengthMax)] + public static void PssPaddingSaltLengths(int saltLengthToTest) + { + using (RSA rsa = RSA.Create()) + { + rsa.ImportParameters(TestData.RsaBigExponentParams); + + RSASignaturePadding signaturePadding = RSASignaturePadding.CreatePss(saltLengthToTest); + X509SignatureGenerator signatureGenerator = X509SignatureGenerator.CreateForRSA(rsa, signaturePadding); + + var data = new byte[] { 1, 2, 3, 4, 5 }; + var signature = signatureGenerator.SignData(data, HashAlgorithmName.SHA256); + var signatureAlgorithm = signatureGenerator.GetSignatureAlgorithmIdentifier(HashAlgorithmName.SHA256); + + var asnReader = new AsnReader(signatureAlgorithm, AsnEncodingRules.DER); + var rootSequence = asnReader.ReadSequence(); + Assert.Equal("1.2.840.113549.1.1.10", rootSequence.ReadObjectIdentifier()); // Make sure it's RSASSA-PSS + var pssStructure = rootSequence.ReadSequence(); + pssStructure.ReadEncodedValue(); // Ignore the hash algorithm OID + pssStructure.ReadEncodedValue(); // Ignore the mask generation function OID + var saltTag = new Asn1Tag(TagClass.ContextSpecific, 2, true); + if (pssStructure.HasData && pssStructure.PeekTag().HasSameClassAndValue(saltTag)) + { + var saltEntry = pssStructure.ReadSequence(saltTag); + var actualSaltLength = saltEntry.ReadInteger(); + var expectedSaltLength = saltLengthToTest switch + { + RSASignaturePadding.PssSaltLengthIsHashLength => 32, + RSASignaturePadding.PssSaltLengthMax => 222, + _ => saltLengthToTest + }; + Assert.Equal(expectedSaltLength, actualSaltLength); + } + + Assert.True(rsa.VerifyData(data, signature, HashAlgorithmName.SHA256, signaturePadding)); + } + } + [Theory] [InlineData("SHA256")] [InlineData("SHA384")] From c0d0ce081b70ab2eebcfebab6b8041fac9e2f41e Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Wed, 11 Jun 2025 08:53:21 +0200 Subject: [PATCH 08/32] Added test for CertificateRequest.LoadSigningRequest --- .../Cryptography/Asn1/PssParamsAsn.manual.cs | 4 +++ .../CertificateRequestChainTests.cs | 10 +++++-- .../CertificateRequestLoadTests.cs | 14 +++++---- .../CertificateRequestUsageTests.cs | 29 +++++++++++++++++++ 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.manual.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.manual.cs index b80004f5efa50c..5014c5896cb63c 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.manual.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.manual.cs @@ -41,6 +41,9 @@ internal RSASignaturePadding GetSignaturePadding( HashAlgorithm.Algorithm)); } +#if NET10_0_OR_GREATER + return RSASignaturePadding.CreatePss(SaltLength); +#else int saltSize = digestValueLength.GetValueOrDefault(); if (!digestValueLength.HasValue) @@ -59,6 +62,7 @@ internal RSASignaturePadding GetSignaturePadding( // When RSASignaturePadding supports custom salt sizes this return will look different. return RSASignaturePadding.Pss; +#endif } } } diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs index a4c0af014952fd..5bd32ad0031316 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs @@ -486,8 +486,12 @@ private static void CreateAndTestChain( } } - [ConditionalFact(nameof(PlatformSupportsPss))] - public static void CreateChain_RSAPSS() + [ConditionalTheory(nameof(PlatformSupportsPss))] + [InlineData(0)] + [InlineData(1)] + [InlineData(RSASignaturePadding.PssSaltLengthMax)] + [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] + public static void CreateChain_RSAPSS(int saltLength) { using (RSA rootKey = RSA.Create()) using (RSA intermedKey = RSA.Create()) @@ -498,7 +502,7 @@ public static void CreateChain_RSAPSS() X509Certificate2 leafCert = null; CertificateRequest request; - RSASignaturePadding padding = RSASignaturePadding.Pss; + RSASignaturePadding padding = RSASignaturePadding.CreatePss(saltLength); ; DateTimeOffset notBefore = DateTimeOffset.UtcNow; DateTimeOffset notAfter = notBefore.AddHours(1); diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs index 418552c4ea1cb3..68cb327fa9af79 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs @@ -825,8 +825,12 @@ public static void LoadCreate_MatchesCreate_RSAPkcs1() } } - [Fact] - public static void LoadCreate_MatchesCreate_RSAPss() + [Theory] + [InlineData(0)] + [InlineData(4)] + [InlineData(RSASignaturePadding.PssSaltLengthMax)] + [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] + public static void LoadCreate_MatchesCreate_RSAPss(int saltLength) { using (RSA key = RSA.Create(2048)) { @@ -835,9 +839,9 @@ public static void LoadCreate_MatchesCreate_RSAPss() "CN=Roundtrip, O=RSA, OU=PSS", key, HashAlgorithmName.SHA256, - RSASignaturePadding.Pss), - X509SignatureGenerator.CreateForRSA(key, RSASignaturePadding.Pss), - deterministicSignature: false); + RSASignaturePadding.CreatePss(saltLength)), + X509SignatureGenerator.CreateForRSA(key, RSASignaturePadding.CreatePss(saltLength)), + deterministicSignature: saltLength == 0); } } diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs index 4824610078bb04..8735802ca57a24 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs @@ -5,6 +5,7 @@ using RsaTestData = System.Security.Cryptography.Rsa.Tests.TestData; using Test.Cryptography; using Xunit; +using System.Formats.Asn1; namespace System.Security.Cryptography.X509Certificates.Tests.CertificateCreation { @@ -306,6 +307,34 @@ public static void SelfSign_ECC_DiminishedPoint_UseCertKeys() } } + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(RSASignaturePadding.PssSaltLengthMax)] + [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] + public static void SelfSign_RSA_PssPadding_CustomSaltLength(int customSaltLength) + { + using (RSA rsa = RSA.Create()) + { + var requestBuilder = new CertificateRequest("CN=Test", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.CreatePss(customSaltLength)); + var cert = requestBuilder.CreateSelfSigned(DateTime.Now, DateTime.Now.AddYears(1)); + + var reader = new AsnReader(cert.RawData, AsnEncodingRules.DER); + var sequence = reader.ReadSequence(); + var tbsCertificate = sequence.ReadEncodedValue(); + var signatureAlgorithm = sequence.ReadEncodedValue(); + var signature = sequence.ReadBitString(out var _); + + var testSaltLength = customSaltLength switch + { + RSASignaturePadding.PssSaltLengthMax => 222, + RSASignaturePadding.PssSaltLengthIsHashLength => 32, + _ => customSaltLength + }; + Assert.True(rsa.VerifyData(tbsCertificate.Span, signature, HashAlgorithmName.SHA256, RSASignaturePadding.CreatePss(testSaltLength))); + } + } + [Theory] [InlineData("80", "0080")] [InlineData("0080", "0080")] From 81432d59670fc5b122c7c8c58aa39ac291ccdf5d Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Wed, 11 Jun 2025 10:47:54 +0200 Subject: [PATCH 09/32] More tests for the CertificateRequest --- .../RSAPssX509SignatureGenerator.cs | 2 -- .../tests/RSATests.cs | 6 ++++ .../CertificateRequestLoadTests.cs | 35 +++++++++++++------ .../X509Sha1SignatureGenerators.cs | 4 +-- 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs index fb1596cdb1b596..5f11907fbf00af 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs @@ -18,7 +18,6 @@ internal RSAPssX509SignatureGenerator(RSA key, RSASignaturePadding padding) Debug.Assert(padding != null); Debug.Assert(padding.Mode == RSASignaturePaddingMode.Pss); - // Currently we don't accept options in PSS mode, but we could, so store the padding here. _key = key; _padding = padding; } @@ -64,7 +63,6 @@ public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlg // * don't support SHA-1 in this class // * only support MGF-1 // * don't support the MGF PRF being different than hashAlgorithm - // * use saltLength==hashLength // * don't allow custom trailer // we don't have to worry about any of the DEFAULTs. (specify, specify, specify, omit). diff --git a/src/libraries/System.Security.Cryptography/tests/RSATests.cs b/src/libraries/System.Security.Cryptography/tests/RSATests.cs index 7b55391916c587..97bd8ed61002dd 100644 --- a/src/libraries/System.Security.Cryptography/tests/RSATests.cs +++ b/src/libraries/System.Security.Cryptography/tests/RSATests.cs @@ -226,6 +226,12 @@ public void RSASignaturePadding_Equality() Assert.False(RSASignaturePadding.Pkcs1.Equals((object)null)); Assert.False(RSASignaturePadding.Pkcs1 == null); Assert.True(RSASignaturePadding.Pkcs1 != null); + + Assert.True(RSASignaturePadding.CreatePss(15).Equals(RSASignaturePadding.CreatePss(15))); + Assert.False(RSASignaturePadding.CreatePss(15).Equals(RSASignaturePadding.CreatePss(16))); + Assert.False(RSASignaturePadding.Pkcs1.Equals(RSASignaturePadding.CreatePss(16))); + Assert.True(RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthMax).Equals(RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthMax))); + Assert.True(RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthIsHashLength).Equals(RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthIsHashLength))); } [Fact] diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs index 68cb327fa9af79..ea98c7b7468118 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs @@ -375,21 +375,34 @@ public static void VerifySignature_RSA_PKCS1(string hashAlgorithm) } [Theory] - [InlineData("SHA256")] - [InlineData("SHA384")] - [InlineData("SHA512")] - [InlineData("SHA1")] - public static void VerifySignature_RSA_PSS(string hashAlgorithm) + [InlineData("SHA256", 0)] + [InlineData("SHA384", 0)] + [InlineData("SHA512", 0)] + //[InlineData("SHA1", 0)] // The current implementation for CertificateRequest does not support SHA-1 with PSS. If this is required, the RSASha1PssSignatureGenerator and the RSAPssX509SignatureGenerator class needs updates. + [InlineData("SHA256", 1)] + [InlineData("SHA384", 1)] + [InlineData("SHA512", 1)] + //[InlineData("SHA1", 1)] // The current implementation for CertificateRequest does not support SHA-1 with PSS. If this is required, the RSASha1PssSignatureGenerator and the RSAPssX509SignatureGenerator class needs updates. + [InlineData("SHA256", RSASignaturePadding.PssSaltLengthMax)] + [InlineData("SHA384", RSASignaturePadding.PssSaltLengthMax)] + [InlineData("SHA512", RSASignaturePadding.PssSaltLengthMax)] + //[InlineData("SHA1", RSASignaturePadding.PssSaltLengthMax)] // The current implementation for CertificateRequest does not support SHA-1 with PSS. If this is required, the RSASha1PssSignatureGenerator and the RSAPssX509SignatureGenerator class needs updates. + [InlineData("SHA256", RSASignaturePadding.PssSaltLengthIsHashLength)] + [InlineData("SHA384", RSASignaturePadding.PssSaltLengthIsHashLength)] + [InlineData("SHA512", RSASignaturePadding.PssSaltLengthIsHashLength)] + [InlineData("SHA1", RSASignaturePadding.PssSaltLengthIsHashLength)] + public static void VerifySignature_RSA_PSS(string hashAlgorithm, int saltLength) { HashAlgorithmName hashAlgorithmName = new HashAlgorithmName(hashAlgorithm); using (RSA key = RSA.Create()) { + RSASignaturePadding padding = RSASignaturePadding.CreatePss(saltLength); CertificateRequest first = new CertificateRequest( "CN=Test", key, hashAlgorithmName, - RSASignaturePadding.Pss); + padding); byte[] pkcs10; @@ -397,11 +410,11 @@ public static void VerifySignature_RSA_PSS(string hashAlgorithm) { if (SignatureSupport.SupportsX509Sha1Signatures) { - pkcs10 = first.CreateSigningRequest(new RSASha1PssSignatureGenerator(key)); + pkcs10 = first.CreateSigningRequest(new RSASha1PssSignatureGenerator(key, padding)); } else { - Assert.ThrowsAny(() => first.CreateSigningRequest(new RSASha1PssSignatureGenerator(key))); + Assert.ThrowsAny(() => first.CreateSigningRequest(new RSASha1PssSignatureGenerator(key, padding))); return; } } @@ -411,19 +424,19 @@ public static void VerifySignature_RSA_PSS(string hashAlgorithm) } // Assert.NoThrow - CertificateRequest.LoadSigningRequest(pkcs10, hashAlgorithmName, out _); + CertificateRequest.LoadSigningRequest(pkcs10, hashAlgorithmName, out _, signerSignaturePadding: padding); pkcs10[^1] ^= 0xFF; Assert.Throws( - () => CertificateRequest.LoadSigningRequest(pkcs10, hashAlgorithmName, out _)); + () => CertificateRequest.LoadSigningRequest(pkcs10, hashAlgorithmName, out _, signerSignaturePadding: padding)); // Assert.NoThrow CertificateRequest.LoadSigningRequest( pkcs10, hashAlgorithmName, out _, - CertificateRequestLoadOptions.SkipSignatureValidation); + CertificateRequestLoadOptions.SkipSignatureValidation, signerSignaturePadding: padding); } } diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/X509Sha1SignatureGenerators.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/X509Sha1SignatureGenerators.cs index 0ed6da88215eb7..71904695a6ce5e 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/X509Sha1SignatureGenerators.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/X509Sha1SignatureGenerators.cs @@ -55,9 +55,9 @@ internal sealed class RSASha1PssSignatureGenerator : X509SignatureGenerator { private readonly X509SignatureGenerator _realRsaGenerator; - internal RSASha1PssSignatureGenerator(RSA rsa) + internal RSASha1PssSignatureGenerator(RSA rsa, RSASignaturePadding signaturePadding) { - _realRsaGenerator = CreateForRSA(rsa, RSASignaturePadding.Pss); + _realRsaGenerator = CreateForRSA(rsa, signaturePadding); } protected override PublicKey BuildPublicKey() => _realRsaGenerator.PublicKey; From a01638242fb07d7d34bcc459adcce0e9ff4977d9 Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Thu, 12 Jun 2025 08:38:03 +0200 Subject: [PATCH 10/32] Added custom salt support for SignedCms --- .../Cryptography/Pkcs/CmsSignature.RSA.cs | 49 ++++++++++++++++++- .../Cryptography/Pkcs/CmsSignature.cs | 10 +++- .../Security/Cryptography/Pkcs/CmsSigner.cs | 4 +- .../SignedCms/SignedCmsTests.netcoreapp.cs | 46 ++++++++++++----- .../ref/System.Security.Cryptography.cs | 1 + .../Cryptography/RSASignaturePadding.cs | 8 ++- 6 files changed, 100 insertions(+), 18 deletions(-) diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.RSA.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.RSA.cs index 9d4d237172e8a0..893e5b7fa8c1c5 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.RSA.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.RSA.cs @@ -283,12 +283,19 @@ private sealed class RSAPssCmsSignature : RSACmsSignature 0x01, 0x40, }; - internal override RSASignaturePadding? SignaturePadding => RSASignaturePadding.Pss; + internal override RSASignaturePadding SignaturePadding { get; } public RSAPssCmsSignature() : base(null, null) { + SignaturePadding = RSASignaturePadding.Pss; } +#if NET10_0_OR_GREATER + public RSAPssCmsSignature(int saltLength) : base(null, null) + { + SignaturePadding = RSASignaturePadding.CreatePss(saltLength); + } +#endif protected override RSASignaturePadding GetSignaturePadding( ReadOnlyMemory? signatureParameters, string? digestAlgorithmOid, @@ -337,13 +344,20 @@ protected override bool Sign( certificate, key, silent, - RSASignaturePadding.Pss, + SignaturePadding, out signatureValue); if (result) { signatureAlgorithm = Oids.RsaPss; +#if NET10_0_OR_GREATER + if (SignaturePadding.PssSaltLength != RSASignaturePadding.PssSaltLengthIsHashLength) + { + signatureParameters = GetSignaturePaddingForCustomPssSaltLength(certificate, hashAlgorithmName); + return result; + } +#endif if (hashAlgorithmName == HashAlgorithmName.SHA1) { signatureParameters = s_rsaPssSha1Parameters; @@ -378,6 +392,37 @@ protected override bool Sign( return result; } + +#if NET10_0_OR_GREATER + private byte[] GetSignaturePaddingForCustomPssSaltLength(X509Certificate2 certificate, HashAlgorithmName hashAlgorithmName) + { + string digestOid = PkcsHelpers.GetOidFromHashAlgorithm(hashAlgorithmName); + using RSA? publicKey = certificate.GetRSAPublicKey(); + Debug.Assert(publicKey != null, "Expected a public key to be present for PSS parameters."); + + PssParamsAsn parameters = new PssParamsAsn + { + HashAlgorithm = new AlgorithmIdentifierAsn { Algorithm = digestOid }, + MaskGenAlgorithm = new AlgorithmIdentifierAsn { Algorithm = Oids.Mgf1 }, + SaltLength = SignaturePadding.CalculatePssSaltLength(publicKey.KeySize, hashAlgorithmName), + TrailerField = 1 + }; + + AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); + + using (writer.PushSequence()) + { + writer.WriteObjectIdentifierForCrypto(digestOid); + } + + parameters.MaskGenAlgorithm.Parameters = writer.Encode(); + writer.Reset(); + + parameters.Encode(writer); + + return writer.Encode(); + } +#endif } } } diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.cs index ac08a6c975df92..b3c3a7d20cab1e 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.cs @@ -84,13 +84,19 @@ protected abstract bool Sign( // The processor is RSA, but does not agree with the specified signature padding, so override. if (processor.SignaturePadding != rsaSignaturePadding) { - if (rsaSignaturePadding == RSASignaturePadding.Pkcs1) + if (rsaSignaturePadding.Mode == RSASignaturePaddingMode.Pkcs1) { processor = s_lookup[Oids.Rsa]; Debug.Assert(processor is not null); } - else if (rsaSignaturePadding == RSASignaturePadding.Pss) + else if (rsaSignaturePadding.Mode == RSASignaturePaddingMode.Pss) { +#if NET10_0_OR_GREATER + if (rsaSignaturePadding.PssSaltLength != RSASignaturePadding.PssSaltLengthIsHashLength) + { + return new RSAPssCmsSignature(rsaSignaturePadding.PssSaltLength); + } +#endif processor = s_lookup[Oids.RsaPss]; Debug.Assert(processor is not null); } diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs index 3ff267bb3f8f3a..49df0e7322420c 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs @@ -62,7 +62,7 @@ private AsymmetricAlgorithm? PrivateKey set { if (value is not null && - value != RSASignaturePadding.Pkcs1 && value != RSASignaturePadding.Pss) + value != RSASignaturePadding.Pkcs1 && value.Mode != RSASignaturePaddingMode.Pss) { throw new ArgumentException(SR.Argument_InvalidRsaSignaturePadding, nameof(value)); } @@ -168,7 +168,7 @@ private CmsSigner( RSASignaturePadding? signaturePadding) { if (signaturePadding is not null && - signaturePadding != RSASignaturePadding.Pkcs1 && signaturePadding != RSASignaturePadding.Pss) + signaturePadding != RSASignaturePadding.Pkcs1 && signaturePadding.Mode != RSASignaturePaddingMode.Pss) { throw new ArgumentException(SR.Argument_InvalidRsaSignaturePadding, nameof(signaturePadding)); } diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.netcoreapp.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.netcoreapp.cs index faa41a19c7cb8b..11d71ec8c704c5 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.netcoreapp.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.netcoreapp.cs @@ -593,15 +593,39 @@ public static void CreateSignature_DigestAlgorithmWithSignatureOid_Prohibited() } [Theory] - [InlineData(Oids.Sha256, true)] - [InlineData(Oids.Sha384, true)] - [InlineData(Oids.Sha512, true)] - [InlineData(Oids.Sha1, true)] - [InlineData(Oids.Sha256, false)] - [InlineData(Oids.Sha384, false)] - [InlineData(Oids.Sha512, false)] - [InlineData(Oids.Sha1, false)] - public static void CreateSignature_RsaPss(string digestOid, bool assignByConstructor) + [InlineData(Oids.Sha256, true, 0)] + [InlineData(Oids.Sha384, true, 0)] + [InlineData(Oids.Sha512, true, 0)] + [InlineData(Oids.Sha1, true, 0)] + [InlineData(Oids.Sha256, false, 0)] + [InlineData(Oids.Sha384, false, 0)] + [InlineData(Oids.Sha512, false, 0)] + [InlineData(Oids.Sha1, false, 0)] + [InlineData(Oids.Sha256, true, 1)] + [InlineData(Oids.Sha384, true, 1)] + [InlineData(Oids.Sha512, true, 1)] + [InlineData(Oids.Sha1, true, 1)] + [InlineData(Oids.Sha256, false, 1)] + [InlineData(Oids.Sha384, false, 1)] + [InlineData(Oids.Sha512, false, 1)] + [InlineData(Oids.Sha1, false, 1)] + [InlineData(Oids.Sha256, true, RSASignaturePadding.PssSaltLengthMax)] + [InlineData(Oids.Sha384, true, RSASignaturePadding.PssSaltLengthMax)] + [InlineData(Oids.Sha512, true, RSASignaturePadding.PssSaltLengthMax)] + [InlineData(Oids.Sha1, true, RSASignaturePadding.PssSaltLengthMax)] + [InlineData(Oids.Sha256, false, RSASignaturePadding.PssSaltLengthMax)] + [InlineData(Oids.Sha384, false, RSASignaturePadding.PssSaltLengthMax)] + [InlineData(Oids.Sha512, false, RSASignaturePadding.PssSaltLengthMax)] + [InlineData(Oids.Sha1, false, RSASignaturePadding.PssSaltLengthMax)] + [InlineData(Oids.Sha256, true, RSASignaturePadding.PssSaltLengthIsHashLength)] + [InlineData(Oids.Sha384, true, RSASignaturePadding.PssSaltLengthIsHashLength)] + [InlineData(Oids.Sha512, true, RSASignaturePadding.PssSaltLengthIsHashLength)] + [InlineData(Oids.Sha1, true, RSASignaturePadding.PssSaltLengthIsHashLength)] + [InlineData(Oids.Sha256, false, RSASignaturePadding.PssSaltLengthIsHashLength)] + [InlineData(Oids.Sha384, false, RSASignaturePadding.PssSaltLengthIsHashLength)] + [InlineData(Oids.Sha512, false, RSASignaturePadding.PssSaltLengthIsHashLength)] + [InlineData(Oids.Sha1, false, RSASignaturePadding.PssSaltLengthIsHashLength)] + public static void CreateSignature_RsaPss(string digestOid, bool assignByConstructor, int saltLength) { ContentInfo content = new ContentInfo(new byte[] { 1, 2, 3 }); SignedCms cms = new SignedCms(content); @@ -613,12 +637,12 @@ public static void CreateSignature_RsaPss(string digestOid, bool assignByConstru if (assignByConstructor) { - signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, cert, null, RSASignaturePadding.Pss); + signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, cert, null, RSASignaturePadding.CreatePss(saltLength)); } else { signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, cert); - signer.SignaturePadding = RSASignaturePadding.Pss; + signer.SignaturePadding = RSASignaturePadding.CreatePss(saltLength); } signer.DigestAlgorithm = new Oid(digestOid, null); diff --git a/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs b/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs index afd3d7502a1ee9..64f01aa2e3e43b 100644 --- a/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs +++ b/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs @@ -2522,6 +2522,7 @@ internal RSASignaturePadding() { } public static System.Security.Cryptography.RSASignaturePadding Pkcs1 { get { throw null; } } public static System.Security.Cryptography.RSASignaturePadding Pss { get { throw null; } } public static RSASignaturePadding CreatePss(int saltLength) { throw null;} + public int CalculatePssSaltLength(int rsaKeySizeInBits, HashAlgorithmName hashAlgorithm) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } public bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] System.Security.Cryptography.RSASignaturePadding? other) { throw null; } public override int GetHashCode() { throw null; } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs index d3da560e0764a0..5f8cd0a0d8f1cf 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs @@ -75,7 +75,13 @@ public RSASignaturePaddingMode Mode get { return _mode; } } - internal int CalculatePssSaltLength(int rsaKeySizeInBits, HashAlgorithmName hashAlgorithm) + /// + /// Calculates the length of the salt for PSS signatures based on the RSA key size and hash algorithm. + /// + /// The key size of the RSA key used. + /// The hash algorithm used. + /// + public int CalculatePssSaltLength(int rsaKeySizeInBits, HashAlgorithmName hashAlgorithm) { int emLen = (rsaKeySizeInBits + 7) / 8; int hLen = RsaPaddingProcessor.HashLength(hashAlgorithm); From 9cde2fa657593ca0f8e7a165afc5fdd3eddd873c Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Tue, 8 Jul 2025 07:29:20 +0200 Subject: [PATCH 11/32] Add error handling for PSS salt length in CoseSigner Cose does not support custom salt lengths with PSS. --- .../src/Resources/Strings.resx | 5 ++++- .../System/Security/Cryptography/Cose/CoseSigner.cs | 9 +++++++++ .../tests/CoseSignerTests.cs | 11 +++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Security.Cryptography.Cose/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography.Cose/src/Resources/Strings.resx index 8a49f05e5e00e0..9986885ba181be 100644 --- a/src/libraries/System.Security.Cryptography.Cose/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography.Cose/src/Resources/Strings.resx @@ -237,4 +237,7 @@ Algorithm (alg) header is required and it must be a protected header. - \ No newline at end of file + + COSE does not support custom salt length for PSS signatures. + + diff --git a/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSigner.cs b/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSigner.cs index 64a38a7765b5a1..527e617c52ca6e 100644 --- a/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSigner.cs +++ b/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSigner.cs @@ -105,6 +105,15 @@ public CoseSigner(RSA key, RSASignaturePadding signaturePadding, HashAlgorithmNa ArgumentNullException.ThrowIfNull(key); ArgumentNullException.ThrowIfNull(signaturePadding); +#if NET10_0_OR_GREATER + if (signaturePadding.Mode == RSASignaturePaddingMode.Pss) + { + if (signaturePadding.PssSaltLength != RSASignaturePadding.PssSaltLengthIsHashLength) + { + throw new ArgumentException(SR.CoseSignerPssSaltLengthMustBeHashLength, nameof(signaturePadding)); + } + } +#endif Key = key; HashAlgorithm = hashAlgorithm; RSASignaturePadding = signaturePadding; diff --git a/src/libraries/System.Security.Cryptography.Cose/tests/CoseSignerTests.cs b/src/libraries/System.Security.Cryptography.Cose/tests/CoseSignerTests.cs index 3269f0acf0a20e..064f129d50f99e 100644 --- a/src/libraries/System.Security.Cryptography.Cose/tests/CoseSignerTests.cs +++ b/src/libraries/System.Security.Cryptography.Cose/tests/CoseSignerTests.cs @@ -53,5 +53,16 @@ public void CoseSigner_NullSignaturePadding() { Assert.Throws("signaturePadding", () => new CoseSigner(RSA.Create(), null!, HashAlgorithmName.SHA256)); } + +#if NET10_0_OR_GREATER + [Theory] + [InlineData(0)] + [InlineData(17)] + [InlineData(RSASignaturePadding.PssSaltLengthMax)] + public void CoseSigner_PssPaddingWithInvalidSaltLength(int saltLength) + { + Assert.Throws("signaturePadding", () => new CoseSigner(RSA.Create(), RSASignaturePadding.CreatePss(saltLength), HashAlgorithmName.SHA256)); + } +#endif } } From a6dd48a05e044ca0d3b4537511483c5268754313 Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Wed, 27 Aug 2025 07:10:06 +0200 Subject: [PATCH 12/32] Updated RSA --- .../Cryptography/HashAlgorithmNames.cs | 0 .../Security/Cryptography/RSAAndroid.cs | 4 +- .../Cryptography/RSACng.SignVerify.cs | 6 +- .../Security/Cryptography/RSAOpenSsl.cs | 6 +- .../Cryptography/RSASecurityTransforms.cs | 2 +- .../RsaPaddingProcessor.DigestInfo.cs | 142 ++++++++++++++++++ .../Cryptography/RsaPaddingProcessor.cs | 100 +----------- .../System.Security.Cryptography.Pkcs.csproj | 9 +- .../Cryptography/Pkcs/CmsSignature.RSA.cs | 2 +- .../ref/System.Security.Cryptography.cs | 1 - .../src/System.Security.Cryptography.csproj | 5 +- .../System/Security/Cryptography/RSABCrypt.cs | 4 +- .../Cryptography/RSASignaturePadding.cs | 21 +-- .../RSAPssX509SignatureGenerator.cs | 2 +- 14 files changed, 170 insertions(+), 134 deletions(-) rename src/libraries/{System.Security.Cryptography => Common}/src/System/Security/Cryptography/HashAlgorithmNames.cs (100%) create mode 100644 src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.DigestInfo.cs diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmNames.cs b/src/libraries/Common/src/System/Security/Cryptography/HashAlgorithmNames.cs similarity index 100% rename from src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmNames.cs rename to src/libraries/Common/src/System/Security/Cryptography/HashAlgorithmNames.cs diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs index 3cc91424420c1a..2d656ebd0ec7fd 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs @@ -688,7 +688,7 @@ private bool TrySignHash( } else if (padding.Mode == RSASignaturePaddingMode.Pss) { - RsaPaddingProcessor.EncodePss(hashAlgorithm, hash, encodedBytes, KeySize, padding.CalculatePssSaltLength(KeySize, hashAlgorithm)); + RsaPaddingProcessor.EncodePss(hashAlgorithm, hash, encodedBytes, KeySize, RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm)); } else { @@ -774,7 +774,7 @@ public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan sign } else if (padding == RSASignaturePadding.Pss) { - return RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, KeySize, padding.CalculatePssSaltLength(KeySize, hashAlgorithm)); + return RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, KeySize, RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm)); } else { diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs b/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs index 53e2f9b3f8d1fe..d5311b07f3e4fe 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs @@ -66,7 +66,7 @@ public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RS return keyHandle.SignHash(hash, AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, &pkcsPaddingInfo, estimatedSize); case RSASignaturePaddingMode.Pss: - var pssPaddingInfo = new BCRYPT_PSS_PADDING_INFO() { pszAlgId = namePtr, cbSalt = padding.CalculatePssSaltLength(KeySize, hashAlgorithm) }; + var pssPaddingInfo = new BCRYPT_PSS_PADDING_INFO() { pszAlgId = namePtr, cbSalt = RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm) }; return keyHandle.SignHash(hash, AsymmetricPaddingMode.NCRYPT_PAD_PSS_FLAG, &pssPaddingInfo, estimatedSize); default: @@ -107,7 +107,7 @@ public override unsafe bool TrySignHash(ReadOnlySpan hash, Span dest var pssPaddingInfo = new BCRYPT_PSS_PADDING_INFO() { pszAlgId = namePtr, - cbSalt = padding.CalculatePssSaltLength(KeySize, hashAlgorithm) + cbSalt = RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm) }; return keyHandle.TrySignHash(hash, destination, AsymmetricPaddingMode.NCRYPT_PAD_PSS_FLAG, &pssPaddingInfo, out bytesWritten); @@ -159,7 +159,7 @@ public override unsafe bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan hash, ReadOnlySpan sign return Interop.Crypto.RsaVerifyHash( key, padding.Mode, - padding.Mode == RSASignaturePaddingMode.Pss ? padding.CalculatePssSaltLength(KeySize, hashAlgorithm) : 0, + padding.Mode == RSASignaturePaddingMode.Pss ? RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm) : 0, hashAlgorithm, hash, signature); diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs index 595311f7fe7f7f..1010e2409fd33d 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs @@ -544,7 +544,7 @@ public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan sign throw new CryptographicException(); } Debug.Assert(bytesWritten == rsaSize); - return RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, keySize, padding.CalculatePssSaltLength(KeySize, hashAlgorithm)); + return RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, keySize, RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm)); } finally { diff --git a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.DigestInfo.cs b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.DigestInfo.cs new file mode 100644 index 00000000000000..c5ddf5350925e6 --- /dev/null +++ b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.DigestInfo.cs @@ -0,0 +1,142 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +namespace System.Security.Cryptography +{ + internal static partial class RsaPaddingProcessor + { + // DigestInfo header values taken from https://tools.ietf.org/html/rfc3447#section-9.2, Note 1. + private static ReadOnlySpan DigestInfoMD5 => + [ + 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, + 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, + 0x04, 0x10, + ]; + + private static ReadOnlySpan DigestInfoSha1 => + [ + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, + 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14, + ]; + + private static ReadOnlySpan DigestInfoSha256 => + [ + 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, + 0x20, + ]; + + private static ReadOnlySpan DigestInfoSha384 => + [ + 0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, + 0x30, + ]; + + private static ReadOnlySpan DigestInfoSha512 => + [ + 0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, + 0x40, + ]; + + private static ReadOnlySpan DigestInfoSha3_256 => + [ + 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, 0x02, 0x08, 0x05, 0x00, 0x04, + 0x20, + ]; + + private static ReadOnlySpan DigestInfoSha3_384 => + [ + 0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, 0x02, 0x09, 0x05, 0x00, 0x04, + 0x30, + ]; + + private static ReadOnlySpan DigestInfoSha3_512 => + [ + 0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A, 0x05, 0x00, 0x04, + 0x40, + ]; + + + /// + /// Represents a constant value indicating that the salt length should match the hash length. + /// + /// This value is typically used in cryptographic operations where the salt length is required to + /// be the same as the hash length. + public const int PssSaltLengthIsHashLength = -1; + /// + /// Represents the maximum allowable length, in bytes, for a PSS (Probabilistic Signature Scheme) salt. + /// + /// This constant is used to define the upper limit for the salt length in PSS-based + /// cryptographic operations. The maximum length is determined by the hash algorithm's output size. + public const int PssSaltLengthMax = -2; + + /// + /// Calculates the length of the salt for PSS signatures based on the RSA key size and hash algorithm. + /// + /// The salt lenght used for the padding. + /// The key size of the RSA key used. + /// The hash algorithm used. + /// + public static int CalculatePssSaltLength(int pssSaltLength, int rsaKeySizeInBits, HashAlgorithmName hashAlgorithm) + { + int emLen = (rsaKeySizeInBits + 7) / 8; + int hLen = HashLength(hashAlgorithm); + return pssSaltLength switch + { + PssSaltLengthMax => Math.Max(0, emLen - hLen - 2), + PssSaltLengthIsHashLength => hLen, + _ => pssSaltLength + }; + } + + private static ReadOnlySpan GetDigestInfoForAlgorithm( + HashAlgorithmName hashAlgorithmName, + out int digestLengthInBytes) + { + switch (hashAlgorithmName.Name) + { + case HashAlgorithmNames.MD5: + digestLengthInBytes = MD5.HashSizeInBytes; + return DigestInfoMD5; + case HashAlgorithmNames.SHA1: + digestLengthInBytes = SHA1.HashSizeInBytes; + return DigestInfoSha1; + case HashAlgorithmNames.SHA256: + digestLengthInBytes = SHA256.HashSizeInBytes; + return DigestInfoSha256; + case HashAlgorithmNames.SHA384: + digestLengthInBytes = SHA384.HashSizeInBytes; + return DigestInfoSha384; + case HashAlgorithmNames.SHA512: + digestLengthInBytes = SHA512.HashSizeInBytes; + return DigestInfoSha512; + case HashAlgorithmNames.SHA3_256: + digestLengthInBytes = SHA3_256.HashSizeInBytes; + return DigestInfoSha3_256; + case HashAlgorithmNames.SHA3_384: + digestLengthInBytes = SHA3_384.HashSizeInBytes; + return DigestInfoSha3_384; + case HashAlgorithmNames.SHA3_512: + digestLengthInBytes = SHA3_512.HashSizeInBytes; + return DigestInfoSha3_512; + default: + Debug.Fail("Unknown digest algorithm"); + throw new CryptographicException(); + } + } + + internal static int HashLength(HashAlgorithmName hashAlgorithmName) + { + GetDigestInfoForAlgorithm(hashAlgorithmName, out int hLen); + return hLen; + } + + } +} diff --git a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs index ac7da1357192d6..50390d252a02ae 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs @@ -8,113 +8,15 @@ namespace System.Security.Cryptography { - internal static class RsaPaddingProcessor + internal static partial class RsaPaddingProcessor { - // DigestInfo header values taken from https://tools.ietf.org/html/rfc3447#section-9.2, Note 1. - private static ReadOnlySpan DigestInfoMD5 => - [ - 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, - 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, - 0x04, 0x10, - ]; - - private static ReadOnlySpan DigestInfoSha1 => - [ - 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, - 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14, - ]; - - private static ReadOnlySpan DigestInfoSha256 => - [ - 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, - 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, - 0x20, - ]; - - private static ReadOnlySpan DigestInfoSha384 => - [ - 0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, - 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, - 0x30, - ]; - - private static ReadOnlySpan DigestInfoSha512 => - [ - 0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, - 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, - 0x40, - ]; - - private static ReadOnlySpan DigestInfoSha3_256 => - [ - 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, - 0x01, 0x65, 0x03, 0x04, 0x02, 0x08, 0x05, 0x00, 0x04, - 0x20, - ]; - - private static ReadOnlySpan DigestInfoSha3_384 => - [ - 0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, - 0x01, 0x65, 0x03, 0x04, 0x02, 0x09, 0x05, 0x00, 0x04, - 0x30, - ]; - - private static ReadOnlySpan DigestInfoSha3_512 => - [ - 0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, - 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A, 0x05, 0x00, 0x04, - 0x40, - ]; - private static ReadOnlySpan EightZeros => [0, 0, 0, 0, 0, 0, 0, 0]; - private static ReadOnlySpan GetDigestInfoForAlgorithm( - HashAlgorithmName hashAlgorithmName, - out int digestLengthInBytes) - { - switch (hashAlgorithmName.Name) - { - case HashAlgorithmNames.MD5: - digestLengthInBytes = MD5.HashSizeInBytes; - return DigestInfoMD5; - case HashAlgorithmNames.SHA1: - digestLengthInBytes = SHA1.HashSizeInBytes; - return DigestInfoSha1; - case HashAlgorithmNames.SHA256: - digestLengthInBytes = SHA256.HashSizeInBytes; - return DigestInfoSha256; - case HashAlgorithmNames.SHA384: - digestLengthInBytes = SHA384.HashSizeInBytes; - return DigestInfoSha384; - case HashAlgorithmNames.SHA512: - digestLengthInBytes = SHA512.HashSizeInBytes; - return DigestInfoSha512; - case HashAlgorithmNames.SHA3_256: - digestLengthInBytes = SHA3_256.HashSizeInBytes; - return DigestInfoSha3_256; - case HashAlgorithmNames.SHA3_384: - digestLengthInBytes = SHA3_384.HashSizeInBytes; - return DigestInfoSha3_384; - case HashAlgorithmNames.SHA3_512: - digestLengthInBytes = SHA3_512.HashSizeInBytes; - return DigestInfoSha3_512; - default: - Debug.Fail("Unknown digest algorithm"); - throw new CryptographicException(); - } - } - internal static int BytesRequiredForBitCount(int keySizeInBits) { return (int)(((uint)keySizeInBits + 7) / 8); } - internal static int HashLength(HashAlgorithmName hashAlgorithmName) - { - GetDigestInfoForAlgorithm(hashAlgorithmName, out int hLen); - return hLen; - } - internal static void PadPkcs1Encryption( ReadOnlySpan source, Span destination) diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj b/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj index cc3bd8acb8999d..7b9fbd64638afc 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent);$(NetCoreAppMinimum)-windows;$(NetCoreAppMinimum);netstandard2.1;netstandard2.0;$(NetFrameworkMinimum) @@ -719,6 +719,13 @@ System.Security.Cryptography.Pkcs.EnvelopedCms + + + + + diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.RSA.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.RSA.cs index 893e5b7fa8c1c5..927858b013498c 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.RSA.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.RSA.cs @@ -404,7 +404,7 @@ private byte[] GetSignaturePaddingForCustomPssSaltLength(X509Certificate2 certif { HashAlgorithm = new AlgorithmIdentifierAsn { Algorithm = digestOid }, MaskGenAlgorithm = new AlgorithmIdentifierAsn { Algorithm = Oids.Mgf1 }, - SaltLength = SignaturePadding.CalculatePssSaltLength(publicKey.KeySize, hashAlgorithmName), + SaltLength = RsaPaddingProcessor.CalculatePssSaltLength(SignaturePadding.PssSaltLength, publicKey.KeySize, hashAlgorithmName), TrailerField = 1 }; diff --git a/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs b/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs index 64f01aa2e3e43b..afd3d7502a1ee9 100644 --- a/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs +++ b/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs @@ -2522,7 +2522,6 @@ internal RSASignaturePadding() { } public static System.Security.Cryptography.RSASignaturePadding Pkcs1 { get { throw null; } } public static System.Security.Cryptography.RSASignaturePadding Pss { get { throw null; } } public static RSASignaturePadding CreatePss(int saltLength) { throw null;} - public int CalculatePssSaltLength(int rsaKeySizeInBits, HashAlgorithmName hashAlgorithm) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } public bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] System.Security.Cryptography.RSASignaturePadding? other) { throw null; } public override int GetHashCode() { throw null; } diff --git a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj index 236cd618d1d3c3..cb5f6a7d3e28ed 100644 --- a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj +++ b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj @@ -438,8 +438,12 @@ Link="Common\System\Security\Cryptography\RSAKeyFormatHelper.cs" /> + + - diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSABCrypt.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSABCrypt.cs index 2940d03424eb17..17bee3435880c3 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSABCrypt.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSABCrypt.cs @@ -294,7 +294,7 @@ public override bool TrySignHash( hash, destination, hashAlgorithmName, - padding.CalculatePssSaltLength(KeySize, hashAlgorithm), + RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm), out written); break; @@ -347,7 +347,7 @@ public override bool VerifyHash( key, hash, signature, - hashAlgorithmName, padding.CalculatePssSaltLength(KeySize, hashAlgorithm)); + hashAlgorithmName, RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm)); default: throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode); } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs index 5f8cd0a0d8f1cf..7a5ed02cd32d9a 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs @@ -16,13 +16,13 @@ public sealed class RSASignaturePadding : IEquatable /// /// This value is typically used in cryptographic operations where the salt length is required to /// be the same as the hash length. - public const int PssSaltLengthIsHashLength = -1; + public const int PssSaltLengthIsHashLength = RsaPaddingProcessor.PssSaltLengthIsHashLength; /// /// Represents the maximum allowable length, in bytes, for a PSS (Probabilistic Signature Scheme) salt. /// /// This constant is used to define the upper limit for the salt length in PSS-based /// cryptographic operations. The maximum length is determined by the hash algorithm's output size. - public const int PssSaltLengthMax = -2; + public const int PssSaltLengthMax = RsaPaddingProcessor.PssSaltLengthMax; public int PssSaltLength { @@ -75,23 +75,6 @@ public RSASignaturePaddingMode Mode get { return _mode; } } - /// - /// Calculates the length of the salt for PSS signatures based on the RSA key size and hash algorithm. - /// - /// The key size of the RSA key used. - /// The hash algorithm used. - /// - public int CalculatePssSaltLength(int rsaKeySizeInBits, HashAlgorithmName hashAlgorithm) - { - int emLen = (rsaKeySizeInBits + 7) / 8; - int hLen = RsaPaddingProcessor.HashLength(hashAlgorithm); - return PssSaltLength switch - { - PssSaltLengthMax => Math.Max(0, emLen - hLen - 2), - PssSaltLengthIsHashLength => hLen, - _ => PssSaltLength - }; - } public override int GetHashCode() { return HashCode.Combine(_mode, _pssSaltLength); diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs index 5f11907fbf00af..73e41fd666cdbf 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs @@ -53,7 +53,7 @@ public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlg SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name)); } - cbSalt = _padding.CalculatePssSaltLength(_key.KeySize, hashAlgorithm); + cbSalt = RsaPaddingProcessor.CalculatePssSaltLength(_padding.PssSaltLength, _key.KeySize, hashAlgorithm); // RFC 5754 says that the NULL for SHA2 (256/384/512) MUST be omitted // (https://tools.ietf.org/html/rfc5754#section-2) (and that you MUST From e2407bea3854769177b617756fa25175001fb3a6 Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Fri, 29 Aug 2025 07:14:55 +0200 Subject: [PATCH 13/32] Updated CoseSigner --- .../src/System/Security/Cryptography/Cose/CoseSigner.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSigner.cs b/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSigner.cs index c2252282fda597..10006785b9c973 100644 --- a/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSigner.cs +++ b/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSigner.cs @@ -122,9 +122,6 @@ public CoseSigner(RSA key, RSASignaturePadding signaturePadding, HashAlgorithmNa } } #endif - Key = key; - HashAlgorithm = hashAlgorithm; - RSASignaturePadding = signaturePadding; _protectedHeaders = protectedHeaders; _unprotectedHeaders = unprotectedHeaders; From 7b651407e063c77855395872a159652408ef2459 Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Fri, 29 Aug 2025 07:26:22 +0200 Subject: [PATCH 14/32] Code fixes --- .../Common/src/System/Security/Cryptography/RSAOpenSsl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index fd59c3788c6de2..04125148b4fd20 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -861,7 +861,7 @@ private static void ValidatePadding(RSASignaturePadding padding) } else if (padding.Mode == RSASignaturePaddingMode.Pss) { - if (padding.PssSaltLength < RSASignaturePadding.PssSaltLengthIsHashLength) + if (padding.PssSaltLength is < 0 and not RSASignaturePadding.PssSaltLengthMax and not RSASignaturePadding.PssSaltLengthMax) { throw PaddingModeNotSupported(); } From 623199cc8fbd5cd69dd35a92f55b9d6bbcc27914 Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Fri, 29 Aug 2025 07:29:27 +0200 Subject: [PATCH 15/32] Code fixes --- .../Common/src/System/Security/Cryptography/RSAOpenSsl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index 04125148b4fd20..bdf2887f0d5ad5 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -861,7 +861,7 @@ private static void ValidatePadding(RSASignaturePadding padding) } else if (padding.Mode == RSASignaturePaddingMode.Pss) { - if (padding.PssSaltLength is < 0 and not RSASignaturePadding.PssSaltLengthMax and not RSASignaturePadding.PssSaltLengthMax) + if (padding.PssSaltLength < RSASignaturePadding.PssSaltLengthMax) { throw PaddingModeNotSupported(); } From b14906e057bdb07040c06502d23ccd5a852f1f0f Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Fri, 29 Aug 2025 07:31:22 +0200 Subject: [PATCH 16/32] Code fixes --- .../Common/src/System/Security/Cryptography/RSAOpenSsl.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index bdf2887f0d5ad5..70b1e9de750801 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -861,10 +861,10 @@ private static void ValidatePadding(RSASignaturePadding padding) } else if (padding.Mode == RSASignaturePaddingMode.Pss) { - if (padding.PssSaltLength < RSASignaturePadding.PssSaltLengthMax) + /* if (padding.PssSaltLength < RSASignaturePadding.PssSaltLengthMax) { throw PaddingModeNotSupported(); - } + }*/ } else { From 9dcb4ea8e43aaaf3ef073f04ce707ff1e50efb33 Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Fri, 29 Aug 2025 07:34:04 +0200 Subject: [PATCH 17/32] Code fixes --- .../Common/src/System/Security/Cryptography/RSAOpenSsl.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index 70b1e9de750801..b501956c3fcb9a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -861,10 +861,12 @@ private static void ValidatePadding(RSASignaturePadding padding) } else if (padding.Mode == RSASignaturePaddingMode.Pss) { - /* if (padding.PssSaltLength < RSASignaturePadding.PssSaltLengthMax) + throw new InvalidCastException(); + /*if (padding.PssSaltLength < RSASignaturePadding.PssSaltLengthMax) { throw PaddingModeNotSupported(); - }*/ + } + */ } else { From fee0f0921ed11e625a068bd1d0b9c6dd2a0556ca Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Fri, 29 Aug 2025 07:36:15 +0200 Subject: [PATCH 18/32] Code fixes --- .../Common/src/System/Security/Cryptography/RSAOpenSsl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index b501956c3fcb9a..aa5e66ac8ed4dd 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -853,6 +853,7 @@ padding.OaepHashAlgorithm.Name is string name && private static void ValidatePadding(RSASignaturePadding padding) { ArgumentNullException.ThrowIfNull(padding); + throw new InvalidOperationException($"{padding.Mode}: {padding.PssSaltLength}"); // PKCS#1 does not currently have anything to validate. if (padding.Mode == RSASignaturePaddingMode.Pkcs1) @@ -861,7 +862,6 @@ private static void ValidatePadding(RSASignaturePadding padding) } else if (padding.Mode == RSASignaturePaddingMode.Pss) { - throw new InvalidCastException(); /*if (padding.PssSaltLength < RSASignaturePadding.PssSaltLengthMax) { throw PaddingModeNotSupported(); From a386baccfc65e97084dec09d766bc00dab2f390d Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Fri, 29 Aug 2025 07:38:22 +0200 Subject: [PATCH 19/32] Code fixes --- .../Common/src/System/Security/Cryptography/RSAOpenSsl.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index aa5e66ac8ed4dd..bdf2887f0d5ad5 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -853,7 +853,6 @@ padding.OaepHashAlgorithm.Name is string name && private static void ValidatePadding(RSASignaturePadding padding) { ArgumentNullException.ThrowIfNull(padding); - throw new InvalidOperationException($"{padding.Mode}: {padding.PssSaltLength}"); // PKCS#1 does not currently have anything to validate. if (padding.Mode == RSASignaturePaddingMode.Pkcs1) @@ -862,11 +861,10 @@ private static void ValidatePadding(RSASignaturePadding padding) } else if (padding.Mode == RSASignaturePaddingMode.Pss) { - /*if (padding.PssSaltLength < RSASignaturePadding.PssSaltLengthMax) + if (padding.PssSaltLength < RSASignaturePadding.PssSaltLengthMax) { throw PaddingModeNotSupported(); } - */ } else { From 430a84647db7c42dc7c62aac666023ac69805208 Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Mon, 1 Sep 2025 08:16:54 +0200 Subject: [PATCH 20/32] Updated a few test cases --- .../Security/Cryptography/RSAAndroid.cs | 4 +- .../RSACngPkcs8TestsHashSizePssSaltLength.cs | 10 + .../tests/RSACngPkcs8TestsPssSaltLength.cs | 29 +++ .../RSACngPkcs8TestsWitMaxPssSaltLength.cs | 10 + ...RSACngPkcs8TestsWithCustomPssSaltLength.cs | 11 + .../RSACngPkcs8TestsWithZeroPssSaltLength.cs | 10 + .../tests/RsaCngTests.cs | 9 +- ...tem.Security.Cryptography.Cng.Tests.csproj | 238 ++++++------------ 8 files changed, 158 insertions(+), 163 deletions(-) create mode 100644 src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsHashSizePssSaltLength.cs create mode 100644 src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsPssSaltLength.cs create mode 100644 src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWitMaxPssSaltLength.cs create mode 100644 src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs create mode 100644 src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithZeroPssSaltLength.cs diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs index 2d656ebd0ec7fd..c5ee4f688dd98a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs @@ -657,7 +657,7 @@ private bool TrySignHash( Debug.Assert(padding != null); signature = null; - if (padding != RSASignaturePadding.Pkcs1 && padding != RSASignaturePadding.Pss) + if (padding != RSASignaturePadding.Pkcs1 && padding.Mode != RSASignaturePaddingMode.Pss) { throw PaddingModeNotSupported(); } @@ -726,7 +726,7 @@ public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan sign { ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm)); ArgumentNullException.ThrowIfNull(padding); - if (padding != RSASignaturePadding.Pkcs1 && padding != RSASignaturePadding.Pss) + if (padding != RSASignaturePadding.Pkcs1 && padding.Mode != RSASignaturePaddingMode.Pss) { throw PaddingModeNotSupported(); } diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsHashSizePssSaltLength.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsHashSizePssSaltLength.cs new file mode 100644 index 00000000000000..e72dbfc1a1bb10 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsHashSizePssSaltLength.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Security.Cryptography.Cng.Tests +{ + public class RSACngPkcs8TestsHashSizePssSaltLength : RSACngPkcs8TestsPssSaltLength + { + protected override int SaltLength => RSASignaturePadding.PssSaltLengthIsHashLength; + } +} diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsPssSaltLength.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsPssSaltLength.cs new file mode 100644 index 00000000000000..69827cb58040f9 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsPssSaltLength.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; + +namespace System.Security.Cryptography.Cng.Tests +{ + public abstract class RSACngPkcs8TestsPssSaltLength : CngPkcs8Tests + { + protected override RSACng CreateKey(out CngKey cngKey) + { + RSACng rsa = new RSACng(); + cngKey = rsa.Key; + return rsa; + } + + protected override void VerifyMatch(RSACng exported, RSACng imported) + { + byte[] data = { 8, 4, 1, 2, 11 }; + HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA256; + RSASignaturePadding padding = RSASignaturePadding.CreatePss(SaltLength); + + byte[] signature = imported.SignData(data, hashAlgorithm, padding); + Assert.True(exported.VerifyData(data, signature, hashAlgorithm, padding)); + } + + protected abstract int SaltLength { get; } + } +} diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWitMaxPssSaltLength.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWitMaxPssSaltLength.cs new file mode 100644 index 00000000000000..f6497d1f88dda3 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWitMaxPssSaltLength.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Security.Cryptography.Cng.Tests +{ + public class RSACngPkcs8TestsWitMaxPssSaltLength : RSACngPkcs8TestsPssSaltLength + { + protected override int SaltLength => RSASignaturePadding.PssSaltLengthMax; + } +} diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs new file mode 100644 index 00000000000000..b30ae8f1894836 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Security.Cryptography.Cng.Tests +{ + + public class RSACngPkcs8TestsWithCustomPssSaltLength : RSACngPkcs8TestsPssSaltLength + { + protected override int SaltLength => 200; + } +} diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithZeroPssSaltLength.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithZeroPssSaltLength.cs new file mode 100644 index 00000000000000..64aa38c34b4b1a --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithZeroPssSaltLength.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Security.Cryptography.Cng.Tests +{ + public class RSACngPkcs8TestsWithZeroPssSaltLength : RSACngPkcs8TestsPssSaltLength + { + protected override int SaltLength => 0; + } +} diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RsaCngTests.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RsaCngTests.cs index 1d6310797ab28b..48d71efb025f93 100644 --- a/src/libraries/System.Security.Cryptography.Cng/tests/RsaCngTests.cs +++ b/src/libraries/System.Security.Cryptography.Cng/tests/RsaCngTests.cs @@ -15,12 +15,15 @@ namespace System.Security.Cryptography.Cng.Tests { public static class RsaCngTests { - [Fact] - public static void SignVerifyHashRoundTrip() + [Theory] + [InlineData(0)] + [InlineData(32)] + [InlineData(64)] + public static void SignVerifyHashRoundTrip(int saltLength) { byte[] message = "781021abcd982139a8bc91387870ac01".HexToByteArray(); byte[] hash = SHA1.Create().ComputeHash(message); - TestSignVerifyHashRoundTrip(hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pss, 0x100); + TestSignVerifyHashRoundTrip(hash, HashAlgorithmName.SHA1, RSASignaturePadding.CreatePss(saltLength), 0x100); } private static void TestSignVerifyHashRoundTrip(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding paddingMode, int expectedSignatureLength) diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj b/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj index e7ba206ca0c53d..dfdc7c0e20e511 100644 --- a/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj @@ -9,84 +9,53 @@ + - - - - - - + + + + + + - + - - - - - - - - - + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + + @@ -95,103 +64,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - + + + + + + + + + From e0eb70477199094c1c2767093778cf7b1b29a93f Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Mon, 1 Sep 2025 08:51:03 +0200 Subject: [PATCH 21/32] CRL Builder tests extended --- .../CertificateCreation/CrlBuilderTests.cs | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs index 6723283a95097a..b1598187ba75dd 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs @@ -22,6 +22,9 @@ public enum CertKind MLDsa, RsaPkcs1, RsaPss, + RsaPssWithCustomSaltLength, + RsaPssWithMaxSaltLength, + RsaPssWithZeroSaltLength, SlhDsa, } @@ -36,6 +39,9 @@ public static IEnumerable SupportedCertKinds() yield return new object[] { CertKind.RsaPkcs1 }; yield return new object[] { CertKind.RsaPss }; + yield return new object[] { CertKind.RsaPssWithCustomSaltLength }; + yield return new object[] { CertKind.RsaPssWithMaxSaltLength }; + yield return new object[] { CertKind.RsaPssWithZeroSaltLength }; if (SlhDsa.IsSupported) { @@ -1538,6 +1544,24 @@ private static void BuildCertificateAndRun( key = rsa; req = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA384, GetRsaPadding(certKind)); } + else if (certKind == CertKind.RsaPssWithMaxSaltLength) + { + var rsa = RSA.Create(); + key = rsa; + req = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA384, RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthMax)); + } + else if (certKind == CertKind.RsaPssWithCustomSaltLength) + { + var rsa = RSA.Create(); + key = rsa; + req = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA384, RSASignaturePadding.CreatePss(200)); + } + else if (certKind == CertKind.RsaPssWithZeroSaltLength) + { + var rsa = RSA.Create(); + key = rsa; + req = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA384, RSASignaturePadding.CreatePss(0)); + } else if (certKind == CertKind.MLDsa) { MLDsa mldsa = MLDsa.GenerateKey(MLDsaAlgorithm.MLDsa44); @@ -1696,7 +1720,7 @@ private static X509SignatureGenerator GetSignatureGenerator( X509Certificate2 cert, out IDisposable key) { - if (certKind == CertKind.RsaPkcs1 || certKind == CertKind.RsaPss) + if (certKind == CertKind.RsaPkcs1 || certKind == CertKind.RsaPss || certKind == CertKind.RsaPssWithZeroSaltLength || certKind == CertKind.RsaPssWithCustomSaltLength || certKind == CertKind.RsaPssWithMaxSaltLength) { RSA rsa = cert.GetRSAPrivateKey(); key = rsa; @@ -1735,7 +1759,7 @@ private static void VerifySignature( { bool signatureValid; - if (certKind == CertKind.RsaPkcs1 || certKind == CertKind.RsaPss) + if (certKind == CertKind.RsaPkcs1 || certKind == CertKind.RsaPss || certKind == CertKind.RsaPssWithZeroSaltLength || certKind == CertKind.RsaPssWithCustomSaltLength || certKind == CertKind.RsaPssWithMaxSaltLength) { using RSA rsa = cert.GetRSAPublicKey(); signatureValid = rsa.VerifyData(data, signature, hashAlgorithm, GetRsaPadding(certKind)); @@ -1770,7 +1794,7 @@ private static bool RequiresHashAlgorithm(CertKind certKind) { return certKind switch { - CertKind.ECDsa or CertKind.RsaPkcs1 or CertKind.RsaPss => true, + CertKind.ECDsa or CertKind.RsaPkcs1 or CertKind.RsaPss or CertKind.RsaPssWithCustomSaltLength or CertKind.RsaPssWithMaxSaltLength or CertKind.RsaPssWithZeroSaltLength => true, CertKind.MLDsa or CertKind.SlhDsa => false, _ => throw new NotSupportedException(certKind.ToString()) }; @@ -1782,6 +1806,9 @@ private static RSASignaturePadding GetRsaPadding(CertKind certKind) { CertKind.RsaPkcs1 => RSASignaturePadding.Pkcs1, CertKind.RsaPss => RSASignaturePadding.Pss, + CertKind.RsaPssWithCustomSaltLength => RSASignaturePadding.CreatePss(200), + CertKind.RsaPssWithZeroSaltLength => RSASignaturePadding.CreatePss(0), + CertKind.RsaPssWithMaxSaltLength => RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthMax), _ => null, }; } From dd6463603b95f694cb0435383f7c818d40147bde Mon Sep 17 00:00:00 2001 From: Henning Krause Date: Tue, 2 Sep 2025 07:51:52 +0200 Subject: [PATCH 22/32] Update src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../CertificateCreation/CertificateRequestChainTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs index deb497ec95c2c4..7b044495db78df 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs @@ -505,7 +505,7 @@ public static void CreateChain_RSAPSS(int saltLength) X509Certificate2 leafCert = null; CertificateRequest request; - RSASignaturePadding padding = RSASignaturePadding.CreatePss(saltLength); ; + RSASignaturePadding padding = RSASignaturePadding.CreatePss(saltLength); DateTimeOffset notBefore = DateTimeOffset.UtcNow; DateTimeOffset notAfter = notBefore.AddHours(1); From d97581cdb6525aafad8c52c8a7361842417e41d5 Mon Sep 17 00:00:00 2001 From: Henning Krause Date: Tue, 2 Sep 2025 07:52:00 +0200 Subject: [PATCH 23/32] Update src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../ref/System.Security.Cryptography.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs b/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs index 98ff9ae08d1d14..0a1b02fd3f431f 100644 --- a/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs +++ b/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs @@ -2743,7 +2743,7 @@ internal RSASignaturePadding() { } public int PssSaltLength { get { throw null; } } public static System.Security.Cryptography.RSASignaturePadding Pkcs1 { get { throw null; } } public static System.Security.Cryptography.RSASignaturePadding Pss { get { throw null; } } - public static RSASignaturePadding CreatePss(int saltLength) { throw null;} + public static RSASignaturePadding CreatePss(int saltLength) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } public bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] System.Security.Cryptography.RSASignaturePadding? other) { throw null; } public override int GetHashCode() { throw null; } From e99f10dbc92a4182825a9d80ffb6e4a66ef56ba3 Mon Sep 17 00:00:00 2001 From: Henning Krause Date: Tue, 2 Sep 2025 07:52:05 +0200 Subject: [PATCH 24/32] Update src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.DigestInfo.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Security/Cryptography/RsaPaddingProcessor.DigestInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.DigestInfo.cs b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.DigestInfo.cs index c5ddf5350925e6..6e5cfb978c8ea0 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.DigestInfo.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.DigestInfo.cs @@ -80,7 +80,7 @@ internal static partial class RsaPaddingProcessor /// /// Calculates the length of the salt for PSS signatures based on the RSA key size and hash algorithm. /// - /// The salt lenght used for the padding. + /// The salt length used for the padding. /// The key size of the RSA key used. /// The hash algorithm used. /// From f066e9741139f8d650705cbf594484338e0bdc92 Mon Sep 17 00:00:00 2001 From: Henning Krause Date: Tue, 2 Sep 2025 07:52:19 +0200 Subject: [PATCH 25/32] Update src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs index b30ae8f1894836..8da7d313de2955 100644 --- a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs +++ b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs @@ -3,7 +3,6 @@ namespace System.Security.Cryptography.Cng.Tests { - public class RSACngPkcs8TestsWithCustomPssSaltLength : RSACngPkcs8TestsPssSaltLength { protected override int SaltLength => 200; From de11a87a40335463e1b65c2e7768b3d34b8141e8 Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Wed, 3 Sep 2025 08:07:54 +0200 Subject: [PATCH 26/32] Fixed unit tests --- .../tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs | 1 - .../tests/System.Security.Cryptography.Cng.Tests.csproj | 3 ++- .../src/System/Security/Cryptography/Cose/CoseKey.cs | 5 ++++- .../src/System/Security/Cryptography/Cose/CoseSigner.cs | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs index b30ae8f1894836..8da7d313de2955 100644 --- a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs +++ b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs @@ -3,7 +3,6 @@ namespace System.Security.Cryptography.Cng.Tests { - public class RSACngPkcs8TestsWithCustomPssSaltLength : RSACngPkcs8TestsPssSaltLength { protected override int SaltLength => 200; diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj b/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj index dfdc7c0e20e511..91650a54fde340 100644 --- a/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj @@ -1,9 +1,10 @@ - + $(DefineConstants);TESTING_CNG_IMPLEMENTATION $(NetCoreAppCurrent)-windows + diff --git a/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseKey.cs b/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseKey.cs index ee7b02f00d1415..5b30569d85a85a 100644 --- a/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseKey.cs +++ b/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseKey.cs @@ -269,8 +269,11 @@ private static CoseAlgorithm GetRSAAlgorithm(RSASignaturePadding signaturePaddin { Debug.Assert(signaturePadding != null); - if (signaturePadding == RSASignaturePadding.Pss) + if (signaturePadding.Mode == RSASignaturePaddingMode.Pss) { +#if NET10_0_OR_GREATER + Debug.Assert(signaturePadding.PssSaltLength == RSASignaturePadding.PssSaltLengthIsHashLength); +#endif return hashAlgorithm.Name switch { nameof(HashAlgorithmName.SHA256) => CoseAlgorithm.PS256, diff --git a/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSigner.cs b/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSigner.cs index 10006785b9c973..90c1de42f1b489 100644 --- a/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSigner.cs +++ b/src/libraries/System.Security.Cryptography.Cose/src/System/Security/Cryptography/Cose/CoseSigner.cs @@ -112,7 +112,6 @@ public CoseSigner(RSA key, RSASignaturePadding signaturePadding, HashAlgorithmNa ArgumentNullException.ThrowIfNull(key); ArgumentNullException.ThrowIfNull(signaturePadding); - CoseKey = new CoseKey(key, signaturePadding, hashAlgorithm); #if NET10_0_OR_GREATER if (signaturePadding.Mode == RSASignaturePaddingMode.Pss) { @@ -122,6 +121,7 @@ public CoseSigner(RSA key, RSASignaturePadding signaturePadding, HashAlgorithmNa } } #endif + CoseKey = new CoseKey(key, signaturePadding, hashAlgorithm); _protectedHeaders = protectedHeaders; _unprotectedHeaders = unprotectedHeaders; From aeab1136715bc904943a774a31be35b29488295f Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Wed, 3 Sep 2025 12:46:59 +0200 Subject: [PATCH 27/32] Fixed tests --- .../Common/src/System/Security/Cryptography/RSAAppleCrypto.cs | 2 +- .../tests/SignedCms/SignedCmsWholeDocumentTests.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.cs index 158892d2c2153b..02b3af0a53f5d2 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.cs @@ -398,7 +398,7 @@ public override bool TrySignHash(ReadOnlySpan hash, Span destination ArgumentNullException.ThrowIfNull(padding); // Apple does not support custom salt length for the PSS padding - if (padding.Mode == RSASignaturePaddingMode.Pss && (padding.PssSaltLength != RSASignaturePadding.PssSaltLengthIsHashLength || padding.PssSaltLength != RsaPaddingProcessor.HashLength(hashAlgorithm))) + if (padding.Mode == RSASignaturePaddingMode.Pss && (padding.PssSaltLength != RSASignaturePadding.PssSaltLengthIsHashLength && padding.PssSaltLength != RsaPaddingProcessor.HashLength(hashAlgorithm))) { throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); } diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs index f3adf2c9af4cf7..488cbcb6a6022a 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs @@ -127,14 +127,14 @@ public static void ReadRsaPssDocument(bool fromSpan) Assert.Throws(() => signer.CheckHash()); // At this time we cannot support the PSS parameters for this document. - Assert.Throws(() => signer.CheckSignature(true)); + signer.CheckSignature(true); // Since there are no NoSignature signers the document CheckHash will succeed. // Assert.NotThrows cms.CheckHash(); // Since at least one signer fails, the document signature will fail - Assert.Throws(() => cms.CheckSignature(true)); + cms.CheckSignature(true); } [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))] From d70ef9b5720b0db62d0729bbbeb7b8bff2911ad4 Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Fri, 5 Sep 2025 08:06:26 +0200 Subject: [PATCH 28/32] Review changes --- .../Windows/BCrypt/Interop.BCryptSignHash.cs | 1 - .../BCrypt/Interop.BCryptVerifySignature.cs | 3 +- .../Security/Cryptography/RSAAndroid.cs | 5 +- .../Security/Cryptography/RSAAppleCrypto.cs | 9 +- .../Cryptography/RSACng.SignVerify.cs | 3 +- .../Security/Cryptography/RSAOpenSsl.cs | 15 +- .../RsaPaddingProcessor.DigestInfo.cs | 9 +- .../Cryptography/RsaPaddingProcessor.cs | 7 +- .../RSA/SignVerify.cs | 4 +- .../src/Microsoft.Bcl.Cryptography.csproj | 1 + .../RSACngPkcs8TestsHashSizePssSaltLength.cs | 10 - .../tests/RSACngPkcs8TestsPssSaltLength.cs | 29 --- .../RSACngPkcs8TestsWitMaxPssSaltLength.cs | 10 - ...RSACngPkcs8TestsWithCustomPssSaltLength.cs | 10 - .../RSACngPkcs8TestsWithZeroPssSaltLength.cs | 10 - .../tests/RsaCngTests.cs | 1 - ...tem.Security.Cryptography.Cng.Tests.csproj | 241 ++++++++++++------ .../src/Resources/Strings.resx | 6 +- .../System.Security.Cryptography.Pkcs.csproj | 2 +- .../src/Resources/Strings.resx | 6 + .../Cryptography/RSASignaturePadding.cs | 28 +- .../tests/RSATests.cs | 20 ++ .../CertificateRequestChainTests.cs | 1 - .../CertificateRequestLoadTests.cs | 5 - .../CertificateRequestUsageTests.cs | 13 +- .../CertificateCreation/CrlBuilderTests.cs | 15 +- .../RSAPssX509SignatureGeneratorTests.cs | 1 - 27 files changed, 256 insertions(+), 209 deletions(-) delete mode 100644 src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsHashSizePssSaltLength.cs delete mode 100644 src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsPssSaltLength.cs delete mode 100644 src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWitMaxPssSaltLength.cs delete mode 100644 src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs delete mode 100644 src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithZeroPssSaltLength.cs diff --git a/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptSignHash.cs b/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptSignHash.cs index b97239ab237fdc..2c33b59dbc1c28 100644 --- a/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptSignHash.cs +++ b/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptSignHash.cs @@ -4,7 +4,6 @@ using System; using System.Diagnostics; using System.Runtime.InteropServices; -using System.Security.Cryptography; using Internal.Cryptography; using Microsoft.Win32.SafeHandles; diff --git a/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptVerifySignature.cs b/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptVerifySignature.cs index e67b8ee6c432be..852660e6dde604 100644 --- a/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptVerifySignature.cs +++ b/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptVerifySignature.cs @@ -61,7 +61,8 @@ internal static unsafe bool BCryptVerifySignaturePss( SafeBCryptKeyHandle key, ReadOnlySpan hash, ReadOnlySpan signature, - string hashAlgorithmName, int saltLength) + string hashAlgorithmName, + int saltLength) { NTSTATUS status; diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs index c5ee4f688dd98a..d97cef8a38c3e7 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs @@ -772,9 +772,10 @@ public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan sign CryptoPool.Return(repadRent, requiredBytes); return valid; } - else if (padding == RSASignaturePadding.Pss) + else if (padding.Mode == RSASignaturePaddingMode.Pss) { - return RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, KeySize, RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm)); + int saltLength = RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm); + return RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, KeySize, saltLength); } else { diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.cs index 02b3af0a53f5d2..b012e3fb22818b 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.cs @@ -398,9 +398,11 @@ public override bool TrySignHash(ReadOnlySpan hash, Span destination ArgumentNullException.ThrowIfNull(padding); // Apple does not support custom salt length for the PSS padding - if (padding.Mode == RSASignaturePaddingMode.Pss && (padding.PssSaltLength != RSASignaturePadding.PssSaltLengthIsHashLength && padding.PssSaltLength != RsaPaddingProcessor.HashLength(hashAlgorithm))) + if (padding.Mode == RSASignaturePaddingMode.Pss && + (padding.PssSaltLength != RSASignaturePadding.PssSaltLengthIsHashLength && + padding.PssSaltLength != RsaPaddingProcessor.HashLength(hashAlgorithm))) { - throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); + throw new CryptographicException(SR.Cryptography_CustomPssSaltLengthNotSupported); } ThrowIfDisposed(); @@ -544,7 +546,8 @@ public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan sign throw new CryptographicException(); } Debug.Assert(bytesWritten == rsaSize); - return RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, keySize, RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm)); + int saltLength = RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm); + return RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, keySize, saltLength); } finally { diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs b/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs index d5311b07f3e4fe..bcdcf1224c7c88 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs @@ -66,7 +66,8 @@ public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RS return keyHandle.SignHash(hash, AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, &pkcsPaddingInfo, estimatedSize); case RSASignaturePaddingMode.Pss: - var pssPaddingInfo = new BCRYPT_PSS_PADDING_INFO() { pszAlgId = namePtr, cbSalt = RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm) }; + int saltLength = RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm); + var pssPaddingInfo = new BCRYPT_PSS_PADDING_INFO() { pszAlgId = namePtr, cbSalt = saltLength }; return keyHandle.SignHash(hash, AsymmetricPaddingMode.NCRYPT_PAD_PSS_FLAG, &pssPaddingInfo, estimatedSize); default: diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index bdf2887f0d5ad5..53b79e0d00ec77 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -735,7 +735,10 @@ public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RS int bytesRequired = Interop.Crypto.GetEvpPKeySizeBytes(key); byte[] signature = new byte[bytesRequired]; - int written = Interop.Crypto.RsaSignHash(key, padding.Mode, padding.Mode == RSASignaturePaddingMode.Pss ? RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm) : 0, hashAlgorithm, hash, signature); + int pssSaltLength = padding.Mode == RSASignaturePaddingMode.Pss + ? RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm) + : 0; + int written = Interop.Crypto.RsaSignHash(key, padding.Mode, pssSaltLength, hashAlgorithm, hash, signature); if (written != signature.Length) { @@ -766,7 +769,10 @@ public override bool TrySignHash( return false; } - bytesWritten = Interop.Crypto.RsaSignHash(key, padding.Mode, padding.Mode == RSASignaturePaddingMode.Pss ? RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm) : 0, hashAlgorithm, hash, destination); + int pssSaltLength = padding.Mode == RSASignaturePaddingMode.Pss + ? RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm) + : 0; + bytesWritten = Interop.Crypto.RsaSignHash(key, padding.Mode, pssSaltLength, hashAlgorithm, hash, destination); Debug.Assert(bytesWritten == bytesRequired); return true; } @@ -791,10 +797,13 @@ public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan sign SafeEvpPKeyHandle key = GetKey(); + int pssSaltLength = padding.Mode == RSASignaturePaddingMode.Pss + ? RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm) + : 0; return Interop.Crypto.RsaVerifyHash( key, padding.Mode, - padding.Mode == RSASignaturePaddingMode.Pss ? RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm) : 0, + pssSaltLength, hashAlgorithm, hash, signature); diff --git a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.DigestInfo.cs b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.DigestInfo.cs index 6e5cfb978c8ea0..34a0b6877b1fc9 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.DigestInfo.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.DigestInfo.cs @@ -69,13 +69,14 @@ internal static partial class RsaPaddingProcessor /// /// This value is typically used in cryptographic operations where the salt length is required to /// be the same as the hash length. - public const int PssSaltLengthIsHashLength = -1; + internal const int PssSaltLengthIsHashLength = -1; + /// /// Represents the maximum allowable length, in bytes, for a PSS (Probabilistic Signature Scheme) salt. /// /// This constant is used to define the upper limit for the salt length in PSS-based /// cryptographic operations. The maximum length is determined by the hash algorithm's output size. - public const int PssSaltLengthMax = -2; + internal const int PssSaltLengthMax = -2; /// /// Calculates the length of the salt for PSS signatures based on the RSA key size and hash algorithm. @@ -84,9 +85,9 @@ internal static partial class RsaPaddingProcessor /// The key size of the RSA key used. /// The hash algorithm used. /// - public static int CalculatePssSaltLength(int pssSaltLength, int rsaKeySizeInBits, HashAlgorithmName hashAlgorithm) + internal static int CalculatePssSaltLength(int pssSaltLength, int rsaKeySizeInBits, HashAlgorithmName hashAlgorithm) { - int emLen = (rsaKeySizeInBits + 7) / 8; + int emLen = (rsaKeySizeInBits + 7) >>> 3; int hLen = HashLength(hashAlgorithm); return pssSaltLength switch { diff --git a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs index 50390d252a02ae..4a10fd97a431c1 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs @@ -284,6 +284,8 @@ internal static void PadOaep( internal static void EncodePss(HashAlgorithmName hashAlgorithmName, ReadOnlySpan mHash, Span destination, int keySize, int saltLength) { + const int MaxStackSaltLength = 128; + int hLen = HashLength(hashAlgorithmName); // https://tools.ietf.org/html/rfc3447#section-9.1.1 @@ -325,7 +327,10 @@ internal static void EncodePss(HashAlgorithmName hashAlgorithmName, ReadOnlySpan Debug.Assert(hasher.HashLengthInBytes == hLen); // 4. Generate a random salt of length sLen Debug.Assert(hLen is >= 0 and <= 64); - Span salt = stackalloc byte[saltLength]; + + Span salt = saltLength > MaxStackSaltLength + ? new byte[saltLength] + : stackalloc byte[saltLength]; RandomNumberGenerator.Fill(salt); // 5. Let M' = an octet string of 8 zeros concat mHash concat salt diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs index 32a58b1200ea02..80877da36d1aa4 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs @@ -612,7 +612,7 @@ public void PssSignature_Sha_256_RSA2048_PSS_SaltLength_24(bool validateWithCorr using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params)) { - var signatureIsValid = VerifyData(rsa, data, signature, HashAlgorithmName.SHA256, padding); + bool signatureIsValid = VerifyData(rsa, data, signature, HashAlgorithmName.SHA256, padding); if (validateWithCorrectSaltLength) { Assert.True(signatureIsValid); @@ -1673,7 +1673,7 @@ public static IEnumerable PssRoundTripParameters { get { - int?[] saltLengths = [null, RSASignaturePadding.PssSaltLengthMax, RSASignaturePadding.PssSaltLengthIsHashLength, 0, 1, 4]; + int?[] saltLengths = [null, RSASignaturePadding.PssSaltLengthMax, RSASignaturePadding.PssSaltLengthIsHashLength, 1, 4]; foreach (var saltLength in saltLengths) { var padding = saltLength is null ? RSASignaturePadding.Pss : RSASignaturePadding.CreatePss(saltLength.Value); diff --git a/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj b/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj index f34fbaa03c6f13..01b2b281f2dd45 100644 --- a/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj +++ b/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj @@ -7,6 +7,7 @@ Provides support for some cryptographic primitives for .NET Framework and .NET Standard. $(NoWarn);SYSLIB5006 true + false diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsHashSizePssSaltLength.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsHashSizePssSaltLength.cs deleted file mode 100644 index e72dbfc1a1bb10..00000000000000 --- a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsHashSizePssSaltLength.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Security.Cryptography.Cng.Tests -{ - public class RSACngPkcs8TestsHashSizePssSaltLength : RSACngPkcs8TestsPssSaltLength - { - protected override int SaltLength => RSASignaturePadding.PssSaltLengthIsHashLength; - } -} diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsPssSaltLength.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsPssSaltLength.cs deleted file mode 100644 index 69827cb58040f9..00000000000000 --- a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsPssSaltLength.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Xunit; - -namespace System.Security.Cryptography.Cng.Tests -{ - public abstract class RSACngPkcs8TestsPssSaltLength : CngPkcs8Tests - { - protected override RSACng CreateKey(out CngKey cngKey) - { - RSACng rsa = new RSACng(); - cngKey = rsa.Key; - return rsa; - } - - protected override void VerifyMatch(RSACng exported, RSACng imported) - { - byte[] data = { 8, 4, 1, 2, 11 }; - HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA256; - RSASignaturePadding padding = RSASignaturePadding.CreatePss(SaltLength); - - byte[] signature = imported.SignData(data, hashAlgorithm, padding); - Assert.True(exported.VerifyData(data, signature, hashAlgorithm, padding)); - } - - protected abstract int SaltLength { get; } - } -} diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWitMaxPssSaltLength.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWitMaxPssSaltLength.cs deleted file mode 100644 index f6497d1f88dda3..00000000000000 --- a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWitMaxPssSaltLength.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Security.Cryptography.Cng.Tests -{ - public class RSACngPkcs8TestsWitMaxPssSaltLength : RSACngPkcs8TestsPssSaltLength - { - protected override int SaltLength => RSASignaturePadding.PssSaltLengthMax; - } -} diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs deleted file mode 100644 index 8da7d313de2955..00000000000000 --- a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithCustomPssSaltLength.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Security.Cryptography.Cng.Tests -{ - public class RSACngPkcs8TestsWithCustomPssSaltLength : RSACngPkcs8TestsPssSaltLength - { - protected override int SaltLength => 200; - } -} diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithZeroPssSaltLength.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithZeroPssSaltLength.cs deleted file mode 100644 index 64aa38c34b4b1a..00000000000000 --- a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkcs8TestsWithZeroPssSaltLength.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Security.Cryptography.Cng.Tests -{ - public class RSACngPkcs8TestsWithZeroPssSaltLength : RSACngPkcs8TestsPssSaltLength - { - protected override int SaltLength => 0; - } -} diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RsaCngTests.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RsaCngTests.cs index 48d71efb025f93..d08fdf2100e601 100644 --- a/src/libraries/System.Security.Cryptography.Cng/tests/RsaCngTests.cs +++ b/src/libraries/System.Security.Cryptography.Cng/tests/RsaCngTests.cs @@ -16,7 +16,6 @@ namespace System.Security.Cryptography.Cng.Tests public static class RsaCngTests { [Theory] - [InlineData(0)] [InlineData(32)] [InlineData(64)] public static void SignVerifyHashRoundTrip(int saltLength) diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj b/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj index 91650a54fde340..e7ba206ca0c53d 100644 --- a/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj @@ -1,62 +1,92 @@ - + $(DefineConstants);TESTING_CNG_IMPLEMENTATION $(NetCoreAppCurrent)-windows - - - - - - - - + + + + + + - + - - - - - - - - - + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + + @@ -65,56 +95,103 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - + + + + + + + + + diff --git a/src/libraries/System.Security.Cryptography.Cose/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography.Cose/src/Resources/Strings.resx index 9986885ba181be..a1438ee67031be 100644 --- a/src/libraries/System.Security.Cryptography.Cose/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography.Cose/src/Resources/Strings.resx @@ -150,6 +150,9 @@ Error while decoding CBOR-encoded value, see inner exception for details. + + COSE does not support custom salt length for PSS signatures. + RSA key needs a signature padding. @@ -237,7 +240,4 @@ Algorithm (alg) header is required and it must be a protected header. - - COSE does not support custom salt length for PSS signatures. - diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj b/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj index 3f3e803bc511b2..954e44ff188415 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent);$(NetCoreAppMinimum)-windows;$(NetCoreAppMinimum);netstandard2.1;netstandard2.0;$(NetFrameworkMinimum) diff --git a/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx index c62f5dac36b581..e0b2acef70c70d 100644 --- a/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx @@ -366,6 +366,9 @@ The specified curve '{0}' or its parameters are not valid for this platform. + + Custom salt lengths for PSS are not supported on this platform. + Custom trust certificates were provided while in System trust mode. @@ -522,6 +525,9 @@ Specified padding mode is not valid for this algorithm. + + Specified salt length is invalid. + The store handle is invalid. diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs index 7a5ed02cd32d9a..7baa8ff434d712 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs @@ -17,6 +17,7 @@ public sealed class RSASignaturePadding : IEquatable /// This value is typically used in cryptographic operations where the salt length is required to /// be the same as the hash length. public const int PssSaltLengthIsHashLength = RsaPaddingProcessor.PssSaltLengthIsHashLength; + /// /// Represents the maximum allowable length, in bytes, for a PSS (Probabilistic Signature Scheme) salt. /// @@ -24,21 +25,30 @@ public sealed class RSASignaturePadding : IEquatable /// cryptographic operations. The maximum length is determined by the hash algorithm's output size. public const int PssSaltLengthMax = RsaPaddingProcessor.PssSaltLengthMax; - public int PssSaltLength - { - get { return _pssSaltLength; } - } + /// + /// Specifies the salt length to use for PSS padding. This property is only relevant when the is . + /// + /// + /// This value must either be a positive number or one of the special constants or . + /// + public int PssSaltLength { get; } public static RSASignaturePadding CreatePss(int saltLength) { - return new RSASignaturePadding(saltLength); + switch (saltLength) + { + case PssSaltLengthIsHashLength or PssSaltLengthMax: + case > 0: + return new RSASignaturePadding(saltLength); + default: + throw new ArgumentOutOfRangeException(nameof(saltLength), SR.Cryptography_InvalidSaltLengthForPss); + } } private static readonly RSASignaturePadding s_pkcs1 = new RSASignaturePadding(RSASignaturePaddingMode.Pkcs1); private static readonly RSASignaturePadding s_pss = CreatePss(PssSaltLengthIsHashLength); private readonly RSASignaturePaddingMode _mode; - private readonly int _pssSaltLength; private RSASignaturePadding(RSASignaturePaddingMode mode) { @@ -48,7 +58,7 @@ private RSASignaturePadding(RSASignaturePaddingMode mode) private RSASignaturePadding(int pssSaltLength) { _mode = RSASignaturePaddingMode.Pss; - _pssSaltLength = pssSaltLength; + PssSaltLength = pssSaltLength; } /// @@ -77,7 +87,7 @@ public RSASignaturePaddingMode Mode public override int GetHashCode() { - return HashCode.Combine(_mode, _pssSaltLength); + return HashCode.Combine(_mode, PssSaltLength); } public override bool Equals([NotNullWhen(true)] object? obj) @@ -87,7 +97,7 @@ public override bool Equals([NotNullWhen(true)] object? obj) public bool Equals([NotNullWhen(true)] RSASignaturePadding? other) { - return other is not null && _mode == other._mode && _pssSaltLength == other._pssSaltLength; + return other is not null && _mode == other._mode && PssSaltLength == other.PssSaltLength; } public static bool operator ==(RSASignaturePadding? left, RSASignaturePadding? right) diff --git a/src/libraries/System.Security.Cryptography/tests/RSATests.cs b/src/libraries/System.Security.Cryptography/tests/RSATests.cs index 97bd8ed61002dd..7f965ea1e8ccd2 100644 --- a/src/libraries/System.Security.Cryptography/tests/RSATests.cs +++ b/src/libraries/System.Security.Cryptography/tests/RSATests.cs @@ -234,6 +234,26 @@ public void RSASignaturePadding_Equality() Assert.True(RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthIsHashLength).Equals(RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthIsHashLength))); } + [Theory] + [InlineData(2)] + [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] + [InlineData(RSASignaturePadding.PssSaltLengthMax)] + public void RSASignaturePadding_Constructor_ValidParameters(int saltLength) + { + RSASignaturePadding padding = RSASignaturePadding.CreatePss(saltLength); + Assert.Equal(RSASignaturePaddingMode.Pss, padding.Mode); + Assert.Equal(saltLength, padding.PssSaltLength); + } + + [Theory] + [InlineData(-3)] + [InlineData(0)] + public void RSASignaturePadding_Constructor_InvalidParameters(int saltLength) + { + ArgumentOutOfRangeException exception = Assert.Throws(() => RSASignaturePadding.CreatePss(saltLength)); + Assert.Equal("saltLength", exception.ParamName); + } + [Fact] public static void ExportPem_ExportRSAPublicKey() { diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs index 7b044495db78df..e43596501a4ace 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs @@ -490,7 +490,6 @@ private static void CreateAndTestChain( } [ConditionalTheory(nameof(PlatformSupportsPss))] - [InlineData(0)] [InlineData(1)] [InlineData(RSASignaturePadding.PssSaltLengthMax)] [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs index 3890d696a12372..0cfedaf8475bce 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs @@ -375,10 +375,6 @@ public static void VerifySignature_RSA_PKCS1(string hashAlgorithm) } [Theory] - [InlineData("SHA256", 0)] - [InlineData("SHA384", 0)] - [InlineData("SHA512", 0)] - //[InlineData("SHA1", 0)] // The current implementation for CertificateRequest does not support SHA-1 with PSS. If this is required, the RSASha1PssSignatureGenerator and the RSAPssX509SignatureGenerator class needs updates. [InlineData("SHA256", 1)] [InlineData("SHA384", 1)] [InlineData("SHA512", 1)] @@ -838,7 +834,6 @@ public static void LoadCreate_MatchesCreate_RSAPkcs1() } [Theory] - [InlineData(0)] [InlineData(4)] [InlineData(RSASignaturePadding.PssSaltLengthMax)] [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs index 8735802ca57a24..737da5410ab688 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs @@ -308,7 +308,6 @@ public static void SelfSign_ECC_DiminishedPoint_UseCertKeys() } [Theory] - [InlineData(0)] [InlineData(1)] [InlineData(RSASignaturePadding.PssSaltLengthMax)] [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] @@ -317,15 +316,15 @@ public static void SelfSign_RSA_PssPadding_CustomSaltLength(int customSaltLength using (RSA rsa = RSA.Create()) { var requestBuilder = new CertificateRequest("CN=Test", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.CreatePss(customSaltLength)); - var cert = requestBuilder.CreateSelfSigned(DateTime.Now, DateTime.Now.AddYears(1)); + X509Certificate2 cert = requestBuilder.CreateSelfSigned(DateTime.Now, DateTime.Now.AddYears(1)); var reader = new AsnReader(cert.RawData, AsnEncodingRules.DER); - var sequence = reader.ReadSequence(); - var tbsCertificate = sequence.ReadEncodedValue(); - var signatureAlgorithm = sequence.ReadEncodedValue(); - var signature = sequence.ReadBitString(out var _); + AsnReader sequence = reader.ReadSequence(); + ReadOnlyMemory tbsCertificate = sequence.ReadEncodedValue(); + ReadOnlyMemory signatureAlgorithm = sequence.ReadEncodedValue(); + byte[] signature = sequence.ReadBitString(out var _); - var testSaltLength = customSaltLength switch + int testSaltLength = customSaltLength switch { RSASignaturePadding.PssSaltLengthMax => 222, RSASignaturePadding.PssSaltLengthIsHashLength => 32, diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs index 7d20155851c15e..e7d3a197d8e140 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs @@ -24,7 +24,6 @@ public enum CertKind RsaPss, RsaPssWithCustomSaltLength, RsaPssWithMaxSaltLength, - RsaPssWithZeroSaltLength, SlhDsa, } @@ -41,7 +40,6 @@ public static IEnumerable SupportedCertKinds() yield return new object[] { CertKind.RsaPss }; yield return new object[] { CertKind.RsaPssWithCustomSaltLength }; yield return new object[] { CertKind.RsaPssWithMaxSaltLength }; - yield return new object[] { CertKind.RsaPssWithZeroSaltLength }; if (SlhDsa.IsSupported) { @@ -1555,12 +1553,6 @@ private static void BuildCertificateAndRun( key = rsa; req = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA384, RSASignaturePadding.CreatePss(200)); } - else if (certKind == CertKind.RsaPssWithZeroSaltLength) - { - var rsa = RSA.Create(); - key = rsa; - req = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA384, RSASignaturePadding.CreatePss(0)); - } else if (certKind == CertKind.MLDsa) { MLDsa mldsa = MLDsa.GenerateKey(MLDsaAlgorithm.MLDsa44); @@ -1719,7 +1711,7 @@ private static X509SignatureGenerator GetSignatureGenerator( X509Certificate2 cert, out IDisposable key) { - if (certKind == CertKind.RsaPkcs1 || certKind == CertKind.RsaPss || certKind == CertKind.RsaPssWithZeroSaltLength || certKind == CertKind.RsaPssWithCustomSaltLength || certKind == CertKind.RsaPssWithMaxSaltLength) + if (certKind == CertKind.RsaPkcs1 || certKind == CertKind.RsaPss || certKind == CertKind.RsaPssWithCustomSaltLength || certKind == CertKind.RsaPssWithMaxSaltLength) { RSA rsa = cert.GetRSAPrivateKey(); key = rsa; @@ -1758,7 +1750,7 @@ private static void VerifySignature( { bool signatureValid; - if (certKind == CertKind.RsaPkcs1 || certKind == CertKind.RsaPss || certKind == CertKind.RsaPssWithZeroSaltLength || certKind == CertKind.RsaPssWithCustomSaltLength || certKind == CertKind.RsaPssWithMaxSaltLength) + if (certKind == CertKind.RsaPkcs1 || certKind == CertKind.RsaPss ||certKind == CertKind.RsaPssWithCustomSaltLength || certKind == CertKind.RsaPssWithMaxSaltLength) { using RSA rsa = cert.GetRSAPublicKey(); signatureValid = rsa.VerifyData(data, signature, hashAlgorithm, GetRsaPadding(certKind)); @@ -1793,7 +1785,7 @@ private static bool RequiresHashAlgorithm(CertKind certKind) { return certKind switch { - CertKind.ECDsa or CertKind.RsaPkcs1 or CertKind.RsaPss or CertKind.RsaPssWithCustomSaltLength or CertKind.RsaPssWithMaxSaltLength or CertKind.RsaPssWithZeroSaltLength => true, + CertKind.ECDsa or CertKind.RsaPkcs1 or CertKind.RsaPss or CertKind.RsaPssWithCustomSaltLength or CertKind.RsaPssWithMaxSaltLength => true, CertKind.MLDsa or CertKind.SlhDsa => false, _ => throw new NotSupportedException(certKind.ToString()) }; @@ -1806,7 +1798,6 @@ private static RSASignaturePadding GetRsaPadding(CertKind certKind) CertKind.RsaPkcs1 => RSASignaturePadding.Pkcs1, CertKind.RsaPss => RSASignaturePadding.Pss, CertKind.RsaPssWithCustomSaltLength => RSASignaturePadding.CreatePss(200), - CertKind.RsaPssWithZeroSaltLength => RSASignaturePadding.CreatePss(0), CertKind.RsaPssWithMaxSaltLength => RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthMax), _ => null, }; diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs index aa102aee4dd5e0..681fe74729d7d9 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs @@ -59,7 +59,6 @@ public static void PublicKeyEncoding() [Theory] - [InlineData(0)] [InlineData(1)] [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] [InlineData(RSASignaturePadding.PssSaltLengthMax)] From 28f437198b3ca676ce7e0d570fdb9d1375185982 Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Tue, 9 Sep 2025 07:57:31 +0200 Subject: [PATCH 29/32] Fixed issues from review --- .../System/Security/Cryptography/RSAOpenSsl.cs | 6 ++---- .../tests/CoseSignerTests.cs | 1 + .../SignedCms/SignedCmsWholeDocumentTests.cs | 1 - .../System/Security/Cryptography/RSABCrypt.cs | 3 ++- .../Security/Cryptography/RSASignaturePadding.cs | 8 +++++++- .../RSAPssX509SignatureGenerator.cs | 7 ------- .../tests/RSATests.cs | 10 +++++----- .../CertificateRequestLoadTests.cs | 1 + .../RSAPssX509SignatureGeneratorTests.cs | 16 ++++++++-------- 9 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index 53b79e0d00ec77..06f9ab5cef22df 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -870,10 +870,8 @@ private static void ValidatePadding(RSASignaturePadding padding) } else if (padding.Mode == RSASignaturePaddingMode.Pss) { - if (padding.PssSaltLength < RSASignaturePadding.PssSaltLengthMax) - { - throw PaddingModeNotSupported(); - } + // PSS salt length is validated in the RsaSignaturePaddingMode constructor. + Debug.Assert(padding.PssSaltLength < RSASignaturePadding.PssSaltLengthMax); } else { diff --git a/src/libraries/System.Security.Cryptography.Cose/tests/CoseSignerTests.cs b/src/libraries/System.Security.Cryptography.Cose/tests/CoseSignerTests.cs index 4a4a44b2aa53c2..0aade42cec867c 100644 --- a/src/libraries/System.Security.Cryptography.Cose/tests/CoseSignerTests.cs +++ b/src/libraries/System.Security.Cryptography.Cose/tests/CoseSignerTests.cs @@ -82,6 +82,7 @@ public void CoseSigner_NullSignaturePadding() [Theory] [InlineData(0)] [InlineData(17)] + [InlineData(32)] [InlineData(RSASignaturePadding.PssSaltLengthMax)] public void CoseSigner_PssPaddingWithInvalidSaltLength(int saltLength) { diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs index 488cbcb6a6022a..eed726ea3c0195 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs @@ -126,7 +126,6 @@ public static void ReadRsaPssDocument(bool fromSpan) // CheckHash always throws for certificate-based signers. Assert.Throws(() => signer.CheckHash()); - // At this time we cannot support the PSS parameters for this document. signer.CheckSignature(true); // Since there are no NoSignature signers the document CheckHash will succeed. diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSABCrypt.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSABCrypt.cs index 17bee3435880c3..b52d593668b95c 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSABCrypt.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSABCrypt.cs @@ -347,7 +347,8 @@ public override bool VerifyHash( key, hash, signature, - hashAlgorithmName, RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm)); + hashAlgorithmName, + RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm)); default: throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode); } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs index 7baa8ff434d712..a630ac971d6fb2 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSASignaturePadding.cs @@ -33,12 +33,18 @@ public sealed class RSASignaturePadding : IEquatable /// public int PssSaltLength { get; } + /// + /// Creates a new instance of for PSS padding with a specific salt length. + /// + /// The length of the salt in bytes, or one of the constants or . + /// A new instance of configured for PSS padding with the specified salt length. + /// The is negative or not one of the special constants. public static RSASignaturePadding CreatePss(int saltLength) { switch (saltLength) { case PssSaltLengthIsHashLength or PssSaltLengthMax: - case > 0: + case >= 0: return new RSASignaturePadding(saltLength); default: throw new ArgumentOutOfRangeException(nameof(saltLength), SR.Cryptography_InvalidSaltLengthForPss); diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs index 73e41fd666cdbf..abd7b7def535f3 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs @@ -58,13 +58,6 @@ public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlg // RFC 5754 says that the NULL for SHA2 (256/384/512) MUST be omitted // (https://tools.ietf.org/html/rfc5754#section-2) (and that you MUST // be able to read it even if someone wrote it down) - // - // Since we - // * don't support SHA-1 in this class - // * only support MGF-1 - // * don't support the MGF PRF being different than hashAlgorithm - // * don't allow custom trailer - // we don't have to worry about any of the DEFAULTs. (specify, specify, specify, omit). PssParamsAsn parameters = new PssParamsAsn { diff --git a/src/libraries/System.Security.Cryptography/tests/RSATests.cs b/src/libraries/System.Security.Cryptography/tests/RSATests.cs index 7f965ea1e8ccd2..bdb812b88ea8eb 100644 --- a/src/libraries/System.Security.Cryptography/tests/RSATests.cs +++ b/src/libraries/System.Security.Cryptography/tests/RSATests.cs @@ -227,11 +227,11 @@ public void RSASignaturePadding_Equality() Assert.False(RSASignaturePadding.Pkcs1 == null); Assert.True(RSASignaturePadding.Pkcs1 != null); - Assert.True(RSASignaturePadding.CreatePss(15).Equals(RSASignaturePadding.CreatePss(15))); - Assert.False(RSASignaturePadding.CreatePss(15).Equals(RSASignaturePadding.CreatePss(16))); - Assert.False(RSASignaturePadding.Pkcs1.Equals(RSASignaturePadding.CreatePss(16))); - Assert.True(RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthMax).Equals(RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthMax))); - Assert.True(RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthIsHashLength).Equals(RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthIsHashLength))); + Assert.Equal(RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthIsHashLength), RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthIsHashLength)); + Assert.Equal(RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthMax), RSASignaturePadding.CreatePss(RSASignaturePadding.PssSaltLengthMax)); + Assert.Equal(RSASignaturePadding.CreatePss(15), RSASignaturePadding.CreatePss(15)); + Assert.NotEqual(RSASignaturePadding.CreatePss(15), RSASignaturePadding.CreatePss(16)); + Assert.NotEqual(RSASignaturePadding.Pkcs1, RSASignaturePadding.CreatePss(16)); } [Theory] diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs index 0cfedaf8475bce..ae1ab4ae46ab5c 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs @@ -834,6 +834,7 @@ public static void LoadCreate_MatchesCreate_RSAPkcs1() } [Theory] + [InlineData(0)] [InlineData(4)] [InlineData(RSASignaturePadding.PssSaltLengthMax)] [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs index 681fe74729d7d9..a0645d016cf3e4 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs @@ -57,7 +57,6 @@ public static void PublicKeyEncoding() } } - [Theory] [InlineData(1)] [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] @@ -71,17 +70,18 @@ public static void PssPaddingSaltLengths(int saltLengthToTest) RSASignaturePadding signaturePadding = RSASignaturePadding.CreatePss(saltLengthToTest); X509SignatureGenerator signatureGenerator = X509SignatureGenerator.CreateForRSA(rsa, signaturePadding); - var data = new byte[] { 1, 2, 3, 4, 5 }; - var signature = signatureGenerator.SignData(data, HashAlgorithmName.SHA256); - var signatureAlgorithm = signatureGenerator.GetSignatureAlgorithmIdentifier(HashAlgorithmName.SHA256); + byte[] data = new byte[] { 1, 2, 3, 4, 5 }; + byte[] signature = signatureGenerator.SignData(data, HashAlgorithmName.SHA256); + byte[] signatureAlgorithm = signatureGenerator.GetSignatureAlgorithmIdentifier(HashAlgorithmName.SHA256); - var asnReader = new AsnReader(signatureAlgorithm, AsnEncodingRules.DER); - var rootSequence = asnReader.ReadSequence(); + AsnReader asnReader = new AsnReader(signatureAlgorithm, AsnEncodingRules.DER); + AsnReader rootSequence = asnReader.ReadSequence(); Assert.Equal("1.2.840.113549.1.1.10", rootSequence.ReadObjectIdentifier()); // Make sure it's RSASSA-PSS - var pssStructure = rootSequence.ReadSequence(); + AsnReader pssStructure = rootSequence.ReadSequence(); pssStructure.ReadEncodedValue(); // Ignore the hash algorithm OID pssStructure.ReadEncodedValue(); // Ignore the mask generation function OID - var saltTag = new Asn1Tag(TagClass.ContextSpecific, 2, true); + Asn1Tag saltTag = new Asn1Tag(TagClass.ContextSpecific, 2, true); + if (pssStructure.HasData && pssStructure.PeekTag().HasSameClassAndValue(saltTag)) { var saltEntry = pssStructure.ReadSequence(saltTag); From 03d9b9a42d4b16b0e8a75c8459ba8d46fe30629a Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Wed, 10 Sep 2025 08:17:04 +0200 Subject: [PATCH 30/32] Fixed tests --- .../RSA/SignVerify.cs | 9 ++-- .../SignedCms/SignedCmsTests.netcoreapp.cs | 43 +++++------------- .../SignedCms/SignedCmsWholeDocumentTests.cs | 10 +++++ .../tests/RSATests.cs | 1 - .../CertificateRequestChainTests.cs | 14 +++++- .../CertificateRequestLoadTests.cs | 45 +++++++++++++++---- .../CertificateRequestUsageTests.cs | 4 +- .../CertificateCreation/CrlBuilderTests.cs | 9 +++- .../RSAPssX509SignatureGeneratorTests.cs | 4 +- .../X509Sha1SignatureGenerators.cs | 24 +++++++++- 10 files changed, 112 insertions(+), 51 deletions(-) diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs index 80877da36d1aa4..cfab54977168a3 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs @@ -43,6 +43,7 @@ public void NullArray_Throws() public abstract class SignVerify { public static bool SupportsPss => RSAFactory.SupportsPss; + public static bool AreCustomPssSaltLengthsSupported => PlatformDetection.IsWindows || PlatformDetection.IsLinux; protected abstract byte[] SignData(RSA rsa, byte[] data, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding); protected abstract byte[] SignHash(RSA rsa, byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding); @@ -582,7 +583,7 @@ public void VerifySignature_SHA3_512_RSA2048() VerifySignature(signature, TestData.HelloBytes, HashAlgorithmName.SHA3_512.Name, TestData.RSA2048Params); } - [ConditionalTheory(nameof(SupportsPss))] + [ConditionalTheory(nameof(AreCustomPssSaltLengthsSupported))] [InlineData(true)] [InlineData(false)] public void PssSignature_Sha_256_RSA2048_PSS_SaltLength_24(bool validateWithCorrectSaltLength) @@ -624,7 +625,7 @@ public void PssSignature_Sha_256_RSA2048_PSS_SaltLength_24(bool validateWithCorr } } - [ConditionalTheory(nameof(SupportsPss))] + [ConditionalTheory(nameof(AreCustomPssSaltLengthsSupported))] [InlineData(true)] [InlineData(false)] public void PssSignature_Sha_256_RSA2048_PSS_SaltLength_Max(bool validateWithCorrectSaltLength) @@ -1673,7 +1674,9 @@ public static IEnumerable PssRoundTripParameters { get { - int?[] saltLengths = [null, RSASignaturePadding.PssSaltLengthMax, RSASignaturePadding.PssSaltLengthIsHashLength, 1, 4]; + int?[] saltLengths = AreCustomPssSaltLengthsSupported + ? [null, RSASignaturePadding.PssSaltLengthMax, RSASignaturePadding.PssSaltLengthIsHashLength, 0, 1, 4] + : [null]; foreach (var saltLength in saltLengths) { var padding = saltLength is null ? RSASignaturePadding.Pss : RSASignaturePadding.CreatePss(saltLength.Value); diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.netcoreapp.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.netcoreapp.cs index d2268bdf724213..3e7f60a1eac005 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.netcoreapp.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.netcoreapp.cs @@ -14,6 +14,8 @@ namespace System.Security.Cryptography.Pkcs.Tests { public static partial class SignedCmsTests { + private static bool AreCustomPssSaltLengthsSupported => PlatformDetection.IsWindows || PlatformDetection.IsLinux; + [Fact] public static void CmsSignerKeyIsNullByDefault() { @@ -684,38 +686,7 @@ public static void CreateSignature_DigestAlgorithmWithSignatureOid_Prohibited() } [Theory] - [InlineData(Oids.Sha256, true, 0)] - [InlineData(Oids.Sha384, true, 0)] - [InlineData(Oids.Sha512, true, 0)] - [InlineData(Oids.Sha1, true, 0)] - [InlineData(Oids.Sha256, false, 0)] - [InlineData(Oids.Sha384, false, 0)] - [InlineData(Oids.Sha512, false, 0)] - [InlineData(Oids.Sha1, false, 0)] - [InlineData(Oids.Sha256, true, 1)] - [InlineData(Oids.Sha384, true, 1)] - [InlineData(Oids.Sha512, true, 1)] - [InlineData(Oids.Sha1, true, 1)] - [InlineData(Oids.Sha256, false, 1)] - [InlineData(Oids.Sha384, false, 1)] - [InlineData(Oids.Sha512, false, 1)] - [InlineData(Oids.Sha1, false, 1)] - [InlineData(Oids.Sha256, true, RSASignaturePadding.PssSaltLengthMax)] - [InlineData(Oids.Sha384, true, RSASignaturePadding.PssSaltLengthMax)] - [InlineData(Oids.Sha512, true, RSASignaturePadding.PssSaltLengthMax)] - [InlineData(Oids.Sha1, true, RSASignaturePadding.PssSaltLengthMax)] - [InlineData(Oids.Sha256, false, RSASignaturePadding.PssSaltLengthMax)] - [InlineData(Oids.Sha384, false, RSASignaturePadding.PssSaltLengthMax)] - [InlineData(Oids.Sha512, false, RSASignaturePadding.PssSaltLengthMax)] - [InlineData(Oids.Sha1, false, RSASignaturePadding.PssSaltLengthMax)] - [InlineData(Oids.Sha256, true, RSASignaturePadding.PssSaltLengthIsHashLength)] - [InlineData(Oids.Sha384, true, RSASignaturePadding.PssSaltLengthIsHashLength)] - [InlineData(Oids.Sha512, true, RSASignaturePadding.PssSaltLengthIsHashLength)] - [InlineData(Oids.Sha1, true, RSASignaturePadding.PssSaltLengthIsHashLength)] - [InlineData(Oids.Sha256, false, RSASignaturePadding.PssSaltLengthIsHashLength)] - [InlineData(Oids.Sha384, false, RSASignaturePadding.PssSaltLengthIsHashLength)] - [InlineData(Oids.Sha512, false, RSASignaturePadding.PssSaltLengthIsHashLength)] - [InlineData(Oids.Sha1, false, RSASignaturePadding.PssSaltLengthIsHashLength)] + [MemberData(nameof(CreateSignature_RsaPssTests))] public static void CreateSignature_RsaPss(string digestOid, bool assignByConstructor, int saltLength) { ContentInfo content = new ContentInfo(new byte[] { 1, 2, 3 }); @@ -757,6 +728,14 @@ public static void CreateSignature_RsaPss(string digestOid, bool assignByConstru } } + public static IEnumerable CreateSignature_RsaPssTests() => + from oid in (string[])([Oids.Sha256, Oids.Sha384, Oids.Sha512, Oids.Sha1]) + from byCtor in new[] { true, false } + from saltLength in AreCustomPssSaltLengthsSupported + ? new[] { 0, RSASignaturePadding.PssSaltLengthMax, RSASignaturePadding.PssSaltLengthIsHashLength } + : new[] { RSASignaturePadding.PssSaltLengthIsHashLength } + select new object[] { oid, byCtor, saltLength }; + [Fact] public static void CreateSignature_RsaPss_SeparateKey() { diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs index eed726ea3c0195..bea89598dbf2a9 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs @@ -126,14 +126,24 @@ public static void ReadRsaPssDocument(bool fromSpan) // CheckHash always throws for certificate-based signers. Assert.Throws(() => signer.CheckHash()); + // PSS signature with parameters are only supported on .NET 10 or later +#if NET10_0_OR_GREATER signer.CheckSignature(true); +#else + Assert.Throws(() => signer.CheckSignature(true)); +#endif // Since there are no NoSignature signers the document CheckHash will succeed. // Assert.NotThrows cms.CheckHash(); + // PSS signature with parameters are only supported on .NET 10 or later +#if NET10_0_OR_GREATER // Since at least one signer fails, the document signature will fail cms.CheckSignature(true); +#else + Assert.Throws(() => cms.CheckSignature(true)); +#endif } [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))] diff --git a/src/libraries/System.Security.Cryptography/tests/RSATests.cs b/src/libraries/System.Security.Cryptography/tests/RSATests.cs index bdb812b88ea8eb..b48cbe8f2aad4f 100644 --- a/src/libraries/System.Security.Cryptography/tests/RSATests.cs +++ b/src/libraries/System.Security.Cryptography/tests/RSATests.cs @@ -247,7 +247,6 @@ public void RSASignaturePadding_Constructor_ValidParameters(int saltLength) [Theory] [InlineData(-3)] - [InlineData(0)] public void RSASignaturePadding_Constructor_InvalidParameters(int saltLength) { ArgumentOutOfRangeException exception = Assert.Throws(() => RSASignaturePadding.CreatePss(saltLength)); diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs index e43596501a4ace..f28206cf2dbf2d 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs @@ -13,6 +13,7 @@ public static class CertificateRequestChainTests // Android supports PSS at the algorithms layer, but does not support it // being used in cert chains. public static bool PlatformSupportsPss { get; } = !PlatformDetection.IsAndroid && PlatformSupport.IsRsaPssSupported; + private static bool AreCustomPssSaltLengthsSupported => PlatformDetection.IsWindows || PlatformDetection.IsLinux; [Fact] public static void CreateChain_ECC() @@ -489,11 +490,22 @@ private static void CreateAndTestChain( } } - [ConditionalTheory(nameof(PlatformSupportsPss))] + [ConditionalTheory(nameof(AreCustomPssSaltLengthsSupported))] [InlineData(1)] [InlineData(RSASignaturePadding.PssSaltLengthMax)] [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] public static void CreateChain_RSAPSS(int saltLength) + { + CreateChain_RSAPSSCore(saltLength); + } + + [ConditionalFact(nameof(PlatformSupportsPss))] + public static void CreateChain_RSAPSS_SaltLengthIsHashLength() + { + CreateChain_RSAPSSCore(RSASignaturePadding.PssSaltLengthIsHashLength); + } + + private static void CreateChain_RSAPSSCore(int saltLength) { using (RSA rootKey = RSA.Create()) using (RSA intermedKey = RSA.Create()) diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs index ae1ab4ae46ab5c..2ba874633b111c 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs @@ -11,6 +11,8 @@ namespace System.Security.Cryptography.X509Certificates.Tests.CertificateCreatio [SkipOnPlatform(TestPlatforms.Browser, "Browser doesn't support X.509 certificates")] public static class CertificateRequestLoadTests { + private static bool AreCustomPssSaltLengthsSupported => PlatformDetection.IsWindows || PlatformDetection.IsLinux; + [Theory] [InlineData(CertificateRequestLoadOptions.Default, false)] [InlineData(CertificateRequestLoadOptions.UnsafeLoadCertificateExtensions, false)] @@ -374,20 +376,35 @@ public static void VerifySignature_RSA_PKCS1(string hashAlgorithm) } } - [Theory] + [ConditionalTheory(nameof(AreCustomPssSaltLengthsSupported))] [InlineData("SHA256", 1)] [InlineData("SHA384", 1)] [InlineData("SHA512", 1)] - //[InlineData("SHA1", 1)] // The current implementation for CertificateRequest does not support SHA-1 with PSS. If this is required, the RSASha1PssSignatureGenerator and the RSAPssX509SignatureGenerator class needs updates. + [InlineData("SHA1", 1)] [InlineData("SHA256", RSASignaturePadding.PssSaltLengthMax)] [InlineData("SHA384", RSASignaturePadding.PssSaltLengthMax)] [InlineData("SHA512", RSASignaturePadding.PssSaltLengthMax)] - //[InlineData("SHA1", RSASignaturePadding.PssSaltLengthMax)] // The current implementation for CertificateRequest does not support SHA-1 with PSS. If this is required, the RSASha1PssSignatureGenerator and the RSAPssX509SignatureGenerator class needs updates. + [InlineData("SHA1", RSASignaturePadding.PssSaltLengthMax)] [InlineData("SHA256", RSASignaturePadding.PssSaltLengthIsHashLength)] [InlineData("SHA384", RSASignaturePadding.PssSaltLengthIsHashLength)] [InlineData("SHA512", RSASignaturePadding.PssSaltLengthIsHashLength)] [InlineData("SHA1", RSASignaturePadding.PssSaltLengthIsHashLength)] - public static void VerifySignature_RSA_PSS(string hashAlgorithm, int saltLength) + public static void VerifySignature_RSA_PSS_CustomSaltLength(string hashAlgorithm, int saltLength) + { + VerifySignature_RSA_PSSCore(hashAlgorithm, saltLength); + } + + [Theory] + [InlineData("SHA256")] + [InlineData("SHA384")] + [InlineData("SHA512")] + [InlineData("SHA1")] + public static void VerifySignature_RSA_PSS_SaltLengthIsHashLength(string hashAlgorithm) + { + VerifySignature_RSA_PSSCore(hashAlgorithm, RSASignaturePadding.PssSaltLengthIsHashLength); + } + + private static bool VerifySignature_RSA_PSSCore(string hashAlgorithm, int saltLength) { HashAlgorithmName hashAlgorithmName = new HashAlgorithmName(hashAlgorithm); @@ -411,7 +428,7 @@ public static void VerifySignature_RSA_PSS(string hashAlgorithm, int saltLength) else { Assert.ThrowsAny(() => first.CreateSigningRequest(new RSASha1PssSignatureGenerator(key, padding))); - return; + return false; } } else @@ -434,6 +451,8 @@ public static void VerifySignature_RSA_PSS(string hashAlgorithm, int saltLength) out _, CertificateRequestLoadOptions.SkipSignatureValidation, signerSignaturePadding: padding); } + + return true; } [ConditionalFact(typeof(PlatformSupport), nameof(PlatformSupport.IsDSASupported))] @@ -833,12 +852,22 @@ public static void LoadCreate_MatchesCreate_RSAPkcs1() } } - [Theory] + [ConditionalTheory(nameof(AreCustomPssSaltLengthsSupported))] [InlineData(0)] [InlineData(4)] [InlineData(RSASignaturePadding.PssSaltLengthMax)] - [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] - public static void LoadCreate_MatchesCreate_RSAPss(int saltLength) + public static void LoadCreate_MatchesCreate_RSAPss_CustomSaltLength(int saltLength) + { + LoadCreate_MatchesCreate_RSAPssCore(saltLength); + } + + [Fact] + public static void LoadCreate_MatchesCreate_RSAPss_SaltLengthIsHashLength() + { + LoadCreate_MatchesCreate_RSAPssCore(RSASignaturePadding.PssSaltLengthIsHashLength); + } + + private static void LoadCreate_MatchesCreate_RSAPssCore(int saltLength) { using (RSA key = RSA.Create(2048)) { diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs index 737da5410ab688..602c492df1dade 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs @@ -12,6 +12,8 @@ namespace System.Security.Cryptography.X509Certificates.Tests.CertificateCreatio [SkipOnPlatform(TestPlatforms.Browser, "Browser doesn't support X.509 certificates")] public static class CertificateRequestUsageTests { + private static bool AreCustomPssSaltLengthsSupported => PlatformDetection.IsWindows || PlatformDetection.IsLinux; + [Fact] public static void ReproduceBigExponentCsr() { @@ -307,7 +309,7 @@ public static void SelfSign_ECC_DiminishedPoint_UseCertKeys() } } - [Theory] + [ConditionalTheory(nameof(AreCustomPssSaltLengthsSupported))] [InlineData(1)] [InlineData(RSASignaturePadding.PssSaltLengthMax)] [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs index 895f623ec5591d..debc48de015953 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs @@ -14,6 +14,8 @@ namespace System.Security.Cryptography.X509Certificates.Tests.CertificateCreatio [SkipOnPlatform(TestPlatforms.Browser, "Browser doesn't support asymmetric cryptography")] public static class CrlBuilderTests { + private static bool AreCustomPssSaltLengthsSupported => PlatformDetection.IsWindows || PlatformDetection.IsLinux; + private const string CertParam = "issuerCertificate"; public enum CertKind @@ -38,8 +40,11 @@ public static IEnumerable SupportedCertKinds() yield return new object[] { CertKind.RsaPkcs1 }; yield return new object[] { CertKind.RsaPss }; - yield return new object[] { CertKind.RsaPssWithCustomSaltLength }; - yield return new object[] { CertKind.RsaPssWithMaxSaltLength }; + if (AreCustomPssSaltLengthsSupported) + { + yield return new object[] { CertKind.RsaPssWithCustomSaltLength }; + yield return new object[] { CertKind.RsaPssWithMaxSaltLength }; + } if (SlhDsa.IsSupported) { diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs index a0645d016cf3e4..7e337dcd463fcb 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs @@ -10,6 +10,8 @@ namespace System.Security.Cryptography.X509Certificates.Tests.CertificateCreatio [SkipOnPlatform(TestPlatforms.Browser, "Browser doesn't support asymmetric cryptography")] public static class RSAPssX509SignatureGeneratorTests { + private static bool AreCustomPssSaltLengthsSupported => PlatformDetection.IsWindows || PlatformDetection.IsLinux; + [Fact] public static void RsaPssSignatureGeneratorCtor_Exceptions() { @@ -57,7 +59,7 @@ public static void PublicKeyEncoding() } } - [Theory] + [ConditionalTheory(nameof(AreCustomPssSaltLengthsSupported))] [InlineData(1)] [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] [InlineData(RSASignaturePadding.PssSaltLengthMax)] diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/X509Sha1SignatureGenerators.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/X509Sha1SignatureGenerators.cs index 71904695a6ce5e..ff0dc43366219b 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/X509Sha1SignatureGenerators.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/X509Sha1SignatureGenerators.cs @@ -1,7 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Security.Cryptography.Asn1; using Test.Cryptography; +#if NET10_0_OR_GREATER +using System.Formats.Asn1; +#endif namespace System.Security.Cryptography.X509Certificates.Tests.CertificateCreation { @@ -53,10 +57,12 @@ public override byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm) => internal sealed class RSASha1PssSignatureGenerator : X509SignatureGenerator { + private readonly RSASignaturePadding _signaturePadding; private readonly X509SignatureGenerator _realRsaGenerator; internal RSASha1PssSignatureGenerator(RSA rsa, RSASignaturePadding signaturePadding) { + _signaturePadding = signaturePadding; _realRsaGenerator = CreateForRSA(rsa, signaturePadding); } @@ -65,8 +71,22 @@ internal RSASha1PssSignatureGenerator(RSA rsa, RSASignaturePadding signaturePadd public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlgorithm) { if (hashAlgorithm == HashAlgorithmName.SHA1) - return "300D06092A864886F70D01010A3000".HexToByteArray(); - + { + if (_signaturePadding.PssSaltLength == RSASignaturePadding.PssSaltLengthIsHashLength) + { + // sha1WithRSAEncryption with RSASSA-PSS parameters + return "300D06092A864886F70D01010A3000".HexToByteArray(); + } + else if (_signaturePadding.PssSaltLength == 1) + { + return "303506092a864886f70d01010a3028a009300706052b0e03021aa116301406092a864886f70d010108300706052b0e03021aa203020101".HexToByteArray(); + } + else if (_signaturePadding.PssSaltLength == RSASignaturePadding.PssSaltLengthMax) + { + // Salt length is 234 + return "303606092a864886f70d01010a3029a009300706052b0e03021aa116301406092a864886f70d010108300706052b0e03021aa204020200ea".HexToByteArray(); + } + } throw new InvalidOperationException(); } From e374a1959bb3429841f658caf76fe8974dcc3afd Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Wed, 10 Sep 2025 08:20:01 +0200 Subject: [PATCH 31/32] Fixed assertion --- .../Common/src/System/Security/Cryptography/RSAOpenSsl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index 06f9ab5cef22df..0bbce81ce5953e 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -871,7 +871,7 @@ private static void ValidatePadding(RSASignaturePadding padding) else if (padding.Mode == RSASignaturePaddingMode.Pss) { // PSS salt length is validated in the RsaSignaturePaddingMode constructor. - Debug.Assert(padding.PssSaltLength < RSASignaturePadding.PssSaltLengthMax); + Debug.Assert(padding.PssSaltLength >= RSASignaturePadding.PssSaltLengthMax); } else { From f5459a1cd11052fa8d0d99a0414b1cca5e7dd4e2 Mon Sep 17 00:00:00 2001 From: "Krause, Henning" Date: Thu, 11 Sep 2025 07:41:15 +0200 Subject: [PATCH 32/32] Fixed tests --- .../AlgorithmImplementations/RSA/SignVerify.cs | 9 ++++----- .../Security/Cryptography/PlatformSupport.cs | 6 ++++++ .../SignedCms/SignedCmsWholeDocumentTests.cs | 18 +++++++++++------- .../CertificateRequestChainTests.cs | 4 ++-- .../CertificateRequestLoadTests.cs | 6 ++---- .../CertificateRequestUsageTests.cs | 4 +--- .../CertificateCreation/CrlBuilderTests.cs | 4 +--- .../RSAPssX509SignatureGeneratorTests.cs | 4 +--- 8 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs index cfab54977168a3..96aa233a692d82 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs @@ -43,8 +43,7 @@ public void NullArray_Throws() public abstract class SignVerify { public static bool SupportsPss => RSAFactory.SupportsPss; - public static bool AreCustomPssSaltLengthsSupported => PlatformDetection.IsWindows || PlatformDetection.IsLinux; - + public static bool AreCustomSaltLengthsSupportedWithPss => SupportsPss && PlatformSupport.AreCustomSaltLengthsSupportedWithPss; protected abstract byte[] SignData(RSA rsa, byte[] data, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding); protected abstract byte[] SignHash(RSA rsa, byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding); protected abstract bool VerifyData(RSA rsa, byte[] data, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding); @@ -583,7 +582,7 @@ public void VerifySignature_SHA3_512_RSA2048() VerifySignature(signature, TestData.HelloBytes, HashAlgorithmName.SHA3_512.Name, TestData.RSA2048Params); } - [ConditionalTheory(nameof(AreCustomPssSaltLengthsSupported))] + [ConditionalTheory(nameof(AreCustomSaltLengthsSupportedWithPss))] [InlineData(true)] [InlineData(false)] public void PssSignature_Sha_256_RSA2048_PSS_SaltLength_24(bool validateWithCorrectSaltLength) @@ -625,7 +624,7 @@ public void PssSignature_Sha_256_RSA2048_PSS_SaltLength_24(bool validateWithCorr } } - [ConditionalTheory(nameof(AreCustomPssSaltLengthsSupported))] + [ConditionalTheory(nameof(AreCustomSaltLengthsSupportedWithPss))] [InlineData(true)] [InlineData(false)] public void PssSignature_Sha_256_RSA2048_PSS_SaltLength_Max(bool validateWithCorrectSaltLength) @@ -1674,7 +1673,7 @@ public static IEnumerable PssRoundTripParameters { get { - int?[] saltLengths = AreCustomPssSaltLengthsSupported + int?[] saltLengths = AreCustomSaltLengthsSupportedWithPss ? [null, RSASignaturePadding.PssSaltLengthMax, RSASignaturePadding.PssSaltLengthIsHashLength, 0, 1, 4] : [null]; foreach (var saltLength in saltLengths) diff --git a/src/libraries/Common/tests/System/Security/Cryptography/PlatformSupport.cs b/src/libraries/Common/tests/System/Security/Cryptography/PlatformSupport.cs index a7e6dee0820d13..d2335720acfdd5 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/PlatformSupport.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/PlatformSupport.cs @@ -164,6 +164,12 @@ private static bool CheckIfRsaPssSupported() /// internal static bool IsRsaPssSupported => s_isRsaPssSupported ??= CheckIfRsaPssSupported(); +#if NET10_0_OR_GREATER + internal static bool AreCustomSaltLengthsSupportedWithPss => IsRsaPssSupported && !PlatformDetection.IsApplePlatform; +#else + internal static bool AreCustomSaltLengthsSupportedWithPss => false; +#endif + internal static bool IsPqcMLKemX509Supported { get diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs index bea89598dbf2a9..6e72b6dccc68bc 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsWholeDocumentTests.cs @@ -91,6 +91,7 @@ public static void ReadRsaPssDocument(bool fromSpan) "07849DC26FCBB2F3BD5F57BDF214BAE374575F1BD4E6816482324799417CB379", messageDigestAttr.MessageDigest.ByteArrayToHex()); + Assert.IsType(signedAttrs[3].Values[0]); #if !NET Assert.NotSame(signedAttrs[3].Oid, signedAttrs[3].Values[0].Oid); @@ -137,13 +138,16 @@ public static void ReadRsaPssDocument(bool fromSpan) // Assert.NotThrows cms.CheckHash(); - // PSS signature with parameters are only supported on .NET 10 or later -#if NET10_0_OR_GREATER - // Since at least one signer fails, the document signature will fail - cms.CheckSignature(true); -#else - Assert.Throws(() => cms.CheckSignature(true)); -#endif + // PSS signature with parameters are only supported on .NET 10 or later, but not on all platforms. + if (PlatformSupport.AreCustomSaltLengthsSupportedWithPss) + { + cms.CheckSignature(true); + } + else + { + // Since at least one signer fails, the document signature will fail + Assert.Throws(() => cms.CheckSignature(true)); + } } [ConditionalFact(typeof(SignatureSupport), nameof(SignatureSupport.SupportsRsaSha1Signatures))] diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs index f28206cf2dbf2d..e04b7a99907505 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs @@ -13,7 +13,7 @@ public static class CertificateRequestChainTests // Android supports PSS at the algorithms layer, but does not support it // being used in cert chains. public static bool PlatformSupportsPss { get; } = !PlatformDetection.IsAndroid && PlatformSupport.IsRsaPssSupported; - private static bool AreCustomPssSaltLengthsSupported => PlatformDetection.IsWindows || PlatformDetection.IsLinux; + public static bool AreCustomSaltLengthsSupportedWithPss { get; } = !PlatformDetection.IsAndroid && PlatformSupport.AreCustomSaltLengthsSupportedWithPss; [Fact] public static void CreateChain_ECC() @@ -490,7 +490,7 @@ private static void CreateAndTestChain( } } - [ConditionalTheory(nameof(AreCustomPssSaltLengthsSupported))] + [ConditionalTheory(nameof(PlatformSupport.AreCustomSaltLengthsSupportedWithPss))] [InlineData(1)] [InlineData(RSASignaturePadding.PssSaltLengthMax)] [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs index 2ba874633b111c..fb81803cc6669e 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs @@ -11,8 +11,6 @@ namespace System.Security.Cryptography.X509Certificates.Tests.CertificateCreatio [SkipOnPlatform(TestPlatforms.Browser, "Browser doesn't support X.509 certificates")] public static class CertificateRequestLoadTests { - private static bool AreCustomPssSaltLengthsSupported => PlatformDetection.IsWindows || PlatformDetection.IsLinux; - [Theory] [InlineData(CertificateRequestLoadOptions.Default, false)] [InlineData(CertificateRequestLoadOptions.UnsafeLoadCertificateExtensions, false)] @@ -376,7 +374,7 @@ public static void VerifySignature_RSA_PKCS1(string hashAlgorithm) } } - [ConditionalTheory(nameof(AreCustomPssSaltLengthsSupported))] + [ConditionalTheory(typeof(PlatformSupport), nameof(PlatformSupport.AreCustomSaltLengthsSupportedWithPss))] [InlineData("SHA256", 1)] [InlineData("SHA384", 1)] [InlineData("SHA512", 1)] @@ -852,7 +850,7 @@ public static void LoadCreate_MatchesCreate_RSAPkcs1() } } - [ConditionalTheory(nameof(AreCustomPssSaltLengthsSupported))] + [ConditionalTheory(typeof(PlatformSupport), nameof(PlatformSupport.AreCustomSaltLengthsSupportedWithPss))] [InlineData(0)] [InlineData(4)] [InlineData(RSASignaturePadding.PssSaltLengthMax)] diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs index 602c492df1dade..1ad6b58e60c2c5 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestUsageTests.cs @@ -12,8 +12,6 @@ namespace System.Security.Cryptography.X509Certificates.Tests.CertificateCreatio [SkipOnPlatform(TestPlatforms.Browser, "Browser doesn't support X.509 certificates")] public static class CertificateRequestUsageTests { - private static bool AreCustomPssSaltLengthsSupported => PlatformDetection.IsWindows || PlatformDetection.IsLinux; - [Fact] public static void ReproduceBigExponentCsr() { @@ -309,7 +307,7 @@ public static void SelfSign_ECC_DiminishedPoint_UseCertKeys() } } - [ConditionalTheory(nameof(AreCustomPssSaltLengthsSupported))] + [ConditionalTheory(typeof(PlatformSupport), nameof(PlatformSupport.AreCustomSaltLengthsSupportedWithPss))] [InlineData(1)] [InlineData(RSASignaturePadding.PssSaltLengthMax)] [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs index debc48de015953..25c71b049a945f 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs @@ -14,8 +14,6 @@ namespace System.Security.Cryptography.X509Certificates.Tests.CertificateCreatio [SkipOnPlatform(TestPlatforms.Browser, "Browser doesn't support asymmetric cryptography")] public static class CrlBuilderTests { - private static bool AreCustomPssSaltLengthsSupported => PlatformDetection.IsWindows || PlatformDetection.IsLinux; - private const string CertParam = "issuerCertificate"; public enum CertKind @@ -40,7 +38,7 @@ public static IEnumerable SupportedCertKinds() yield return new object[] { CertKind.RsaPkcs1 }; yield return new object[] { CertKind.RsaPss }; - if (AreCustomPssSaltLengthsSupported) + if (PlatformSupport.AreCustomSaltLengthsSupportedWithPss) { yield return new object[] { CertKind.RsaPssWithCustomSaltLength }; yield return new object[] { CertKind.RsaPssWithMaxSaltLength }; diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs index 7e337dcd463fcb..c637b6675b5f2a 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/RSAPssX509SignatureGeneratorTests.cs @@ -10,8 +10,6 @@ namespace System.Security.Cryptography.X509Certificates.Tests.CertificateCreatio [SkipOnPlatform(TestPlatforms.Browser, "Browser doesn't support asymmetric cryptography")] public static class RSAPssX509SignatureGeneratorTests { - private static bool AreCustomPssSaltLengthsSupported => PlatformDetection.IsWindows || PlatformDetection.IsLinux; - [Fact] public static void RsaPssSignatureGeneratorCtor_Exceptions() { @@ -59,7 +57,7 @@ public static void PublicKeyEncoding() } } - [ConditionalTheory(nameof(AreCustomPssSaltLengthsSupported))] + [ConditionalTheory(typeof(PlatformSupport), nameof(PlatformSupport.AreCustomSaltLengthsSupportedWithPss))] [InlineData(1)] [InlineData(RSASignaturePadding.PssSaltLengthIsHashLength)] [InlineData(RSASignaturePadding.PssSaltLengthMax)]