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