diff --git a/src/Common/src/Interop/Unix/System.Net.Security.Native/SecuritySafeHandles.cs b/src/Common/src/Interop/Unix/System.Net.Security.Native/SecuritySafeHandles.cs new file mode 100644 index 000000000000..e4e07954e02c --- /dev/null +++ b/src/Common/src/Interop/Unix/System.Net.Security.Native/SecuritySafeHandles.cs @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; +using Microsoft.Win32.SafeHandles; + +namespace System.Net.Security +{ + internal sealed class SafeFreeNegoCredentials : SafeFreeCredentials + { + private SafeGssCredHandle _credential; + + public SafeGssCredHandle GssCredential + { + get { return _credential; } + } + + public SafeFreeNegoCredentials(string username, string password, string domain) : base(IntPtr.Zero, true) + { + bool ignore = false; + _credential = SafeGssCredHandle.Create(username, password, domain); + _credential.DangerousAddRef(ref ignore); + } + + public override bool IsInvalid + { + get { return (null == _credential); } + } + + protected override bool ReleaseHandle() + { + _credential.DangerousRelease(); + _credential = null; + return true; + } + } + + internal sealed class SafeDeleteNegoContext : SafeDeleteContext + { + private SafeGssNameHandle _targetName; + private SafeGssContextHandle _context; + + public SafeGssNameHandle TargetName + { + get { return _targetName; } + } + + public SafeGssContextHandle GssContext + { + get { return _context; } + } + + public SafeDeleteNegoContext(SafeFreeNegoCredentials credential, string targetName) + : base(credential) + { + try + { + _targetName = SafeGssNameHandle.CreatePrincipal(targetName); + } + catch + { + Debug.Assert((null != credential), "Null credential in SafeDeleteNegoContext"); + Dispose(); + throw; + } + } + + public void SetGssContext(SafeGssContextHandle context) + { + Debug.Assert(!context.IsInvalid, "Invalid context passed to SafeDeleteNegoContext"); + _context = context; + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (null != _context) + { + _context.Dispose(); + _context = null; + } + + if (_targetName != null) + { + _targetName.Dispose(); + _targetName = null; + } + } + base.Dispose(disposing); + } + } +} diff --git a/src/Common/src/Interop/Unix/libssl/SecuritySafeHandles.cs b/src/Common/src/Interop/Unix/libssl/SecuritySafeHandles.cs index c0a7a062462d..0ee431792647 100644 --- a/src/Common/src/Interop/Unix/libssl/SecuritySafeHandles.cs +++ b/src/Common/src/Interop/Unix/libssl/SecuritySafeHandles.cs @@ -56,12 +56,19 @@ protected override bool ReleaseHandle() // Implementation of handles dependable on FreeCredentialsHandle // #if DEBUG - internal sealed class SafeFreeCredentials : DebugSafeHandle + internal abstract class SafeFreeCredentials : DebugSafeHandle { #else - internal sealed class SafeFreeCredentials : SafeHandle + internal abstract class SafeFreeCredentials : SafeHandle { #endif + protected SafeFreeCredentials(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle) + { + } + } + + internal sealed class SafeFreeSslCredentials : SafeFreeCredentials + { private SafeX509Handle _certHandle; private SafeEvpPKeyHandle _certKeyHandle; private SslProtocols _protocols = SslProtocols.None; @@ -87,7 +94,7 @@ internal EncryptionPolicy Policy get { return _policy; } } - public SafeFreeCredentials(X509Certificate certificate, SslProtocols protocols, EncryptionPolicy policy) + public SafeFreeSslCredentials(X509Certificate certificate, SslProtocols protocols, EncryptionPolicy policy) : base(IntPtr.Zero, true) { Debug.Assert( @@ -207,14 +214,50 @@ protected override bool ReleaseHandle() } #if DEBUG - internal sealed class SafeDeleteContext : DebugSafeHandle + internal abstract class SafeDeleteContext : DebugSafeHandle { #else - internal sealed class SafeDeleteContext : SafeHandle + internal abstract class SafeDeleteContext : SafeHandle { #endif - private readonly SafeFreeCredentials _credential; - private readonly SafeSslHandle _sslContext; + private SafeFreeCredentials _credential; + + protected SafeDeleteContext(SafeFreeCredentials credential) + : base(IntPtr.Zero, 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 override bool IsInvalid + { + get { return (null == _credential); } + } + + protected override bool ReleaseHandle() + { + Debug.Assert((null != _credential), "Null credential in SafeDeleteContext"); + _credential.DangerousRelease(); + _credential = null; + return true; + } + + public override string ToString() + { + return handle.ToString(); + } + } + + internal sealed class SafeDeleteSslContext : SafeDeleteContext + { + private SafeSslHandle _sslContext; public SafeSslHandle SslContext { @@ -224,18 +267,10 @@ public SafeSslHandle SslContext } } - public SafeDeleteContext(SafeFreeCredentials credential, bool isServer, bool remoteCertRequired) - : base(IntPtr.Zero, true) + public SafeDeleteSslContext(SafeFreeSslCredentials credential, bool isServer, bool remoteCertRequired) + : base(credential) { - Debug.Assert((null != credential) && !credential.IsInvalid, "Invalid credential used in SafeDeleteContext"); - - // When a credential handle is first associated with the context we keep credential - // ref count bumped up to ensure ordered finalization. The certificate handle and - // key handle are used in the SSL data structures and should survive the lifetime of - // the SSL context - bool gotCredRef = false; - _credential = credential; - _credential.DangerousAddRef(ref gotCredRef); + Debug.Assert((null != credential) && !credential.IsInvalid, "Invalid credential used in SafeDeleteSslContext"); try { @@ -249,11 +284,8 @@ public SafeDeleteContext(SafeFreeCredentials credential, bool isServer, bool rem } catch(Exception ex) { - if (gotCredRef) - { - _credential.DangerousRelease(); - } Debug.Write("Exception Caught. - " + ex); + Dispose(); throw; } } @@ -266,18 +298,15 @@ public override bool IsInvalid } } - protected override bool ReleaseHandle() - { - Debug.Assert((null != _credential) && !_credential.IsInvalid, "Invalid credential saved in SafeDeleteContext"); - _credential.DangerousRelease(); - return true; - } - protected override void Dispose(bool disposing) { if (disposing) { - _sslContext.Dispose(); + if (null != _sslContext) + { + _sslContext.Dispose(); + _sslContext = null; + } } base.Dispose(disposing); @@ -285,7 +314,7 @@ protected override void Dispose(bool disposing) public override string ToString() { - return IsInvalid ? String.Empty : handle.ToString(); + return handle.ToString(); } } diff --git a/src/System.Net.Security/src/Resources/Strings.resx b/src/System.Net.Security/src/Resources/Strings.resx index 378e4ea45c62..3634df93afa9 100644 --- a/src/System.Net.Security/src/Resources/Strings.resx +++ b/src/System.Net.Security/src/Resources/Strings.resx @@ -432,4 +432,13 @@ Insufficient buffer space. Required: {0} Actual: {1}. + + No support for channel binding on operating systems other than Windows + + + NTLM is not supported + + + Server implementation is not supported + diff --git a/src/System.Net.Security/src/System.Net.Security.csproj b/src/System.Net.Security/src/System.Net.Security.csproj index e9343f7d48fb..28e37dc86c3e 100644 --- a/src/System.Net.Security/src/System.Net.Security.csproj +++ b/src/System.Net.Security/src/System.Net.Security.csproj @@ -241,6 +241,7 @@ + @@ -306,6 +307,24 @@ Common\Interop\Unix\System.Net.Security.Native\Interop.Initialization.cs + + Common\Interop\Unix\System.Net.Security.Native\Interop.GssApi.cs + + + Common\Interop\Unix\System.Net.Security.Native\Interop.GssApiException.cs + + + Common\Interop\Unix\System.Net.Security.Native\Interop.GssBuffer.cs + + + Common\Interop\Unix\System.Net.Security.Native\SecuritySafeHandles.cs + + + Common\Microsoft\Win32\SafeHandles\GssSafeHandles.cs + + + Common\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.cs + Common\Microsoft\Win32\SafeHandles\SafeX509Handles.Unix.cs diff --git a/src/System.Net.Security/src/System/Net/CertificateValidationPal.Unix.cs b/src/System.Net.Security/src/System/Net/CertificateValidationPal.Unix.cs index 4c68992cb047..29f02ace7398 100644 --- a/src/System.Net.Security/src/System/Net/CertificateValidationPal.Unix.cs +++ b/src/System.Net.Security/src/System/Net/CertificateValidationPal.Unix.cs @@ -113,7 +113,7 @@ internal static X509Certificate2 GetRemoteCertificate(SafeDeleteContext security remoteCertificateStore = new X509Certificate2Collection(); using (SafeSharedX509StackHandle chainStack = - Interop.OpenSsl.GetPeerCertificateChain(securityContext.SslContext)) + Interop.OpenSsl.GetPeerCertificateChain(((SafeDeleteSslContext)securityContext).SslContext)) { if (!chainStack.IsInvalid) { @@ -163,7 +163,7 @@ internal static X509Certificate2 GetRemoteCertificate(SafeDeleteContext security // internal static string[] GetRequestCertificateAuthorities(SafeDeleteContext securityContext) { - using (SafeSharedX509NameStackHandle names = Interop.Ssl.SslGetClientCAList(securityContext.SslContext)) + using (SafeSharedX509NameStackHandle names = Interop.Ssl.SslGetClientCAList(((SafeDeleteSslContext)securityContext).SslContext)) { if (names.IsInvalid) { @@ -257,7 +257,7 @@ private static int QueryContextRemoteCertificate(SafeDeleteContext securityConte remoteCertContext = null; try { - SafeX509Handle remoteCertificate = Interop.OpenSsl.GetPeerCertificate(securityContext.SslContext); + SafeX509Handle remoteCertificate = Interop.OpenSsl.GetPeerCertificate(((SafeDeleteSslContext)securityContext).SslContext); // Note that cert ownership is transferred to SafeFreeCertContext remoteCertContext = new SafeFreeCertContext(remoteCertificate); return 0; diff --git a/src/System.Net.Security/src/System/Net/ContextFlagsAdapterPal.Unix.cs b/src/System.Net.Security/src/System/Net/ContextFlagsAdapterPal.Unix.cs new file mode 100644 index 000000000000..9aa35df168d3 --- /dev/null +++ b/src/System.Net.Security/src/System/Net/ContextFlagsAdapterPal.Unix.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace System.Net +{ + internal static class ContextFlagsAdapterPal + { + private struct ContextFlagMapping + { + public readonly Interop.NetSecurityNative.GssFlags GssFlags; + public readonly ContextFlagsPal ContextFlag; + + public ContextFlagMapping(Interop.NetSecurityNative.GssFlags gssFlag, ContextFlagsPal contextFlag) + { + GssFlags = gssFlag; + ContextFlag = contextFlag; + } + } + + private static readonly ContextFlagMapping[] s_contextFlagMapping = new[] + { + // GSS_C_INTEG_FLAG is set if either AcceptIntegrity (used by server) or InitIntegrity (used by client) is set + new ContextFlagMapping(Interop.NetSecurityNative.GssFlags.GSS_C_INTEG_FLAG, ContextFlagsPal.AcceptIntegrity | ContextFlagsPal.InitIntegrity), + new ContextFlagMapping(Interop.NetSecurityNative.GssFlags.GSS_C_CONF_FLAG, ContextFlagsPal.Confidentiality), + new ContextFlagMapping(Interop.NetSecurityNative.GssFlags.GSS_C_IDENTIFY_FLAG, ContextFlagsPal.InitIdentify), + new ContextFlagMapping(Interop.NetSecurityNative.GssFlags.GSS_C_MUTUAL_FLAG, ContextFlagsPal.MutualAuth), + new ContextFlagMapping(Interop.NetSecurityNative.GssFlags.GSS_C_REPLAY_FLAG, ContextFlagsPal.ReplayDetect), + new ContextFlagMapping(Interop.NetSecurityNative.GssFlags.GSS_C_SEQUENCE_FLAG, ContextFlagsPal.SequenceDetect) + }; + + + internal static ContextFlagsPal GetContextFlagsPalFromInterop(Interop.NetSecurityNative.GssFlags gssFlags) + { + ContextFlagsPal flags = ContextFlagsPal.Zero; + foreach (ContextFlagMapping mapping in s_contextFlagMapping) + { + if ((gssFlags & mapping.GssFlags) != 0) + { + flags |= mapping.ContextFlag; + } + } + + return flags; + } + + internal static Interop.NetSecurityNative.GssFlags GetInteropFromContextFlagsPal(ContextFlagsPal flags) + { + Interop.NetSecurityNative.GssFlags gssFlags = (Interop.NetSecurityNative.GssFlags)0; + foreach (ContextFlagMapping mapping in s_contextFlagMapping) + { + if ((flags & mapping.ContextFlag) != 0) + { + gssFlags |= mapping.GssFlags; + } + } + + return gssFlags; + } + } +} diff --git a/src/System.Net.Security/src/System/Net/NegotiateStreamPal.Unix.cs b/src/System.Net.Security/src/System/Net/NegotiateStreamPal.Unix.cs index 9790f4f90b7c..c028c9e4d0dc 100644 --- a/src/System.Net.Security/src/System/Net/NegotiateStreamPal.Unix.cs +++ b/src/System.Net.Security/src/System/Net/NegotiateStreamPal.Unix.cs @@ -7,8 +7,11 @@ using System.Security.Principal; using System.Threading; using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.InteropServices; using System.Security.Authentication; using System.Security.Authentication.ExtendedProtection; +using Microsoft.Win32.SafeHandles; namespace System.Net.Security { @@ -21,9 +24,19 @@ namespace System.Net.Security // internal static class NegotiateStreamPal { + // value should match the Windows sspicli NTE_FAIL value + // defined in winerror.h + private const int NTE_FAIL = unchecked((int)0x80090020); + internal static IIdentity GetIdentity(NTAuthentication context) { - throw new PlatformNotSupportedException(); + Debug.Assert(!context.IsServer, "GetIdentity: Server is not supported"); + + string name = context.Spn; + string protocol = context.ProtocolName; + + return new GenericIdentity(name, protocol); + } internal static string QueryContextAssociatedName(SafeDeleteContext securityContext) @@ -33,17 +46,13 @@ internal static string QueryContextAssociatedName(SafeDeleteContext securityCont internal static string QueryContextAuthenticationPackage(SafeDeleteContext securityContext) { - throw new PlatformNotSupportedException(); - } - - internal static object QueryContextSizes(SafeDeleteContext securityContext) - { - throw new PlatformNotSupportedException(); + return NegotiationInfoClass.Kerberos; } internal static int QueryMaxTokenSize(string package) { - throw new PlatformNotSupportedException(); + // This value is not used on Unix + return 0; } internal static string QueryContextClientSpecifiedSpn(SafeDeleteContext securityContext) @@ -53,12 +62,36 @@ internal static string QueryContextClientSpecifiedSpn(SafeDeleteContext security internal static SafeFreeCredentials AcquireDefaultCredential(string package, bool isServer) { - throw new PlatformNotSupportedException(); + return AcquireCredentialsHandle(package, isServer, new NetworkCredential(string.Empty, string.Empty, string.Empty)); } internal static SafeFreeCredentials AcquireCredentialsHandle(string package, bool isServer, NetworkCredential credential) { - throw new PlatformNotSupportedException(); + if (isServer) + { + throw new PlatformNotSupportedException(SR.net_nego_server_not_supported); + } + + SafeFreeCredentials outCredential; + bool isNtlm = string.Equals(package, NegotiationInfoClass.NTLM); + + if (isNtlm) + { + throw new PlatformNotSupportedException(SR.net_nego_ntlm_not_supported); + } + + if (string.IsNullOrEmpty(credential.UserName) || string.IsNullOrEmpty(credential.Password)) + { + // In client case, equivalent of default credentials is to use previous, + // cached Kerberos TGT to get service-specific ticket. + outCredential = new SafeFreeNegoCredentials(string.Empty, string.Empty, string.Empty); + } + else + { + outCredential = new SafeFreeNegoCredentials(credential.UserName, credential.Password, credential.Domain); + } + return outCredential; + } internal static SecurityStatusPal InitializeSecurityContext( @@ -70,14 +103,28 @@ internal static SecurityStatusPal InitializeSecurityContext( SecurityBuffer outSecurityBuffer, ref ContextFlagsPal contextFlags) { - throw new PlatformNotSupportedException(); + // TODO (Issue #3718): The second buffer can contain a channel binding which is not supported + if ((null != inSecurityBufferArray) && (inSecurityBufferArray.Length > 1)) + { + throw new PlatformNotSupportedException(SR.net_nego_channel_binding_not_supported); + } + + return EstablishSecurityContext( + (SafeFreeNegoCredentials)credentialsHandle, + ref securityContext, + false, + spn, + requestedContextFlags, + ((inSecurityBufferArray != null && inSecurityBufferArray.Length != 0) ? inSecurityBufferArray[0] : null), + outSecurityBuffer, + ref contextFlags); } internal static SecurityStatusPal CompleteAuthToken( ref SafeDeleteContext securityContext, SecurityBuffer[] inSecurityBufferArray) { - throw new PlatformNotSupportedException(); + return SecurityStatusPal.OK; } internal static SecurityStatusPal AcceptSecurityContext( @@ -93,22 +140,17 @@ internal static SecurityStatusPal AcceptSecurityContext( internal static void ValidateImpersonationLevel(TokenImpersonationLevel impersonationLevel) { - throw new PlatformNotSupportedException(); - } + if (impersonationLevel != TokenImpersonationLevel.Identification) + { + throw new ArgumentOutOfRangeException("impersonationLevel", impersonationLevel.ToString(), + SR.net_auth_supported_impl_levels); + } - internal static void ThrowCredentialException(long error) - { - throw new PlatformNotSupportedException(); - } - - internal static bool IsLogonDeniedException(Exception exception) - { - throw new PlatformNotSupportedException(); } internal static Exception CreateExceptionFromError(SecurityStatusPal statusCode) { - throw new PlatformNotSupportedException(); + return new Win32Exception(NTE_FAIL); } internal static int Encrypt( @@ -121,7 +163,24 @@ internal static int Encrypt( ref byte[] output, uint sequenceNumber) { - throw new PlatformNotSupportedException(); + Debug.Assert(!isNtlm, "Encrypt: NTLM is not yet supported"); + SafeDeleteNegoContext gssContext = (SafeDeleteNegoContext) securityContext; + byte[] tempOutput = Interop.GssApi.Encrypt(gssContext.GssContext, isConfidential, buffer, offset, count); + + // Create space for prefixing with the length + const int prefixLength = 4; + output = new byte[tempOutput.Length + prefixLength]; + Array.Copy(tempOutput, 0, output, prefixLength, tempOutput.Length); + int resultSize = tempOutput.Length; + unchecked + { + output[0] = (byte)((resultSize) & 0xFF); + output[1] = (byte)(((resultSize) >> 8) & 0xFF); + output[2] = (byte)(((resultSize) >> 16) & 0xFF); + output[3] = (byte)(((resultSize) >> 24) & 0xFF); + } + + return resultSize + 4; } internal static int Decrypt( @@ -134,7 +193,32 @@ internal static int Decrypt( out int newOffset, uint sequenceNumber) { - throw new PlatformNotSupportedException(); + if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length)) + { + if (GlobalLog.IsEnabled) + { + GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'offset' out of range."); + } + + Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'offset' out of range."); + + throw new ArgumentOutOfRangeException("offset"); + } + + if (count < 0 || count > (buffer == null ? 0 : buffer.Length - offset)) + { + if (GlobalLog.IsEnabled) + { + GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'count' out of range."); + } + + Debug.Fail("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt", "Argument 'count' out of range."); + + throw new ArgumentOutOfRangeException("count"); + } + + newOffset = offset; + return Interop.GssApi.Decrypt(((SafeDeleteNegoContext)securityContext).GssContext, buffer, offset, count); } internal static int DecryptNtlm( @@ -146,8 +230,67 @@ internal static int DecryptNtlm( out int newOffset, uint sequenceNumber) { - throw new PlatformNotSupportedException(); + throw new PlatformNotSupportedException(SR.net_nego_ntlm_not_supported); } + private static SecurityStatusPal EstablishSecurityContext( + SafeFreeNegoCredentials credential, + ref SafeDeleteContext context, + bool isNtlm, + string targetName, + ContextFlagsPal inFlags, + SecurityBuffer inputBuffer, + SecurityBuffer outputBuffer, + ref ContextFlagsPal outFlags) + { + Debug.Assert(!isNtlm, "EstablishSecurityContext: NTLM is not yet supported"); + + if (context == null) + { + context = new SafeDeleteNegoContext(credential, targetName); + } + + SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)context; + try + { + Interop.NetSecurityNative.GssFlags inputFlags = ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(inFlags); + uint outputFlags; + SafeGssContextHandle contextHandle = negoContext.GssContext; + bool done = Interop.GssApi.EstablishSecurityContext( + ref contextHandle, + credential.GssCredential, + isNtlm, + negoContext.TargetName, + inputFlags, + ((inputBuffer != null) ? inputBuffer.token : null), + out outputBuffer.token, + out outputFlags); + + Debug.Assert(outputBuffer.token != null, "Unexpected null buffer returned by GssApi"); + outputBuffer.size = outputBuffer.token.Length; + outputBuffer.offset = 0; + + outFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop((Interop.NetSecurityNative.GssFlags)outputFlags); + Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext); + + // Save the inner context handle for further calls to NetSecurity + if (null == negoContext.GssContext) + { + negoContext.SetGssContext(contextHandle); + } + return done ? SecurityStatusPal.CompleteNeeded : SecurityStatusPal.ContinueNeeded; + } + catch(Exception ex) + { + //TODO (Issue #5890): Print exception until issue is fixed + Debug.Write("Exception Caught. - " + ex); + if (GlobalLog.IsEnabled) + { + GlobalLog.Print("Exception Caught. - " + ex); + } + + return SecurityStatusPal.InternalError; + } + } } } diff --git a/src/System.Net.Security/src/System/Net/NegotiateStreamPal.Windows.cs b/src/System.Net.Security/src/System/Net/NegotiateStreamPal.Windows.cs index 9545c6d881a6..16f437f91a35 100644 --- a/src/System.Net.Security/src/System/Net/NegotiateStreamPal.Windows.cs +++ b/src/System.Net.Security/src/System/Net/NegotiateStreamPal.Windows.cs @@ -219,30 +219,6 @@ internal static void ValidateImpersonationLevel(TokenImpersonationLevel imperson } } - internal static void ThrowCredentialException(long error) - { - Win32Exception e = new Win32Exception((int)error); - - if (e.NativeErrorCode == (int)Interop.SecurityStatus.LogonDenied) - { - throw new InvalidCredentialException(SR.net_auth_bad_client_creds, e); - } - - if (e.NativeErrorCode == NegoState.ERROR_TRUST_FAILURE) - { - throw new AuthenticationException(SR.net_auth_context_expectation_remote, e); - } - - throw new AuthenticationException(SR.net_auth_alert, e); - } - - internal static bool IsLogonDeniedException(Exception exception) - { - Win32Exception win32exception = exception as Win32Exception; - - return (win32exception != null) && (win32exception.NativeErrorCode == (int)Interop.SecurityStatus.LogonDenied); - } - internal static Exception CreateExceptionFromError(SecurityStatusPal statusCode) { return new Win32Exception((int)SecurityStatusAdapterPal.GetInteropFromSecurityStatusPal(statusCode)); diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.cs index e1761999d200..bbe7fed333fc 100644 --- a/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.cs +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.cs @@ -606,7 +606,7 @@ private void ProcessReceivedBlob(byte[] message, LazyAsyncResult lazyResult) error = (error << 8) + message[i]; } - NegotiateStreamPal.ThrowCredentialException(error); + ThrowCredentialException(error); } throw new AuthenticationException(SR.net_auth_alert, null); @@ -656,7 +656,7 @@ private void StartSendAuthResetSignal(LazyAsyncResult lazyResult, byte[] message { _framer.WriteHeader.MessageId = FrameHeader.HandshakeErrId; - if (NegotiateStreamPal.IsLogonDeniedException(exception)) + if (IsLogonDeniedException(exception)) { if (IsServer) { @@ -825,5 +825,29 @@ internal int DecryptData(byte[] buffer, int offset, int count, out int newOffset ++_readSequenceNumber; return _context.Decrypt(buffer, offset, count, out newOffset, _readSequenceNumber); } + + internal static void ThrowCredentialException(long error) + { + Win32Exception e = new Win32Exception((int)error); + + if (e.NativeErrorCode == (int)SecurityStatusPal.LogonDenied) + { + throw new InvalidCredentialException(SR.net_auth_bad_client_creds, e); + } + + if (e.NativeErrorCode == NegoState.ERROR_TRUST_FAILURE) + { + throw new AuthenticationException(SR.net_auth_context_expectation_remote, e); + } + + throw new AuthenticationException(SR.net_auth_alert, e); + } + + internal static bool IsLogonDeniedException(Exception exception) + { + Win32Exception win32exception = exception as Win32Exception; + + return (win32exception != null) && (win32exception.NativeErrorCode == (int)SecurityStatusPal.LogonDenied); + } } } diff --git a/src/System.Net.Security/src/System/Net/SslStreamPal.Unix.cs b/src/System.Net.Security/src/System/Net/SslStreamPal.Unix.cs index acf1faab6194..3f69b6b5f58e 100644 --- a/src/System.Net.Security/src/System/Net/SslStreamPal.Unix.cs +++ b/src/System.Net.Security/src/System/Net/SslStreamPal.Unix.cs @@ -49,7 +49,7 @@ public static SecurityStatusPal InitializeSecurityContext(SafeFreeCredentials cr public static SafeFreeCredentials AcquireCredentialsHandle(X509Certificate certificate, SslProtocols protocols, EncryptionPolicy policy, bool isServer) { - return new SafeFreeCredentials(certificate, protocols, policy); + return new SafeFreeSslCredentials(certificate, protocols, policy); } public static SecurityStatusPal EncryptMessage(SafeDeleteContext securityContext, byte[] buffer, int size, int headerSize, int trailerSize, out int resultSize) @@ -71,7 +71,7 @@ public static SecurityStatusPal DecryptMessage(SafeDeleteContext securityContext public static SafeFreeContextBufferChannelBinding QueryContextChannelBinding(SafeDeleteContext securityContext, ChannelBindingKind attribute) { - SafeChannelBindingHandle bindingHandle = Interop.OpenSsl.QueryChannelBinding(securityContext.SslContext, attribute); + SafeChannelBindingHandle bindingHandle = Interop.OpenSsl.QueryChannelBinding(((SafeDeleteSslContext)securityContext).SslContext, attribute); var refHandle = bindingHandle == null ? null : new SafeFreeContextBufferChannelBinding(bindingHandle); return refHandle; } @@ -83,7 +83,7 @@ public static void QueryContextStreamSizes(SafeDeleteContext securityContext, ou public static void QueryContextConnectionInfo(SafeDeleteContext securityContext, out SslConnectionInfo connectionInfo) { - connectionInfo = new SslConnectionInfo(securityContext.SslContext); + connectionInfo = new SslConnectionInfo(((SafeDeleteSslContext)securityContext).SslContext); } private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credential, ref SafeDeleteContext context, @@ -95,7 +95,7 @@ private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credentia { if ((null == context) || context.IsInvalid) { - context = new SafeDeleteContext(credential, isServer, remoteCertRequired); + context = new SafeDeleteSslContext(credential as SafeFreeSslCredentials, isServer, remoteCertRequired); } byte[] output = null; @@ -104,11 +104,11 @@ private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credentia if (null == inputBuffer) { - done = Interop.OpenSsl.DoSslHandshake(context.SslContext, null, 0, 0, out output, out outputSize); + done = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, null, 0, 0, out output, out outputSize); } else { - done = Interop.OpenSsl.DoSslHandshake(context.SslContext, inputBuffer.token, inputBuffer.offset, inputBuffer.size, out output, out outputSize); + done = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, inputBuffer.token, inputBuffer.offset, inputBuffer.size, out output, out outputSize); } outputBuffer.size = outputSize; @@ -133,7 +133,7 @@ private static SecurityStatusPal EncryptDecryptHelper(SafeDeleteContext security Interop.Ssl.SslErrorCode errorCode = Interop.Ssl.SslErrorCode.SSL_ERROR_NONE; - SafeSslHandle scHandle = securityContext.SslContext; + SafeSslHandle scHandle = ((SafeDeleteSslContext)securityContext).SslContext; resultSize = encrypt ? Interop.OpenSsl.Encrypt(scHandle, buffer, offset, size, out errorCode) :