From 97a993f19b8b803d1d2e3061818284f7acfb69b0 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Wed, 19 Feb 2025 18:25:45 +0100 Subject: [PATCH 01/24] Dirty WIP on Windows --- .../Interop/Windows/SspiCli/Interop.SSPI.cs | 8 ++++---- .../src/System.Net.Security.csproj | 2 ++ .../Net/Security/SslStreamPal.Windows.cs | 20 ++++++++++++++++--- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs index cbff2b2798efed..a7652dd8749cc8 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs @@ -248,7 +248,7 @@ public enum Flags SCH_CRED_IGNORE_REVOCATION_OFFLINE = 0x1000, SCH_CRED_CACHE_ONLY_URL_RETRIEVAL_ON_CREATE = 0x2000, SCH_SEND_ROOT_CERT = 0x40000, - SCH_SEND_AUX_RECORD = 0x00200000, + SCH_SEND_AUX_RECORD = 0x00200000, SCH_USE_STRONG_CRYPTO = 0x00400000, SCH_USE_PRESHAREDKEY_ONLY = 0x800000, SCH_ALLOW_NULL_ENCRYPTION = 0x02000000, @@ -259,7 +259,7 @@ public enum Flags internal unsafe struct TLS_PARAMETERS { public int cAlpnIds; // Valid for server applications only. Must be zero otherwise. Number of ALPN IDs in rgstrAlpnIds; set to 0 if applies to all. - public IntPtr rgstrAlpnIds; // Valid for server applications only. Must be NULL otherwise. Array of ALPN IDs that the following settings apply to; set to NULL if applies to all. + public UNICODE_STRING* rgstrAlpnIds; // Valid for server applications only. Must be NULL otherwise. Array of ALPN IDs that the following settings apply to; set to NULL if applies to all. public uint grbitDisabledProtocols; // List protocols you DO NOT want negotiated. public int cDisabledCrypto; // Number of CRYPTO_SETTINGS structures; set to 0 if there are none. public CRYPTO_SETTINGS* pDisabledCrypto; // Array of CRYPTO_SETTINGS structures; set to NULL if there are none; @@ -278,7 +278,7 @@ public enum Flags internal unsafe struct CRYPTO_SETTINGS { public TlsAlgorithmUsage eAlgorithmUsage; // How this algorithm is being used. - public UNICODE_STRING* strCngAlgId; // CNG algorithm identifier. + public UNICODE_STRING strCngAlgId; // CNG algorithm identifier. public int cChainingModes; // Set to 0 if CNG algorithm does not have a chaining mode. public UNICODE_STRING* rgstrChainingModes; // Set to NULL if CNG algorithm does not have a chaining mode. public int dwMinBitLength; // Minimum bit length for the specified CNG algorithm. Set to 0 if not defined or CNG algorithm implies bit length. @@ -374,7 +374,7 @@ internal static unsafe partial int VerifySignature( ref CredHandle contextHandle, in SecBufferDesc input, uint sequenceNumber, - uint *qualityOfProtection); + uint* qualityOfProtection); [LibraryImport(Interop.Libraries.SspiCli, SetLastError = true)] internal static partial int QuerySecurityContextToken( diff --git a/src/libraries/System.Net.Security/src/System.Net.Security.csproj b/src/libraries/System.Net.Security/src/System.Net.Security.csproj index e7c1c325b7a75e..134419623e0c81 100644 --- a/src/libraries/System.Net.Security/src/System.Net.Security.csproj +++ b/src/libraries/System.Net.Security/src/System.Net.Security.csproj @@ -186,6 +186,8 @@ Link="Common\Interop\Windows\Interop.Libraries.cs" /> + input, int headerSize, int trailerSize) From 07983a002a3eb790087f643169c8ab2f60fb66f2 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Tue, 11 Mar 2025 14:09:09 +0100 Subject: [PATCH 02/24] Linux half of the experiment --- .../System.Security.Cryptography.Native/Interop.OpenSsl.cs | 7 +++++++ .../System.Security.Cryptography.Native/Interop.Ssl.cs | 3 +++ .../Security/SslClientAuthenticationOptionsExtensions.cs | 5 +++-- .../System.Net.Security/ref/System.Net.Security.cs | 2 ++ .../src/System/Net/Security/SslAuthenticationOptions.cs | 3 +++ .../System/Net/Security/SslClientAuthenticationOptions.cs | 2 ++ .../System/Net/Security/SslServerAuthenticationOptions.cs | 2 ++ .../libs/System.Security.Cryptography.Native/entrypoints.c | 1 + .../System.Security.Cryptography.Native/osslcompat_111.h | 1 + .../libs/System.Security.Cryptography.Native/pal_ssl.c | 6 ++++++ .../libs/System.Security.Cryptography.Native/pal_ssl.h | 5 +++++ 11 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index d89ce63d496fb3..025979309efecc 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -414,6 +414,13 @@ internal static SafeSslHandle AllocateSslHandle(SslAuthenticationOptions sslAuth sslHandle.SslContextHandle = sslCtxHandle; } + if (Environment.GetEnvironmentVariable("DOTNET_SIGALGS") is string s) + { + byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s); + int result = Interop.Ssl.SslSetSigalgs(sslHandle, utf8Bytes); + Debug.Assert(result == 1); + } + if (sslAuthenticationOptions.ApplicationProtocols != null && sslAuthenticationOptions.ApplicationProtocols.Count != 0) { if (sslAuthenticationOptions.IsServer) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index 65c0d37e3d5a30..647e4bbc20a237 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -186,6 +186,9 @@ internal static SafeSharedX509StackHandle SslGetPeerCertChain(SafeSslHandle ssl) [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSetPostHandshakeAuth")] internal static partial void SslSetPostHandshakeAuth(SafeSslHandle ssl, int value); + [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSetSigalgs")] + internal static partial int SslSetSigalgs(SafeSslHandle ssl, ReadOnlySpan str); + [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_Tls13Supported")] private static partial int Tls13SupportedImpl(); diff --git a/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs b/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs index d1ad29435f9be0..1085887409b59e 100644 --- a/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs +++ b/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs @@ -29,14 +29,15 @@ public static SslClientAuthenticationOptions ShallowClone(this SslClientAuthenti EncryptionPolicy = options.EncryptionPolicy, LocalCertificateSelectionCallback = options.LocalCertificateSelectionCallback, RemoteCertificateValidationCallback = options.RemoteCertificateValidationCallback, - TargetHost = options.TargetHost + TargetHost = options.TargetHost, + AllowRsaPssPad = options.AllowRsaPssPad }; #if DEBUG // Try to detect if a property gets added that we're not copying correctly. // The property count is guard for new properties that also needs to be added above. PropertyInfo[] properties = typeof(SslClientAuthenticationOptions).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)!; - Debug.Assert(properties.Length == 13); + Debug.Assert(properties.Length == 14); foreach (PropertyInfo pi in properties) { object? origValue = pi.GetValue(options); diff --git a/src/libraries/System.Net.Security/ref/System.Net.Security.cs b/src/libraries/System.Net.Security/ref/System.Net.Security.cs index ca8aa52a2dbf62..c74666c0ffba56 100644 --- a/src/libraries/System.Net.Security/ref/System.Net.Security.cs +++ b/src/libraries/System.Net.Security/ref/System.Net.Security.cs @@ -213,6 +213,7 @@ public SslClientAuthenticationOptions() { } public System.Net.Security.LocalCertificateSelectionCallback? LocalCertificateSelectionCallback { get { throw null; } set { } } public System.Net.Security.RemoteCertificateValidationCallback? RemoteCertificateValidationCallback { get { throw null; } set { } } public string? TargetHost { get { throw null; } set { } } + public bool AllowRsaPssPad { get { throw null; } set { } } } public readonly partial struct SslClientHelloInfo { @@ -238,6 +239,7 @@ public SslServerAuthenticationOptions() { } public System.Security.Cryptography.X509Certificates.X509Certificate? ServerCertificate { get { throw null; } set { } } public System.Net.Security.SslStreamCertificateContext? ServerCertificateContext { get { throw null; } set { } } public System.Net.Security.ServerCertificateSelectionCallback? ServerCertificateSelectionCallback { get { throw null; } set { } } + public bool AllowRsaPssPad { get { throw null; } set { } } } public partial class SslStream : System.Net.Security.AuthenticatedStream { diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs index 5f7d0b311f3c98..8011724a469b78 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs @@ -51,6 +51,7 @@ internal void UpdateOptions(SslClientAuthenticationOptions sslClientAuthenticati RemoteCertRequired = true; CertificateContext = sslClientAuthenticationOptions.ClientCertificateContext; TargetHost = sslClientAuthenticationOptions.TargetHost ?? string.Empty; + AllowRsaPssPad = sslClientAuthenticationOptions.AllowRsaPssPad; // Client specific options. CertificateRevocationCheckMode = sslClientAuthenticationOptions.CertificateRevocationCheckMode; @@ -110,6 +111,7 @@ internal void UpdateOptions(SslServerAuthenticationOptions sslServerAuthenticati RemoteCertRequired = sslServerAuthenticationOptions.ClientCertificateRequired; CipherSuitesPolicy = sslServerAuthenticationOptions.CipherSuitesPolicy; CertificateRevocationCheckMode = sslServerAuthenticationOptions.CertificateRevocationCheckMode; + AllowRsaPssPad = sslServerAuthenticationOptions.AllowRsaPssPad; if (sslServerAuthenticationOptions.ServerCertificateContext != null) { CertificateContext = sslServerAuthenticationOptions.ServerCertificateContext; @@ -185,6 +187,7 @@ private static SslProtocols FilterOutIncompatibleSslProtocols(SslProtocols proto internal ServerOptionsSelectionCallback? ServerOptionDelegate { get; set; } internal X509ChainPolicy? CertificateChainPolicy { get; set; } internal bool AllowTlsResume { get; set; } + internal bool AllowRsaPssPad { get; set; } #if TARGET_ANDROID internal SslStream.JavaProxy? SslStreamProxy { get; set; } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs index 5e7ccf90c0e714..cc2fde3906decf 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs @@ -96,5 +96,7 @@ public SslProtocols EnabledSslProtocols /// are ignored. /// public X509ChainPolicy? CertificateChainPolicy { get; set; } + + public bool AllowRsaPssPad { get; set; } = true; } } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs index cc082eaa04f7e6..1ef16948230785 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs @@ -92,5 +92,7 @@ public EncryptionPolicy EncryptionPolicy /// are ignored. /// public X509ChainPolicy? CertificateChainPolicy { get; set; } + + public bool AllowRsaPssPad { get; set; } = true; } } diff --git a/src/native/libs/System.Security.Cryptography.Native/entrypoints.c b/src/native/libs/System.Security.Cryptography.Native/entrypoints.c index 09fd43b529bd3e..b4bce37e9864d8 100644 --- a/src/native/libs/System.Security.Cryptography.Native/entrypoints.c +++ b/src/native/libs/System.Security.Cryptography.Native/entrypoints.c @@ -397,6 +397,7 @@ static const Entry s_cryptoNative[] = DllImportEntry(CryptoNative_SslSetSession) DllImportEntry(CryptoNative_SslSetTlsExtHostName) DllImportEntry(CryptoNative_SslSetVerifyPeer) + DllImportEntry(CryptoNative_SslSetSigalgs) DllImportEntry(CryptoNative_SslShutdown) DllImportEntry(CryptoNative_SslStapleOcsp) DllImportEntry(CryptoNative_SslUseCertificate) diff --git a/src/native/libs/System.Security.Cryptography.Native/osslcompat_111.h b/src/native/libs/System.Security.Cryptography.Native/osslcompat_111.h index a56becf4f85578..56d00cdbd9e360 100644 --- a/src/native/libs/System.Security.Cryptography.Native/osslcompat_111.h +++ b/src/native/libs/System.Security.Cryptography.Native/osslcompat_111.h @@ -71,6 +71,7 @@ void SSL_CTX_set_security_level(SSL_CTX* ctx, int32_t level); int32_t SSL_is_init_finished(SSL* ssl); unsigned long SSL_set_options(SSL* ctx, unsigned long options); void SSL_set_post_handshake_auth(SSL *s, int val); +int32_t SSL_set_post_handshake_auth(SSL *s, int val); int SSL_session_reused(SSL* ssl); int SSL_verify_client_post_handshake(SSL *s); const SSL_METHOD* TLS_method(void); diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c index 93d352702748f6..fe8a63b115497b 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c +++ b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c @@ -1117,6 +1117,12 @@ int32_t CryptoNative_SslSetTlsExtHostName(SSL* ssl, uint8_t* name) return (int32_t)SSL_set_tlsext_host_name(ssl, name); } +int32_t CryptoNative_SslSetSigalgs(SSL* ssl, uint8_t* str) +{ + ERR_clear_error(); + return (int32_t) SSL_ctrl(ssl, SSL_CTRL_SET_SIGALGS_LIST, 0, (void*)str); +} + int32_t CryptoNative_SslGetCurrentCipherId(SSL* ssl, int32_t* cipherId) { // No error queue impact. diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h index 8566c7b8ff9b35..cc9254ab9d17ce 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h +++ b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h @@ -522,6 +522,11 @@ Shims the SSL_set_tlsext_host_name method. */ PALEXPORT int32_t CryptoNative_SslSetTlsExtHostName(SSL* ssl, uint8_t* name); +/* +Shims the SSL_set1_sigalgs_list method. +*/ +PALEXPORT int32_t CryptoNative_SslSetSigalgs(SSL* ssl, uint8_t* str); + /* Shims the SSL_get_current_cipher and SSL_CIPHER_get_id. */ From 17c2da136021cd30a0e1985176b00f7d4e8c4692 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Wed, 16 Apr 2025 13:32:27 +0200 Subject: [PATCH 03/24] OpenSSL configure signature algorithm WIP --- .../Interop.OpenSsl.cs | 119 +++++++++++++++++- .../Interop.Ssl.cs | 13 +- ...slClientAuthenticationOptionsExtensions.cs | 5 +- .../ref/System.Net.Security.cs | 25 ++-- .../Net/Security/SslAuthenticationOptions.cs | 3 + .../SslClientAuthenticationOptions.cs | 1 + .../SslServerAuthenticationOptions.cs | 1 + .../entrypoints.c | 1 + .../opensslshim.h | 2 + .../pal_ssl.c | 83 ++++++++++++ .../pal_ssl.h | 5 + 11 files changed, 241 insertions(+), 17 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index 025979309efecc..15d28c5b5edbc7 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Buffers; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -15,6 +16,7 @@ using System.Security.Authentication.ExtendedProtection; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; +using System.Text; using Microsoft.Win32.SafeHandles; internal static partial class Interop @@ -28,6 +30,7 @@ internal static partial class OpenSsl private const int DefaultTlsCacheSizeClient = 500; // since we keep only one TLS Session per hostname, 500 should be enough to cover most scenarios private const int DefaultTlsCacheSizeServer = -1; // use implementation default private const SslProtocols FakeAlpnSslProtocol = (SslProtocols)1; // used to distinguish server sessions with ALPN + private static readonly Lazy s_defaultSigAlgs = new(GetDefaultSignatureAlgorithms); private sealed class SafeSslContextCache : SafeHandleCache { } @@ -414,11 +417,9 @@ internal static SafeSslHandle AllocateSslHandle(SslAuthenticationOptions sslAuth sslHandle.SslContextHandle = sslCtxHandle; } - if (Environment.GetEnvironmentVariable("DOTNET_SIGALGS") is string s) + if (!sslAuthenticationOptions.AllowRsaPssPad || !sslAuthenticationOptions.AllowRsaRsae) { - byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s); - int result = Interop.Ssl.SslSetSigalgs(sslHandle, utf8Bytes); - Debug.Assert(result == 1); + ConfigureSignatureAlgorithms(sslHandle, sslAuthenticationOptions.AllowRsaPssPad, sslAuthenticationOptions.AllowRsaRsae); } if (sslAuthenticationOptions.ApplicationProtocols != null && sslAuthenticationOptions.ApplicationProtocols.Count != 0) @@ -523,6 +524,116 @@ internal static SafeSslHandle AllocateSslHandle(SslAuthenticationOptions sslAuth return sslHandle; } + internal static string[] GetDefaultSignatureAlgorithms() + { + ushort[] rawAlgs = Interop.Ssl.GetDefaultSignatureAlgorithms(); + + static string ConvertAlg(ushort rawAlg) => rawAlg switch + { + 0x0201 => "rsa_pkcs1_sha1", + 0x0203 => "ecdsa_sha1", + 0x0401 => "rsa_pkcs1_sha256", + 0x0403 => "ecdsa_secp256r1_sha256", + 0x0501 => "rsa_pkcs1_sha384", + 0x0503 => "ecdsa_secp384r1_sha384", + 0x0601 => "rsa_pkcs1_sha512", + 0x0603 => "ecdsa_secp521r1_sha512", + 0x0804 => "rsa_pss_rsae_sha256", + 0x0805 => "rsa_pss_rsae_sha384", + 0x0806 => "rsa_pss_rsae_sha512", + 0x0807 => "ed25519", + 0x0808 => "ed448", + 0x0809 => "rsa_pss_pss_sha256", + 0x080a => "rsa_pss_pss_sha384", + 0x080b => "rsa_pss_pss_sha512", + 0x081a => "ecdsa_brainpoolP256r1_sha256", + 0x081b => "ecdsa_brainpoolP384r1_sha384", + 0x081c => "ecdsa_brainpoolP512r1_sha512", + _ => $"{Tls12SignatureName((byte)rawAlg)}+{Tls12HashName((byte)(rawAlg >> 8))}" + }; + + static string Tls12HashName(byte raw) => raw switch + { + 0x00 => "none", + 0x01 => "MD5", + 0x02 => "SHA1", + 0x03 => "SHA224", + 0x04 => "SHA256", + 0x05 => "SHA384", + 0x06 => "SHA512", + _ => $"unknown(0x{raw:x2})" + }; + + static string Tls12SignatureName(byte raw) => raw switch + { + 0x00 => "anonymous", + 0x01 => "RSA", + 0x02 => "DSA", + 0x03 => "ECDSA", + _ => $"unknown(0x{raw:x2})" + }; + + return Array.ConvertAll(rawAlgs, ConvertAlg); + } + + internal static unsafe void ConfigureSignatureAlgorithms(SafeSslHandle sslHandle, bool enablePss, bool enableRsae) + { + byte[] buffer = ArrayPool.Shared.Rent(512); + try + { + int index = 0; + + foreach (string alg in s_defaultSigAlgs.Value) + { + if (alg.StartsWith("rsa_pss_pss_") && !enablePss) + { + continue; + } + + if (alg.StartsWith("rsa_pss_rsae_") && !enableRsae) + { + continue; + } + + EnsureSize(ref buffer, index + alg.Length + 1); + + if (index > 0) + { + buffer[index++] = (byte)':'; + } + + index += Encoding.UTF8.GetBytes(alg, buffer.AsSpan(index)); + } + buffer[index] = 0; // null terminator + + int ret; + fixed (byte* pBuffer = buffer) + { + ret = Interop.Ssl.SslSetSigalgs(sslHandle, pBuffer); + } + + if (ret != 1) + { + throw new InvalidOperationException("Failed to set signature algorithms."); + } + } + finally + { + ArrayPool.Shared.Return(buffer); + } + + static void EnsureSize(ref byte[] buffer, int size) + { + if (buffer.Length < size) + { + byte[] oldBuffer = buffer; + Array.Resize(ref buffer, buffer.Length * 2); + + ArrayPool.Shared.Return(oldBuffer); + } + } + } + internal static SecurityStatusPal SslRenegotiate(SafeSslHandle sslContext, out byte[]? outputBuffer) { int ret = Interop.Ssl.SslRenegotiate(sslContext, out Ssl.SslErrorCode errorCode); diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index 647e4bbc20a237..cd5ff81e369ebd 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -83,6 +83,17 @@ internal static unsafe ReadOnlySpan SslGetAlpnSelected(SafeSslHandle ssl) [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslRead", SetLastError = true)] internal static partial int SslRead(SafeSslHandle ssl, ref byte buf, int num, out SslErrorCode error); + [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetDefaultSignatureAlgorithms")] + private static unsafe partial void GetDefaultSignatureAlgorithms(Span algorithms, ref int algorithmCount); + + internal static ushort[] GetDefaultSignatureAlgorithms() + { + Span algorithms = stackalloc ushort[256]; + int algorithmCount = algorithms.Length; + GetDefaultSignatureAlgorithms(algorithms, ref algorithmCount); + return algorithms.Slice(0, algorithmCount).ToArray(); + } + [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslRenegotiate")] internal static partial int SslRenegotiate(SafeSslHandle ssl, out SslErrorCode error); @@ -187,7 +198,7 @@ internal static SafeSharedX509StackHandle SslGetPeerCertChain(SafeSslHandle ssl) internal static partial void SslSetPostHandshakeAuth(SafeSslHandle ssl, int value); [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSetSigalgs")] - internal static partial int SslSetSigalgs(SafeSslHandle ssl, ReadOnlySpan str); + internal static unsafe partial int SslSetSigalgs(SafeSslHandle ssl, byte* str); [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_Tls13Supported")] private static partial int Tls13SupportedImpl(); diff --git a/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs b/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs index 1085887409b59e..5ec4cd17cc14cb 100644 --- a/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs +++ b/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs @@ -30,14 +30,15 @@ public static SslClientAuthenticationOptions ShallowClone(this SslClientAuthenti LocalCertificateSelectionCallback = options.LocalCertificateSelectionCallback, RemoteCertificateValidationCallback = options.RemoteCertificateValidationCallback, TargetHost = options.TargetHost, - AllowRsaPssPad = options.AllowRsaPssPad + AllowRsaPssPad = options.AllowRsaPssPad, + AllowRsaRsae = options.AllowRsaRsae }; #if DEBUG // Try to detect if a property gets added that we're not copying correctly. // The property count is guard for new properties that also needs to be added above. PropertyInfo[] properties = typeof(SslClientAuthenticationOptions).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)!; - Debug.Assert(properties.Length == 14); + Debug.Assert(properties.Length == 15); foreach (PropertyInfo pi in properties) { object? origValue = pi.GetValue(options); diff --git a/src/libraries/System.Net.Security/ref/System.Net.Security.cs b/src/libraries/System.Net.Security/ref/System.Net.Security.cs index c74666c0ffba56..d7f96e3c8dde46 100644 --- a/src/libraries/System.Net.Security/ref/System.Net.Security.cs +++ b/src/libraries/System.Net.Security/ref/System.Net.Security.cs @@ -51,14 +51,14 @@ public NegotiateAuthentication(System.Net.Security.NegotiateAuthenticationServer public System.Net.Security.ProtectionLevel ProtectionLevel { get { throw null; } } public System.Security.Principal.IIdentity RemoteIdentity { get { throw null; } } public string? TargetName { get { throw null; } } + public void ComputeIntegrityCheck(System.ReadOnlySpan message, System.Buffers.IBufferWriter signatureWriter) { } public void Dispose() { } public byte[]? GetOutgoingBlob(System.ReadOnlySpan incomingBlob, out System.Net.Security.NegotiateAuthenticationStatusCode statusCode) { throw null; } public string? GetOutgoingBlob(string? incomingBlob, out System.Net.Security.NegotiateAuthenticationStatusCode statusCode) { throw null; } public System.Net.Security.NegotiateAuthenticationStatusCode Unwrap(System.ReadOnlySpan input, System.Buffers.IBufferWriter outputWriter, out bool wasEncrypted) { throw null; } public System.Net.Security.NegotiateAuthenticationStatusCode UnwrapInPlace(System.Span input, out int unwrappedOffset, out int unwrappedLength, out bool wasEncrypted) { throw null; } - public System.Net.Security.NegotiateAuthenticationStatusCode Wrap(System.ReadOnlySpan input, System.Buffers.IBufferWriter outputWriter, bool requestEncryption, out bool isEncrypted) { throw null; } - public void ComputeIntegrityCheck(System.ReadOnlySpan message, System.Buffers.IBufferWriter signatureWriter) { } public bool VerifyIntegrityCheck(System.ReadOnlySpan message, System.ReadOnlySpan signature) { throw null; } + public System.Net.Security.NegotiateAuthenticationStatusCode Wrap(System.ReadOnlySpan input, System.Buffers.IBufferWriter outputWriter, bool requestEncryption, out bool isEncrypted) { throw null; } } public partial class NegotiateAuthenticationClientOptions { @@ -201,6 +201,8 @@ public partial class SslClientAuthenticationOptions { public SslClientAuthenticationOptions() { } public bool AllowRenegotiation { get { throw null; } set { } } + public bool AllowRsaPssPad { get { throw null; } set { } } + public bool AllowRsaRsae { get { throw null; } set { } } public bool AllowTlsResume { get { throw null; } set { } } public System.Collections.Generic.List? ApplicationProtocols { get { throw null; } set { } } public System.Security.Cryptography.X509Certificates.X509ChainPolicy? CertificateChainPolicy { get { throw null; } set { } } @@ -213,7 +215,6 @@ public SslClientAuthenticationOptions() { } public System.Net.Security.LocalCertificateSelectionCallback? LocalCertificateSelectionCallback { get { throw null; } set { } } public System.Net.Security.RemoteCertificateValidationCallback? RemoteCertificateValidationCallback { get { throw null; } set { } } public string? TargetHost { get { throw null; } set { } } - public bool AllowRsaPssPad { get { throw null; } set { } } } public readonly partial struct SslClientHelloInfo { @@ -227,6 +228,8 @@ public partial class SslServerAuthenticationOptions { public SslServerAuthenticationOptions() { } public bool AllowRenegotiation { get { throw null; } set { } } + public bool AllowRsaPssPad { get { throw null; } set { } } + public bool AllowRsaRsae { get { throw null; } set { } } public bool AllowTlsResume { get { throw null; } set { } } public System.Collections.Generic.List? ApplicationProtocols { get { throw null; } set { } } public System.Security.Cryptography.X509Certificates.X509ChainPolicy? CertificateChainPolicy { get { throw null; } set { } } @@ -239,7 +242,6 @@ public SslServerAuthenticationOptions() { } public System.Security.Cryptography.X509Certificates.X509Certificate? ServerCertificate { get { throw null; } set { } } public System.Net.Security.SslStreamCertificateContext? ServerCertificateContext { get { throw null; } set { } } public System.Net.Security.ServerCertificateSelectionCallback? ServerCertificateSelectionCallback { get { throw null; } set { } } - public bool AllowRsaPssPad { get { throw null; } set { } } } public partial class SslStream : System.Net.Security.AuthenticatedStream { @@ -253,22 +255,22 @@ public partial class SslStream : System.Net.Security.AuthenticatedStream public override bool CanTimeout { get { throw null; } } public override bool CanWrite { get { throw null; } } public virtual bool CheckCertRevocationStatus { get { throw null; } } - [Obsolete("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherAlgorithmStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public virtual System.Security.Authentication.CipherAlgorithmType CipherAlgorithm { get { throw null; } } - [Obsolete("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherAlgorithmStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public virtual int CipherStrength { get { throw null; } } - [Obsolete("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherAlgorithmStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public virtual System.Security.Authentication.HashAlgorithmType HashAlgorithm { get { throw null; } } - [Obsolete("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherAlgorithmStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public virtual int HashStrength { get { throw null; } } public override bool IsAuthenticated { get { throw null; } } public override bool IsEncrypted { get { throw null; } } public override bool IsMutuallyAuthenticated { get { throw null; } } public override bool IsServer { get { throw null; } } public override bool IsSigned { get { throw null; } } - [Obsolete("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherAlgorithmStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public virtual System.Security.Authentication.ExchangeAlgorithmType KeyExchangeAlgorithm { get { throw null; } } - [Obsolete("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherAlgorithmStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public virtual int KeyExchangeStrength { get { throw null; } } public override long Length { get { throw null; } } public virtual System.Security.Cryptography.X509Certificates.X509Certificate? LocalCertificate { get { throw null; } } @@ -321,6 +323,7 @@ public override void Flush() { } [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] public virtual System.Threading.Tasks.Task NegotiateClientCertificateAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public override int Read(byte[] buffer, int offset, int count) { throw null; } + public override int Read(System.Span buffer) { throw null; } public override System.Threading.Tasks.Task ReadAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; } public override System.Threading.Tasks.ValueTask ReadAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public override int ReadByte() { throw null; } @@ -329,8 +332,10 @@ public override void SetLength(long value) { } public virtual System.Threading.Tasks.Task ShutdownAsync() { throw null; } public void Write(byte[] buffer) { } public override void Write(byte[] buffer, int offset, int count) { } + public override void Write(System.ReadOnlySpan buffer) { } public override System.Threading.Tasks.Task WriteAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; } public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public override void WriteByte(byte value) { } } public partial class SslStreamCertificateContext { diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs index 8011724a469b78..92111c9b1b396c 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs @@ -52,6 +52,7 @@ internal void UpdateOptions(SslClientAuthenticationOptions sslClientAuthenticati CertificateContext = sslClientAuthenticationOptions.ClientCertificateContext; TargetHost = sslClientAuthenticationOptions.TargetHost ?? string.Empty; AllowRsaPssPad = sslClientAuthenticationOptions.AllowRsaPssPad; + AllowRsaRsae = sslClientAuthenticationOptions.AllowRsaRsae; // Client specific options. CertificateRevocationCheckMode = sslClientAuthenticationOptions.CertificateRevocationCheckMode; @@ -112,6 +113,7 @@ internal void UpdateOptions(SslServerAuthenticationOptions sslServerAuthenticati CipherSuitesPolicy = sslServerAuthenticationOptions.CipherSuitesPolicy; CertificateRevocationCheckMode = sslServerAuthenticationOptions.CertificateRevocationCheckMode; AllowRsaPssPad = sslServerAuthenticationOptions.AllowRsaPssPad; + AllowRsaRsae = sslServerAuthenticationOptions.AllowRsaRsae; if (sslServerAuthenticationOptions.ServerCertificateContext != null) { CertificateContext = sslServerAuthenticationOptions.ServerCertificateContext; @@ -188,6 +190,7 @@ private static SslProtocols FilterOutIncompatibleSslProtocols(SslProtocols proto internal X509ChainPolicy? CertificateChainPolicy { get; set; } internal bool AllowTlsResume { get; set; } internal bool AllowRsaPssPad { get; set; } + internal bool AllowRsaRsae { get; set; } #if TARGET_ANDROID internal SslStream.JavaProxy? SslStreamProxy { get; set; } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs index cc2fde3906decf..89d70b51eb8028 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs @@ -98,5 +98,6 @@ public SslProtocols EnabledSslProtocols public X509ChainPolicy? CertificateChainPolicy { get; set; } public bool AllowRsaPssPad { get; set; } = true; + public bool AllowRsaRsae { get; set; } = true; } } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs index 1ef16948230785..688da093834c73 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs @@ -94,5 +94,6 @@ public EncryptionPolicy EncryptionPolicy public X509ChainPolicy? CertificateChainPolicy { get; set; } public bool AllowRsaPssPad { get; set; } = true; + public bool AllowRsaRsae { get; set; } = true; } } diff --git a/src/native/libs/System.Security.Cryptography.Native/entrypoints.c b/src/native/libs/System.Security.Cryptography.Native/entrypoints.c index b4bce37e9864d8..c415e833a5e9b9 100644 --- a/src/native/libs/System.Security.Cryptography.Native/entrypoints.c +++ b/src/native/libs/System.Security.Cryptography.Native/entrypoints.c @@ -408,6 +408,7 @@ static const Entry s_cryptoNative[] = DllImportEntry(CryptoNative_X509DecodeOcspToExpiration) DllImportEntry(CryptoNative_X509Duplicate) DllImportEntry(CryptoNative_SslGet0AlpnSelected) + DllImportEntry(CryptoNative_GetDefaultSignatureAlgorithms) }; EXTERN_C const void* CryptoResolveDllImport(const char* name); diff --git a/src/native/libs/System.Security.Cryptography.Native/opensslshim.h b/src/native/libs/System.Security.Cryptography.Native/opensslshim.h index 82023bab1b7af2..a5d23b6a3796d7 100644 --- a/src/native/libs/System.Security.Cryptography.Native/opensslshim.h +++ b/src/native/libs/System.Security.Cryptography.Native/opensslshim.h @@ -718,6 +718,7 @@ extern bool g_libSslUses32BitTime; REQUIRED_FUNCTION(SSL_do_handshake) \ REQUIRED_FUNCTION(SSL_free) \ REQUIRED_FUNCTION(SSL_get_ciphers) \ + REQUIRED_FUNCTION(SSL_get_sigalgs) \ REQUIRED_FUNCTION(SSL_get_client_CA_list) \ REQUIRED_FUNCTION(SSL_get_current_cipher) \ REQUIRED_FUNCTION(SSL_get_error) \ @@ -1293,6 +1294,7 @@ extern TYPEOF(OPENSSL_gmtime)* OPENSSL_gmtime_ptr; #define SSL_do_handshake SSL_do_handshake_ptr #define SSL_free SSL_free_ptr #define SSL_get_ciphers SSL_get_ciphers_ptr +#define SSL_get_sigalgs SSL_get_sigalgs_ptr #define SSL_get_client_CA_list SSL_get_client_CA_list_ptr #define SSL_get_certificate SSL_get_certificate_ptr #define SSL_get_current_cipher SSL_get_current_cipher_ptr diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c index fe8a63b115497b..8f7be0e74ff32d 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c +++ b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c @@ -1194,6 +1194,89 @@ static int MakeSelfSignedCertificate(X509* cert, EVP_PKEY* evp) return ret; } +int32_t CryptoNative_GetDefaultSignatureAlgorithms(uint16_t* buffer, int32_t* count) +{ + int ret = 0; + + SSL_CTX* clientCtx = CryptoNative_SslCtxCreate(TLS_method()); + SSL_CTX* serverCtx = CryptoNative_SslCtxCreate(TLS_method()); + + BIO *bio1 = BIO_new(BIO_s_mem()); + BIO *bio2 = BIO_new(BIO_s_mem()); + + SSL* client = NULL; + SSL* server = NULL; + + if (clientCtx != NULL && serverCtx != NULL && bio1 != NULL && bio2 != NULL) + { + SSL_CTX_set_verify(clientCtx, SSL_VERIFY_NONE, NULL); + SSL_CTX_set_verify(serverCtx, SSL_VERIFY_NONE, NULL); + + server = CryptoNative_SslCreate(serverCtx); + SSL_set_accept_state(server); + + client = CryptoNative_SslCreate(clientCtx); + SSL_set_connect_state(client); + + // set BIOs in opposite + SSL_set_bio(client, bio1, bio2); + SSL_set_bio(server, bio2, bio1); + + // SSL_set_bio takes ownership so we need to up reference since same BIO is shared. + BIO_up_ref(bio1); + BIO_up_ref(bio2); + bio1 = NULL; + bio2 = NULL; + + // send/receive the client hello + ret = SSL_do_handshake(client); + ret = SSL_do_handshake(server); + + int c = SSL_get_sigalgs(server, 0, NULL, NULL, NULL, NULL, NULL); + if (c > 0) + { + for (int i = 0; i < c; i++) + { + if (i >= *count) + { + break; + } + + unsigned char sig, hash; + SSL_get_sigalgs(server, i, NULL, NULL, NULL, &sig, &hash); + buffer[i] = (uint16_t)(hash << 8 | sig); + } + + *count = c; + ret = 0; + } + } + + if (bio1) + { + BIO_free(bio1); + } + + if (bio2) + { + BIO_free(bio2); + } + + if (client != NULL) + { + SSL_free(client); + } + + if (server != NULL) + { + SSL_free(server); + } + + ERR_clear_error(); + + return ret; +} + int32_t CryptoNative_OpenSslGetProtocolSupport(SslProtocols protocol) { // Many of these helpers already clear the error queue, and we unconditionally diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h index cc9254ab9d17ce..6d34704196b158 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h +++ b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h @@ -538,6 +538,11 @@ and emits a value indicating if the cipher belongs to the SSL2-TLS1.2 list, or t */ PALEXPORT const char* CryptoNative_GetOpenSslCipherSuiteName(SSL* ssl, int32_t cipherSuite, int32_t* isTls12OrLower); +/* +Returns the signature algorithms enabled by default +*/ +PALEXPORT int32_t CryptoNative_GetDefaultSignatureAlgorithms(uint16_t* buffer, int32_t* count); + /* Checks if given protocol version is supported. */ From 0843e94461d174f983c9e57a8271ea95217569ec Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Wed, 16 Apr 2025 13:57:34 +0200 Subject: [PATCH 04/24] Fix windows --- .../Net/Security/SslStreamPal.Windows.cs | 53 ++++++++++++++----- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs index fdfa82ac7f1cee..7ed4d0e2df3023 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs @@ -448,29 +448,54 @@ public static unsafe SafeFreeCredentials AcquireCredentialsHandleSchCredentials( Interop.SspiCli.TLS_PARAMETERS tlsParameters = default; if (protocolFlags != 0) { + credential.cTlsParameters = 1; + credential.pTlsParameters = &tlsParameters; + // If we were asked to do specific protocol we need to fill TLS_PARAMETERS. tlsParameters.grbitDisabledProtocols = (uint)protocolFlags ^ uint.MaxValue; } - Interop.SspiCli.CRYPTO_SETTINGS cryptoSettings = default; - IntPtr algIdPtr = IntPtr.Zero; + Span cryptoSettings = stackalloc Interop.SspiCli.CRYPTO_SETTINGS[(!authOptions.AllowRsaRsae ? 1 : 0) + (!authOptions.AllowRsaPssPad ? 1 : 0)]; + Span algIdPtrs = stackalloc IntPtr[cryptoSettings.Length]; - if (Environment.GetEnvironmentVariable("DISABLED_ALG") is string alg) + try { - algIdPtr = Marshal.StringToHGlobalUni(alg); - cryptoSettings.eAlgorithmUsage = Interop.SspiCli.CRYPTO_SETTINGS.TlsAlgorithmUsage.TlsParametersCngAlgUsageCertSig; - Interop.NtDll.RtlInitUnicodeString(out cryptoSettings.strCngAlgId, algIdPtr); + if (cryptoSettings.Length > 0) + { + int i = 0; - tlsParameters.pDisabledCrypto = &cryptoSettings; - tlsParameters.cDisabledCrypto = 1; + if (!authOptions.AllowRsaRsae) + { + algIdPtrs[i] = Marshal.StringToHGlobalUni("SCH_RSA_PSS_PAD"); + cryptoSettings[i].eAlgorithmUsage = Interop.SspiCli.CRYPTO_SETTINGS.TlsAlgorithmUsage.TlsParametersCngAlgUsageCertSig; + Interop.NtDll.RtlInitUnicodeString(out cryptoSettings[i].strCngAlgId, algIdPtrs[i]); + i++; + } - credential.cTlsParameters = 1; - credential.pTlsParameters = &tlsParameters; - } + if (!authOptions.AllowRsaPssPad) + { + algIdPtrs[i] = Marshal.StringToHGlobalUni("SCH_RSA_PKCS_PAD"); + cryptoSettings[i].eAlgorithmUsage = Interop.SspiCli.CRYPTO_SETTINGS.TlsAlgorithmUsage.TlsParametersCngAlgUsageCertSig; + Interop.NtDll.RtlInitUnicodeString(out cryptoSettings[i].strCngAlgId, algIdPtrs[i]); + i++; + } + + tlsParameters.pDisabledCrypto = (Interop.SspiCli.CRYPTO_SETTINGS*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(cryptoSettings)); + tlsParameters.cDisabledCrypto = cryptoSettings.Length; + + credential.cTlsParameters = 1; + credential.pTlsParameters = &tlsParameters; + } - var ret = AcquireCredentialsHandle(direction, &credential); - Marshal.FreeHGlobal(algIdPtr); - return ret; + return AcquireCredentialsHandle(direction, &credential); + } + finally + { + foreach (IntPtr algIdPtr in algIdPtrs) + { + Marshal.FreeHGlobal(algIdPtr); + } + } } public static unsafe ProtocolToken EncryptMessage(SafeDeleteSslContext securityContext, ReadOnlyMemory input, int headerSize, int trailerSize) From d41dd03cddb9b873fe37645bda0de517bf5f741a Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Wed, 16 Apr 2025 14:01:34 +0200 Subject: [PATCH 05/24] Rename to EnableRsaPkcsPad --- .../Interop.OpenSsl.cs | 4 +-- ...slClientAuthenticationOptionsExtensions.cs | 2 +- .../ref/System.Net.Security.cs | 4 +-- .../Net/Security/SslAuthenticationOptions.cs | 6 ++-- .../SslClientAuthenticationOptions.cs | 2 +- .../SslServerAuthenticationOptions.cs | 2 +- .../Net/Security/SslStreamPal.Windows.cs | 28 +++++++++---------- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index 15d28c5b5edbc7..8bb85d8e368dd2 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -417,9 +417,9 @@ internal static SafeSslHandle AllocateSslHandle(SslAuthenticationOptions sslAuth sslHandle.SslContextHandle = sslCtxHandle; } - if (!sslAuthenticationOptions.AllowRsaPssPad || !sslAuthenticationOptions.AllowRsaRsae) + if (!sslAuthenticationOptions.AllowRsaPssPad || !sslAuthenticationOptions.AllowRsaPkcsPad) { - ConfigureSignatureAlgorithms(sslHandle, sslAuthenticationOptions.AllowRsaPssPad, sslAuthenticationOptions.AllowRsaRsae); + ConfigureSignatureAlgorithms(sslHandle, sslAuthenticationOptions.AllowRsaPssPad, sslAuthenticationOptions.AllowRsaPkcsPad); } if (sslAuthenticationOptions.ApplicationProtocols != null && sslAuthenticationOptions.ApplicationProtocols.Count != 0) diff --git a/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs b/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs index 5ec4cd17cc14cb..776cc36defbd59 100644 --- a/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs +++ b/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs @@ -31,7 +31,7 @@ public static SslClientAuthenticationOptions ShallowClone(this SslClientAuthenti RemoteCertificateValidationCallback = options.RemoteCertificateValidationCallback, TargetHost = options.TargetHost, AllowRsaPssPad = options.AllowRsaPssPad, - AllowRsaRsae = options.AllowRsaRsae + AllowRsaPkcsPad = options.AllowRsaPkcsPad }; #if DEBUG diff --git a/src/libraries/System.Net.Security/ref/System.Net.Security.cs b/src/libraries/System.Net.Security/ref/System.Net.Security.cs index d7f96e3c8dde46..5fc718b69247f7 100644 --- a/src/libraries/System.Net.Security/ref/System.Net.Security.cs +++ b/src/libraries/System.Net.Security/ref/System.Net.Security.cs @@ -202,7 +202,7 @@ public partial class SslClientAuthenticationOptions public SslClientAuthenticationOptions() { } public bool AllowRenegotiation { get { throw null; } set { } } public bool AllowRsaPssPad { get { throw null; } set { } } - public bool AllowRsaRsae { get { throw null; } set { } } + public bool AllowRsaPkcsPad { get { throw null; } set { } } public bool AllowTlsResume { get { throw null; } set { } } public System.Collections.Generic.List? ApplicationProtocols { get { throw null; } set { } } public System.Security.Cryptography.X509Certificates.X509ChainPolicy? CertificateChainPolicy { get { throw null; } set { } } @@ -229,7 +229,7 @@ public partial class SslServerAuthenticationOptions public SslServerAuthenticationOptions() { } public bool AllowRenegotiation { get { throw null; } set { } } public bool AllowRsaPssPad { get { throw null; } set { } } - public bool AllowRsaRsae { get { throw null; } set { } } + public bool AllowRsaPkcsPad { get { throw null; } set { } } public bool AllowTlsResume { get { throw null; } set { } } public System.Collections.Generic.List? ApplicationProtocols { get { throw null; } set { } } public System.Security.Cryptography.X509Certificates.X509ChainPolicy? CertificateChainPolicy { get { throw null; } set { } } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs index 92111c9b1b396c..3c2ba69b8f2862 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs @@ -52,7 +52,7 @@ internal void UpdateOptions(SslClientAuthenticationOptions sslClientAuthenticati CertificateContext = sslClientAuthenticationOptions.ClientCertificateContext; TargetHost = sslClientAuthenticationOptions.TargetHost ?? string.Empty; AllowRsaPssPad = sslClientAuthenticationOptions.AllowRsaPssPad; - AllowRsaRsae = sslClientAuthenticationOptions.AllowRsaRsae; + AllowRsaPkcsPad = sslClientAuthenticationOptions.AllowRsaPkcsPad; // Client specific options. CertificateRevocationCheckMode = sslClientAuthenticationOptions.CertificateRevocationCheckMode; @@ -113,7 +113,7 @@ internal void UpdateOptions(SslServerAuthenticationOptions sslServerAuthenticati CipherSuitesPolicy = sslServerAuthenticationOptions.CipherSuitesPolicy; CertificateRevocationCheckMode = sslServerAuthenticationOptions.CertificateRevocationCheckMode; AllowRsaPssPad = sslServerAuthenticationOptions.AllowRsaPssPad; - AllowRsaRsae = sslServerAuthenticationOptions.AllowRsaRsae; + AllowRsaPkcsPad = sslServerAuthenticationOptions.AllowRsaPkcsPad; if (sslServerAuthenticationOptions.ServerCertificateContext != null) { CertificateContext = sslServerAuthenticationOptions.ServerCertificateContext; @@ -190,7 +190,7 @@ private static SslProtocols FilterOutIncompatibleSslProtocols(SslProtocols proto internal X509ChainPolicy? CertificateChainPolicy { get; set; } internal bool AllowTlsResume { get; set; } internal bool AllowRsaPssPad { get; set; } - internal bool AllowRsaRsae { get; set; } + internal bool AllowRsaPkcsPad { get; set; } #if TARGET_ANDROID internal SslStream.JavaProxy? SslStreamProxy { get; set; } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs index 89d70b51eb8028..c6583bd876be45 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs @@ -98,6 +98,6 @@ public SslProtocols EnabledSslProtocols public X509ChainPolicy? CertificateChainPolicy { get; set; } public bool AllowRsaPssPad { get; set; } = true; - public bool AllowRsaRsae { get; set; } = true; + public bool AllowRsaPkcsPad { get; set; } = true; } } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs index 688da093834c73..bc9b17385087a4 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs @@ -94,6 +94,6 @@ public EncryptionPolicy EncryptionPolicy public X509ChainPolicy? CertificateChainPolicy { get; set; } public bool AllowRsaPssPad { get; set; } = true; - public bool AllowRsaRsae { get; set; } = true; + public bool AllowRsaPkcsPad { get; set; } = true; } } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs index 7ed4d0e2df3023..6a528e49e75887 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs @@ -455,33 +455,33 @@ public static unsafe SafeFreeCredentials AcquireCredentialsHandleSchCredentials( tlsParameters.grbitDisabledProtocols = (uint)protocolFlags ^ uint.MaxValue; } - Span cryptoSettings = stackalloc Interop.SspiCli.CRYPTO_SETTINGS[(!authOptions.AllowRsaRsae ? 1 : 0) + (!authOptions.AllowRsaPssPad ? 1 : 0)]; - Span algIdPtrs = stackalloc IntPtr[cryptoSettings.Length]; + Span cryptoSettings = stackalloc Interop.SspiCli.CRYPTO_SETTINGS[2]; + Span algIdPtrs = stackalloc IntPtr[2]; + int cryptoSettingsCount = 0; try { if (cryptoSettings.Length > 0) { - int i = 0; - if (!authOptions.AllowRsaRsae) + if (!authOptions.AllowRsaPkcsPad) { - algIdPtrs[i] = Marshal.StringToHGlobalUni("SCH_RSA_PSS_PAD"); - cryptoSettings[i].eAlgorithmUsage = Interop.SspiCli.CRYPTO_SETTINGS.TlsAlgorithmUsage.TlsParametersCngAlgUsageCertSig; - Interop.NtDll.RtlInitUnicodeString(out cryptoSettings[i].strCngAlgId, algIdPtrs[i]); - i++; + algIdPtrs[cryptoSettingsCount] = Marshal.StringToHGlobalUni("SCH_RSA_PSS_PAD"); + cryptoSettings[cryptoSettingsCount].eAlgorithmUsage = Interop.SspiCli.CRYPTO_SETTINGS.TlsAlgorithmUsage.TlsParametersCngAlgUsageCertSig; + Interop.NtDll.RtlInitUnicodeString(out cryptoSettings[cryptoSettingsCount].strCngAlgId, algIdPtrs[cryptoSettingsCount]); + cryptoSettingsCount++; } if (!authOptions.AllowRsaPssPad) { - algIdPtrs[i] = Marshal.StringToHGlobalUni("SCH_RSA_PKCS_PAD"); - cryptoSettings[i].eAlgorithmUsage = Interop.SspiCli.CRYPTO_SETTINGS.TlsAlgorithmUsage.TlsParametersCngAlgUsageCertSig; - Interop.NtDll.RtlInitUnicodeString(out cryptoSettings[i].strCngAlgId, algIdPtrs[i]); - i++; + algIdPtrs[cryptoSettingsCount] = Marshal.StringToHGlobalUni("SCH_RSA_PKCS_PAD"); + cryptoSettings[cryptoSettingsCount].eAlgorithmUsage = Interop.SspiCli.CRYPTO_SETTINGS.TlsAlgorithmUsage.TlsParametersCngAlgUsageCertSig; + Interop.NtDll.RtlInitUnicodeString(out cryptoSettings[cryptoSettingsCount].strCngAlgId, algIdPtrs[cryptoSettingsCount]); + cryptoSettingsCount++; } tlsParameters.pDisabledCrypto = (Interop.SspiCli.CRYPTO_SETTINGS*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(cryptoSettings)); - tlsParameters.cDisabledCrypto = cryptoSettings.Length; + tlsParameters.cDisabledCrypto = cryptoSettingsCount; credential.cTlsParameters = 1; credential.pTlsParameters = &tlsParameters; @@ -491,7 +491,7 @@ public static unsafe SafeFreeCredentials AcquireCredentialsHandleSchCredentials( } finally { - foreach (IntPtr algIdPtr in algIdPtrs) + foreach (IntPtr algIdPtr in algIdPtrs.Slice(0, cryptoSettingsCount)) { Marshal.FreeHGlobal(algIdPtr); } From f3c28e9191b2f031fa09f8768421a5801e5eccf9 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Wed, 16 Apr 2025 16:58:35 +0200 Subject: [PATCH 06/24] Minor changes --- .../Interop.OpenSsl.cs | 4 ++-- .../Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs | 2 +- .../src/System/Net/Security/SslStreamPal.Windows.cs | 9 ++++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index 8bb85d8e368dd2..daa411e2e3515d 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -576,7 +576,7 @@ internal static string[] GetDefaultSignatureAlgorithms() return Array.ConvertAll(rawAlgs, ConvertAlg); } - internal static unsafe void ConfigureSignatureAlgorithms(SafeSslHandle sslHandle, bool enablePss, bool enableRsae) + internal static unsafe void ConfigureSignatureAlgorithms(SafeSslHandle sslHandle, bool enablePss, bool enablePkcs) { byte[] buffer = ArrayPool.Shared.Rent(512); try @@ -590,7 +590,7 @@ internal static unsafe void ConfigureSignatureAlgorithms(SafeSslHandle sslHandle continue; } - if (alg.StartsWith("rsa_pss_rsae_") && !enableRsae) + if (alg.StartsWith("rsa_pkcs1_") && !enablePkcs) { continue; } diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs index a7652dd8749cc8..ffb51e5dd0d969 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs @@ -278,7 +278,7 @@ public enum Flags internal unsafe struct CRYPTO_SETTINGS { public TlsAlgorithmUsage eAlgorithmUsage; // How this algorithm is being used. - public UNICODE_STRING strCngAlgId; // CNG algorithm identifier. + public UNICODE_STRING strCngAlgId; // CNG algorithm identifier. public int cChainingModes; // Set to 0 if CNG algorithm does not have a chaining mode. public UNICODE_STRING* rgstrChainingModes; // Set to NULL if CNG algorithm does not have a chaining mode. public int dwMinBitLength; // Minimum bit length for the specified CNG algorithm. Set to 0 if not defined or CNG algorithm implies bit length. diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs index 6a528e49e75887..d68f89f4e41c7a 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs @@ -463,10 +463,11 @@ public static unsafe SafeFreeCredentials AcquireCredentialsHandleSchCredentials( { if (cryptoSettings.Length > 0) { - if (!authOptions.AllowRsaPkcsPad) { - algIdPtrs[cryptoSettingsCount] = Marshal.StringToHGlobalUni("SCH_RSA_PSS_PAD"); + algIdPtrs[cryptoSettingsCount] = Marshal.StringToHGlobalUni("SCH_RSA_PKCS_PAD"); + + cryptoSettings[cryptoSettingsCount] = default; cryptoSettings[cryptoSettingsCount].eAlgorithmUsage = Interop.SspiCli.CRYPTO_SETTINGS.TlsAlgorithmUsage.TlsParametersCngAlgUsageCertSig; Interop.NtDll.RtlInitUnicodeString(out cryptoSettings[cryptoSettingsCount].strCngAlgId, algIdPtrs[cryptoSettingsCount]); cryptoSettingsCount++; @@ -474,7 +475,9 @@ public static unsafe SafeFreeCredentials AcquireCredentialsHandleSchCredentials( if (!authOptions.AllowRsaPssPad) { - algIdPtrs[cryptoSettingsCount] = Marshal.StringToHGlobalUni("SCH_RSA_PKCS_PAD"); + algIdPtrs[cryptoSettingsCount] = Marshal.StringToHGlobalUni("SCH_RSA_PSS_PAD"); + + cryptoSettings[cryptoSettingsCount] = default; cryptoSettings[cryptoSettingsCount].eAlgorithmUsage = Interop.SspiCli.CRYPTO_SETTINGS.TlsAlgorithmUsage.TlsParametersCngAlgUsageCertSig; Interop.NtDll.RtlInitUnicodeString(out cryptoSettings[cryptoSettingsCount].strCngAlgId, algIdPtrs[cryptoSettingsCount]); cryptoSettingsCount++; From e7adf124d17cce74678aedc0596d2eb4d7e3fbac Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Wed, 4 Jun 2025 11:35:41 +0200 Subject: [PATCH 07/24] Rename in accordance to approved API shape --- .../Interop.OpenSsl.cs | 4 ++-- .../SslClientAuthenticationOptionsExtensions.cs | 4 ++-- .../System.Net.Security/ref/System.Net.Security.cs | 8 ++++---- .../System/Net/Security/SslAuthenticationOptions.cs | 12 ++++++------ .../Net/Security/SslClientAuthenticationOptions.cs | 4 ++-- .../Net/Security/SslServerAuthenticationOptions.cs | 4 ++-- .../src/System/Net/Security/SslStreamPal.Windows.cs | 4 ++-- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index daa411e2e3515d..8f7c65ebb12a40 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -417,9 +417,9 @@ internal static SafeSslHandle AllocateSslHandle(SslAuthenticationOptions sslAuth sslHandle.SslContextHandle = sslCtxHandle; } - if (!sslAuthenticationOptions.AllowRsaPssPad || !sslAuthenticationOptions.AllowRsaPkcsPad) + if (!sslAuthenticationOptions.AllowRsaPssPadding || !sslAuthenticationOptions.AllowRsaPkcs1Padding) { - ConfigureSignatureAlgorithms(sslHandle, sslAuthenticationOptions.AllowRsaPssPad, sslAuthenticationOptions.AllowRsaPkcsPad); + ConfigureSignatureAlgorithms(sslHandle, sslAuthenticationOptions.AllowRsaPssPadding, sslAuthenticationOptions.AllowRsaPkcs1Padding); } if (sslAuthenticationOptions.ApplicationProtocols != null && sslAuthenticationOptions.ApplicationProtocols.Count != 0) diff --git a/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs b/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs index 776cc36defbd59..e7ee8b22d15e10 100644 --- a/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs +++ b/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs @@ -30,8 +30,8 @@ public static SslClientAuthenticationOptions ShallowClone(this SslClientAuthenti LocalCertificateSelectionCallback = options.LocalCertificateSelectionCallback, RemoteCertificateValidationCallback = options.RemoteCertificateValidationCallback, TargetHost = options.TargetHost, - AllowRsaPssPad = options.AllowRsaPssPad, - AllowRsaPkcsPad = options.AllowRsaPkcsPad + AllowRsaPssPadding = options.AllowRsaPssPadding, + AllowRsaPkcs1Padding = options.AllowRsaPkcs1Padding }; #if DEBUG diff --git a/src/libraries/System.Net.Security/ref/System.Net.Security.cs b/src/libraries/System.Net.Security/ref/System.Net.Security.cs index 5fc718b69247f7..849d5469fba216 100644 --- a/src/libraries/System.Net.Security/ref/System.Net.Security.cs +++ b/src/libraries/System.Net.Security/ref/System.Net.Security.cs @@ -201,8 +201,8 @@ public partial class SslClientAuthenticationOptions { public SslClientAuthenticationOptions() { } public bool AllowRenegotiation { get { throw null; } set { } } - public bool AllowRsaPssPad { get { throw null; } set { } } - public bool AllowRsaPkcsPad { get { throw null; } set { } } + public bool AllowRsaPssPadding { get { throw null; } set { } } + public bool AllowRsaPkcs1Padding { get { throw null; } set { } } public bool AllowTlsResume { get { throw null; } set { } } public System.Collections.Generic.List? ApplicationProtocols { get { throw null; } set { } } public System.Security.Cryptography.X509Certificates.X509ChainPolicy? CertificateChainPolicy { get { throw null; } set { } } @@ -228,8 +228,8 @@ public partial class SslServerAuthenticationOptions { public SslServerAuthenticationOptions() { } public bool AllowRenegotiation { get { throw null; } set { } } - public bool AllowRsaPssPad { get { throw null; } set { } } - public bool AllowRsaPkcsPad { get { throw null; } set { } } + public bool AllowRsaPssPadding { get { throw null; } set { } } + public bool AllowRsaPkcs1Padding { get { throw null; } set { } } public bool AllowTlsResume { get { throw null; } set { } } public System.Collections.Generic.List? ApplicationProtocols { get { throw null; } set { } } public System.Security.Cryptography.X509Certificates.X509ChainPolicy? CertificateChainPolicy { get { throw null; } set { } } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs index 3c2ba69b8f2862..aed2a539cb0f4d 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs @@ -51,8 +51,8 @@ internal void UpdateOptions(SslClientAuthenticationOptions sslClientAuthenticati RemoteCertRequired = true; CertificateContext = sslClientAuthenticationOptions.ClientCertificateContext; TargetHost = sslClientAuthenticationOptions.TargetHost ?? string.Empty; - AllowRsaPssPad = sslClientAuthenticationOptions.AllowRsaPssPad; - AllowRsaPkcsPad = sslClientAuthenticationOptions.AllowRsaPkcsPad; + AllowRsaPssPadding = sslClientAuthenticationOptions.AllowRsaPssPadding; + AllowRsaPkcs1Padding = sslClientAuthenticationOptions.AllowRsaPkcs1Padding; // Client specific options. CertificateRevocationCheckMode = sslClientAuthenticationOptions.CertificateRevocationCheckMode; @@ -112,8 +112,8 @@ internal void UpdateOptions(SslServerAuthenticationOptions sslServerAuthenticati RemoteCertRequired = sslServerAuthenticationOptions.ClientCertificateRequired; CipherSuitesPolicy = sslServerAuthenticationOptions.CipherSuitesPolicy; CertificateRevocationCheckMode = sslServerAuthenticationOptions.CertificateRevocationCheckMode; - AllowRsaPssPad = sslServerAuthenticationOptions.AllowRsaPssPad; - AllowRsaPkcsPad = sslServerAuthenticationOptions.AllowRsaPkcsPad; + AllowRsaPssPadding = sslServerAuthenticationOptions.AllowRsaPssPadding; + AllowRsaPkcs1Padding = sslServerAuthenticationOptions.AllowRsaPkcs1Padding; if (sslServerAuthenticationOptions.ServerCertificateContext != null) { CertificateContext = sslServerAuthenticationOptions.ServerCertificateContext; @@ -189,8 +189,8 @@ private static SslProtocols FilterOutIncompatibleSslProtocols(SslProtocols proto internal ServerOptionsSelectionCallback? ServerOptionDelegate { get; set; } internal X509ChainPolicy? CertificateChainPolicy { get; set; } internal bool AllowTlsResume { get; set; } - internal bool AllowRsaPssPad { get; set; } - internal bool AllowRsaPkcsPad { get; set; } + internal bool AllowRsaPssPadding { get; set; } + internal bool AllowRsaPkcs1Padding { get; set; } #if TARGET_ANDROID internal SslStream.JavaProxy? SslStreamProxy { get; set; } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs index c6583bd876be45..bf8a612c5f1ea2 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs @@ -97,7 +97,7 @@ public SslProtocols EnabledSslProtocols /// public X509ChainPolicy? CertificateChainPolicy { get; set; } - public bool AllowRsaPssPad { get; set; } = true; - public bool AllowRsaPkcsPad { get; set; } = true; + public bool AllowRsaPssPadding { get; set; } = true; + public bool AllowRsaPkcs1Padding { get; set; } = true; } } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs index bc9b17385087a4..218c0057cbf7a1 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs @@ -93,7 +93,7 @@ public EncryptionPolicy EncryptionPolicy /// public X509ChainPolicy? CertificateChainPolicy { get; set; } - public bool AllowRsaPssPad { get; set; } = true; - public bool AllowRsaPkcsPad { get; set; } = true; + public bool AllowRsaPssPadding { get; set; } = true; + public bool AllowRsaPkcs1Padding { get; set; } = true; } } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs index d68f89f4e41c7a..276da3c0f71fa4 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs @@ -463,7 +463,7 @@ public static unsafe SafeFreeCredentials AcquireCredentialsHandleSchCredentials( { if (cryptoSettings.Length > 0) { - if (!authOptions.AllowRsaPkcsPad) + if (!authOptions.AllowRsaPkcs1Padding) { algIdPtrs[cryptoSettingsCount] = Marshal.StringToHGlobalUni("SCH_RSA_PKCS_PAD"); @@ -473,7 +473,7 @@ public static unsafe SafeFreeCredentials AcquireCredentialsHandleSchCredentials( cryptoSettingsCount++; } - if (!authOptions.AllowRsaPssPad) + if (!authOptions.AllowRsaPssPadding) { algIdPtrs[cryptoSettingsCount] = Marshal.StringToHGlobalUni("SCH_RSA_PSS_PAD"); From 1342d45ffde3eefcca2f66f58ba9d9cbad60d00f Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Wed, 4 Jun 2025 13:41:28 +0200 Subject: [PATCH 08/24] Remove unintended change --- .../System.Net.Security/ref/System.Net.Security.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Net.Security/ref/System.Net.Security.cs b/src/libraries/System.Net.Security/ref/System.Net.Security.cs index 849d5469fba216..b4334245666705 100644 --- a/src/libraries/System.Net.Security/ref/System.Net.Security.cs +++ b/src/libraries/System.Net.Security/ref/System.Net.Security.cs @@ -255,22 +255,22 @@ public partial class SslStream : System.Net.Security.AuthenticatedStream public override bool CanTimeout { get { throw null; } } public override bool CanWrite { get { throw null; } } public virtual bool CheckCertRevocationStatus { get { throw null; } } - [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherAlgorithmStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public virtual System.Security.Authentication.CipherAlgorithmType CipherAlgorithm { get { throw null; } } - [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherAlgorithmStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public virtual int CipherStrength { get { throw null; } } - [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherAlgorithmStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public virtual System.Security.Authentication.HashAlgorithmType HashAlgorithm { get { throw null; } } - [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherAlgorithmStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public virtual int HashStrength { get { throw null; } } public override bool IsAuthenticated { get { throw null; } } public override bool IsEncrypted { get { throw null; } } public override bool IsMutuallyAuthenticated { get { throw null; } } public override bool IsServer { get { throw null; } } public override bool IsSigned { get { throw null; } } - [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherAlgorithmStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public virtual System.Security.Authentication.ExchangeAlgorithmType KeyExchangeAlgorithm { get { throw null; } } - [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherAlgorithmStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public virtual int KeyExchangeStrength { get { throw null; } } public override long Length { get { throw null; } } public virtual System.Security.Cryptography.X509Certificates.X509Certificate? LocalCertificate { get { throw null; } } From d830f1f998e213e936d899322cff642eba119770 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Wed, 4 Jun 2025 13:41:44 +0200 Subject: [PATCH 09/24] Set also client sigalgs --- .../Interop.OpenSsl.cs | 13 +++++++++---- .../Interop.Ssl.cs | 3 +++ .../entrypoints.c | 1 + .../System.Security.Cryptography.Native/pal_ssl.c | 7 +++++++ .../System.Security.Cryptography.Native/pal_ssl.h | 7 ++++++- 5 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index 8f7c65ebb12a40..a70f0d3782502f 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -610,11 +610,16 @@ internal static unsafe void ConfigureSignatureAlgorithms(SafeSslHandle sslHandle fixed (byte* pBuffer = buffer) { ret = Interop.Ssl.SslSetSigalgs(sslHandle, pBuffer); - } + if (ret != 1) + { + throw new InvalidOperationException("Failed to set signature algorithms."); + } - if (ret != 1) - { - throw new InvalidOperationException("Failed to set signature algorithms."); + ret = Interop.Ssl.SslSetClientSigalgs(sslHandle, pBuffer); + if (ret != 1) + { + throw new InvalidOperationException("Failed to set client signature algorithms."); + } } } finally diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index cd5ff81e369ebd..f448b011748a69 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -200,6 +200,9 @@ internal static SafeSharedX509StackHandle SslGetPeerCertChain(SafeSslHandle ssl) [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSetSigalgs")] internal static unsafe partial int SslSetSigalgs(SafeSslHandle ssl, byte* str); + [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSetClientSigalgs")] + internal static unsafe partial int SslSetClientSigalgs(SafeSslHandle ssl, byte* str); + [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_Tls13Supported")] private static partial int Tls13SupportedImpl(); diff --git a/src/native/libs/System.Security.Cryptography.Native/entrypoints.c b/src/native/libs/System.Security.Cryptography.Native/entrypoints.c index c415e833a5e9b9..d69d74111f1a1c 100644 --- a/src/native/libs/System.Security.Cryptography.Native/entrypoints.c +++ b/src/native/libs/System.Security.Cryptography.Native/entrypoints.c @@ -398,6 +398,7 @@ static const Entry s_cryptoNative[] = DllImportEntry(CryptoNative_SslSetTlsExtHostName) DllImportEntry(CryptoNative_SslSetVerifyPeer) DllImportEntry(CryptoNative_SslSetSigalgs) + DllImportEntry(CryptoNative_SslSetClientSigalgs) DllImportEntry(CryptoNative_SslShutdown) DllImportEntry(CryptoNative_SslStapleOcsp) DllImportEntry(CryptoNative_SslUseCertificate) diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c index 8f7be0e74ff32d..c0745fa9c5dd1a 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c +++ b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c @@ -1123,6 +1123,13 @@ int32_t CryptoNative_SslSetSigalgs(SSL* ssl, uint8_t* str) return (int32_t) SSL_ctrl(ssl, SSL_CTRL_SET_SIGALGS_LIST, 0, (void*)str); } +int32_t CryptoNative_SslSetClientSigalgs(SSL* ssl, const char* str) +{ + if (ssl == NULL || str == NULL) + return 0; + return (int32_t) SSL_ctrl(ssl, SSL_CTRL_SET_CLIENT_SIGALGS_LIST, 0, (void*)str); +} + int32_t CryptoNative_SslGetCurrentCipherId(SSL* ssl, int32_t* cipherId) { // No error queue impact. diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h index 6d34704196b158..997cf3b05b2dcd 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h +++ b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h @@ -525,7 +525,12 @@ PALEXPORT int32_t CryptoNative_SslSetTlsExtHostName(SSL* ssl, uint8_t* name); /* Shims the SSL_set1_sigalgs_list method. */ -PALEXPORT int32_t CryptoNative_SslSetSigalgs(SSL* ssl, uint8_t* str); +PALEXPORT int32_t CryptoNative_SslSetSigalgs(SSL* ssl, const char* str); + +/* +Shim for SSL_set_client_sigalgs +*/ +PALEXPORT int32_t CryptoNative_SslSetClientSigalgs(SSL* ssl, const char* str); /* Shims the SSL_get_current_cipher and SSL_CIPHER_get_id. From 5c7429ef568a05ca28d7d6ff65f235f47d5add33 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Wed, 4 Jun 2025 13:55:08 +0200 Subject: [PATCH 10/24] Minor changes --- .../Net/Security/SslStreamPal.Windows.cs | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs index 276da3c0f71fa4..f74c3364317144 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs @@ -446,57 +446,60 @@ public static unsafe SafeFreeCredentials AcquireCredentialsHandleSchCredentials( if (NetEventSource.Log.IsEnabled()) NetEventSource.Info($"flags=({flags}), ProtocolFlags=({protocolFlags}), EncryptionPolicy={policy}"); Interop.SspiCli.TLS_PARAMETERS tlsParameters = default; + credential.cTlsParameters = 1; + credential.pTlsParameters = &tlsParameters; + if (protocolFlags != 0) { - credential.cTlsParameters = 1; - credential.pTlsParameters = &tlsParameters; - - // If we were asked to do specific protocol we need to fill TLS_PARAMETERS. tlsParameters.grbitDisabledProtocols = (uint)protocolFlags ^ uint.MaxValue; } Span cryptoSettings = stackalloc Interop.SspiCli.CRYPTO_SETTINGS[2]; - Span algIdPtrs = stackalloc IntPtr[2]; + + // init to null ptrs to prevent freeing uninitialized memory in finally block + Span algIdPtrs = stackalloc IntPtr[2] { IntPtr.Zero, IntPtr.Zero }; int cryptoSettingsCount = 0; try { - if (cryptoSettings.Length > 0) + if (!authOptions.AllowRsaPkcs1Padding) { - if (!authOptions.AllowRsaPkcs1Padding) - { - algIdPtrs[cryptoSettingsCount] = Marshal.StringToHGlobalUni("SCH_RSA_PKCS_PAD"); + algIdPtrs[cryptoSettingsCount] = Marshal.StringToHGlobalUni("SCH_RSA_PKCS_PAD"); - cryptoSettings[cryptoSettingsCount] = default; - cryptoSettings[cryptoSettingsCount].eAlgorithmUsage = Interop.SspiCli.CRYPTO_SETTINGS.TlsAlgorithmUsage.TlsParametersCngAlgUsageCertSig; - Interop.NtDll.RtlInitUnicodeString(out cryptoSettings[cryptoSettingsCount].strCngAlgId, algIdPtrs[cryptoSettingsCount]); - cryptoSettingsCount++; - } - - if (!authOptions.AllowRsaPssPadding) + cryptoSettings[cryptoSettingsCount] = new() { - algIdPtrs[cryptoSettingsCount] = Marshal.StringToHGlobalUni("SCH_RSA_PSS_PAD"); + eAlgorithmUsage = Interop.SspiCli.CRYPTO_SETTINGS.TlsAlgorithmUsage.TlsParametersCngAlgUsageCertSig + }; - cryptoSettings[cryptoSettingsCount] = default; - cryptoSettings[cryptoSettingsCount].eAlgorithmUsage = Interop.SspiCli.CRYPTO_SETTINGS.TlsAlgorithmUsage.TlsParametersCngAlgUsageCertSig; - Interop.NtDll.RtlInitUnicodeString(out cryptoSettings[cryptoSettingsCount].strCngAlgId, algIdPtrs[cryptoSettingsCount]); - cryptoSettingsCount++; - } + Interop.NtDll.RtlInitUnicodeString(out cryptoSettings[cryptoSettingsCount].strCngAlgId, algIdPtrs[cryptoSettingsCount]); + cryptoSettingsCount++; + } - tlsParameters.pDisabledCrypto = (Interop.SspiCli.CRYPTO_SETTINGS*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(cryptoSettings)); - tlsParameters.cDisabledCrypto = cryptoSettingsCount; + if (!authOptions.AllowRsaPssPadding) + { + algIdPtrs[cryptoSettingsCount] = Marshal.StringToHGlobalUni("SCH_RSA_PSS_PAD"); - credential.cTlsParameters = 1; - credential.pTlsParameters = &tlsParameters; + cryptoSettings[cryptoSettingsCount] = new() + { + eAlgorithmUsage = Interop.SspiCli.CRYPTO_SETTINGS.TlsAlgorithmUsage.TlsParametersCngAlgUsageCertSig + }; + Interop.NtDll.RtlInitUnicodeString(out cryptoSettings[cryptoSettingsCount].strCngAlgId, algIdPtrs[cryptoSettingsCount]); + cryptoSettingsCount++; } + tlsParameters.pDisabledCrypto = &MemoryMarshal.GetReference(cryptoSettings); + tlsParameters.cDisabledCrypto = cryptoSettingsCount; + return AcquireCredentialsHandle(direction, &credential); } finally { foreach (IntPtr algIdPtr in algIdPtrs.Slice(0, cryptoSettingsCount)) { - Marshal.FreeHGlobal(algIdPtr); + if (algIdPtr != IntPtr.Zero) + { + Marshal.FreeHGlobal(algIdPtr); + } } } } From 37cb11ebcb045984b2af70ea211b12707eccdee9 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Wed, 4 Jun 2025 15:20:05 +0200 Subject: [PATCH 11/24] Fix build --- .../src/System/Net/Security/SslStreamPal.Windows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs index f74c3364317144..61bc2fd2e71c04 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs @@ -487,7 +487,7 @@ public static unsafe SafeFreeCredentials AcquireCredentialsHandleSchCredentials( cryptoSettingsCount++; } - tlsParameters.pDisabledCrypto = &MemoryMarshal.GetReference(cryptoSettings); + tlsParameters.pDisabledCrypto = (Interop.SspiCli.CRYPTO_SETTINGS*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(cryptoSettings)); tlsParameters.cDisabledCrypto = cryptoSettingsCount; return AcquireCredentialsHandle(direction, &credential); From 8a3ec9cb30141484d531270404b832973a7406ee Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Wed, 4 Jun 2025 16:58:41 +0200 Subject: [PATCH 12/24] Add unit test --- .../SslStreamNetworkStreamTest.cs | 67 ++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs index 7852a4c671f427..dd7f1096180489 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs @@ -938,7 +938,7 @@ public async Task SslStream_ClientCertificateContext_SendsChain(bool useTrust) TargetHost = "localhost", }; clientOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; - clientOptions.ClientCertificateContext = SslStreamCertificateContext.Create(clientCertificate, useTrust ? null : clientChain, offline:true, trust); + clientOptions.ClientCertificateContext = SslStreamCertificateContext.Create(clientCertificate, useTrust ? null : clientChain, offline: true, trust); await SslStream_ClientSendsChain_Core(clientOptions, clientChain); @@ -1137,6 +1137,71 @@ public async Task SslStream_UnifiedHello_Ok(bool useOptionCallback) await Assert.ThrowsAnyAsync(() => serverTask); } + [Theory] + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + public async Task DisableUnusedRsaPadding_Connects(bool clientDisable, bool serverDisable) + { + (Stream client, Stream server) = TestHelper.GetConnectedTcpStreams(); + + using SslStream clientSslStream = new SslStream(client); + using SslStream serverSslStream = new SslStream(server); + + using X509Certificate2 serverCertificate = Configuration.Certificates.GetServerCertificate(); + using X509Certificate2 clientCertificate = Configuration.Certificates.GetClientCertificate(); + + // the test certificates use PSS padding, so we disable PKCS1 padding + Task t1 = clientSslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions() + { + ClientCertificates = new X509CertificateCollection(new X509Certificate2[] { clientCertificate }), + RemoteCertificateValidationCallback = delegate { return true; }, + AllowRsaPkcs1Padding = !clientDisable + }, CancellationToken.None); + Task t2 = serverSslStream.AuthenticateAsServerAsync(new SslServerAuthenticationOptions() + { + ServerCertificate = serverCertificate, + ClientCertificateRequired = true, + AllowRsaPkcs1Padding = !serverDisable + }, CancellationToken.None); + + await t1.WaitAsync(TestConfiguration.PassingTestTimeout); + await t2.WaitAsync(TestConfiguration.PassingTestTimeout); + } + + [Theory] + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + public async Task DisableUsedRsaPadding_Throws(bool clientDisable, bool serverDisable) + { + (Stream client, Stream server) = TestHelper.GetConnectedTcpStreams(); + + using SslStream clientSslStream = new SslStream(client); + using SslStream serverSslStream = new SslStream(server); + + using X509Certificate2 serverCertificate = Configuration.Certificates.GetServerCertificate(); + using X509Certificate2 clientCertificate = Configuration.Certificates.GetClientCertificate(); + + // the test certificates use PSS padding + Task t1 = clientSslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions() + { + ClientCertificates = new X509CertificateCollection(new X509Certificate2[] { clientCertificate }), + RemoteCertificateValidationCallback = delegate { return true; }, + AllowRsaPssPadding = !clientDisable + }, CancellationToken.None); + Task t2 = serverSslStream.AuthenticateAsServerAsync(new SslServerAuthenticationOptions() + { + ServerCertificate = serverCertificate, + ClientCertificateRequired = true, + AllowRsaPssPadding = !serverDisable + }, CancellationToken.None); + + await Assert.ThrowsAsync(() => t1.WaitAsync(TestConfiguration.PassingTestTimeout)); + await Assert.ThrowsAsync(() => t2.WaitAsync(TestConfiguration.PassingTestTimeout)); + } + + private static bool ValidateServerCertificate( object sender, X509Certificate retrievedServerPublicCertificate, From 44639f588fa26632c0027f6061185c5ff9f91655 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Thu, 5 Jun 2025 13:16:54 +0200 Subject: [PATCH 13/24] Fix interaction with TLS session caching --- .../System/Net/Security/SslSessionsCache.cs | 47 ++++++++++++------- .../System/Net/Security/SslStream.Protocol.cs | 15 ++++-- .../SslStreamNetworkStreamTest.cs | 6 +++ 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslSessionsCache.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslSessionsCache.cs index 4c74bcb2af0005..d69e86b5501d1f 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslSessionsCache.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslSessionsCache.cs @@ -29,6 +29,8 @@ internal static class SslSessionsCache private readonly bool _sendTrustList; private readonly bool _checkRevocation; private readonly bool _allowTlsResume; + private readonly bool _allowRsaPssPadding; + private readonly bool _allowRsaPkcs1Padding; // // SECURITY: X509Certificate.GetCertHash() is virtual hence before going here, @@ -42,7 +44,9 @@ internal SslCredKey( EncryptionPolicy encryptionPolicy, bool sendTrustList, bool checkRevocation, - bool allowTlsResume) + bool allowTlsResume, + bool allowRsaPssPadding, + bool allowRsaPkcs1Padding) { _thumbPrint = thumbPrint ?? Array.Empty(); _allowedProtocols = allowedProtocols; @@ -51,23 +55,24 @@ internal SslCredKey( _checkRevocation = checkRevocation; _sendTrustList = sendTrustList; _allowTlsResume = allowTlsResume; + _allowRsaPssPadding = allowRsaPssPadding; + _allowRsaPkcs1Padding = allowRsaPkcs1Padding; } public override int GetHashCode() { - int hashCode = 0; - if (_thumbPrint.Length > 3) - { - hashCode ^= _thumbPrint[0] | (_thumbPrint[1] << 8) | (_thumbPrint[2] << 16) | (_thumbPrint[3] << 24); - } - - return HashCode.Combine(_allowedProtocols, - (int)_encryptionPolicy, - _isServerMode, - _sendTrustList, - _checkRevocation, - _allowedProtocols, - hashCode); + HashCode hash = default; + hash.AddBytes(_thumbPrint); + hash.Add(_allowedProtocols); + hash.Add((int)_encryptionPolicy); + hash.Add(_isServerMode); + hash.Add(_sendTrustList); + hash.Add(_checkRevocation); + hash.Add(_allowTlsResume); + hash.Add(_allowRsaPssPadding); + hash.Add(_allowRsaPkcs1Padding); + + return hash.ToHashCode(); } public override bool Equals([NotNullWhen(true)] object? obj) => @@ -86,6 +91,8 @@ public bool Equals(SslCredKey other) _sendTrustList == other._sendTrustList && _checkRevocation == other._checkRevocation && _allowTlsResume == other._allowTlsResume && + _allowRsaPssPadding == other._allowRsaPssPadding && + _allowRsaPkcs1Padding == other._allowRsaPkcs1Padding && thumbPrint.AsSpan().SequenceEqual(otherThumbPrint); } } @@ -103,7 +110,9 @@ public bool Equals(SslCredKey other) EncryptionPolicy encryptionPolicy, bool checkRevocation, bool allowTlsResume, - bool sendTrustList) + bool sendTrustList, + bool allowRsaPssPadding, + bool allowRsaPkcs1Padding) { if (s_cachedCreds.IsEmpty) { @@ -111,7 +120,7 @@ public bool Equals(SslCredKey other) return null; } - var key = new SslCredKey(thumbPrint, (int)sslProtocols, isServer, encryptionPolicy, sendTrustList, checkRevocation, allowTlsResume); + var key = new SslCredKey(thumbPrint, (int)sslProtocols, isServer, encryptionPolicy, sendTrustList, checkRevocation, allowTlsResume, allowRsaPssPadding, allowRsaPkcs1Padding); //SafeCredentialReference? cached; SafeFreeCredentials? credentials = GetCachedCredential(key); @@ -144,7 +153,9 @@ internal static void CacheCredential( EncryptionPolicy encryptionPolicy, bool checkRevocation, bool allowTlsResume, - bool sendTrustList) + bool sendTrustList, + bool allowRsaPssPadding, + bool allowRsaPkcs1Padding) { Debug.Assert(creds != null, "creds == null"); @@ -154,7 +165,7 @@ internal static void CacheCredential( return; } - SslCredKey key = new SslCredKey(thumbPrint, (int)sslProtocols, isServer, encryptionPolicy, sendTrustList, checkRevocation, allowTlsResume); + SslCredKey key = new SslCredKey(thumbPrint, (int)sslProtocols, isServer, encryptionPolicy, sendTrustList, checkRevocation, allowTlsResume, allowRsaPssPadding, allowRsaPkcs1Padding); SafeFreeCredentials? credentials = GetCachedCredential(key); diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs index 1e0a8ed0e2a756..4e9f4327ee9e22 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs @@ -604,7 +604,9 @@ private bool AcquireClientCredentials(ref byte[]? thumbPrint, bool newCredential _sslAuthenticationOptions.EncryptionPolicy, _sslAuthenticationOptions.CertificateRevocationCheckMode != X509RevocationMode.NoCheck, _sslAuthenticationOptions.AllowTlsResume, - sendTrustList: false); + sendTrustList: false, + _sslAuthenticationOptions.AllowRsaPssPadding, + _sslAuthenticationOptions.AllowRsaPkcs1Padding); // We can probably do some optimization here. If the selectedCert is returned by the delegate // we can always go ahead and use the certificate to create our credential @@ -742,15 +744,16 @@ private bool AcquireServerCredentials(ref byte[]? thumbPrint) // // Note selectedCert is a safe ref possibly cloned from the user passed Cert object // - byte[] guessedThumbPrint = selectedCert.GetCertHash(HashAlgorithmName.SHA512); - bool sendTrustedList = _sslAuthenticationOptions.CertificateContext!.Trust?._sendTrustInHandshake ?? false; + byte[] guessedThumbPrint = selectedCert.GetCertHash(HashAlgorithmName.SHA512); bool sendTrustedList = _sslAuthenticationOptions.CertificateContext!.Trust?._sendTrustInHandshake ?? false; SafeFreeCredentials? cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, _sslAuthenticationOptions.EnabledSslProtocols, _sslAuthenticationOptions.IsServer, _sslAuthenticationOptions.EncryptionPolicy, _sslAuthenticationOptions.CertificateRevocationCheckMode != X509RevocationMode.NoCheck, _sslAuthenticationOptions.AllowTlsResume, - sendTrustedList); + sendTrustedList, + _sslAuthenticationOptions.AllowRsaPssPadding, + _sslAuthenticationOptions.AllowRsaPkcs1Padding); if (cachedCredentialHandle != null) { _credentialsHandle = cachedCredentialHandle; @@ -952,7 +955,9 @@ private ProtocolToken GenerateToken(ReadOnlySpan inputBuffer, out int cons _sslAuthenticationOptions.EncryptionPolicy, _sslAuthenticationOptions.CertificateRevocationCheckMode != X509RevocationMode.NoCheck, _sslAuthenticationOptions.AllowTlsResume, - sendTrustList); + sendTrustList, + _sslAuthenticationOptions.AllowRsaPssPadding, + _sslAuthenticationOptions.AllowRsaPkcs1Padding); } } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs index dd7f1096180489..6bf63fd497c80a 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs @@ -1156,12 +1156,15 @@ public async Task DisableUnusedRsaPadding_Connects(bool clientDisable, bool serv { ClientCertificates = new X509CertificateCollection(new X509Certificate2[] { clientCertificate }), RemoteCertificateValidationCallback = delegate { return true; }, + CertificateRevocationCheckMode = X509RevocationMode.NoCheck, AllowRsaPkcs1Padding = !clientDisable }, CancellationToken.None); Task t2 = serverSslStream.AuthenticateAsServerAsync(new SslServerAuthenticationOptions() { ServerCertificate = serverCertificate, + RemoteCertificateValidationCallback = delegate { return true; }, ClientCertificateRequired = true, + CertificateRevocationCheckMode = X509RevocationMode.NoCheck, AllowRsaPkcs1Padding = !serverDisable }, CancellationToken.None); @@ -1188,12 +1191,15 @@ public async Task DisableUsedRsaPadding_Throws(bool clientDisable, bool serverDi { ClientCertificates = new X509CertificateCollection(new X509Certificate2[] { clientCertificate }), RemoteCertificateValidationCallback = delegate { return true; }, + CertificateRevocationCheckMode = X509RevocationMode.NoCheck, AllowRsaPssPadding = !clientDisable }, CancellationToken.None); Task t2 = serverSslStream.AuthenticateAsServerAsync(new SslServerAuthenticationOptions() { ServerCertificate = serverCertificate, + RemoteCertificateValidationCallback = delegate { return true; }, ClientCertificateRequired = true, + CertificateRevocationCheckMode = X509RevocationMode.NoCheck, AllowRsaPssPadding = !serverDisable }, CancellationToken.None); From e0a479be3f87480528898596c14ee77107282078 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Thu, 5 Jun 2025 15:07:53 +0200 Subject: [PATCH 14/24] Fix linux build --- src/native/libs/System.Security.Cryptography.Native/pal_ssl.c | 2 +- src/native/libs/System.Security.Cryptography.Native/pal_ssl.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c index c0745fa9c5dd1a..39d57210ae3d13 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c +++ b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c @@ -1123,7 +1123,7 @@ int32_t CryptoNative_SslSetSigalgs(SSL* ssl, uint8_t* str) return (int32_t) SSL_ctrl(ssl, SSL_CTRL_SET_SIGALGS_LIST, 0, (void*)str); } -int32_t CryptoNative_SslSetClientSigalgs(SSL* ssl, const char* str) +int32_t CryptoNative_SslSetClientSigalgs(SSL* ssl, uint8_t* str) { if (ssl == NULL || str == NULL) return 0; diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h index 997cf3b05b2dcd..66457e17710771 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h +++ b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.h @@ -525,12 +525,12 @@ PALEXPORT int32_t CryptoNative_SslSetTlsExtHostName(SSL* ssl, uint8_t* name); /* Shims the SSL_set1_sigalgs_list method. */ -PALEXPORT int32_t CryptoNative_SslSetSigalgs(SSL* ssl, const char* str); +PALEXPORT int32_t CryptoNative_SslSetSigalgs(SSL* ssl, uint8_t* str); /* Shim for SSL_set_client_sigalgs */ -PALEXPORT int32_t CryptoNative_SslSetClientSigalgs(SSL* ssl, const char* str); +PALEXPORT int32_t CryptoNative_SslSetClientSigalgs(SSL* ssl, uint8_t* str); /* Shims the SSL_get_current_cipher and SSL_CIPHER_get_id. From ae36015698aca3d6eae793626f0ad9b84275861a Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Thu, 5 Jun 2025 15:33:52 +0200 Subject: [PATCH 15/24] Fix linux filtering --- .../System.Security.Cryptography.Native/Interop.OpenSsl.cs | 3 ++- .../tests/FunctionalTests/SslStreamNetworkStreamTest.cs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index a70f0d3782502f..b39b6ddda77880 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -585,7 +585,8 @@ internal static unsafe void ConfigureSignatureAlgorithms(SafeSslHandle sslHandle foreach (string alg in s_defaultSigAlgs.Value) { - if (alg.StartsWith("rsa_pss_pss_") && !enablePss) + // includes both rsa_pss_pss_* and rsa_pss_rsae_* + if (alg.StartsWith("rsa_pss_") && !enablePss) { continue; } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs index 6bf63fd497c80a..e18253208e2448 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs @@ -1192,7 +1192,7 @@ public async Task DisableUsedRsaPadding_Throws(bool clientDisable, bool serverDi ClientCertificates = new X509CertificateCollection(new X509Certificate2[] { clientCertificate }), RemoteCertificateValidationCallback = delegate { return true; }, CertificateRevocationCheckMode = X509RevocationMode.NoCheck, - AllowRsaPssPadding = !clientDisable + AllowRsaPssPadding = !clientDisable, }, CancellationToken.None); Task t2 = serverSslStream.AuthenticateAsServerAsync(new SslServerAuthenticationOptions() { @@ -1200,7 +1200,7 @@ public async Task DisableUsedRsaPadding_Throws(bool clientDisable, bool serverDi RemoteCertificateValidationCallback = delegate { return true; }, ClientCertificateRequired = true, CertificateRevocationCheckMode = X509RevocationMode.NoCheck, - AllowRsaPssPadding = !serverDisable + AllowRsaPssPadding = !serverDisable, }, CancellationToken.None); await Assert.ThrowsAsync(() => t1.WaitAsync(TestConfiguration.PassingTestTimeout)); From 7f2036bcdd45e89496d47e95a4f55f09f1904d47 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Mon, 9 Jun 2025 14:40:01 +0200 Subject: [PATCH 16/24] Code review feedback --- .../Interop.OpenSsl.cs | 18 ++++++++++++------ .../Interop.Ssl.cs | 6 ++++-- .../pal_ssl.c | 2 ++ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index b39b6ddda77880..ba252bb8521bab 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -528,6 +528,8 @@ internal static string[] GetDefaultSignatureAlgorithms() { ushort[] rawAlgs = Interop.Ssl.GetDefaultSignatureAlgorithms(); + // The mapping below is taken from STRINT_PAIR signature_tls13_scheme_list and other + // data structures in OpenSSL source code (apps/lib/s_cb.c file). static string ConvertAlg(ushort rawAlg) => rawAlg switch { 0x0201 => "rsa_pkcs1_sha1", @@ -576,7 +578,7 @@ internal static string[] GetDefaultSignatureAlgorithms() return Array.ConvertAll(rawAlgs, ConvertAlg); } - internal static unsafe void ConfigureSignatureAlgorithms(SafeSslHandle sslHandle, bool enablePss, bool enablePkcs) + internal static unsafe void ConfigureSignatureAlgorithms(SafeSslHandle sslHandle, bool enablePss, bool enablePkcs1) { byte[] buffer = ArrayPool.Shared.Rent(512); try @@ -586,17 +588,18 @@ internal static unsafe void ConfigureSignatureAlgorithms(SafeSslHandle sslHandle foreach (string alg in s_defaultSigAlgs.Value) { // includes both rsa_pss_pss_* and rsa_pss_rsae_* - if (alg.StartsWith("rsa_pss_") && !enablePss) + if (alg.StartsWith("rsa_pss_", StringComparison.Ordinal) && !enablePss) { continue; } - if (alg.StartsWith("rsa_pkcs1_") && !enablePkcs) + if (alg.StartsWith("rsa_pkcs1_", StringComparison.Ordinal) && !enablePkcs1) { continue; } - EnsureSize(ref buffer, index + alg.Length + 1); + // Ensure we have enough space for the algorithm name, separator and null terminator. + EnsureSize(ref buffer, index + alg.Length + 2); if (index > 0) { @@ -632,9 +635,12 @@ static void EnsureSize(ref byte[] buffer, int size) { if (buffer.Length < size) { - byte[] oldBuffer = buffer; - Array.Resize(ref buffer, buffer.Length * 2); + // there are a few dozen algorithms total in existence, so we don't expect the buffer to grow too large. + Debug.Assert(size < 10 * 1024, "The buffer should not grow too large."); + byte[] oldBuffer = buffer; + buffer = ArrayPool.Shared.Rent(buffer.Length * 2); + oldBuffer.AsSpan().CopyTo(buffer); ArrayPool.Shared.Return(oldBuffer); } } diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index f448b011748a69..def7544bb1791a 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -84,13 +84,15 @@ internal static unsafe ReadOnlySpan SslGetAlpnSelected(SafeSslHandle ssl) internal static partial int SslRead(SafeSslHandle ssl, ref byte buf, int num, out SslErrorCode error); [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetDefaultSignatureAlgorithms")] - private static unsafe partial void GetDefaultSignatureAlgorithms(Span algorithms, ref int algorithmCount); + private static unsafe partial int GetDefaultSignatureAlgorithms(Span algorithms, ref int algorithmCount); internal static ushort[] GetDefaultSignatureAlgorithms() { + // 256 algorithms should be more than enough for any use case. Span algorithms = stackalloc ushort[256]; int algorithmCount = algorithms.Length; - GetDefaultSignatureAlgorithms(algorithms, ref algorithmCount); + int res = GetDefaultSignatureAlgorithms(algorithms, ref algorithmCount); + Debug.Assert(res == 0, "Expected GetDefaultSignatureAlgorithms to return 0 on success"); return algorithms.Slice(0, algorithmCount).ToArray(); } diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c index 39d57210ae3d13..49d4e5aead38ec 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c +++ b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c @@ -1246,6 +1246,8 @@ int32_t CryptoNative_GetDefaultSignatureAlgorithms(uint16_t* buffer, int32_t* co { if (i >= *count) { + // this should not happen, but just in case + ret = -1; break; } From 9a2353df984b403249995d8dd6a48a48ed6fa87d Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Mon, 9 Jun 2025 14:49:35 +0200 Subject: [PATCH 17/24] Reuse string resource --- .../System.Security.Cryptography.Native/Interop.OpenSsl.cs | 4 ++-- .../System.Security.Cryptography.Native/Interop.Ssl.cs | 7 ++++++- .../System.Net.Security/src/Resources/Strings.resx | 6 ++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index ba252bb8521bab..f7c8b725df9c1c 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -616,13 +616,13 @@ internal static unsafe void ConfigureSignatureAlgorithms(SafeSslHandle sslHandle ret = Interop.Ssl.SslSetSigalgs(sslHandle, pBuffer); if (ret != 1) { - throw new InvalidOperationException("Failed to set signature algorithms."); + throw CreateSslException(SR.Format(SR.net_ssl_set_sigalgs_failed, "server")); } ret = Interop.Ssl.SslSetClientSigalgs(sslHandle, pBuffer); if (ret != 1) { - throw new InvalidOperationException("Failed to set client signature algorithms."); + throw CreateSslException(SR.Format(SR.net_ssl_set_sigalgs_failed, "client")); } } } diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index def7544bb1791a..cdac694697f017 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -92,7 +92,12 @@ internal static ushort[] GetDefaultSignatureAlgorithms() Span algorithms = stackalloc ushort[256]; int algorithmCount = algorithms.Length; int res = GetDefaultSignatureAlgorithms(algorithms, ref algorithmCount); - Debug.Assert(res == 0, "Expected GetDefaultSignatureAlgorithms to return 0 on success"); + + if (res != 0 || algorithmCount > algorithms.Length) + { + throw Interop.OpenSsl.CreateSslException(SR.net_ssl_get_default_sigalgs_failed); + } + return algorithms.Slice(0, algorithmCount).ToArray(); } diff --git a/src/libraries/System.Net.Security/src/Resources/Strings.resx b/src/libraries/System.Net.Security/src/Resources/Strings.resx index cf00f35a9a0044..fd076c4a02029b 100644 --- a/src/libraries/System.Net.Security/src/Resources/Strings.resx +++ b/src/libraries/System.Net.Security/src/Resources/Strings.resx @@ -314,6 +314,12 @@ Failed to allocate SSL/TLS context, OpenSSL error - {0}. + + Failed to get default signature algorithms. + + + Failed to set {0} signature algorithms. + Operation failed with error - {0}. From 92542658c34247bbb2f2c66cc9c87185fc12d863 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Tue, 10 Jun 2025 11:37:11 +0200 Subject: [PATCH 18/24] recognize MLDSA sigalgs --- .../Interop.OpenSsl.cs | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index f7c8b725df9c1c..ca8d53c618407f 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -551,10 +551,17 @@ internal static string[] GetDefaultSignatureAlgorithms() 0x081a => "ecdsa_brainpoolP256r1_sha256", 0x081b => "ecdsa_brainpoolP384r1_sha384", 0x081c => "ecdsa_brainpoolP512r1_sha512", - _ => $"{Tls12SignatureName((byte)rawAlg)}+{Tls12HashName((byte)(rawAlg >> 8))}" + 0x0904 => "mldsa44", + 0x0905 => "mldsa65", + 0x0906 => "mldsa87", + _ => + Tls12HashName((byte)(rawAlg >> 8)) is string hashName && + Tls12SignatureName((byte)rawAlg) is string sigName + ? $"{sigName}+{hashName}" + : $"0x{rawAlg:x4}" // this will cause the setter to fail, but at least we get a string representation in the log. }; - static string Tls12HashName(byte raw) => raw switch + static string? Tls12HashName(byte raw) => raw switch { 0x00 => "none", 0x01 => "MD5", @@ -563,19 +570,25 @@ internal static string[] GetDefaultSignatureAlgorithms() 0x04 => "SHA256", 0x05 => "SHA384", 0x06 => "SHA512", - _ => $"unknown(0x{raw:x2})" + _ => null }; - static string Tls12SignatureName(byte raw) => raw switch + static string? Tls12SignatureName(byte raw) => raw switch { 0x00 => "anonymous", 0x01 => "RSA", 0x02 => "DSA", 0x03 => "ECDSA", - _ => $"unknown(0x{raw:x2})" + _ => null }; - return Array.ConvertAll(rawAlgs, ConvertAlg); + string[] result = Array.ConvertAll(rawAlgs, ConvertAlg); + if (NetEventSource.Log.IsEnabled()) + { + NetEventSource.Info(null, $"Default signature algorithms: {string.Join(":", result)}"); + } + + return result; } internal static unsafe void ConfigureSignatureAlgorithms(SafeSslHandle sslHandle, bool enablePss, bool enablePkcs1) From 949917c21f3e1e459f18d6526267f4b0c6ffec91 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Wed, 11 Jun 2025 09:24:42 +0200 Subject: [PATCH 19/24] Scope tests to Windows and OSX --- .../tests/FunctionalTests/SslStreamNetworkStreamTest.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs index e18253208e2448..df9d1311e5a881 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs @@ -1141,6 +1141,7 @@ public async Task SslStream_UnifiedHello_Ok(bool useOptionCallback) [InlineData(true, true)] [InlineData(true, false)] [InlineData(false, true)] + [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.Linux)] public async Task DisableUnusedRsaPadding_Connects(bool clientDisable, bool serverDisable) { (Stream client, Stream server) = TestHelper.GetConnectedTcpStreams(); @@ -1176,6 +1177,7 @@ public async Task DisableUnusedRsaPadding_Connects(bool clientDisable, bool serv [InlineData(true, true)] [InlineData(true, false)] [InlineData(false, true)] + [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.Linux)] public async Task DisableUsedRsaPadding_Throws(bool clientDisable, bool serverDisable) { (Stream client, Stream server) = TestHelper.GetConnectedTcpStreams(); From c812e57ed1c6b548a2757f6f71d07ce9cb232500 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Thu, 12 Jun 2025 14:30:48 +0200 Subject: [PATCH 20/24] Throw PNSE on unsupported platforms, add supported os annotation --- .../ref/System.Net.Security.cs | 44 +++++++++---------- .../src/Resources/Strings.resx | 3 ++ .../Net/Security/SslAuthenticationOptions.cs | 19 ++++++++ .../SslClientAuthenticationOptions.cs | 28 +++++++++++- .../SslServerAuthenticationOptions.cs | 28 +++++++++++- .../SslStreamNetworkStreamTest.cs | 33 ++++++++++++++ 6 files changed, 129 insertions(+), 26 deletions(-) diff --git a/src/libraries/System.Net.Security/ref/System.Net.Security.cs b/src/libraries/System.Net.Security/ref/System.Net.Security.cs index b4334245666705..08aaf8df3ed2cc 100644 --- a/src/libraries/System.Net.Security/ref/System.Net.Security.cs +++ b/src/libraries/System.Net.Security/ref/System.Net.Security.cs @@ -31,9 +31,9 @@ public CipherSuitesPolicy(System.Collections.Generic.IEnumerable? ApplicationProtocols { get { throw null; } set { } } public System.Security.Cryptography.X509Certificates.X509ChainPolicy? CertificateChainPolicy { get { throw null; } set { } } @@ -228,8 +228,8 @@ public partial class SslServerAuthenticationOptions { public SslServerAuthenticationOptions() { } public bool AllowRenegotiation { get { throw null; } set { } } - public bool AllowRsaPssPadding { get { throw null; } set { } } - public bool AllowRsaPkcs1Padding { get { throw null; } set { } } + public bool AllowRsaPkcs1Padding { get { throw null; } [System.Runtime.Versioning.SupportedOSPlatformAttribute("linux"), System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] set { } } + public bool AllowRsaPssPadding { get { throw null; } [System.Runtime.Versioning.SupportedOSPlatformAttribute("linux"), System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] set { } } public bool AllowTlsResume { get { throw null; } set { } } public System.Collections.Generic.List? ApplicationProtocols { get { throw null; } set { } } public System.Security.Cryptography.X509Certificates.X509ChainPolicy? CertificateChainPolicy { get { throw null; } set { } } @@ -245,32 +245,32 @@ public SslServerAuthenticationOptions() { } } public partial class SslStream : System.Net.Security.AuthenticatedStream { - public SslStream(System.IO.Stream innerStream) : base(default(System.IO.Stream), default(bool)) { } - public SslStream(System.IO.Stream innerStream, bool leaveInnerStreamOpen) : base(default(System.IO.Stream), default(bool)) { } - public SslStream(System.IO.Stream innerStream, bool leaveInnerStreamOpen, System.Net.Security.RemoteCertificateValidationCallback? userCertificateValidationCallback) : base(default(System.IO.Stream), default(bool)) { } - public SslStream(System.IO.Stream innerStream, bool leaveInnerStreamOpen, System.Net.Security.RemoteCertificateValidationCallback? userCertificateValidationCallback, System.Net.Security.LocalCertificateSelectionCallback? userCertificateSelectionCallback) : base(default(System.IO.Stream), default(bool)) { } - public SslStream(System.IO.Stream innerStream, bool leaveInnerStreamOpen, System.Net.Security.RemoteCertificateValidationCallback? userCertificateValidationCallback, System.Net.Security.LocalCertificateSelectionCallback? userCertificateSelectionCallback, System.Net.Security.EncryptionPolicy encryptionPolicy) : base(default(System.IO.Stream), default(bool)) { } + public SslStream(System.IO.Stream innerStream) : base (default(System.IO.Stream), default(bool)) { } + public SslStream(System.IO.Stream innerStream, bool leaveInnerStreamOpen) : base (default(System.IO.Stream), default(bool)) { } + public SslStream(System.IO.Stream innerStream, bool leaveInnerStreamOpen, System.Net.Security.RemoteCertificateValidationCallback? userCertificateValidationCallback) : base (default(System.IO.Stream), default(bool)) { } + public SslStream(System.IO.Stream innerStream, bool leaveInnerStreamOpen, System.Net.Security.RemoteCertificateValidationCallback? userCertificateValidationCallback, System.Net.Security.LocalCertificateSelectionCallback? userCertificateSelectionCallback) : base (default(System.IO.Stream), default(bool)) { } + public SslStream(System.IO.Stream innerStream, bool leaveInnerStreamOpen, System.Net.Security.RemoteCertificateValidationCallback? userCertificateValidationCallback, System.Net.Security.LocalCertificateSelectionCallback? userCertificateSelectionCallback, System.Net.Security.EncryptionPolicy encryptionPolicy) : base (default(System.IO.Stream), default(bool)) { } public override bool CanRead { get { throw null; } } public override bool CanSeek { get { throw null; } } public override bool CanTimeout { get { throw null; } } public override bool CanWrite { get { throw null; } } public virtual bool CheckCertRevocationStatus { get { throw null; } } - [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId="SYSLIB0058", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] public virtual System.Security.Authentication.CipherAlgorithmType CipherAlgorithm { get { throw null; } } - [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId="SYSLIB0058", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] public virtual int CipherStrength { get { throw null; } } - [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId="SYSLIB0058", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] public virtual System.Security.Authentication.HashAlgorithmType HashAlgorithm { get { throw null; } } - [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId="SYSLIB0058", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] public virtual int HashStrength { get { throw null; } } public override bool IsAuthenticated { get { throw null; } } public override bool IsEncrypted { get { throw null; } } public override bool IsMutuallyAuthenticated { get { throw null; } } public override bool IsServer { get { throw null; } } public override bool IsSigned { get { throw null; } } - [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId="SYSLIB0058", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] public virtual System.Security.Authentication.ExchangeAlgorithmType KeyExchangeAlgorithm { get { throw null; } } - [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId = "SYSLIB0058", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties of SslStream are obsolete. Use NegotiatedCipherSuite instead.", DiagnosticId="SYSLIB0058", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] public virtual int KeyExchangeStrength { get { throw null; } } public override long Length { get { throw null; } } public virtual System.Security.Cryptography.X509Certificates.X509Certificate? LocalCertificate { get { throw null; } } @@ -694,7 +694,7 @@ public partial class AuthenticationException : System.SystemException { public AuthenticationException() { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - [System.ObsoleteAttribute("This API supports obsolete formatter-based serialization. It should not be called or extended by application code.", DiagnosticId = "SYSLIB0051", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("This API supports obsolete formatter-based serialization. It should not be called or extended by application code.", DiagnosticId="SYSLIB0051", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] protected AuthenticationException(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } public AuthenticationException(string? message) { } public AuthenticationException(string? message, System.Exception? innerException) { } @@ -703,7 +703,7 @@ public partial class InvalidCredentialException : System.Security.Authentication { public InvalidCredentialException() { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - [System.ObsoleteAttribute("This API supports obsolete formatter-based serialization. It should not be called or extended by application code.", DiagnosticId = "SYSLIB0051", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("This API supports obsolete formatter-based serialization. It should not be called or extended by application code.", DiagnosticId="SYSLIB0051", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] protected InvalidCredentialException(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } public InvalidCredentialException(string? message) { } public InvalidCredentialException(string? message, System.Exception? innerException) { } @@ -714,7 +714,7 @@ namespace System.Security.Authentication.ExtendedProtection public partial class ExtendedProtectionPolicy : System.Runtime.Serialization.ISerializable { [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - [System.ObsoleteAttribute("This API supports obsolete formatter-based serialization. It should not be called or extended by application code.", DiagnosticId = "SYSLIB0051", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("This API supports obsolete formatter-based serialization. It should not be called or extended by application code.", DiagnosticId="SYSLIB0051", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] protected ExtendedProtectionPolicy(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } public ExtendedProtectionPolicy(System.Security.Authentication.ExtendedProtection.PolicyEnforcement policyEnforcement) { } public ExtendedProtectionPolicy(System.Security.Authentication.ExtendedProtection.PolicyEnforcement policyEnforcement, System.Security.Authentication.ExtendedProtection.ChannelBinding customChannelBinding) { } diff --git a/src/libraries/System.Net.Security/src/Resources/Strings.resx b/src/libraries/System.Net.Security/src/Resources/Strings.resx index fd076c4a02029b..5b842ae977aae3 100644 --- a/src/libraries/System.Net.Security/src/Resources/Strings.resx +++ b/src/libraries/System.Net.Security/src/Resources/Strings.resx @@ -416,6 +416,9 @@ CipherSuitesPolicy is not supported on this platform. + + Disabling AllowRsaRssPadding or AllowRsaPkcs1Padding is not supported on this platform. + System.Net.Security is not supported on this platform. diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs index aed2a539cb0f4d..4c6d87735c8e24 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs @@ -51,9 +51,18 @@ internal void UpdateOptions(SslClientAuthenticationOptions sslClientAuthenticati RemoteCertRequired = true; CertificateContext = sslClientAuthenticationOptions.ClientCertificateContext; TargetHost = sslClientAuthenticationOptions.TargetHost ?? string.Empty; + AllowRsaPssPadding = sslClientAuthenticationOptions.AllowRsaPssPadding; AllowRsaPkcs1Padding = sslClientAuthenticationOptions.AllowRsaPkcs1Padding; + if (!OperatingSystem.IsWindows() && !OperatingSystem.IsLinux()) + { + if (!sslClientAuthenticationOptions.AllowRsaPssPadding || !sslClientAuthenticationOptions.AllowRsaPkcs1Padding) + { + throw new PlatformNotSupportedException(SR.net_ssl_allow_rsa_padding_not_supported); + } + } + // Client specific options. CertificateRevocationCheckMode = sslClientAuthenticationOptions.CertificateRevocationCheckMode; ClientCertificates = sslClientAuthenticationOptions.ClientCertificates; @@ -112,8 +121,18 @@ internal void UpdateOptions(SslServerAuthenticationOptions sslServerAuthenticati RemoteCertRequired = sslServerAuthenticationOptions.ClientCertificateRequired; CipherSuitesPolicy = sslServerAuthenticationOptions.CipherSuitesPolicy; CertificateRevocationCheckMode = sslServerAuthenticationOptions.CertificateRevocationCheckMode; + AllowRsaPssPadding = sslServerAuthenticationOptions.AllowRsaPssPadding; AllowRsaPkcs1Padding = sslServerAuthenticationOptions.AllowRsaPkcs1Padding; + + if (!OperatingSystem.IsWindows() && !OperatingSystem.IsLinux()) + { + if (!sslServerAuthenticationOptions.AllowRsaPssPadding || !sslServerAuthenticationOptions.AllowRsaPkcs1Padding) + { + throw new PlatformNotSupportedException(SR.net_ssl_allow_rsa_padding_not_supported); + } + } + if (sslServerAuthenticationOptions.ServerCertificateContext != null) { CertificateContext = sslServerAuthenticationOptions.ServerCertificateContext; diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs index bf8a612c5f1ea2..9f159207f93351 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.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.Runtime.Versioning; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Security.Authentication; @@ -97,7 +98,30 @@ public SslProtocols EnabledSslProtocols /// public X509ChainPolicy? CertificateChainPolicy { get; set; } - public bool AllowRsaPssPadding { get; set; } = true; - public bool AllowRsaPkcs1Padding { get; set; } = true; + private bool _allowRsaPssPadding = true; + /// + /// Gets or sets a value that indicates whether the the rsa_pss_* family of TLS signature algorithms is enabled for use in the TLS handshake. + /// + public bool AllowRsaPssPadding + { + get => _allowRsaPssPadding; + + [SupportedOSPlatform("windows")] + [SupportedOSPlatform("linux")] + set { _allowRsaPssPadding = value; } + } + + private bool _allowRsaPkcs1Padding = true; + /// + /// Gets or sets a value that indicates whether the the rsa_pkcs1_* family of TLS signature algorithms is enabled for use in the TLS handshake. + /// + public bool AllowRsaPkcs1Padding + { + get => _allowRsaPkcs1Padding; + + [SupportedOSPlatform("windows")] + [SupportedOSPlatform("linux")] + set { _allowRsaPkcs1Padding = value; } + } } } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs index 218c0057cbf7a1..6ca64677652d50 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.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.Runtime.Versioning; using System.Collections.Generic; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; @@ -93,7 +94,30 @@ public EncryptionPolicy EncryptionPolicy /// public X509ChainPolicy? CertificateChainPolicy { get; set; } - public bool AllowRsaPssPadding { get; set; } = true; - public bool AllowRsaPkcs1Padding { get; set; } = true; + private bool _allowRsaPssPadding = true; + /// + /// Gets or sets a value that indicates whether the the rsa_pss_* family of TLS signature algorithms is enabled for use in the TLS handshake. + /// + public bool AllowRsaPssPadding + { + get => _allowRsaPssPadding; + + [SupportedOSPlatform("windows")] + [SupportedOSPlatform("linux")] + set { _allowRsaPssPadding = value; } + } + + private bool _allowRsaPkcs1Padding = true; + /// + /// Gets or sets a value that indicates whether the the rsa_pkcs1_* family of TLS signature algorithms is enabled for use in the TLS handshake. + /// + public bool AllowRsaPkcs1Padding + { + get => _allowRsaPkcs1Padding; + + [SupportedOSPlatform("windows")] + [SupportedOSPlatform("linux")] + set { _allowRsaPkcs1Padding = value; } + } } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs index df9d1311e5a881..6aed75e927725d 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs @@ -1209,6 +1209,39 @@ public async Task DisableUsedRsaPadding_Throws(bool clientDisable, bool serverDi await Assert.ThrowsAsync(() => t2.WaitAsync(TestConfiguration.PassingTestTimeout)); } + [Theory] + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [PlatformSpecific(~(TestPlatforms.Windows | TestPlatforms.Linux))] + public void DisallowPkcsOrPss_UnsupportedPlatforms_Throws(bool disablePkcs1Padding, bool disablePssPadding) + { + using X509Certificate2 serverCertificate = Configuration.Certificates.GetServerCertificate(); + (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); + using SslStream client = new SslStream(stream1); + using SslStream server = new SslStream(stream2); + + Assert.Throws(() => + { + server.AuthenticateAsServer(new SslServerAuthenticationOptions() + { + ServerCertificate = serverCertificate, + RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true, + AllowRsaPkcs1Padding = !disablePkcs1Padding, + AllowRsaPssPadding = !disablePssPadding + }); + }); + + Assert.Throws(() => + { + client.AuthenticateAsServer(new SslClientAuthenticationOptions() + { + RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true, + AllowRsaPkcs1Padding = !disablePkcs1Padding, + AllowRsaPssPadding = !disablePssPadding + }); + }); + } private static bool ValidateServerCertificate( object sender, From 34be5474b5304075cdd19fa408a1ce5469067d05 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Thu, 12 Jun 2025 14:32:59 +0200 Subject: [PATCH 21/24] Disable tests on Windows Nano --- .../FunctionalTests/SslStreamNetworkStreamTest.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs index 6aed75e927725d..8fe82632a06fc0 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs @@ -1144,6 +1144,11 @@ public async Task SslStream_UnifiedHello_Ok(bool useOptionCallback) [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.Linux)] public async Task DisableUnusedRsaPadding_Connects(bool clientDisable, bool serverDisable) { + if (PlatformDetection.IsWindowsNanoServer) + { + throw new SkipTestException("Windows Nano Server does not support sigalg disabling."); + } + (Stream client, Stream server) = TestHelper.GetConnectedTcpStreams(); using SslStream clientSslStream = new SslStream(client); @@ -1180,6 +1185,11 @@ public async Task DisableUnusedRsaPadding_Connects(bool clientDisable, bool serv [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.Linux)] public async Task DisableUsedRsaPadding_Throws(bool clientDisable, bool serverDisable) { + if (PlatformDetection.IsWindowsNanoServer) + { + throw new SkipTestException("Windows Nano Server does not support sigalg disabling."); + } + (Stream client, Stream server) = TestHelper.GetConnectedTcpStreams(); using SslStream clientSslStream = new SslStream(client); From ea9cd46aad1c4d0c657cd80e6931bc737505a6dd Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Thu, 12 Jun 2025 14:35:28 +0200 Subject: [PATCH 22/24] Fix typo --- .../tests/FunctionalTests/SslStreamNetworkStreamTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs index 8fe82632a06fc0..bbe6f8edbfdd26 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs @@ -1244,7 +1244,7 @@ public void DisallowPkcsOrPss_UnsupportedPlatforms_Throws(bool disablePkcs1Paddi Assert.Throws(() => { - client.AuthenticateAsServer(new SslClientAuthenticationOptions() + client.AuthenticateAsClient(new SslClientAuthenticationOptions() { RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true, AllowRsaPkcs1Padding = !disablePkcs1Padding, From ad3f71539e9ca50cebda0713fe4b570c228a5f80 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Thu, 12 Jun 2025 16:07:56 +0200 Subject: [PATCH 23/24] Fix build --- .../Net/Security/SslClientAuthenticationOptionsExtensions.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs b/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs index e7ee8b22d15e10..a8a599d6d3d84d 100644 --- a/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs +++ b/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs @@ -30,8 +30,10 @@ public static SslClientAuthenticationOptions ShallowClone(this SslClientAuthenti LocalCertificateSelectionCallback = options.LocalCertificateSelectionCallback, RemoteCertificateValidationCallback = options.RemoteCertificateValidationCallback, TargetHost = options.TargetHost, +#pragma warning disable CA1416 // Ignore SupportedOSPlatform checks, the value will be validated at runtime inside SslStream AllowRsaPssPadding = options.AllowRsaPssPadding, AllowRsaPkcs1Padding = options.AllowRsaPkcs1Padding +#pragma warning restore CA1416 }; #if DEBUG From 30dc87eb5995197caa0f72826e1e34b78a0f4822 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Fri, 13 Jun 2025 08:50:08 +0200 Subject: [PATCH 24/24] fixup! Disable tests on Windows Nano --- .../FunctionalTests/SslStreamNetworkStreamTest.cs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs index bbe6f8edbfdd26..d5486ef526aa1a 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamNetworkStreamTest.cs @@ -1137,18 +1137,13 @@ public async Task SslStream_UnifiedHello_Ok(bool useOptionCallback) await Assert.ThrowsAnyAsync(() => serverTask); } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.SupportsTls13))] [InlineData(true, true)] [InlineData(true, false)] [InlineData(false, true)] [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.Linux)] public async Task DisableUnusedRsaPadding_Connects(bool clientDisable, bool serverDisable) { - if (PlatformDetection.IsWindowsNanoServer) - { - throw new SkipTestException("Windows Nano Server does not support sigalg disabling."); - } - (Stream client, Stream server) = TestHelper.GetConnectedTcpStreams(); using SslStream clientSslStream = new SslStream(client); @@ -1178,18 +1173,13 @@ public async Task DisableUnusedRsaPadding_Connects(bool clientDisable, bool serv await t2.WaitAsync(TestConfiguration.PassingTestTimeout); } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.SupportsTls13))] [InlineData(true, true)] [InlineData(true, false)] [InlineData(false, true)] [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.Linux)] public async Task DisableUsedRsaPadding_Throws(bool clientDisable, bool serverDisable) { - if (PlatformDetection.IsWindowsNanoServer) - { - throw new SkipTestException("Windows Nano Server does not support sigalg disabling."); - } - (Stream client, Stream server) = TestHelper.GetConnectedTcpStreams(); using SslStream clientSslStream = new SslStream(client);