diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/ISSPIInterface.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/ISSPIInterface.cs index ccaca072c6bf8b..f504e175cfdc78 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/ISSPIInterface.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/ISSPIInterface.cs @@ -22,6 +22,7 @@ internal interface ISSPIInterface int QueryContextChannelBinding(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, out SafeFreeContextBufferChannelBinding refHandle); int QueryContextAttributes(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, Span buffer, Type? handleType, out SafeHandle? refHandle); + unsafe int QueryContextAttributes(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, IntPtr* refHandle); int QuerySecurityContextToken(SafeDeleteContext phContext, out SecurityContextTokenHandle phToken); int CompleteAuthToken(ref SafeDeleteSslContext? refContext, in InputSecurityBuffer inputBuffer); int ApplyControlToken(ref SafeDeleteSslContext? refContext, in SecurityBuffer inputBuffer); diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIAuthType.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIAuthType.cs index 387dbef10abca6..2f24afa114b0b4 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIAuthType.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIAuthType.cs @@ -106,6 +106,11 @@ public int QueryContextChannelBinding(SafeDeleteContext context, Interop.SspiCli throw new NotSupportedException(); } + public unsafe int QueryContextAttributes(SafeDeleteContext context, Interop.SspiCli.ContextAttribute attribute, IntPtr* refHandle) + { + return SafeFreeContextBuffer.QueryContextAttributes(context, attribute, refHandle); + } + public unsafe int QueryContextAttributes(SafeDeleteContext context, Interop.SspiCli.ContextAttribute attribute, Span buffer, Type? handleType, out SafeHandle? refHandle) { refHandle = null; @@ -115,10 +120,6 @@ public unsafe int QueryContextAttributes(SafeDeleteContext context, Interop.Sspi { refHandle = SafeFreeContextBuffer.CreateEmptyHandle(); } - else if (handleType == typeof(SafeFreeCertContext)) - { - refHandle = new SafeFreeCertContext(); - } else { throw new ArgumentException(SR.Format(SR.SSPIInvalidHandleType, handleType.FullName), nameof(handleType)); diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPISecureChannelType.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPISecureChannelType.cs index 3ca74bf7dfe1fa..90e40a5dc0556f 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPISecureChannelType.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPISecureChannelType.cs @@ -108,6 +108,11 @@ public unsafe int QueryContextChannelBinding(SafeDeleteContext phContext, Intero return SafeFreeContextBufferChannelBinding.QueryContextChannelBinding(phContext, attribute, &bindings, refHandle); } + public unsafe int QueryContextAttributes(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, IntPtr* refHandle) + { + return SafeFreeContextBuffer.QueryContextAttributes(phContext, attribute, refHandle); + } + public unsafe int QueryContextAttributes(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, Span buffer, Type? handleType, out SafeHandle? refHandle) { refHandle = null; diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs index 014e357bc23eaf..b41a8b3ce20eac 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs @@ -270,29 +270,42 @@ public static bool QueryBlittableContextAttributes(ISSPIInterface secModule, } } - private static bool QueryCertContextAttribute(ISSPIInterface secModule, SafeDeleteContext securityContext, Interop.SspiCli.ContextAttribute attribute, out SafeFreeCertContext? certContext) + private static unsafe bool QueryCertContextAttribute(ISSPIInterface secModule, SafeDeleteContext securityContext, Interop.SspiCli.ContextAttribute attribute, out SafeFreeCertContext? certContext) { - Span buffer = stackalloc IntPtr[1]; - int errorCode = secModule.QueryContextAttributes( - securityContext, - attribute, - MemoryMarshal.AsBytes(buffer), - typeof(SafeFreeCertContext), - out SafeHandle? sspiHandle); + IntPtr handle = IntPtr.Zero; + certContext = null; - // certificate is not always present (e.g. on server when querying client certificate) - // but we still want to consider such case as a success. - bool success = errorCode == 0 || errorCode == (int)Interop.SECURITY_STATUS.NoCredentials; + try + { + int errorCode = secModule.QueryContextAttributes( + securityContext, + attribute, + &handle); + + // certificate is not always present (e.g. on server when querying client certificate) + // but we still want to consider such case as a success. + bool success = errorCode == 0 || errorCode == (int)Interop.SECURITY_STATUS.NoCredentials; - if (!success) + if (errorCode == 0 && handle != IntPtr.Zero) + { + certContext = new SafeFreeCertContext(); + certContext.Set(handle); + // Handle was successfully transferred to SafeHandle + handle = IntPtr.Zero; + } + if (!success) + { + if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(null, $"ERROR = {ErrorDescription(errorCode)}"); + } + return success; + } + finally { - sspiHandle?.Dispose(); - sspiHandle = null; - if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(null, $"ERROR = {ErrorDescription(errorCode)}"); + if (handle != IntPtr.Zero) + { + Interop.Crypt32.CertFreeCertificateContext(handle); + } } - - certContext = sspiHandle as SafeFreeCertContext; - return success; } public static bool QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CONTEXT(ISSPIInterface secModule, SafeDeleteContext securityContext, out SafeFreeCertContext? certContext) diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs index 4b0e0f4f689cb2..589bc56352bb7f 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs @@ -65,6 +65,23 @@ internal static SafeFreeContextBuffer CreateEmptyHandle() return new SafeFreeContextBuffer_SECURITY(); } + public static unsafe int QueryContextAttributes(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute contextAttribute, IntPtr* handle) + { + bool mustRelease = false; + try + { + phContext.DangerousAddRef(ref mustRelease); + return Interop.SspiCli.QueryContextAttributesW(ref phContext._handle, contextAttribute, handle); + } + finally + { + if (mustRelease) + { + phContext.DangerousRelease(); + } + } + } + // // After PInvoke call the method will fix the refHandle.handle with the returned value. // The caller is responsible for creating a correct SafeHandle template or null can be passed if no handle is returned. @@ -98,7 +115,7 @@ public static unsafe int QueryContextAttributes(SafeDeleteContext phContext, Int } else { - ((SafeFreeCertContext)refHandle).Set(*(IntPtr*)buffer); + Debug.Assert(false); } } diff --git a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Windows.cs index a3254540047f37..27224b4e4be046 100644 --- a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Windows.cs @@ -111,10 +111,9 @@ internal static bool IsLocalCertificateUsed(SafeFreeCredentials? _credentialsHan SafeFreeCertContext? localContext = null; try { - if (SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_LOCAL_CERT_CONTEXT(GlobalSSPI.SSPISecureChannel, securityContext, out localContext) && - localContext != null) + if (SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_LOCAL_CERT_CONTEXT(GlobalSSPI.SSPISecureChannel, securityContext, out localContext)) { - return !localContext.IsInvalid; + return localContext != null ? !localContext.IsInvalid : false; } } finally 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 a9fe7f0a4e741d..b04a0571f0a53d 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 @@ -119,6 +119,7 @@ public static ProtocolToken AcceptSecurityContext( } ProtocolToken token = default; + token.RentBuffer = true; int errorCode = SSPIWrapper.AcceptSecurityContext( GlobalSSPI.SSPISecureChannel, @@ -163,6 +164,7 @@ public static ProtocolToken InitializeSecurityContext( } ProtocolToken token = default; + token.RentBuffer = true; int errorCode = SSPIWrapper.InitializeSecurityContext( GlobalSSPI.SSPISecureChannel, ref credentialsHandle,