예제 #1
0
        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);
        }
예제 #2
0
        //
        // 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);
        }
예제 #3
0
 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));
 }
예제 #4
0
        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)));
            }
        }
예제 #5
0
 public void InitializeSecurityContext(SafeFreeCredentials?credential, SafeDeleteContext?context, string?targetName, Interop.SspiCli.ContextFlags inFlags)
 {
     if (IsEnabled())
     {
         InitializeSecurityContext(IdOf(credential), IdOf(context), targetName, inFlags);
     }
 }
예제 #6
0
        private void Dispose(bool disposing)
        {
            SafeFreeCredentials?target = Target;

            target?.DangerousRelease();
            Target = null;
        }
예제 #7
0
 public void AcceptSecurityContext(SafeFreeCredentials?credential, SafeDeleteContext?context, Interop.SspiCli.ContextFlags inFlags)
 {
     if (IsEnabled())
     {
         AcceptSecurityContext(IdOf(credential), IdOf(context), inFlags);
     }
 }
예제 #8
0
 public static SecurityStatusPal Renegotiate(
     ref SafeFreeCredentials?credentialsHandle,
     ref SafeDeleteSslContext?context,
     SslAuthenticationOptions sslAuthenticationOptions,
     out byte[]?outputBuffer)
 {
     throw new PlatformNotSupportedException();
 }
예제 #9
0
        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));
예제 #10
0
        //
        // 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}");
                }
            }
예제 #11
0
 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));
 }
예제 #12
0
        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();
 }
예제 #14
0
 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));
 }
예제 #15
0
 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));
 }
예제 #16
0
        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));
        }
예제 #17
0
        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));
        }
예제 #18
0
        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);
        }
예제 #19
0
        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)));
        }
예제 #20
0
        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));
        }
예제 #21
0
            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}");
                    }
                }
            }
예제 #22
0
        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));
        }
예제 #23
0
        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);
        }
예제 #24
0
        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);
        }
예제 #25
0
        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);
            }
        }
예제 #26
0
        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));
            }
        }
예제 #27
0
 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));
 }
예제 #28
0
 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));
 }
예제 #29
0
        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);
        }
예제 #30
0
        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);
        }