certHandle.DangerousAddRef(ref hasCertReference);
using (X509Certificate2 cert = new X509Certificate2(certHandle.DangerousGetHandle()))
{
- using (X509Chain chain = TLSCertificateExtensions.BuildNewChain(cert, includeClientApplicationPolicy: false))
+ X509Chain chain = null;
+ try
{
+ chain = TLSCertificateExtensions.BuildNewChain(cert, includeClientApplicationPolicy: false);
if (chain != null && !Ssl.AddExtraChainCertificates(context, chain))
+ {
throw CreateSslException(SR.net_ssl_use_cert_failed);
+ }
+ }
+ finally
+ {
+ if (chain != null)
+ {
+ int elementsCount = chain.ChainElements.Count;
+ for (int i = 0; i < elementsCount; i++)
+ {
+ chain.ChainElements[i].Certificate.Dispose();
+ }
+
+ chain.Dispose();
+ }
}
}
}
internal static extern void SslSetAcceptState(SafeSslHandle ssl);
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslGetVersion")]
- private static extern IntPtr SslGetVersion(SafeSslHandle ssl);
+ internal static extern IntPtr SslGetVersion(SafeSslHandle ssl);
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSetTlsExtHostName")]
[return: MarshalAs(UnmanagedType.Bool)]
return result;
}
- internal static string GetProtocolVersion(SafeSslHandle ssl)
- {
- return Marshal.PtrToStringAnsi(SslGetVersion(ssl));
- }
-
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetSslConnectionInfo")]
internal static extern bool GetSslConnectionInfo(
SafeSslHandle ssl,
}
[StructLayout(LayoutKind.Sequential)]
- internal class SecPkgContext_ApplicationProtocol
+ internal unsafe struct SecPkgContext_ApplicationProtocol
{
private const int MaxProtocolIdSize = 0xFF;
public ApplicationProtocolNegotiationStatus ProtoNegoStatus;
public ApplicationProtocolNegotiationExt ProtoNegoExt;
public byte ProtocolIdSize;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = MaxProtocolIdSize)]
- public byte[] ProtocolId;
+ public fixed byte ProtocolId[MaxProtocolIdSize];
public byte[] Protocol
{
get
{
- return new Span<byte>(ProtocolId, 0, ProtocolIdSize).ToArray();
+ fixed (byte* pid = ProtocolId)
+ {
+ return new Span<byte>(pid, ProtocolIdSize).ToArray();
+ }
}
}
}
// 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.Diagnostics;
using System.Runtime.InteropServices;
namespace System.Net
{
- // TODO (Issue #3114): Investigate if this can be safely converted to a struct.
// From Schannel.h
[StructLayout(LayoutKind.Sequential)]
- internal class SecPkgContext_ConnectionInfo
+ internal struct SecPkgContext_ConnectionInfo
{
public readonly int Protocol;
public readonly int DataCipherAlg;
public readonly int DataHashKeySize;
public readonly int KeyExchangeAlg;
public readonly int KeyExchKeySize;
-
- internal unsafe SecPkgContext_ConnectionInfo(byte[] nativeBuffer)
- {
- fixed (void* voidPtr = nativeBuffer)
- {
- try
- {
- // TODO (Issue #3114): replace with Marshal.PtrToStructure.
- IntPtr unmanagedAddress = new IntPtr(voidPtr);
- Protocol = Marshal.ReadInt32(unmanagedAddress);
- DataCipherAlg = Marshal.ReadInt32(unmanagedAddress, 4);
- DataKeySize = Marshal.ReadInt32(unmanagedAddress, 8);
- DataHashAlg = Marshal.ReadInt32(unmanagedAddress, 12);
- DataHashKeySize = Marshal.ReadInt32(unmanagedAddress, 16);
- KeyExchangeAlg = Marshal.ReadInt32(unmanagedAddress, 20);
- KeyExchKeySize = Marshal.ReadInt32(unmanagedAddress, 24);
- }
- catch (OverflowException)
- {
- NetEventSource.Fail(this, "Negative size");
- throw;
- }
- }
- }
}
}
{
internal static class GlobalSSPI
{
- internal static readonly SSPIInterface SSPIAuth = new SSPIAuthType();
- internal static readonly SSPIInterface SSPISecureChannel = new SSPISecureChannelType();
+ internal static readonly SSPIAuthType SSPIAuth = new SSPIAuthType();
+ internal static readonly SSPISecureChannelType SSPISecureChannel = new SSPISecureChannelType();
}
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct SecPkgContext_IssuerListInfoEx
{
- public SafeHandle aIssuers;
+ public IntPtr aIssuers;
public uint cIssuers;
-
- public unsafe SecPkgContext_IssuerListInfoEx(SafeHandle handle, byte[] nativeBuffer)
- {
- aIssuers = handle;
- fixed (byte* voidPtr = nativeBuffer)
- {
- // TODO (Issue #3114): Properly marshal the struct instead of assuming no padding.
- cIssuers = *((uint*)(voidPtr + IntPtr.Size));
- }
- }
}
[StructLayout(LayoutKind.Sequential)]
{
// This class is used to determine if NTLM or
// Kerberos are used in the context of a Negotiate handshake
- internal partial class NegotiationInfoClass
+ internal static partial class NegotiationInfoClass
{
- internal string AuthenticationPackage;
-
- internal NegotiationInfoClass(SafeHandle safeHandle, int negotiationState)
+ internal static string GetAuthenticationPackageName(SafeHandle safeHandle, int negotiationState)
{
if (safeHandle.IsInvalid)
{
- if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"Invalid handle:{safeHandle}");
- return;
+ if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"Invalid handle:{safeHandle}");
+ return null;
}
- IntPtr packageInfo = safeHandle.DangerousGetHandle();
- if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"packageInfo:{packageInfo} negotiationState:{negotiationState:x}");
-
- if (negotiationState == Interop.SspiCli.SECPKG_NEGOTIATION_COMPLETE
- || negotiationState == Interop.SspiCli.SECPKG_NEGOTIATION_OPTIMISTIC)
+ bool gotRef = false;
+ try
{
- string name = null;
+ safeHandle.DangerousAddRef(ref gotRef);
+ IntPtr packageInfo = safeHandle.DangerousGetHandle();
+ if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"packageInfo:{packageInfo} negotiationState:{negotiationState:x}");
- unsafe
+ if (negotiationState == Interop.SspiCli.SECPKG_NEGOTIATION_COMPLETE ||
+ negotiationState == Interop.SspiCli.SECPKG_NEGOTIATION_OPTIMISTIC)
{
- IntPtr unmanagedString = ((SecurityPackageInfo *)packageInfo)->Name;
- if (unmanagedString != IntPtr.Zero)
+ string name;
+ unsafe
{
- name = Marshal.PtrToStringUni(unmanagedString);
+ name = Marshal.PtrToStringUni(((SecurityPackageInfo*)packageInfo)->Name);
}
- }
- if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"packageInfo:{packageInfo} negotiationState:{negotiationState:x} name:{name}");
+ if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"packageInfo:{packageInfo} negotiationState:{negotiationState:x} name:{name}");
- // An optimization for future string comparisons.
- if (string.Equals(name, Kerberos, StringComparison.OrdinalIgnoreCase))
- {
- AuthenticationPackage = Kerberos;
+ // An optimization for future string comparisons.
+ return
+ string.Equals(name, Kerberos, StringComparison.OrdinalIgnoreCase) ? Kerberos :
+ string.Equals(name, NTLM, StringComparison.OrdinalIgnoreCase) ? NTLM :
+ name;
}
- else if (string.Equals(name, NTLM, StringComparison.OrdinalIgnoreCase))
- {
- AuthenticationPackage = NTLM;
- }
- else
+ }
+ finally
+ {
+ if (gotRef)
{
- AuthenticationPackage = name;
+ safeHandle.DangerousRelease();
}
}
+
+ return null;
}
}
}
return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential);
}
- public int AcceptSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
+ public int AcceptSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, ReadOnlySpan<SecurityBuffer> inputBuffers, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ref SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
{
- return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, null, inputBuffers, outputBuffer, ref outFlags);
+ return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, inputBuffers, ref outputBuffer, ref outFlags);
}
- public int InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
+ public int InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ReadOnlySpan<SecurityBuffer> inputBuffers, ref SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
{
- return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, inputBuffer, null, outputBuffer, ref outFlags);
- }
-
- public int InitializeSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
- {
- return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, null, inputBuffers, outputBuffer, ref outFlags);
+ return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, inputBuffers, ref outputBuffer, ref outFlags);
}
public int EncryptMessage(SafeDeleteContext context, ref Interop.SspiCli.SecBufferDesc inputOutput, uint sequenceNumber)
public int QueryContextChannelBinding(SafeDeleteContext context, Interop.SspiCli.ContextAttribute attribute, out SafeFreeContextBufferChannelBinding binding)
{
// Querying an auth SSP for a CBT is not supported.
- binding = null;
throw new NotSupportedException();
}
- public unsafe int QueryContextAttributes(SafeDeleteContext context, Interop.SspiCli.ContextAttribute attribute, byte[] buffer, Type handleType, out SafeHandle refHandle)
+ public unsafe int QueryContextAttributes(SafeDeleteContext context, Interop.SspiCli.ContextAttribute attribute, Span<byte> buffer, Type handleType, out SafeHandle refHandle)
{
refHandle = null;
if (handleType != null)
return GetSecurityContextToken(phContext, out phToken);
}
- public int CompleteAuthToken(ref SafeDeleteContext refContext, SecurityBuffer[] inputBuffers)
+ public int CompleteAuthToken(ref SafeDeleteContext refContext, in SecurityBuffer inputBuffer)
{
- return SafeDeleteContext.CompleteAuthToken(ref refContext, inputBuffers);
+ return SafeDeleteContext.CompleteAuthToken(ref refContext, in inputBuffer);
}
private static int GetSecurityContextToken(SafeDeleteContext phContext, out SecurityContextTokenHandle safeHandle)
{
- safeHandle = null;
-
try
{
bool ignore = false;
}
}
- public int ApplyControlToken(ref SafeDeleteContext refContext, SecurityBuffer[] inputBuffers)
+ public int ApplyControlToken(ref SafeDeleteContext refContext, in SecurityBuffer inputBuffers)
{
throw new NotSupportedException();
}
SecurityPackageInfoClass[] SecurityPackages { get; set; }
int EnumerateSecurityPackages(out int pkgnum, out SafeFreeContextBuffer pkgArray);
int AcquireCredentialsHandle(string moduleName, Interop.SspiCli.CredentialUse usage, ref SafeSspiAuthDataHandle authdata, out SafeFreeCredentials outCredential);
- int AcquireDefaultCredential(string moduleName, Interop.SspiCli.CredentialUse usage, out SafeFreeCredentials outCredential);
int AcquireCredentialsHandle(string moduleName, Interop.SspiCli.CredentialUse usage, ref Interop.SspiCli.SCHANNEL_CRED authdata, out SafeFreeCredentials outCredential);
- int AcceptSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags);
- int InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags);
- int InitializeSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags);
+ int AcquireDefaultCredential(string moduleName, Interop.SspiCli.CredentialUse usage, out SafeFreeCredentials outCredential);
+ int AcceptSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, ReadOnlySpan<SecurityBuffer> inputBuffers, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ref SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags);
+ int InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ReadOnlySpan<SecurityBuffer> inputBuffers, ref SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags);
int EncryptMessage(SafeDeleteContext context, ref Interop.SspiCli.SecBufferDesc inputOutput, uint sequenceNumber);
int DecryptMessage(SafeDeleteContext context, ref Interop.SspiCli.SecBufferDesc inputOutput, uint sequenceNumber);
int MakeSignature(SafeDeleteContext context, ref Interop.SspiCli.SecBufferDesc inputOutput, uint sequenceNumber);
int VerifySignature(SafeDeleteContext context, ref Interop.SspiCli.SecBufferDesc inputOutput, uint sequenceNumber);
int QueryContextChannelBinding(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, out SafeFreeContextBufferChannelBinding refHandle);
- int QueryContextAttributes(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, byte[] buffer, Type handleType, out SafeHandle refHandle);
+ int QueryContextAttributes(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, Span<byte> buffer, Type handleType, out SafeHandle refHandle);
int QuerySecurityContextToken(SafeDeleteContext phContext, out SecurityContextTokenHandle phToken);
- int CompleteAuthToken(ref SafeDeleteContext refContext, SecurityBuffer[] inputBuffers);
- int ApplyControlToken(ref SafeDeleteContext refContext, SecurityBuffer[] inputBuffers);
+ int CompleteAuthToken(ref SafeDeleteContext refContext, in SecurityBuffer inputBuffer);
+ int ApplyControlToken(ref SafeDeleteContext refContext, in SecurityBuffer inputBuffer);
}
}
return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential);
}
- public int AcceptSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
+ public int AcceptSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, ReadOnlySpan<SecurityBuffer> inputBuffers, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ref SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
{
- return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, inputBuffer, null, outputBuffer, ref outFlags);
+ return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, inputBuffers, ref outputBuffer, ref outFlags);
}
- public int AcceptSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
+ public int InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ReadOnlySpan<SecurityBuffer> inputBuffers, ref SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
{
- return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, null, inputBuffers, outputBuffer, ref outFlags);
- }
-
- public int InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
- {
- return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, inputBuffer, null, outputBuffer, ref outFlags);
- }
-
- public int InitializeSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
- {
- return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, null, inputBuffers, outputBuffer, ref outFlags);
+ return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, inputBuffers, ref outputBuffer, ref outFlags);
}
public int EncryptMessage(SafeDeleteContext context, ref Interop.SspiCli.SecBufferDesc inputOutput, uint sequenceNumber)
return SafeFreeContextBufferChannelBinding.QueryContextChannelBinding(phContext, attribute, &bindings, refHandle);
}
- public unsafe int QueryContextAttributes(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, byte[] buffer, Type handleType, out SafeHandle refHandle)
+ public unsafe int QueryContextAttributes(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, Span<byte> buffer, Type handleType, out SafeHandle refHandle)
{
refHandle = null;
if (handleType != null)
throw new NotSupportedException();
}
- public int CompleteAuthToken(ref SafeDeleteContext refContext, SecurityBuffer[] inputBuffers)
+ public int CompleteAuthToken(ref SafeDeleteContext refContext, in SecurityBuffer inputBuffer)
{
throw new NotSupportedException();
}
- public int ApplyControlToken(ref SafeDeleteContext refContext, SecurityBuffer[] inputBuffers)
+ public int ApplyControlToken(ref SafeDeleteContext refContext, in SecurityBuffer inputBuffer)
{
- return SafeDeleteContext.ApplyControlToken(ref refContext, inputBuffers);
+ return SafeDeleteContext.ApplyControlToken(ref refContext, in inputBuffer);
}
}
}
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
+using System.Diagnostics;
using System.Globalization;
using System.Net.Security;
using System.Runtime.InteropServices;
}
finally
{
- if (arrayBaseHandle != null)
- {
- arrayBaseHandle.Dispose();
- }
+ arrayBaseHandle?.Dispose();
}
}
}
return outCredential;
}
- internal static int InitializeSecurityContext(SSPIInterface secModule, ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness datarep, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
+ internal static int InitializeSecurityContext(SSPIInterface secModule, ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness datarep, ReadOnlySpan<SecurityBuffer> inputBuffers, ref SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
{
if (NetEventSource.IsEnabled) NetEventSource.Log.InitializeSecurityContext(credential, context, targetName, inFlags);
- int errorCode = secModule.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, datarep, inputBuffer, outputBuffer, ref outFlags);
+ int errorCode = secModule.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, datarep, inputBuffers, ref outputBuffer, ref outFlags);
- if (NetEventSource.IsEnabled) NetEventSource.Log.SecurityContextInputBuffer(nameof(InitializeSecurityContext), inputBuffer?.size ?? 0, outputBuffer.size, (Interop.SECURITY_STATUS)errorCode);
+ if (NetEventSource.IsEnabled) NetEventSource.Log.SecurityContextInputBuffers(nameof(InitializeSecurityContext), inputBuffers.Length, outputBuffer.size, (Interop.SECURITY_STATUS)errorCode);
return errorCode;
}
- internal static int InitializeSecurityContext(SSPIInterface secModule, SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness datarep, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
- {
- if (NetEventSource.IsEnabled) NetEventSource.Log.InitializeSecurityContext(credential, context, targetName, inFlags);
-
- int errorCode = secModule.InitializeSecurityContext(credential, ref context, targetName, inFlags, datarep, inputBuffers, outputBuffer, ref outFlags);
-
- if (NetEventSource.IsEnabled) NetEventSource.Log.SecurityContextInputBuffers(nameof(InitializeSecurityContext), inputBuffers?.Length ?? 0, outputBuffer.size, (Interop.SECURITY_STATUS)errorCode);
-
- return errorCode;
- }
-
- internal static int AcceptSecurityContext(SSPIInterface secModule, SafeFreeCredentials credential, ref SafeDeleteContext context, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness datarep, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
+ internal static int AcceptSecurityContext(SSPIInterface secModule, SafeFreeCredentials credential, ref SafeDeleteContext context, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness datarep, ReadOnlySpan<SecurityBuffer> inputBuffers, ref SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
{
if (NetEventSource.IsEnabled) NetEventSource.Log.AcceptSecurityContext(credential, context, inFlags);
- int errorCode = secModule.AcceptSecurityContext(credential, ref context, inputBuffers, inFlags, datarep, outputBuffer, ref outFlags);
+ int errorCode = secModule.AcceptSecurityContext(credential, ref context, inputBuffers, inFlags, datarep, ref outputBuffer, ref outFlags);
- if (NetEventSource.IsEnabled) NetEventSource.Log.SecurityContextInputBuffers(nameof(AcceptSecurityContext), inputBuffers?.Length ?? 0, outputBuffer.size, (Interop.SECURITY_STATUS)errorCode);
+ if (NetEventSource.IsEnabled) NetEventSource.Log.SecurityContextInputBuffers(nameof(AcceptSecurityContext), inputBuffers.Length, outputBuffer.size, (Interop.SECURITY_STATUS)errorCode);
return errorCode;
}
- internal static int CompleteAuthToken(SSPIInterface secModule, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers)
+ internal static int CompleteAuthToken(SSPIInterface secModule, ref SafeDeleteContext context, in SecurityBuffer inputBuffer)
{
- int errorCode = secModule.CompleteAuthToken(ref context, inputBuffers);
+ int errorCode = secModule.CompleteAuthToken(ref context, in inputBuffer);
if (NetEventSource.IsEnabled) NetEventSource.Log.OperationReturnedSomething(nameof(CompleteAuthToken), (Interop.SECURITY_STATUS)errorCode);
return errorCode;
}
- internal static int ApplyControlToken(SSPIInterface secModule, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers)
+ internal static int ApplyControlToken(SSPIInterface secModule, ref SafeDeleteContext context, in SecurityBuffer inputBuffer)
{
- int errorCode = secModule.ApplyControlToken(ref context, inputBuffers);
+ int errorCode = secModule.ApplyControlToken(ref context, in inputBuffer);
if (NetEventSource.IsEnabled) NetEventSource.Log.OperationReturnedSomething(nameof(ApplyControlToken), (Interop.SECURITY_STATUS)errorCode);
return secModule.QuerySecurityContextToken(context, out token);
}
- public static int EncryptMessage(SSPIInterface secModule, SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber)
+ public static int EncryptMessage(SSPIInterface secModule, SafeDeleteContext context, Span<SecurityBuffer> input, uint sequenceNumber)
{
return EncryptDecryptHelper(OP.Encrypt, secModule, context, input, sequenceNumber);
}
- public static int DecryptMessage(SSPIInterface secModule, SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber)
+ public static int DecryptMessage(SSPIInterface secModule, SafeDeleteContext context, Span<SecurityBuffer> input, uint sequenceNumber)
{
return EncryptDecryptHelper(OP.Decrypt, secModule, context, input, sequenceNumber);
}
- internal static int MakeSignature(SSPIInterface secModule, SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber)
+ internal static int MakeSignature(SSPIInterface secModule, SafeDeleteContext context, Span<SecurityBuffer> input, uint sequenceNumber)
{
return EncryptDecryptHelper(OP.MakeSignature, secModule, context, input, sequenceNumber);
}
- public static int VerifySignature(SSPIInterface secModule, SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber)
+ public static int VerifySignature(SSPIInterface secModule, SafeDeleteContext context, Span<SecurityBuffer> input, uint sequenceNumber)
{
return EncryptDecryptHelper(OP.VerifySignature, secModule, context, input, sequenceNumber);
}
VerifySignature
}
- private static unsafe int EncryptDecryptHelper(OP op, SSPIInterface secModule, SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber)
+ private static unsafe int EncryptDecryptHelper(OP op, SSPIInterface secModule, SafeDeleteContext context, Span<SecurityBuffer> input, uint sequenceNumber)
{
Interop.SspiCli.SecBufferDesc sdcInOut = new Interop.SspiCli.SecBufferDesc(input.Length);
- var unmanagedBuffer = new Interop.SspiCli.SecBuffer[input.Length];
+ Span<Interop.SspiCli.SecBuffer> unmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[input.Length];
+ unmanagedBuffer.Clear();
fixed (Interop.SspiCli.SecBuffer* unmanagedBufferPtr = unmanagedBuffer)
{
sdcInOut.pBuffers = unmanagedBufferPtr;
- GCHandle[] pinnedBuffers = new GCHandle[input.Length];
+ Span<GCHandle> pinnedBuffers = stackalloc GCHandle[input.Length];
+ pinnedBuffers.Clear();
byte[][] buffers = new byte[input.Length][];
try
{
for (int i = 0; i < input.Length; i++)
{
- SecurityBuffer iBuffer = input[i];
+ ref readonly SecurityBuffer iBuffer = ref input[i];
unmanagedBuffer[i].cbBuffer = iBuffer.size;
unmanagedBuffer[i].BufferType = iBuffer.type;
if (iBuffer.token == null || iBuffer.token.Length == 0)
// Marshalling back returned sizes / data.
for (int i = 0; i < input.Length; i++)
{
- SecurityBuffer iBuffer = input[i];
+ ref SecurityBuffer iBuffer = ref input[i];
iBuffer.size = unmanagedBuffer[i].cbBuffer;
iBuffer.type = unmanagedBuffer[i].BufferType;
return result;
}
- public static object QueryContextAttributes(SSPIInterface secModule, SafeDeleteContext securityContext, Interop.SspiCli.ContextAttribute contextAttribute)
- {
- int errorCode;
- return QueryContextAttributes(secModule, securityContext, contextAttribute, out errorCode);
- }
-
- public static object QueryContextAttributes(SSPIInterface secModule, SafeDeleteContext securityContext, Interop.SspiCli.ContextAttribute contextAttribute, out int errorCode)
+ public static bool QueryBlittableContextAttributes<T>(SSPIInterface secModule, SafeDeleteContext securityContext, Interop.SspiCli.ContextAttribute contextAttribute, ref T attribute) where T : unmanaged
{
if (NetEventSource.IsEnabled) NetEventSource.Enter(null, contextAttribute);
- int nativeBlockSize = IntPtr.Size;
- Type handleType = null;
-
- switch (contextAttribute)
+ Span<T> span =
+#if netstandard
+ stackalloc T[1] { attribute };
+#else
+ MemoryMarshal.CreateSpan(ref attribute, 1);
+#endif
+ int errorCode = secModule.QueryContextAttributes(
+ securityContext, contextAttribute,
+ MemoryMarshal.AsBytes(span),
+ null,
+ out SafeHandle sspiHandle);
+#if netstandard
+ attribute = span[0];
+#endif
+
+ using (sspiHandle)
{
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_SIZES:
- nativeBlockSize = SecPkgContext_Sizes.SizeOf;
- break;
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_STREAM_SIZES:
- nativeBlockSize = SecPkgContext_StreamSizes.SizeOf;
- break;
-
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_NAMES:
- handleType = typeof(SafeFreeContextBuffer);
- break;
-
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_PACKAGE_INFO:
- handleType = typeof(SafeFreeContextBuffer);
- break;
-
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_NEGOTIATION_INFO:
- handleType = typeof(SafeFreeContextBuffer);
- unsafe
- {
- nativeBlockSize = sizeof(SecPkgContext_NegotiationInfoW);
- }
- break;
-
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_CLIENT_SPECIFIED_TARGET:
- handleType = typeof(SafeFreeContextBuffer);
- break;
+ if (errorCode != 0)
+ {
+ if (NetEventSource.IsEnabled) NetEventSource.Exit(null, $"ERROR = {ErrorDescription(errorCode)}");
+ return false;
+ }
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_REMOTE_CERT_CONTEXT:
- handleType = typeof(SafeFreeCertContext);
- break;
+ if (NetEventSource.IsEnabled) NetEventSource.Exit(null, attribute);
+ return true;
+ }
+ }
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_LOCAL_CERT_CONTEXT:
- handleType = typeof(SafeFreeCertContext);
- break;
+ public static bool QueryBlittableContextAttributes<T>(SSPIInterface secModule, SafeDeleteContext securityContext, Interop.SspiCli.ContextAttribute contextAttribute, Type safeHandleType, out SafeHandle sspiHandle, ref T attribute) where T : unmanaged
+ {
+ if (NetEventSource.IsEnabled) NetEventSource.Enter(null, contextAttribute);
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_ISSUER_LIST_EX:
- nativeBlockSize = Marshal.SizeOf<Interop.SspiCli.SecPkgContext_IssuerListInfoEx>();
- handleType = typeof(SafeFreeContextBuffer);
- break;
+ Span<T> span =
+#if netstandard
+ stackalloc T[1] { attribute };
+#else
+ MemoryMarshal.CreateSpan(ref attribute, 1);
+#endif
+ int errorCode = secModule.QueryContextAttributes(
+ securityContext, contextAttribute,
+ MemoryMarshal.AsBytes(span),
+ safeHandleType,
+ out sspiHandle);
+#if netstandard
+ attribute = span[0];
+#endif
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_CONNECTION_INFO:
- nativeBlockSize = Marshal.SizeOf<SecPkgContext_ConnectionInfo>();
- break;
+ if (errorCode != 0)
+ {
+ if (NetEventSource.IsEnabled) NetEventSource.Exit(null, $"ERROR = {ErrorDescription(errorCode)}");
+ return false;
+ }
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_APPLICATION_PROTOCOL:
- nativeBlockSize = Marshal.SizeOf<Interop.SecPkgContext_ApplicationProtocol>();
- break;
+ if (NetEventSource.IsEnabled) NetEventSource.Exit(null, attribute);
+ return true;
+ }
- default:
- throw new ArgumentException(SR.Format(SR.net_invalid_enum, nameof(contextAttribute)), nameof(contextAttribute));
- }
+ public static string QueryStringContextAttributes(SSPIInterface secModule, SafeDeleteContext securityContext, Interop.SspiCli.ContextAttribute contextAttribute)
+ {
+ Debug.Assert(
+ contextAttribute == Interop.SspiCli.ContextAttribute.SECPKG_ATTR_NAMES ||
+ contextAttribute == Interop.SspiCli.ContextAttribute.SECPKG_ATTR_CLIENT_SPECIFIED_TARGET);
- SafeHandle sspiHandle = null;
- object attribute = null;
+ if (NetEventSource.IsEnabled) NetEventSource.Enter(null, contextAttribute);
- try
+ Span<IntPtr> buffer = stackalloc IntPtr[1];
+ int errorCode = secModule.QueryContextAttributes(
+ securityContext,
+ contextAttribute,
+ MemoryMarshal.AsBytes(buffer),
+ typeof(SafeFreeContextBuffer),
+ out SafeHandle sspiHandle);
+ using (sspiHandle)
{
- var nativeBuffer = new byte[nativeBlockSize];
- errorCode = secModule.QueryContextAttributes(securityContext, contextAttribute, nativeBuffer, handleType, out sspiHandle);
if (errorCode != 0)
{
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, $"ERROR = {ErrorDescription(errorCode)}");
return null;
}
- switch (contextAttribute)
- {
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_SIZES:
- attribute = new SecPkgContext_Sizes(nativeBuffer);
- break;
+ string result = Marshal.PtrToStringUni(sspiHandle.DangerousGetHandle());
+ if (NetEventSource.IsEnabled) NetEventSource.Exit(null, result);
+ return result;
+ }
+ }
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_STREAM_SIZES:
- attribute = new SecPkgContext_StreamSizes(nativeBuffer);
- break;
+ public static SafeFreeCertContext QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CONTEXT(SSPIInterface secModule, SafeDeleteContext securityContext)
+ {
+ if (NetEventSource.IsEnabled) NetEventSource.Enter(null);
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_NAMES:
- attribute = Marshal.PtrToStringUni(sspiHandle.DangerousGetHandle());
- break;
+ Span<IntPtr> buffer = stackalloc IntPtr[1];
+ int errorCode = secModule.QueryContextAttributes(
+ securityContext,
+ Interop.SspiCli.ContextAttribute.SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+ MemoryMarshal.AsBytes(buffer),
+ typeof(SafeFreeCertContext),
+ out SafeHandle sspiHandle);
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_PACKAGE_INFO:
- attribute = new SecurityPackageInfoClass(sspiHandle, 0);
- break;
+ if (errorCode != 0)
+ {
+ sspiHandle?.Dispose();
+ if (NetEventSource.IsEnabled) NetEventSource.Exit(null, $"ERROR = {ErrorDescription(errorCode)}");
+ return null;
+ }
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_NEGOTIATION_INFO:
- unsafe
- {
- fixed (void* ptr = &nativeBuffer[0])
- {
- attribute = new NegotiationInfoClass(sspiHandle, (int)((SecPkgContext_NegotiationInfoW*)ptr)->NegotiationState);
- }
- }
- break;
-
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_CLIENT_SPECIFIED_TARGET:
- attribute = Marshal.PtrToStringUni(sspiHandle.DangerousGetHandle());
- break;
-
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_LOCAL_CERT_CONTEXT:
- // Fall-through to RemoteCertificate is intentional.
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_REMOTE_CERT_CONTEXT:
- attribute = sspiHandle;
- sspiHandle = null;
- break;
-
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_ISSUER_LIST_EX:
- attribute = new Interop.SspiCli.SecPkgContext_IssuerListInfoEx(sspiHandle, nativeBuffer);
- sspiHandle = null;
- break;
-
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_CONNECTION_INFO:
- attribute = new SecPkgContext_ConnectionInfo(nativeBuffer);
- break;
-
- case Interop.SspiCli.ContextAttribute.SECPKG_ATTR_APPLICATION_PROTOCOL:
- unsafe
- {
- fixed (void *ptr = nativeBuffer)
- {
- attribute = Marshal.PtrToStructure<Interop.SecPkgContext_ApplicationProtocol>(new IntPtr(ptr));
- }
- }
- break;
+ var result = (SafeFreeCertContext)sspiHandle;
+ if (NetEventSource.IsEnabled) NetEventSource.Exit(null, result);
+ return result;
+ }
- default:
- // Will return null.
- break;
- }
- }
- finally
+ public static bool QueryContextAttributes_SECPKG_ATTR_ISSUER_LIST_EX(SSPIInterface secModule, SafeDeleteContext securityContext, ref Interop.SspiCli.SecPkgContext_IssuerListInfoEx ctx, out SafeHandle sspiHandle)
+ {
+ if (NetEventSource.IsEnabled) NetEventSource.Enter(null);
+
+ Span<Interop.SspiCli.SecPkgContext_IssuerListInfoEx> buffer =
+#if netstandard
+ stackalloc Interop.SspiCli.SecPkgContext_IssuerListInfoEx[1] { ctx };
+#else
+ MemoryMarshal.CreateSpan(ref ctx, 1);
+#endif
+ int errorCode = secModule.QueryContextAttributes(
+ securityContext,
+ Interop.SspiCli.ContextAttribute.SECPKG_ATTR_ISSUER_LIST_EX,
+ MemoryMarshal.AsBytes(buffer),
+ typeof(SafeFreeContextBuffer),
+ out sspiHandle);
+#if netstandard
+ ctx = buffer[0];
+#endif
+
+ if (errorCode != 0)
{
- if (sspiHandle != null)
- {
- sspiHandle.Dispose();
- }
+ if (NetEventSource.IsEnabled) NetEventSource.Exit(null, $"ERROR = {ErrorDescription(errorCode)}");
+ return false;
}
- if (NetEventSource.IsEnabled) NetEventSource.Exit(null, attribute);
- return attribute;
+ if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ctx);
+ return true;
}
public static string ErrorDescription(int errorCode)
// 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.Diagnostics;
using System.Runtime.InteropServices;
namespace System.Net
{
// sspi.h
[StructLayout(LayoutKind.Sequential)]
- internal class SecPkgContext_Sizes
+ internal struct SecPkgContext_Sizes
{
public readonly int cbMaxToken;
public readonly int cbMaxSignature;
public readonly int cbBlockSize;
public readonly int cbSecurityTrailer;
-
- internal unsafe SecPkgContext_Sizes(byte[] memory)
- {
- fixed (void* voidPtr = memory)
- {
- IntPtr unmanagedAddress = new IntPtr(voidPtr);
- try
- {
- // TODO (Issue #3114): replace with Marshal.PtrToStructure.
- cbMaxToken = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress));
- cbMaxSignature = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 4));
- cbBlockSize = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 8));
- cbSecurityTrailer = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 12));
- }
- catch (OverflowException)
- {
- NetEventSource.Fail(this, "Negative size.");
- throw;
- }
- }
- }
-
- public static readonly int SizeOf = Marshal.SizeOf<SecPkgContext_Sizes>();
}
}
// 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.Diagnostics;
using System.Runtime.InteropServices;
namespace System.Net
{
// sspi.h
[StructLayout(LayoutKind.Sequential)]
- internal class SecPkgContext_StreamSizes
+ internal struct SecPkgContext_StreamSizes
{
public int cbHeader;
public int cbTrailer;
public int cbMaximumMessage;
public int cBuffers;
public int cbBlockSize;
-
- internal unsafe SecPkgContext_StreamSizes(byte[] memory)
- {
- fixed (void* voidPtr = memory)
- {
- var unmanagedAddress = new IntPtr(voidPtr);
- try
- {
- // TODO (Issue #3114): replace with Marshal.PtrToStructure.
- cbHeader = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress));
- cbTrailer = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 4));
- cbMaximumMessage = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 8));
- cBuffers = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 12));
- cbBlockSize = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 16));
- }
- catch (OverflowException)
- {
- NetEventSource.Fail(this, "Negative size.");
- throw;
- }
- }
- }
-
- public static readonly int SizeOf = Marshal.SizeOf<SecPkgContext_StreamSizes>();
}
}
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Microsoft.Win32.SafeHandles;
-
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security.Authentication.ExtendedProtection;
+using Microsoft.Win32.SafeHandles;
namespace System.Net.Security
{
res = Interop.SspiCli.EnumerateSecurityPackagesW(out pkgnum, out pkgArray_SECURITY);
pkgArray = pkgArray_SECURITY;
- if (res != 0 && pkgArray != null)
+ if (res != 0)
{
- pkgArray.SetHandleAsInvalid();
+ pkgArray?.SetHandleAsInvalid();
}
return res;
}
}
- if (status != 0 && refHandle != null)
+ if (status != 0)
{
- refHandle.SetHandleAsInvalid();
+ refHandle?.SetHandleAsInvalid();
}
return status;
protected override bool ReleaseHandle()
{
SafeFreeCredentials target = Target;
- if (target != null)
- {
- target.DangerousRelease();
- }
-
+ target?.DangerousRelease();
Target = null;
return true;
}
{
#endif
private const string dummyStr = " ";
- private static readonly byte[] s_dummyBytes = new byte[] { 0 };
private static readonly IdnMapping s_idnMapping = new IdnMapping();
protected SafeFreeCredentials _EffectiveCredential;
string targetName,
Interop.SspiCli.ContextFlags inFlags,
Interop.SspiCli.Endianness endianness,
- SecurityBuffer inSecBuffer,
- SecurityBuffer[] inSecBuffers,
- SecurityBuffer outSecBuffer,
+ ReadOnlySpan<SecurityBuffer> inSecBuffers,
+ ref SecurityBuffer outSecBuffer,
ref Interop.SspiCli.ContextFlags outFlags)
{
#if TRACE_VERBOSE
if (NetEventSource.IsEnabled)
{
NetEventSource.Enter(null, $"credential:{inCredentials}, crefContext:{refContext}, targetName:{targetName}, inFlags:{inFlags}, endianness:{endianness}");
- if (inSecBuffers == null)
- {
- NetEventSource.Info(null, $"inSecBuffers = (null)");
- }
- else
- {
- NetEventSource.Info(null, $"inSecBuffers = {inSecBuffers}");
- }
+ NetEventSource.Info(null, $"inSecBuffers.Length = {inSecBuffers.Length}");
}
#endif
- if (outSecBuffer == null)
- {
- NetEventSource.Fail(null, "outSecBuffer != null");
- }
- if (inSecBuffer != null && inSecBuffers != null)
- {
- NetEventSource.Fail(null, "inSecBuffer == null || inSecBuffers == null");
- }
-
if (inCredentials == null)
{
throw new ArgumentNullException(nameof(inCredentials));
}
- Interop.SspiCli.SecBufferDesc inSecurityBufferDescriptor = default(Interop.SspiCli.SecBufferDesc);
- bool haveInSecurityBufferDescriptor = false;
- if (inSecBuffer != null)
- {
- inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(1);
- haveInSecurityBufferDescriptor = true;
- }
- else if (inSecBuffers != null)
- {
- inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Length);
- haveInSecurityBufferDescriptor = true;
- }
-
+ Interop.SspiCli.SecBufferDesc inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Length);
Interop.SspiCli.SecBufferDesc outSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(1);
// Actually, this is returned in outFlags.
isContextAbsent = refContext._handle.IsZero;
}
- // These are pinned user byte arrays passed along with SecurityBuffers.
- GCHandle[] pinnedInBytes = null;
- GCHandle pinnedOutBytes = new GCHandle();
-
// Optional output buffer that may need to be freed.
SafeFreeContextBuffer outFreeContextBuffer = null;
try
{
- pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned);
- Interop.SspiCli.SecBuffer[] inUnmanagedBuffer = new Interop.SspiCli.SecBuffer[haveInSecurityBufferDescriptor ? inSecurityBufferDescriptor.cBuffers : 1];
+ Span<Interop.SspiCli.SecBuffer> inUnmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[inSecurityBufferDescriptor.cBuffers];
+ inUnmanagedBuffer.Clear();
+
fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer)
+ fixed (void* pinnedToken0 = inSecBuffers.Length > 0 ? inSecBuffers[0].token : null)
+ fixed (void* pinnedToken1 = inSecBuffers.Length > 1 ? inSecBuffers[1].token : null)
+ fixed (void* pinnedToken2 = inSecBuffers.Length > 2 ? inSecBuffers[2].token : null) // pin all buffers, even if null or not used, to avoid needing to allocate GCHandles
{
- if (haveInSecurityBufferDescriptor)
+ Debug.Assert(inSecBuffers.Length <= 3);
+
+ // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
+ inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr;
+ for (int index = 0; index < inSecurityBufferDescriptor.cBuffers; ++index)
{
- // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
- inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr;
- pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.cBuffers];
- SecurityBuffer securityBuffer;
- for (int index = 0; index < inSecurityBufferDescriptor.cBuffers; ++index)
- {
- securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index];
- if (securityBuffer != null)
- {
- // Copy the SecurityBuffer content into unmanaged place holder.
- inUnmanagedBuffer[index].cbBuffer = securityBuffer.size;
- inUnmanagedBuffer[index].BufferType = securityBuffer.type;
-
- // Use the unmanaged token if it's not null; otherwise use the managed buffer.
- if (securityBuffer.unmanagedToken != null)
- {
- inUnmanagedBuffer[index].pvBuffer = securityBuffer.unmanagedToken.DangerousGetHandle();
- }
- else if (securityBuffer.token == null || securityBuffer.token.Length == 0)
- {
- inUnmanagedBuffer[index].pvBuffer = IntPtr.Zero;
- }
- else
- {
- pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned);
- inUnmanagedBuffer[index].pvBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset);
- }
+ ref readonly SecurityBuffer securityBuffer = ref inSecBuffers[index];
+
+ // Copy the SecurityBuffer content into unmanaged place holder.
+ inUnmanagedBuffer[index].cbBuffer = securityBuffer.size;
+ inUnmanagedBuffer[index].BufferType = securityBuffer.type;
+
+ // Use the unmanaged token if it's not null; otherwise use the managed buffer.
+ inUnmanagedBuffer[index].pvBuffer =
+ securityBuffer.unmanagedToken != null ? securityBuffer.unmanagedToken.DangerousGetHandle() :
+ securityBuffer.token == null || securityBuffer.token.Length == 0 ? IntPtr.Zero :
+ Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset);
#if TRACE_VERBOSE
- if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"SecBuffer: cbBuffer:{securityBuffer.size} BufferType:{securityBuffer.type}");
+ if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"SecBuffer: cbBuffer:{securityBuffer.size} BufferType:{securityBuffer.type}");
#endif
- }
- }
}
- Interop.SspiCli.SecBuffer outUnmanagedBuffer = default;
-
- // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
- outSecurityBufferDescriptor.pBuffers = &outUnmanagedBuffer;
- outUnmanagedBuffer.cbBuffer = outSecBuffer.size;
- outUnmanagedBuffer.BufferType = outSecBuffer.type;
- if (outSecBuffer.token == null || outSecBuffer.token.Length == 0)
- {
- outUnmanagedBuffer.pvBuffer = IntPtr.Zero;
- }
- else
+ fixed (byte* pinnedOutBytes = outSecBuffer.token)
{
- outUnmanagedBuffer.pvBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset);
- }
+ // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
+ Interop.SspiCli.SecBuffer outUnmanagedBuffer = default;
+ outSecurityBufferDescriptor.pBuffers = &outUnmanagedBuffer;
+ outUnmanagedBuffer.cbBuffer = outSecBuffer.size;
+ outUnmanagedBuffer.BufferType = outSecBuffer.type;
+ outUnmanagedBuffer.pvBuffer = outSecBuffer.token == null || outSecBuffer.token.Length == 0 ?
+ IntPtr.Zero :
+ (IntPtr)(pinnedOutBytes + outSecBuffer.offset);
- if (isSspiAllocated)
- {
- outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle();
- }
+ if (isSspiAllocated)
+ {
+ outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle();
+ }
- if (refContext == null || refContext.IsInvalid)
- {
- // Previous versions unconditionally built a new "refContext" here, but would pass
- // incorrect arguments to InitializeSecurityContextW in cases where an "contextHandle" was
- // already present and non-zero.
- if (isContextAbsent)
- refContext = new SafeDeleteContext_SECURITY();
- }
+ if (refContext == null || refContext.IsInvalid)
+ {
+ // Previous versions unconditionally built a new "refContext" here, but would pass
+ // incorrect arguments to InitializeSecurityContextW in cases where an "contextHandle" was
+ // already present and non-zero.
+ if (isContextAbsent)
+ refContext = new SafeDeleteContext_SECURITY();
+ }
- if (targetName == null || targetName.Length == 0)
- {
- targetName = dummyStr;
- }
+ if (targetName == null || targetName.Length == 0)
+ {
+ targetName = dummyStr;
+ }
- string punyCode = s_idnMapping.GetAscii(targetName);
- fixed (char* namePtr = punyCode)
- {
- errorCode = MustRunInitializeSecurityContext(
- ref inCredentials,
- isContextAbsent,
- (byte*)(((object)targetName == (object)dummyStr) ? null : namePtr),
- inFlags,
- endianness,
- haveInSecurityBufferDescriptor ? &inSecurityBufferDescriptor : null,
- refContext,
- ref outSecurityBufferDescriptor,
- ref outFlags,
- outFreeContextBuffer);
- }
+ string punyCode = s_idnMapping.GetAscii(targetName);
+ fixed (char* namePtr = punyCode)
+ {
+ errorCode = MustRunInitializeSecurityContext(
+ ref inCredentials,
+ isContextAbsent,
+ (byte*)(((object)targetName == (object)dummyStr) ? null : namePtr),
+ inFlags,
+ endianness,
+ &inSecurityBufferDescriptor,
+ refContext,
+ ref outSecurityBufferDescriptor,
+ ref outFlags,
+ outFreeContextBuffer);
+ }
- if (NetEventSource.IsEnabled) NetEventSource.Info(null, "Marshalling OUT buffer");
+ if (NetEventSource.IsEnabled) NetEventSource.Info(null, "Marshalling OUT buffer");
- // Get unmanaged buffer with index 0 as the only one passed into PInvoke.
- outSecBuffer.size = outUnmanagedBuffer.cbBuffer;
- outSecBuffer.type = outUnmanagedBuffer.BufferType;
- if (outSecBuffer.size > 0)
- {
- outSecBuffer.token = new byte[outSecBuffer.size];
- Marshal.Copy(outUnmanagedBuffer.pvBuffer, outSecBuffer.token, 0, outSecBuffer.size);
- }
- else
- {
- outSecBuffer.token = null;
+ // Get unmanaged buffer with index 0 as the only one passed into PInvoke.
+ outSecBuffer.size = outUnmanagedBuffer.cbBuffer;
+ outSecBuffer.type = outUnmanagedBuffer.BufferType;
+ outSecBuffer.token = outSecBuffer.size > 0 ?
+ new Span<byte>((byte*)outUnmanagedBuffer.pvBuffer, outUnmanagedBuffer.cbBuffer).ToArray() :
+ null;
}
}
}
finally
{
- if (pinnedInBytes != null)
- {
- for (int index = 0; index < pinnedInBytes.Length; index++)
- {
- if (pinnedInBytes[index].IsAllocated)
- {
- pinnedInBytes[index].Free();
- }
- }
- }
- if (pinnedOutBytes.IsAllocated)
- {
- pinnedOutBytes.Free();
- }
-
- if (outFreeContextBuffer != null)
- {
- outFreeContextBuffer.Dispose();
- }
+ outFreeContextBuffer?.Dispose();
}
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, $"errorCode:0x{errorCode:x8}, refContext:{refContext}");
if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0)
{
// Disassociate the previous credential handle
- if (outContext._EffectiveCredential != null)
- {
- outContext._EffectiveCredential.DangerousRelease();
- }
-
+ outContext._EffectiveCredential?.DangerousRelease();
outContext._EffectiveCredential = inCredentials;
}
else
ref SafeDeleteContext refContext,
Interop.SspiCli.ContextFlags inFlags,
Interop.SspiCli.Endianness endianness,
- SecurityBuffer inSecBuffer,
- SecurityBuffer[] inSecBuffers,
- SecurityBuffer outSecBuffer,
+ ReadOnlySpan<SecurityBuffer> inSecBuffers,
+ ref SecurityBuffer outSecBuffer,
ref Interop.SspiCli.ContextFlags outFlags)
{
#if TRACE_VERBOSE
if (NetEventSource.IsEnabled)
{
NetEventSource.Enter(null, $"credential={inCredentials}, refContext={refContext}, inFlags={inFlags}");
- if (inSecBuffers == null)
- {
- NetEventSource.Info(null, "inSecBuffers = (null)");
- }
- else
- {
- NetEventSource.Info(null, $"inSecBuffers[] = (inSecBuffers)");
- }
+ NetEventSource.Info(null, $"inSecBuffers.Length = {inSecBuffers.Length}");
}
#endif
- if (outSecBuffer == null)
- {
- NetEventSource.Fail(null, "outSecBuffer != null");
- }
- if (inSecBuffer != null && inSecBuffers != null)
- {
- NetEventSource.Fail(null, "inSecBuffer == null || inSecBuffers == null");
- }
-
if (inCredentials == null)
{
throw new ArgumentNullException(nameof(inCredentials));
}
- Interop.SspiCli.SecBufferDesc inSecurityBufferDescriptor = default(Interop.SspiCli.SecBufferDesc);
- bool haveInSecurityBufferDescriptor = false;
- if (inSecBuffer != null)
- {
- inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(1);
- haveInSecurityBufferDescriptor = true;
- }
- else if (inSecBuffers != null)
- {
- inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Length);
- haveInSecurityBufferDescriptor = true;
- }
-
+ Interop.SspiCli.SecBufferDesc inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Length);
Interop.SspiCli.SecBufferDesc outSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(1);
// Actually, this is returned in outFlags.
isContextAbsent = refContext._handle.IsZero;
}
- // These are pinned user byte arrays passed along with SecurityBuffers.
- GCHandle[] pinnedInBytes = null;
- GCHandle pinnedOutBytes = new GCHandle();
-
// Optional output buffer that may need to be freed.
SafeFreeContextBuffer outFreeContextBuffer = null;
try
{
- pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned);
- var inUnmanagedBuffer = new Interop.SspiCli.SecBuffer[haveInSecurityBufferDescriptor ? inSecurityBufferDescriptor.cBuffers : 1];
+ Span<Interop.SspiCli.SecBuffer> inUnmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[inSecurityBufferDescriptor.cBuffers];
+ inUnmanagedBuffer.Clear();
+
fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer)
+ fixed (void* pinnedToken0 = inSecBuffers.Length > 0 ? inSecBuffers[0].token : null)
+ fixed (void* pinnedToken1 = inSecBuffers.Length > 1 ? inSecBuffers[1].token : null)
+ fixed (void* pinnedToken2 = inSecBuffers.Length > 2 ? inSecBuffers[2].token : null) // pin all buffers, even if null or not used, to avoid needing to allocate GCHandles
{
- if (haveInSecurityBufferDescriptor)
+ Debug.Assert(inSecBuffers.Length <= 3);
+
+ // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
+ inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr;
+ for (int index = 0; index < inSecurityBufferDescriptor.cBuffers; ++index)
{
- // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
- inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr;
- pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.cBuffers];
- SecurityBuffer securityBuffer;
- for (int index = 0; index < inSecurityBufferDescriptor.cBuffers; ++index)
- {
- securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index];
- if (securityBuffer != null)
- {
- // Copy the SecurityBuffer content into unmanaged place holder.
- inUnmanagedBuffer[index].cbBuffer = securityBuffer.size;
- inUnmanagedBuffer[index].BufferType = securityBuffer.type;
-
- // Use the unmanaged token if it's not null; otherwise use the managed buffer.
- if (securityBuffer.unmanagedToken != null)
- {
- inUnmanagedBuffer[index].pvBuffer = securityBuffer.unmanagedToken.DangerousGetHandle();
- }
- else if (securityBuffer.token == null || securityBuffer.token.Length == 0)
- {
- inUnmanagedBuffer[index].pvBuffer = IntPtr.Zero;
- }
- else
- {
- pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned);
- inUnmanagedBuffer[index].pvBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset);
- }
+ ref readonly SecurityBuffer securityBuffer = ref inSecBuffers[index];
+
+ // Copy the SecurityBuffer content into unmanaged place holder.
+ inUnmanagedBuffer[index].cbBuffer = securityBuffer.size;
+ inUnmanagedBuffer[index].BufferType = securityBuffer.type;
+
+ // Use the unmanaged token if it's not null; otherwise use the managed buffer.
+ inUnmanagedBuffer[index].pvBuffer =
+ securityBuffer.unmanagedToken != null ? securityBuffer.unmanagedToken.DangerousGetHandle() :
+ securityBuffer.token == null || securityBuffer.token.Length == 0 ? IntPtr.Zero :
+ Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset);
#if TRACE_VERBOSE
- if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"SecBuffer: cbBuffer:{securityBuffer.size} BufferType:{securityBuffer.type}");
+ if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"SecBuffer: cbBuffer:{securityBuffer.size} BufferType:{securityBuffer.type}");
#endif
- }
- }
}
- var outUnmanagedBuffer = new Interop.SspiCli.SecBuffer[1];
- fixed (void* outUnmanagedBufferPtr = &outUnmanagedBuffer[0])
+ fixed (byte* pinnedOutBytes = outSecBuffer.token)
{
// Fix Descriptor pointer that points to unmanaged SecurityBuffers.
- outSecurityBufferDescriptor.pBuffers = outUnmanagedBufferPtr;
- // Copy the SecurityBuffer content into unmanaged place holder.
- outUnmanagedBuffer[0].cbBuffer = outSecBuffer.size;
- outUnmanagedBuffer[0].BufferType = outSecBuffer.type;
+ Interop.SspiCli.SecBuffer outUnmanagedBuffer = default;
+ outSecurityBufferDescriptor.pBuffers = &outUnmanagedBuffer;
- if (outSecBuffer.token == null || outSecBuffer.token.Length == 0)
- {
- outUnmanagedBuffer[0].pvBuffer = IntPtr.Zero;
- }
- else
- {
- outUnmanagedBuffer[0].pvBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset);
- }
+ // Copy the SecurityBuffer content into unmanaged place holder.
+ outUnmanagedBuffer.cbBuffer = outSecBuffer.size;
+ outUnmanagedBuffer.BufferType = outSecBuffer.type;
+ outUnmanagedBuffer.pvBuffer = outSecBuffer.token == null || outSecBuffer.token.Length == 0 ?
+ IntPtr.Zero :
+ (IntPtr)(pinnedOutBytes + outSecBuffer.offset);
if (isSspiAllocated)
{
errorCode = MustRunAcceptSecurityContext_SECURITY(
ref inCredentials,
isContextAbsent,
- haveInSecurityBufferDescriptor ? &inSecurityBufferDescriptor : null,
+ &inSecurityBufferDescriptor,
inFlags,
endianness,
refContext,
if (NetEventSource.IsEnabled) NetEventSource.Info(null, "Marshaling OUT buffer");
// Get unmanaged buffer with index 0 as the only one passed into PInvoke.
- outSecBuffer.size = outUnmanagedBuffer[0].cbBuffer;
- outSecBuffer.type = outUnmanagedBuffer[0].BufferType;
- if (outSecBuffer.size > 0)
- {
- outSecBuffer.token = new byte[outSecBuffer.size];
- Marshal.Copy(outUnmanagedBuffer[0].pvBuffer, outSecBuffer.token, 0, outSecBuffer.size);
- }
- else
- {
- outSecBuffer.token = null;
- }
+ outSecBuffer.size = outUnmanagedBuffer.cbBuffer;
+ outSecBuffer.type = outUnmanagedBuffer.BufferType;
+ outSecBuffer.token = outUnmanagedBuffer.cbBuffer > 0 ?
+ new Span<byte>((byte*)outUnmanagedBuffer.pvBuffer, outUnmanagedBuffer.cbBuffer).ToArray() :
+ null;
}
}
}
finally
{
- if (pinnedInBytes != null)
- {
- for (int index = 0; index < pinnedInBytes.Length; index++)
- {
- if (pinnedInBytes[index].IsAllocated)
- {
- pinnedInBytes[index].Free();
- }
- }
- }
-
- if (pinnedOutBytes.IsAllocated)
- {
- pinnedOutBytes.Free();
- }
-
- if (outFreeContextBuffer != null)
- {
- outFreeContextBuffer.Dispose();
- }
+ outFreeContextBuffer?.Dispose();
}
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, $"errorCode:0x{errorCode:x8}, refContext:{refContext}");
if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0)
{
// Disassociate the previous credential handle.
- if (outContext._EffectiveCredential != null)
- {
- outContext._EffectiveCredential.DangerousRelease();
- }
-
+ outContext._EffectiveCredential?.DangerousRelease();
outContext._EffectiveCredential = inCredentials;
}
else
internal static unsafe int CompleteAuthToken(
ref SafeDeleteContext refContext,
- SecurityBuffer[] inSecBuffers)
+ in SecurityBuffer inSecBuffer)
{
if (NetEventSource.IsEnabled)
{
NetEventSource.Enter(null, "SafeDeleteContext::CompleteAuthToken");
NetEventSource.Info(null, $" refContext = {refContext}");
- NetEventSource.Info(null, $" inSecBuffers[] = {inSecBuffers}");
+ NetEventSource.Info(null, $" inSecBuffer = {inSecBuffer}");
}
- if (inSecBuffers == null)
- {
- NetEventSource.Fail(null, "inSecBuffers == null");
- }
-
- var inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Length);
+ var inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(1);
int errorCode = (int)Interop.SECURITY_STATUS.InvalidHandle;
- // These are pinned user byte arrays passed along with SecurityBuffers.
- GCHandle[] pinnedInBytes = null;
-
- var inUnmanagedBuffer = new Interop.SspiCli.SecBuffer[inSecurityBufferDescriptor.cBuffers];
- fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer)
+ Interop.SspiCli.SecBuffer inUnmanagedBuffer = default;
+ inSecurityBufferDescriptor.pBuffers = &inUnmanagedBuffer;
+ fixed (byte* pinnedToken = inSecBuffer.token)
{
- // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
- inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr;
- pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.cBuffers];
- SecurityBuffer securityBuffer;
- for (int index = 0; index < inSecurityBufferDescriptor.cBuffers; ++index)
- {
- securityBuffer = inSecBuffers[index];
- if (securityBuffer != null)
- {
- inUnmanagedBuffer[index].cbBuffer = securityBuffer.size;
- inUnmanagedBuffer[index].BufferType = securityBuffer.type;
-
- // Use the unmanaged token if it's not null; otherwise use the managed buffer.
- if (securityBuffer.unmanagedToken != null)
- {
- inUnmanagedBuffer[index].pvBuffer = securityBuffer.unmanagedToken.DangerousGetHandle();
- }
- else if (securityBuffer.token == null || securityBuffer.token.Length == 0)
- {
- inUnmanagedBuffer[index].pvBuffer = IntPtr.Zero;
- }
- else
- {
- pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned);
- inUnmanagedBuffer[index].pvBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset);
- }
+ inUnmanagedBuffer.cbBuffer = inSecBuffer.size;
+ inUnmanagedBuffer.BufferType = inSecBuffer.type;
+
+ // Use the unmanaged token if it's not null; otherwise use the managed buffer.
+ inUnmanagedBuffer.pvBuffer =
+ inSecBuffer.unmanagedToken != null ? inSecBuffer.unmanagedToken.DangerousGetHandle() :
+ inSecBuffer.token == null || inSecBuffer.token.Length == 0 ? IntPtr.Zero :
+ (IntPtr)(pinnedToken + inSecBuffer.offset);
#if TRACE_VERBOSE
- if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"SecBuffer: cbBuffer:{securityBuffer.size} BufferType: {securityBuffer.type}");
+ if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"SecBuffer: cbBuffer:{inSecBuffer.size} BufferType: {inSecBuffer.type}");
#endif
- }
- }
- Interop.SspiCli.CredHandle contextHandle = new Interop.SspiCli.CredHandle();
- if (refContext != null)
+ Interop.SspiCli.CredHandle contextHandle = refContext != null ? refContext._handle : default;
+ if (refContext == null || refContext.IsInvalid)
{
- contextHandle = refContext._handle;
- }
- try
- {
- if (refContext == null || refContext.IsInvalid)
+ // Previous versions unconditionally built a new "refContext" here, but would pass
+ // incorrect arguments to CompleteAuthToken in cases where a nonzero "contextHandle" was
+ // already present. In these cases, allow the "refContext" to flow through unmodified
+ // (which will generate an ObjectDisposedException below). In all other cases, continue to
+ // build a new "refContext" in an attempt to maximize compat.
+ if (contextHandle.IsZero)
{
- // Previous versions unconditionally built a new "refContext" here, but would pass
- // incorrect arguments to CompleteAuthToken in cases where a nonzero "contextHandle" was
- // already present. In these cases, allow the "refContext" to flow through unmodified
- // (which will generate an ObjectDisposedException below). In all other cases, continue to
- // build a new "refContext" in an attempt to maximize compat.
- if (contextHandle.IsZero)
- refContext = new SafeDeleteContext_SECURITY();
+ refContext = new SafeDeleteContext_SECURITY();
}
+ }
- try
- {
- bool ignore = false;
- refContext.DangerousAddRef(ref ignore);
- errorCode = Interop.SspiCli.CompleteAuthToken(contextHandle.IsZero ? null : &contextHandle, ref inSecurityBufferDescriptor);
- }
- finally
- {
- refContext.DangerousRelease();
- }
+ bool gotRef = false;
+ try
+ {
+ refContext.DangerousAddRef(ref gotRef);
+ errorCode = Interop.SspiCli.CompleteAuthToken(contextHandle.IsZero ? null : &contextHandle, ref inSecurityBufferDescriptor);
}
finally
{
- if (pinnedInBytes != null)
+ if (gotRef)
{
- for (int index = 0; index < pinnedInBytes.Length; index++)
- {
- if (pinnedInBytes[index].IsAllocated)
- {
- pinnedInBytes[index].Free();
- }
- }
+ refContext.DangerousRelease();
}
}
}
internal static unsafe int ApplyControlToken(
ref SafeDeleteContext refContext,
- SecurityBuffer[] inSecBuffers)
+ in SecurityBuffer inSecBuffer)
{
if (NetEventSource.IsEnabled)
{
NetEventSource.Enter(null);
NetEventSource.Info(null, $" refContext = {refContext}");
- NetEventSource.Info(null, $" inSecBuffers[] = length:{inSecBuffers.Length}");
+ NetEventSource.Info(null, $" inSecBuffer = {inSecBuffer}");
}
- if (inSecBuffers == null)
- {
- NetEventSource.Fail(null, "inSecBuffers == null");
- }
-
- var inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Length);
-
int errorCode = (int)Interop.SECURITY_STATUS.InvalidHandle;
- // These are pinned user byte arrays passed along with SecurityBuffers.
- GCHandle[] pinnedInBytes = null;
-
- var inUnmanagedBuffer = new Interop.SspiCli.SecBuffer[inSecurityBufferDescriptor.cBuffers];
- fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer)
+ // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
+ fixed (byte* pinnedInSecBufferToken = inSecBuffer.token)
{
- // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
- inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr;
- pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.cBuffers];
- SecurityBuffer securityBuffer;
- for (int index = 0; index < inSecurityBufferDescriptor.cBuffers; ++index)
- {
- securityBuffer = inSecBuffers[index];
- if (securityBuffer != null)
- {
- inUnmanagedBuffer[index].cbBuffer = securityBuffer.size;
- inUnmanagedBuffer[index].BufferType = securityBuffer.type;
-
- // Use the unmanaged token if it's not null; otherwise use the managed buffer.
- if (securityBuffer.unmanagedToken != null)
- {
- inUnmanagedBuffer[index].pvBuffer = securityBuffer.unmanagedToken.DangerousGetHandle();
- }
- else if (securityBuffer.token == null || securityBuffer.token.Length == 0)
- {
- inUnmanagedBuffer[index].pvBuffer = IntPtr.Zero;
- }
- else
- {
- pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned);
- inUnmanagedBuffer[index].pvBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset);
- }
+ var inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(1);
+ Interop.SspiCli.SecBuffer inUnmanagedBuffer = default;
+ inSecurityBufferDescriptor.pBuffers = &inUnmanagedBuffer;
+ inUnmanagedBuffer.cbBuffer = inSecBuffer.size;
+ inUnmanagedBuffer.BufferType = inSecBuffer.type;
+
+ // Use the unmanaged token if it's not null; otherwise use the managed buffer.
+ inUnmanagedBuffer.pvBuffer =
+ inSecBuffer.unmanagedToken != null ? inSecBuffer.unmanagedToken.DangerousGetHandle() :
+ inSecBuffer.token == null || inSecBuffer.token.Length == 0 ? IntPtr.Zero :
+ (IntPtr)(pinnedInSecBufferToken + inSecBuffer.offset);
#if TRACE_VERBOSE
- if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"SecBuffer: cbBuffer:{securityBuffer.size} BufferType:{securityBuffer.type}");
+ if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"SecBuffer: cbBuffer:{inSecBuffer.size} BufferType:{inSecBuffer.type}");
#endif
- }
- }
- // TODO: (#3114): Optimizations to remove the unnecesary allocation of a CredHandle, remove the AddRef
- // if refContext was previously null, refactor the code to unify CompleteAuthToken and ApplyControlToken.
- Interop.SspiCli.CredHandle contextHandle = new Interop.SspiCli.CredHandle();
- if (refContext != null)
- {
- contextHandle = refContext._handle;
- }
+ Interop.SspiCli.CredHandle contextHandle = refContext != null ? refContext._handle : default;
- try
+ if (refContext == null || refContext.IsInvalid)
{
- if (refContext == null || refContext.IsInvalid)
+ // Previous versions unconditionally built a new "refContext" here, but would pass
+ // incorrect arguments to ApplyControlToken in cases where a nonzero "contextHandle" was
+ // already present. In these cases, allow the "refContext" to flow through unmodified
+ // (which will generate an ObjectDisposedException below). In all other cases, continue to
+ // build a new "refContext" in an attempt to maximize compat.
+ if (contextHandle.IsZero)
{
- // Previous versions unconditionally built a new "refContext" here, but would pass
- // incorrect arguments to ApplyControlToken in cases where a nonzero "contextHandle" was
- // already present. In these cases, allow the "refContext" to flow through unmodified
- // (which will generate an ObjectDisposedException below). In all other cases, continue to
- // build a new "refContext" in an attempt to maximize compat.
- if (contextHandle.IsZero)
- refContext = new SafeDeleteContext_SECURITY();
+ refContext = new SafeDeleteContext_SECURITY();
}
+ }
- try
- {
- bool ignore = false;
- refContext.DangerousAddRef(ref ignore);
- errorCode = Interop.SspiCli.ApplyControlToken(contextHandle.IsZero ? null : &contextHandle, ref inSecurityBufferDescriptor);
- }
- finally
- {
- refContext.DangerousRelease();
- }
+ bool gotRef = false;
+ try
+ {
+ refContext.DangerousAddRef(ref gotRef);
+ errorCode = Interop.SspiCli.ApplyControlToken(contextHandle.IsZero ? null : &contextHandle, ref inSecurityBufferDescriptor);
}
finally
{
- if (pinnedInBytes != null)
+ if (gotRef)
{
- for (int index = 0; index < pinnedInBytes.Length; index++)
- {
- if (pinnedInBytes[index].IsAllocated)
- {
- pinnedInBytes[index].Free();
- }
- }
+ refContext.DangerousRelease();
}
}
}
protected override bool ReleaseHandle()
{
- if (this._EffectiveCredential != null)
- {
- this._EffectiveCredential.DangerousRelease();
- }
-
+ this._EffectiveCredential?.DangerousRelease();
return Interop.SspiCli.DeleteSecurityContext(ref _handle) == 0;
}
}
refHandle._size = (*buffer).BindingsLength;
}
- if (status != 0 && refHandle != null)
+ if (status != 0)
{
- refHandle.SetHandleAsInvalid();
+ refHandle?.SetHandleAsInvalid();
}
return status;
{
// This should be very rare, but doing this will reduce the chance of deadlock.
_event = null;
- if (waitHandle != null)
- {
- waitHandle.Dispose();
- }
+ waitHandle?.Dispose();
throw;
}
// 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.Collections.Generic;
-using System.ComponentModel;
using System.Diagnostics;
using System.Net.Security;
+using System.Runtime.InteropServices;
using System.Security.Authentication.ExtendedProtection;
-using System.Threading;
namespace System.Net
{
{
if (NetEventSource.IsEnabled) NetEventSource.Enter(this, incomingBlob);
- SecurityBuffer[] inSecurityBufferArray = null;
- if (incomingBlob != null && _channelBinding != null)
- {
- inSecurityBufferArray = new SecurityBuffer[2]
- {
- new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN),
- new SecurityBuffer(_channelBinding)
- };
- }
- else if (incomingBlob != null)
- {
- inSecurityBufferArray = new SecurityBuffer[1] { new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN) };
- }
- else if (_channelBinding != null)
- {
- inSecurityBufferArray = new SecurityBuffer[1] { new SecurityBuffer(_channelBinding) };
- }
-
- var outSecurityBuffer = new SecurityBuffer(_tokenSize, SecurityBufferType.SECBUFFER_TOKEN);
+ var result = new byte[_tokenSize];
bool firstTime = _securityContext == null;
try
{
// client session
statusCode = NegotiateStreamPal.InitializeSecurityContext(
- _credentialsHandle,
+ ref _credentialsHandle,
ref _securityContext,
_spn,
_requestedContextFlags,
- inSecurityBufferArray,
- outSecurityBuffer,
+ incomingBlob,
+ _channelBinding,
+ ref result,
ref _contextFlags);
if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"SSPIWrapper.InitializeSecurityContext() returns statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})");
if (statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded)
{
- var inSecurityBuffers = new SecurityBuffer[1];
- inSecurityBuffers[0] = outSecurityBuffer;
-
- statusCode = NegotiateStreamPal.CompleteAuthToken(ref _securityContext, inSecurityBuffers);
+ statusCode = NegotiateStreamPal.CompleteAuthToken(ref _securityContext, result);
if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"SSPIWrapper.CompleteAuthToken() returns statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})");
- outSecurityBuffer.token = null;
+ result = null;
}
}
else
_credentialsHandle,
ref _securityContext,
_requestedContextFlags,
- inSecurityBufferArray,
- outSecurityBuffer,
+ incomingBlob,
+ _channelBinding,
+ ref result,
ref _contextFlags);
if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"SSPIWrapper.AcceptSecurityContext() returns statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})");
// The real dispose will happen when the security context is closed.
// Note if the first call was not successful the handle is physically destroyed here.
//
- if (firstTime && _credentialsHandle != null)
+ if (firstTime)
{
- _credentialsHandle.Dispose();
+ _credentialsHandle?.Dispose();
}
}
if (NetEventSource.IsEnabled) NetEventSource.Exit(this, $"IsCompleted: {IsCompleted}");
}
- return outSecurityBuffer.token;
+ return result;
}
private string GetClientSpecifiedSpn()
{
// This class is used to determine if NTLM or
// Kerberos are used in the context of a Negotiate handshake
- internal partial class NegotiationInfoClass
+ internal static partial class NegotiationInfoClass
{
internal const string NTLM = "NTLM";
internal const string Kerberos = "Kerberos";
ref SafeGssContextHandle context,
SafeGssCredHandle credential,
bool isNtlm,
- SecurityBuffer cbt,
+ ChannelBinding channelBinding,
SafeGssNameHandle targetName,
Interop.NetSecurityNative.GssFlags inFlags,
byte[] buffer,
// to the application specific data.
IntPtr cbtAppData = IntPtr.Zero;
int cbtAppDataSize = 0;
- if (cbt != null)
+ if (channelBinding != null)
{
int appDataOffset = Marshal.SizeOf<SecChannelBindings>();
- Debug.Assert(appDataOffset < cbt.size);
- cbtAppData = cbt.unmanagedToken.DangerousGetHandle() + appDataOffset;
- cbtAppDataSize = cbt.size - appDataOffset;
+ Debug.Assert(appDataOffset < channelBinding.Size);
+ cbtAppData = channelBinding.DangerousGetHandle() + appDataOffset;
+ cbtAppDataSize = channelBinding.Size - appDataOffset;
}
outputBuffer = null;
private static SecurityStatusPal EstablishSecurityContext(
SafeFreeNegoCredentials credential,
ref SafeDeleteContext context,
- SecurityBuffer cbt,
+ ChannelBinding channelBinding,
string targetName,
ContextFlagsPal inFlags,
- SecurityBuffer inputBuffer,
- SecurityBuffer outputBuffer,
+ byte[] incomingBlob,
+ ref byte[] resultBuffer,
ref ContextFlagsPal outFlags)
{
bool isNtlmOnly = credential.IsNtlmOnly;
ref contextHandle,
credential.GssCredential,
isNtlmOnly,
- cbt,
+ channelBinding,
negoContext.TargetName,
inputFlags,
- inputBuffer?.token,
- out outputBuffer.token,
+ incomingBlob,
+ out resultBuffer,
out outputFlags,
out isNtlmUsed);
- Debug.Assert(outputBuffer.token != null, "Unexpected null buffer returned by GssApi");
- outputBuffer.size = outputBuffer.token.Length;
- outputBuffer.offset = 0;
+ Debug.Assert(resultBuffer != null, "Unexpected null buffer returned by GssApi");
outFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop((Interop.NetSecurityNative.GssFlags)outputFlags, isServer: false);
Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext);
}
SecurityStatusPalErrorCode errorCode = done ?
- (negoContext.IsNtlmUsed && outputBuffer.size > 0 ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.CompleteNeeded) :
+ (negoContext.IsNtlmUsed && resultBuffer.Length > 0 ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.CompleteNeeded) :
SecurityStatusPalErrorCode.ContinueNeeded;
return new SecurityStatusPal(errorCode);
}
}
internal static SecurityStatusPal InitializeSecurityContext(
- SafeFreeCredentials credentialsHandle,
+ ref SafeFreeCredentials credentialsHandle,
ref SafeDeleteContext securityContext,
string spn,
ContextFlagsPal requestedContextFlags,
- SecurityBuffer[] inSecurityBufferArray,
- SecurityBuffer outSecurityBuffer,
+ byte[] incomingBlob,
+ ChannelBinding channelBinding,
+ ref byte[] resultBlob,
ref ContextFlagsPal contextFlags)
{
SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle;
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,
+ channelBinding,
spn,
requestedContextFlags,
- ((inSecurityBufferArray != null && inSecurityBufferArray.Length != 0) ? inSecurityBufferArray[0] : null),
- outSecurityBuffer,
+ incomingBlob,
+ ref resultBlob,
ref contextFlags);
// Confidentiality flag should not be set if not requested
SafeFreeCredentials credentialsHandle,
ref SafeDeleteContext securityContext,
ContextFlagsPal requestedContextFlags,
- SecurityBuffer[] inSecurityBufferArray,
- SecurityBuffer outSecurityBuffer,
+ byte[] incomingBlob,
+ ChannelBinding channelBinding,
+ ref byte[] resultBlob,
ref ContextFlagsPal contextFlags)
{
throw new PlatformNotSupportedException(SR.net_nego_server_not_supported);
internal static SecurityStatusPal CompleteAuthToken(
ref SafeDeleteContext securityContext,
- SecurityBuffer[] inSecurityBufferArray)
+ byte[] incomingBlob)
{
return new SecurityStatusPal(SecurityStatusPalErrorCode.OK);
}
// 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.Globalization;
using System.ComponentModel;
+using System.Diagnostics;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System.Security.Authentication.ExtendedProtection;
namespace System.Net.Security
{
}
finally
{
- if (authData != null)
- {
- authData.Dispose();
- }
+ authData?.Dispose();
}
}
internal static string QueryContextClientSpecifiedSpn(SafeDeleteContext securityContext)
{
- return SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_CLIENT_SPECIFIED_TARGET) as string;
+ return SSPIWrapper.QueryStringContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_CLIENT_SPECIFIED_TARGET);
}
internal static string QueryContextAuthenticationPackage(SafeDeleteContext securityContext)
{
- var negotiationInfoClass = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_NEGOTIATION_INFO) as NegotiationInfoClass;
- return negotiationInfoClass?.AuthenticationPackage;
+ SecPkgContext_NegotiationInfoW ctx = default;
+ bool success = SSPIWrapper.QueryBlittableContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_NEGOTIATION_INFO, typeof(SafeFreeContextBuffer), out SafeHandle sspiHandle, ref ctx);
+ using (sspiHandle)
+ {
+ return success ? NegotiationInfoClass.GetAuthenticationPackageName(sspiHandle, (int)ctx.NegotiationState) : null;
+ }
}
internal static SecurityStatusPal InitializeSecurityContext(
- SafeFreeCredentials credentialsHandle,
+ ref SafeFreeCredentials credentialsHandle,
ref SafeDeleteContext securityContext,
string spn,
ContextFlagsPal requestedContextFlags,
- SecurityBuffer[] inSecurityBufferArray,
- SecurityBuffer outSecurityBuffer,
+ byte[] incomingBlob,
+ ChannelBinding channelBinding,
+ ref byte[] resultBlob,
ref ContextFlagsPal contextFlags)
{
+#if netstandard
+ Span<SecurityBuffer> inSecurityBufferSpan = new SecurityBuffer[2];
+#else
+ TwoSecurityBuffers twoSecurityBuffers = default;
+ Span<SecurityBuffer> inSecurityBufferSpan = MemoryMarshal.CreateSpan(ref twoSecurityBuffers._item0, 2);
+#endif
+
+ int inSecurityBufferSpanLength = 0;
+ if (incomingBlob != null && channelBinding != null)
+ {
+ inSecurityBufferSpan[0] = new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN);
+ inSecurityBufferSpan[1] = new SecurityBuffer(channelBinding);
+ inSecurityBufferSpanLength = 2;
+ }
+ else if (incomingBlob != null)
+ {
+ inSecurityBufferSpan[0] = new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN);
+ inSecurityBufferSpanLength = 1;
+ }
+ else if (channelBinding != null)
+ {
+ inSecurityBufferSpan[0] = new SecurityBuffer(channelBinding);
+ inSecurityBufferSpanLength = 1;
+ }
+ inSecurityBufferSpan = inSecurityBufferSpan.Slice(0, inSecurityBufferSpanLength);
+
+ var outSecurityBuffer = new SecurityBuffer(resultBlob, SecurityBufferType.SECBUFFER_TOKEN);
+
Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero;
Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.InitializeSecurityContext(
GlobalSSPI.SSPIAuth,
- credentialsHandle,
+ ref credentialsHandle,
ref securityContext,
spn,
ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags),
Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP,
- inSecurityBufferArray,
- outSecurityBuffer,
+ inSecurityBufferSpan,
+ ref outSecurityBuffer,
ref outContextFlags);
+ resultBlob = outSecurityBuffer.token;
contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags);
return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus);
}
internal static SecurityStatusPal CompleteAuthToken(
ref SafeDeleteContext securityContext,
- SecurityBuffer[] inSecurityBufferArray)
+ byte[] incomingBlob)
{
+ var inSecurityBuffer = new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN);
Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.CompleteAuthToken(
GlobalSSPI.SSPIAuth,
ref securityContext,
- inSecurityBufferArray);
+ in inSecurityBuffer);
return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus);
}
SafeFreeCredentials credentialsHandle,
ref SafeDeleteContext securityContext,
ContextFlagsPal requestedContextFlags,
- SecurityBuffer[] inSecurityBufferArray,
- SecurityBuffer outSecurityBuffer,
+ byte[] incomingBlob,
+ ChannelBinding channelBinding,
+ ref byte[] resultBlob,
ref ContextFlagsPal contextFlags)
{
+#if netstandard
+ Span<SecurityBuffer> inSecurityBufferSpan = new SecurityBuffer[2];
+#else
+ TwoSecurityBuffers twoSecurityBuffers = default;
+ Span<SecurityBuffer> inSecurityBufferSpan = MemoryMarshal.CreateSpan(ref twoSecurityBuffers._item0, 2);
+#endif
+
+ int inSecurityBufferSpanLength = 0;
+ if (incomingBlob != null && channelBinding != null)
+ {
+ inSecurityBufferSpan[0] = new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN);
+ inSecurityBufferSpan[1] = new SecurityBuffer(channelBinding);
+ inSecurityBufferSpanLength = 2;
+ }
+ else if (incomingBlob != null)
+ {
+ inSecurityBufferSpan[0] = new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN);
+ inSecurityBufferSpanLength = 1;
+ }
+ else if (channelBinding != null)
+ {
+ inSecurityBufferSpan[0] = new SecurityBuffer(channelBinding);
+ inSecurityBufferSpanLength = 1;
+ }
+ inSecurityBufferSpan = inSecurityBufferSpan.Slice(0, inSecurityBufferSpanLength);
+
+ var outSecurityBuffer = new SecurityBuffer(resultBlob, SecurityBufferType.SECBUFFER_TOKEN);
+
Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero;
Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.AcceptSecurityContext(
GlobalSSPI.SSPIAuth,
ref securityContext,
ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags),
Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP,
- inSecurityBufferArray,
- outSecurityBuffer,
+ inSecurityBufferSpan,
+ ref outSecurityBuffer,
ref outContextFlags);
+ resultBlob = outSecurityBuffer.token;
+
contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags);
return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus);
}
// setup security buffers for ssp call
// one points at signed data
// two will receive payload if signature is valid
- SecurityBuffer[] securityBuffer = new SecurityBuffer[2];
+#if netstandard
+ Span<SecurityBuffer> securityBuffer = new SecurityBuffer[2];
+#else
+ TwoSecurityBuffers stackBuffer = default;
+ Span<SecurityBuffer> securityBuffer = MemoryMarshal.CreateSpan(ref stackBuffer._item0, 2);
+#endif
securityBuffer[0] = new SecurityBuffer(buffer, offset, count, SecurityBufferType.SECBUFFER_STREAM);
securityBuffer[1] = new SecurityBuffer(0, SecurityBufferType.SECBUFFER_DATA);
internal static int MakeSignature(SafeDeleteContext securityContext, byte[] buffer, int offset, int count, ref byte[] output)
{
- SecPkgContext_Sizes sizes = SSPIWrapper.QueryContextAttributes(
- GlobalSSPI.SSPIAuth,
- securityContext,
- Interop.SspiCli.ContextAttribute.SECPKG_ATTR_SIZES
- ) as SecPkgContext_Sizes;
+ SecPkgContext_Sizes sizes = default;
+ bool success = SSPIWrapper.QueryBlittableContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_SIZES, ref sizes);
+ Debug.Assert(success);
// alloc new output buffer if not supplied or too small
int resultSize = count + sizes.cbMaxSignature;
Buffer.BlockCopy(buffer, offset, output, sizes.cbMaxSignature, count);
// setup security buffers for ssp call
- SecurityBuffer[] securityBuffer = new SecurityBuffer[2];
+#if netstandard
+ Span<SecurityBuffer> securityBuffer = new SecurityBuffer[2];
+#else
+ TwoSecurityBuffers stackBuffer = default;
+ Span<SecurityBuffer> securityBuffer = MemoryMarshal.CreateSpan(ref stackBuffer._item0, 2);
+#endif
securityBuffer[0] = new SecurityBuffer(output, 0, sizes.cbMaxSignature, SecurityBufferType.SECBUFFER_TOKEN);
securityBuffer[1] = new SecurityBuffer(output, sizes.cbMaxSignature, count, SecurityBufferType.SECBUFFER_DATA);
// 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.Diagnostics;
using System.Threading;
namespace System.Net.Security
newRef = Interlocked.Exchange<SafeCredentialReference>(ref s_cacheSlots[index], newRef);
}
- if (newRef != null)
- {
- newRef.Dispose();
- }
+ newRef?.Dispose();
}
catch (Exception e)
{
// 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.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Authentication.ExtendedProtection;
namespace System.Net.Security
{
- internal class SecurityBuffer
+ // Until we have stackalloc Span<ReferenceType> support, these two
+ // structs allow us to do the equivalent of stackalloc SecurityBuffer[2]
+ // and stackalloc SecurityBuffer[3], with code like:
+ // TwoSecurityBuffers tmp = default;
+ // Span<SecurityBuffer> buffers = MemoryMarshal.CreateSpan<ref tmp._item0, 2);
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal ref struct TwoSecurityBuffers
{
+ internal SecurityBuffer _item0;
+ private SecurityBuffer _item1;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal ref struct ThreeSecurityBuffers
+ {
+ internal SecurityBuffer _item0;
+ private SecurityBuffer _item1;
+ private SecurityBuffer _item2;
+ }
+
+ [StructLayout(LayoutKind.Auto)]
+ internal struct SecurityBuffer
+ {
+ public int offset;
public int size;
public SecurityBufferType type;
public byte[] token;
public SafeHandle unmanagedToken;
- public int offset;
public SecurityBuffer(byte[] data, int offset, int size, SecurityBufferType tokentype)
{
if (offset < 0 || offset > (data == null ? 0 : data.Length))
{
- NetEventSource.Fail(this, $"'offset' out of range. [{offset}]");
+ NetEventSource.Fail(typeof(SecurityBuffer), $"'offset' out of range. [{offset}]");
}
if (size < 0 || size > (data == null ? 0 : data.Length - offset))
{
- NetEventSource.Fail(this, $"'size' out of range. [{size}]");
+ NetEventSource.Fail(typeof(SecurityBuffer), $"'size' out of range. [{size}]");
}
this.offset = data == null || offset < 0 ? 0 : Math.Min(offset, data.Length);
this.size = data == null || size < 0 ? 0 : Math.Min(size, data.Length - this.offset);
this.type = tokentype;
this.token = size == 0 ? null : data;
+ this.unmanagedToken = null;
}
public SecurityBuffer(byte[] data, SecurityBufferType tokentype)
{
+ this.offset = 0;
this.size = data == null ? 0 : data.Length;
this.type = tokentype;
this.token = size == 0 ? null : data;
+ this.unmanagedToken = null;
}
public SecurityBuffer(int size, SecurityBufferType tokentype)
{
if (size < 0)
{
- NetEventSource.Fail(this, $"'size' out of range. [{size}]");
+ NetEventSource.Fail(typeof(SecurityBuffer), $"'size' out of range. [{size}]");
}
+ this.offset = 0;
this.size = size;
this.type = tokentype;
this.token = size == 0 ? null : new byte[size];
+ this.unmanagedToken = null;
}
public SecurityBuffer(ChannelBinding binding)
{
+ this.offset = 0;
this.size = (binding == null ? 0 : binding.Size);
this.type = SecurityBufferType.SECBUFFER_CHANNEL_BINDINGS;
+ this.token = null;
this.unmanagedToken = binding;
}
}
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(OSGroup)' == 'AnyOS'">SR.PlatformNotSupported_DataSqlClient</GeneratePlatformNotSupportedAssemblyMessage>
<AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard1.2'">4.0.0.0</AssemblyVersion>
<AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard1.3'">4.1.0.0</AssemblyVersion>
+ <DefineConstants Condition="'$(TargetsNetCoreApp)' != 'true'">$(DefineConstants);netstandard</DefineConstants>
<DefineConstants Condition="'$(TargetsNetCoreApp)' == 'true'">$(DefineConstants);netcoreapp</DefineConstants>
<DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp'">$(DefineConstants);FEATURE_TCPKEEPALIVE</DefineConstants>
<Configurations>net461-Windows_NT-Debug;net461-Windows_NT-Release;netcoreapp-Debug;netcoreapp-Release;netcoreapp-Unix-Debug;netcoreapp-Unix-Release;netcoreapp-Windows_NT-Debug;netcoreapp-Windows_NT-Release;netcoreapp2.1-Debug;netcoreapp2.1-Release;netcoreapp2.1-Unix-Debug;netcoreapp2.1-Unix-Release;netcoreapp2.1-Windows_NT-Debug;netcoreapp2.1-Windows_NT-Release;netfx-Windows_NT-Debug;netfx-Windows_NT-Release;netstandard-Debug;netstandard-Release;netstandard-Unix-Debug;netstandard-Unix-Release;netstandard-Windows_NT-Debug;netstandard-Windows_NT-Release;netstandard1.2-Debug;netstandard1.2-Release;netstandard1.3-Debug;netstandard1.3-Release;uap-Windows_NT-Debug;uap-Windows_NT-Release;uap10.0.16299-Windows_NT-Debug;uap10.0.16299-Windows_NT-Release</Configurations>
</ItemGroup>
<!-- Windows dependencies for Integrated Authentication for MANAGED_SNI build -->
<ItemGroup Condition=" '$(TargetsWindows)' == 'true' And '$(IsPartialFacadeAssembly)' != 'true' ">
+ <Compile Include="$(CommonPath)\System\Net\Security\SecurityBufferType.Windows.cs">
+ <Link>Common\System\Net\Security\SecurityBufferType.Windows.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\SecurityBuffer.Windows.cs">
+ <Link>Common\System\Net\Security\SecurityBuffer.Windows.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs">
<Link>Common\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Net\SecurityStatusPal.cs">
<Link>Common\System\Net\SecurityStatusPal.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Net\Security\SecurityBufferType.cs">
- <Link>Common\System\Net\Security\SecurityBufferType.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\Net\Security\SecurityBuffer.cs">
- <Link>Common\System\Net\Security\SecurityBuffer.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\Net\DebugSafeHandle.cs">
<Link>Common\System\Net\DebugSafeHandle.cs</Link>
</Compile>
credentialsHandle = NegotiateStreamPal.AcquireDefaultCredential(securityPackage, false);
}
- SecurityBuffer[] inSecurityBufferArray = null;
- if (receivedBuff != null)
- {
- inSecurityBufferArray = new SecurityBuffer[] { new SecurityBuffer(receivedBuff, SecurityBufferType.SECBUFFER_TOKEN) };
- }
- else
- {
- inSecurityBufferArray = Array.Empty<SecurityBuffer>();
- }
-
int tokenSize = NegotiateStreamPal.QueryMaxTokenSize(securityPackage);
- SecurityBuffer outSecurityBuffer = new SecurityBuffer(tokenSize, SecurityBufferType.SECBUFFER_TOKEN);
+ byte[] resultToken = new byte[tokenSize];
ContextFlagsPal requestedContextFlags = ContextFlagsPal.Connection
| ContextFlagsPal.Confidentiality
string serverSPN = System.Text.Encoding.UTF8.GetString(serverName);
SecurityStatusPal statusCode = NegotiateStreamPal.InitializeSecurityContext(
- credentialsHandle,
+ ref credentialsHandle,
ref securityContext,
serverSPN,
requestedContextFlags,
- inSecurityBufferArray,
- outSecurityBuffer,
+ receivedBuff,
+ null,
+ ref resultToken,
ref contextFlags);
if (statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded ||
statusCode.ErrorCode == SecurityStatusPalErrorCode.CompAndContinue)
{
- inSecurityBufferArray = new SecurityBuffer[] { outSecurityBuffer };
- statusCode = NegotiateStreamPal.CompleteAuthToken(ref securityContext, inSecurityBufferArray);
- outSecurityBuffer.token = null;
+ statusCode = NegotiateStreamPal.CompleteAuthToken(ref securityContext, resultToken);
+ resultToken = null;
}
- sendBuff = outSecurityBuffer.token;
+ sendBuff = resultToken;
if (sendBuff == null)
{
sendBuff = Array.Empty<byte>();
<Compile Include="$(CommonPath)\System\Net\SecurityStatusPal.cs">
<Link>Common\System\Net\SecurityStatusPal.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Net\Security\SecurityBuffer.cs">
- <Link>Common\System\Net\Security\SecurityBuffer.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\Net\Security\SecurityBufferType.cs">
- <Link>Common\System\Net\Security\SecurityBufferType.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\Net\Security\SSPIHandleCache.cs">
<Link>Common\System\Net\Security\SSPIHandleCache.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs">
<Link>Common\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\SecurityBuffer.Windows.cs">
+ <Link>Common\System\Net\Security\SecurityBuffer.Windows.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\SecurityBufferType.Windows.cs">
+ <Link>Common\System\Net\Security\SecurityBufferType.Windows.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Net\Security\SecurityContextTokenHandle.cs">
<Link>Common\System\Net\Security\SecurityContextTokenHandle.cs</Link>
</Compile>
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tools" />
<Reference Include="System.Diagnostics.Tracing" />
+ <Reference Include="System.Memory" />
<Reference Include="System.Net.NameResolution" />
<Reference Include="System.Net.Primitives" />
<Reference Include="System.Net.Requests" />
<Compile Include="$(CommonPath)\System\Net\SecurityStatusPal.cs">
<Link>Common\System\Net\SecurityStatusPal.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Net\Security\SecurityBuffer.cs">
- <Link>Common\System\Net\Security\SecurityBuffer.cs</Link>
+ <Compile Include="$(CommonPath)\System\Net\Security\SecurityBuffer.Windows.cs">
+ <Link>Common\System\Net\Security\SecurityBuffer.Windows.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Net\Security\SecurityBufferType.cs">
- <Link>Common\System\Net\Security\SecurityBufferType.cs</Link>
+ <Compile Include="$(CommonPath)\System\Net\Security\SecurityBufferType.Windows.cs">
+ <Link>Common\System\Net\Security\SecurityBufferType.Windows.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Net\Security\SSPIHandleCache.cs">
<Link>Common\System\Net\Security\SSPIHandleCache.cs</Link>
</Compile>
<Reference Include="System.Buffers" />
<Reference Include="System.Net.Sockets" />
- <Reference Include="System.Threading.ThreadPool" />
<Reference Include="System.Net.ServicePoint" />
+ <Reference Include="System.Threading.ThreadPool" />
</ItemGroup>
</Project>
<Compile Include="$(CommonPath)\System\Net\SecurityStatusPal.cs">
<Link>Common\System\Net\SecurityStatusPal.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Net\Security\SecurityBuffer.cs">
- <Link>Common\System\Net\Security\SecurityBuffer.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\Net\Security\SecurityBufferType.cs">
- <Link>Common\System\Net\Security\SecurityBufferType.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\Net\Security\SSPIHandleCache.cs">
<Link>Common\System\Net\Security\SSPIHandleCache.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs">
<Link>Common\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\SecurityBuffer.Windows.cs">
+ <Link>Common\System\Net\Security\SecurityBuffer.Windows.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\SecurityBufferType.Windows.cs">
+ <Link>Common\System\Net\Security\SecurityBufferType.Windows.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Net\Security\SecurityContextTokenHandle.cs">
<Link>Common\System\Net\Security\SecurityContextTokenHandle.cs</Link>
</Compile>
<Reference Include="System.Diagnostics.Tracing" />
<Reference Include="System.Globalization.Extensions" />
<Reference Include="System.IO.FileSystem" />
+ <Reference Include="System.Memory" />
<Reference Include="System.Net.NetworkInformation" />
<Reference Include="System.Net.Primitives" />
<Reference Include="System.Net.Requests" />
<Compile Include="$(CommonPath)\CoreLib\System\Threading\Tasks\TaskToApm.cs">
<Link>Common\CoreLib\System\Threading\Tasks\TaskToApm.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Net\Security\SecurityBuffer.cs">
- <Link>Common\System\Net\Security\SecurityBuffer.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\Net\Security\SecurityBufferType.cs">
- <Link>Common\System\Net\Security\SecurityBufferType.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\Net\Security\SSPIHandleCache.cs">
<Link>Common\System\Net\Security\SSPIHandleCache.cs</Link>
</Compile>
<Compile Include="System\Net\Security\SslStreamPal.Windows.cs" />
<Compile Include="System\Net\Security\SslConnectionInfo.Windows.cs" />
<Compile Include="System\Net\Security\StreamSizes.Windows.cs" />
+ <Compile Include="$(CommonPath)\System\Net\Security\SecurityBuffer.Windows.cs">
+ <Link>Common\System\Net\Security\SecurityBuffer.Windows.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\SecurityBufferType.Windows.cs">
+ <Link>Common\System\Net\Security\SecurityBufferType.Windows.cs</Link>
+ </Compile>
<!-- NegotiateStream -->
<Compile Include="$(CommonPath)\System\Net\SecurityStatusAdapterPal.Windows.cs">
<Link>Common\System\Net\SecurityStatusAdapterPal.Windows.cs</Link>
}
}
}
+ catch
+ {
+ result?.Dispose();
+ throw;
+ }
finally
{
- if (gotReference)
- {
- remoteContext.DangerousRelease();
- }
-
if (remoteContext != null)
{
+ if (gotReference)
+ {
+ remoteContext.DangerousRelease();
+ }
+
remoteContext.Dispose();
}
}
// See the LICENSE file in the project root for more information.
using Microsoft.Win32.SafeHandles;
+using System.Diagnostics;
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
SafeFreeCertContext remoteContext = null;
try
{
- remoteContext = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_REMOTE_CERT_CONTEXT) as SafeFreeCertContext;
+ remoteContext = SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CONTEXT(GlobalSSPI.SSPISecureChannel, securityContext);
if (remoteContext != null && !remoteContext.IsInvalid)
{
result = new X509Certificate2(remoteContext.DangerousGetHandle());
//
internal static string[] GetRequestCertificateAuthorities(SafeDeleteContext securityContext)
{
- Interop.SspiCli.SecPkgContext_IssuerListInfoEx issuerList =
- (Interop.SspiCli.SecPkgContext_IssuerListInfoEx)SSPIWrapper.QueryContextAttributes(
- GlobalSSPI.SSPISecureChannel,
- securityContext,
- Interop.SspiCli.ContextAttribute.SECPKG_ATTR_ISSUER_LIST_EX);
+ Interop.SspiCli.SecPkgContext_IssuerListInfoEx issuerList = default;
+ bool success = SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_ISSUER_LIST_EX(GlobalSSPI.SSPISecureChannel, securityContext, ref issuerList, out SafeHandle sspiHandle);
string[] issuers = Array.Empty<string>();
-
try
{
- if (issuerList.cIssuers > 0)
+ if (success && issuerList.cIssuers > 0)
{
unsafe
{
- uint count = issuerList.cIssuers;
issuers = new string[issuerList.cIssuers];
- Interop.SspiCli.CERT_CHAIN_ELEMENT* pIL = (Interop.SspiCli.CERT_CHAIN_ELEMENT*)issuerList.aIssuers.DangerousGetHandle();
- for (int i = 0; i < count; ++i)
+ var elements = new Span<Interop.SspiCli.CERT_CHAIN_ELEMENT>((void*)sspiHandle.DangerousGetHandle(), issuers.Length);
+ for (int i = 0; i < elements.Length; ++i)
{
- Interop.SspiCli.CERT_CHAIN_ELEMENT* pIL2 = pIL + i;
- if (pIL2->cbSize <= 0)
+ if (elements[i].cbSize <= 0)
{
- NetEventSource.Fail(securityContext, $"Interop.SspiCli._CERT_CHAIN_ELEMENT size is not positive: {pIL2->cbSize}");
+ NetEventSource.Fail(securityContext, $"Interop.SspiCli._CERT_CHAIN_ELEMENT size is not positive: {elements[i].cbSize}");
}
- if (pIL2->cbSize > 0)
+ if (elements[i].cbSize > 0)
{
- uint size = pIL2->cbSize;
- byte* ptr = (byte*)(pIL2->pCertContext);
- byte[] x = new byte[size];
- for (int j = 0; j < size; j++)
- {
- x[j] = *(ptr + j);
- }
-
- X500DistinguishedName x500DistinguishedName = new X500DistinguishedName(x);
+ byte[] x = new Span<byte>((byte*)elements[i].pCertContext, checked((int)elements[i].cbSize)).ToArray();
+ var x500DistinguishedName = new X500DistinguishedName(x);
issuers[i] = x500DistinguishedName.Name;
if (NetEventSource.IsEnabled) NetEventSource.Info(securityContext, "IssuerListEx[{issuers[i]}]");
}
}
finally
{
- if (issuerList.aIssuers != null)
- {
- issuerList.aIssuers.Dispose();
- }
+ sspiHandle?.Dispose();
}
return issuers;
using System.Diagnostics;
using System.IO;
using System.Threading;
+using System.Threading.Tasks;
namespace System.Net
{
/// Completes "request" with 0 if 0 bytes was requested or legitimate EOF received.
/// Otherwise, reads as directed or completes "request" with an Exception.
/// </summary>
- public static async void ReadPacketAsync(Stream transport, AsyncProtocolRequest request) // "async Task" might result in additional, unnecessary allocation
+ public static async Task ReadPacketAsync(Stream transport, AsyncProtocolRequest request)
{
try
{
// 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.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
if (asyncRequest != null)
{
asyncRequest.SetNextRequest(_ReadHeader, 0, _ReadHeader.Length, s_readCallback);
- FixedSizeReader.ReadPacketAsync(InnerStream, asyncRequest);
+ _ = FixedSizeReader.ReadPacketAsync(InnerStream, asyncRequest);
if (!asyncRequest.MustCompleteSynchronously)
{
return 0;
{
asyncRequest.SetNextRequest(InternalBuffer, 0, readBytes, s_readCallback);
- FixedSizeReader.ReadPacketAsync(InnerStream, asyncRequest);
+ _ = FixedSizeReader.ReadPacketAsync(InnerStream, asyncRequest);
if (!asyncRequest.MustCompleteSynchronously)
{
// 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.ComponentModel;
using System.Diagnostics;
-using System.Globalization;
-using System.IO;
+using System.Runtime.InteropServices;
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
{
}
finally
{
- if (token != null)
- {
- token.Dispose();
- }
+ token?.Dispose();
}
}
internal static string QueryContextAssociatedName(SafeDeleteContext securityContext)
{
- return SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_NAMES) as string;
+ return SSPIWrapper.QueryStringContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_NAMES);
}
internal static void ValidateImpersonationLevel(TokenImpersonationLevel impersonationLevel)
ref byte[] output,
uint sequenceNumber)
{
- SecPkgContext_Sizes sizes = SSPIWrapper.QueryContextAttributes(
- GlobalSSPI.SSPIAuth,
- securityContext,
- Interop.SspiCli.ContextAttribute.SECPKG_ATTR_SIZES
- ) as SecPkgContext_Sizes;
+ SecPkgContext_Sizes sizes = default;
+ bool success = SSPIWrapper.QueryBlittableContextAttributes(GlobalSSPI.SSPIAuth, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_SIZES, ref sizes);
+ Debug.Assert(success);
try
{
Buffer.BlockCopy(buffer, offset, output, 4 + sizes.cbSecurityTrailer, count);
// Prepare buffers TOKEN(signature), DATA and Padding.
- var securityBuffer = new SecurityBuffer[3];
+ ThreeSecurityBuffers buffers = default;
+ var securityBuffer = MemoryMarshal.CreateSpan(ref buffers._item0, 3);
securityBuffer[0] = new SecurityBuffer(output, 4, sizes.cbSecurityTrailer, SecurityBufferType.SECBUFFER_TOKEN);
securityBuffer[1] = new SecurityBuffer(output, 4 + sizes.cbSecurityTrailer, count, SecurityBufferType.SECBUFFER_DATA);
securityBuffer[2] = new SecurityBuffer(output, 4 + sizes.cbSecurityTrailer + count, sizes.cbBlockSize, SecurityBufferType.SECBUFFER_PADDING);
//
// Kerberos and up
//
- var securityBuffer = new SecurityBuffer[2];
+ TwoSecurityBuffers buffers = default;
+ var securityBuffer = MemoryMarshal.CreateSpan(ref buffers._item0, 2);
securityBuffer[0] = new SecurityBuffer(buffer, offset, count, SecurityBufferType.SECBUFFER_STREAM);
securityBuffer[1] = new SecurityBuffer(0, SecurityBufferType.SECBUFFER_DATA);
throw new ArgumentOutOfRangeException(nameof(count));
}
- var securityBuffer = new SecurityBuffer[2];
+ TwoSecurityBuffers buffers = default;
+ var securityBuffer = MemoryMarshal.CreateSpan(ref buffers._item0, 2);
securityBuffer[0] = new SecurityBuffer(buffer, offset, ntlmSignatureLength, SecurityBufferType.SECBUFFER_TOKEN);
securityBuffer[1] = new SecurityBuffer(buffer, offset + ntlmSignatureLength, count - ntlmSignatureLength, SecurityBufferType.SECBUFFER_DATA);
using System.Collections.Generic;
using System.Diagnostics;
-using System.Globalization;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Security;
private SslAuthenticationOptions _sslAuthenticationOptions;
private SslApplicationProtocol _negotiatedApplicationProtocol;
- private readonly Oid _serverAuthOid = new Oid("1.3.6.1.5.5.7.3.1", "1.3.6.1.5.5.7.3.1");
- private readonly Oid _clientAuthOid = new Oid("1.3.6.1.5.5.7.3.2", "1.3.6.1.5.5.7.3.2");
+ private static readonly Oid s_serverAuthOid = new Oid("1.3.6.1.5.5.7.3.1", "1.3.6.1.5.5.7.3.1");
+ private static readonly Oid s_clientAuthOid = new Oid("1.3.6.1.5.5.7.3.2", "1.3.6.1.5.5.7.3.2");
internal SecureChannel(SslAuthenticationOptions sslAuthenticationOptions)
{
internal void Close()
{
- if (_securityContext != null)
- {
- _securityContext.Dispose();
- }
-
- if (_credentialsHandle != null)
- {
- _credentialsHandle.Dispose();
- }
-
+ _securityContext?.Dispose();
+ _credentialsHandle?.Dispose();
GC.SuppressFinalize(this);
}
try
{
- string certHash = null;
-
// Protecting from X509Certificate2 derived classes.
X509Certificate2 certEx = MakeEx(certificate);
-
- certHash = certEx.Thumbprint;
-
+
if (certEx != null)
{
if (certEx.HasPrivateKey)
}
X509Certificate2Collection collectionEx;
+ string certHash = certEx.Thumbprint;
// ELSE Try the MY user and machine stores for private key check.
// For server side mode MY machine store takes priority.
// Acquire possible Client Certificate information and set it on the handle.
X509Certificate clientCertificate = null; // This is a candidate that can come from the user callback or be guessed when targeting a session restart.
- var filteredCerts = new List<X509Certificate>(); // This is an intermediate client certs collection that try to use if no selectedCert is available yet.
+ List<X509Certificate> filteredCerts = null; // This is an intermediate client certs collection that try to use if no selectedCert is available yet.
string[] issuers = null; // This is a list of issuers sent by the server, only valid is we do know what the server cert is.
bool sessionRestartAttempt = false; // If true and no cached creds we will use anonymous creds.
}
finally
{
- if (remoteCert != null)
- {
- remoteCert.Dispose();
- }
+ remoteCert?.Dispose();
}
sessionRestartAttempt = true;
}
- filteredCerts.Add(clientCertificate);
+ EnsureInitialized(ref filteredCerts).Add(clientCertificate);
if (NetEventSource.IsEnabled)
NetEventSource.Log.CertificateFromDelegate(this);
}
sessionRestartAttempt = true;
if (clientCertificate != null)
{
- filteredCerts.Add(clientCertificate);
+ EnsureInitialized(ref filteredCerts).Add(clientCertificate);
}
if (NetEventSource.IsEnabled)
//
if (chain.ChainElements.Count > 0)
{
- for (int ii = 0; ii < chain.ChainElements.Count; ++ii)
+ int elementsCount = chain.ChainElements.Count;
+ for (int ii = 0; ii < elementsCount; ++ii)
{
string issuer = chain.ChainElements[ii].Certificate.Issuer;
found = Array.IndexOf(issuers, issuer) != -1;
if (chain != null)
{
chain.Dispose();
+
+ int elementsCount = chain.ChainElements.Count;
+ for (int element = 0; element < elementsCount; element++)
+ {
+ chain.ChainElements[element].Certificate.Dispose();
+ }
}
if (certificateEx != null && (object)certificateEx != (object)_sslAuthenticationOptions.ClientCertificates[i])
if (NetEventSource.IsEnabled)
NetEventSource.Log.SelectedCert(_sslAuthenticationOptions.ClientCertificates[i], this);
- filteredCerts.Add(_sslAuthenticationOptions.ClientCertificates[i]);
+ EnsureInitialized(ref filteredCerts).Add(_sslAuthenticationOptions.ClientCertificates[i]);
}
}
if (NetEventSource.IsEnabled)
{
- NetEventSource.Log.CertsAfterFiltering(filteredCerts.Count, this);
- if (filteredCerts.Count != 0)
+ if (filteredCerts != null && filteredCerts.Count != 0)
{
+ NetEventSource.Log.CertsAfterFiltering(filteredCerts.Count, this);
NetEventSource.Log.FindingMatchingCerts(this);
}
else
{
+ NetEventSource.Log.CertsAfterFiltering(0, this);
NetEventSource.Info(this, "No client certificate to choose from");
}
}
// SECURITY: Accessing X509 cert Credential is disabled for semitrust.
// We no longer need to demand for unmanaged code permissions.
// EnsurePrivateKey should do the right demand for us.
- for (int i = 0; i < filteredCerts.Count; ++i)
+ if (filteredCerts != null)
{
- clientCertificate = filteredCerts[i];
- if ((selectedCert = EnsurePrivateKey(clientCertificate)) != null)
+ for (int i = 0; i < filteredCerts.Count; ++i)
{
- break;
- }
+ clientCertificate = filteredCerts[i];
+ if ((selectedCert = EnsurePrivateKey(clientCertificate)) != null)
+ {
+ break;
+ }
- clientCertificate = null;
- selectedCert = null;
+ clientCertificate = null;
+ selectedCert = null;
+ }
}
if ((object)clientCertificate != (object)selectedCert && !clientCertificate.Equals(selectedCert))
return cachedCred;
}
+ private static List<T> EnsureInitialized<T>(ref List<T> list) => list ?? (list = new List<T>());
//
// Acquire Server Side Certificate information and set it on the class.
throw new ArgumentOutOfRangeException(nameof(count));
}
- SecurityBuffer incomingSecurity = null;
- SecurityBuffer[] incomingSecurityBuffers = null;
-
- if (input != null)
- {
- incomingSecurity = new SecurityBuffer(input, offset, count, SecurityBufferType.SECBUFFER_TOKEN);
- }
-
- incomingSecurityBuffers = SslStreamPal.GetIncomingSecurityBuffers(_sslAuthenticationOptions, ref incomingSecurity);
-
- SecurityBuffer outgoingSecurity = new SecurityBuffer(null, SecurityBufferType.SECBUFFER_TOKEN);
-
- SecurityStatusPal status = default(SecurityStatusPal);
-
+ byte[] result = Array.Empty<byte>();
+ SecurityStatusPal status = default;
bool cachedCreds = false;
byte[] thumbPrint = null;
status = SslStreamPal.AcceptSecurityContext(
ref _credentialsHandle,
ref _securityContext,
- incomingSecurityBuffers,
- outgoingSecurity,
+ input != null ? new ArraySegment<byte>(input, offset, count) : default,
+ ref result,
_sslAuthenticationOptions);
}
else
{
- if (incomingSecurityBuffers == null)
- {
- status = SslStreamPal.InitializeSecurityContext(
- ref _credentialsHandle,
- ref _securityContext,
- _sslAuthenticationOptions.TargetHost,
- incomingSecurity,
- outgoingSecurity,
- _sslAuthenticationOptions);
- }
- else
- {
- status = SslStreamPal.InitializeSecurityContext(
- _credentialsHandle,
- ref _securityContext,
- _sslAuthenticationOptions.TargetHost,
- incomingSecurityBuffers,
- outgoingSecurity,
- _sslAuthenticationOptions);
- }
+ status = SslStreamPal.InitializeSecurityContext(
+ ref _credentialsHandle,
+ ref _securityContext,
+ _sslAuthenticationOptions.TargetHost,
+ input != null ? new ArraySegment<byte>(input, offset, count) : default,
+ ref result,
+ _sslAuthenticationOptions);
}
} while (cachedCreds && _credentialsHandle == null);
}
// Assuming the ISC or ASC has referenced the credential,
// we want to call dispose so to decrement the effective ref count.
//
- if (_credentialsHandle != null)
- {
- _credentialsHandle.Dispose();
- }
+ _credentialsHandle?.Dispose();
//
// This call may bump up the credential reference count further.
}
}
- output = outgoingSecurity.token;
+ output = result;
if (_negotiatedApplicationProtocol == default)
{
// try to get ALPN info unless we already have it. (this function can be called multiple times)
--*/
//This method validates a remote certificate.
- //SECURITY: The scenario is allowed in semitrust StorePermission is asserted for Chain.Build
- // A user callback has unique signature so it is safe to call it under permission assert.
- //
internal bool VerifyRemoteCertificate(RemoteCertValidationCallback remoteCertValidationCallback, ref ProtocolToken alertToken)
{
if (NetEventSource.IsEnabled)
bool success = false;
X509Chain chain = null;
X509Certificate2 remoteCertificateEx = null;
+ X509Certificate2Collection remoteCertificateStore = null;
try
{
- X509Certificate2Collection remoteCertificateStore;
remoteCertificateEx = CertificateValidationPal.GetRemoteCertificate(_securityContext, out remoteCertificateStore);
_isRemoteCertificateAvailable = remoteCertificateEx != null;
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
// Authenticate the remote party: (e.g. when operating in server mode, authenticate the client).
- chain.ChainPolicy.ApplicationPolicy.Add(_sslAuthenticationOptions.IsServer ? _clientAuthOid : _serverAuthOid);
+ chain.ChainPolicy.ApplicationPolicy.Add(_sslAuthenticationOptions.IsServer ? s_clientAuthOid : s_serverAuthOid);
if (remoteCertificateStore != null)
{
{
// At least on Win2k server the chain is found to have dependencies on the original cert context.
// So it should be closed first.
+
if (chain != null)
{
+ int elementsCount = chain.ChainElements.Count;
+ for (int i = 0; i < elementsCount; i++)
+ {
+ chain.ChainElements[i].Certificate.Dispose();
+ }
+
chain.Dispose();
}
- if (remoteCertificateEx != null)
+ if (remoteCertificateStore != null)
{
- remoteCertificateEx.Dispose();
+ int certCount = remoteCertificateStore.Count;
+ for (int i = 0; i < certCount; i++)
+ {
+ remoteCertificateStore[i].Dispose();
+ }
}
+
+ remoteCertificateEx?.Dispose();
}
if (NetEventSource.IsEnabled)
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
-using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
EncryptionPolicy = sslClientAuthenticationOptions.EncryptionPolicy;
IsServer = false;
RemoteCertRequired = true;
- RemoteCertificateValidationCallback = sslClientAuthenticationOptions.RemoteCertificateValidationCallback;
TargetHost = sslClientAuthenticationOptions.TargetHost;
// Client specific options.
CertSelectionDelegate = localCallback;
CertificateRevocationCheckMode = sslClientAuthenticationOptions.CertificateRevocationCheckMode;
ClientCertificates = sslClientAuthenticationOptions.ClientCertificates;
- LocalCertificateSelectionCallback = sslClientAuthenticationOptions.LocalCertificateSelectionCallback;
}
internal SslAuthenticationOptions(SslServerAuthenticationOptions sslServerAuthenticationOptions)
{
NetEventSource.Info(this, $"Server RemoteCertRequired: {RemoteCertRequired}.");
}
- RemoteCertificateValidationCallback = sslServerAuthenticationOptions.RemoteCertificateValidationCallback;
TargetHost = string.Empty;
// Server specific options.
internal X509CertificateCollection ClientCertificates { get; set; }
internal List<SslApplicationProtocol> ApplicationProtocols { get; }
internal bool IsServer { get; set; }
- internal RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; }
- internal LocalCertificateSelectionCallback LocalCertificateSelectionCallback { get; set; }
internal X509Certificate ServerCertificate { get; set; }
internal SslProtocols EnabledSslProtocols { get; set; }
internal X509RevocationMode CertificateRevocationCheckMode { get; set; }
{
public SslConnectionInfo(SafeSslHandle sslContext)
{
- string protocolVersion = Interop.Ssl.GetProtocolVersion(sslContext);
- Protocol = (int)MapProtocolVersion(protocolVersion);
+ Protocol = (int)MapProtocolVersion(Interop.Ssl.SslGetVersion(sslContext));
int dataCipherAlg;
int keyExchangeAlg;
KeyExchKeySize = 0;
}
- private SslProtocols MapProtocolVersion(string protocolVersion)
+ private unsafe SslProtocols MapProtocolVersion(IntPtr protocolVersion)
{
- switch (protocolVersion)
+ // protocolVersion points to a static ASCII string that's one of:
+ // TLSv1
+ // TLSv1.1
+ // TLSv1.2
+ // TLSv1.3
+ // SSLv2
+ // SSLv3
+ // unknown
+ // Regardless, it's null terminated.
+
+ byte* b = (byte*)protocolVersion;
+ if (b[0] == 'T')
+ {
+ if (b[1] == 'L' &&
+ b[2] == 'S' &&
+ b[3] == 'v' &&
+ b[4] == '1')
+ {
+ if (b[5] == '\0')
+ {
+ return SslProtocols.Tls;
+ }
+ else if (b[5] == '.' && b[6] != '\0' && b[7] == '\0')
+ {
+ switch (b[6])
+ {
+ case (byte)'1': return SslProtocols.Tls11;
+ case (byte)'2': return SslProtocols.Tls12;
+ case (byte)'3': return SslProtocols.Tls13;
+ }
+ }
+ }
+ }
+ else if (b[0] == 'S')
{
+ if (b[1] == 'S' &&
+ b[2] == 'L' &&
+ b[3] == 'v')
+ {
#pragma warning disable 0618 // Ssl2, Ssl3 are deprecated.
- case "SSLv2":
- return SslProtocols.Ssl2;
- case "SSLv3":
- return SslProtocols.Ssl3;
+ if (b[4] == '2' && b[5] == '\0')
+ {
+ return SslProtocols.Ssl2;
+ }
+ else if (b[4] == '3' && b[5] == '\0')
+ {
+ return SslProtocols.Ssl3;
+ }
#pragma warning restore
- case "TLSv1":
- return SslProtocols.Tls;
- case "TLSv1.1":
- return SslProtocols.Tls11;
- case "TLSv1.2":
- return SslProtocols.Tls12;
- case "TLSv1.3":
- return SslProtocols.Tls13;
- default:
- return SslProtocols.None;
+ }
}
+
+ return SslProtocols.None;
}
}
}
{
internal partial class SslConnectionInfo
{
- public int Protocol
- {
- get;
- private set;
- }
-
- public int DataCipherAlg
- {
- get;
- private set;
- }
-
- public int DataKeySize
- {
- get;
- private set;
- }
-
- public int DataHashAlg
- {
- get;
- private set;
- }
-
- public int DataHashKeySize
- {
- get;
- private set;
- }
-
- public int KeyExchangeAlg
- {
- get;
- private set;
- }
-
- public int KeyExchKeySize
- {
- get;
- private set;
- }
+ public int Protocol { get; }
+ public int DataCipherAlg { get; private set; }
+ public int DataKeySize { get; private set; }
+ public int DataHashAlg { get; private set; }
+ public int DataHashKeySize { get; private set; }
+ public int KeyExchangeAlg { get; private set; }
+ public int KeyExchKeySize { get; private set; }
}
}
internal SslAuthenticationOptions _sslAuthenticationOptions;
- private Stream _innerStream;
-
- private SslStreamInternal _secureStream;
+ private readonly Stream _innerStream;
+ private readonly SslStreamInternal _secureStream;
private int _nestedAuth;
private SecureChannel _context;
internal SslState(Stream innerStream)
{
_innerStream = innerStream;
+ _secureStream = new SslStreamInternal(this);
}
/// <summary>Set as the _exception when the instance is disposed.</summary>
get
{
CheckThrow(true);
- if (_secureStream == null)
- {
- Interlocked.CompareExchange<SslStreamInternal>(ref _secureStream, new SslStreamInternal(this), null);
- }
-
return _secureStream;
}
}
else
{
asyncRequest.SetNextRequest(buffer, 0, SecureChannel.ReadHeaderSize, s_partialFrameCallback);
- FixedSizeReader.ReadPacketAsync(_innerStream, asyncRequest);
+ _ = FixedSizeReader.ReadPacketAsync(_innerStream, asyncRequest);
if (!asyncRequest.MustCompleteSynchronously)
{
return;
else
{
asyncRequest.SetNextRequest(buffer, readBytes, restBytes, s_readFrameCallback);
- FixedSizeReader.ReadPacketAsync(_innerStream, asyncRequest);
+ _ = FixedSizeReader.ReadPacketAsync(_innerStream, asyncRequest);
if (!asyncRequest.MustCompleteSynchronously)
{
return;
#if TRACE_VERBOSE
if (bytes[1] != 3 && NetEventSource.IsEnabled)
{
- if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"WARNING: SslState::DetectFraming() SSL protocol is > 3, trying SSL3 framing in retail = {bytes[i]:x}");
+ if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"WARNING: SslState::DetectFraming() SSL protocol is > 3, trying SSL3 framing in retail = {bytes[1]:x}");
}
#endif
// 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.Collections.Generic;
using System.IO;
-using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Security.Authentication.ExtendedProtection;
using System.Security.Cryptography.X509Certificates;
public class SslStream : AuthenticatedStream
{
private SslState _sslState;
- private object _remoteCertificateOrBytes;
+ private X509Certificate2 _remoteCertificate;
+ private bool _remoteCertificateExposed;
internal RemoteCertificateValidationCallback _userCertificateValidationCallback;
internal LocalCertificateSelectionCallback _userCertificateSelectionCallback;
private bool UserCertValidationCallbackWrapper(string hostName, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
- _remoteCertificateOrBytes = certificate == null ? null : certificate.RawData;
+ _remoteCertificate = certificate == null ? null : new X509Certificate2(certificate);
if (_userCertificateValidationCallback == null)
{
if (!_sslState.RemoteCertRequired)
get
{
_sslState.CheckThrow(true);
-
- object chkCertificateOrBytes = _remoteCertificateOrBytes;
- if (chkCertificateOrBytes != null && chkCertificateOrBytes.GetType() == typeof(byte[]))
- {
- return (X509Certificate)(_remoteCertificateOrBytes = new X509Certificate2((byte[])chkCertificateOrBytes));
- }
- else
- {
- return chkCertificateOrBytes as X509Certificate;
- }
+ _remoteCertificateExposed = true;
+ return _remoteCertificate;
}
}
{
try
{
+ if (!_remoteCertificateExposed)
+ {
+ _remoteCertificate?.Dispose();
+ _remoteCertificate = null;
+ _remoteCertificateExposed = false;
+ }
_sslState.Close();
}
finally
using System.Buffers;
using System.Diagnostics;
using System.IO;
-using System.Runtime.ExceptionServices;
using System.Threading;
using System.Threading.Tasks;
ValueTask<int> t = adapter.ReadAsync(_internalBuffer, _internalBufferCount, _internalBuffer.Length - _internalBufferCount);
if (!t.IsCompletedSuccessfully)
{
- return new ValueTask<int>(InternalFillBufferAsync(adapter, t, minSize, initialCount));
+ return InternalFillBufferAsync(adapter, t, minSize, initialCount);
}
int bytes = t.Result;
if (bytes == 0)
return new ValueTask<int>(minSize);
- async Task<int> InternalFillBufferAsync(TReadAdapter adap, ValueTask<int> task, int min, int initial)
+ async ValueTask<int> InternalFillBufferAsync(TReadAdapter adap, ValueTask<int> task, int min, int initial)
{
while (true)
{
public static SecurityStatusPal AcceptSecurityContext(
ref SafeFreeCredentials credential,
ref SafeDeleteContext context,
- SecurityBuffer[] inputBuffers,
- SecurityBuffer outputBuffer,
+ ArraySegment<byte> inputBuffer,
+ ref byte[] outputBuffer,
SslAuthenticationOptions sslAuthenticationOptions)
{
- if (inputBuffers != null)
- {
- Debug.Assert(inputBuffers.Length == 2);
- Debug.Assert(inputBuffers[1].token == null);
-
- return HandshakeInternal(credential, ref context, inputBuffers[0], outputBuffer, sslAuthenticationOptions);
- }
- else
- {
- return HandshakeInternal(credential, ref context, inputBuffer: null, outputBuffer, sslAuthenticationOptions);
- }
+ return HandshakeInternal(credential, ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions);
}
public static SecurityStatusPal InitializeSecurityContext(
ref SafeFreeCredentials credential,
ref SafeDeleteContext context,
string targetName,
- SecurityBuffer inputBuffer,
- SecurityBuffer outputBuffer,
- SslAuthenticationOptions sslAuthenticationOptions)
- {
- return HandshakeInternal(credential, ref context, inputBuffer, outputBuffer, sslAuthenticationOptions);
- }
-
- public static SecurityStatusPal InitializeSecurityContext(
- SafeFreeCredentials credential,
- ref SafeDeleteContext context,
- string targetName,
- SecurityBuffer[] inputBuffers,
- SecurityBuffer outputBuffer,
+ ArraySegment<byte> inputBuffer,
+ ref byte[] outputBuffer,
SslAuthenticationOptions sslAuthenticationOptions)
{
- Debug.Assert(inputBuffers.Length == 2);
- Debug.Assert(inputBuffers[1].token == null);
- return HandshakeInternal(credential, ref context, inputBuffers[0], outputBuffer, sslAuthenticationOptions);
- }
-
- public static SecurityBuffer[] GetIncomingSecurityBuffers(SslAuthenticationOptions options, ref SecurityBuffer incomingSecurity)
- {
- SecurityBuffer[] incomingSecurityBuffers = null;
-
- if (incomingSecurity != null)
- {
- incomingSecurityBuffers = new SecurityBuffer[]
- {
- incomingSecurity,
- new SecurityBuffer(null, 0, 0, SecurityBufferType.SECBUFFER_EMPTY)
- };
- }
-
- return incomingSecurityBuffers;
+ return HandshakeInternal(credential, ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions);
}
public static SafeFreeCredentials AcquireCredentialsHandle(
private static SecurityStatusPal HandshakeInternal(
SafeFreeCredentials credential,
ref SafeDeleteContext context,
- SecurityBuffer inputBuffer,
- SecurityBuffer outputBuffer,
+ ArraySegment<byte> inputBuffer,
+ ref byte[] outputBuffer,
SslAuthenticationOptions sslAuthenticationOptions)
{
Debug.Assert(!credential.IsInvalid);
}
}
- if (inputBuffer != null && inputBuffer.size > 0)
+ if (inputBuffer.Array != null && inputBuffer.Count > 0)
{
- sslContext.Write(inputBuffer.token, inputBuffer.offset, inputBuffer.size);
+ sslContext.Write(inputBuffer.Array, inputBuffer.Offset, inputBuffer.Count);
}
SafeSslHandle sslHandle = sslContext.SslContext;
status = PerformHandshake(sslHandle);
}
- byte[] output = sslContext.ReadPendingWrites();
- outputBuffer.offset = 0;
- outputBuffer.size = output?.Length ?? 0;
- outputBuffer.token = output;
-
+ outputBuffer = sslContext.ReadPendingWrites();
return status;
}
catch (Exception exc)
}
public static SecurityStatusPal AcceptSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context,
- SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
+ ArraySegment<byte> inputBuffer, ref byte[] outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
{
- if (inputBuffers != null)
- {
- Debug.Assert(inputBuffers.Length == 2);
- Debug.Assert(inputBuffers[1].token == null);
-
- return HandshakeInternal(credential, ref context, inputBuffers[0], outputBuffer, sslAuthenticationOptions);
- }
- else
- {
- return HandshakeInternal(credential, ref context, inputBuffer: null, outputBuffer, sslAuthenticationOptions);
- }
- }
-
- public static SecurityStatusPal InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context,
- string targetName, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
- {
- return HandshakeInternal(credential, ref context, inputBuffer, outputBuffer, sslAuthenticationOptions);
+ return HandshakeInternal(credential, ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions);
}
- public static SecurityStatusPal InitializeSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
+ public static SecurityStatusPal InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName,
+ ArraySegment<byte> inputBuffer, ref byte[] outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
{
- Debug.Assert(inputBuffers.Length == 2);
- Debug.Assert(inputBuffers[1].token == null);
-
- return HandshakeInternal(credential, ref context, inputBuffers[0], outputBuffer, sslAuthenticationOptions);
- }
-
- public static SecurityBuffer[] GetIncomingSecurityBuffers(SslAuthenticationOptions options, ref SecurityBuffer incomingSecurity)
- {
- SecurityBuffer[] incomingSecurityBuffers = null;
-
- if (incomingSecurity != null)
- {
- incomingSecurityBuffers = new SecurityBuffer[]
- {
- incomingSecurity,
- new SecurityBuffer(null, 0, 0, SecurityBufferType.SECBUFFER_EMPTY)
- };
- }
-
- return incomingSecurityBuffers;
+ return HandshakeInternal(credential, ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions);
}
public static SafeFreeCredentials AcquireCredentialsHandle(X509Certificate certificate,
return Interop.Ssl.ConvertAlpnProtocolListToByteArray(applicationProtocols);
}
- private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer,
- SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
+ private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credential, ref SafeDeleteContext context,
+ ArraySegment<byte> inputBuffer, ref byte[] outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
{
Debug.Assert(!credential.IsInvalid);
int outputSize;
bool done;
- if (null == inputBuffer)
+ if (inputBuffer.Array == null)
{
done = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, null, 0, 0, out output, out outputSize);
}
else
{
- done = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, inputBuffer.token, inputBuffer.offset, inputBuffer.size, out output, out outputSize);
+ done = Interop.OpenSsl.DoSslHandshake(((SafeDeleteSslContext)context).SslContext, inputBuffer.Array, inputBuffer.Offset, inputBuffer.Count, out output, out outputSize);
}
// When the handshake is done, and the context is server, check if the alpnHandle target was set to null during ALPN.
return new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, Interop.OpenSsl.CreateSslException(SR.net_alpn_failed));
}
- outputBuffer.size = outputSize;
- outputBuffer.offset = 0;
- outputBuffer.token = outputSize > 0 ? output : null;
+ outputBuffer =
+ outputSize == 0 ? null :
+ outputSize == output.Length ? output :
+ new Span<byte>(output, 0, outputSize).ToArray();
return new SecurityStatusPal(done ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.ContinueNeeded);
}
return Interop.Sec_Application_Protocols.ToByteArray(protocols);
}
- public static SecurityStatusPal AcceptSecurityContext(ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
+ public static SecurityStatusPal AcceptSecurityContext(ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, ArraySegment<byte> input, ref byte[] outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
{
- Interop.SspiCli.ContextFlags unusedAttributes = default(Interop.SspiCli.ContextFlags);
+ Interop.SspiCli.ContextFlags unusedAttributes = default;
+
+ ThreeSecurityBuffers threeSecurityBuffers = default;
+ SecurityBuffer? incomingSecurity = input.Array != null ?
+ new SecurityBuffer(input.Array, input.Offset, input.Count, SecurityBufferType.SECBUFFER_TOKEN) :
+ (SecurityBuffer?)null;
+ Span<SecurityBuffer> inputBuffers = MemoryMarshal.CreateSpan(ref threeSecurityBuffers._item0, 3);
+ GetIncomingSecurityBuffers(sslAuthenticationOptions, in incomingSecurity, ref inputBuffers);
+
+ var resultBuffer = new SecurityBuffer(outputBuffer, SecurityBufferType.SECBUFFER_TOKEN);
int errorCode = SSPIWrapper.AcceptSecurityContext(
GlobalSSPI.SSPISecureChannel,
ServerRequiredFlags | (sslAuthenticationOptions.RemoteCertRequired ? Interop.SspiCli.ContextFlags.MutualAuth : Interop.SspiCli.ContextFlags.Zero),
Interop.SspiCli.Endianness.SECURITY_NATIVE_DREP,
inputBuffers,
- outputBuffer,
+ ref resultBuffer,
ref unusedAttributes);
+ outputBuffer = resultBuffer.token;
return SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode);
}
- public static SecurityStatusPal InitializeSecurityContext(ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, string targetName, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
+ public static SecurityStatusPal InitializeSecurityContext(ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, string targetName, ArraySegment<byte> input, ref byte[] outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
{
- Interop.SspiCli.ContextFlags unusedAttributes = default(Interop.SspiCli.ContextFlags);
+ Interop.SspiCli.ContextFlags unusedAttributes = default;
- int errorCode = SSPIWrapper.InitializeSecurityContext(
- GlobalSSPI.SSPISecureChannel,
- ref credentialsHandle,
- ref context,
- targetName,
- RequiredFlags | Interop.SspiCli.ContextFlags.InitManualCredValidation,
- Interop.SspiCli.Endianness.SECURITY_NATIVE_DREP,
- inputBuffer,
- outputBuffer,
- ref unusedAttributes);
-
- return SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode);
- }
+ ThreeSecurityBuffers threeSecurityBuffers = default;
+ SecurityBuffer? incomingSecurity = input.Array != null ?
+ new SecurityBuffer(input.Array, input.Offset, input.Count, SecurityBufferType.SECBUFFER_TOKEN) :
+ (SecurityBuffer?)null;
+ Span<SecurityBuffer> inputBuffers = MemoryMarshal.CreateSpan(ref threeSecurityBuffers._item0, 3);
+ GetIncomingSecurityBuffers(sslAuthenticationOptions, in incomingSecurity, ref inputBuffers);
- public static SecurityStatusPal InitializeSecurityContext(SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, string targetName, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
- {
- Interop.SspiCli.ContextFlags unusedAttributes = default(Interop.SspiCli.ContextFlags);
+ var resultBuffer = new SecurityBuffer(outputBuffer, SecurityBufferType.SECBUFFER_TOKEN);
int errorCode = SSPIWrapper.InitializeSecurityContext(
GlobalSSPI.SSPISecureChannel,
- credentialsHandle,
+ ref credentialsHandle,
ref context,
targetName,
RequiredFlags | Interop.SspiCli.ContextFlags.InitManualCredValidation,
Interop.SspiCli.Endianness.SECURITY_NATIVE_DREP,
inputBuffers,
- outputBuffer,
+ ref resultBuffer,
ref unusedAttributes);
+ outputBuffer = resultBuffer.token;
return SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode);
}
- public static SecurityBuffer[] GetIncomingSecurityBuffers(SslAuthenticationOptions options, ref SecurityBuffer incomingSecurity)
+ private static void GetIncomingSecurityBuffers(SslAuthenticationOptions options, in SecurityBuffer? incomingSecurity, ref Span<SecurityBuffer> incomingSecurityBuffers)
{
- SecurityBuffer alpnBuffer = null;
- SecurityBuffer[] incomingSecurityBuffers = null;
+ SecurityBuffer? alpnBuffer = null;
if (options.ApplicationProtocols != null && options.ApplicationProtocols.Count != 0)
{
- byte[] alpnBytes = SslStreamPal.ConvertAlpnProtocolListToByteArray(options.ApplicationProtocols);
+ byte[] alpnBytes = ConvertAlpnProtocolListToByteArray(options.ApplicationProtocols);
alpnBuffer = new SecurityBuffer(alpnBytes, 0, alpnBytes.Length, SecurityBufferType.SECBUFFER_APPLICATION_PROTOCOLS);
}
{
if (alpnBuffer != null)
{
- incomingSecurityBuffers = new SecurityBuffer[]
- {
- incomingSecurity,
- new SecurityBuffer(null, 0, 0, SecurityBufferType.SECBUFFER_EMPTY),
- alpnBuffer
- };
+ Debug.Assert(incomingSecurityBuffers.Length >= 3);
+ incomingSecurityBuffers[0] = incomingSecurity.GetValueOrDefault();
+ incomingSecurityBuffers[1] = new SecurityBuffer(null, 0, 0, SecurityBufferType.SECBUFFER_EMPTY);
+ incomingSecurityBuffers[2] = alpnBuffer.GetValueOrDefault();
+ incomingSecurityBuffers = incomingSecurityBuffers.Slice(0, 3);
}
else
{
- incomingSecurityBuffers = new SecurityBuffer[]
- {
- incomingSecurity,
- new SecurityBuffer(null, 0, 0, SecurityBufferType.SECBUFFER_EMPTY)
- };
+ Debug.Assert(incomingSecurityBuffers.Length >= 2);
+ incomingSecurityBuffers[0] = incomingSecurity.GetValueOrDefault();
+ incomingSecurityBuffers[1] = new SecurityBuffer(null, 0, 0, SecurityBufferType.SECBUFFER_EMPTY);
+ incomingSecurityBuffers = incomingSecurityBuffers.Slice(0, 2);
}
}
else if (alpnBuffer != null)
{
- incomingSecurity = alpnBuffer;
+ incomingSecurityBuffers[0] = alpnBuffer.GetValueOrDefault();
+ incomingSecurityBuffers = incomingSecurityBuffers.Slice(0, 1);
+ }
+ else
+ {
+ incomingSecurityBuffers = default;
}
-
- return incomingSecurityBuffers;
}
public static SafeFreeCredentials AcquireCredentialsHandle(X509Certificate certificate, SslProtocols protocols, EncryptionPolicy policy, bool isServer)
internal static byte[] GetNegotiatedApplicationProtocol(SafeDeleteContext context)
{
- Interop.SecPkgContext_ApplicationProtocol alpnContext = SSPIWrapper.QueryContextAttributes(
- GlobalSSPI.SSPISecureChannel,
- context,
- Interop.SspiCli.ContextAttribute.SECPKG_ATTR_APPLICATION_PROTOCOL) as Interop.SecPkgContext_ApplicationProtocol;
+ Interop.SecPkgContext_ApplicationProtocol alpnContext = default;
+ bool success = SSPIWrapper.QueryBlittableContextAttributes(GlobalSSPI.SSPISecureChannel, context, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_APPLICATION_PROTOCOL, ref alpnContext);
// Check if the context returned is alpn data, with successful negotiation.
- if (alpnContext == null ||
- alpnContext.ProtoNegoExt != Interop.ApplicationProtocolNegotiationExt.ALPN ||
- alpnContext.ProtoNegoStatus != Interop.ApplicationProtocolNegotiationStatus.Success)
+ if (success &&
+ alpnContext.ProtoNegoExt == Interop.ApplicationProtocolNegotiationExt.ALPN &&
+ alpnContext.ProtoNegoStatus == Interop.ApplicationProtocolNegotiationStatus.Success)
{
- return null;
+ return alpnContext.Protocol;
}
- return alpnContext.Protocol;
+ return null;
}
public static unsafe SecurityStatusPal EncryptMessage(SafeDeleteContext securityContext, ReadOnlyMemory<byte> input, int headerSize, int trailerSize, ref byte[] output, out int resultSize)
public static SecurityStatusPal ApplyAlertToken(ref SafeFreeCredentials credentialsHandle, SafeDeleteContext securityContext, TlsAlertType alertType, TlsAlertMessage alertMessage)
{
- Interop.SChannel.SCHANNEL_ALERT_TOKEN alertToken;
- alertToken.dwTokenType = Interop.SChannel.SCHANNEL_ALERT;
- alertToken.dwAlertType = (uint)alertType;
- alertToken.dwAlertNumber = (uint)alertMessage;
-
- var bufferDesc = new SecurityBuffer[1];
-
- int alertTokenByteSize = Marshal.SizeOf<Interop.SChannel.SCHANNEL_ALERT_TOKEN>();
- IntPtr p = Marshal.AllocHGlobal(alertTokenByteSize);
-
- try
+ var alertToken = new Interop.SChannel.SCHANNEL_ALERT_TOKEN
{
- var buffer = new byte[alertTokenByteSize];
- Marshal.StructureToPtr<Interop.SChannel.SCHANNEL_ALERT_TOKEN>(alertToken, p, false);
- Marshal.Copy(p, buffer, 0, alertTokenByteSize);
+ dwTokenType = Interop.SChannel.SCHANNEL_ALERT,
+ dwAlertType = (uint)alertType,
+ dwAlertNumber = (uint)alertMessage
+ };
+ byte[] buffer = MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref alertToken, 1)).ToArray();
+ var securityBuffer = new SecurityBuffer(buffer, SecurityBufferType.SECBUFFER_TOKEN);
- bufferDesc[0] = new SecurityBuffer(buffer, SecurityBufferType.SECBUFFER_TOKEN);
- var errorCode = (Interop.SECURITY_STATUS)SSPIWrapper.ApplyControlToken(
- GlobalSSPI.SSPISecureChannel,
- ref securityContext,
- bufferDesc);
+ var errorCode = (Interop.SECURITY_STATUS)SSPIWrapper.ApplyControlToken(
+ GlobalSSPI.SSPISecureChannel,
+ ref securityContext,
+ in securityBuffer);
- return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(errorCode, attachException: true);
- }
- finally
- {
- Marshal.FreeHGlobal(p);
- }
+ return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(errorCode, attachException: true);
}
+ private static readonly byte[] s_schannelShutdownBytes = BitConverter.GetBytes(Interop.SChannel.SCHANNEL_SHUTDOWN);
+
public static SecurityStatusPal ApplyShutdownToken(ref SafeFreeCredentials credentialsHandle, SafeDeleteContext securityContext)
{
- int shutdownToken = Interop.SChannel.SCHANNEL_SHUTDOWN;
-
- var bufferDesc = new SecurityBuffer[1];
- var buffer = BitConverter.GetBytes(shutdownToken);
+ var securityBuffer = new SecurityBuffer(s_schannelShutdownBytes, SecurityBufferType.SECBUFFER_TOKEN);
- bufferDesc[0] = new SecurityBuffer(buffer, SecurityBufferType.SECBUFFER_TOKEN);
var errorCode = (Interop.SECURITY_STATUS)SSPIWrapper.ApplyControlToken(
GlobalSSPI.SSPISecureChannel,
ref securityContext,
- bufferDesc);
+ in securityBuffer);
return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(errorCode, attachException: true);
}
public static void QueryContextStreamSizes(SafeDeleteContext securityContext, out StreamSizes streamSizes)
{
- var interopStreamSizes = SSPIWrapper.QueryContextAttributes(
- GlobalSSPI.SSPISecureChannel,
- securityContext,
- Interop.SspiCli.ContextAttribute.SECPKG_ATTR_STREAM_SIZES) as SecPkgContext_StreamSizes;
-
+ SecPkgContext_StreamSizes interopStreamSizes = default;
+ bool success = SSPIWrapper.QueryBlittableContextAttributes(GlobalSSPI.SSPISecureChannel, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_STREAM_SIZES, ref interopStreamSizes);
+ Debug.Assert(success);
streamSizes = new StreamSizes(interopStreamSizes);
}
public static void QueryContextConnectionInfo(SafeDeleteContext securityContext, out SslConnectionInfo connectionInfo)
{
- var interopConnectionInfo = SSPIWrapper.QueryContextAttributes(
- GlobalSSPI.SSPISecureChannel,
- securityContext,
- Interop.SspiCli.ContextAttribute.SECPKG_ATTR_CONNECTION_INFO) as SecPkgContext_ConnectionInfo;
-
+ SecPkgContext_ConnectionInfo interopConnectionInfo = default;
+ bool success = SSPIWrapper.QueryBlittableContextAttributes(GlobalSSPI.SSPISecureChannel, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_CONNECTION_INFO, ref interopConnectionInfo);
+ Debug.Assert(success);
connectionInfo = new SslConnectionInfo(interopConnectionInfo);
}
// See the LICENSE file in the project root for more information.
using System.Collections;
-using System.Collections.Generic;
using Internal.Cryptography;
namespace System.Security.Cryptography
{
public sealed class OidCollection : ICollection
{
- public OidCollection()
- {
- _list = new List<Oid>();
- }
+ private Oid[] _oids = Array.Empty<Oid>();
+ private int _count;
+
+ public OidCollection() { }
public int Add(Oid oid)
{
- int count = _list.Count;
- _list.Add(oid);
+ int count = _count;
+ if (count == _oids.Length)
+ {
+ Array.Resize(ref _oids, count == 0 ? 4 : count * 2);
+ }
+ _oids[count] = oid;
+ _count = count + 1;
return count;
}
- public Oid this[int index] => _list[index];
+ public Oid this[int index]
+ {
+ get
+ {
+ if ((uint)index >= (uint)_count)
+ {
+ // For compat, throw an ArgumentOutOfRangeException instead of
+ // the IndexOutOfRangeException that comes from the array's indexer.
+ throw new ArgumentOutOfRangeException(nameof(index));
+ }
+ return _oids[index];
+ }
+ }
// Indexer using an OID friendly name or value.
public Oid this[string oid]
{
oidValue = oid;
}
- foreach (Oid entry in _list)
+ for (int i = 0; i < _count; i++)
{
+ Oid entry = _oids[i];
if (entry.Value == oidValue)
return entry;
}
}
}
- public int Count => _list.Count;
+ public int Count => _count;
public OidEnumerator GetEnumerator() => new OidEnumerator(this);
if (index < 0 || index >= array.Length)
throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index);
- _list.CopyTo(array, index);
+ Array.Copy(_oids, 0, array, index, _count);
}
public bool IsSynchronized => false;
public object SyncRoot => this;
-
- private readonly List<Oid> _list;
}
}
private X509ChainElement BuildElement(X509Certificate2 cert, int dwStatus)
{
- const int errSecCertificateExpired = -67818;
- const int errSecCertificateNotValidYet = -67819;
-
if (dwStatus == 0)
{
return new X509ChainElement(cert, Array.Empty<X509ChainStatus>(), "");
if ((mapping.ChainStatusFlag & flags) == mapping.ChainStatusFlag)
{
int osStatus;
+ string errorString;
// Disambiguate the NotTimeValid code to get the right string.
if (mapping.ChainStatusFlag == X509ChainStatusFlags.NotTimeValid)
{
- if (cert != null && cert.NotBefore > _verificationTime)
- {
- osStatus = errSecCertificateNotValidYet;
- }
- else
- {
- osStatus = errSecCertificateExpired;
- }
+ const int errSecCertificateExpired = -67818;
+ const int errSecCertificateNotValidYet = -67819;
+
+ osStatus = cert != null && cert.NotBefore > _verificationTime ?
+ errSecCertificateNotValidYet :
+ errSecCertificateExpired;
+ errorString = Interop.AppleCrypto.GetSecErrorString(osStatus);
}
else
{
osStatus = mapping.OSStatus;
+ errorString = mapping.ErrorString;
}
statuses.Add(
new X509ChainStatus
{
Status = mapping.ChainStatusFlag,
- StatusInformation = Interop.AppleCrypto.GetSecErrorString(osStatus),
+ StatusInformation = errorString
});
}
}
internal readonly X509ChainStatusFlags ChainStatusFlag;
internal readonly int OSStatus;
+ internal readonly string ErrorString;
private X509ChainErrorMapping(X509ChainStatusFlags flag)
{
ChainStatusFlag = flag;
OSStatus = Interop.AppleCrypto.GetOSStatusForChainStatus(flag);
+ ErrorString = Interop.AppleCrypto.GetSecErrorString(OSStatus);
}
}
}
unsafe
{
CERT_CONTEXT* pCertContext = _certContext.CertContext;
- int count = pCertContext->cbCertEncoded;
- byte[] rawData = new byte[count];
- Marshal.Copy((IntPtr)(pCertContext->pbCertEncoded), rawData, 0, count);
+ byte[] rawData = new Span<byte>(pCertContext->pbCertEncoded, pCertContext->cbCertEncoded).ToArray();
GC.KeepAlive(this);
return rawData;
}
{
Debug.Assert(index < chainStatus.Length);
- chainStatus[index].StatusInformation = Interop.Kernel32.GetMessage(mapping.Win32ErrorCode);
+ chainStatus[index].StatusInformation = mapping.Message;
chainStatus[index].Status = mapping.ChainStatusFlag;
index++;
dwStatus &= ~mapping.Win32Flag;
public readonly CertTrustErrorStatus Win32Flag;
public readonly int Win32ErrorCode;
public readonly X509ChainStatusFlags ChainStatusFlag;
+ public readonly string Message;
public X509ChainErrorMapping(CertTrustErrorStatus win32Flag, int win32ErrorCode, X509ChainStatusFlags chainStatusFlag)
{
Win32Flag = win32Flag;
Win32ErrorCode = win32ErrorCode;
ChainStatusFlag = chainStatusFlag;
+ Message = Interop.Kernel32.GetMessage(win32ErrorCode);
}
}
_lazyNotAfter = DateTime.MinValue;
ICertificatePalCore pal = Pal;
- Pal = null;
if (pal != null)
+ {
+ Pal = null;
pal.Dispose();
+ }
}
public X509Certificate()
// UrlRetrievalTimeout = new TimeSpan(0, 0, 0)
bool verified = chain.Build(this, throwOnException: false);
+
+ for (int i = 0; i < chain.ChainElements.Count; i++)
+ {
+ chain.ChainElements[i].Certificate.Dispose();
+ }
+
return verified;
}
}
// 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.IO;
-using System.Text;
-using System.Diagnostics;
using System.Globalization;
-using System.Runtime.InteropServices;
-
-using Internal.Cryptography;
namespace System.Security.Cryptography.X509Certificates
{
public sealed class X509ChainPolicy
{
+ private X509RevocationMode _revocationMode;
+ private X509RevocationFlag _revocationFlag;
+ private X509VerificationFlags _verificationFlags;
+ private OidCollection _applicationPolicy;
+ private OidCollection _certificatePolicy;
+ private X509Certificate2Collection _extraStore;
+
public X509ChainPolicy()
{
Reset();
}
- public OidCollection ApplicationPolicy { get; private set; }
+ public OidCollection ApplicationPolicy => _applicationPolicy ?? (_applicationPolicy = new OidCollection());
+
+ public OidCollection CertificatePolicy => _certificatePolicy ?? (_certificatePolicy = new OidCollection());
- public OidCollection CertificatePolicy { get; private set; }
+ public X509Certificate2Collection ExtraStore => _extraStore ?? (_extraStore = new X509Certificate2Collection());
public X509RevocationMode RevocationMode
{
public TimeSpan UrlRetrievalTimeout { get; set; }
- public X509Certificate2Collection ExtraStore { get; private set; }
-
public void Reset()
{
- ApplicationPolicy = new OidCollection();
- CertificatePolicy = new OidCollection();
+ _applicationPolicy = null;
+ _certificatePolicy = null;
+ _extraStore = null;
_revocationMode = X509RevocationMode.Online;
_revocationFlag = X509RevocationFlag.ExcludeRoot;
_verificationFlags = X509VerificationFlags.NoFlag;
VerificationTime = DateTime.Now;
- UrlRetrievalTimeout = new TimeSpan(0, 0, 0); // default timeout
- ExtraStore = new X509Certificate2Collection();
+ UrlRetrievalTimeout = TimeSpan.Zero; // default timeout
}
-
- private X509RevocationMode _revocationMode;
- private X509RevocationFlag _revocationFlag;
- private X509VerificationFlags _verificationFlags;
}
}