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 0ff798bedd50f0..826d39abc09e1f 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 @@ -150,11 +150,8 @@ private static SslProtocols CalculateEffectiveProtocols(SslAuthenticationOptions } // This essentially wraps SSL_CTX* aka SSL_CTX_new + setting - internal static unsafe SafeSslContextHandle AllocateSslContext(SafeFreeSslCredentials credential, SslAuthenticationOptions sslAuthenticationOptions, SslProtocols protocols, bool enableResume) + internal static unsafe SafeSslContextHandle AllocateSslContext(SslAuthenticationOptions sslAuthenticationOptions, SslProtocols protocols, bool enableResume) { - SafeX509Handle? certHandle = credential.CertHandle; - SafeEvpPKeyHandle? certKeyHandle = credential.CertKeyHandle; - // 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. @@ -225,17 +222,10 @@ internal static unsafe SafeSslContextHandle AllocateSslContext(SafeFreeSslCreden Interop.Ssl.SslCtxSetAlpnSelectCb(sslCtx, &AlpnServerSelectCallback, IntPtr.Zero); } - bool hasCertificateAndKey = - certHandle != null && !certHandle.IsInvalid - && certKeyHandle != null && !certKeyHandle.IsInvalid; - - if (hasCertificateAndKey) - { - SetSslCertificate(sslCtx, certHandle!, certKeyHandle!); - } - if (sslAuthenticationOptions.CertificateContext != null) { + SetSslCertificate(sslCtx, sslAuthenticationOptions.CertificateContext.CertificateHandle, sslAuthenticationOptions.CertificateContext.KeyHandle); + if (sslAuthenticationOptions.CertificateContext.IntermediateCertificates.Length > 0) { if (!Ssl.AddExtraChainCertificates(sslCtx, sslAuthenticationOptions.CertificateContext.IntermediateCertificates)) @@ -269,20 +259,16 @@ internal static void UpdateClientCertiticate(SafeSslHandle ssl, SslAuthenticatio return; } - var credential = new SafeFreeSslCredentials(sslAuthenticationOptions.CertificateContext, sslAuthenticationOptions.EnabledSslProtocols, sslAuthenticationOptions.EncryptionPolicy, sslAuthenticationOptions.IsServer); - SafeX509Handle? certHandle = credential.CertHandle; - SafeEvpPKeyHandle? certKeyHandle = credential.CertKeyHandle; + Debug.Assert(sslAuthenticationOptions.CertificateContext.CertificateHandle != null); + Debug.Assert(sslAuthenticationOptions.CertificateContext.KeyHandle != null); - Debug.Assert(certHandle != null); - Debug.Assert(certKeyHandle != null); - - int retVal = Ssl.SslUseCertificate(ssl, certHandle); + int retVal = Ssl.SslUseCertificate(ssl, sslAuthenticationOptions.CertificateContext.CertificateHandle); if (1 != retVal) { throw CreateSslException(SR.net_ssl_use_cert_failed); } - retVal = Ssl.SslUsePrivateKey(ssl, certKeyHandle); + retVal = Ssl.SslUsePrivateKey(ssl, sslAuthenticationOptions.CertificateContext.KeyHandle); if (1 != retVal) { throw CreateSslException(SR.net_ssl_use_private_key_failed); @@ -295,11 +281,10 @@ internal static void UpdateClientCertiticate(SafeSslHandle ssl, SslAuthenticatio throw CreateSslException(SR.net_ssl_use_cert_failed); } } - } // This essentially wraps SSL* SSL_new() - internal static SafeSslHandle AllocateSslHandle(SafeFreeSslCredentials credential, SslAuthenticationOptions sslAuthenticationOptions) + internal static SafeSslHandle AllocateSslHandle(SslAuthenticationOptions sslAuthenticationOptions) { SafeSslHandle? sslHandle = null; SafeSslContextHandle? sslCtxHandle = null; @@ -352,7 +337,7 @@ internal static SafeSslHandle AllocateSslHandle(SafeFreeSslCredentials credentia if (sslCtxHandle == null) { // We did not get SslContext from cache - sslCtxHandle = newCtxHandle = AllocateSslContext(credential, sslAuthenticationOptions, protocols, cacheSslContext); + sslCtxHandle = newCtxHandle = AllocateSslContext(sslAuthenticationOptions, protocols, cacheSslContext); if (cacheSslContext) { 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 d4afcf1027dda3..bea9f4625a4ac0 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 @@ -327,7 +327,7 @@ internal enum SslErrorCode namespace Microsoft.Win32.SafeHandles { - internal sealed class SafeSslHandle : SafeHandle + internal sealed class SafeSslHandle : SafeDeleteSslContext { private SafeBioHandle? _readBio; private SafeBioHandle? _writeBio; diff --git a/src/libraries/Common/src/System/Net/Security/Unix/SafeDeleteContext.cs b/src/libraries/Common/src/System/Net/Security/Unix/SafeDeleteContext.cs index eab627c6afd9c0..b26e691ea40380 100644 --- a/src/libraries/Common/src/System/Net/Security/Unix/SafeDeleteContext.cs +++ b/src/libraries/Common/src/System/Net/Security/Unix/SafeDeleteContext.cs @@ -13,32 +13,21 @@ internal abstract class SafeDeleteContext : DebugSafeHandle internal abstract class SafeDeleteContext : SafeHandle { #endif - private SafeFreeCredentials _credential; - - protected SafeDeleteContext(SafeFreeCredentials credential) - : base(IntPtr.Zero, true) + public SafeDeleteContext(IntPtr handle) : base(handle, true) { - Debug.Assert((null != credential), "Invalid credential passed to SafeDeleteContext"); + } - // When a credential handle is first associated with the context we keep credential - // ref count bumped up to ensure ordered finalization. The credential properties - // are used in the SSL/NEGO data structures and should survive the lifetime of - // the SSL/NEGO context - bool ignore = false; - _credential = credential; - _credential.DangerousAddRef(ref ignore); + public SafeDeleteContext(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle) + { } public override bool IsInvalid { - get { return (null == _credential); } + get { return (IntPtr.Zero == handle); } } protected override bool ReleaseHandle() { - Debug.Assert((null != _credential), "Null credential in SafeDeleteContext"); - _credential.DangerousRelease(); - _credential = null!; return true; } } diff --git a/src/libraries/Common/src/System/Net/Security/Unix/SafeDeleteNegoContext.cs b/src/libraries/Common/src/System/Net/Security/Unix/SafeDeleteNegoContext.cs index c3316ee343538b..443e98e9de4b4f 100644 --- a/src/libraries/Common/src/System/Net/Security/Unix/SafeDeleteNegoContext.cs +++ b/src/libraries/Common/src/System/Net/Security/Unix/SafeDeleteNegoContext.cs @@ -15,6 +15,7 @@ internal sealed class SafeDeleteNegoContext : SafeDeleteContext private SafeGssNameHandle? _targetName; private SafeGssContextHandle _context; private bool _isNtlmUsed; + private SafeFreeNegoCredentials? _credential; public SafeGssCredHandle AcceptorCredential { @@ -42,14 +43,17 @@ public SafeGssContextHandle GssContext } public SafeDeleteNegoContext(SafeFreeNegoCredentials credential) - : base(credential) + : base(IntPtr.Zero) { Debug.Assert((null != credential), "Null credential in SafeDeleteNegoContext"); + bool added = false; + credential.DangerousAddRef(ref added); + _credential = credential; _context = new SafeGssContextHandle(); } public SafeDeleteNegoContext(SafeFreeNegoCredentials credential, string targetName) - : this(credential) + : base(IntPtr.Zero) { try { @@ -61,6 +65,9 @@ public SafeDeleteNegoContext(SafeFreeNegoCredentials credential, string targetNa Dispose(); throw; } + _credential = credential; + bool ignore = false; + _credential.DangerousAddRef(ref ignore); } public void SetGssContext(SafeGssContextHandle context) @@ -73,6 +80,11 @@ public void SetAuthenticationPackage(bool isNtlmUsed) _isNtlmUsed = isNtlmUsed; } + public override bool IsInvalid + { + get { return (null == _credential); } + } + protected override void Dispose(bool disposing) { if (disposing) @@ -93,5 +105,11 @@ protected override void Dispose(bool disposing) } base.Dispose(disposing); } + + protected override bool ReleaseHandle() + { + _credential?.DangerousRelease(); + return true; + } } } 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 f35a693a651535..0a870ef627327d 100644 --- a/src/libraries/Common/src/System/Net/Security/Unix/SafeDeleteSslContext.cs +++ b/src/libraries/Common/src/System/Net/Security/Unix/SafeDeleteSslContext.cs @@ -13,55 +13,14 @@ namespace System.Net.Security { - internal sealed class SafeDeleteSslContext : SafeDeleteContext + internal class SafeDeleteSslContext : SafeDeleteContext { - private SafeSslHandle _sslContext; - - public SafeSslHandle SslContext + public SafeDeleteSslContext(IntPtr handle) : base(handle, true) { - get - { - return _sslContext; - } - } - - public SafeDeleteSslContext(SafeFreeSslCredentials credential, SslAuthenticationOptions sslAuthenticationOptions) - : base(credential) - { - Debug.Assert((null != credential) && !credential.IsInvalid, "Invalid credential used in SafeDeleteSslContext"); - - try - { - _sslContext = Interop.OpenSsl.AllocateSslHandle(credential, sslAuthenticationOptions); - } - catch (Exception ex) - { - Debug.Write("Exception Caught. - " + ex); - Dispose(); - throw; - } } - public override bool IsInvalid + public SafeDeleteSslContext(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle) { - get - { - return (null == _sslContext) || _sslContext.IsInvalid; - } - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - if (null != _sslContext) - { - _sslContext.Dispose(); - _sslContext = null!; - } - } - - base.Dispose(disposing); } } } diff --git a/src/libraries/Common/src/System/Net/Security/Unix/SafeFreeNegoCredentials.cs b/src/libraries/Common/src/System/Net/Security/Unix/SafeFreeNegoCredentials.cs index 3f722378891643..4adf347cdfdb5b 100644 --- a/src/libraries/Common/src/System/Net/Security/Unix/SafeFreeNegoCredentials.cs +++ b/src/libraries/Common/src/System/Net/Security/Unix/SafeFreeNegoCredentials.cs @@ -44,7 +44,7 @@ public SafeFreeNegoCredentials(Interop.NetSecurityNative.PackageType packageType const char At = '@'; const char Backwhack = '\\'; - // any invalid user format will not be mnipulated and passed as it is. + // any invalid user format will not be manipulated and passed as it is. int index = username.IndexOf(Backwhack); if (index > 0 && username.IndexOf(Backwhack, index + 1) < 0 && string.IsNullOrEmpty(domain)) { diff --git a/src/libraries/Common/src/System/Net/Security/Unix/SafeFreeSslCredentials.cs b/src/libraries/Common/src/System/Net/Security/Unix/SafeFreeSslCredentials.cs deleted file mode 100644 index c509a7c4c5b5e1..00000000000000 --- a/src/libraries/Common/src/System/Net/Security/Unix/SafeFreeSslCredentials.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.Win32.SafeHandles; - -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Security.Authentication; -using System.Security.Authentication.ExtendedProtection; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; - -namespace System.Net.Security -{ - internal sealed class SafeFreeSslCredentials : SafeFreeCredentials - { - private SafeX509Handle? _certHandle; - private SafeEvpPKeyHandle? _certKeyHandle; - private SslProtocols _protocols = SslProtocols.None; - private EncryptionPolicy _policy; - private bool _isInvalid; - private SslStreamCertificateContext? _context; - - internal SafeX509Handle? CertHandle - { - get { return _certHandle; } - } - - internal SafeEvpPKeyHandle? CertKeyHandle - { - get { return _certKeyHandle; } - } - - internal SslProtocols Protocols - { - get { return _protocols; } - } - - internal EncryptionPolicy Policy - { - get { return _policy; } - } - - public SafeFreeSslCredentials(SslStreamCertificateContext? context, SslProtocols protocols, EncryptionPolicy policy, bool isServer) - : base(IntPtr.Zero, true) - { - - Debug.Assert( - context == null || context.Certificate is X509Certificate2, - "Only X509Certificate2 certificates are supported at this time"); - - X509Certificate2? cert = context?.Certificate; - - if (cert != null) - { - Debug.Assert(cert.HasPrivateKey, "cert.HasPrivateKey"); - - using (RSAOpenSsl? rsa = (RSAOpenSsl?)cert.GetRSAPrivateKey()) - { - if (rsa != null) - { - _certKeyHandle = rsa.DuplicateKeyHandle(); - Interop.Crypto.CheckValidOpenSslHandle(_certKeyHandle); - } - } - - if (_certKeyHandle == null) - { - using (ECDsaOpenSsl? ecdsa = (ECDsaOpenSsl?)cert.GetECDsaPrivateKey()) - { - if (ecdsa != null) - { - _certKeyHandle = ecdsa.DuplicateKeyHandle(); - Interop.Crypto.CheckValidOpenSslHandle(_certKeyHandle); - } - } - } - - if (_certKeyHandle == null) - { - throw new NotSupportedException(SR.net_ssl_io_no_server_cert); - } - - _certHandle = Interop.Crypto.X509UpRef(cert.Handle); - Interop.Crypto.CheckValidOpenSslHandle(_certHandle); - } - - _protocols = protocols; - _policy = policy; - _context = context; - } - - public override bool IsInvalid - { - get { return _isInvalid; } - } - - protected override bool ReleaseHandle() - { - _certHandle?.Dispose(); - _certKeyHandle?.Dispose(); - - _isInvalid = true; - return true; - } - } -} 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 c586e4e9c9a758..fb6b48dd4fb1fe 100644 --- a/src/libraries/System.Net.Security/src/System.Net.Security.csproj +++ b/src/libraries/System.Net.Security/src/System.Net.Security.csproj @@ -366,8 +366,6 @@ Link="Common\System\Net\Security\Unix\SafeDeleteSslContext.cs" /> - - @@ -416,7 +413,6 @@ - diff --git a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Unix.cs b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Unix.cs index 7e68a7c7f35c07..498a095410376a 100644 --- a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Unix.cs +++ b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Unix.cs @@ -58,7 +58,7 @@ internal static SslPolicyErrors VerifyCertificateProperties( } using (SafeSharedX509StackHandle chainStack = - Interop.OpenSsl.GetPeerCertificateChain(((SafeDeleteSslContext)securityContext).SslContext)) + Interop.OpenSsl.GetPeerCertificateChain((SafeSslHandle)securityContext)) { if (!chainStack.IsInvalid) { @@ -106,7 +106,7 @@ internal static SslPolicyErrors VerifyCertificateProperties( // internal static string[] GetRequestCertificateAuthorities(SafeDeleteContext securityContext) { - using (SafeSharedX509NameStackHandle names = Interop.Ssl.SslGetClientCAList(((SafeDeleteSslContext)securityContext).SslContext)) + using (SafeSharedX509NameStackHandle names = Interop.Ssl.SslGetClientCAList((SafeSslHandle)securityContext)) { if (names.IsInvalid) { @@ -160,7 +160,7 @@ private static int QueryContextRemoteCertificate(SafeDeleteContext securityConte remoteCertContext = null; try { - SafeX509Handle remoteCertificate = Interop.OpenSsl.GetPeerCertificate(((SafeDeleteSslContext)securityContext).SslContext); + SafeX509Handle remoteCertificate = Interop.OpenSsl.GetPeerCertificate((SafeSslHandle)securityContext); // Note that cert ownership is transferred to SafeFreeCertContext remoteCertContext = new SafeFreeCertContext(remoteCertificate); return 0; diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Android/SafeDeleteSslContext.cs b/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Android/SafeDeleteSslContext.cs index d653d56f115314..e4a2ee35c53d85 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Android/SafeDeleteSslContext.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Android/SafeDeleteSslContext.cs @@ -36,15 +36,13 @@ internal sealed class SafeDeleteSslContext : SafeDeleteContext public SafeSslHandle SslContext => _sslContext; - public SafeDeleteSslContext(SafeFreeSslCredentials credential, SslAuthenticationOptions authOptions) - : base(credential) + public SafeDeleteSslContext(SslAuthenticationOptions authOptions) + : base(IntPtr.Zero) { - Debug.Assert((credential != null) && !credential.IsInvalid, "Invalid credential used in SafeDeleteSslContext"); - try { - _sslContext = CreateSslContext(credential); - InitializeSslContext(_sslContext, credential, authOptions); + _sslContext = CreateSslContext(authOptions); + InitializeSslContext(_sslContext, authOptions); } catch (Exception ex) { @@ -147,14 +145,14 @@ internal int ReadPendingWrites(byte[] buf, int offset, int count) return limit; } - private static SafeSslHandle CreateSslContext(SafeFreeSslCredentials credential) + private static SafeSslHandle CreateSslContext(SslAuthenticationOptions authOptions) { - if (credential.CertificateContext == null) + if (authOptions.CertificateContext == null) { return Interop.AndroidCrypto.SSLStreamCreate(); } - SslStreamCertificateContext context = credential.CertificateContext; + SslStreamCertificateContext context = authOptions.CertificateContext; X509Certificate2 cert = context.Certificate; Debug.Assert(context.Certificate.HasPrivateKey); @@ -199,10 +197,9 @@ private static AsymmetricAlgorithm GetPrivateKeyAlgorithm(X509Certificate2 cert, private unsafe void InitializeSslContext( SafeSslHandle handle, - SafeFreeSslCredentials credential, SslAuthenticationOptions authOptions) { - switch (credential.Policy) + switch (authOptions.EncryptionPolicy) { case EncryptionPolicy.RequireEncryption: #pragma warning disable SYSLIB0040 // NoEncryption and AllowNoEncryption are obsolete @@ -210,7 +207,7 @@ private unsafe void InitializeSslContext( break; #pragma warning restore SYSLIB0040 default: - throw new PlatformNotSupportedException(SR.Format(SR.net_encryptionpolicy_notsupported, credential.Policy)); + throw new PlatformNotSupportedException(SR.Format(SR.net_encryptionpolicy_notsupported, authOptions.EncryptionPolicy)); } bool isServer = authOptions.IsServer; @@ -226,12 +223,12 @@ private unsafe void InitializeSslContext( IntPtr managedContextHandle = GCHandle.ToIntPtr(GCHandle.Alloc(this, GCHandleType.Weak)); Interop.AndroidCrypto.SSLStreamInitialize(handle, isServer, managedContextHandle, &ReadFromConnection, &WriteToConnection, InitialBufferSize); - if (credential.Protocols != SslProtocols.None) + if (authOptions.EnabledSslProtocols != SslProtocols.None) { - SslProtocols protocolsToEnable = credential.Protocols & s_supportedSslProtocols.Value; + SslProtocols protocolsToEnable = authOptions.EnabledSslProtocols & s_supportedSslProtocols.Value; if (protocolsToEnable == 0) { - throw new PlatformNotSupportedException(SR.Format(SR.net_security_sslprotocol_notsupported, credential.Protocols)); + throw new PlatformNotSupportedException(SR.Format(SR.net_security_sslprotocol_notsupported, authOptions.EnabledSslProtocols)); } (int minIndex, int maxIndex) = protocolsToEnable.ValidateContiguous(s_orderedSslProtocols); diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Managed/SafeFreeSslCredentials.cs b/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Managed/SafeFreeSslCredentials.cs deleted file mode 100644 index 24a4e7be7843a6..00000000000000 --- a/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Managed/SafeFreeSslCredentials.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; -using System.Net.Security; -using System.Security.Authentication; -using System.Security.Cryptography.X509Certificates; - -namespace System.Net -{ - internal sealed class SafeFreeSslCredentials : SafeFreeCredentials - { - public SafeFreeSslCredentials(SslStreamCertificateContext? certificateContext, SslProtocols protocols, EncryptionPolicy policy) - : base(IntPtr.Zero, true) - { - if (certificateContext != null) - { - // Make a defensive copy of the certificate. In some async cases the - // certificate can have been disposed before being provided to the handshake. - // - // This meshes with the Unix (OpenSSL) PAL, because it extracts the private key - // and cert handle (which get up-reffed) to match the API expectations. - certificateContext = certificateContext.Duplicate(); - - Debug.Assert(certificateContext.Certificate.HasPrivateKey, "cert clone.HasPrivateKey"); - } - - CertificateContext = certificateContext; - Protocols = protocols; - Policy = policy; - } - - public EncryptionPolicy Policy { get; } - - public SslProtocols Protocols { get; } - - public SslStreamCertificateContext? CertificateContext { get; } - - public override bool IsInvalid => false; - - protected override bool ReleaseHandle() - { - CertificateContext?.Certificate.Dispose(); - return true; - } - } -} diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs b/src/libraries/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs index bb4f84ce8de8ff..fd86353ed1fa58 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs @@ -25,16 +25,14 @@ internal sealed class SafeDeleteSslContext : SafeDeleteContext public SafeSslHandle SslContext => _sslContext; - public SafeDeleteSslContext(SafeFreeSslCredentials credential, SslAuthenticationOptions sslAuthenticationOptions) - : base(credential) + public SafeDeleteSslContext(SslAuthenticationOptions sslAuthenticationOptions) + : base(IntPtr.Zero) { - Debug.Assert((null != credential) && !credential.IsInvalid, "Invalid credential used in SafeDeleteSslContext"); - try { int osStatus; - _sslContext = CreateSslContext(credential, sslAuthenticationOptions); + _sslContext = CreateSslContext(sslAuthenticationOptions); // Make sure the class instance is associated to the session and is provided // in the Read/Write callback connection parameter @@ -129,9 +127,9 @@ public SafeDeleteSslContext(SafeFreeSslCredentials credential, SslAuthentication } } - private static SafeSslHandle CreateSslContext(SafeFreeSslCredentials credential, SslAuthenticationOptions sslAuthenticationOptions) + private static SafeSslHandle CreateSslContext(SslAuthenticationOptions sslAuthenticationOptions) { - switch (credential.Policy) + switch (sslAuthenticationOptions.EncryptionPolicy) { case EncryptionPolicy.RequireEncryption: #pragma warning disable SYSLIB0040 // NoEncryption and AllowNoEncryption are obsolete @@ -142,7 +140,7 @@ private static SafeSslHandle CreateSslContext(SafeFreeSslCredentials credential, break; #pragma warning restore SYSLIB0040 default: - throw new PlatformNotSupportedException(SR.Format(SR.net_encryptionpolicy_notsupported, credential.Policy)); + throw new PlatformNotSupportedException(SR.Format(SR.net_encryptionpolicy_notsupported, sslAuthenticationOptions.EncryptionPolicy)); } SafeSslHandle sslContext = Interop.AppleCrypto.SslCreateContext(sslAuthenticationOptions.IsServer ? 1 : 0); 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 4f9a09347b7454..ac8db67ba27753 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 @@ -687,11 +687,11 @@ private bool AcquireServerCredentials(ref byte[]? thumbPrint) return cachedCred; } - private static SafeFreeCredentials AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions) + private static SafeFreeCredentials? AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions) { - SafeFreeCredentials cred = SslStreamPal.AcquireCredentialsHandle(sslAuthenticationOptions); + SafeFreeCredentials? cred = SslStreamPal.AcquireCredentialsHandle(sslAuthenticationOptions); - if (sslAuthenticationOptions.CertificateContext != null) + if (sslAuthenticationOptions.CertificateContext != null && cred != null) { // // Since the SafeFreeCredentials can be cached and reused, it may happen on long running processes that some cert on @@ -869,6 +869,8 @@ private SecurityStatusPal GenerateToken(ReadOnlySpan inputBuffer, ref byte internal SecurityStatusPal Renegotiate(out byte[]? output) { + Debug.Assert(_securityContext != null); + return SslStreamPal.Renegotiate( ref _credentialsHandle!, ref _securityContext, 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 dedea329f240eb..fdc98705d426b2 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 @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Security.Authentication; +using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; @@ -17,6 +18,8 @@ public partial class SslStreamCertificateContext { private const bool TrimRootCertificate = true; internal readonly ConcurrentDictionary SslContexts; + internal readonly SafeX509Handle CertificateHandle; + internal readonly SafeEvpPKeyHandle KeyHandle; private bool _staplingForbidden; private byte[]? _ocspResponse; @@ -32,6 +35,32 @@ private SslStreamCertificateContext(X509Certificate2 target, X509Certificate2[] IntermediateCertificates = intermediates; Trust = trust; SslContexts = new ConcurrentDictionary(); + + using (RSAOpenSsl? rsa = (RSAOpenSsl?)target.GetRSAPrivateKey()) + { + if (rsa != null) + { + KeyHandle = rsa.DuplicateKeyHandle(); + } + } + + if (KeyHandle == null) + { + using (ECDsaOpenSsl? ecdsa = (ECDsaOpenSsl?)target.GetECDsaPrivateKey()) + { + if (ecdsa != null) + { + KeyHandle = ecdsa.DuplicateKeyHandle(); + } + } + + if (KeyHandle== null) + { + throw new NotSupportedException(SR.net_ssl_io_no_server_cert); + } + } + + CertificateHandle = Interop.Crypto.X509UpRef(target.Handle); } internal static SslStreamCertificateContext Create(X509Certificate2 target) => diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Android.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Android.cs index 11889b0836f8c0..f01dd68e294b2d 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Android.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Android.cs @@ -55,12 +55,9 @@ public static SecurityStatusPal Renegotiate( throw new PlatformNotSupportedException(); } - public static SafeFreeCredentials AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions) + public static SafeFreeCredentials? AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions) { - return new SafeFreeSslCredentials( - sslAuthenticationOptions.CertificateContext, - sslAuthenticationOptions.EnabledSslProtocols, - sslAuthenticationOptions.EncryptionPolicy); + return null; } public static SecurityStatusPal EncryptMessage( @@ -177,15 +174,13 @@ private static SecurityStatusPal HandshakeInternal( ref byte[]? outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { - Debug.Assert(!credential.IsInvalid); - try { SafeDeleteSslContext? sslContext = ((SafeDeleteSslContext?)context); if ((context == null) || context.IsInvalid) { - context = new SafeDeleteSslContext((credential as SafeFreeSslCredentials)!, sslAuthenticationOptions); + context = new SafeDeleteSslContext(sslAuthenticationOptions); sslContext = context; } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs index 5c96b2550ce821..255b30d7f2c2fe 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs @@ -62,12 +62,9 @@ public static SecurityStatusPal Renegotiate( throw new PlatformNotSupportedException(); } - public static SafeFreeCredentials AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions) + public static SafeFreeCredentials? AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions) { - return new SafeFreeSslCredentials( - sslAuthenticationOptions.CertificateContext, - sslAuthenticationOptions.EnabledSslProtocols, - sslAuthenticationOptions.EncryptionPolicy); + return null; } public static SecurityStatusPal EncryptMessage( @@ -227,15 +224,13 @@ private static SecurityStatusPal HandshakeInternal( SslAuthenticationOptions sslAuthenticationOptions, SelectClientCertificate? clientCertificateSelectionCallback) { - Debug.Assert(!credential.IsInvalid); - try { SafeDeleteSslContext? sslContext = ((SafeDeleteSslContext?)context); if ((null == context) || context.IsInvalid) { - sslContext = new SafeDeleteSslContext((credential as SafeFreeSslCredentials)!, sslAuthenticationOptions); + sslContext = new SafeDeleteSslContext(sslAuthenticationOptions); context = sslContext; } 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 7a4f5a67f0fa94..1e1a0df55889e9 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 @@ -31,7 +31,7 @@ public static SecurityStatusPal AcceptSecurityContext( ref byte[]? outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { - return HandshakeInternal(credential!, ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions, null); + return HandshakeInternal(ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions, null); } public static SecurityStatusPal InitializeSecurityContext( @@ -43,23 +43,19 @@ public static SecurityStatusPal InitializeSecurityContext( SslAuthenticationOptions sslAuthenticationOptions, SelectClientCertificate? clientCertificateSelectionCallback) { - return HandshakeInternal(credential!, ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions, clientCertificateSelectionCallback); + return HandshakeInternal(ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions, clientCertificateSelectionCallback); } - public static SafeFreeCredentials AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions) + public static SafeFreeCredentials? AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions) { - return new SafeFreeSslCredentials( - sslAuthenticationOptions.CertificateContext, - sslAuthenticationOptions.EnabledSslProtocols, - sslAuthenticationOptions.EncryptionPolicy, - sslAuthenticationOptions.IsServer); + return null; } public static SecurityStatusPal EncryptMessage(SafeDeleteSslContext securityContext, ReadOnlyMemory input, int headerSize, int trailerSize, ref byte[] output, out int resultSize) { try { - resultSize = Interop.OpenSsl.Encrypt(securityContext.SslContext, input.Span, ref output, out Interop.Ssl.SslErrorCode errorCode); + resultSize = Interop.OpenSsl.Encrypt((SafeSslHandle)securityContext, input.Span, ref output, out Interop.Ssl.SslErrorCode errorCode); return MapNativeErrorCode(errorCode); } @@ -77,7 +73,7 @@ public static SecurityStatusPal DecryptMessage(SafeDeleteSslContext securityCont try { - int resultSize = Interop.OpenSsl.Decrypt(securityContext.SslContext, buffer, out Interop.Ssl.SslErrorCode errorCode); + int resultSize = Interop.OpenSsl.Decrypt((SafeSslHandle)securityContext, buffer, out Interop.Ssl.SslErrorCode errorCode); SecurityStatusPal retVal = MapNativeErrorCode(errorCode); @@ -122,7 +118,7 @@ Interop.Ssl.SslErrorCode.SSL_ERROR_NONE or else { bindingHandle = Interop.OpenSsl.QueryChannelBinding( - securityContext.SslContext, + (SafeSslHandle)securityContext, attribute); } @@ -131,19 +127,18 @@ Interop.Ssl.SslErrorCode.SSL_ERROR_NONE or public static SecurityStatusPal Renegotiate( ref SafeFreeCredentials? credentialsHandle, - ref SafeDeleteSslContext? securityContext, + ref SafeDeleteSslContext context, SslAuthenticationOptions sslAuthenticationOptions, out byte[]? outputBuffer) { - var sslContext = ((SafeDeleteSslContext)securityContext!).SslContext; - SecurityStatusPal status = Interop.OpenSsl.SslRenegotiate(sslContext, out _); + SecurityStatusPal status = Interop.OpenSsl.SslRenegotiate((SafeSslHandle)context, out _); outputBuffer = Array.Empty(); if (status.ErrorCode != SecurityStatusPalErrorCode.OK) { return status; } - return HandshakeInternal(credentialsHandle!, ref securityContext, null, ref outputBuffer, sslAuthenticationOptions, null); + return HandshakeInternal(ref context!, null, ref outputBuffer, sslAuthenticationOptions, null); } public static void QueryContextStreamSizes(SafeDeleteContext? securityContext, out StreamSizes streamSizes) @@ -153,14 +148,12 @@ public static void QueryContextStreamSizes(SafeDeleteContext? securityContext, o public static void QueryContextConnectionInfo(SafeDeleteSslContext securityContext, ref SslConnectionInfo connectionInfo) { - connectionInfo.UpdateSslConnectionInfo(securityContext.SslContext); + connectionInfo.UpdateSslConnectionInfo((SafeSslHandle)securityContext); } - private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credential, ref SafeDeleteSslContext? context, + private static SecurityStatusPal HandshakeInternal(ref SafeDeleteSslContext? context, ReadOnlySpan inputBuffer, ref byte[]? outputBuffer, SslAuthenticationOptions sslAuthenticationOptions, SelectClientCertificate? clientCertificateSelectionCallback) { - Debug.Assert(!credential.IsInvalid); - byte[]? output = null; int outputSize = 0; @@ -168,10 +161,10 @@ private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credentia { if ((null == context) || context.IsInvalid) { - context = new SafeDeleteSslContext((credential as SafeFreeSslCredentials)!, sslAuthenticationOptions); + context = Interop.OpenSsl.AllocateSslHandle(sslAuthenticationOptions); } - SecurityStatusPalErrorCode errorCode = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, inputBuffer, out output, out outputSize); + SecurityStatusPalErrorCode errorCode = Interop.OpenSsl.DoSslHandshake((SafeSslHandle)context, inputBuffer, out output, out outputSize); if (errorCode == SecurityStatusPalErrorCode.CredentialsNeeded && clientCertificateSelectionCallback != null) { @@ -181,22 +174,22 @@ private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credentia sslAuthenticationOptions.CertificateContext = SslStreamCertificateContext.Create(clientCertificate); } - Interop.OpenSsl.UpdateClientCertiticate(((SafeDeleteSslContext)context).SslContext, sslAuthenticationOptions); - errorCode = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, null, out output, out outputSize); + Interop.OpenSsl.UpdateClientCertiticate((SafeSslHandle)context, sslAuthenticationOptions); + errorCode = Interop.OpenSsl.DoSslHandshake((SafeSslHandle)context, null, out output, out outputSize); } // sometimes during renegotiation processing message does not yield new output. // That seems to be flaw in OpenSSL state machine and we have workaround to peek it and try it again. - if (outputSize == 0 && Interop.Ssl.IsSslRenegotiatePending(((SafeDeleteSslContext)context).SslContext)) + if (outputSize == 0 && Interop.Ssl.IsSslRenegotiatePending((SafeSslHandle)context)) { - errorCode = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, ReadOnlySpan.Empty, out output, out outputSize); + errorCode = Interop.OpenSsl.DoSslHandshake((SafeSslHandle)context, ReadOnlySpan.Empty, out output, out outputSize); } // When the handshake is done, and the context is server, check if the alpnHandle target was set to null during ALPN. // If it was, then that indicates ALPN failed, send failure. // We have this workaround, as openssl supports terminating handshake only from version 1.1.0, // whereas ALPN is supported from version 1.0.2. - SafeSslHandle sslContext = context.SslContext; + SafeSslHandle sslContext = (SafeSslHandle)context; if (errorCode == SecurityStatusPalErrorCode.OK && sslAuthenticationOptions.IsServer && sslAuthenticationOptions.ApplicationProtocols != null && sslAuthenticationOptions.ApplicationProtocols.Count != 0 && sslContext.AlpnHandle.IsAllocated && sslContext.AlpnHandle.Target == null) @@ -231,22 +224,22 @@ public static SecurityStatusPal ApplyAlertToken(ref SafeFreeCredentials? credent return new SecurityStatusPal(SecurityStatusPalErrorCode.OK); } - public static SecurityStatusPal ApplyShutdownToken(ref SafeFreeCredentials? credentialsHandle, SafeDeleteSslContext sslContext) + public static SecurityStatusPal ApplyShutdownToken(ref SafeFreeCredentials? credentialsHandle, SafeDeleteSslContext context) { // Unset the quiet shutdown option initially configured. - Interop.Ssl.SslSetQuietShutdown(sslContext.SslContext, 0); + Interop.Ssl.SslSetQuietShutdown((SafeSslHandle)context, 0); - int status = Interop.Ssl.SslShutdown(sslContext.SslContext); + int status = Interop.Ssl.SslShutdown((SafeSslHandle)context); if (status == 0) { // Call SSL_shutdown again for a bi-directional shutdown. - status = Interop.Ssl.SslShutdown(sslContext.SslContext); + status = Interop.Ssl.SslShutdown((SafeSslHandle)context); } if (status == 1) return new SecurityStatusPal(SecurityStatusPalErrorCode.OK); - Interop.Ssl.SslErrorCode code = Interop.Ssl.SslGetError(sslContext.SslContext, status); + Interop.Ssl.SslErrorCode code = Interop.Ssl.SslGetError((SafeSslHandle)context, status); if (code == Interop.Ssl.SslErrorCode.SSL_ERROR_WANT_READ || code == Interop.Ssl.SslErrorCode.SSL_ERROR_WANT_WRITE) {