From 261c0a9d419e28209e2c1a95f0716f3d47e49a20 Mon Sep 17 00:00:00 2001 From: Shruti Garg Date: Thu, 21 Jan 2016 12:27:00 +0530 Subject: [PATCH 1/5] Renaming NegoState.Windows.cs file as it had some common code. --- src/System.Net.Security/src/System.Net.Security.csproj | 2 +- .../{NegoState.Windows.cs => InternalNegoState.cs} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/System.Net.Security/src/System/Net/SecureProtocols/{NegoState.Windows.cs => InternalNegoState.cs} (100%) diff --git a/src/System.Net.Security/src/System.Net.Security.csproj b/src/System.Net.Security/src/System.Net.Security.csproj index f525e1ff2dd3..a933e19cdb93 100644 --- a/src/System.Net.Security/src/System.Net.Security.csproj +++ b/src/System.Net.Security/src/System.Net.Security.csproj @@ -147,7 +147,7 @@ - + diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Windows.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/InternalNegoState.cs similarity index 100% rename from src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Windows.cs rename to src/System.Net.Security/src/System/Net/SecureProtocols/InternalNegoState.cs From 6d62ab9dc967fae379569a1c64eebe90a2342bdf Mon Sep 17 00:00:00 2001 From: Shruti Garg Date: Thu, 21 Jan 2016 13:53:36 +0530 Subject: [PATCH 2/5] Updating NegoState Pal Layer and other refactoring --- .../NegotiationInfoClass.cs | 14 + .../src/System.Net.Security.csproj | 13 +- .../src/System/Net/ContextFlagsPal.cs | 34 + .../src/System/Net/NTAuthentication.cs | 327 ++------- .../Net/SecureProtocols/InternalNegoState.cs | 127 +--- .../Net/SecureProtocols/NegoState.Unix.cs | 138 ++-- .../Net/SecureProtocols/NegoState.Windows.cs | 626 ++++++++++++++++++ .../src/System/Net/SslStreamPal.Windows.cs | 6 +- 8 files changed, 843 insertions(+), 442 deletions(-) create mode 100644 src/Common/src/Interop/Unix/System.Net.Security.Native/NegotiationInfoClass.cs create mode 100644 src/System.Net.Security/src/System/Net/ContextFlagsPal.cs create mode 100644 src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Windows.cs diff --git a/src/Common/src/Interop/Unix/System.Net.Security.Native/NegotiationInfoClass.cs b/src/Common/src/Interop/Unix/System.Net.Security.Native/NegotiationInfoClass.cs new file mode 100644 index 000000000000..ead6c893c9ec --- /dev/null +++ b/src/Common/src/Interop/Unix/System.Net.Security.Native/NegotiationInfoClass.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Net +{ + // This class is used to determine if NTLM or + // Kerberos are used in the context of a Negotiate handshake + internal class NegotiationInfoClass + { + internal const string NTLM = "NTLM"; + internal const string Kerberos = "Kerberos"; + internal const string Negotiate = "Negotiate"; + } +} diff --git a/src/System.Net.Security/src/System.Net.Security.csproj b/src/System.Net.Security/src/System.Net.Security.csproj index a933e19cdb93..8c095c1e1992 100644 --- a/src/System.Net.Security/src/System.Net.Security.csproj +++ b/src/System.Net.Security/src/System.Net.Security.csproj @@ -48,8 +48,13 @@ + + + + + @@ -143,11 +148,8 @@ - - - - + @@ -292,6 +294,9 @@ Common\Interop\Unix\System.Net.Security.Native\Interop.Initialization.cs + + Common\Interop\Unix\System.Net.Security.Native\NegotiationInfoClass.cs + Common\Microsoft\Win32\SafeHandles\SafeX509Handles.Unix.cs diff --git a/src/System.Net.Security/src/System/Net/ContextFlagsPal.cs b/src/System.Net.Security/src/System/Net/ContextFlagsPal.cs new file mode 100644 index 000000000000..8da411e816cd --- /dev/null +++ b/src/System.Net.Security/src/System/Net/ContextFlagsPal.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace System.Net +{ + [Flags] + internal enum ContextFlagsPal + { + Zero = 0, + Delegate = 0x00000001, + MutualAuth = 0x00000002, + ReplayDetect = 0x00000004, + SequenceDetect = 0x00000008, + Confidentiality = 0x00000010, + UseSessionKey = 0x00000020, + AllocateMemory = 0x00000100, + Connection = 0x00000800, + InitExtendedError = 0x00004000, + AcceptExtendedError = 0x00008000, + InitStream = 0x00008000, + AcceptStream = 0x00010000, + InitIntegrity = 0x00010000, + AcceptIntegrity = 0x00020000, + InitManualCredValidation = 0x00080000, + InitUseSuppliedCreds = 0x00000080, + InitIdentify = 0x00020000, + AcceptIdentify = 0x00080000, + ProxyBindings = 0x04000000, + AllowMissingBindings = 0x10000000, + UnverifiedTargetName = 0x20000000, + } +} diff --git a/src/System.Net.Security/src/System/Net/NTAuthentication.cs b/src/System.Net.Security/src/System/Net/NTAuthentication.cs index bfe544f1d140..6a7cb10b9034 100644 --- a/src/System.Net.Security/src/System/Net/NTAuthentication.cs +++ b/src/System.Net.Security/src/System/Net/NTAuthentication.cs @@ -23,12 +23,12 @@ internal class NTAuthentication private string _clientSpecifiedSpn; private int _tokenSize; - private Interop.SspiCli.ContextFlags _requestedContextFlags; - private Interop.SspiCli.ContextFlags _contextFlags; + private ContextFlagsPal _requestedContextFlags; + private ContextFlagsPal _contextFlags; private bool _isCompleted; private string _protocolName; - private SecSizes _sizes; + private object _sizes; private string _lastProtocolName; private string _package; @@ -57,10 +57,10 @@ internal string AssociatedName { if (!(IsValidContext && IsCompleted)) { - throw new Win32Exception((int)Interop.SecurityStatus.InvalidHandle); + throw new Exception(SR.net_auth_noauth); } - string name = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, _securityContext, Interop.SspiCli.ContextAttribute.Names) as string; + string name = NegoState.QueryContextAssociatedName(_securityContext); if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication: The context is associated with [" + name + "]"); @@ -73,7 +73,7 @@ internal bool IsConfidentialityFlag { get { - return (_contextFlags & Interop.SspiCli.ContextFlags.Confidentiality) != 0; + return (_contextFlags & ContextFlagsPal.Confidentiality) != 0; } } @@ -81,7 +81,7 @@ internal bool IsIntegrityFlag { get { - return (_contextFlags & (_isServer ? Interop.SspiCli.ContextFlags.AcceptIntegrity : Interop.SspiCli.ContextFlags.InitIntegrity)) != 0; + return (_contextFlags & (_isServer ? ContextFlagsPal.AcceptIntegrity : ContextFlagsPal.InitIntegrity)) != 0; } } @@ -89,7 +89,7 @@ internal bool IsMutualAuthFlag { get { - return (_contextFlags & Interop.SspiCli.ContextFlags.MutualAuth) != 0; + return (_contextFlags & ContextFlagsPal.MutualAuth) != 0; } } @@ -97,7 +97,7 @@ internal bool IsDelegationFlag { get { - return (_contextFlags & Interop.SspiCli.ContextFlags.Delegate) != 0; + return (_contextFlags & ContextFlagsPal.Delegate) != 0; } } @@ -105,7 +105,7 @@ internal bool IsIdentifyFlag { get { - return (_contextFlags & (_isServer ? Interop.SspiCli.ContextFlags.AcceptIdentify : Interop.SspiCli.ContextFlags.InitIdentify)) != 0; + return (_contextFlags & (_isServer ? ContextFlagsPal.AcceptIdentify : ContextFlagsPal.InitIdentify)) != 0; } } @@ -174,29 +174,24 @@ internal string ProtocolName // Note: May return string.Empty if the auth is not done yet or failed. if (_protocolName == null) { - NegotiationInfoClass negotiationInfo = null; + string negotiationAuthenticationPackage = null; if (IsValidContext) { - negotiationInfo = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, _securityContext, Interop.SspiCli.ContextAttribute.NegotiationInfo) as NegotiationInfoClass; + negotiationAuthenticationPackage = NegoState.QueryContextAuthenticationPackage(_securityContext); if (IsCompleted) { - if (negotiationInfo != null) - { - // Cache it only when it's completed. - _protocolName = negotiationInfo.AuthenticationPackage; - } + _protocolName = negotiationAuthenticationPackage; } } - - return negotiationInfo == null ? string.Empty : negotiationInfo.AuthenticationPackage; + return negotiationAuthenticationPackage ?? string.Empty; } return _protocolName; } } - internal SecSizes Sizes + internal object Sizes { get { @@ -211,11 +206,7 @@ internal SecSizes Sizes if (_sizes == null) { - _sizes = SSPIWrapper.QueryContextAttributes( - GlobalSSPI.SSPIAuth, - _securityContext, - Interop.SspiCli.ContextAttribute.Sizes - ) as SecSizes; + _sizes = NegoState.QueryContextSizes(_securityContext); } return _sizes; @@ -225,14 +216,14 @@ internal SecSizes Sizes // // This overload does not attempt to impersonate because the caller either did it already or the original thread context is still preserved. // - internal NTAuthentication(bool isServer, string package, NetworkCredential credential, string spn, Interop.SspiCli.ContextFlags requestedContextFlags, ChannelBinding channelBinding) + internal NTAuthentication(bool isServer, string package, NetworkCredential credential, string spn, ContextFlagsPal requestedContextFlags, ChannelBinding channelBinding) { Initialize(isServer, package, credential, spn, requestedContextFlags, channelBinding); } private class InitializeCallbackContext { - internal InitializeCallbackContext(NTAuthentication thisPtr, bool isServer, string package, NetworkCredential credential, string spn, Interop.SspiCli.ContextFlags requestedContextFlags, ChannelBinding channelBinding) + internal InitializeCallbackContext(NTAuthentication thisPtr, bool isServer, string package, NetworkCredential credential, string spn, ContextFlagsPal requestedContextFlags, ChannelBinding channelBinding) { ThisPtr = thisPtr; IsServer = isServer; @@ -248,7 +239,7 @@ internal InitializeCallbackContext(NTAuthentication thisPtr, bool isServer, stri internal readonly string Package; internal readonly NetworkCredential Credential; internal readonly string Spn; - internal readonly Interop.SspiCli.ContextFlags RequestedContextFlags; + internal readonly ContextFlagsPal RequestedContextFlags; internal readonly ChannelBinding ChannelBinding; } @@ -258,14 +249,14 @@ private static void InitializeCallback(object state) context.ThisPtr.Initialize(context.IsServer, context.Package, context.Credential, context.Spn, context.RequestedContextFlags, context.ChannelBinding); } - private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, Interop.SspiCli.ContextFlags requestedContextFlags, ChannelBinding channelBinding) + private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, ContextFlagsPal requestedContextFlags, ChannelBinding channelBinding) { if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::.ctor() package:" + LoggingHash.ObjectToString(package) + " spn:" + LoggingHash.ObjectToString(spn) + " flags :" + requestedContextFlags.ToString()); } - _tokenSize = SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPIAuth, package, true).MaxToken; + _tokenSize = NegoState.QueryMaxTokenSize(package); _isServer = isServer; _spn = spn; _securityContext = null; @@ -290,55 +281,17 @@ private void Initialize(bool isServer, string package, NetworkCredential credent GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::.ctor(): using DefaultCredentials"); } - _credentialsHandle = SSPIWrapper.AcquireDefaultCredential( - GlobalSSPI.SSPIAuth, - package, - (_isServer ? Interop.SspiCli.CredentialUse.Inbound : Interop.SspiCli.CredentialUse.Outbound)); + _credentialsHandle = NegoState.AcquireDefaultCredential(package, _isServer); } else { - unsafe - { - SafeSspiAuthDataHandle authData = null; - try - { - Interop.SecurityStatus result = Interop.SspiCli.SspiEncodeStringsAsAuthIdentity( - credential.UserName, credential.Domain, - credential.Password, out authData); - - if (result != Interop.SecurityStatus.OK) - { - if (NetEventSource.Log.IsEnabled()) - { - NetEventSource.PrintError( - NetEventSource.ComponentType.Security, - SR.Format( - SR.net_log_operation_failed_with_error, - "SspiEncodeStringsAsAuthIdentity()", - String.Format(CultureInfo.CurrentCulture, "0x{0:X}", (int)result))); - } - - throw new Win32Exception((int)result); - } - - _credentialsHandle = SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPIAuth, - package, (_isServer ? Interop.SspiCli.CredentialUse.Inbound : Interop.SspiCli.CredentialUse.Outbound), ref authData); - } - finally - { - if (authData != null) - { - authData.Dispose(); - } - } - } + _credentialsHandle = NegoState.AcquireCredentialsHandle(package, _isServer, credential); } } - // This will return a client token when conducted authentication on server side. - // This token can be used for impersonation. We use it to create a WindowsIdentity and hand it out to the server app. - internal SecurityContextTokenHandle GetContextToken(out Interop.SecurityStatus status) + internal SafeDeleteContext GetContext(out SecurityStatusPal status) { + status = SecurityStatusPal.OK; if ((IsCompleted && IsValidContext)) { if (GlobalLog.IsEnabled) @@ -359,28 +312,11 @@ internal SecurityContextTokenHandle GetContextToken(out Interop.SecurityStatus s if (!IsValidContext) { - throw new Win32Exception((int)Interop.SecurityStatus.InvalidHandle); - } - - SecurityContextTokenHandle token = null; - status = (Interop.SecurityStatus)SSPIWrapper.QuerySecurityContextToken( - GlobalSSPI.SSPIAuth, - _securityContext, - out token); - - return token; - } - - internal SecurityContextTokenHandle GetContextToken() - { - Interop.SecurityStatus status; - SecurityContextTokenHandle token = GetContextToken(out status); - if (status != Interop.SecurityStatus.OK) - { - throw new Win32Exception((int)status); + status = SecurityStatusPal.InvalidHandle; + return null; } - return token; + return _securityContext; } internal void CloseContext() @@ -392,7 +328,7 @@ internal void CloseContext() } // Accepts an incoming binary security blob and returns an outgoing binary security blob. - internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out Interop.SecurityStatus statusCode) + internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatusPal statusCode) { if (GlobalLog.IsEnabled) { @@ -425,13 +361,11 @@ internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out Inte if (!_isServer) { // client session - statusCode = (Interop.SecurityStatus)SSPIWrapper.InitializeSecurityContext( - GlobalSSPI.SSPIAuth, + statusCode = NegoState.InitializeSecurityContext( _credentialsHandle, ref _securityContext, _spn, _requestedContextFlags, - Interop.SspiCli.Endianness.Network, inSecurityBufferArray, outSecurityBuffer, ref _contextFlags); @@ -441,15 +375,12 @@ internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out Inte GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); } - if (statusCode == Interop.SecurityStatus.CompleteNeeded) + if (statusCode == SecurityStatusPal.CompleteNeeded) { var inSecurityBuffers = new SecurityBuffer[1]; inSecurityBuffers[0] = outSecurityBuffer; - statusCode = (Interop.SecurityStatus)SSPIWrapper.CompleteAuthToken( - GlobalSSPI.SSPIAuth, - ref _securityContext, - inSecurityBuffers); + statusCode = NegoState.CompleteAuthToken(ref _securityContext, inSecurityBuffers); if (GlobalLog.IsEnabled) { @@ -462,12 +393,10 @@ internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out Inte else { // Server session. - statusCode = (Interop.SecurityStatus)SSPIWrapper.AcceptSecurityContext( - GlobalSSPI.SSPIAuth, + statusCode = NegoState.AcceptSecurityContext( _credentialsHandle, ref _securityContext, _requestedContextFlags, - Interop.SspiCli.Endianness.Network, inSecurityBufferArray, outSecurityBuffer, ref _contextFlags); @@ -493,13 +422,13 @@ internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out Inte } - if (((int)statusCode & unchecked((int)0x80000000)) != 0) + if (NegoState.IsError(statusCode)) { CloseContext(); _isCompleted = true; if (throwOnError) { - var exception = new Win32Exception((int)statusCode); + Exception exception = NegoState.CreateExceptionFromError(statusCode); if (GlobalLog.IsEnabled) { GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "Win32Exception:" + exception); @@ -519,21 +448,18 @@ internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out Inte SSPIHandleCache.CacheCredential(_credentialsHandle); } - // The return value from SSPI will tell us correctly if the - // handshake is over or not: http://msdn.microsoft.com/library/psdk/secspi/sspiref_67p0.htm - // we also have to consider the case in which SSPI formed a new context, in this case we're done as well. - if (statusCode == Interop.SecurityStatus.OK) + // The return value will tell us correctly if the handshake is over or not + if (statusCode == SecurityStatusPal.OK) { // Success. - if ((statusCode == Interop.SecurityStatus.OK)) + if (GlobalLog.IsEnabled) { - if (GlobalLog.IsEnabled) - { - GlobalLog.AssertFormat("NTAuthentication#{0}::GetOutgoingBlob()|statusCode:[0x{1:x8}] ({2}) m_SecurityContext#{3}::Handle:[{4}] [STATUS != OK]", LoggingHash.HashString(this), (int)statusCode, statusCode, LoggingHash.HashString(_securityContext), LoggingHash.ObjectToString(_securityContext)); - } - Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob()|statusCode:[0x" + ((int)statusCode).ToString("x8") + "] (" + statusCode + ") m_SecurityContext#" + LoggingHash.HashString(_securityContext) + "::Handle:[" + LoggingHash.ObjectToString(_securityContext) + "] [STATUS != OK]"); + GlobalLog.AssertFormat( + "NTAuthentication#{0}::GetOutgoingBlob()|statusCode:[0x{1:x8}] ({2}) m_SecurityContext#{3}::Handle:[{4}] [STATUS != OK]", + LoggingHash.HashString(this), (int) statusCode, statusCode, + LoggingHash.HashString(_securityContext), LoggingHash.ObjectToString(_securityContext)); } - + Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob()|statusCode:[0x" + ((int)statusCode).ToString("x8") + "] (" + statusCode + ") m_SecurityContext#" + LoggingHash.HashString(_securityContext) + "::Handle:[" + LoggingHash.ObjectToString(_securityContext) + "] [STATUS != OK]"); _isCompleted = true; } else if (GlobalLog.IsEnabled) @@ -552,86 +478,16 @@ internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out Inte internal int Encrypt(byte[] buffer, int offset, int count, ref byte[] output, uint sequenceNumber) { - SecSizes sizes = Sizes; - - try - { - int maxCount = checked(Int32.MaxValue - 4 - sizes.BlockSize - sizes.SecurityTrailer); - - if (count > maxCount || count < 0) - { - throw new ArgumentOutOfRangeException("count", SR.Format(SR.net_io_out_range, maxCount)); - } - } - catch (Exception e) - { - if (!ExceptionCheck.IsFatal(e)) - { - if (GlobalLog.IsEnabled) - { - GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(this) + "::Encrypt", "Arguments out of range."); - } - Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::Encrypt", "Arguments out of range."); - } - - throw; - } - - int resultSize = count + sizes.SecurityTrailer + sizes.BlockSize; - if (output == null || output.Length < resultSize + 4) - { - output = new byte[resultSize + 4]; - } - - // Make a copy of user data for in-place encryption. - Buffer.BlockCopy(buffer, offset, output, 4 + sizes.SecurityTrailer, count); - - // Prepare buffers TOKEN(signature), DATA and Padding. - var securityBuffer = new SecurityBuffer[3]; - securityBuffer[0] = new SecurityBuffer(output, 4, sizes.SecurityTrailer, SecurityBufferType.Token); - securityBuffer[1] = new SecurityBuffer(output, 4 + sizes.SecurityTrailer, count, SecurityBufferType.Data); - securityBuffer[2] = new SecurityBuffer(output, 4 + sizes.SecurityTrailer + count, sizes.BlockSize, SecurityBufferType.Padding); - - int errorCode; - if (IsConfidentialityFlag) - { - errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPIAuth, _securityContext, securityBuffer, sequenceNumber); - } - else - { - if (IsNTLM) - { - securityBuffer[1].type |= SecurityBufferType.ReadOnlyFlag; - } - - errorCode = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, _securityContext, securityBuffer, 0); - } - - if (errorCode != 0) - { - if (GlobalLog.IsEnabled) - { - GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::Encrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo)); - } - throw new Win32Exception(errorCode); - } - - // Compacting the result. - resultSize = securityBuffer[0].size; - bool forceCopy = false; - if (resultSize != sizes.SecurityTrailer) - { - forceCopy = true; - Buffer.BlockCopy(output, securityBuffer[1].offset, output, 4 + resultSize, securityBuffer[1].size); - } - - resultSize += securityBuffer[1].size; - if (securityBuffer[2].size != 0 && (forceCopy || resultSize != (count + sizes.SecurityTrailer))) - { - Buffer.BlockCopy(output, securityBuffer[2].offset, output, 4 + resultSize, securityBuffer[2].size); - } - - resultSize += securityBuffer[2].size; + int resultSize = NegoState.Encrypt( + _securityContext, + buffer, + offset, + count, + Sizes, + IsConfidentialityFlag, + IsNTLM, + ref output, + sequenceNumber); unchecked { @@ -668,44 +524,7 @@ internal int Decrypt(byte[] payload, int offset, int count, out int newOffset, u throw new ArgumentOutOfRangeException("count"); } - if (IsNTLM) - { - return DecryptNtlm(payload, offset, count, out newOffset, expectedSeqNumber); - } - - // - // Kerberos and up - // - var securityBuffer = new SecurityBuffer[2]; - securityBuffer[0] = new SecurityBuffer(payload, offset, count, SecurityBufferType.Stream); - securityBuffer[1] = new SecurityBuffer(0, SecurityBufferType.Data); - - int errorCode; - if (IsConfidentialityFlag) - { - errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, _securityContext, securityBuffer, expectedSeqNumber); - } - else - { - errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, _securityContext, securityBuffer, expectedSeqNumber); - } - - if (errorCode != 0) - { - if (GlobalLog.IsEnabled) - { - GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::Decrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo)); - } - throw new Win32Exception(errorCode); - } - - if (securityBuffer[1].type != SecurityBufferType.Data) - { - throw new InternalException(); - } - - newOffset = securityBuffer[1].offset; - return securityBuffer[1].size; + return NegoState.Decrypt(_securityContext, payload, offset, count, IsConfidentialityFlag, IsNTLM, out newOffset, expectedSeqNumber); } private string GetClientSpecifiedSpn() @@ -719,8 +538,7 @@ private string GetClientSpecifiedSpn() Debug.Fail("NTAuthentication: Trying to get the client SPN before handshaking is done!"); } - string spn = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, _securityContext, - Interop.SspiCli.ContextAttribute.ClientSpecifiedSpn) as string; + string spn = NegoState.QueryContextClientSpecifiedSpn(_securityContext); if (GlobalLog.IsEnabled) { @@ -743,40 +561,7 @@ private int DecryptNtlm(byte[] payload, int offset, int count, out int newOffset throw new ArgumentOutOfRangeException("count"); } - var securityBuffer = new SecurityBuffer[2]; - securityBuffer[0] = new SecurityBuffer(payload, offset, 16, SecurityBufferType.Token); - securityBuffer[1] = new SecurityBuffer(payload, offset + 16, count - 16, SecurityBufferType.Data); - - int errorCode; - SecurityBufferType realDataType = SecurityBufferType.Data; - - if (IsConfidentialityFlag) - { - errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, _securityContext, securityBuffer, expectedSeqNumber); - } - else - { - realDataType |= SecurityBufferType.ReadOnlyFlag; - securityBuffer[1].type = realDataType; - errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, _securityContext, securityBuffer, expectedSeqNumber); - } - - if (errorCode != 0) - { - if (GlobalLog.IsEnabled) - { - GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::Decrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo)); - } - throw new Win32Exception(errorCode); - } - - if (securityBuffer[1].type != realDataType) - { - throw new InternalException(); - } - - newOffset = securityBuffer[1].offset; - return securityBuffer[1].size; + return NegoState.DecryptNtlm(_securityContext, payload, offset, count, IsConfidentialityFlag, out newOffset, expectedSeqNumber); } } } diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/InternalNegoState.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/InternalNegoState.cs index e07415ee00f9..d215e11c3e42 100644 --- a/src/System.Net.Security/src/System/Net/SecureProtocols/InternalNegoState.cs +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/InternalNegoState.cs @@ -15,11 +15,9 @@ namespace System.Net.Security // // The class maintains the state of the authentication process and the security context. // It encapsulates security context and does the real work in authentication and - // user data encryption with NEGO SSPI package. + // user data encryption // - // This is part of the NegotiateStream PAL. - // - internal class NegoState + internal partial class NegoState { private const int ERROR_TRUST_FAILURE = 1790; // Used to serialize protectionLevel or impersonationLevel mismatch error to the remote side. @@ -126,12 +124,7 @@ internal void ValidateCreateContext( throw new ArgumentNullException("servicePrincipalName"); } - if (impersonationLevel != TokenImpersonationLevel.Identification && - impersonationLevel != TokenImpersonationLevel.Impersonation && - impersonationLevel != TokenImpersonationLevel.Delegation) - { - throw new ArgumentOutOfRangeException("impersonationLevel", impersonationLevel.ToString(), SR.net_auth_supported_impl_levels); - } + ValidateImpersonationLevel(impersonationLevel); if (_context != null && IsServer != isServer) { @@ -148,7 +141,7 @@ internal void ValidateCreateContext( _writeSequenceNumber = 0; _readSequenceNumber = 0; - Interop.SspiCli.ContextFlags flags = Interop.SspiCli.ContextFlags.Connection; + ContextFlagsPal flags = ContextFlagsPal.Connection; // A workaround for the client when talking to Win9x on the server side. if (protectionLevel == ProtectionLevel.None && !isServer) @@ -158,25 +151,25 @@ internal void ValidateCreateContext( else if (protectionLevel == ProtectionLevel.EncryptAndSign) { - flags |= Interop.SspiCli.ContextFlags.Confidentiality; + flags |= ContextFlagsPal.Confidentiality; } else if (protectionLevel == ProtectionLevel.Sign) { // Assuming user expects NT4 SP4 and above. - flags |= Interop.SspiCli.ContextFlags.ReplayDetect | Interop.SspiCli.ContextFlags.SequenceDetect | Interop.SspiCli.ContextFlags.InitIntegrity; + flags |= (ContextFlagsPal.ReplayDetect | ContextFlagsPal.SequenceDetect | ContextFlagsPal.InitIntegrity); } if (isServer) { if (_extendedProtectionPolicy.PolicyEnforcement == PolicyEnforcement.WhenSupported) { - flags |= Interop.SspiCli.ContextFlags.AllowMissingBindings; + flags |= ContextFlagsPal.AllowMissingBindings; } if (_extendedProtectionPolicy.PolicyEnforcement != PolicyEnforcement.Never && _extendedProtectionPolicy.ProtectionScenario == ProtectionScenario.TrustedProxy) { - flags |= Interop.SspiCli.ContextFlags.ProxyBindings; + flags |= ContextFlagsPal.ProxyBindings; } } else @@ -184,17 +177,17 @@ internal void ValidateCreateContext( // Server side should not request any of these flags. if (protectionLevel != ProtectionLevel.None) { - flags |= Interop.SspiCli.ContextFlags.MutualAuth; + flags |= ContextFlagsPal.MutualAuth; } if (impersonationLevel == TokenImpersonationLevel.Identification) { - flags |= Interop.SspiCli.ContextFlags.InitIdentify; + flags |= ContextFlagsPal.InitIdentify; } if (impersonationLevel == TokenImpersonationLevel.Delegation) { - flags |= Interop.SspiCli.ContextFlags.Delegate; + flags |= ContextFlagsPal.Delegate; } } @@ -204,7 +197,7 @@ internal void ValidateCreateContext( { _context = new NTAuthentication(isServer, package, credential, servicePrincipalName, flags, channelBinding); } - catch (Win32Exception e) + catch (Exception e) { throw new AuthenticationException(SR.net_auth_SSPI, e); } @@ -312,48 +305,6 @@ private bool HandshakeComplete } } - internal IIdentity GetIdentity() - { - CheckThrow(true); - - IIdentity result = null; - string name = _context.IsServer ? _context.AssociatedName : _context.Spn; - string protocol = "NTLM"; - - protocol = _context.ProtocolName; - - if (_context.IsServer) - { - SecurityContextTokenHandle token = null; - try - { - token = _context.GetContextToken(); - string authtype = _context.ProtocolName; - - // TODO #5241: - // The following call was also specifying WindowsAccountType.Normal, true. - // WindowsIdentity.IsAuthenticated is no longer supported in CoreFX. - result = new WindowsIdentity(token.DangerousGetHandle(), authtype); - return result; - } - catch (SecurityException) - { - // Ignore and construct generic Identity if failed due to security problem. - } - finally - { - if (token != null) - { - token.Dispose(); - } - } - } - - // On the client we don't have access to the remote side identity. - result = new GenericIdentity(name, protocol); - return result; - } - internal void CheckThrow(bool authSucessCheck) { if (_exception != null) @@ -482,16 +433,16 @@ private bool CheckSpn() // private void StartSendBlob(byte[] message, LazyAsyncResult lazyResult) { - Win32Exception win32exception = null; + Exception exception = null; if (message != s_emptyMessage) { - message = GetOutgoingBlob(message, ref win32exception); + message = GetOutgoingBlob(message, ref exception); } - if (win32exception != null) + if (exception != null) { // Signal remote side on a failed attempt. - StartSendAuthResetSignal(lazyResult, message, win32exception); + StartSendAuthResetSignal(lazyResult, message, exception); return; } @@ -499,7 +450,7 @@ private void StartSendBlob(byte[] message, LazyAsyncResult lazyResult) { if (_context.IsServer && !CheckSpn()) { - Exception exception = new AuthenticationException(SR.net_auth_bad_client_creds_or_target_mismatch); + exception = new AuthenticationException(SR.net_auth_bad_client_creds_or_target_mismatch); int statusCode = ERROR_TRUST_FAILURE; message = new byte[8]; //sizeof(long) @@ -515,7 +466,7 @@ private void StartSendBlob(byte[] message, LazyAsyncResult lazyResult) if (PrivateImpersonationLevel < _expectedImpersonationLevel) { - Exception exception = new AuthenticationException(SR.Format(SR.net_auth_context_expectation, _expectedImpersonationLevel.ToString(), PrivateImpersonationLevel.ToString())); + exception = new AuthenticationException(SR.Format(SR.net_auth_context_expectation, _expectedImpersonationLevel.ToString(), PrivateImpersonationLevel.ToString())); int statusCode = ERROR_TRUST_FAILURE; message = new byte[8]; //sizeof(long) @@ -533,7 +484,7 @@ private void StartSendBlob(byte[] message, LazyAsyncResult lazyResult) if (result < _expectedProtectionLevel) { - Exception exception = new AuthenticationException(SR.Format(SR.net_auth_context_expectation, result.ToString(), _expectedProtectionLevel.ToString())); + exception = new AuthenticationException(SR.Format(SR.net_auth_context_expectation, result.ToString(), _expectedProtectionLevel.ToString())); int statusCode = ERROR_TRUST_FAILURE; message = new byte[8]; //sizeof(long) @@ -641,7 +592,6 @@ private void ProcessReceivedBlob(byte[] message, LazyAsyncResult lazyResult) // Process Header information. if (_framer.ReadHeader.MessageId == FrameHeader.HandshakeErrId) { - Win32Exception e = null; if (message.Length >= 8) // sizeof(long) { // Try to recover remote win32 Exception. @@ -651,23 +601,10 @@ private void ProcessReceivedBlob(byte[] message, LazyAsyncResult lazyResult) error = (error << 8) + message[i]; } - e = new Win32Exception((int)error); + ThrowCredentialException(error); } - if (e != null) - { - if (e.NativeErrorCode == (int)Interop.SecurityStatus.LogonDenied) - { - throw new InvalidCredentialException(SR.net_auth_bad_client_creds, e); - } - - if (e.NativeErrorCode == ERROR_TRUST_FAILURE) - { - throw new AuthenticationException(SR.net_auth_context_expectation_remote, e); - } - } - - throw new AuthenticationException(SR.net_auth_alert, e); + throw new AuthenticationException(SR.net_auth_alert, null); } if (_framer.ReadHeader.MessageId == FrameHeader.HandshakeDoneId) @@ -714,9 +651,7 @@ private void StartSendAuthResetSignal(LazyAsyncResult lazyResult, byte[] message { _framer.WriteHeader.MessageId = FrameHeader.HandshakeErrId; - Win32Exception win32exception = exception as Win32Exception; - - if (win32exception != null && win32exception.NativeErrorCode == (int)Interop.SecurityStatus.LogonDenied) + if (IsLogonDeniedException(exception)) { if (IsServer) { @@ -835,20 +770,26 @@ private static void ReadCallback(IAsyncResult transportResult) } } - private unsafe byte[] GetOutgoingBlob(byte[] incomingBlob, ref Win32Exception e) + internal static bool IsError(SecurityStatusPal status) + { + return ((int)status >= (int)SecurityStatusPal.OutOfMemory); + } + + private unsafe byte[] GetOutgoingBlob(byte[] incomingBlob, ref Exception e) { - Interop.SecurityStatus statusCode; + SecurityStatusPal statusCode; byte[] message = _context.GetOutgoingBlob(incomingBlob, false, out statusCode); - if (((int)statusCode & unchecked((int)0x80000000)) != 0) + if (IsError(statusCode)) { - e = new System.ComponentModel.Win32Exception((int)statusCode); + e = CreateExceptionFromError(statusCode); + uint error = (uint)e.HResult; message = new byte[8]; //sizeof(long) for (int i = message.Length - 1; i >= 0; --i) { - message[i] = (byte)((uint)statusCode & 0xFF); - statusCode = (Interop.SecurityStatus)((uint)statusCode >> 8); + message[i] = (byte)(error & 0xFF); + error = (error >> 8); } } diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Unix.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Unix.cs index a98dc8fae706..90afad24c3d0 100644 --- a/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Unix.cs +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Unix.cs @@ -18,140 +18,136 @@ namespace System.Net.Security // // This is part of the NegotiateStream PAL. // - internal class NegoState + internal partial class NegoState { - internal const int MaxReadFrameSize = 64 * 1024; - internal const int MaxWriteDataSize = 63 * 1024; // 1k for the framing and trailer that is always less as per SSPI. - - internal NegoState(Stream innerStream, bool leaveStreamOpen) + internal IIdentity GetIdentity() { throw new PlatformNotSupportedException(); } - internal static string DefaultPackage + internal static string QueryContextAssociatedName(SafeDeleteContext securityContext) { - get - { - throw new PlatformNotSupportedException(); - } + throw new PlatformNotSupportedException(); } - internal void ValidateCreateContext(string package, - NetworkCredential credential, - string servicePrincipalName, - ExtendedProtectionPolicy policy, - ProtectionLevel protectionLevel, - TokenImpersonationLevel impersonationLevel) + internal static string QueryContextAuthenticationPackage(SafeDeleteContext securityContext) { throw new PlatformNotSupportedException(); } - internal void ValidateCreateContext( - string package, - bool isServer, - NetworkCredential credential, - string servicePrincipalName, - ChannelBinding channelBinding, - ProtectionLevel protectionLevel, - TokenImpersonationLevel impersonationLevel - ) + internal static object QueryContextSizes(SafeDeleteContext securityContext) { throw new PlatformNotSupportedException(); } - internal bool IsAuthenticated + internal static int QueryMaxTokenSize(string package) { - get - { - throw new PlatformNotSupportedException(); - } + throw new PlatformNotSupportedException(); } - internal bool IsMutuallyAuthenticated + internal static string QueryContextClientSpecifiedSpn(SafeDeleteContext securityContext) { - get - { - throw new PlatformNotSupportedException(); - } + throw new PlatformNotSupportedException(); } - internal bool IsEncrypted + internal static SafeFreeCredentials AcquireDefaultCredential(string package, bool isServer) { - get - { - throw new PlatformNotSupportedException(); - } + throw new PlatformNotSupportedException(); } - internal bool IsSigned + internal static SafeFreeCredentials AcquireCredentialsHandle(string package, bool isServer, NetworkCredential credential) { - get - { - throw new PlatformNotSupportedException(); - } + throw new PlatformNotSupportedException(); } - internal bool IsServer + internal static SecurityStatusPal InitializeSecurityContext( + SafeFreeCredentials credentialsHandle, + ref SafeDeleteContext securityContext, + string spn, + ContextFlagsPal requestedContextFlags, + SecurityBuffer[] inSecurityBufferArray, + SecurityBuffer outSecurityBuffer, + ref ContextFlagsPal contextFlags) { - get - { - throw new PlatformNotSupportedException(); - } + throw new PlatformNotSupportedException(); } - internal bool CanGetSecureStream + internal static SecurityStatusPal CompleteAuthToken( + ref SafeDeleteContext securityContext, + SecurityBuffer[] inSecurityBufferArray) { - get - { - throw new PlatformNotSupportedException(); - } + throw new PlatformNotSupportedException(); } - internal TokenImpersonationLevel AllowedImpersonation + internal static SecurityStatusPal AcceptSecurityContext( + SafeFreeCredentials credentialsHandle, + ref SafeDeleteContext securityContext, + ContextFlagsPal requestedContextFlags, + SecurityBuffer[] inSecurityBufferArray, + SecurityBuffer outSecurityBuffer, + ref ContextFlagsPal contextFlags) { - get - { - throw new PlatformNotSupportedException(); - } + throw new PlatformNotSupportedException(); } - internal IIdentity GetIdentity() + private static void ValidateImpersonationLevel(TokenImpersonationLevel impersonationLevel) { throw new PlatformNotSupportedException(); } - internal void CheckThrow(bool authSucessCheck) + private static void ThrowCredentialException(long error) { throw new PlatformNotSupportedException(); } - // - // This is to not depend on GC&SafeHandle class if the context is not needed anymore. - // - internal void Close() + private static bool IsLogonDeniedException(Exception exception) { throw new PlatformNotSupportedException(); } - internal void ProcessAuthentication(LazyAsyncResult lazyResult) + internal static Exception CreateExceptionFromError(SecurityStatusPal statusCode) { throw new PlatformNotSupportedException(); } - internal void EndProcessAuthentication(IAsyncResult result) + internal static int Encrypt( + SafeDeleteContext securityContext, + byte[] buffer, + int offset, + int count, + object secSizes, + bool isConfidential, + bool isNtlm, + ref byte[] output, + uint sequenceNumber) { throw new PlatformNotSupportedException(); } - - internal int EncryptData(byte[] buffer, int offset, int count, ref byte[] outBuffer) + internal static int Decrypt( + SafeDeleteContext securityContext, + byte[] buffer, + int offset, + int count, + bool isConfidential, + bool isNtlm, + out int newOffset, + uint sequenceNumber) { throw new PlatformNotSupportedException(); } - internal int DecryptData(byte[] buffer, int offset, int count, out int newOffset) + internal static int DecryptNtlm( + SafeDeleteContext securityContext, + byte[] buffer, + int offset, + int count, + bool isConfidential, + out int newOffset, + uint sequenceNumber) { throw new PlatformNotSupportedException(); } + } } diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Windows.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Windows.cs new file mode 100644 index 000000000000..c91feebd2509 --- /dev/null +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Windows.cs @@ -0,0 +1,626 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Globalization; +using System.IO; +using System.Security; +using System.Security.Principal; +using System.Threading; +using System.ComponentModel; +using System.Security.Authentication; +using System.Security.Authentication.ExtendedProtection; + +namespace System.Net.Security +{ + // + // The class does the real work in authentication and + // user data encryption with NEGO SSPI package. + // + // This is part of the NegotiateStream PAL. + // + internal partial class NegoState + { + internal IIdentity GetIdentity() + { + CheckThrow(true); + + IIdentity result = null; + string name = _context.IsServer ? _context.AssociatedName : _context.Spn; + string protocol = "NTLM"; + + protocol = _context.ProtocolName; + + if (_context.IsServer) + { + SecurityContextTokenHandle token = null; + try + { + //token = _context.GetContextToken(); + SecurityStatusPal status; + SafeDeleteContext securityContext = _context.GetContext(out status); + if (status != SecurityStatusPal.OK) + { + throw new Win32Exception((int)SslStreamPal.GetInteropFromSecurityStatusPal(status)); + } + + // This will return a client token when conducted authentication on server side. + // This token can be used for impersonation. We use it to create a WindowsIdentity and hand it out to the server app. + Interop.SecurityStatus winStatus = (Interop.SecurityStatus)SSPIWrapper.QuerySecurityContextToken( + GlobalSSPI.SSPIAuth, + securityContext, + out token); + if (winStatus != Interop.SecurityStatus.OK) + { + throw new Win32Exception((int)winStatus); + } + string authtype = _context.ProtocolName; + + // TODO #5241: + // The following call was also specifying WindowsAccountType.Normal, true. + // WindowsIdentity.IsAuthenticated is no longer supported in CoreFX. + result = new WindowsIdentity(token.DangerousGetHandle(), authtype); + return result; + } + catch (SecurityException) + { + // Ignore and construct generic Identity if failed due to security problem. + } + finally + { + if (token != null) + { + token.Dispose(); + } + } + } + + // On the client we don't have access to the remote side identity. + result = new GenericIdentity(name, protocol); + return result; + } + + internal static string QueryContextAssociatedName(SafeDeleteContext securityContext) + { + return SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.Names) as string; + } + + internal static string QueryContextAuthenticationPackage(SafeDeleteContext securityContext) + { + var negotiationInfoClass = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.NegotiationInfo) as NegotiationInfoClass; + if (negotiationInfoClass != null) + { + return negotiationInfoClass.AuthenticationPackage; + } + return null; + } + + internal static object QueryContextSizes(SafeDeleteContext securityContext) + { + return SSPIWrapper.QueryContextAttributes( + GlobalSSPI.SSPIAuth, + securityContext, + Interop.SspiCli.ContextAttribute.Sizes + ) as SecSizes; + } + + internal static int QueryMaxTokenSize(string package) + { + return SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPIAuth, package, true).MaxToken; + } + + internal static string QueryContextClientSpecifiedSpn(SafeDeleteContext securityContext) + { + return SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.ClientSpecifiedSpn) as string; + } + + internal static SafeFreeCredentials AcquireDefaultCredential(string package, bool isServer) + { + return SSPIWrapper.AcquireDefaultCredential( + GlobalSSPI.SSPIAuth, + package, + (isServer ? Interop.SspiCli.CredentialUse.Inbound : Interop.SspiCli.CredentialUse.Outbound)); + } + + internal static SafeFreeCredentials AcquireCredentialsHandle(string package, bool isServer, NetworkCredential credential) + { + unsafe + { + SafeSspiAuthDataHandle authData = null; + try + { + Interop.SecurityStatus result = Interop.SspiCli.SspiEncodeStringsAsAuthIdentity( + credential.UserName, credential.Domain, + credential.Password, out authData); + + if (result != Interop.SecurityStatus.OK) + { + if (NetEventSource.Log.IsEnabled()) + { + NetEventSource.PrintError( + NetEventSource.ComponentType.Security, + SR.Format( + SR.net_log_operation_failed_with_error, + "SspiEncodeStringsAsAuthIdentity()", + String.Format(CultureInfo.CurrentCulture, "0x{0:X}", (int)result))); + } + + throw new Win32Exception((int)result); + } + + return SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPIAuth, + package, (isServer ? Interop.SspiCli.CredentialUse.Inbound : Interop.SspiCli.CredentialUse.Outbound), ref authData); + } + finally + { + if (authData != null) + { + authData.Dispose(); + } + } + } + } + + internal static SecurityStatusPal InitializeSecurityContext( + SafeFreeCredentials credentialsHandle, + ref SafeDeleteContext securityContext, + string spn, + ContextFlagsPal requestedContextFlags, + SecurityBuffer[] inSecurityBufferArray, + SecurityBuffer outSecurityBuffer, + ref ContextFlagsPal contextFlags) + { + Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; + Interop.SecurityStatus winStatus = (Interop.SecurityStatus)SSPIWrapper.InitializeSecurityContext( + GlobalSSPI.SSPIAuth, + credentialsHandle, + ref securityContext, + spn, + GetInteropFromContextFlagsPal(requestedContextFlags), + Interop.SspiCli.Endianness.Network, + inSecurityBufferArray, + outSecurityBuffer, + ref outContextFlags); + + contextFlags = GetContextFlagsPalFromInterop(outContextFlags); + return SslStreamPal.GetSecurityStatusPalFromInterop(winStatus); + } + + internal static SecurityStatusPal CompleteAuthToken( + ref SafeDeleteContext securityContext, + SecurityBuffer[] inSecurityBufferArray) + { + Interop.SecurityStatus winStatus = (Interop.SecurityStatus)SSPIWrapper.CompleteAuthToken( + GlobalSSPI.SSPIAuth, + ref securityContext, + inSecurityBufferArray); + return SslStreamPal.GetSecurityStatusPalFromInterop(winStatus); + } + + internal static SecurityStatusPal AcceptSecurityContext( + SafeFreeCredentials credentialsHandle, + ref SafeDeleteContext securityContext, + ContextFlagsPal requestedContextFlags, + SecurityBuffer[] inSecurityBufferArray, + SecurityBuffer outSecurityBuffer, + ref ContextFlagsPal contextFlags) + { + Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; + Interop.SecurityStatus winStatus = (Interop.SecurityStatus)SSPIWrapper.AcceptSecurityContext( + GlobalSSPI.SSPIAuth, + credentialsHandle, + ref securityContext, + GetInteropFromContextFlagsPal(requestedContextFlags), + Interop.SspiCli.Endianness.Network, + inSecurityBufferArray, + outSecurityBuffer, + ref outContextFlags); + + contextFlags = GetContextFlagsPalFromInterop(outContextFlags); + return SslStreamPal.GetSecurityStatusPalFromInterop(winStatus); + } + + private static void ValidateImpersonationLevel(TokenImpersonationLevel impersonationLevel) + { + if (impersonationLevel != TokenImpersonationLevel.Identification && + impersonationLevel != TokenImpersonationLevel.Impersonation && + impersonationLevel != TokenImpersonationLevel.Delegation) + { + throw new ArgumentOutOfRangeException("impersonationLevel", impersonationLevel.ToString(), SR.net_auth_supported_impl_levels); + } + } + + private 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); + } + + private 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)SslStreamPal.GetInteropFromSecurityStatusPal(statusCode)); + } + + internal static int Encrypt( + SafeDeleteContext securityContext, + byte[] buffer, + int offset, + int count, + object secSizes, + bool isConfidential, + bool isNtlm, + ref byte[] output, + uint sequenceNumber) + { + SecSizes sizes = secSizes as SecSizes; + + try + { + int maxCount = checked(Int32.MaxValue - 4 - sizes.BlockSize - sizes.SecurityTrailer); + + if (count > maxCount || count < 0) + { + throw new ArgumentOutOfRangeException("count", SR.Format(SR.net_io_out_range, maxCount)); + } + } + catch (Exception e) + { + if (!ExceptionCheck.IsFatal(e) && GlobalLog.IsEnabled) + { + GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Encrypt", "Arguments out of range."); + } + + throw; + } + + int resultSize = count + sizes.SecurityTrailer + sizes.BlockSize; + if (output == null || output.Length < resultSize + 4) + { + output = new byte[resultSize + 4]; + } + + // Make a copy of user data for in-place encryption. + Buffer.BlockCopy(buffer, offset, output, 4 + sizes.SecurityTrailer, count); + + // Prepare buffers TOKEN(signature), DATA and Padding. + var securityBuffer = new SecurityBuffer[3]; + securityBuffer[0] = new SecurityBuffer(output, 4, sizes.SecurityTrailer, SecurityBufferType.Token); + securityBuffer[1] = new SecurityBuffer(output, 4 + sizes.SecurityTrailer, count, SecurityBufferType.Data); + securityBuffer[2] = new SecurityBuffer(output, 4 + sizes.SecurityTrailer + count, sizes.BlockSize, SecurityBufferType.Padding); + + int errorCode; + if (isConfidential) + { + errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); + } + else + { + if (isNtlm) + { + securityBuffer[1].type |= SecurityBufferType.ReadOnlyFlag; + } + + errorCode = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, 0); + } + + if (errorCode != 0) + { + if (GlobalLog.IsEnabled) + { + GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Encrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo)); + } + throw new Win32Exception(errorCode); + } + + // Compacting the result. + resultSize = securityBuffer[0].size; + bool forceCopy = false; + if (resultSize != sizes.SecurityTrailer) + { + forceCopy = true; + Buffer.BlockCopy(output, securityBuffer[1].offset, output, 4 + resultSize, securityBuffer[1].size); + } + + resultSize += securityBuffer[1].size; + if (securityBuffer[2].size != 0 && (forceCopy || resultSize != (count + sizes.SecurityTrailer))) + { + Buffer.BlockCopy(output, securityBuffer[2].offset, output, 4 + resultSize, securityBuffer[2].size); + } + + resultSize += securityBuffer[2].size; + return resultSize; + } + + internal static int Decrypt( + SafeDeleteContext securityContext, + byte[] buffer, + int offset, + int count, + bool isConfidential, + bool isNtlm, + out int newOffset, + uint sequenceNumber) + { + if (isNtlm) + { + return DecryptNtlm(securityContext, buffer, offset, count, isConfidential, out newOffset, sequenceNumber); + } + + // + // Kerberos and up + // + var securityBuffer = new SecurityBuffer[2]; + securityBuffer[0] = new SecurityBuffer(buffer, offset, count, SecurityBufferType.Stream); + securityBuffer[1] = new SecurityBuffer(0, SecurityBufferType.Data); + + int errorCode; + if (isConfidential) + { + errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); + } + else + { + errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); + } + + if (errorCode != 0) + { + if (GlobalLog.IsEnabled) + { + GlobalLog.Print("NTAuthentication#"+ "::Decrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo)); + } + throw new Win32Exception(errorCode); + } + + if (securityBuffer[1].type != SecurityBufferType.Data) + { + throw new InternalException(); + } + + newOffset = securityBuffer[1].offset; + return securityBuffer[1].size; + } + + internal static int DecryptNtlm( + SafeDeleteContext securityContext, + byte[] buffer, + int offset, + int count, + bool isConfidential, + out int newOffset, + uint sequenceNumber) + { + var securityBuffer = new SecurityBuffer[2]; + securityBuffer[0] = new SecurityBuffer(buffer, offset, 16, SecurityBufferType.Token); + securityBuffer[1] = new SecurityBuffer(buffer, offset + 16, count - 16, SecurityBufferType.Data); + + int errorCode; + SecurityBufferType realDataType = SecurityBufferType.Data; + + if (isConfidential) + { + errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); + } + else + { + realDataType |= SecurityBufferType.ReadOnlyFlag; + securityBuffer[1].type = realDataType; + errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, securityContext, securityBuffer, sequenceNumber); + } + + if (errorCode != 0) + { + if (GlobalLog.IsEnabled) + { + GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(securityContext) + "::Decrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo)); + } + throw new Win32Exception(errorCode); + } + + if (securityBuffer[1].type != realDataType) + { + throw new InternalException(); + } + + newOffset = securityBuffer[1].offset; + return securityBuffer[1].size; + } + + private static ContextFlagsPal GetContextFlagsPalFromInterop(Interop.SspiCli.ContextFlags win32Flags) + { + ContextFlagsPal flags = ContextFlagsPal.Zero; + if ((win32Flags & Interop.SspiCli.ContextFlags.AcceptExtendedError) != 0) + { + flags |= ContextFlagsPal.AcceptExtendedError; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.AcceptIdentify) != 0) + { + flags |= ContextFlagsPal.AcceptIdentify; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.AcceptIntegrity) != 0) + { + flags |= ContextFlagsPal.AcceptIntegrity; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.AcceptStream) != 0) + { + flags |= ContextFlagsPal.AcceptStream; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.AllocateMemory) != 0) + { + flags |= ContextFlagsPal.AllocateMemory; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.AllowMissingBindings) != 0) + { + flags |= ContextFlagsPal.AllowMissingBindings; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.Confidentiality) != 0) + { + flags |= ContextFlagsPal.Confidentiality; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.Connection) != 0) + { + flags |= ContextFlagsPal.Connection; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.Delegate) != 0) + { + flags |= ContextFlagsPal.Delegate; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.InitExtendedError) != 0) + { + flags |= ContextFlagsPal.InitExtendedError; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.InitIdentify) != 0) + { + flags |= ContextFlagsPal.InitIdentify; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.InitIntegrity) != 0) + { + flags |= ContextFlagsPal.InitIntegrity; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.InitManualCredValidation) != 0) + { + flags |= ContextFlagsPal.InitManualCredValidation; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.InitStream) != 0) + { + flags |= ContextFlagsPal.InitStream; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.InitUseSuppliedCreds) != 0) + { + flags |= ContextFlagsPal.InitUseSuppliedCreds; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.MutualAuth) != 0) + { + flags |= ContextFlagsPal.MutualAuth; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.ProxyBindings) != 0) + { + flags |= ContextFlagsPal.ProxyBindings; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.ReplayDetect) != 0) + { + flags |= ContextFlagsPal.ReplayDetect; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.SequenceDetect) != 0) + { + flags |= ContextFlagsPal.SequenceDetect; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.UnverifiedTargetName) != 0) + { + flags |= ContextFlagsPal.UnverifiedTargetName; + } + if ((win32Flags & Interop.SspiCli.ContextFlags.UseSessionKey) != 0) + { + flags |= ContextFlagsPal.UseSessionKey; + } + return flags; + } + + private static Interop.SspiCli.ContextFlags GetInteropFromContextFlagsPal(ContextFlagsPal flags) + { + Interop.SspiCli.ContextFlags win32Flags = Interop.SspiCli.ContextFlags.Zero; + if ((flags & ContextFlagsPal.AcceptExtendedError) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.AcceptExtendedError; + } + if ((flags & ContextFlagsPal.AcceptIdentify) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.AcceptIdentify; + } + if ((flags & ContextFlagsPal.AcceptIntegrity) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.AcceptIntegrity; + } + if ((flags & ContextFlagsPal.AcceptStream) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.AcceptStream; + } + if ((flags & ContextFlagsPal.AllocateMemory) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.AllocateMemory; + } + if ((flags & ContextFlagsPal.AllowMissingBindings) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.AllowMissingBindings; + } + if ((flags & ContextFlagsPal.Confidentiality) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.Confidentiality; + } + if ((flags & ContextFlagsPal.Connection) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.Connection; + } + if ((flags & ContextFlagsPal.Delegate) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.Delegate; + } + if ((flags & ContextFlagsPal.InitExtendedError) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.InitExtendedError; + } + if ((flags & ContextFlagsPal.InitIdentify) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.InitIdentify; + } + if ((flags & ContextFlagsPal.InitIntegrity) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.InitIntegrity; + } + if ((flags & ContextFlagsPal.InitManualCredValidation) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.InitManualCredValidation; + } + if ((flags & ContextFlagsPal.InitStream) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.InitStream; + } + if ((flags & ContextFlagsPal.InitUseSuppliedCreds) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.InitUseSuppliedCreds; + } + if ((flags & ContextFlagsPal.MutualAuth) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.MutualAuth; + } + if ((flags & ContextFlagsPal.ProxyBindings) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.ProxyBindings; + } + if ((flags & ContextFlagsPal.ReplayDetect) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.ReplayDetect; + } + if ((flags & ContextFlagsPal.SequenceDetect) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.SequenceDetect; + } + if ((flags & ContextFlagsPal.UnverifiedTargetName) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.UnverifiedTargetName; + } + if ((flags & ContextFlagsPal.UseSessionKey) != 0) + { + win32Flags |= Interop.SspiCli.ContextFlags.UseSessionKey; + } + return win32Flags; + } + } +} diff --git a/src/System.Net.Security/src/System/Net/SslStreamPal.Windows.cs b/src/System.Net.Security/src/System/Net/SslStreamPal.Windows.cs index 5848c17c84a5..26ebc7e50e05 100644 --- a/src/System.Net.Security/src/System/Net/SslStreamPal.Windows.cs +++ b/src/System.Net.Security/src/System/Net/SslStreamPal.Windows.cs @@ -298,12 +298,12 @@ private static SafeFreeCredentials AcquireCredentialsHandle(Interop.SspiCli.Cred } } - private static SecurityStatusPal GetSecurityStatusPalFromWin32Int(int win32SecurityStatus) + internal static SecurityStatusPal GetSecurityStatusPalFromWin32Int(int win32SecurityStatus) { return GetSecurityStatusPalFromInterop((Interop.SecurityStatus)win32SecurityStatus); } - private static SecurityStatusPal GetSecurityStatusPalFromInterop(Interop.SecurityStatus win32SecurityStatus) + internal static SecurityStatusPal GetSecurityStatusPalFromInterop(Interop.SecurityStatus win32SecurityStatus) { switch (win32SecurityStatus) { @@ -391,7 +391,7 @@ private static SecurityStatusPal GetSecurityStatusPalFromInterop(Interop.Securit } } - private static Interop.SecurityStatus GetInteropFromSecurityStatusPal(SecurityStatusPal status) + internal static Interop.SecurityStatus GetInteropFromSecurityStatusPal(SecurityStatusPal status) { switch (status) { From 45d6dbcc556f7371da4a9a2088925606e734abca Mon Sep 17 00:00:00 2001 From: Shruti Garg Date: Fri, 22 Jan 2016 15:24:38 +0530 Subject: [PATCH 3/5] Fixed PR comments --- .../Windows/sspicli/NegotiationInfoClass.cs | 6 +---- .../src/System.Net.Security.csproj | 4 +--- .../src/System/Net/NTAuthentication.cs | 24 ------------------- .../src/System/Net}/NegotiationInfoClass.cs | 3 ++- .../Net/SecureProtocols/InternalNegoState.cs | 1 - .../Net/SecureProtocols/NegoState.Unix.cs | 1 - .../Net/SecureProtocols/NegoState.Windows.cs | 17 ++++--------- 7 files changed, 9 insertions(+), 47 deletions(-) rename src/{Common/src/Interop/Unix/System.Net.Security.Native => System.Net.Security/src/System/Net}/NegotiationInfoClass.cs (82%) diff --git a/src/Common/src/Interop/Windows/sspicli/NegotiationInfoClass.cs b/src/Common/src/Interop/Windows/sspicli/NegotiationInfoClass.cs index 3a3149598b7a..1fcded4950d9 100644 --- a/src/Common/src/Interop/Windows/sspicli/NegotiationInfoClass.cs +++ b/src/Common/src/Interop/Windows/sspicli/NegotiationInfoClass.cs @@ -7,12 +7,8 @@ namespace System.Net { // This class is used to determine if NTLM or // Kerberos are used in the context of a Negotiate handshake - internal class NegotiationInfoClass + internal partial class NegotiationInfoClass { - internal const string NTLM = "NTLM"; - internal const string Kerberos = "Kerberos"; - internal const string WDigest = "WDigest"; - internal const string Negotiate = "Negotiate"; internal string AuthenticationPackage; internal NegotiationInfoClass(SafeHandle safeHandle, int negotiationState) diff --git a/src/System.Net.Security/src/System.Net.Security.csproj b/src/System.Net.Security/src/System.Net.Security.csproj index 8c095c1e1992..dc3a00c70f34 100644 --- a/src/System.Net.Security/src/System.Net.Security.csproj +++ b/src/System.Net.Security/src/System.Net.Security.csproj @@ -56,6 +56,7 @@ + @@ -294,9 +295,6 @@ Common\Interop\Unix\System.Net.Security.Native\Interop.Initialization.cs - - Common\Interop\Unix\System.Net.Security.Native\NegotiationInfoClass.cs - Common\Microsoft\Win32\SafeHandles\SafeX509Handles.Unix.cs diff --git a/src/System.Net.Security/src/System/Net/NTAuthentication.cs b/src/System.Net.Security/src/System/Net/NTAuthentication.cs index 6a7cb10b9034..5deb98af009b 100644 --- a/src/System.Net.Security/src/System/Net/NTAuthentication.cs +++ b/src/System.Net.Security/src/System/Net/NTAuthentication.cs @@ -28,7 +28,6 @@ internal class NTAuthentication private bool _isCompleted; private string _protocolName; - private object _sizes; private string _lastProtocolName; private string _package; @@ -191,28 +190,6 @@ internal string ProtocolName } } - internal object Sizes - { - get - { - if ((IsCompleted && IsValidContext)) - { - if (GlobalLog.IsEnabled) - { - GlobalLog.Assert("NTAuthentication#{0}::MaxDataSize|The context is not completed or invalid.", LoggingHash.HashString(this)); - } - Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::MaxDataSize |The context is not completed or invalid."); - } - - if (_sizes == null) - { - _sizes = NegoState.QueryContextSizes(_securityContext); - } - - return _sizes; - } - } - // // This overload does not attempt to impersonate because the caller either did it already or the original thread context is still preserved. // @@ -483,7 +460,6 @@ internal int Encrypt(byte[] buffer, int offset, int count, ref byte[] output, ui buffer, offset, count, - Sizes, IsConfidentialityFlag, IsNTLM, ref output, diff --git a/src/Common/src/Interop/Unix/System.Net.Security.Native/NegotiationInfoClass.cs b/src/System.Net.Security/src/System/Net/NegotiationInfoClass.cs similarity index 82% rename from src/Common/src/Interop/Unix/System.Net.Security.Native/NegotiationInfoClass.cs rename to src/System.Net.Security/src/System/Net/NegotiationInfoClass.cs index ead6c893c9ec..eaf5983cfa9d 100644 --- a/src/Common/src/Interop/Unix/System.Net.Security.Native/NegotiationInfoClass.cs +++ b/src/System.Net.Security/src/System/Net/NegotiationInfoClass.cs @@ -5,10 +5,11 @@ namespace System.Net { // This class is used to determine if NTLM or // Kerberos are used in the context of a Negotiate handshake - internal class NegotiationInfoClass + internal partial class NegotiationInfoClass { internal const string NTLM = "NTLM"; internal const string Kerberos = "Kerberos"; + internal const string WDigest = "WDigest"; internal const string Negotiate = "Negotiate"; } } diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/InternalNegoState.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/InternalNegoState.cs index d215e11c3e42..beef946762f2 100644 --- a/src/System.Net.Security/src/System/Net/SecureProtocols/InternalNegoState.cs +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/InternalNegoState.cs @@ -148,7 +148,6 @@ internal void ValidateCreateContext( { package = NegotiationInfoClass.NTLM; } - else if (protectionLevel == ProtectionLevel.EncryptAndSign) { flags |= ContextFlagsPal.Confidentiality; diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Unix.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Unix.cs index 90afad24c3d0..820a6116b282 100644 --- a/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Unix.cs +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Unix.cs @@ -115,7 +115,6 @@ internal static int Encrypt( byte[] buffer, int offset, int count, - object secSizes, bool isConfidential, bool isNtlm, ref byte[] output, diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Windows.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Windows.cs index c91feebd2509..da0b47514f45 100644 --- a/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Windows.cs +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Windows.cs @@ -35,7 +35,6 @@ internal IIdentity GetIdentity() SecurityContextTokenHandle token = null; try { - //token = _context.GetContextToken(); SecurityStatusPal status; SafeDeleteContext securityContext = _context.GetContext(out status); if (status != SecurityStatusPal.OK) @@ -94,15 +93,6 @@ internal static string QueryContextAuthenticationPackage(SafeDeleteContext secur return null; } - internal static object QueryContextSizes(SafeDeleteContext securityContext) - { - return SSPIWrapper.QueryContextAttributes( - GlobalSSPI.SSPIAuth, - securityContext, - Interop.SspiCli.ContextAttribute.Sizes - ) as SecSizes; - } - internal static int QueryMaxTokenSize(string package) { return SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPIAuth, package, true).MaxToken; @@ -263,13 +253,16 @@ internal static int Encrypt( byte[] buffer, int offset, int count, - object secSizes, bool isConfidential, bool isNtlm, ref byte[] output, uint sequenceNumber) { - SecSizes sizes = secSizes as SecSizes; + SecSizes sizes = SSPIWrapper.QueryContextAttributes( + GlobalSSPI.SSPIAuth, + securityContext, + Interop.SspiCli.ContextAttribute.Sizes + ) as SecSizes; try { From bb715d436b399a690fa90b568d89868b2bdfdedb Mon Sep 17 00:00:00 2001 From: Shruti Garg Date: Wed, 27 Jan 2016 16:35:40 +0530 Subject: [PATCH 4/5] Implementing NegoState.Unix.cs and SafeHandles --- .../SecuritySafeHandles.cs | 89 +++++++ .../Unix/libssl/SecuritySafeHandles.cs | 80 ++++-- .../src/System.Net.Security.csproj | 15 ++ .../Net/CertificateValidationPal.Unix.cs | 6 +- .../Net/SecureProtocols/NegoState.Unix.cs | 240 ++++++++++++++++-- .../src/System/Net/SslStreamPal.Unix.cs | 16 +- 6 files changed, 392 insertions(+), 54 deletions(-) create mode 100644 src/Common/src/Interop/Unix/System.Net.Security.Native/SecuritySafeHandles.cs 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..eaedd736d026 --- /dev/null +++ b/src/Common/src/Interop/Unix/System.Net.Security.Native/SecuritySafeHandles.cs @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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) + { + _credential = SafeGssCredHandle.Create(username, password, domain); + } + + public override bool IsInvalid + { + get { return (null == _credential); } + } + + protected override bool ReleaseHandle() + { + _credential.Dispose(); + _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.Create(targetName, false); + } + catch + { + base.ReleaseHandle(); + 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; + } + _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 2f4ae05d3699..9c9b72aff954 100644 --- a/src/Common/src/Interop/Unix/libssl/SecuritySafeHandles.cs +++ b/src/Common/src/Interop/Unix/libssl/SecuritySafeHandles.cs @@ -55,12 +55,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; @@ -86,7 +93,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( @@ -206,13 +213,48 @@ 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 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() + { + _credential.DangerousRelease(); + _credential = null; + return true; + } + + public override string ToString() + { + return IsInvalid ? String.Empty : handle.ToString(); + } + } + + internal sealed class SafeDeleteSslContext : SafeDeleteContext + { private readonly SafeSslHandle _sslContext; public SafeSslHandle SslContext @@ -223,18 +265,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 { @@ -248,11 +282,8 @@ public SafeDeleteContext(SafeFreeCredentials credential, bool isServer, bool rem } catch(Exception ex) { - if (gotCredRef) - { - _credential.DangerousRelease(); - } Debug.Write("Exception Caught. - " + ex); + base.ReleaseHandle(); throw; } } @@ -265,13 +296,6 @@ 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) diff --git a/src/System.Net.Security/src/System.Net.Security.csproj b/src/System.Net.Security/src/System.Net.Security.csproj index dc3a00c70f34..1345462a56b1 100644 --- a/src/System.Net.Security/src/System.Net.Security.csproj +++ b/src/System.Net.Security/src/System.Net.Security.csproj @@ -295,6 +295,21 @@ 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\SecuritySafeHandles.cs + + + Common\Microsoft\Win32\SafeHandles\GssSafeHandles.cs + + + Common\Interop\Unix\System.Net.Security.Native\Interop.NetSecurity.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 213567bd1887..290819784999 100644 --- a/src/System.Net.Security/src/System/Net/CertificateValidationPal.Unix.cs +++ b/src/System.Net.Security/src/System/Net/CertificateValidationPal.Unix.cs @@ -112,7 +112,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) { @@ -162,7 +162,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) { @@ -256,7 +256,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/SecureProtocols/NegoState.Unix.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Unix.cs index 820a6116b282..d0b5dbee34c0 100644 --- a/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Unix.cs +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Unix.cs @@ -6,8 +6,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 { @@ -20,9 +23,37 @@ namespace System.Net.Security // internal partial class NegoState { + private const int LogonDenied = unchecked((int)0x8009030C); + + private class NNSProtocolException : Exception + { + internal static readonly Exception Instance; + + // MS-NNS Protocol requires a Windows error code to be + // passed back. Hence, we always use NTE_FAIL + private const int NTE_FAIL = unchecked((int)0x80090020); + + static NNSProtocolException() + { + Instance = new NNSProtocolException(); + } + + private NNSProtocolException() : base() + { + HResult = NTE_FAIL; + } + } + + internal IIdentity GetIdentity() { - 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) @@ -32,17 +63,19 @@ internal static string QueryContextAssociatedName(SafeDeleteContext securityCont internal static string QueryContextAuthenticationPackage(SafeDeleteContext securityContext) { - throw new PlatformNotSupportedException(); + return NegotiationInfoClass.Kerberos; } internal static object QueryContextSizes(SafeDeleteContext securityContext) { - throw new PlatformNotSupportedException(); + // This return value is never used + return null; } internal static int QueryMaxTokenSize(string package) { - throw new PlatformNotSupportedException(); + // The value is unused in non-Windows code paths + return 0; } internal static string QueryContextClientSpecifiedSpn(SafeDeleteContext securityContext) @@ -52,12 +85,32 @@ 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(); + Debug.Assert(!isServer, "AcquireCredentialsHandle: Server is not yet supported"); + SafeFreeCredentials outCredential; + bool isNtlm = string.Equals(package, NegotiationInfoClass.NTLM); + + if (isNtlm) + { + throw new NotImplementedException("AcquireCredentialsHandle: NTLM is not yet 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( @@ -69,14 +122,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("No support for channel binding on non-Windows"); + } + + return EstablishSecurityContext( + (SafeFreeNegoCredentials)credentialsHandle, + ref securityContext, + false, + spn, + requestedContextFlags, + ((inSecurityBufferArray != null) ? 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( @@ -92,22 +159,38 @@ internal static SecurityStatusPal AcceptSecurityContext( private static void ValidateImpersonationLevel(TokenImpersonationLevel impersonationLevel) { - throw new PlatformNotSupportedException(); + if (impersonationLevel != TokenImpersonationLevel.Identification) + { + throw new ArgumentOutOfRangeException("impersonationLevel", impersonationLevel.ToString(), + SR.net_auth_supported_impl_levels); + } + } private static void ThrowCredentialException(long error) { - throw new PlatformNotSupportedException(); + string message = SR.net_auth_alert; + if ((int)error == LogonDenied) + { + message = SR.net_auth_bad_client_creds; + } + + if ((int)error == NegoState.ERROR_TRUST_FAILURE) + { + message = SR.net_auth_context_expectation_remote; + } + + throw new AuthenticationException(message, null); } private static bool IsLogonDeniedException(Exception exception) { - throw new PlatformNotSupportedException(); + return exception.HResult == LogonDenied; } internal static Exception CreateExceptionFromError(SecurityStatusPal statusCode) { - throw new PlatformNotSupportedException(); + return NNSProtocolException.Instance; } internal static int Encrypt( @@ -120,7 +203,16 @@ internal static int Encrypt( ref byte[] output, uint sequenceNumber) { - throw new PlatformNotSupportedException(); + Debug.Assert(!isNtlm, "Encrypt: NTLM is not yet supported"); + SafeDeleteNegoContext gssContext = securityContext as SafeDeleteNegoContext; + byte[] tempOutput; + Interop.NetSecurity.Encrypt(gssContext.GssContext, isConfidential, buffer, offset, count, out tempOutput); + + // 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); + return tempOutput.Length; } internal static int Decrypt( @@ -133,7 +225,8 @@ internal static int Decrypt( out int newOffset, uint sequenceNumber) { - throw new PlatformNotSupportedException(); + newOffset = offset; + return Interop.NetSecurity.Decrypt(((SafeDeleteNegoContext)securityContext).GssContext, buffer, offset, count); } internal static int DecryptNtlm( @@ -145,7 +238,124 @@ internal static int DecryptNtlm( out int newOffset, uint sequenceNumber) { - throw new PlatformNotSupportedException(); + throw new NotImplementedException("DecryptNtlm: NTLM is not yet 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.NetSecurity.GssFlags inputFlags = GetInteropGssFromContextFlagsPal(inFlags); + uint outputFlags; + SafeGssContextHandle contextHandle = negoContext.GssContext; + + bool done = Interop.NetSecurity.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 = GetContextFlagsPalFromInteropGss((Interop.NetSecurity.GssFlags)outputFlags); + + // Save the inner context handle for further calls to NetSecurity + if (null == negoContext.GssContext) + { + negoContext.SetGssContext(contextHandle); + } + return done ? SecurityStatusPal.CompleteNeeded : SecurityStatusPal.ContinueNeeded; + } + catch + { + return SecurityStatusPal.InternalError; + } + } + + private static ContextFlagsPal GetContextFlagsPalFromInteropGss(Interop.NetSecurity.GssFlags gssFlags) + { + ContextFlagsPal flags = ContextFlagsPal.Zero; + if ((gssFlags & Interop.NetSecurity.GssFlags.GSS_C_INTEG_FLAG) != 0) + { + flags |= (ContextFlagsPal.AcceptIntegrity | ContextFlagsPal.InitIntegrity); + } + if ((gssFlags & Interop.NetSecurity.GssFlags.GSS_C_CONF_FLAG) != 0) + { + flags |= ContextFlagsPal.Confidentiality; + } + if ((gssFlags & Interop.NetSecurity.GssFlags.GSS_C_IDENTIFY_FLAG) != 0) + { + flags |= ContextFlagsPal.InitIdentify; + } + if ((gssFlags & Interop.NetSecurity.GssFlags.GSS_C_MUTUAL_FLAG) != 0) + { + flags |= ContextFlagsPal.MutualAuth; + } + if ((gssFlags & Interop.NetSecurity.GssFlags.GSS_C_REPLAY_FLAG) != 0) + { + flags |= ContextFlagsPal.ReplayDetect; + } + if ((gssFlags & Interop.NetSecurity.GssFlags.GSS_C_SEQUENCE_FLAG) != 0) + { + flags |= ContextFlagsPal.SequenceDetect; + } + return flags; + } + + private static Interop.NetSecurity.GssFlags GetInteropGssFromContextFlagsPal(ContextFlagsPal flags) + { + Interop.NetSecurity.GssFlags gssFlags = (Interop.NetSecurity.GssFlags)0; + if ((flags & ContextFlagsPal.AcceptIntegrity) != 0) + { + gssFlags |= Interop.NetSecurity.GssFlags.GSS_C_INTEG_FLAG; + } + if ((flags & ContextFlagsPal.Confidentiality) != 0) + { + gssFlags |= Interop.NetSecurity.GssFlags.GSS_C_CONF_FLAG; + } + if ((flags & ContextFlagsPal.InitIdentify) != 0) + { + gssFlags |= Interop.NetSecurity.GssFlags.GSS_C_IDENTIFY_FLAG; + } + if ((flags & ContextFlagsPal.InitIntegrity) != 0) + { + gssFlags |= Interop.NetSecurity.GssFlags.GSS_C_INTEG_FLAG; + } + if ((flags & ContextFlagsPal.MutualAuth) != 0) + { + gssFlags |= Interop.NetSecurity.GssFlags.GSS_C_MUTUAL_FLAG; + } + if ((flags & ContextFlagsPal.ReplayDetect) != 0) + { + gssFlags |= Interop.NetSecurity.GssFlags.GSS_C_REPLAY_FLAG; + } + if ((flags & ContextFlagsPal.SequenceDetect) != 0) + { + gssFlags |= Interop.NetSecurity.GssFlags.GSS_C_SEQUENCE_FLAG; + } + return gssFlags; } } 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 755c0fbae642..af722050ad2f 100644 --- a/src/System.Net.Security/src/System/Net/SslStreamPal.Unix.cs +++ b/src/System.Net.Security/src/System/Net/SslStreamPal.Unix.cs @@ -44,7 +44,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) @@ -66,7 +66,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; } @@ -78,7 +78,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, @@ -90,7 +90,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; @@ -99,11 +99,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; @@ -116,7 +116,7 @@ private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credentia { // TODO: This Debug.Fail is triggering on Linux in many test cases #4317 // Debug.Fail("Exception Caught. - " + ex); - return SecurityStatusPal.InternalError; + return SecurityStatusPal.InternalError; } } @@ -128,7 +128,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) : From 1c5045c7ba559fc4a26a1f37bf63a7cd4fd600ed Mon Sep 17 00:00:00 2001 From: Shruti Garg Date: Fri, 29 Jan 2016 11:34:57 +0530 Subject: [PATCH 5/5] fixed PR comments --- src/Common/src/Interop/Unix/libssl/SecuritySafeHandles.cs | 1 + .../src/System/Net/SecureProtocols/NegoState.Unix.cs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Common/src/Interop/Unix/libssl/SecuritySafeHandles.cs b/src/Common/src/Interop/Unix/libssl/SecuritySafeHandles.cs index 9c9b72aff954..0b4427a5f3c0 100644 --- a/src/Common/src/Interop/Unix/libssl/SecuritySafeHandles.cs +++ b/src/Common/src/Interop/Unix/libssl/SecuritySafeHandles.cs @@ -242,6 +242,7 @@ public override bool IsInvalid protected override bool ReleaseHandle() { + Debug.Assert((null != _credential), "Null credential in SafeDeleteContext"); _credential.DangerousRelease(); _credential = null; return true; diff --git a/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Unix.cs b/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Unix.cs index d0b5dbee34c0..d00d81a66711 100644 --- a/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Unix.cs +++ b/src/System.Net.Security/src/System/Net/SecureProtocols/NegoState.Unix.cs @@ -90,7 +90,11 @@ internal static SafeFreeCredentials AcquireDefaultCredential(string package, boo internal static SafeFreeCredentials AcquireCredentialsHandle(string package, bool isServer, NetworkCredential credential) { - Debug.Assert(!isServer, "AcquireCredentialsHandle: Server is not yet supported"); + if (isServer) + { + throw new NotImplementedException("AcquireCredentialsHandle: Server is not yet supported"); + } + SafeFreeCredentials outCredential; bool isNtlm = string.Equals(package, NegotiationInfoClass.NTLM);