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 73a9d32bb45c84..828af2acfac0ee 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 @@ -8,7 +8,6 @@ using System.IO; using System.Net; using System.Net.Security; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Authentication; using System.Security.Authentication.ExtendedProtection; @@ -19,6 +18,8 @@ internal static partial class Interop { internal static partial class OpenSsl { + private const string DisableTlsResumeCtxSwitch = "System.Net.Security.DisableTlsResume"; + private const string DisableTlsResumeEnvironmentVariable = "DOTNET_SYSTEM_NET_SECURITY_DISABLETLSRESUME"; private static readonly IdnMapping s_idnMapping = new IdnMapping(); #region internal methods @@ -45,85 +46,116 @@ internal static partial class OpenSsl return bindingHandle; } - internal static SafeSslHandle AllocateSslContext(SslProtocols protocols, SafeX509Handle? certHandle, SafeEvpPKeyHandle? certKeyHandle, EncryptionPolicy policy, SslAuthenticationOptions sslAuthenticationOptions) + private static volatile int s_disableTlsResume = -1; + + private static bool DisableTlsResume + { + get + { + int disableTlsResume = s_disableTlsResume; + if (disableTlsResume != -1) + { + return disableTlsResume != 0; + } + + // First check for the AppContext switch, giving it priority over the environment variable. + if (AppContext.TryGetSwitch(DisableTlsResumeCtxSwitch, out bool value)) + { + s_disableTlsResume = value ? 1 : 0; + } + else + { + // AppContext switch wasn't used. Check the environment variable. + s_disableTlsResume = + Environment.GetEnvironmentVariable(DisableTlsResumeEnvironmentVariable) is string envVar && + (envVar == "1" || envVar.Equals("true", StringComparison.OrdinalIgnoreCase)) ? 1 : 0; + } + + return s_disableTlsResume != 0; + } + } + + // This is helper function to adjust requested protocols based on CipherSuitePolicy and system capability. + private static SslProtocols CalculateEffectiveProtocols(SslAuthenticationOptions sslAuthenticationOptions) { - SafeSslHandle? context = null; + SslProtocols protocols = sslAuthenticationOptions.EnabledSslProtocols; - // Always use SSLv23_method, regardless of protocols. It supports negotiating to the highest - // mutually supported version and can thus handle any of the set protocols, and we then use - // SetProtocolOptions to ensure we only allow the ones requested. - using (SafeSslContextHandle innerContext = Ssl.SslCtxCreate(Ssl.SslMethods.SSLv23_method)) + if (!Interop.Ssl.Tls13Supported) { - if (innerContext.IsInvalid) + if (protocols != SslProtocols.None && + CipherSuitesPolicyPal.WantsTls13(protocols)) { - throw CreateSslException(SR.net_allocate_ssl_context_failed); + protocols = protocols & (~SslProtocols.Tls13); } - - if (!Interop.Ssl.Tls13Supported) + } + else if (CipherSuitesPolicyPal.WantsTls13(protocols) && + CipherSuitesPolicyPal.ShouldOptOutOfTls13(sslAuthenticationOptions.CipherSuitesPolicy, sslAuthenticationOptions.EncryptionPolicy)) + { + if (protocols == SslProtocols.None) { - if (protocols != SslProtocols.None && - CipherSuitesPolicyPal.WantsTls13(protocols)) - { - protocols = protocols & (~SslProtocols.Tls13); - } + // we are using default settings but cipher suites policy says that TLS 1.3 + // is not compatible with our settings (i.e. we requested no encryption or disabled + // all TLS 1.3 cipher suites) + protocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12; } - else if (CipherSuitesPolicyPal.WantsTls13(protocols) && - CipherSuitesPolicyPal.ShouldOptOutOfTls13(sslAuthenticationOptions.CipherSuitesPolicy, policy)) + else { - if (protocols == SslProtocols.None) - { - // we are using default settings but cipher suites policy says that TLS 1.3 - // is not compatible with our settings (i.e. we requested no encryption or disabled - // all TLS 1.3 cipher suites) - protocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12; - } - else - { - // user explicitly asks for TLS 1.3 but their policy is not compatible with TLS 1.3 - throw new SslException( - SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy)); - } + // user explicitly asks for TLS 1.3 but their policy is not compatible with TLS 1.3 + throw new SslException( + SR.Format(SR.net_ssl_encryptionpolicy_notsupported, sslAuthenticationOptions.EncryptionPolicy)); } + } - if (CipherSuitesPolicyPal.ShouldOptOutOfLowerThanTls13(sslAuthenticationOptions.CipherSuitesPolicy, policy)) + if (CipherSuitesPolicyPal.ShouldOptOutOfLowerThanTls13(sslAuthenticationOptions.CipherSuitesPolicy, sslAuthenticationOptions.EncryptionPolicy)) + { + if (!CipherSuitesPolicyPal.WantsTls13(protocols)) { - if (!CipherSuitesPolicyPal.WantsTls13(protocols)) - { - // We cannot provide neither TLS 1.3 or non TLS 1.3, user disabled all cipher suites - throw new SslException( - SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy)); - } - - protocols = SslProtocols.Tls13; + // We cannot provide neither TLS 1.3 or non TLS 1.3, user disabled all cipher suites + throw new SslException( + SR.Format(SR.net_ssl_encryptionpolicy_notsupported, sslAuthenticationOptions.EncryptionPolicy)); } - // Configure allowed protocols. It's ok to use DangerousGetHandle here without AddRef/Release as we just - // create the handle, it's rooted by the using, no one else has a reference to it, etc. - Ssl.SetProtocolOptions(innerContext.DangerousGetHandle(), protocols); + protocols = SslProtocols.Tls13; + } + + return protocols; + } + + // This essentially wraps SSL_CTX* aka SSL_CTX_new + setting + internal static SafeSslContextHandle AllocateSslContext(SafeFreeSslCredentials credential, SslAuthenticationOptions sslAuthenticationOptions, SslProtocols protocols) + { + SafeX509Handle? certHandle = credential.CertHandle; + SafeEvpPKeyHandle? certKeyHandle = credential.CertKeyHandle; - // Sets policy and security level - if (!Ssl.SetEncryptionPolicy(innerContext, policy)) + // Always use SSLv23_method, regardless of protocols. It supports negotiating to the highest + // mutually supported version and can thus handle any of the set protocols, and we then use + // SetProtocolOptions to ensure we only allow the ones requested. + SafeSslContextHandle sslCtx = Ssl.SslCtxCreate(Ssl.SslMethods.SSLv23_method); + try + { + if (sslCtx.IsInvalid) { - throw new SslException( - SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy)); + throw CreateSslException(SR.net_allocate_ssl_context_failed); } - // The logic in SafeSslHandle.Disconnect is simple because we are doing a quiet - // shutdown (we aren't negotiating for session close to enable later session - // restoration). - // - // If you find yourself wanting to remove this line to enable bidirectional - // close-notify, you'll probably need to rewrite SafeSslHandle.Disconnect(). - // https://www.openssl.org/docs/manmaster/ssl/SSL_shutdown.html - Ssl.SslCtxSetQuietShutdown(innerContext); + Ssl.SslCtxSetProtocolOptions(sslCtx, protocols); + + if (sslAuthenticationOptions.EncryptionPolicy != EncryptionPolicy.RequireEncryption) + { + // Sets policy and security level + if (!Ssl.SetEncryptionPolicy(sslCtx, sslAuthenticationOptions.EncryptionPolicy)) + { + throw new SslException( SR.Format(SR.net_ssl_encryptionpolicy_notsupported, sslAuthenticationOptions.EncryptionPolicy)); + } + } byte[]? cipherList = - CipherSuitesPolicyPal.GetOpenSslCipherList(sslAuthenticationOptions.CipherSuitesPolicy, protocols, policy); + CipherSuitesPolicyPal.GetOpenSslCipherList(sslAuthenticationOptions.CipherSuitesPolicy, protocols, sslAuthenticationOptions.EncryptionPolicy); Debug.Assert(cipherList == null || (cipherList.Length >= 1 && cipherList[cipherList.Length - 1] == 0)); byte[]? cipherSuites = - CipherSuitesPolicyPal.GetOpenSslCipherSuites(sslAuthenticationOptions.CipherSuitesPolicy, protocols, policy); + CipherSuitesPolicyPal.GetOpenSslCipherSuites(sslAuthenticationOptions.CipherSuitesPolicy, protocols, sslAuthenticationOptions.EncryptionPolicy); Debug.Assert(cipherSuites == null || (cipherSuites.Length >= 1 && cipherSuites[cipherSuites.Length - 1] == 0)); @@ -132,96 +164,147 @@ internal static SafeSslHandle AllocateSslContext(SslProtocols protocols, SafeX50 fixed (byte* cipherListStr = cipherList) fixed (byte* cipherSuitesStr = cipherSuites) { - if (!Ssl.SetCiphers(innerContext, cipherListStr, cipherSuitesStr)) + if (!Ssl.SslCtxSetCiphers(sslCtx, cipherListStr, cipherSuitesStr)) { Crypto.ErrClearError(); - throw new PlatformNotSupportedException(SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy)); + throw new PlatformNotSupportedException(SR.Format(SR.net_ssl_encryptionpolicy_notsupported, sslAuthenticationOptions.EncryptionPolicy)); } } } + // The logic in SafeSslHandle.Disconnect is simple because we are doing a quiet + // shutdown (we aren't negotiating for session close to enable later session + // restoration). + // + // If you find yourself wanting to remove this line to enable bidirectional + // close-notify, you'll probably need to rewrite SafeSslHandle.Disconnect(). + // https://www.openssl.org/docs/manmaster/ssl/SSL_shutdown.html + Ssl.SslCtxSetQuietShutdown(sslCtx); + + if (sslAuthenticationOptions.IsServer && sslAuthenticationOptions.ApplicationProtocols != null && sslAuthenticationOptions.ApplicationProtocols.Count != 0) + { + unsafe + { + Interop.Ssl.SslCtxSetAlpnSelectCb(sslCtx, &AlpnServerSelectCallback, IntPtr.Zero); + } + } + bool hasCertificateAndKey = certHandle != null && !certHandle.IsInvalid && certKeyHandle != null && !certKeyHandle.IsInvalid; if (hasCertificateAndKey) { - SetSslCertificate(innerContext, certHandle!, certKeyHandle!); + SetSslCertificate(sslCtx, certHandle!, certKeyHandle!); } - if (sslAuthenticationOptions.IsServer && sslAuthenticationOptions.RemoteCertRequired) + if (sslAuthenticationOptions.CertificateContext != null && sslAuthenticationOptions.CertificateContext.IntermediateCertificates.Length > 0) { - unsafe + if (!Ssl.AddExtraChainCertificates(sslCtx, sslAuthenticationOptions.CertificateContext.IntermediateCertificates)) { - Ssl.SslCtxSetVerify(innerContext, &VerifyClientCertificate); + throw CreateSslException(SR.net_ssl_use_cert_failed); } } + } + catch + { + sslCtx.Dispose(); + throw; + } - GCHandle alpnHandle = default; - try + return sslCtx; + } + + // This essentially wraps SSL* SSL_new() + internal static SafeSslHandle AllocateSslHandle(SafeFreeSslCredentials credential, SslAuthenticationOptions sslAuthenticationOptions) + { + SafeSslHandle? sslHandle = null; + SafeSslContextHandle? sslCtxHandle = null; + SafeSslContextHandle? newCtxHandle = null; + SslProtocols protocols = CalculateEffectiveProtocols(sslAuthenticationOptions); + bool cacheSslContext = !DisableTlsResume && sslAuthenticationOptions.EncryptionPolicy == EncryptionPolicy.RequireEncryption && + sslAuthenticationOptions.CertificateContext != null && + sslAuthenticationOptions.CertificateContext.SslContexts != null && + sslAuthenticationOptions.CipherSuitesPolicy == null && + (!sslAuthenticationOptions.IsServer || + (sslAuthenticationOptions.ApplicationProtocols != null && sslAuthenticationOptions.ApplicationProtocols.Count != 0)); + + if (cacheSslContext) + { + sslAuthenticationOptions.CertificateContext!.SslContexts!.TryGetValue(protocols, out sslCtxHandle); + } + + if (sslCtxHandle == null) + { + // We did not get SslContext from cache + sslCtxHandle = newCtxHandle = AllocateSslContext(credential, sslAuthenticationOptions, protocols); + + if (cacheSslContext && sslAuthenticationOptions.CertificateContext!.SslContexts!.TryAdd(protocols, newCtxHandle)) { - if (sslAuthenticationOptions.ApplicationProtocols != null && sslAuthenticationOptions.ApplicationProtocols.Count != 0) - { - if (sslAuthenticationOptions.IsServer) - { - alpnHandle = GCHandle.Alloc(sslAuthenticationOptions.ApplicationProtocols); + newCtxHandle = null; + } + } - unsafe - { - Interop.Ssl.SslCtxSetAlpnSelectCb(innerContext, &AlpnServerSelectCallback, GCHandle.ToIntPtr(alpnHandle)); - } - } - else - { - if (Interop.Ssl.SslCtxSetAlpnProtos(innerContext, sslAuthenticationOptions.ApplicationProtocols) != 0) - { - throw CreateSslException(SR.net_alpn_config_failed); - } - } - } + GCHandle alpnHandle = default; + try + { + sslHandle = SafeSslHandle.Create(sslCtxHandle, sslAuthenticationOptions.IsServer); + Debug.Assert(sslHandle != null, "Expected non-null return value from SafeSslHandle.Create"); + if (sslHandle.IsInvalid) + { + sslHandle.Dispose(); + throw CreateSslException(SR.net_allocate_ssl_context_failed); + } - context = SafeSslHandle.Create(innerContext, sslAuthenticationOptions.IsServer); - Debug.Assert(context != null, "Expected non-null return value from SafeSslHandle.Create"); - if (context.IsInvalid) + if (sslAuthenticationOptions.ApplicationProtocols != null && sslAuthenticationOptions.ApplicationProtocols.Count != 0) + { + if (sslAuthenticationOptions.IsServer) { - context.Dispose(); - throw CreateSslException(SR.net_allocate_ssl_context_failed); + alpnHandle = GCHandle.Alloc(sslAuthenticationOptions.ApplicationProtocols); + Interop.Ssl.SslSetData(sslHandle, GCHandle.ToIntPtr(alpnHandle)); + sslHandle.AlpnHandle = alpnHandle; } - - if (!sslAuthenticationOptions.IsServer) + else { - // The IdnMapping converts unicode input into the IDNA punycode sequence. - string punyCode = string.IsNullOrEmpty(sslAuthenticationOptions.TargetHost) ? string.Empty : s_idnMapping.GetAscii(sslAuthenticationOptions.TargetHost!); - - // Similar to windows behavior, set SNI on openssl by default for client context, ignore errors. - if (!Ssl.SslSetTlsExtHostName(context, punyCode)) + if (Interop.Ssl.SslSetAlpnProtos(sslHandle, sslAuthenticationOptions.ApplicationProtocols) != 0) { - Crypto.ErrClearError(); + throw CreateSslException(SR.net_alpn_config_failed); } } + } - if (sslAuthenticationOptions.CertificateContext != null && sslAuthenticationOptions.CertificateContext.IntermediateCertificates.Length > 0) + if (!sslAuthenticationOptions.IsServer) + { + // The IdnMapping converts unicode input into the IDNA punycode sequence. + string punyCode = string.IsNullOrEmpty(sslAuthenticationOptions.TargetHost) ? string.Empty : s_idnMapping.GetAscii(sslAuthenticationOptions.TargetHost!); + + // Similar to windows behavior, set SNI on openssl by default for client context, ignore errors. + if (!Ssl.SslSetTlsExtHostName(sslHandle, punyCode)) { - if (!Ssl.AddExtraChainCertificates(context, sslAuthenticationOptions.CertificateContext!.IntermediateCertificates)) - { - throw CreateSslException(SR.net_ssl_use_cert_failed); - } + Crypto.ErrClearError(); } + } - context.AlpnHandle = alpnHandle; + if (sslAuthenticationOptions.IsServer && sslAuthenticationOptions.RemoteCertRequired) + { + Ssl.SslSetVerifyPeer(sslHandle); } - catch + } + catch + { + if (alpnHandle.IsAllocated) { - if (alpnHandle.IsAllocated) - { - alpnHandle.Free(); - } - - throw; + alpnHandle.Free(); } + + throw; + } + finally + { + newCtxHandle?.Dispose(); } - return context; + return sslHandle; } internal static SecurityStatusPal SslRenegotiate(SafeSslHandle sslContext, out byte[]? outputBuffer) @@ -441,8 +524,12 @@ private static unsafe int AlpnServerSelectCallback(IntPtr ssl, byte** outp, byte { *outp = null; *outlen = 0; + IntPtr sslData = Ssl.SslGetData(ssl); + + // reset application data to avoid dangling pointer. + Ssl.SslSetData(ssl, IntPtr.Zero); - GCHandle protocolHandle = GCHandle.FromIntPtr(arg); + GCHandle protocolHandle = GCHandle.FromIntPtr(sslData); if (!(protocolHandle.Target is List protocolList)) { return Ssl.SSL_TLSEXT_ERR_ALERT_FATAL; diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SetProtocolOptions.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SetProtocolOptions.cs index d75ab5c5cc55c5..a8439617d1d689 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SetProtocolOptions.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SetProtocolOptions.cs @@ -4,12 +4,16 @@ using System; using System.Runtime.InteropServices; using System.Security.Authentication; +using Microsoft.Win32.SafeHandles; internal static partial class Interop { internal static partial class Ssl { - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SetProtocolOptions")] - internal static extern void SetProtocolOptions(IntPtr ctx, SslProtocols protocols); + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetProtocolOptions")] + internal static extern void SslCtxSetProtocolOptions(IntPtr ctx, SslProtocols protocols); + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetProtocolOptions")] + internal static extern void SslCtxSetProtocolOptions(SafeSslContextHandle ctx, SslProtocols protocols); } } 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 29154b77da6325..a73de253541283 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 @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Diagnostics; using System.Net.Security; using System.Runtime.InteropServices; @@ -44,6 +45,9 @@ internal static partial class Ssl [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSetAcceptState")] internal static extern void SslSetAcceptState(SafeSslHandle ssl); + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSetAlpnProtos")] + internal static extern int SslSetAlpnProtos(SafeSslHandle ssl, IntPtr protos, int len); + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslGetVersion")] internal static extern IntPtr SslGetVersion(SafeSslHandle ssl); @@ -120,9 +124,6 @@ internal static partial class Ssl [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SslSessionReused(SafeSslHandle ssl); - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslAddExtraChainCert")] - internal static extern bool SslAddExtraChainCert(SafeSslHandle ssl, SafeX509Handle x509); - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslGetClientCAList")] private static extern SafeSharedX509NameStackHandle SslGetClientCAList_private(SafeSslHandle ssl); @@ -133,6 +134,55 @@ internal static partial class Ssl [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetOpenSslCipherSuiteName")] private static extern IntPtr GetOpenSslCipherSuiteName(SafeSslHandle ssl, int cipherSuite, out int isTls12OrLower); + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SetCiphers")] + internal static extern unsafe bool SslSetCiphers(SafeSslHandle ssl, byte* cipherList, byte* cipherSuites); + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSetVerifyPeer")] + internal static extern void SslSetVerifyPeer(SafeSslHandle ssl); + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslGetData")] + internal static extern IntPtr SslGetData(IntPtr ssl); + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSetData")] + internal static extern int SslSetData(SafeSslHandle ssl, IntPtr data); + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSetData")] + internal static extern int SslSetData(IntPtr ssl, IntPtr data); + + internal static unsafe int SslSetAlpnProtos(SafeSslHandle ssl, List protocols) + { + byte[] buffer = ConvertAlpnProtocolListToByteArray(protocols); + fixed (byte* b = buffer) + { + return SslSetAlpnProtos(ssl, (IntPtr)b, buffer.Length); + } + } + + internal static byte[] ConvertAlpnProtocolListToByteArray(List applicationProtocols) + { + int protocolSize = 0; + foreach (SslApplicationProtocol protocol in applicationProtocols) + { + if (protocol.Protocol.Length == 0 || protocol.Protocol.Length > byte.MaxValue) + { + throw new ArgumentException(SR.net_ssl_app_protocols_invalid, nameof(applicationProtocols)); + } + + protocolSize += protocol.Protocol.Length + 1; + } + + byte[] buffer = new byte[protocolSize]; + var offset = 0; + foreach (SslApplicationProtocol protocol in applicationProtocols) + { + buffer[offset++] = (byte)(protocol.Protocol.Length); + protocol.Protocol.Span.CopyTo(buffer.AsSpan(offset)); + offset += protocol.Protocol.Length; + } + + return buffer; + } + internal static string? GetOpenSslCipherSuiteName(SafeSslHandle ssl, TlsCipherSuite cipherSuite, out bool isTls12OrLower) { string? ret = Marshal.PtrToStringAnsi(GetOpenSslCipherSuiteName(ssl, (int)cipherSuite, out int isTls12OrLowerInt)); @@ -159,58 +209,6 @@ internal static SafeSharedX509NameStackHandle SslGetClientCAList(SafeSslHandle s return handle; } - internal static bool AddExtraChainCertificates(SafeSslHandle sslContext, X509Chain chain) - { - Debug.Assert(chain != null, "X509Chain should not be null"); - Debug.Assert(chain.ChainElements.Count > 0, "chain.Build should have already been called"); - - // If the last certificate is a root certificate, don't send it. PartialChain means the last cert wasn't a root. - int stop = chain.ChainElements.Count - 1; - foreach (X509ChainStatus s in chain.ChainStatus) - { - if ((s.Status & X509ChainStatusFlags.PartialChain) != 0) - { - stop++; - break; - } - } - - // Don't include the first item (the cert whose private key we have) - for (int i = 1; i < stop; i++) - { - SafeX509Handle dupCertHandle = Crypto.X509UpRef(chain.ChainElements[i].Certificate!.Handle); - Crypto.CheckValidOpenSslHandle(dupCertHandle); - if (!SslAddExtraChainCert(sslContext, dupCertHandle)) - { - Crypto.ErrClearError(); - dupCertHandle.Dispose(); // we still own the safe handle; clean it up - return false; - } - dupCertHandle.SetHandleAsInvalid(); // ownership has been transferred to sslHandle; do not free via this safe handle - } - - return true; - } - - internal static bool AddExtraChainCertificates(SafeSslHandle sslContext, X509Certificate2[] chain) - { - // send pre-computed list of intermediates. - for (int i = 0; i < chain.Length; i++) - { - SafeX509Handle dupCertHandle = Crypto.X509UpRef(chain[i].Handle); - Crypto.CheckValidOpenSslHandle(dupCertHandle); - if (!SslAddExtraChainCert(sslContext, dupCertHandle)) - { - Crypto.ErrClearError(); - dupCertHandle.Dispose(); // we still own the safe handle; clean it up - return false; - } - dupCertHandle.SetHandleAsInvalid(); // ownership has been transferred to sslHandle; do not free via this safe handle - } - - return true; - } - internal static class SslMethods { internal static readonly IntPtr SSLv23_method = SslV2_3Method(); diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtx.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtx.cs index d39b6595d39b1e..e8e208e5859aae 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtx.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtx.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Net.Security; using System.Runtime.InteropServices; +using System.Security.Cryptography.X509Certificates; using System.Text; using Microsoft.Win32.SafeHandles; @@ -18,44 +19,26 @@ internal static partial class Ssl [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxDestroy")] internal static extern void SslCtxDestroy(IntPtr ctx); - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetAlpnProtos")] - internal static extern int SslCtxSetAlpnProtos(SafeSslContextHandle ctx, IntPtr protos, int len); - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetAlpnSelectCb")] internal static extern unsafe void SslCtxSetAlpnSelectCb(SafeSslContextHandle ctx, delegate* unmanaged callback, IntPtr arg); - internal static unsafe int SslCtxSetAlpnProtos(SafeSslContextHandle ctx, List protocols) - { - byte[] buffer = ConvertAlpnProtocolListToByteArray(protocols); - fixed (byte* b = buffer) - { - return SslCtxSetAlpnProtos(ctx, (IntPtr)b, buffer.Length); - } - } - - internal static byte[] ConvertAlpnProtocolListToByteArray(List applicationProtocols) + internal static bool AddExtraChainCertificates(SafeSslContextHandle ctx, X509Certificate2[] chain) { - int protocolSize = 0; - foreach (SslApplicationProtocol protocol in applicationProtocols) + // send pre-computed list of intermediates. + for (int i = 0; i < chain.Length; i++) { - if (protocol.Protocol.Length == 0 || protocol.Protocol.Length > byte.MaxValue) + SafeX509Handle dupCertHandle = Crypto.X509UpRef(chain[i].Handle); + Crypto.CheckValidOpenSslHandle(dupCertHandle); + if (!SslCtxAddExtraChainCert(ctx, dupCertHandle)) { - throw new ArgumentException(SR.net_ssl_app_protocols_invalid, nameof(applicationProtocols)); + Crypto.ErrClearError(); + dupCertHandle.Dispose(); // we still own the safe handle; clean it up + return false; } - - protocolSize += protocol.Protocol.Length + 1; + dupCertHandle.SetHandleAsInvalid(); // ownership has been transferred to sslHandle; do not free via this safe handle } - byte[] buffer = new byte[protocolSize]; - var offset = 0; - foreach (SslApplicationProtocol protocol in applicationProtocols) - { - buffer[offset++] = (byte)(protocol.Protocol.Length); - protocol.Protocol.Span.CopyTo(buffer.AsSpan(offset)); - offset += protocol.Protocol.Length; - } - - return buffer; + return true; } } } diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtxOptions.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtxOptions.cs index 978f846939c2f9..60c81072325c60 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtxOptions.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtxOptions.cs @@ -11,6 +11,9 @@ internal static partial class Interop { internal static partial class Ssl { + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxAddExtraChainCert")] + internal static extern bool SslCtxAddExtraChainCert(SafeSslContextHandle ctx, SafeX509Handle x509); + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxUseCertificate")] internal static extern int SslCtxUseCertificate(SafeSslContextHandle ctx, SafeX509Handle certPtr); @@ -26,10 +29,10 @@ internal static partial class Ssl [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetVerify")] internal static extern unsafe void SslCtxSetVerify(SafeSslContextHandle ctx, delegate* unmanaged callback); - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SetCiphers")] - internal static extern unsafe bool SetCiphers(SafeSslContextHandle ctx, byte* cipherList, byte* cipherSuites); + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetCiphers")] + internal static extern unsafe bool SslCtxSetCiphers(SafeSslContextHandle ctx, byte* cipherList, byte* cipherSuites); - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SetEncryptionPolicy")] + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetEncryptionPolicy")] internal static extern bool SetEncryptionPolicy(SafeSslContextHandle ctx, EncryptionPolicy policy); } } diff --git a/src/libraries/Common/src/System/Net/Security/Unix/SafeDeleteSslContext.cs b/src/libraries/Common/src/System/Net/Security/Unix/SafeDeleteSslContext.cs index 3f550d36d7f439..89ac9b6d8dc11c 100644 --- a/src/libraries/Common/src/System/Net/Security/Unix/SafeDeleteSslContext.cs +++ b/src/libraries/Common/src/System/Net/Security/Unix/SafeDeleteSslContext.cs @@ -34,12 +34,7 @@ public SafeDeleteSslContext(SafeFreeSslCredentials credential, SslAuthentication try { - _sslContext = Interop.OpenSsl.AllocateSslContext( - credential.Protocols, - credential.CertHandle, - credential.CertKeyHandle, - credential.Policy, - sslAuthenticationOptions); + _sslContext = Interop.OpenSsl.AllocateSslHandle(credential, sslAuthenticationOptions); } catch (Exception ex) { diff --git a/src/libraries/Common/src/System/Net/Security/Unix/SafeFreeSslCredentials.cs b/src/libraries/Common/src/System/Net/Security/Unix/SafeFreeSslCredentials.cs index ff378ab425139b..ae6bab3968d49e 100644 --- a/src/libraries/Common/src/System/Net/Security/Unix/SafeFreeSslCredentials.cs +++ b/src/libraries/Common/src/System/Net/Security/Unix/SafeFreeSslCredentials.cs @@ -21,6 +21,7 @@ internal sealed class SafeFreeSslCredentials : SafeFreeCredentials private SslProtocols _protocols = SslProtocols.None; private EncryptionPolicy _policy; private bool _isInvalid; + private SslStreamCertificateContext? _context; internal SafeX509Handle? CertHandle { @@ -42,14 +43,15 @@ internal EncryptionPolicy Policy get { return _policy; } } - public SafeFreeSslCredentials(X509Certificate? certificate, SslProtocols protocols, EncryptionPolicy policy) + public SafeFreeSslCredentials(SslStreamCertificateContext? context, SslProtocols protocols, EncryptionPolicy policy, bool isServer) : base(IntPtr.Zero, true) { + Debug.Assert( - certificate == null || certificate is X509Certificate2, + context == null || context.Certificate is X509Certificate2, "Only X509Certificate2 certificates are supported at this time"); - X509Certificate2? cert = (X509Certificate2?)certificate; + X509Certificate2? cert = context?.Certificate; if (cert != null) { @@ -87,6 +89,7 @@ public SafeFreeSslCredentials(X509Certificate? certificate, SslProtocols protoco _protocols = protocols; _policy = policy; + _context = context; } public override bool IsInvalid diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.c index 15df621f7a7dfa..0a3705321eec4c 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.c @@ -803,6 +803,12 @@ void local_SSL_CTX_set_security_level(SSL_CTX* ctx, int32_t level) (void)level; } +void local_SSL_set_security_level(SSL* ssl, int32_t level) +{ + (void)ssl; + (void)level; +} + int local_BIO_up_ref(BIO *bio) { if (!bio) diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.h index 3998f1abbf3a4a..2079d81fd96816 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.h @@ -36,6 +36,7 @@ int32_t local_SSL_CTX_config(SSL_CTX* ctx, const char* name); unsigned long local_SSL_CTX_set_options(SSL_CTX* ctx, unsigned long options); unsigned long local_SSL_set_options(SSL* ssl, unsigned long options); void local_SSL_CTX_set_security_level(SSL_CTX* ctx, int32_t level); +void local_SSL_set_security_level(SSL* ssl, int32_t level); int local_SSL_session_reused(SSL* ssl); int32_t local_X509_check_host(X509* x509, const char* name, size_t namelen, unsigned int flags, char** peername); const ASN1_TIME* local_X509_CRL_get0_nextUpdate(const X509_CRL* crl); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/entrypoints.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/entrypoints.c index bf68f23be3633a..102ccd91e8b44b 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/entrypoints.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/entrypoints.c @@ -287,16 +287,16 @@ static const Entry s_cryptoNative[] = DllImportEntry(CryptoNative_SslRenegotiate) DllImportEntry(CryptoNative_IsSslRenegotiatePending) DllImportEntry(CryptoNative_IsSslStateOK) + DllImportEntry(CryptoNative_SslCtxAddExtraChainCert) + DllImportEntry(CryptoNative_SslCtxSetCiphers) + DllImportEntry(CryptoNative_SslCtxSetEncryptionPolicy) DllImportEntry(CryptoNative_SetCiphers) - DllImportEntry(CryptoNative_SetEncryptionPolicy) - DllImportEntry(CryptoNative_SetProtocolOptions) - DllImportEntry(CryptoNative_SslAddExtraChainCert) DllImportEntry(CryptoNative_SslCreate) DllImportEntry(CryptoNative_SslCtxCheckPrivateKey) DllImportEntry(CryptoNative_SslCtxCreate) DllImportEntry(CryptoNative_SslCtxDestroy) - DllImportEntry(CryptoNative_SslCtxSetAlpnProtos) DllImportEntry(CryptoNative_SslCtxSetAlpnSelectCb) + DllImportEntry(CryptoNative_SslCtxSetProtocolOptions) DllImportEntry(CryptoNative_SslCtxSetQuietShutdown) DllImportEntry(CryptoNative_SslCtxSetVerify) DllImportEntry(CryptoNative_SslCtxUseCertificate) @@ -305,6 +305,7 @@ static const Entry s_cryptoNative[] = DllImportEntry(CryptoNative_SslDoHandshake) DllImportEntry(CryptoNative_SslGetClientCAList) DllImportEntry(CryptoNative_SslGetCurrentCipherId) + DllImportEntry(CryptoNative_SslGetData) DllImportEntry(CryptoNative_SslGetError) DllImportEntry(CryptoNative_SslGetFinished) DllImportEntry(CryptoNative_SslGetPeerCertChain) @@ -314,10 +315,13 @@ static const Entry s_cryptoNative[] = DllImportEntry(CryptoNative_SslRead) DllImportEntry(CryptoNative_SslSessionReused) DllImportEntry(CryptoNative_SslSetAcceptState) + DllImportEntry(CryptoNative_SslSetAlpnProtos) DllImportEntry(CryptoNative_SslSetBio) DllImportEntry(CryptoNative_SslSetConnectState) + DllImportEntry(CryptoNative_SslSetData) DllImportEntry(CryptoNative_SslSetQuietShutdown) DllImportEntry(CryptoNative_SslSetTlsExtHostName) + DllImportEntry(CryptoNative_SslSetVerifyPeer) DllImportEntry(CryptoNative_SslShutdown) DllImportEntry(CryptoNative_SslV2_3Method) DllImportEntry(CryptoNative_SslWrite) diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h index 7de59f0ba3bace..2e783f49352de1 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h @@ -115,6 +115,7 @@ int EC_POINT_set_affine_coordinates_GF2m( #undef HAVE_OPENSSL_SET_CIPHERSUITES #define HAVE_OPENSSL_SET_CIPHERSUITES 1 int SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str); +int SSL_set_ciphersuites(SSL *s, const char *str); const SSL_CIPHER* SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr); #endif @@ -128,7 +129,6 @@ const SSL_CIPHER* SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr); #include "osslcompat_111.h" #endif - #if !HAVE_OPENSSL_ALPN #undef HAVE_OPENSSL_ALPN #define HAVE_OPENSSL_ALPN 1 @@ -459,6 +459,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void); LIGHTUP_FUNCTION(SSL_CIPHER_get_name) \ LIGHTUP_FUNCTION(SSL_CIPHER_get_version) \ REQUIRED_FUNCTION(SSL_ctrl) \ + REQUIRED_FUNCTION(SSL_set_alpn_protos) \ REQUIRED_FUNCTION(SSL_set_quiet_shutdown) \ REQUIRED_FUNCTION(SSL_CTX_check_private_key) \ FALLBACK_FUNCTION(SSL_CTX_config) \ @@ -483,6 +484,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void); REQUIRED_FUNCTION(SSL_get_client_CA_list) \ REQUIRED_FUNCTION(SSL_get_current_cipher) \ REQUIRED_FUNCTION(SSL_get_error) \ + REQUIRED_FUNCTION(SSL_get_ex_data) \ REQUIRED_FUNCTION(SSL_get_finished) \ REQUIRED_FUNCTION(SSL_get_peer_cert_chain) \ REQUIRED_FUNCTION(SSL_get_peer_finished) \ @@ -500,7 +502,10 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void); FALLBACK_FUNCTION(SSL_session_reused) \ REQUIRED_FUNCTION(SSL_set_accept_state) \ REQUIRED_FUNCTION(SSL_set_bio) \ + REQUIRED_FUNCTION(SSL_set_cipher_list) \ + LIGHTUP_FUNCTION(SSL_set_ciphersuites) \ REQUIRED_FUNCTION(SSL_set_connect_state) \ + REQUIRED_FUNCTION(SSL_set_ex_data) \ FALLBACK_FUNCTION(SSL_set_options) \ REQUIRED_FUNCTION(SSL_set_verify) \ REQUIRED_FUNCTION(SSL_shutdown) \ @@ -910,6 +915,7 @@ FOR_ALL_OPENSSL_FUNCTIONS #define SSL_CIPHER_get_name SSL_CIPHER_get_name_ptr #define SSL_CIPHER_get_version SSL_CIPHER_get_version_ptr #define SSL_ctrl SSL_ctrl_ptr +#define SSL_set_alpn_protos SSL_set_alpn_protos_ptr #define SSL_set_quiet_shutdown SSL_set_quiet_shutdown_ptr #define SSL_CTX_check_private_key SSL_CTX_check_private_key_ptr #define SSL_CTX_config SSL_CTX_config_ptr @@ -933,6 +939,7 @@ FOR_ALL_OPENSSL_FUNCTIONS #define SSL_get_client_CA_list SSL_get_client_CA_list_ptr #define SSL_get_current_cipher SSL_get_current_cipher_ptr #define SSL_get_error SSL_get_error_ptr +#define SSL_get_ex_data SSL_get_ex_data_ptr #define SSL_get_finished SSL_get_finished_ptr #define SSL_get_peer_cert_chain SSL_get_peer_cert_chain_ptr #define SSL_get_peer_finished SSL_get_peer_finished_ptr @@ -953,7 +960,10 @@ FOR_ALL_OPENSSL_FUNCTIONS #define SSL_session_reused SSL_session_reused_ptr #define SSL_set_accept_state SSL_set_accept_state_ptr #define SSL_set_bio SSL_set_bio_ptr +#define SSL_set_cipher_list SSL_set_cipher_list_ptr +#define SSL_set_ciphersuites SSL_set_ciphersuites_ptr #define SSL_set_connect_state SSL_set_connect_state_ptr +#define SSL_set_ex_data SSL_set_ex_data_ptr #define SSL_set_options SSL_set_options_ptr #define SSL_set_verify SSL_set_verify_ptr #define SSL_shutdown SSL_shutdown_ptr diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c index 77ac385a799059..2b4eb271b022a2 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c @@ -39,6 +39,7 @@ static void EnsureLibSsl10Initialized() #endif static int32_t g_config_specified_ciphersuites = 0; +static char* g_emptyAlpn = ""; static void DetectCiphersuiteConfiguration() { @@ -210,14 +211,14 @@ static long TrySetECDHNamedCurve(SSL_CTX* ctx) } } - return result; + return result; #else (void)ctx; return 1; #endif } -static void ResetProtocolRestrictions(SSL_CTX* ctx) +static void ResetCtxProtocolRestrictions(SSL_CTX* ctx) { #ifndef SSL_CTRL_SET_MIN_PROTO_VERSION #define SSL_CTRL_SET_MIN_PROTO_VERSION 123 @@ -230,7 +231,7 @@ static void ResetProtocolRestrictions(SSL_CTX* ctx) SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, 0, NULL); } -void CryptoNative_SetProtocolOptions(SSL_CTX* ctx, SslProtocols protocols) +void CryptoNative_SslCtxSetProtocolOptions(SSL_CTX* ctx, SslProtocols protocols) { // Ensure that ECDHE is available if (TrySetECDHNamedCurve(ctx) == 0) @@ -278,7 +279,7 @@ void CryptoNative_SetProtocolOptions(SSL_CTX* ctx, SslProtocols protocols) // We manually set protocols - we need to reset OpenSSL restrictions // to a maximum possible range - ResetProtocolRestrictions(ctx); + ResetCtxProtocolRestrictions(ctx); // OpenSSL 1.0 calls this long, OpenSSL 1.1 calls it unsigned long. #pragma clang diagnostic push @@ -469,7 +470,12 @@ void CryptoNative_SslCtxSetVerify(SSL_CTX* ctx, SslCtxSetVerifyCallback callback SSL_CTX_set_verify(ctx, mode, callback); } -int32_t CryptoNative_SetEncryptionPolicy(SSL_CTX* ctx, EncryptionPolicy policy) +void CryptoNative_SslSetVerifyPeer(SSL* ssl) +{ + SSL_set_verify(ssl, SSL_VERIFY_PEER, verify_callback); +} + +int32_t CryptoNative_SslCtxSetEncryptionPolicy(SSL_CTX* ctx, EncryptionPolicy policy) { switch (policy) { @@ -477,7 +483,7 @@ int32_t CryptoNative_SetEncryptionPolicy(SSL_CTX* ctx, EncryptionPolicy policy) case NoEncryption: // No minimum security policy, same as OpenSSL 1.0 SSL_CTX_set_security_level(ctx, 0); - ResetProtocolRestrictions(ctx); + ResetCtxProtocolRestrictions(ctx); return true; case RequireEncryption: return true; @@ -486,7 +492,7 @@ int32_t CryptoNative_SetEncryptionPolicy(SSL_CTX* ctx, EncryptionPolicy policy) return false; } -int32_t CryptoNative_SetCiphers(SSL_CTX* ctx, const char* cipherList, const char* cipherSuites) +int32_t CryptoNative_SslCtxSetCiphers(SSL_CTX* ctx, const char* cipherList, const char* cipherSuites) { int32_t ret = true; @@ -513,6 +519,33 @@ int32_t CryptoNative_SetCiphers(SSL_CTX* ctx, const char* cipherList, const char return ret; } +int32_t CryptoNative_SetCiphers(SSL* ssl, const char* cipherList, const char* cipherSuites) +{ + int32_t ret = true; + + // for < TLS 1.3 + if (cipherList != NULL) + { + ret &= SSL_set_cipher_list(ssl, cipherList); + if (!ret) + { + return ret; + } + } + + // for TLS 1.3 +#if HAVE_OPENSSL_SET_CIPHERSUITES + if (CryptoNative_Tls13Supported() && cipherSuites != NULL) + { + ret &= SSL_set_ciphersuites(ssl, cipherSuites); + } +#else + (void)cipherSuites; +#endif + + return ret; +} + const char* CryptoNative_GetOpenSslCipherSuiteName(SSL* ssl, int32_t cipherSuite, int32_t* isTls12OrLower) { #if HAVE_OPENSSL_SET_CIPHERSUITES @@ -582,15 +615,14 @@ int32_t CryptoNative_Tls13Supported() #endif } -int32_t CryptoNative_SslAddExtraChainCert(SSL* ssl, X509* x509) +int32_t CryptoNative_SslCtxAddExtraChainCert(SSL_CTX* ctx, X509* x509) { - if (!x509 || !ssl) + if (!x509 || !ctx) { return 0; } - SSL_CTX* ssl_ctx = SSL_get_SSL_CTX(ssl); - if (SSL_CTX_add_extra_chain_cert(ssl_ctx, x509) == 1) + if (SSL_CTX_add_extra_chain_cert(ctx, x509) == 1) { return 1; } @@ -603,7 +635,8 @@ void CryptoNative_SslCtxSetAlpnSelectCb(SSL_CTX* ctx, SslCtxSetAlpnCallback cb, #if HAVE_OPENSSL_ALPN if (API_EXISTS(SSL_CTX_set_alpn_select_cb)) { - SSL_CTX_set_alpn_select_cb(ctx, cb, arg); + (void)arg; + SSL_CTX_set_alpn_select_cb(ctx, cb, g_emptyAlpn); } #else (void)ctx; @@ -612,12 +645,23 @@ void CryptoNative_SslCtxSetAlpnSelectCb(SSL_CTX* ctx, SslCtxSetAlpnCallback cb, #endif } -int32_t CryptoNative_SslCtxSetAlpnProtos(SSL_CTX* ctx, const uint8_t* protos, uint32_t protos_len) +int32_t CryptoNative_SslSetData(SSL* ssl, void *ptr) +{ + return SSL_set_ex_data(ssl, 0, ptr); +} + +void* CryptoNative_SslGetData(SSL* ssl) +{ +// void* data = SSL_get_ex_data(ssl, 0, ptr); + return SSL_get_ex_data(ssl, 0); +} + +int32_t CryptoNative_SslSetAlpnProtos(SSL* ssl, const uint8_t* protos, uint32_t protos_len) { #if HAVE_OPENSSL_ALPN if (API_EXISTS(SSL_CTX_set_alpn_protos)) { - return SSL_CTX_set_alpn_protos(ctx, protos, protos_len); + return SSL_set_alpn_protos(ssl, protos, protos_len); } else #else @@ -737,8 +781,8 @@ int32_t CryptoNative_OpenSslGetProtocolSupport(SslProtocols protocol) if (clientCtx != NULL && serverCtx != NULL && cert != NULL && evp != NULL && bio1 != NULL && bio2 != NULL) { - CryptoNative_SetProtocolOptions(serverCtx, protocol); - CryptoNative_SetProtocolOptions(clientCtx, protocol); + CryptoNative_SslCtxSetProtocolOptions(serverCtx, protocol); + CryptoNative_SslCtxSetProtocolOptions(clientCtx, protocol); SSL_CTX_set_verify(clientCtx, SSL_VERIFY_NONE, NULL); SSL_CTX_set_verify(serverCtx, SSL_VERIFY_NONE, NULL); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ssl.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ssl.h index 79c6cbe22f955b..0a18f7a764c17f 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ssl.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ssl.h @@ -142,7 +142,7 @@ PALEXPORT SSL_CTX* CryptoNative_SslCtxCreate(const SSL_METHOD* method); /* Sets the specified protocols in the SSL_CTX options. */ -PALEXPORT void CryptoNative_SetProtocolOptions(SSL_CTX* ctx, SslProtocols protocols); +PALEXPORT void CryptoNative_SslCtxSetProtocolOptions(SSL_CTX* ctx, SslProtocols protocols); /* Shims the SSL_new method. @@ -318,14 +318,31 @@ Shims the SSL_CTX_set_verify method. PALEXPORT void CryptoNative_SslCtxSetVerify(SSL_CTX* ctx, SslCtxSetVerifyCallback callback); /* +Shims the SSL_set_verify method. +*/ +PALEXPORT void CryptoNative_SslSetVerifyPeer(SSL* ssl); + +/* +Shims SSL_set_ex_data to attach application context. +*/ +PALEXPORT int32_t CryptoNative_SslSetData(SSL* ssl, void *ptr); + +/* +Shims SSL_get_ex_data to retrieve application context. +*/ +PALEXPORT void* CryptoNative_SslGetData(SSL* ssl); + +/* + Sets the specified encryption policy on the SSL_CTX. */ -PALEXPORT int32_t CryptoNative_SetEncryptionPolicy(SSL_CTX* ctx, EncryptionPolicy policy); +PALEXPORT int32_t CryptoNative_SslCtxSetEncryptionPolicy(SSL_CTX* ctx, EncryptionPolicy policy); /* Sets ciphers (< TLS 1.3) and cipher suites (TLS 1.3) on the SSL_CTX */ -PALEXPORT int32_t CryptoNative_SetCiphers(SSL_CTX* ctx, const char* cipherList, const char* cipherSuites); +PALEXPORT int32_t CryptoNative_SslCtxSetCiphers(SSL_CTX* ctx, const char* cipherList, const char* cipherSuites); +PALEXPORT int32_t CryptoNative_SetCiphers(SSL* ssl, const char* cipherList, const char* cipherSuites); /* Determines if TLS 1.3 is supported by this OpenSSL implementation @@ -349,12 +366,12 @@ Shims the SSL_session_reused macro. PALEXPORT int32_t CryptoNative_SslSessionReused(SSL* ssl); /* -adds the given certificate to the extra chain certificates associated with ctx that is associated with the ssl. +adds the given certificate to the extra chain certificates associated with ctx. libssl frees the x509 object. Returns 1 if success and 0 in case of failure */ -PALEXPORT int32_t CryptoNative_SslAddExtraChainCert(SSL* ssl, X509* x509); +PALEXPORT int32_t CryptoNative_SslCtxAddExtraChainCert(SSL_CTX* ctx, X509* x509); /* Shims the ssl_ctx_set_alpn_select_cb method. @@ -362,10 +379,10 @@ Shims the ssl_ctx_set_alpn_select_cb method. PALEXPORT void CryptoNative_SslCtxSetAlpnSelectCb(SSL_CTX* ctx, SslCtxSetAlpnCallback cb, void *arg); /* -Shims the ssl_ctx_set_alpn_protos method. +Shims the ssl_set_alpn_protos method. Returns 0 on success, non-zero on failure. */ -PALEXPORT int32_t CryptoNative_SslCtxSetAlpnProtos(SSL_CTX* ctx, const uint8_t* protos, uint32_t protos_len); +PALEXPORT int32_t CryptoNative_SslSetAlpnProtos(SSL* ssl, const uint8_t* protos, uint32_t protos_len); /* Shims the ssl_get0_alpn_selected method. diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index f6bcf3faacba20..516b4ddeb54693 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -596,6 +596,8 @@ Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Ssl.cs" /> + + 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 60c21f69a2cfde..aaf56dd14bed4f 100644 --- a/src/libraries/System.Net.Security/src/System.Net.Security.csproj +++ b/src/libraries/System.Net.Security/src/System.Net.Security.csproj @@ -367,7 +367,7 @@ - + diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Android.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Android.cs new file mode 100644 index 00000000000000..facb437f02b42f --- /dev/null +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Android.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Security.Cryptography.X509Certificates; + +namespace System.Net.Security +{ + public partial class SslStreamCertificateContext + { + private const bool TrimRootCertificate = true; + + private SslStreamCertificateContext(X509Certificate2 target, X509Certificate2[] intermediates, SslCertificateTrust? trust) + { + Certificate = target; + IntermediateCertificates = intermediates; + Trust = trust; + } + + internal static SslStreamCertificateContext Create(X509Certificate2 target) => Create(target, null); + } +} diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Linux.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Linux.cs index facb437f02b42f..0b40ccc367e842 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Linux.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Linux.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Win32.SafeHandles; +using System.Collections.Concurrent; +using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; namespace System.Net.Security @@ -8,12 +11,14 @@ namespace System.Net.Security public partial class SslStreamCertificateContext { private const bool TrimRootCertificate = true; + internal readonly ConcurrentDictionary SslContexts; private SslStreamCertificateContext(X509Certificate2 target, X509Certificate2[] intermediates, SslCertificateTrust? trust) { Certificate = target; IntermediateCertificates = intermediates; Trust = trust; + SslContexts = new ConcurrentDictionary(); } internal static SslStreamCertificateContext Create(X509Certificate2 target) => Create(target, null); diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs index c3b2e7e291e89f..78b6cf47405c3e 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs @@ -39,7 +39,7 @@ public static SecurityStatusPal InitializeSecurityContext(ref SafeFreeCredential public static SafeFreeCredentials AcquireCredentialsHandle(SslStreamCertificateContext? certificateContext, SslProtocols protocols, EncryptionPolicy policy, bool isServer) { - return new SafeFreeSslCredentials(certificateContext?.Certificate, protocols, policy); + return new SafeFreeSslCredentials(certificateContext, protocols, policy, isServer); } public static SecurityStatusPal EncryptMessage(SafeDeleteSslContext securityContext, ReadOnlyMemory input, int headerSize, int trailerSize, ref byte[] output, out int resultSize)