This PR adds support for passing in the computed TLS channel binding
token (cbt) into the gssapi during NTLM authentication. This included
removing the code that threw the PlatformNotSupported exception.
No new tests were added to this PR since it requires machine changes
to test. However, I manually tested various combinations of NTLM
authentication including when the server requires (or NOT) the cbt
to be used. Currently only Windows Servers uses this functionality
as part of the "Extended Protection for Authentication" feature.
CurlHandler does not support using the cbt during NTLM authentication.
This is a problem with libcurl itself.
As part of this PR I removed a redundant assert and refactored the
SecChannelBindings structure into src/Common.
Fixes dotnet/corefx#34879
Commit migrated from https://github.com/dotnet/corefx/commit/
6575de65608c95717b2a032b689adae32378778f
SafeGssCredHandle initiatorCredHandle,
ref SafeGssContextHandle contextHandle,
bool isNtlmOnly,
+ IntPtr cbt,
+ int cbtSize,
SafeGssNameHandle targetName,
uint reqFlags,
byte[] inputBytes,
ref SafeGssContextHandle context,
SafeGssCredHandle credential,
bool isNtlm,
+ SecurityBuffer cbt,
SafeGssNameHandle targetName,
Interop.NetSecurityNative.GssFlags inFlags,
byte[] buffer,
out uint outFlags,
out int isNtlmUsed)
{
+ // If a TLS channel binding token (cbt) is available then get the pointer
+ // to the application specific data.
+ IntPtr cbtAppData = IntPtr.Zero;
+ int cbtAppDataSize = 0;
+ if (cbt != null)
+ {
+ int appDataOffset = Marshal.SizeOf<SecChannelBindings>();
+ Debug.Assert(appDataOffset < cbt.size);
+ cbtAppData = cbt.unmanagedToken.DangerousGetHandle() + appDataOffset;
+ cbtAppDataSize = cbt.size - appDataOffset;
+ }
+
outputBuffer = null;
outFlags = 0;
credential,
ref context,
isNtlm,
+ cbtAppData,
+ cbtAppDataSize,
targetName,
(uint)inFlags,
buffer,
private static SecurityStatusPal EstablishSecurityContext(
SafeFreeNegoCredentials credential,
ref SafeDeleteContext context,
+ SecurityBuffer cbt,
string targetName,
ContextFlagsPal inFlags,
SecurityBuffer inputBuffer,
ref contextHandle,
credential.GssCredential,
isNtlmOnly,
+ cbt,
negoContext.TargetName,
inputFlags,
inputBuffer?.token,
SecurityBuffer outSecurityBuffer,
ref ContextFlagsPal contextFlags)
{
- // 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);
- }
-
SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle;
if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn))
throw new PlatformNotSupportedException(SR.net_nego_not_supported_empty_target_with_defaultcreds);
}
+ SecurityBuffer cbtBuffer = null;
+ if ((inSecurityBufferArray != null) && (inSecurityBufferArray.Length > 1))
+ {
+ Debug.Assert(inSecurityBufferArray[1].type == SecurityBufferType.SECBUFFER_CHANNEL_BINDINGS);
+ cbtBuffer = inSecurityBufferArray[1];
+ }
+
SecurityStatusPal status = EstablishSecurityContext(
negoCredentialsHandle,
ref securityContext,
+ cbtBuffer,
spn,
requestedContextFlags,
((inSecurityBufferArray != null && inSecurityBufferArray.Length != 0) ? inSecurityBufferArray[0] : null),
--- /dev/null
+// 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.Runtime.InteropServices;
+
+namespace System.Net.Security
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct SecChannelBindings
+ {
+ internal int InitiatorLength;
+ internal int InitiatorOffset;
+ internal int AcceptorAddrType;
+ internal int AcceptorLength;
+ internal int AcceptorOffset;
+ internal int ApplicationDataLength;
+ internal int ApplicationDataOffset;
+ }
+}
GssCredId* claimantCredHandle,
GssCtxId** contextHandle,
uint32_t isNtlm,
+ void* cbt,
+ int32_t cbtSize,
GssName* targetName,
uint32_t reqFlags,
uint8_t* inputBytes,
assert(outBuffer != NULL);
assert(retFlags != NULL);
assert(isNtlmUsed != NULL);
- assert(inputBytes != NULL || inputLength == 0);
+ assert(cbt != NULL || cbtSize == 0);
// Note: claimantCredHandle can be null
// Note: *contextHandle is null only in the first call and non-null in the subsequent calls
GssBuffer gssBuffer = {.length = 0, .value = NULL};
gss_OID_desc* outmech;
+ struct gss_channel_bindings_struct gssCbt;
+ if (cbt != NULL)
+ {
+ memset(&gssCbt, 0, sizeof(struct gss_channel_bindings_struct));
+ gssCbt.application_data.length = (size_t)cbtSize;
+ gssCbt.application_data.value = cbt;
+ }
+
uint32_t majorStatus = gss_init_sec_context(minorStatus,
claimantCredHandle,
contextHandle,
desiredMech,
reqFlags,
0,
- GSS_C_NO_CHANNEL_BINDINGS,
+ (cbt != NULL) ? &gssCbt : GSS_C_NO_CHANNEL_BINDINGS,
&inputToken,
&outmech,
&gssBuffer,
GssCredId* claimantCredHandle,
GssCtxId** contextHandle,
uint32_t isNtlm,
+ void* cbt,
+ int32_t cbtSize,
GssName* targetName,
uint32_t reqFlags,
uint8_t* inputBytes,
<data name="AZURESQL_ChinaEndpoint" xml:space="preserve">
<value>.database.chinacloudapi.cn</value>
</data>
- <data name="net_nego_channel_binding_not_supported" xml:space="preserve">
- <value>No support for channel binding on operating systems other than Windows.</value>
- </data>
<data name="net_gssapi_operation_failed_detailed" xml:space="preserve">
<value>GSSAPI operation failed with error - {0} ({1}).</value>
</data>
<Compile Include="$(CommonPath)\System\Net\Security\Unix\SafeFreeNegoCredentials.cs">
<Link>Common\System\Net\Security\Unix\SafeFreeNegoCredentials.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\Unix\SecChannelBindings.cs">
+ <Link>Common\System\Net\Security\Unix\SecChannelBindings.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\Interop.Libraries.cs">
<Link>Common\Interop\Unix\Interop.Libraries.cs</Link>
</Compile>
<data name="net_gssapi_ntlm_missing_plugin" xml:space="preserve">
<value>NTLM authentication requires the GSSAPI plugin 'gss-ntlmssp'.</value>
</data>
- <data name="net_nego_channel_binding_not_supported" xml:space="preserve">
- <value>No support for channel binding on operating systems other than Windows.</value>
- </data>
<data name="net_ntlm_not_possible_default_cred" xml:space="preserve">
<value>NTLM authentication is not possible with default credentials on this platform.</value>
</data>
<Compile Include="$(CommonPath)\System\Net\Security\Unix\SafeFreeNegoCredentials.cs">
<Link>Common\System\Net\Security\Unix\SafeFreeNegoCredentials.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\Unix\SecChannelBindings.cs">
+ <Link>Common\System\Net\Security\Unix\SecChannelBindings.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.cs">
<Link>Common\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.cs</Link>
</Compile>
<data name="net_gssapi_ntlm_missing_plugin" xml:space="preserve">
<value>NTLM authentication requires the GSSAPI plugin 'gss-ntlmssp'.</value>
</data>
- <data name="net_nego_channel_binding_not_supported" xml:space="preserve">
- <value>No support for channel binding on operating systems other than Windows.</value>
- </data>
<data name="net_ntlm_not_possible_default_cred" xml:space="preserve">
<value>NTLM authentication is not possible with default credentials on this platform.</value>
</data>
<Compile Include="$(CommonPath)\System\Net\Security\Unix\SafeFreeNegoCredentials.cs">
<Link>Common\System\Net\Security\Unix\SafeFreeNegoCredentials.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\Unix\SecChannelBindings.cs">
+ <Link>Common\System\Net\Security\Unix\SecChannelBindings.cs</Link>
+ </Compile>
</ItemGroup>
<!-- Windows specific files -->
<ItemGroup Condition="'$(TargetsWindows)'=='true'">
<data name="net_context_buffer_too_small" xml:space="preserve">
<value>Insufficient buffer space. Required: {0} Actual: {1}.</value>
</data>
- <data name="net_nego_channel_binding_not_supported" xml:space="preserve">
- <value>No support for channel binding on operating systems other than Windows.</value>
- </data>
<data name="net_ntlm_not_possible_default_cred" xml:space="preserve">
<value>NTLM authentication is not possible with default credentials on this platform.</value>
</data>
<Compile Include="$(CommonPath)\System\Net\Security\Unix\SafeFreeNegoCredentials.cs">
<Link>Common\System\Net\Security\Unix\SafeFreeNegoCredentials.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\Unix\SecChannelBindings.cs">
+ <Link>Common\System\Net\Security\Unix\SecChannelBindings.cs</Link>
+ </Compile>
<Compile Include="System\Net\Security\NegotiateStreamPal.Unix.cs" />
<Compile Include="System\Net\Security\Pal.Managed\EndpointChannelBindingToken.cs" />
<Compile Include="System\Net\Security\Pal.Managed\SafeChannelBindingHandle.cs" />
{
internal sealed class SafeChannelBindingHandle : ChannelBinding
{
- [StructLayout(LayoutKind.Sequential)]
- private struct SecChannelBindings
- {
- internal int InitiatorLength;
- internal int InitiatorOffset;
- internal int AcceptorAddrType;
- internal int AcceptorLength;
- internal int AcceptorOffset;
- internal int ApplicationDataLength;
- internal int ApplicationDataOffset;
- }
-
private const int CertHashMaxSize = 128;
private static readonly byte[] s_tlsServerEndPointByteArray = Encoding.UTF8.GetBytes("tls-server-end-point:");
private static readonly byte[] s_tlsUniqueByteArray = Encoding.UTF8.GetBytes("tls-unique:");