Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
e0b1dae
Added support for a custom salt length when using PSS signature valid…
henning-krause May 16, 2025
05ed28b
Review
henning-krause May 16, 2025
21135d5
Merge branch 'dotnet:main' into 104080-custom-rsapss-salt-length
henning-krause Jun 5, 2025
d705126
Review all usages for RSASignaturePadding to check for missing PSS sa…
henning-krause Jun 6, 2025
3c6288c
Added error handling for apple devices (custom PSS salt length not su…
henning-krause Jun 6, 2025
4d3bd37
Added sign and verify tests for custom salt lengths
henning-krause Jun 10, 2025
d19d017
Added test for max salt length verification
henning-krause Jun 10, 2025
20be62b
Added a test for the RSAPssX509SignatureGenerator
henning-krause Jun 11, 2025
c0d0ce0
Added test for CertificateRequest.LoadSigningRequest
henning-krause Jun 11, 2025
81432d5
More tests for the CertificateRequest
henning-krause Jun 11, 2025
a016382
Added custom salt support for SignedCms
henning-krause Jun 12, 2025
9cde2fa
Add error handling for PSS salt length in CoseSigner
henning-krause Jul 8, 2025
a6dd48a
Updated RSA
henning-krause Aug 27, 2025
71325e3
Merged from main
henning-krause Aug 27, 2025
e2407be
Updated CoseSigner
henning-krause Aug 29, 2025
7b65140
Code fixes
henning-krause Aug 29, 2025
623199c
Code fixes
henning-krause Aug 29, 2025
b14906e
Code fixes
henning-krause Aug 29, 2025
9dcb4ea
Code fixes
henning-krause Aug 29, 2025
fee0f09
Code fixes
henning-krause Aug 29, 2025
a386bac
Code fixes
henning-krause Aug 29, 2025
430a846
Updated a few test cases
henning-krause Sep 1, 2025
e0eb704
CRL Builder tests extended
henning-krause Sep 1, 2025
dd64636
Update src/libraries/System.Security.Cryptography/tests/X509Certifica…
henning-krause Sep 2, 2025
d97581c
Update src/libraries/System.Security.Cryptography/ref/System.Security…
henning-krause Sep 2, 2025
e99f10d
Update src/libraries/Common/src/System/Security/Cryptography/RsaPaddi…
henning-krause Sep 2, 2025
f066e97
Update src/libraries/System.Security.Cryptography.Cng/tests/RSACngPkc…
henning-krause Sep 2, 2025
de11a87
Fixed unit tests
henning-krause Sep 3, 2025
79bb2de
Merge branch '104080-custom-rsapss-salt-length' of https://github.com…
henning-krause Sep 3, 2025
6e64ad1
Merge branch 'main' into 104080-custom-rsapss-salt-length
henning-krause Sep 3, 2025
aeab113
Fixed tests
henning-krause Sep 3, 2025
d70ef9b
Review changes
henning-krause Sep 5, 2025
76065fe
Merge branch 'main' into 104080-custom-rsapss-salt-length
henning-krause Sep 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -133,6 +134,7 @@ private static partial int CryptoNative_RsaSignHash(
internal static int RsaSignHash(
SafeEvpPKeyHandle pkey,
RSASignaturePaddingMode paddingMode,
int pssSaltLength,
HashAlgorithmName digestAlgorithm,
ReadOnlySpan<byte> hash,
Span<byte> destination)
Expand All @@ -145,6 +147,7 @@ internal static int RsaSignHash(
pkey,
pkey.ExtraHandle,
paddingMode,
pssSaltLength,
digestAlgorithmPtr,
ref MemoryMarshal.GetReference(hash),
hash.Length,
Expand All @@ -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,
Expand All @@ -174,6 +178,7 @@ private static partial int CryptoNative_RsaVerifyHash(
internal static bool RsaVerifyHash(
SafeEvpPKeyHandle pkey,
RSASignaturePaddingMode paddingMode,
int pssSaltLength,
HashAlgorithmName digestAlgorithm,
ReadOnlySpan<byte> hash,
ReadOnlySpan<byte> signature)
Expand All @@ -186,6 +191,7 @@ internal static bool RsaVerifyHash(
pkey,
pkey.ExtraHandle,
paddingMode,
pssSaltLength,
digestAlgorithmPtr,
ref MemoryMarshal.GetReference(hash),
hash.Length,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ internal static unsafe NTSTATUS BCryptSignHashPss(
ReadOnlySpan<byte> hash,
Span<byte> destination,
string hashAlgorithmName,
int saltLength,
out int bytesWritten)
{
fixed (char* pHashAlgorithmName = hashAlgorithmName)
Expand All @@ -62,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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ internal static unsafe bool BCryptVerifySignaturePss(
SafeBCryptKeyHandle key,
ReadOnlySpan<byte> hash,
ReadOnlySpan<byte> signature,
string hashAlgorithmName)
string hashAlgorithmName,
int saltLength)
{

NTSTATUS status;
Expand All @@ -72,7 +73,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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ internal RSASignaturePadding GetSignaturePadding(
HashAlgorithm.Algorithm));
}

#if NET10_0_OR_GREATER
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is tricky. Right now, .NET 10 is "done". Technically this work will go in for .NET 11. However, the runtime and SDK are not "bumped" to .NET 11 yet so #if NET11_0_OR_GREATER doesn't exist. We might need to wait for this work until #118583 is complete.

return RSASignaturePadding.CreatePss(SaltLength);
#else
int saltSize = digestValueLength.GetValueOrDefault();

if (!digestValueLength.HasValue)
Expand All @@ -59,6 +62,7 @@ internal RSASignaturePadding GetSignaturePadding(

// When RSASignaturePadding supports custom salt sizes this return will look different.
return RSASignaturePadding.Pss;
#endif
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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, RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm));
}
else
{
Expand Down Expand Up @@ -726,7 +726,7 @@ public override bool VerifyHash(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> 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();
}
Expand Down Expand Up @@ -772,9 +772,10 @@ public override bool VerifyHash(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> 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);
int saltLength = RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm);
return RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, KeySize, saltLength);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,14 @@ public override bool TrySignHash(ReadOnlySpan<byte> hash, Span<byte> 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_CustomPssSaltLengthNotSupported);
}

ThrowIfDisposed();

Interop.AppleCrypto.PAL_SignatureAlgorithm signatureAlgorithm = padding.Mode switch
Expand Down Expand Up @@ -454,7 +462,7 @@ public override bool TrySignHash(ReadOnlySpan<byte> hash, Span<byte> destination

byte[] rented = CryptoPool.Rent(rsaSize);
Span<byte> buf = new Span<byte>(rented, 0, rsaSize);
RsaPaddingProcessor.EncodePss(hashAlgorithm, hash, buf, keySize);
RsaPaddingProcessor.EncodePss(hashAlgorithm, hash, buf, keySize, hash.Length);

try
{
Expand Down Expand Up @@ -537,9 +545,9 @@ public override bool VerifyHash(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> sign
Debug.Fail($"TryRsaVerificationPrimitive with a pre-allocated buffer");
throw new CryptographicException();
}

Debug.Assert(bytesWritten == rsaSize);
return RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, keySize);
int saltLength = RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm);
return RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, keySize, saltLength);
}
finally
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = hash.Length };
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:
Expand Down Expand Up @@ -104,7 +105,11 @@ public override unsafe bool TrySignHash(ReadOnlySpan<byte> hash, Span<byte> 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 = RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm)
};
return keyHandle.TrySignHash(hash, destination, AsymmetricPaddingMode.NCRYPT_PAD_PSS_FLAG, &pssPaddingInfo, out bytesWritten);

default:
Expand Down Expand Up @@ -152,7 +157,11 @@ public override unsafe bool VerifyHash(ReadOnlySpan<byte> hash, ReadOnlySpan<byt
return keyHandle.VerifyHash(hash, signature, AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, &pkcs1PaddingInfo);

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 = RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm)
};
return keyHandle.VerifyHash(hash, signature, AsymmetricPaddingMode.NCRYPT_PAD_PSS_FLAG, &pssPaddingInfo);

default:
Expand Down
27 changes: 17 additions & 10 deletions src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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, 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)
{
Expand Down Expand Up @@ -766,7 +769,10 @@ public override bool TrySignHash(
return false;
}

bytesWritten = Interop.Crypto.RsaSignHash(key, padding.Mode, 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;
}
Expand All @@ -791,9 +797,13 @@ public override bool VerifyHash(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> sign

SafeEvpPKeyHandle key = GetKey();

int pssSaltLength = padding.Mode == RSASignaturePaddingMode.Pss
? RsaPaddingProcessor.CalculatePssSaltLength(padding.PssSaltLength, KeySize, hashAlgorithm)
: 0;
return Interop.Crypto.RsaVerifyHash(
key,
padding.Mode,
pssSaltLength,
hashAlgorithm,
hash,
signature);
Expand Down Expand Up @@ -853,20 +863,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.PssSaltLengthMax)
{
throw PaddingModeNotSupported();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exception says the padding "mode" is invalid. Which isn't the case here. The "mode" is PSS, which is valid. So we probably want a new message for the salt size being gibberish (and yet a different one for "that doesn't work here")

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bartonjs Given that I followed the suggestion by @vcsjones and implemented validation logic on the RSASignaturePadding.CreatePss method, I think we can't run into this any more. Would it be sufficient to put in a Debug.Assert?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, an assert here is fine given the throw there.

}
}
else
{
Expand Down
Loading
Loading