public static SafeFreeCredentials AcquireCredentialsHandle(ISSPIInterface secModule, string package, Interop.SspiCli.CredentialUse intent, Interop.SspiCli.SCHANNEL_CRED scc) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Log.AcquireCredentialsHandle(package, intent, scc); } SafeFreeCredentials?outCredential = null; int errorCode = secModule.AcquireCredentialsHandle( package, intent, ref scc, out outCredential); if (errorCode != 0) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(null, SR.Format(SR.net_log_operation_failed_with_error, nameof(AcquireCredentialsHandle), $"0x{errorCode:X}")); } throw new Win32Exception(errorCode); } return(outCredential); }
// // Returns null or previously cached cred handle. // // ATTN: The returned handle can be invalid, the callers of InitializeSecurityContext and AcceptSecurityContext // must be prepared to execute a back-out code if the call fails. // internal static SafeFreeCredentials?TryCachedCredential(byte[]?thumbPrint, SslProtocols sslProtocols, bool isServer, EncryptionPolicy encryptionPolicy) { if (s_cachedCreds.IsEmpty) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Not found, Current Cache Count = {s_cachedCreds.Count}"); } return(null); } var key = new SslCredKey(thumbPrint, (int)sslProtocols, isServer, encryptionPolicy); //SafeCredentialReference? cached; SafeFreeCredentials?credentials = GetCachedCredential(key); if (credentials == null || credentials.IsClosed || credentials.IsInvalid) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Not found or invalid, Current Cache Coun = {s_cachedCreds.Count}"); } return(null); } if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Found a cached Handle = {credentials}"); } return(credentials); }
public static SecurityStatusPal ApplyAlertToken(ref SafeFreeCredentials?credentialsHandle, SafeDeleteContext?securityContext, TlsAlertType alertType, TlsAlertMessage alertMessage) { // There doesn't seem to be an exposed API for writing an alert, // the API seems to assume that all alerts are generated internally by // SSLHandshake. return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); }
public static SecurityStatusPal ApplyShutdownToken(ref SafeFreeCredentials?credentialsHandle, SafeDeleteSslContext sslContext) { // Unset the quiet shutdown option initially configured. Interop.Ssl.SslSetQuietShutdown(sslContext.SslContext, 0); int status = Interop.Ssl.SslShutdown(sslContext.SslContext); if (status == 0) { // Call SSL_shutdown again for a bi-directional shutdown. status = Interop.Ssl.SslShutdown(sslContext.SslContext); } if (status == 1) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); } Interop.Ssl.SslErrorCode code = Interop.Ssl.SslGetError(sslContext.SslContext, status); if (code == Interop.Ssl.SslErrorCode.SSL_ERROR_WANT_READ || code == Interop.Ssl.SslErrorCode.SSL_ERROR_WANT_WRITE) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); } else if (code == Interop.Ssl.SslErrorCode.SSL_ERROR_SSL) { // OpenSSL failure occurred. The error queue contains more details, when building the exception the queue will be cleared. return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, Interop.Crypto.CreateOpenSslCryptographicException())); } else { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, new Interop.OpenSsl.SslException((int)code))); } }
public void InitializeSecurityContext(SafeFreeCredentials?credential, SafeDeleteContext?context, string?targetName, Interop.SspiCli.ContextFlags inFlags) { if (IsEnabled()) { InitializeSecurityContext(IdOf(credential), IdOf(context), targetName, inFlags); } }
private void Dispose(bool disposing) { SafeFreeCredentials?target = Target; target?.DangerousRelease(); Target = null; }
public void AcceptSecurityContext(SafeFreeCredentials?credential, SafeDeleteContext?context, Interop.SspiCli.ContextFlags inFlags) { if (IsEnabled()) { AcceptSecurityContext(IdOf(credential), IdOf(context), inFlags); } }
public static SecurityStatusPal Renegotiate( ref SafeFreeCredentials?credentialsHandle, ref SafeDeleteSslContext?context, SslAuthenticationOptions sslAuthenticationOptions, out byte[]?outputBuffer) { throw new PlatformNotSupportedException(); }
public static SecurityStatusPal AcceptSecurityContext(ref SafeFreeCredentials?credentialsHandle, ref SafeDeleteSslContext?context, ReadOnlySpan <byte> inputBuffer, ref byte[]?outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { Interop.SspiCli.ContextFlags unusedAttributes = default; InputSecurityBuffers inputBuffers = default; inputBuffers.SetNextBuffer(new InputSecurityBuffer(inputBuffer, SecurityBufferType.SECBUFFER_TOKEN)); inputBuffers.SetNextBuffer(new InputSecurityBuffer(default, SecurityBufferType.SECBUFFER_EMPTY));
// // The app is calling this method after starting an SSL handshake. // // ATTN: The thumbPrint must be from inspected and possibly cloned user Cert object or we get a security hole in SslCredKey ctor. // internal static void CacheCredential(SafeFreeCredentials creds, byte[]?thumbPrint, SslProtocols sslProtocols, bool isServer, EncryptionPolicy encryptionPolicy, bool sendTrustList = false) { Debug.Assert(creds != null, "creds == null"); if (creds.IsInvalid) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Refused to cache an Invalid Handle {creds}, Current Cache Count = {s_cachedCreds.Count}"); } return; } SslCredKey key = new SslCredKey(thumbPrint, (int)sslProtocols, isServer, encryptionPolicy, sendTrustList); SafeFreeCredentials?credentials = GetCachedCredential(key); DateTime utcNow = DateTime.UtcNow; if (credentials == null || credentials.IsClosed || credentials.IsInvalid || credentials.Expiry < utcNow) { lock (s_cachedCreds) { credentials = GetCachedCredential(key); if (credentials == null || credentials.IsClosed || credentials.IsInvalid || credentials.Expiry < utcNow) { SafeCredentialReference?cached = SafeCredentialReference.CreateReference(creds); if (cached == null) { // Means the handle got closed in between, return it back and let caller deal with the issue. return; } s_cachedCreds[key] = cached; if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Caching New Handle = {creds}, Current Cache Count = {s_cachedCreds.Count}"); } ShrinkCredentialCache(); } else { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"CacheCredential() (locked retry) Found already cached Handle = {credentials}"); } } } } else { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"CacheCredential() Ignoring incoming handle = {creds} since found already cached Handle = {credentials}"); } }
public static SecurityStatusPal AcceptSecurityContext( ref SafeFreeCredentials?credential, ref SafeDeleteSslContext?context, ReadOnlySpan <byte> inputBuffer, ref byte[]?outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { return(HandshakeInternal(ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions, null)); }
private SafeCredentialReference(SafeFreeCredentials target) { // Bumps up the refcount on Target to signify that target handle is statically cached so // its dispose should be postponed bool ignore = false; target.DangerousAddRef(ref ignore); Target = target; }
internal static SecurityStatusPal AcceptSecurityContext( SafeFreeCredentials?credentialsHandle, ref SafeDeleteContext?securityContext, ContextFlagsPal requestedContextFlags, byte[]?incomingBlob, ChannelBinding?channelBinding, ref byte[] resultBlob, ref ContextFlagsPal contextFlags) { throw new PlatformNotSupportedException(); }
public static SecurityStatusPal InitializeSecurityContext( ref SafeFreeCredentials?credential, ref SafeDeleteSslContext?context, string?targetName, ReadOnlySpan <byte> inputBuffer, ref byte[]?outputBuffer, SslAuthenticationOptions sslAuthenticationOptions, SelectClientCertificate?clientCertificateSelectionCallback) { return(HandshakeInternal(ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions, clientCertificateSelectionCallback)); }
public static SecurityStatusPal InitializeSecurityContext( SecureChannel secureChannel, ref SafeFreeCredentials?credential, ref SafeDeleteSslContext?context, string?targetName, ReadOnlySpan <byte> inputBuffer, ref byte[]?outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { return(HandshakeInternal(secureChannel, credential !, ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions)); }
internal static SecurityStatusPal AcceptSecurityContext( SafeFreeCredentials?credentialsHandle, ref SafeDeleteContext?securityContext, ContextFlagsPal requestedContextFlags, ReadOnlySpan <byte> incomingBlob, ChannelBinding?channelBinding, ref byte[]?resultBlob, out int resultBlobLength, ref ContextFlagsPal contextFlags) { InputSecurityBuffers inputBuffers = default; if (!incomingBlob.IsEmpty) { inputBuffers.SetNextBuffer(new InputSecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN)); } if (channelBinding != null) { inputBuffers.SetNextBuffer(new InputSecurityBuffer(channelBinding)); } var outSecurityBuffer = new SecurityBuffer(resultBlob, SecurityBufferType.SECBUFFER_TOKEN); Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; // There is only one SafeDeleteContext type on Windows which is SafeDeleteSslContext so this cast is safe. SafeDeleteSslContext?sslContext = (SafeDeleteSslContext?)securityContext; Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.AcceptSecurityContext( GlobalSSPI.SSPIAuth, credentialsHandle, ref sslContext, ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags), Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP, inputBuffers, ref outSecurityBuffer, ref outContextFlags); // SSPI Workaround // If a client sends up a blob on the initial request, Negotiate returns SEC_E_INVALID_HANDLE // when it should return SEC_E_INVALID_TOKEN. if (winStatus == Interop.SECURITY_STATUS.InvalidHandle && securityContext == null && !incomingBlob.IsEmpty) { winStatus = Interop.SECURITY_STATUS.InvalidToken; } Debug.Assert(outSecurityBuffer.offset == 0); resultBlob = outSecurityBuffer.token; resultBlobLength = outSecurityBuffer.size; securityContext = sslContext; contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus)); }
public static SecurityStatusPal ApplyShutdownToken( ref SafeFreeCredentials?credentialsHandle, SafeDeleteSslContext securityContext) { SafeSslHandle sslHandle = securityContext.SslContext; bool success = Interop.AndroidCrypto.SSLStreamShutdown(sslHandle); if (success) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); } return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError)); }
internal static int AcceptSecurityContext(ISSPIInterface secModule, SafeFreeCredentials?credential, ref SafeDeleteSslContext?context, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness datarep, InputSecurityBuffers inputBuffers, ref SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Log.AcceptSecurityContext(credential, context, inFlags); } int errorCode = secModule.AcceptSecurityContext(credential, ref context, inputBuffers, inFlags, datarep, ref outputBuffer, ref outFlags); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Log.SecurityContextInputBuffers(nameof(AcceptSecurityContext), inputBuffers.Count, outputBuffer.size, (Interop.SECURITY_STATUS)errorCode); } return(errorCode); }
public static SecurityStatusPal ApplyShutdownToken( ref SafeFreeCredentials?credentialsHandle, SafeDeleteSslContext securityContext) { SafeSslHandle sslHandle = securityContext.SslContext; int osStatus = Interop.AppleCrypto.SslShutdown(sslHandle); if (osStatus == 0) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK)); } return(new SecurityStatusPal( SecurityStatusPalErrorCode.InternalError, Interop.AppleCrypto.CreateExceptionForOSStatus(osStatus))); }
internal static SecurityStatusPal InitializeSecurityContext( ref SafeFreeCredentials?credentialsHandle, ref SafeDeleteContext?securityContext, string?spn, ContextFlagsPal requestedContextFlags, ReadOnlySpan <byte> incomingBlob, ChannelBinding?channelBinding, ref byte[]?resultBlob, out int resultBlobLength, ref ContextFlagsPal contextFlags) { InputSecurityBuffers inputBuffers = default; if (!incomingBlob.IsEmpty) { inputBuffers.SetNextBuffer(new InputSecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN)); } if (channelBinding != null) { inputBuffers.SetNextBuffer(new InputSecurityBuffer(channelBinding)); } var outSecurityBuffer = new SecurityBuffer(resultBlob, SecurityBufferType.SECBUFFER_TOKEN); Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; // There is only one SafeDeleteContext type on Windows which is SafeDeleteSslContext so this cast is safe. SafeDeleteSslContext?sslContext = (SafeDeleteSslContext?)securityContext; Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.InitializeSecurityContext( GlobalSSPI.SSPIAuth, ref credentialsHandle, ref sslContext, spn, ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags), Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP, inputBuffers, ref outSecurityBuffer, ref outContextFlags); securityContext = sslContext; Debug.Assert(outSecurityBuffer.offset == 0); resultBlob = outSecurityBuffer.token; resultBlobLength = outSecurityBuffer.size; contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus)); }
static void ShrinkCredentialCache() { // // A simplest way of preventing infinite cache grows. // // Security relief (DoS): // A number of active creds is never greater than a number of _outstanding_ // security sessions, i.e. SSL connections. // So we will try to shrink cache to the number of active creds once in a while. // // We won't shrink cache in the case when NO new handles are coming to it. // if ((s_cachedCreds.Count % CheckExpiredModulo) == 0) { KeyValuePair <SslCredKey, SafeCredentialReference>[] toRemoveAttempt = s_cachedCreds.ToArray(); for (int i = 0; i < toRemoveAttempt.Length; ++i) { SafeCredentialReference?cahced = toRemoveAttempt[i].Value; SafeFreeCredentials? creds = cahced.Target; if (creds == null) { s_cachedCreds.TryRemove(toRemoveAttempt[i].Key, out _); continue; } cahced.Dispose(); cahced = SafeCredentialReference.CreateReference(creds); if (cahced != null) { s_cachedCreds[toRemoveAttempt[i].Key] = cahced; } else { s_cachedCreds.TryRemove(toRemoveAttempt[i].Key, out _); } } if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Scavenged cache, New Cache Count = {s_cachedCreds.Count}"); } } }
internal static SecurityStatusPal AcceptSecurityContext( SafeFreeCredentials?credentialsHandle, ref SafeDeleteContext?securityContext, ContextFlagsPal requestedContextFlags, byte[]?incomingBlob, ChannelBinding?channelBinding, ref byte[]?resultBlob, ref ContextFlagsPal contextFlags) { InputSecurityBuffers inputBuffers = default; if (incomingBlob != null) { inputBuffers.SetNextBuffer(new InputSecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN)); } if (channelBinding != null) { inputBuffers.SetNextBuffer(new InputSecurityBuffer(channelBinding)); } var outSecurityBuffer = new SecurityBuffer(resultBlob, SecurityBufferType.SECBUFFER_TOKEN); Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; // There is only one SafeDeleteContext type on Windows which is SafeDeleteSslContext so this cast is safe. SafeDeleteSslContext?sslContext = (SafeDeleteSslContext?)securityContext; Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.AcceptSecurityContext( GlobalSSPI.SSPIAuth, credentialsHandle, ref sslContext, ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags), Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP, inputBuffers, ref outSecurityBuffer, ref outContextFlags); resultBlob = outSecurityBuffer.token; securityContext = sslContext; contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus)); }
public static SafeFreeCredentials AcquireDefaultCredential(ISSPIInterface secModule, string package, Interop.SspiCli.CredentialUse intent) { if (NetEventSource.IsEnabled) { NetEventSource.Enter(null, package); NetEventSource.Log.AcquireDefaultCredential(package, intent); } SafeFreeCredentials?outCredential = null; int errorCode = secModule.AcquireDefaultCredential(package, intent, out outCredential); if (errorCode != 0) { if (NetEventSource.IsEnabled) { NetEventSource.Error(null, SR.Format(SR.net_log_operation_failed_with_error, nameof(AcquireDefaultCredential), $"0x{errorCode:X}")); } throw new Win32Exception(errorCode); } return(outCredential); }
public static SafeFreeCredentials AcquireCredentialsHandle(ISSPIInterface secModule, string package, Interop.SspiCli.CredentialUse intent, ref SafeSspiAuthDataHandle authdata) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Log.AcquireCredentialsHandle(package, intent, authdata); } SafeFreeCredentials?credentialsHandle = null; int errorCode = secModule.AcquireCredentialsHandle(package, intent, ref authdata, out credentialsHandle); if (errorCode != 0) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(null, SR.Format(SR.net_log_operation_failed_with_error, nameof(AcquireCredentialsHandle), $"0x{errorCode:X}")); } throw new Win32Exception(errorCode); } return(credentialsHandle); }
private void Initialize(bool isServer, string package, NetworkCredential credential, string?spn, ContextFlagsPal requestedContextFlags, ChannelBinding?channelBinding) { if (NetEventSource.IsEnabled) { NetEventSource.Enter(this, package, spn, requestedContextFlags); } _tokenSize = NegotiateStreamPal.QueryMaxTokenSize(package); _isServer = isServer; _spn = spn; _securityContext = null; _requestedContextFlags = requestedContextFlags; _package = package; _channelBinding = channelBinding; if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"Peer SPN-> '{_spn}'"); } // // Check if we're using DefaultCredentials. // Debug.Assert(CredentialCache.DefaultCredentials == CredentialCache.DefaultNetworkCredentials); if (credential == CredentialCache.DefaultCredentials) { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, "using DefaultCredentials"); } _credentialsHandle = NegotiateStreamPal.AcquireDefaultCredential(package, _isServer); } else { _credentialsHandle = NegotiateStreamPal.AcquireCredentialsHandle(package, _isServer, credential); } }
internal static SecurityStatusPal AcceptSecurityContext( SafeFreeCredentials?credentialsHandle, ref SafeDeleteContext?securityContext, ContextFlagsPal requestedContextFlags, byte[]?incomingBlob, ChannelBinding?channelBinding, ref byte[] resultBlob, ref ContextFlagsPal contextFlags) { if (securityContext == null) { securityContext = new SafeDeleteNegoContext((SafeFreeNegoCredentials)credentialsHandle !); } SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)securityContext; try { SafeGssContextHandle?contextHandle = negoContext.GssContext; bool done = GssAcceptSecurityContext( ref contextHandle, negoContext.AcceptorCredential, incomingBlob, out resultBlob, out uint outputFlags, out bool isNtlmUsed); Debug.Assert(resultBlob != null, "Unexpected null buffer returned by GssApi"); Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext); // Save the inner context handle for further calls to NetSecurity Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext); if (null == negoContext.GssContext) { negoContext.SetGssContext(contextHandle !); } contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop( (Interop.NetSecurityNative.GssFlags)outputFlags, isServer: true); SecurityStatusPalErrorCode errorCode; if (done) { if (NetEventSource.Log.IsEnabled()) { string protocol = isNtlmUsed ? "SPNEGO-NTLM" : "SPNEGO-Kerberos"; NetEventSource.Info(securityContext, $"AcceptSecurityContext: actual protocol = {protocol}"); } negoContext.SetAuthenticationPackage(isNtlmUsed); errorCode = (isNtlmUsed && resultBlob.Length > 0) ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.CompleteNeeded; } else { errorCode = SecurityStatusPalErrorCode.ContinueNeeded; } return(new SecurityStatusPal(errorCode)); } catch (Interop.NetSecurityNative.GssApiException gex) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(null, gex); } return(new SecurityStatusPal(GetErrorCode(gex), gex)); } catch (Exception ex) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(null, ex); } return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex)); } }
public int InitializeSecurityContext(ref SafeFreeCredentials?credential, ref SafeDeleteSslContext?context, string?targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, InputSecurityBuffers inputBuffers, ref SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags) { return(SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, inputBuffers, ref outputBuffer, ref outFlags)); }
public int AcceptSecurityContext(SafeFreeCredentials?credential, ref SafeDeleteSslContext?context, InputSecurityBuffers 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, inputBuffers, ref outputBuffer, ref outFlags)); }
internal static unsafe int AcceptSecurityContext( ref SafeFreeCredentials?inCredentials, ref SafeDeleteSslContext?refContext, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, InputSecurityBuffers inSecBuffers, ref SecurityBuffer outSecBuffer, ref Interop.SspiCli.ContextFlags outFlags) { #if TRACE_VERBOSE if (NetEventSource.IsEnabled) { NetEventSource.Enter(null, $"credential={inCredentials}, refContext={refContext}, inFlags={inFlags}"); NetEventSource.Info(null, $"inSecBuffers.Length = {inSecBuffers.Length}"); } #endif if (inCredentials == null) { throw new ArgumentNullException(nameof(inCredentials)); } Debug.Assert(inSecBuffers.Count <= 3); Interop.SspiCli.SecBufferDesc inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Count); Interop.SspiCli.SecBufferDesc outSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(count: 2); // Actually, this is returned in outFlags. bool isSspiAllocated = (inFlags & Interop.SspiCli.ContextFlags.AllocateMemory) != 0 ? true : false; int errorCode = -1; bool isContextAbsent = true; if (refContext != null) { isContextAbsent = refContext._handle.IsZero; } // Optional output buffer that may need to be freed. SafeFreeContextBuffer? outFreeContextBuffer = null; Span <Interop.SspiCli.SecBuffer> outUnmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[2]; outUnmanagedBuffer[1].pvBuffer = IntPtr.Zero; try { // Allocate always maximum to allow better code optimization. Span <Interop.SspiCli.SecBuffer> inUnmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[3]; fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer) fixed(void *outUnmanagedBufferPtr = outUnmanagedBuffer) fixed(void *pinnedToken0 = inSecBuffers._item0.Token) fixed(void *pinnedToken1 = inSecBuffers._item1.Token) fixed(void *pinnedToken2 = inSecBuffers._item2.Token) { inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr; // Updated pvBuffer with pinned address. UnmanagedToken takes precedence. if (inSecBuffers.Count > 2) { inUnmanagedBuffer[2].BufferType = inSecBuffers._item2.Type; inUnmanagedBuffer[2].cbBuffer = inSecBuffers._item2.Token.Length; inUnmanagedBuffer[2].pvBuffer = inSecBuffers._item2.UnmanagedToken != null ? (IntPtr)inSecBuffers._item2.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken2; } if (inSecBuffers.Count > 1) { inUnmanagedBuffer[1].BufferType = inSecBuffers._item1.Type; inUnmanagedBuffer[1].cbBuffer = inSecBuffers._item1.Token.Length; inUnmanagedBuffer[1].pvBuffer = inSecBuffers._item1.UnmanagedToken != null ? (IntPtr)inSecBuffers._item1.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken1; } if (inSecBuffers.Count > 0) { inUnmanagedBuffer[0].BufferType = inSecBuffers._item0.Type; inUnmanagedBuffer[0].cbBuffer = inSecBuffers._item0.Token.Length; inUnmanagedBuffer[0].pvBuffer = inSecBuffers._item0.UnmanagedToken != null ? (IntPtr)inSecBuffers._item0.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken0; } 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; outUnmanagedBuffer[0].pvBuffer = outSecBuffer.token == null || outSecBuffer.token.Length == 0 ? IntPtr.Zero : (IntPtr)(pinnedOutBytes + outSecBuffer.offset); outUnmanagedBuffer[1].cbBuffer = 0; outUnmanagedBuffer[1].BufferType = SecurityBufferType.SECBUFFER_ALERT; if (isSspiAllocated) { outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle(); } if (refContext == null || refContext.IsInvalid) { // Previous versions unconditionally built a new "refContext" here, but would pass // incorrect arguments to AcceptSecurityContext in cases where an "contextHandle" was // already present and non-zero. if (isContextAbsent) { refContext = new SafeDeleteSslContext(); } } errorCode = MustRunAcceptSecurityContext_SECURITY( ref inCredentials, isContextAbsent, &inSecurityBufferDescriptor, inFlags, endianness, refContext !, ref outSecurityBufferDescriptor, ref outFlags, outFreeContextBuffer); if (NetEventSource.IsEnabled) { NetEventSource.Info(null, "Marshaling OUT buffer"); } // No data written out but there is Alert if (outUnmanagedBuffer[0].cbBuffer == 0 && outUnmanagedBuffer[1].cbBuffer > 0) { outSecBuffer.size = outUnmanagedBuffer[1].cbBuffer; outSecBuffer.type = outUnmanagedBuffer[1].BufferType; outSecBuffer.token = new Span <byte>((byte *)outUnmanagedBuffer[1].pvBuffer, outUnmanagedBuffer[1].cbBuffer).ToArray(); } else { outSecBuffer.size = outUnmanagedBuffer[0].cbBuffer; outSecBuffer.type = outUnmanagedBuffer[0].BufferType; outSecBuffer.token = outUnmanagedBuffer[0].cbBuffer > 0 ? new Span <byte>((byte *)outUnmanagedBuffer[0].pvBuffer, outUnmanagedBuffer[0].cbBuffer).ToArray() : null; } } } } finally { outFreeContextBuffer?.Dispose(); if (outUnmanagedBuffer[1].pvBuffer != IntPtr.Zero) { Interop.SspiCli.FreeContextBuffer(outUnmanagedBuffer[1].pvBuffer); } } if (NetEventSource.IsEnabled) { NetEventSource.Exit(null, $"errorCode:0x{errorCode:x8}, refContext:{refContext}"); } return(errorCode); }
internal static unsafe int InitializeSecurityContext( ref SafeFreeCredentials?inCredentials, ref SafeDeleteSslContext?refContext, string?targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, InputSecurityBuffers 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}"); NetEventSource.Info(null, $"inSecBuffers.Length = {inSecBuffers.Length}"); } #endif if (inCredentials == null) { throw new ArgumentNullException(nameof(inCredentials)); } Debug.Assert(inSecBuffers.Count <= 3); Interop.SspiCli.SecBufferDesc inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Count); Interop.SspiCli.SecBufferDesc outSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(1); // Actually, this is returned in outFlags. bool isSspiAllocated = (inFlags & Interop.SspiCli.ContextFlags.AllocateMemory) != 0 ? true : false; int errorCode = -1; bool isContextAbsent = true; if (refContext != null) { isContextAbsent = refContext._handle.IsZero; } // Optional output buffer that may need to be freed. SafeFreeContextBuffer?outFreeContextBuffer = null; try { Span <Interop.SspiCli.SecBuffer> inUnmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[3]; fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer) fixed(void *pinnedToken0 = inSecBuffers._item0.Token) fixed(void *pinnedToken1 = inSecBuffers._item1.Token) fixed(void *pinnedToken2 = inSecBuffers._item2.Token) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr; // Updated pvBuffer with pinned address. UnmanagedToken takes precedence. if (inSecBuffers.Count > 2) { inUnmanagedBuffer[2].BufferType = inSecBuffers._item2.Type; inUnmanagedBuffer[2].cbBuffer = inSecBuffers._item2.Token.Length; inUnmanagedBuffer[2].pvBuffer = inSecBuffers._item2.UnmanagedToken != null ? (IntPtr)inSecBuffers._item2.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken2; } if (inSecBuffers.Count > 1) { inUnmanagedBuffer[1].BufferType = inSecBuffers._item1.Type; inUnmanagedBuffer[1].cbBuffer = inSecBuffers._item1.Token.Length; inUnmanagedBuffer[1].pvBuffer = inSecBuffers._item1.UnmanagedToken != null ? (IntPtr)inSecBuffers._item1.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken1; } if (inSecBuffers.Count > 0) { inUnmanagedBuffer[0].BufferType = inSecBuffers._item0.Type; inUnmanagedBuffer[0].cbBuffer = inSecBuffers._item0.Token.Length; inUnmanagedBuffer[0].pvBuffer = inSecBuffers._item0.UnmanagedToken != null ? (IntPtr)inSecBuffers._item0.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken0; } fixed(byte *pinnedOutBytes = outSecBuffer.token) { // 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 (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 SafeDeleteSslContext(); } } 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, &inSecurityBufferDescriptor, refContext !, ref outSecurityBufferDescriptor, ref outFlags, outFreeContextBuffer); } 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; outSecBuffer.token = outSecBuffer.size > 0 ? new Span <byte>((byte *)outUnmanagedBuffer.pvBuffer, outUnmanagedBuffer.cbBuffer).ToArray() : null; } } } finally { outFreeContextBuffer?.Dispose(); } if (NetEventSource.IsEnabled) { NetEventSource.Exit(null, $"errorCode:0x{errorCode:x8}, refContext:{refContext}"); } return(errorCode); }