Esempio n. 1
0
        internal static void CacheCredential(SafeFreeCredentials newHandle)
        {
            try
            {
                SafeCredentialReference newRef = SafeCredentialReference.CreateReference(newHandle);

                if (newRef == null)
                {
                    return;
                }
                
                unchecked
                {
                    int index = Interlocked.Increment(ref s_current) & c_MaxCacheSize;
                    newRef = Interlocked.Exchange<SafeCredentialReference>(ref s_cacheSlots[index], newRef);
                }

                if (newRef != null)
                {
                    newRef.Dispose();
                }
            }
            catch (Exception e)
            {
                if (!ExceptionCheck.IsFatal(e) && GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("SSPIHandlCache", "Attempted to throw: " + e.ToString());
                }
            }
        }
Esempio n. 2
0
 protected override bool ReleaseHandle()
 {
     Debug.Assert((null != _credential), "Null credential in SafeDeleteContext");
     _credential.DangerousRelease();
     _credential = null;
     return true;
 }
Esempio n. 3
0
        internal static void CacheCredential(SafeFreeCredentials newHandle)
        {
            try
            {
                SafeCredentialReference newRef = SafeCredentialReference.CreateReference(newHandle);

                if (newRef == null)
                {
                    return;
                }

                unchecked
                {
                    int index = Interlocked.Increment(ref s_current) & c_MaxCacheSize;
                    newRef = Interlocked.Exchange<SafeCredentialReference>(ref s_cacheSlots[index], newRef);
                }

                if (newRef != null)
                {
                    newRef.Dispose();
                }
            }
            catch (Exception e)
            {
                if (!ExceptionCheck.IsFatal(e))
                {
                    NetEventSource.Fail(null, "Attempted to throw: {e}");
                }
            }
        }
Esempio n. 4
0
 private SafeCredentialReference(SafeFreeCredentials target) : base()
 {
     // 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;
     SetHandle(new IntPtr(0));   // make this handle valid
 }
Esempio n. 5
0
        internal static SafeCredentialReference CreateReference(SafeFreeCredentials target)
        {
            SafeCredentialReference result = new SafeCredentialReference(target);
            if (result.IsInvalid)
            {
                return null;
            }

            return result;
        }
Esempio n. 6
0
        protected override bool ReleaseHandle()
        {
            SafeFreeCredentials target = Target;
            if (target != null)
            {
                target.DangerousRelease();
            }

            Target = null;
            return true;
        }
Esempio n. 7
0
        protected SafeDeleteContext(SafeFreeCredentials credential)
            : base(IntPtr.Zero, true)
        {
            Debug.Assert((null != credential), "Invalid credential passed to SafeDeleteContext");

            // When a credential handle is first associated with the context we keep credential
            // ref count bumped up to ensure ordered finalization. The credential properties
            // are used in the SSL/NEGO data structures and should survive the lifetime of
            // the SSL/NEGO context
            bool ignore = false;
            _credential = credential;
            _credential.DangerousAddRef(ref ignore);
        }
Esempio n. 8
0
        public static SecurityStatusPal AcceptSecurityContext(ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, bool remoteCertRequired)
        {
            Interop.SspiCli.ContextFlags unusedAttributes = default(Interop.SspiCli.ContextFlags);

            int errorCode = SSPIWrapper.AcceptSecurityContext(
                GlobalSSPI.SSPISecureChannel,
                ref credentialsHandle,
                ref context,
                ServerRequiredFlags | (remoteCertRequired ? Interop.SspiCli.ContextFlags.MutualAuth : Interop.SspiCli.ContextFlags.Zero),
                Interop.SspiCli.Endianness.SECURITY_NATIVE_DREP,
                inputBuffer,
                outputBuffer,
                ref unusedAttributes);

            return SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode);
        }
Esempio n. 9
0
        public static SecurityStatusPal InitializeSecurityContext(SafeFreeCredentials credentialsHandle, ref SafeDeleteContext context, string targetName, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer)
        {
            Interop.SspiCli.ContextFlags unusedAttributes = default(Interop.SspiCli.ContextFlags);

            int errorCode = SSPIWrapper.InitializeSecurityContext(
                            GlobalSSPI.SSPISecureChannel,
                            credentialsHandle,
                            ref context,
                            targetName,
                            RequiredFlags | Interop.SspiCli.ContextFlags.InitManualCredValidation,
                            Interop.SspiCli.Endianness.SECURITY_NATIVE_DREP,
                            inputBuffers,
                            outputBuffer,
                            ref unusedAttributes);

            return SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode);
        }
Esempio n. 10
0
        public static unsafe int AcquireDefaultCredential(
            string package,
            Interop.SspiCli.CredentialUse intent,
            out SafeFreeCredentials outCredential)
        {
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Enter(null, package, intent);
            }

            int  errorCode = -1;
            long timeStamp;

            outCredential = new SafeFreeCredential_SECURITY();

            errorCode = Interop.SspiCli.AcquireCredentialsHandleW(
                null,
                package,
                (int)intent,
                null,
                IntPtr.Zero,
                null,
                null,
                ref outCredential._handle,
                out timeStamp);

#if TRACE_VERBOSE
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Info(null, $"{nameof(Interop.SspiCli.AcquireCredentialsHandleW)} returns 0x{errorCode:x}, handle = {outCredential}");
            }
#endif

            if (errorCode != 0)
            {
                outCredential.SetHandleAsInvalid();
            }

            return(errorCode);
        }
Esempio n. 11
0
        internal static void CacheCredential(SafeFreeCredentials newHandle)
        {
            try
            {
                SafeCredentialReference?newRef = SafeCredentialReference.CreateReference(newHandle);
                if (newRef == null)
                {
                    return;
                }

                int index = Interlocked.Increment(ref s_current) & MaxCacheSize;

                Interlocked.Exchange(ref s_cacheSlots[index], newRef)?.Dispose();
            }
            catch (Exception e)
            {
                if (NetEventSource.Log.IsEnabled() && !ExceptionCheck.IsFatal(e))
                {
                    NetEventSource.Error(null, $"Attempted to throw: {e}");
                }
            }
        }
        internal static SecurityStatusPal AcceptSecurityContext(
            SafeFreeCredentials credentialsHandle,
            ref SafeDeleteContext securityContext,
            ContextFlagsPal requestedContextFlags,
            SecurityBuffer[] inSecurityBufferArray,
            SecurityBuffer outSecurityBuffer,
            ref ContextFlagsPal contextFlags)
        {
            Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero;
            Interop.SECURITY_STATUS      winStatus       = (Interop.SECURITY_STATUS)SSPIWrapper.AcceptSecurityContext(
                GlobalSSPI.SSPIAuth,
                credentialsHandle,
                ref securityContext,
                ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags),
                Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP,
                inSecurityBufferArray,
                outSecurityBuffer,
                ref outContextFlags);

            contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags);
            return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus));
        }
Esempio n. 13
0
        public static SecurityStatusPal ApplyShutdownToken(
            ref SafeFreeCredentials credentialsHandle,
            SafeDeleteContext securityContext)
        {
            SafeDeleteSslContext sslContext = ((SafeDeleteSslContext)securityContext);
            SafeSslHandle        sslHandle  = sslContext.SslContext;
            int osStatus;

            lock (sslHandle)
            {
                osStatus = Interop.AppleCrypto.SslShutdown(sslHandle);
            }

            if (osStatus == 0)
            {
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK));
            }

            return(new SecurityStatusPal(
                       SecurityStatusPalErrorCode.InternalError,
                       Interop.AppleCrypto.CreateExceptionForOSStatus(osStatus)));
        }
        public unsafe static int AcquireCredentialsHandle(
            string package,
            Interop.Secur32.CredentialUse intent,
            ref Interop.Secur32.AuthIdentity authdata,
            out SafeFreeCredentials outCredential)
        {
            GlobalLog.Print("SafeFreeCredentials::AcquireCredentialsHandle#1("
                            + package + ", "
                            + intent + ", "
                            + authdata + ")");

            int  errorCode = -1;
            long timeStamp;

            outCredential = new SafeFreeCredential_SECURITY();

            errorCode = Interop.Secur32.AcquireCredentialsHandleW(
                null,
                package,
                (int)intent,
                null,
                ref authdata,
                null,
                null,
                ref outCredential._handle,
                out timeStamp);
#if TRACE_VERBOSE
            GlobalLog.Print("Unmanaged::AcquireCredentialsHandle() returns 0x"
                            + String.Format("{0:x}", errorCode)
                            + ", handle = " + outCredential.ToString());
#endif

            if (errorCode != 0)
            {
                outCredential.SetHandleAsInvalid();
            }

            return(errorCode);
        }
Esempio n. 15
0
        internal static SecurityStatusPal InitializeSecurityContext(
            ref SafeFreeCredentials credentialsHandle,
            ref SafeDeleteContext?securityContext,
            string?spn,
            ContextFlagsPal requestedContextFlags,
            byte[]?incomingBlob,
            ChannelBinding?channelBinding,
            ref byte[]?resultBlob,
            ref ContextFlagsPal contextFlags)
        {
            SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle;

            if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn))
            {
                throw new PlatformNotSupportedException(SR.net_nego_not_supported_empty_target_with_defaultcreds);
            }

            SecurityStatusPal status = EstablishSecurityContext(
                negoCredentialsHandle,
                ref securityContext,
                channelBinding,
                spn,
                requestedContextFlags,
                incomingBlob,
                ref resultBlob,
                ref contextFlags);

            // Confidentiality flag should not be set if not requested
            if (status.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded)
            {
                ContextFlagsPal mask = ContextFlagsPal.Confidentiality;
                if ((requestedContextFlags & mask) != (contextFlags & mask))
                {
                    throw new PlatformNotSupportedException(SR.net_nego_protection_level_not_supported);
                }
            }

            return(status);
        }
Esempio n. 16
0
        private static SecurityStatusPal HandshakeInternal(
            SafeFreeCredentials credential,
            ref SafeDeleteSslContext?context,
            ReadOnlySpan <byte> inputBuffer,
            ref byte[]?outputBuffer,
            SslAuthenticationOptions sslAuthenticationOptions)
        {
            Debug.Assert(!credential.IsInvalid);

            try
            {
                SafeDeleteSslContext?sslContext = ((SafeDeleteSslContext?)context);

                if ((context == null) || context.IsInvalid)
                {
                    context    = new SafeDeleteSslContext((credential as SafeFreeSslCredentials) !, sslAuthenticationOptions);
                    sslContext = context;
                }

                if (inputBuffer.Length > 0)
                {
                    sslContext !.Write(inputBuffer);
                }

                SafeSslHandle sslHandle = sslContext !.SslContext;

                // Do handshake
                // Interop.AndroidCrypto.SSLStreamHandshake

                outputBuffer = sslContext.ReadPendingWrites();

                return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK));
            }
            catch (Exception exc)
            {
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc));
            }
        }
Esempio n. 17
0
        public unsafe static int AcquireDefaultCredential(
            string package,
            Interop.Secur32.CredentialUse intent,
            out SafeFreeCredentials outCredential)
        {
            GlobalLog.Print("SafeFreeCredentials::AcquireDefaultCredential("
                            + package + ", "
                            + intent + ")");

            int errorCode = -1;
            long timeStamp;

            outCredential = new SafeFreeCredential_SECURITY();

            errorCode = Interop.Secur32.AcquireCredentialsHandleW(
                            null,
                            package,
                            (int)intent,
                            null,
                            IntPtr.Zero,
                            null,
                            null,
                            ref outCredential._handle,
                            out timeStamp);

#if TRACE_VERBOSE
            GlobalLog.Print("Unmanaged::AcquireCredentialsHandle() returns 0x"
                            + errorCode.ToString("x")
                            + ", handle = " + outCredential.ToString());
#endif

            if (errorCode != 0)
            {
                outCredential.SetHandleAsInvalid();
            }

            return errorCode;
        }
Esempio n. 18
0
        private SafeCredentialReference(SafeFreeCredentials target)
            : base()
        {
            // Bumps up the refcount on Target to signify that target handle is statically cached so
            // its dispose should be postponed
            bool b = false;

            try {
                target.DangerousAddRef(ref b);
            } catch {
                if (b)
                {
                    target.DangerousRelease();
                    b = false;
                }
            } finally {
                if (b)
                {
                    _Target = target;
                    SetHandle(new IntPtr(0));                         // make this handle valid
                }
            }
        }
Esempio n. 19
0
        public static SecurityStatusPal ApplyShutdownToken(ref SafeFreeCredentials credentialsHandle, SafeDeleteContext securityContext)
        {
            SafeDeleteSslContext sslContext = ((SafeDeleteSslContext)securityContext);

            // 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)));
            }
        }
Esempio n. 20
0
        private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer,
                                                           SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
        {
            Debug.Assert(!credential.IsInvalid);

            try
            {
                if ((null == context) || context.IsInvalid)
                {
                    context = new SafeDeleteSslContext(credential as SafeFreeSslCredentials, sslAuthenticationOptions);
                }

                byte[] output = null;
                int    outputSize;
                bool   done;

                if (null == inputBuffer)
                {
                    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);
                }

                outputBuffer.size   = outputSize;
                outputBuffer.offset = 0;
                outputBuffer.token  = outputSize > 0 ? output : null;

                return(new SecurityStatusPal(done ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.ContinueNeeded));
            }
            catch (Exception exc)
            {
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc));
            }
        }
Esempio n. 21
0
        internal static SecurityStatusPal InitializeSecurityContext(
            SafeFreeCredentials credentialsHandle,
            ref SafeDeleteContext securityContext,
            string spn,
            ContextFlagsPal requestedContextFlags,
            SecurityBuffer[] inSecurityBufferArray,
            SecurityBuffer outSecurityBuffer,
            ref ContextFlagsPal contextFlags)
        {
            Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero;
            Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.InitializeSecurityContext(
                GlobalSSPI.SSPIAuth,
                credentialsHandle,
                ref securityContext,
                spn,
                ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags),
                Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP,
                inSecurityBufferArray,
                outSecurityBuffer,
                ref outContextFlags);

            contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags);
            return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus);
        }
Esempio n. 22
0
        internal static SecurityStatusPal InitializeSecurityContext(
            SafeFreeCredentials credentialsHandle,
            ref SafeDeleteContext securityContext,
            string spn,
            ContextFlagsPal requestedContextFlags,
            SecurityBuffer[] inSecurityBufferArray,
            SecurityBuffer outSecurityBuffer,
            ref ContextFlagsPal contextFlags)
        {
            Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero;
            Interop.SecurityStatus       winStatus       = (Interop.SecurityStatus)SSPIWrapper.InitializeSecurityContext(
                GlobalSSPI.SSPIAuth,
                credentialsHandle,
                ref securityContext,
                spn,
                ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags),
                Interop.SspiCli.Endianness.Network,
                inSecurityBufferArray,
                outSecurityBuffer,
                ref outContextFlags);

            contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags);
            return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus));
        }
Esempio n. 23
0
        private static unsafe int MustRunAcceptSecurityContext_SECURITY(
            ref SafeFreeCredentials inCredentials,
            bool isContextAbsent,
            Interop.SspiCli.SecBufferDesc *inputBuffer,
            Interop.SspiCli.ContextFlags inFlags,
            Interop.SspiCli.Endianness endianness,
            SafeDeleteContext outContext,
            ref Interop.SspiCli.SecBufferDesc outputBuffer,
            ref Interop.SspiCli.ContextFlags outFlags,
            SafeFreeContextBuffer?handleTemplate)
        {
            int errorCode = (int)Interop.SECURITY_STATUS.InvalidHandle;

            // Run the body of this method as a non-interruptible block.
            try
            {
                bool ignore = false;

                inCredentials.DangerousAddRef(ref ignore);
                outContext.DangerousAddRef(ref ignore);

                Interop.SspiCli.CredHandle credentialHandle = inCredentials._handle;
                long timeStamp;

                // Now that "outContext" (or "refContext" by the caller) references an actual handle (and cannot
                // be closed until it is released below), point "inContextPtr" to its embedded handle (or
                // null if the embedded handle has not yet been initialized).
                Interop.SspiCli.CredHandle contextHandle = outContext._handle;
                void *inContextPtr = contextHandle.IsZero ? null : &contextHandle;

                // The "isContextAbsent" supplied by the caller is generally correct but was computed without proper
                // synchronization. Rewrite the indicator now that the final "inContext" is known, update if necessary.
                isContextAbsent = (inContextPtr == null);

                errorCode = Interop.SspiCli.AcceptSecurityContext(
                    ref credentialHandle,
                    inContextPtr,
                    inputBuffer,
                    inFlags,
                    endianness,
                    ref outContext._handle,
                    ref outputBuffer,
                    ref outFlags,
                    out timeStamp);
            }
            finally
            {
                //
                // When a credential handle is first associated with the context we keep credential
                // ref count bumped up to ensure ordered finalization.
                // If the credential handle has been changed we de-ref the old one and associate the
                //  context with the new cred handle but only if the call was successful.
                if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0)
                {
                    // Disassociate the previous credential handle.
                    outContext._EffectiveCredential?.DangerousRelease();
                    outContext._EffectiveCredential = inCredentials;
                }
                else
                {
                    inCredentials.DangerousRelease();
                }

                outContext.DangerousRelease();
            }

            // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer.
            if (handleTemplate != null)
            {
                //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes.
                handleTemplate.Set(((Interop.SspiCli.SecBuffer *)outputBuffer.pBuffers)->pvBuffer);
                if (handleTemplate.IsInvalid)
                {
                    handleTemplate.SetHandleAsInvalid();
                }
            }

            if (isContextAbsent && (errorCode & 0x80000000) != 0)
            {
                // An error on the first call, need to set the out handle to invalid value.
                outContext._handle.SetToInvalid();
            }

            return(errorCode);
        }
Esempio n. 24
0
 public static SecurityStatusPal ApplyAlertToken(ref SafeFreeCredentials credentialsHandle, SafeDeleteContext securityContext, TlsAlertType alertType, TlsAlertMessage alertMessage)
 {
     // TODO (#12319): Not implemented.
     return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK));
 }
Esempio n. 25
0
        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 buffer = new byte[alertTokenByteSize];
                Marshal.StructureToPtr<Interop.SChannel.SCHANNEL_ALERT_TOKEN>(alertToken, p, false);
                Marshal.Copy(p, buffer, 0, alertTokenByteSize);

                bufferDesc[0] = new SecurityBuffer(buffer, SecurityBufferType.SECBUFFER_TOKEN);
                var errorCode = (Interop.SECURITY_STATUS)SSPIWrapper.ApplyControlToken(
                    GlobalSSPI.SSPISecureChannel,
                    ref securityContext,
                    bufferDesc);

                return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(errorCode, attachException:true);
            }
            finally
            {
                Marshal.FreeHGlobal(p);
            }
        }
Esempio n. 26
0
		private SafeCredentialReference (SafeFreeCredentials target)
			: base ()
		{
			// Bumps up the refcount on Target to signify that target handle is statically cached so
			// its dispose should be postponed
			bool b = false;
			try {
				target.DangerousAddRef (ref b);
			} catch {
				if (b) {
					target.DangerousRelease ();
					b = false;
				}
			} finally {
				if (b) {
					_Target = target;
					SetHandle (new IntPtr (0));   // make this handle valid
				}
			}
		}
        //
        // After PInvoke call the method will fix the handleTemplate.handle with the returned value.
        // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavour or null can be passed if no handle is returned.
        //
        private static unsafe int MustRunAcceptSecurityContext_SECURITY(
            ref SafeFreeCredentials inCredentials,
            void* inContextPtr,
            Interop.Secur32.SecurityBufferDescriptor inputBuffer,
            Interop.Secur32.ContextFlags inFlags,
            Interop.Secur32.Endianness endianness,
            SafeDeleteContext outContext,
            Interop.Secur32.SecurityBufferDescriptor outputBuffer,
            ref Interop.Secur32.ContextFlags outFlags,
            SafeFreeContextBuffer handleTemplate)
        {
            int errorCode = (int)Interop.SecurityStatus.InvalidHandle;

            // Run the body of this method as a non-interruptible block.
            try
            {
                bool ignore = false;

                inCredentials.DangerousAddRef(ref ignore);
                outContext.DangerousAddRef(ref ignore);

                Interop.Secur32.SSPIHandle credentialHandle = inCredentials._handle;
                long timeStamp;

                errorCode = Interop.Secur32.AcceptSecurityContext(
                                ref credentialHandle,
                                inContextPtr,
                                inputBuffer,
                                inFlags,
                                endianness,
                                ref outContext._handle,
                                outputBuffer,
                                ref outFlags,
                                out timeStamp);
            }
            finally
            {
                //
                // When a credential handle is first associated with the context we keep credential
                // ref count bumped up to ensure ordered finalization.
                // If the credential handle has been changed we de-ref the old one and associate the
                //  context with the new cred handle but only if the call was successful.
                if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0)
                {
                    // Disassociate the previous credential handle.
                    if (outContext._EffectiveCredential != null)
                    {
                        outContext._EffectiveCredential.DangerousRelease();
                    }

                    outContext._EffectiveCredential = inCredentials;
                }
                else
                {
                    inCredentials.DangerousRelease();
                }

                outContext.DangerousRelease();
            }

            // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer.
            if (handleTemplate != null)
            {
                //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes.
                handleTemplate.Set(((Interop.Secur32.SecurityBufferStruct*)outputBuffer.UnmanagedPointer)->token);
                if (handleTemplate.IsInvalid)
                {
                    handleTemplate.SetHandleAsInvalid();
                }
            }

            if (inContextPtr == null && (errorCode & 0x80000000) != 0)
            {
                // An error on the first call, need to set the out handle to invalid value.
                outContext._handle.SetToInvalid();
            }

            return errorCode;
        }
Esempio n. 28
0
        public unsafe static int AcquireCredentialsHandle(
            string package,
            Interop.SspiCli.CredentialUse intent,
            ref Interop.SspiCli.AuthIdentity authdata,
            out SafeFreeCredentials outCredential)
        {
            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Print("SafeFreeCredentials::AcquireCredentialsHandle#1("
                                + package + ", "
                                + intent + ", "
                                + authdata + ")");
            }

            int errorCode = -1;
            long timeStamp;

            outCredential = new SafeFreeCredential_SECURITY();

            errorCode = Interop.SspiCli.AcquireCredentialsHandleW(
                            null,
                            package,
                            (int)intent,
                            null,
                            ref authdata,
                            null,
                            null,
                            ref outCredential._handle,
                            out timeStamp);
#if TRACE_VERBOSE
            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Print("Unmanaged::AcquireCredentialsHandle() returns 0x"
                                + String.Format("{0:x}", errorCode)
                                + ", handle = " + outCredential.ToString());
            }
#endif

            if (errorCode != 0)
            {
                outCredential.SetHandleAsInvalid();
            }

            return errorCode;
        }
Esempio n. 29
0
 public static SecurityStatusPal AcceptSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteSslContext context,
                                                       byte[] inputBuffer, int offset, int count, ref byte[] outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
 {
     return(HandshakeInternal(credential, ref context, new ReadOnlySpan <byte>(inputBuffer, offset, count), ref outputBuffer, sslAuthenticationOptions));
 }
Esempio n. 30
0
        private bool AcquireClientCredentials(ref byte[] thumbPrint)
        {
            X509Certificate certificate = null;
            ArrayList       list        = new ArrayList();

            string[] acceptableIssuers = null;
            bool     flag = false;

            if (this.m_CertSelectionDelegate != null)
            {
                if (acceptableIssuers == null)
                {
                    acceptableIssuers = this.GetIssuers();
                }
                X509Certificate2 remoteCertificate = null;
                try
                {
                    X509Certificate2Collection certificates;
                    remoteCertificate = this.GetRemoteCertificate(out certificates);
                    certificate       = this.m_CertSelectionDelegate(this.m_HostName, this.ClientCertificates, remoteCertificate, acceptableIssuers);
                }
                finally
                {
                    if (remoteCertificate != null)
                    {
                        remoteCertificate.Reset();
                    }
                }
                if (certificate != null)
                {
                    if (this.m_CredentialsHandle == null)
                    {
                        flag = true;
                    }
                    list.Add(certificate);
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_got_certificate_from_delegate"));
                    }
                }
                else if (this.ClientCertificates.Count == 0)
                {
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_no_delegate_and_have_no_client_cert"));
                    }
                    flag = true;
                }
                else if (Logging.On)
                {
                    Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_no_delegate_but_have_client_cert"));
                }
            }
            else if (((this.m_CredentialsHandle == null) && (this.m_ClientCertificates != null)) && (this.m_ClientCertificates.Count > 0))
            {
                certificate = this.ClientCertificates[0];
                flag        = true;
                if (certificate != null)
                {
                    list.Add(certificate);
                }
                if (Logging.On)
                {
                    Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_attempting_restart_using_cert", new object[] { (certificate == null) ? "null" : certificate.ToString(true) }));
                }
            }
            else if ((this.m_ClientCertificates != null) && (this.m_ClientCertificates.Count > 0))
            {
                if (acceptableIssuers == null)
                {
                    acceptableIssuers = this.GetIssuers();
                }
                if (Logging.On)
                {
                    if ((acceptableIssuers == null) || (acceptableIssuers.Length == 0))
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_no_issuers_try_all_certs"));
                    }
                    else
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_server_issuers_look_for_matching_certs", new object[] { acceptableIssuers.Length }));
                    }
                }
                for (int j = 0; j < this.m_ClientCertificates.Count; j++)
                {
                    if ((acceptableIssuers != null) && (acceptableIssuers.Length != 0))
                    {
                        X509Certificate2 certificate3 = null;
                        X509Chain        chain        = null;
                        try
                        {
                            certificate3 = MakeEx(this.m_ClientCertificates[j]);
                            if (certificate3 == null)
                            {
                                continue;
                            }
                            chain = new X509Chain {
                                ChainPolicy = { RevocationMode = X509RevocationMode.NoCheck, VerificationFlags = X509VerificationFlags.IgnoreInvalidName }
                            };
                            chain.Build(certificate3);
                            bool flag2 = false;
                            if (chain.ChainElements.Count > 0)
                            {
                                for (int k = 0; k < chain.ChainElements.Count; k++)
                                {
                                    string issuer = chain.ChainElements[k].Certificate.Issuer;
                                    flag2 = Array.IndexOf <string>(acceptableIssuers, issuer) != -1;
                                    if (flag2)
                                    {
                                        break;
                                    }
                                }
                            }
                            if (!flag2)
                            {
                                continue;
                            }
                        }
                        finally
                        {
                            if (chain != null)
                            {
                                chain.Reset();
                            }
                            if ((certificate3 != null) && (certificate3 != this.m_ClientCertificates[j]))
                            {
                                certificate3.Reset();
                            }
                        }
                    }
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_selected_cert", new object[] { this.m_ClientCertificates[j].ToString(true) }));
                    }
                    list.Add(this.m_ClientCertificates[j]);
                }
            }
            X509Certificate2 certificate4 = null;

            certificate = null;
            if (Logging.On)
            {
                Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_n_certs_after_filtering", new object[] { list.Count }));
                if (list.Count != 0)
                {
                    Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_finding_matching_certs"));
                }
            }
            for (int i = 0; i < list.Count; i++)
            {
                certificate  = list[i] as X509Certificate;
                certificate4 = this.EnsurePrivateKey(certificate);
                if (certificate4 != null)
                {
                    break;
                }
                certificate  = null;
                certificate4 = null;
            }
            try
            {
                byte[] buffer = (certificate4 == null) ? null : certificate4.GetCertHash();
                SafeFreeCredentials credentials = SslSessionsCache.TryCachedCredential(buffer, this.m_ProtocolFlags, this.m_EncryptionPolicy);
                if ((flag && (credentials == null)) && (certificate4 != null))
                {
                    if (certificate != certificate4)
                    {
                        certificate4.Reset();
                    }
                    buffer       = null;
                    certificate4 = null;
                    certificate  = null;
                }
                if (credentials != null)
                {
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, SR.GetString("net_log_using_cached_credential"));
                    }
                    this.m_CredentialsHandle         = credentials;
                    this.m_SelectedClientCertificate = certificate;
                    return(true);
                }
                SecureCredential secureCredential = new SecureCredential(4, certificate4, SecureCredential.Flags.NoDefaultCred | SecureCredential.Flags.ValidateManual, this.m_ProtocolFlags, this.m_EncryptionPolicy);
                this.m_CredentialsHandle = this.AcquireCredentialsHandle(CredentialUse.Outbound, ref secureCredential);
                thumbPrint = buffer;
                this.m_SelectedClientCertificate = certificate;
            }
            finally
            {
                if ((certificate4 != null) && (certificate != certificate4))
                {
                    certificate4.Reset();
                }
            }
            return(false);
        }
Esempio n. 31
0
        public SafeDeleteContext(SafeFreeCredentials credential, bool isServer, bool remoteCertRequired)
            : base(IntPtr.Zero, true)
        {
            Debug.Assert((null != credential) && !credential.IsInvalid, "Invalid credential used in SafeDeleteContext");

            // When a credential handle is first associated with the context we keep credential
            // ref count bumped up to ensure ordered finalization. The certificate handle and
            // key handle are used in the SSL data structures and should survive the lifetime of
            // the SSL context
            bool gotCredRef = false;
            _credential = credential;
            _credential.DangerousAddRef(ref gotCredRef);

            try
            {
                _sslContext = Interop.OpenSsl.AllocateSslContext(
                    credential.Protocols,
                    credential.CertHandle,
                    credential.CertKeyHandle,
                    credential.Policy,
                    isServer,
                    remoteCertRequired);
            }
            catch(Exception ex)
            {
                if (gotCredRef)
                {
                    _credential.DangerousRelease();
                }
                Debug.Write("Exception Caught. - " + ex);
                throw;
            }
        }
Esempio n. 32
0
        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);

            bufferDesc[0] = new SecurityBuffer(buffer, SecurityBufferType.SECBUFFER_TOKEN);
            var errorCode = (Interop.SECURITY_STATUS)SSPIWrapper.ApplyControlToken(
                GlobalSSPI.SSPISecureChannel,
                ref securityContext,
                bufferDesc);

            return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(errorCode, attachException:true);
        }
        public unsafe static int AcquireDefaultCredential(
            string package,
            Interop.Secur32.CredentialUse intent,
            out SafeFreeCredentials outCredential)
        {
            GlobalLog.Print("SafeFreeCredentials::AcquireDefaultCredential("
                            + package + ", "
                            + intent + ")");

            int errorCode = -1;
            long timeStamp;

            outCredential = new SafeFreeCredential_SECURITY();

            errorCode = Interop.Secur32.AcquireCredentialsHandleW(
                            null,
                            package,
                            (int)intent,
                            null,
                            IntPtr.Zero,
                            null,
                            null,
                            ref outCredential._handle,
                            out timeStamp);

#if TRACE_VERBOSE
            GlobalLog.Print("Unmanaged::AcquireCredentialsHandle() returns 0x"
                            + errorCode.ToString("x")
                            + ", handle = " + outCredential.ToString());
#endif

            if (errorCode != 0)
            {
                outCredential.SetHandleAsInvalid();
            }

            return errorCode;
        }
Esempio n. 34
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 globalLogEnabled = GlobalLog.IsEnabled;

            if (creds == null && globalLogEnabled)
            {
                GlobalLog.Assert("CacheCredential|creds == null");
            }

            if (creds.IsInvalid)
            {
                if (globalLogEnabled)
                {
                    GlobalLog.Print("CacheCredential() Refused to cache an Invalid Handle = " + creds.ToString() + ", Current Cache Count = " + s_CachedCreds.Count);
                }
                return;
            }

            object key = new SslCredKey(thumbPrint, (int)sslProtocols, isServer, encryptionPolicy);

            SafeCredentialReference cached = s_CachedCreds[key] as SafeCredentialReference;

            if (cached == null || cached.IsClosed || cached.Target.IsInvalid)
            {
                lock (s_CachedCreds)
                {
                    cached = s_CachedCreds[key] as SafeCredentialReference;

                    if (cached == null || cached.IsClosed)
                    {
                        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 (globalLogEnabled)
                        {
                            GlobalLog.Print("CacheCredential() Caching New Handle = " + creds.ToString() + ", Current Cache Count = " + s_CachedCreds.Count);
                        }

                        //
                        // 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)
                        {
                            DictionaryEntry[] toRemoveAttempt = new DictionaryEntry[s_CachedCreds.Count];
                            s_CachedCreds.CopyTo(toRemoveAttempt, 0);

                            for (int i = 0; i < toRemoveAttempt.Length; ++i)
                            {
                                cached = toRemoveAttempt[i].Value as SafeCredentialReference;

                                if (cached != null)
                                {
                                    creds = cached.Target;
                                    cached.Dispose();

                                    if (!creds.IsClosed && !creds.IsInvalid && (cached = SafeCredentialReference.CreateReference(creds)) != null)
                                    {
                                        s_CachedCreds[toRemoveAttempt[i].Key] = cached;
                                    }
                                    else
                                    {
                                        s_CachedCreds.Remove(toRemoveAttempt[i].Key);
                                    }
                                }
                            }
                            if (globalLogEnabled)
                            {
                                GlobalLog.Print("Scavenged cache, New Cache Count = " + s_CachedCreds.Count);
                            }
                        }
                    }
                    else if (globalLogEnabled)
                    {
                        GlobalLog.Print("CacheCredential() (locked retry) Found already cached Handle = " + cached.Target.ToString());
                    }
                }
            }
            else if (globalLogEnabled)
            {
                GlobalLog.Print("CacheCredential() Ignoring incoming handle = " + creds.ToString() + " since found already cached Handle = " + cached.Target.ToString());
            }
        }
        public unsafe static int AcquireCredentialsHandle(
            string package,
            Interop.Secur32.CredentialUse intent,
            ref Interop.Secur32.SecureCredential authdata,
            out SafeFreeCredentials outCredential)
        {
            GlobalLog.Print("SafeFreeCredentials::AcquireCredentialsHandle#2("
                            + package + ", "
                            + intent + ", "
                            + authdata + ")");

            int errorCode = -1;
            long timeStamp;


            // If there is a certificate, wrap it into an array.
            // Not threadsafe.
            IntPtr copiedPtr = authdata.certContextArray;
            try
            {
                IntPtr certArrayPtr = new IntPtr(&copiedPtr);
                if (copiedPtr != IntPtr.Zero)
                {
                    authdata.certContextArray = certArrayPtr;
                }

                outCredential = new SafeFreeCredential_SECURITY();

                errorCode = Interop.Secur32.AcquireCredentialsHandleW(
                                null,
                                package,
                                (int)intent,
                                null,
                                ref authdata,
                                null,
                                null,
                                ref outCredential._handle,
                                out timeStamp);
            }
            finally
            {
                authdata.certContextArray = copiedPtr;
            }

#if TRACE_VERBOSE
            GlobalLog.Print("Unmanaged::AcquireCredentialsHandle() returns 0x"
                            + errorCode.ToString("x")
                            + ", handle = " + outCredential.ToString());
#endif

            if (errorCode != 0)
            {
                outCredential.SetHandleAsInvalid();
            }

            return errorCode;
        }
Esempio n. 36
0
        public unsafe static int AcquireDefaultCredential(
            string package,
            Interop.SspiCli.CredentialUse intent,
            out SafeFreeCredentials outCredential)
        {
            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, package, intent);

            int errorCode = -1;
            long timeStamp;

            outCredential = new SafeFreeCredential_SECURITY();

            errorCode = Interop.SspiCli.AcquireCredentialsHandleW(
                            null,
                            package,
                            (int)intent,
                            null,
                            IntPtr.Zero,
                            null,
                            null,
                            ref outCredential._handle,
                            out timeStamp);

#if TRACE_VERBOSE
            if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"{nameof(Interop.SspiCli.AcquireCredentialsHandleW)} returns 0x{errorCode:x}, handle = {outCredential}");
#endif

            if (errorCode != 0)
            {
                outCredential.SetHandleAsInvalid();
            }

            return errorCode;
        }
Esempio n. 37
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)
        {
            if (creds == null)
            {
                NetEventSource.Fail(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;
            }

            var key = new SslCredKey(thumbPrint, (int)sslProtocols, isServer, encryptionPolicy);

            SafeCredentialReference?cached;

            if (!s_cachedCreds.TryGetValue(key, out cached) || cached.IsClosed || cached.Target.IsInvalid)
            {
                lock (s_cachedCreds)
                {
                    if (!s_cachedCreds.TryGetValue(key, out cached) || cached.IsClosed)
                    {
                        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}");
                        }

                        //
                        // 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)
                            {
                                cached = toRemoveAttempt[i].Value;

                                if (cached != null)
                                {
                                    creds = cached.Target;
                                    cached.Dispose();

                                    if (!creds.IsClosed && !creds.IsInvalid && (cached = SafeCredentialReference.CreateReference(creds)) != null)
                                    {
                                        s_cachedCreds[toRemoveAttempt[i].Key] = cached;
                                    }
                                    else
                                    {
                                        s_cachedCreds.TryRemove(toRemoveAttempt[i].Key, out cached);
                                    }
                                }
                            }
                            if (NetEventSource.Log.IsEnabled())
                            {
                                NetEventSource.Info(null, $"Scavenged cache, New Cache Count = {s_cachedCreds.Count}");
                            }
                        }
                    }
                    else if (NetEventSource.Log.IsEnabled())
                    {
                        if (NetEventSource.Log.IsEnabled())
                        {
                            NetEventSource.Info(null, $"CacheCredential() (locked retry) Found already cached Handle = {cached.Target}");
                        }
                    }
                }
            }
            else if (NetEventSource.Log.IsEnabled())
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Info(null, $"CacheCredential() Ignoring incoming handle = {creds} since found already cached Handle = {cached.Target}");
                }
            }
        }
Esempio n. 38
0
        public unsafe static int AcquireCredentialsHandle(
            string package,
            Interop.SspiCli.CredentialUse intent,
            ref Interop.SspiCli.SCHANNEL_CRED authdata,
            out SafeFreeCredentials outCredential)
        {
            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, package, intent, authdata);

            int errorCode = -1;
            long timeStamp;


            // If there is a certificate, wrap it into an array.
            // Not threadsafe.
            IntPtr copiedPtr = authdata.paCred;
            try
            {
                IntPtr certArrayPtr = new IntPtr(&copiedPtr);
                if (copiedPtr != IntPtr.Zero)
                {
                    authdata.paCred = certArrayPtr;
                }

                outCredential = new SafeFreeCredential_SECURITY();

                errorCode = Interop.SspiCli.AcquireCredentialsHandleW(
                                null,
                                package,
                                (int)intent,
                                null,
                                ref authdata,
                                null,
                                null,
                                ref outCredential._handle,
                                out timeStamp);
            }
            finally
            {
                authdata.paCred = copiedPtr;
            }

#if TRACE_VERBOSE
            if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"{nameof(Interop.SspiCli.AcquireCredentialsHandleW)} returns 0x{errorCode:x}, handle = {outCredential}");
#endif

            if (errorCode != 0)
            {
                outCredential.SetHandleAsInvalid();
            }

            return errorCode;
        }
Esempio n. 39
0
 public static SecurityStatusPal InitializeSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer)
 {
     Debug.Assert(inputBuffers.Length == 2);
     Debug.Assert(inputBuffers[1].token == null);
     return(HandshakeInternal(credential, ref context, inputBuffers[0], outputBuffer, false, false));
 }
        //
        // The app is calling this method after starting an SSL handshake.
        //
        // ATTN: The thumbPrint must be from inspected and possbly cloned user Cert object or we get a security hole in SslCredKey ctor.
        //
        internal static void CacheCredential(SafeFreeCredentials creds, byte[] thumbPrint, SchProtocols allowedProtocols, EncryptionPolicy encryptionPolicy)
        {
            GlobalLog.Assert(creds != null, "CacheCredential|creds == null");
            if (creds.IsInvalid)
            {
                GlobalLog.Print("CacheCredential() Refused to cache an Invalid Handle = " + creds.ToString() + ", Current Cache Count = " + s_CachedCreds.Count);
                return;
            }

            object key = new SslCredKey(thumbPrint, allowedProtocols, encryptionPolicy);

            SafeCredentialReference cached = s_CachedCreds[key] as SafeCredentialReference;

            if (cached == null || cached.IsClosed || cached._Target.IsInvalid)
            {
                lock (s_CachedCreds)
                {
                    cached = s_CachedCreds[key] as SafeCredentialReference;

                    if (cached == null || cached.IsClosed)
                    {
                        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;
                        GlobalLog.Print("CacheCredential() Caching New Handle = " + creds.ToString() + ", Current Cache Count = " + s_CachedCreds.Count);

                        //
                        // 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.
                        //
                        //    Just to make clear we won't shrink cache in the case when NO new handles are coming to it.
                        //
                        if ((s_CachedCreds.Count % c_CheckExpiredModulo) == 0)
                        {
                            DictionaryEntry[] toRemoveAttempt = new DictionaryEntry[s_CachedCreds.Count];
                            s_CachedCreds.CopyTo(toRemoveAttempt, 0);

                            for (int i = 0; i < toRemoveAttempt.Length; ++i)
                            {
                                cached = toRemoveAttempt[i].Value as SafeCredentialReference;

                                if (cached != null)
                                {
                                    creds = cached._Target;
                                    cached.Close();

                                    if (!creds.IsClosed && !creds.IsInvalid && (cached = SafeCredentialReference.CreateReference(creds)) != null)
                                    {
                                        s_CachedCreds[toRemoveAttempt[i].Key] = cached;
                                    }
                                    else
                                    {
                                        s_CachedCreds.Remove(toRemoveAttempt[i].Key);
                                    }
                                }
                            }
                            GlobalLog.Print("Scavenged cache, New Cache Count = " + s_CachedCreds.Count);
                        }
                    }
                    else
                    {
                        GlobalLog.Print("CacheCredential() (locked retry) Found already cached Handle = " + cached._Target.ToString());
                    }
                }
            }
            else
            {
                GlobalLog.Print("CacheCredential() Ignoring incoming handle = " + creds.ToString() + " since found already cached Handle = " + cached._Target.ToString());
            }
        }
Esempio n. 41
0
 public static SecurityStatusPal ApplyShutdownToken(ref SafeFreeCredentials credentialsHandle, SafeDeleteContext securityContext)
 {
     // TODO (#12319): Not implemented.
     return(new SecurityStatusPal(SecurityStatusPalErrorCode.OK));
 }
Esempio n. 42
0
 public static SecurityStatusPal InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteSslContext context, string targetName,
                                                           ReadOnlySpan <byte> inputBuffer, ref byte[] outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
 {
     return(HandshakeInternal(credential, ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions));
 }
Esempio n. 43
0
 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));
 }
Esempio n. 44
0
 public static SecurityStatusPal AcceptSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context,
                                                       ArraySegment <byte> inputBuffer, ref byte[] outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
 {
     return(HandshakeInternal(credential, ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions));
 }
Esempio n. 45
0
        //-------------------------------------------------------------------
        internal unsafe static int AcceptSecurityContext(
            ref SafeFreeCredentials inCredentials,
            ref SafeDeleteContext refContext,
            Interop.SspiCli.ContextFlags inFlags,
            Interop.SspiCli.Endianness endianness,
            SecurityBuffer inSecBuffer,
            SecurityBuffer[] inSecBuffers,
            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)");
                }
            }
#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 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;

            Interop.SspiCli.CredHandle contextHandle = new Interop.SspiCli.CredHandle();
            if (refContext != null)
            {
                contextHandle = refContext._handle;
            }

            // 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];
                fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer)
                {
                    if (haveInSecurityBufferDescriptor)
                    {
                        // 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);
                                }
#if TRACE_VERBOSE
                                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)
                    {
                        // 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;

                        if (outSecBuffer.token == null || outSecBuffer.token.Length == 0)
                        {
                            outUnmanagedBuffer[0].pvBuffer = IntPtr.Zero;
                        }
                        else
                        {
                            outUnmanagedBuffer[0].pvBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset);
                        }

                        if (isSspiAllocated)
                        {
                            outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle();
                        }

                        if (refContext == null || refContext.IsInvalid)
                        {
                            refContext = new SafeDeleteContext_SECURITY();
                        }

                        errorCode = MustRunAcceptSecurityContext_SECURITY(
                                        ref inCredentials,
                                        contextHandle.IsZero ? null : &contextHandle,
                                        haveInSecurityBufferDescriptor ? &inSecurityBufferDescriptor : null,
                                        inFlags,
                                        endianness,
                                        refContext,
                                        ref outSecurityBufferDescriptor,
                                        ref outFlags,
                                        outFreeContextBuffer);

                        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;
                        }
                    }
                }
            }
            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();
                }
            }

            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, $"errorCode:0x{errorCode:x8}, refContext:{refContext}");
            return errorCode;
        }
Esempio n. 46
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 checkRevocation,
            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, checkRevocation);

            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}");
                }
            }
Esempio n. 47
0
        public SafeDeleteContext(SafeFreeCredentials credential, long options, bool isServer, bool remoteCertRequired)
            : base(IntPtr.Zero, true)
        {
            Debug.Assert((null != credential) && !credential.IsInvalid, "Invalid credential used in SafeDeleteContext");

            // When a credential handle is first associated with the context we keep credential
            // ref count bumped up to ensure ordered finalization. The certificate handle and
            // key handle are used in the SSL data structures and should survive the lifetime of
            // the SSL context
            bool ignore = false;
            _credential = credential;
            _credential.DangerousAddRef(ref ignore);

            try
            {
                _sslContext = Interop.OpenSsl.AllocateSslContext(
                    options,
                    credential.CertHandle,
                    credential.CertKeyHandle,
                    isServer,
                    remoteCertRequired);
            }
            finally
            {
                if (IsInvalid)
                {
                    _credential.DangerousRelease();
                }
            }
        }
Esempio n. 48
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,
                    incomingBlob,
                    out resultBlob,
                    out uint outputFlags);

                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 = done ?
                                                       (negoContext.IsNtlmUsed && resultBlob.Length > 0 ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.CompleteNeeded) :
                                                       SecurityStatusPalErrorCode.ContinueNeeded;

                return(new SecurityStatusPal(errorCode));
            }
            catch (Interop.NetSecurityNative.GssApiException gex)
            {
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Error(null, gex);
                }
                return(new SecurityStatusPal(GetErrorCode(gex), gex));
            }
            catch (Exception ex)
            {
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Error(null, ex);
                }
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex));
            }
        }
        //
        // After PInvoke call the method will fix the handleTemplate.handle with the returned value.
        // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavour or null can be passed if no handle is returned.
        //
        private static unsafe int MustRunAcceptSecurityContext_SECURITY(
            ref SafeFreeCredentials inCredentials,
            void *inContextPtr,
            Interop.Secur32.SecurityBufferDescriptor inputBuffer,
            Interop.Secur32.ContextFlags inFlags,
            Interop.Secur32.Endianness endianness,
            SafeDeleteContext outContext,
            Interop.Secur32.SecurityBufferDescriptor outputBuffer,
            ref Interop.Secur32.ContextFlags outFlags,
            SafeFreeContextBuffer handleTemplate)
        {
            int errorCode = (int)Interop.SecurityStatus.InvalidHandle;

            // Run the body of this method as a non-interruptible block.
            try
            {
                bool ignore = false;

                inCredentials.DangerousAddRef(ref ignore);
                outContext.DangerousAddRef(ref ignore);

                Interop.Secur32.SSPIHandle credentialHandle = inCredentials._handle;
                long timeStamp;

                errorCode = Interop.Secur32.AcceptSecurityContext(
                    ref credentialHandle,
                    inContextPtr,
                    inputBuffer,
                    inFlags,
                    endianness,
                    ref outContext._handle,
                    outputBuffer,
                    ref outFlags,
                    out timeStamp);
            }
            finally
            {
                //
                // When a credential handle is first associated with the context we keep credential
                // ref count bumped up to ensure ordered finalization.
                // If the credential handle has been changed we de-ref the old one and associate the
                //  context with the new cred handle but only if the call was successful.
                if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0)
                {
                    // Disassociate the previous credential handle.
                    if (outContext._EffectiveCredential != null)
                    {
                        outContext._EffectiveCredential.DangerousRelease();
                    }

                    outContext._EffectiveCredential = inCredentials;
                }
                else
                {
                    inCredentials.DangerousRelease();
                }

                outContext.DangerousRelease();
            }

            // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer.
            if (handleTemplate != null)
            {
                //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes.
                handleTemplate.Set(((Interop.Secur32.SecurityBufferStruct *)outputBuffer.UnmanagedPointer)->token);
                if (handleTemplate.IsInvalid)
                {
                    handleTemplate.SetHandleAsInvalid();
                }
            }

            if (inContextPtr == null && (errorCode & 0x80000000) != 0)
            {
                // An error on the first call, need to set the out handle to invalid value.
                outContext._handle.SetToInvalid();
            }

            return(errorCode);
        }
Esempio n. 50
0
        //
        // Acquire Server Side Certificate information and set it on the class.
        //
        private bool AcquireServerCredentials(ref byte[] thumbPrint)
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::AcquireServerCredentials");

            X509Certificate localCertificate = null;
            bool            cachedCred       = false;

            if (_certSelectionDelegate != null)
            {
                X509CertificateCollection tempCollection = new X509CertificateCollection();
                tempCollection.Add(_serverCertificate);
                localCertificate = _certSelectionDelegate(string.Empty, tempCollection, null, Array.Empty <string>());
                GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireServerCredentials() Use delegate selected Cert");
            }
            else
            {
                localCertificate = _serverCertificate;
            }

            if (localCertificate == null)
            {
                throw new NotSupportedException(SR.net_ssl_io_no_server_cert);
            }

            // 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.
            X509Certificate2 selectedCert = EnsurePrivateKey(localCertificate);

            if (selectedCert == null)
            {
                throw new NotSupportedException(SR.net_ssl_io_no_server_cert);
            }

            GlobalLog.Assert(localCertificate.Equals(selectedCert), "AcquireServerCredentials()|'selectedCert' does not match 'localCertificate'.");

            //
            // Note selectedCert is a safe ref possibly cloned from the user passed Cert object
            //
            byte[] guessedThumbPrint = selectedCert.GetCertHash();
            try
            {
                SafeFreeCredentials cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, _sslProtocols, _serverMode, _encryptionPolicy);

                if (cachedCredentialHandle != null)
                {
                    _credentialsHandle = cachedCredentialHandle;
                    _serverCertificate = localCertificate;
                    cachedCred         = true;
                }
                else
                {
                    _credentialsHandle = SslStreamPal.AcquireCredentialsHandle(selectedCert, _sslProtocols, _encryptionPolicy, _serverMode);
                    thumbPrint         = guessedThumbPrint;
                    _serverCertificate = localCertificate;
                }
            }
            finally
            {
                // An extra cert could have been created, dispose it now.
                if ((object)localCertificate != (object)selectedCert)
                {
                    selectedCert.Dispose();
                }
            }

            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::AcquireServerCredentials, cachedCreds = " + cachedCred.ToString(), Logging.ObjectToString(_credentialsHandle));
            return(cachedCred);
        }
        internal static SecurityStatusPal AcceptSecurityContext(
            SafeFreeCredentials credentialsHandle,
            ref SafeDeleteContext securityContext,
            ContextFlagsPal requestedContextFlags,
            SecurityBuffer[] inSecurityBufferArray,
            SecurityBuffer outSecurityBuffer,
            ref ContextFlagsPal contextFlags)
        {
            Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero;
            Interop.SecurityStatus winStatus = (Interop.SecurityStatus)SSPIWrapper.AcceptSecurityContext(
                GlobalSSPI.SSPIAuth,
                credentialsHandle,
                ref securityContext,
                ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags),
                Interop.SspiCli.Endianness.Network,
                inSecurityBufferArray,
                outSecurityBuffer,
                ref outContextFlags);

            contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags);
            return SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus);
        }
Esempio n. 52
0
        /*++
            AcquireCredentials - Attempts to find Client Credential
            Information, that can be sent to the server.  In our case,
            this is only Client Certificates, that we have Credential Info.

            How it works:
                case 0: Cert Selection delegate is present
                        Always use its result as the client cert answer.
                        Try to use cached credential handle whenever feasible.
                        Do not use cached anonymous creds if the delegate has returned null
                        and the collection is not empty (allow responding with the cert later).

                case 1: Certs collection is empty
                        Always use the same statically acquired anonymous SSL Credential

                case 2: Before our Connection with the Server
                        If we have a cached credential handle keyed by first X509Certificate
                        **content** in the passed collection, then we use that cached
                        credential and hoping to restart a session.

                        Otherwise create a new anonymous (allow responding with the cert later).

                case 3: After our Connection with the Server (i.e. during handshake or re-handshake)
                        The server has requested that we send it a Certificate then
                        we Enumerate a list of server sent Issuers trying to match against
                        our list of Certificates, the first match is sent to the server.

                        Once we got a cert we again try to match cached credential handle if possible.
                        This will not restart a session but helps minimizing the number of handles we create.

                In the case of an error getting a Certificate or checking its private Key we fall back
                to the behavior of having no certs, case 1.

            Returns: True if cached creds were used, false otherwise.

        --*/

        private bool AcquireClientCredentials(ref byte[] thumbPrint)
        {
            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Enter("SecureChannel#" + LoggingHash.HashString(this) + "::AcquireClientCredentials");
            }

            // 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.
            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.

            if (_certSelectionDelegate != null)
            {
                issuers = GetRequestCertificateAuthorities();

                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(this) + "::AcquireClientCredentials() calling CertificateSelectionCallback");
                }

                X509Certificate2 remoteCert = null;
                try
                {
                    X509Certificate2Collection dummyCollection;
                    remoteCert = CertificateValidationPal.GetRemoteCertificate(_securityContext, out dummyCollection);
                    clientCertificate = _certSelectionDelegate(_hostName, ClientCertificates, remoteCert, issuers);
                }
                finally
                {
                    if (remoteCert != null)
                    {
                        remoteCert.Dispose();
                    }
                }


                if (clientCertificate != null)
                {
                    if (_credentialsHandle == null)
                    {
                        sessionRestartAttempt = true;
                    }

                    filteredCerts.Add(clientCertificate);
                    if (SecurityEventSource.Log.IsEnabled())
                    {
                        SecurityEventSource.Log.CertificateFromDelegate(LoggingHash.HashInt(this));
                    }
                }
                else
                {
                    if (ClientCertificates.Count == 0)
                    {
                        if (SecurityEventSource.Log.IsEnabled())
                        {
                            SecurityEventSource.Log.NoDelegateNoClientCert(LoggingHash.HashInt(this));
                        }

                        sessionRestartAttempt = true;
                    }
                    else
                    {
                        if (SecurityEventSource.Log.IsEnabled())
                        {
                            SecurityEventSource.Log.NoDelegateButClientCert(LoggingHash.HashInt(this));
                        }
                    }
                }
            }
            else if (_credentialsHandle == null && _clientCertificates != null && _clientCertificates.Count > 0)
            {
                // This is where we attempt to restart a session by picking the FIRST cert from the collection.
                // Otherwise it is either server sending a client cert request or the session is renegotiated.
                clientCertificate = ClientCertificates[0];
                sessionRestartAttempt = true;
                if (clientCertificate != null)
                {
                    filteredCerts.Add(clientCertificate);
                }

                if (SecurityEventSource.Log.IsEnabled())
                {
                    SecurityEventSource.Log.AttemptingRestartUsingCert(clientCertificate == null ? "null" : clientCertificate.ToString(true), LoggingHash.HashInt(this));
                }
            }
            else if (_clientCertificates != null && _clientCertificates.Count > 0)
            {
                //
                // This should be a server request for the client cert sent over currently anonymous sessions.
                //
                issuers = GetRequestCertificateAuthorities();

                if (SecurityEventSource.Log.IsEnabled())
                {
                    if (issuers == null || issuers.Length == 0)
                    {
                        SecurityEventSource.Log.NoIssuersTryAllCerts(LoggingHash.HashInt(this));
                    }
                    else
                    {
                        SecurityEventSource.Log.LookForMatchingCerts(issuers.Length, LoggingHash.HashInt(this));
                    }
                }

                for (int i = 0; i < _clientCertificates.Count; ++i)
                {
                    //
                    // Make sure we add only if the cert matches one of the issuers.
                    // If no issuers were sent and then try all client certs starting with the first one.
                    //
                    if (issuers != null && issuers.Length != 0)
                    {
                        X509Certificate2 certificateEx = null;
                        X509Chain chain = null;
                        try
                        {
                            certificateEx = MakeEx(_clientCertificates[i]);
                            if (certificateEx == null)
                            {
                                continue;
                            }

                            if (GlobalLog.IsEnabled)
                            {
                                GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(this) + "::AcquireClientCredentials() root cert:" + certificateEx.Issuer);
                            }

                            chain = new X509Chain();

                            chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreInvalidName;
                            chain.Build(certificateEx);
                            bool found = false;

                            //
                            // We ignore any errors happened with chain.
                            //
                            if (chain.ChainElements.Count > 0)
                            {
                                for (int ii = 0; ii < chain.ChainElements.Count; ++ii)
                                {
                                    string issuer = chain.ChainElements[ii].Certificate.Issuer;
                                    found = Array.IndexOf(issuers, issuer) != -1;
                                    if (found)
                                    {
                                        if (GlobalLog.IsEnabled)
                                        {
                                            GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(this) + "::AcquireClientCredentials() matched:" + issuer);
                                        }
                                        break;
                                    }
                                    if (GlobalLog.IsEnabled)
                                    {
                                        GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(this) + "::AcquireClientCredentials() no match:" + issuer);
                                    }
                                }
                            }

                            if (!found)
                            {
                                continue;
                            }
                        }
                        finally
                        {
                            if (chain != null)
                            {
                                chain.Dispose();
                            }

                            if (certificateEx != null && (object)certificateEx != (object)_clientCertificates[i])
                            {
                                certificateEx.Dispose();
                            }
                        }
                    }

                    if (SecurityEventSource.Log.IsEnabled())
                    {
                        SecurityEventSource.Log.SelectedCert(_clientCertificates[i].ToString(true), LoggingHash.HashInt(this));
                    }

                    filteredCerts.Add(_clientCertificates[i]);
                }
            }

            bool cachedCred = false;                   // This is a return result from this method.
            X509Certificate2 selectedCert = null;      // This is a final selected cert (ensured that it does have private key with it).

            clientCertificate = null;

            if (SecurityEventSource.Log.IsEnabled())
            {
                SecurityEventSource.Log.CertsAfterFiltering(filteredCerts.Count, LoggingHash.HashInt(this));
                if (filteredCerts.Count != 0)
                {
                    SecurityEventSource.Log.FindingMatchingCerts(LoggingHash.HashInt(this));
                }
            }

            //
            // ATTN: When the client cert was returned by the user callback OR it was guessed AND it has no private key,
            //       THEN anonymous (no client cert) credential will be used.
            //
            // 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)
            {
                clientCertificate = filteredCerts[i];
                if ((selectedCert = EnsurePrivateKey(clientCertificate)) != null)
                {
                    break;
                }

                clientCertificate = null;
                selectedCert = null;
            }

            if ((object)clientCertificate != (object)selectedCert && !clientCertificate.Equals(selectedCert))
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("AcquireClientCredentials()|'selectedCert' does not match 'clientCertificate'.");
                }

                Debug.Fail("AcquireClientCredentials()|'selectedCert' does not match 'clientCertificate'.");
            }

            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(this) + "::AcquireClientCredentials() Selected Cert = " + (selectedCert == null ? "null" : selectedCert.Subject));
            }

            try
            {
                // Try to locate cached creds first.
                //
                // SECURITY: selectedCert ref if not null is a safe object that does not depend on possible **user** inherited X509Certificate type.
                //
                byte[] guessedThumbPrint = selectedCert == null ? null : selectedCert.GetCertHash();
                SafeFreeCredentials cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, _sslProtocols, _serverMode, _encryptionPolicy);

                // We can probably do some optimization here. If the selectedCert is returned by the delegate
                // we can always go ahead and use the certificate to create our credential
                // (instead of going anonymous as we do here).
                if (sessionRestartAttempt &&
                    cachedCredentialHandle == null &&
                    selectedCert != null &&
                    SslStreamPal.StartMutualAuthAsAnonymous)
                {
                    if (GlobalLog.IsEnabled)
                    {
                        GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(this) + "::AcquireClientCredentials() Reset to anonymous session.");
                    }

                    // IIS does not renegotiate a restarted session if client cert is needed.
                    // So we don't want to reuse **anonymous** cached credential for a new SSL connection if the client has passed some certificate.
                    // The following block happens if client did specify a certificate but no cached creds were found in the cache.
                    // Since we don't restart a session the server side can still challenge for a client cert.
                    if ((object)clientCertificate != (object)selectedCert)
                    {
                        selectedCert.Dispose();
                    }

                    guessedThumbPrint = null;
                    selectedCert = null;
                    clientCertificate = null;
                }

                if (cachedCredentialHandle != null)
                {
                    if (SecurityEventSource.Log.IsEnabled())
                    {
                        SecurityEventSource.Log.UsingCachedCredential(LoggingHash.HashInt(this));
                    }

                    _credentialsHandle = cachedCredentialHandle;
                    _selectedClientCertificate = clientCertificate;
                    cachedCred = true;
                }
                else
                {
                    _credentialsHandle = SslStreamPal.AcquireCredentialsHandle(selectedCert, _sslProtocols, _encryptionPolicy, _serverMode);

                    thumbPrint = guessedThumbPrint; // Delay until here in case something above threw.
                    _selectedClientCertificate = clientCertificate;
                }
            }
            finally
            {
                // An extra cert could have been created, dispose it now.
                if (selectedCert != null && (object)clientCertificate != (object)selectedCert)
                {
                    selectedCert.Dispose();
                }
            }

            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Leave("SecureChannel#" + LoggingHash.HashString(this) + "::AcquireClientCredentials, cachedCreds = " + cachedCred.ToString(), LoggingHash.ObjectToString(_credentialsHandle));
            }
            return cachedCred;
        }
        public unsafe static int AcquireCredentialsHandle(
            string package,
            Interop.Secur32.CredentialUse intent,
            ref SafeSspiAuthDataHandle authdata,
            out SafeFreeCredentials outCredential)
        {
            int errorCode = -1;
            long timeStamp;

            outCredential = new SafeFreeCredential_SECURITY();
            errorCode = Interop.Secur32.AcquireCredentialsHandleW(
                            null,
                            package,
                            (int)intent,
                            null,
                            authdata,
                            null,
                            null,
                            ref outCredential._handle,
                            out timeStamp);

            if (errorCode != 0)
            {
                outCredential.SetHandleAsInvalid();
            }

            return errorCode;
        }
Esempio n. 54
0
        //
        // Acquire Server Side Certificate information and set it on the class.
        //
        private bool AcquireServerCredentials(ref byte[] thumbPrint)
        {
            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Enter("SecureChannel#" + LoggingHash.HashString(this) + "::AcquireServerCredentials");
            }

            X509Certificate localCertificate = null;
            bool cachedCred = false;

            if (_certSelectionDelegate != null)
            {
                X509CertificateCollection tempCollection = new X509CertificateCollection();
                tempCollection.Add(_serverCertificate);
                localCertificate = _certSelectionDelegate(string.Empty, tempCollection, null, Array.Empty<string>());
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(this) + "::AcquireServerCredentials() Use delegate selected Cert");
                }
            }
            else
            {
                localCertificate = _serverCertificate;
            }

            if (localCertificate == null)
            {
                throw new NotSupportedException(SR.net_ssl_io_no_server_cert);
            }

            // 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.
            X509Certificate2 selectedCert = EnsurePrivateKey(localCertificate);

            if (selectedCert == null)
            {
                throw new NotSupportedException(SR.net_ssl_io_no_server_cert);
            }

            if (!localCertificate.Equals(selectedCert))
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("AcquireServerCredentials()|'selectedCert' does not match 'localCertificate'.");
                }

                Debug.Fail("AcquireServerCredentials()|'selectedCert' does not match 'localCertificate'.");
            }

            //
            // Note selectedCert is a safe ref possibly cloned from the user passed Cert object
            //
            byte[] guessedThumbPrint = selectedCert.GetCertHash();
            try
            {
                SafeFreeCredentials cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, _sslProtocols, _serverMode, _encryptionPolicy);

                if (cachedCredentialHandle != null)
                {
                    _credentialsHandle = cachedCredentialHandle;
                    _serverCertificate = localCertificate;
                    cachedCred = true;
                }
                else
                {
                    _credentialsHandle = SslStreamPal.AcquireCredentialsHandle(selectedCert, _sslProtocols, _encryptionPolicy, _serverMode);
                    thumbPrint = guessedThumbPrint;
                    _serverCertificate = localCertificate;
                }
            }
            finally
            {
                // An extra cert could have been created, dispose it now.
                if ((object)localCertificate != (object)selectedCert)
                {
                    selectedCert.Dispose();
                }
            }

            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Leave("SecureChannel#" + LoggingHash.HashString(this) + "::AcquireServerCredentials, cachedCreds = " + cachedCred.ToString(), LoggingHash.ObjectToString(_credentialsHandle));
            }
            return cachedCred;
        }
        //-------------------------------------------------------------------
        internal unsafe static int AcceptSecurityContext(
            ref SafeFreeCredentials inCredentials,
            ref SafeDeleteContext refContext,
            Interop.Secur32.ContextFlags inFlags,
            Interop.Secur32.Endianness endianness,
            SecurityBuffer inSecBuffer,
            SecurityBuffer[] inSecBuffers,
            SecurityBuffer outSecBuffer,
            ref Interop.Secur32.ContextFlags outFlags)
        {
#if TRACE_VERBOSE
            GlobalLog.Enter("SafeDeleteContext::AcceptSecurityContex");
            GlobalLog.Print("    credential       = " + inCredentials.ToString());
            GlobalLog.Print("    refContext       = " + Logging.ObjectToString(refContext));

            GlobalLog.Print("    inFlags          = " + inFlags);

            if (inSecBuffers == null)
            {
                GlobalLog.Print("    inSecBuffers     = (null)");
            }
            else
            {
                GlobalLog.Print("    inSecBuffers[]   = length:" + inSecBuffers.Length);
            }
#endif
            GlobalLog.Assert(outSecBuffer != null, "SafeDeleteContext::AcceptSecurityContext()|outSecBuffer != null");
            GlobalLog.Assert(inSecBuffer == null || inSecBuffers == null, "SafeDeleteContext::AcceptSecurityContext()|inSecBuffer == null || inSecBuffers == null");

            if (inCredentials == null)
            {
                throw new ArgumentNullException("inCredentials");
            }

            Interop.Secur32.SecurityBufferDescriptor inSecurityBufferDescriptor = null;
            if (inSecBuffer != null)
            {
                inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1);
            }
            else if (inSecBuffers != null)
            {
                inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length);
            }

            Interop.Secur32.SecurityBufferDescriptor outSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1);

            // Actually, this is returned in outFlags.
            bool isSspiAllocated = (inFlags & Interop.Secur32.ContextFlags.AllocateMemory) != 0 ? true : false;

            int errorCode = -1;

            Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle();
            if (refContext != null)
            {
                contextHandle = refContext._handle;
            }

            // 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.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor == null ? 1 : inSecurityBufferDescriptor.Count];
                fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer)
                {
                    if (inSecurityBufferDescriptor != null)
                    {
                        // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
                        inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr;
                        pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count];
                        SecurityBuffer securityBuffer;
                        for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index)
                        {
                            securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index];
                            if (securityBuffer != null)
                            {
                                // Copy the SecurityBuffer content into unmanaged place holder.
                                inUnmanagedBuffer[index].count = securityBuffer.size;
                                inUnmanagedBuffer[index].type = securityBuffer.type;

                                // Use the unmanaged token if it's not null; otherwise use the managed buffer.
                                if (securityBuffer.unmanagedToken != null)
                                {
                                    inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle();
                                }
                                else if (securityBuffer.token == null || securityBuffer.token.Length == 0)
                                {
                                    inUnmanagedBuffer[index].token = IntPtr.Zero;
                                }
                                else
                                {
                                    pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned);
                                    inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset);
                                }
#if TRACE_VERBOSE
                                GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type);
#endif
                            }
                        }
                    }

                    var outUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[1];
                    fixed (void* outUnmanagedBufferPtr = outUnmanagedBuffer)
                    {
                        // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
                        outSecurityBufferDescriptor.UnmanagedPointer = outUnmanagedBufferPtr;
                        // Copy the SecurityBuffer content into unmanaged place holder.
                        outUnmanagedBuffer[0].count = outSecBuffer.size;
                        outUnmanagedBuffer[0].type = outSecBuffer.type;

                        if (outSecBuffer.token == null || outSecBuffer.token.Length == 0)
                        {
                            outUnmanagedBuffer[0].token = IntPtr.Zero;
                        }
                        else
                        {
                            outUnmanagedBuffer[0].token = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset);
                        }

                        if (isSspiAllocated)
                        {
                            outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle();
                        }

                        if (refContext == null || refContext.IsInvalid)
                        {
                            refContext = new SafeDeleteContext_SECURITY();
                        }

                        errorCode = MustRunAcceptSecurityContext_SECURITY(
                                        ref inCredentials,
                                        contextHandle.IsZero ? null : &contextHandle,
                                        inSecurityBufferDescriptor,
                                        inFlags,
                                        endianness,
                                        refContext,
                                        outSecurityBufferDescriptor,
                                        ref outFlags,
                                        outFreeContextBuffer);

                        GlobalLog.Print("SafeDeleteContext:AcceptSecurityContext  Marshalling OUT buffer");
                        // Get unmanaged buffer with index 0 as the only one passed into PInvoke.
                        outSecBuffer.size = outUnmanagedBuffer[0].count;
                        outSecBuffer.type = outUnmanagedBuffer[0].type;
                        if (outSecBuffer.size > 0)
                        {
                            outSecBuffer.token = new byte[outSecBuffer.size];
                            Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size);
                        }
                        else
                        {
                            outSecBuffer.token = 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();
                }
            }

            GlobalLog.Leave("SafeDeleteContext::AcceptSecurityContex() unmanaged AcceptSecurityContex()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + Logging.ObjectToString(refContext));

            return errorCode;
        }
Esempio n. 56
0
        /*++
         *  AcquireCredentials - Attempts to find Client Credential
         *  Information, that can be sent to the server.  In our case,
         *  this is only Client Certificates, that we have Credential Info.
         *
         *  How it works:
         *      case 0: Cert Selection delegate is present
         *              Always use its result as the client cert answer.
         *              Try to use cached credential handle whenever feasible.
         *              Do not use cached anonymous creds if the delegate has returned null
         *              and the collection is not empty (allow responding with the cert later).
         *
         *      case 1: Certs collection is empty
         *              Always use the same statically acquired anonymous SSL Credential
         *
         *      case 2: Before our Connection with the Server
         *              If we have a cached credential handle keyed by first X509Certificate
         **content** in the passed collection, then we use that cached
         *              credential and hoping to restart a session.
         *
         *              Otherwise create a new anonymous (allow responding with the cert later).
         *
         *      case 3: After our Connection with the Server (i.e. during handshake or re-handshake)
         *              The server has requested that we send it a Certificate then
         *              we Enumerate a list of server sent Issuers trying to match against
         *              our list of Certificates, the first match is sent to the server.
         *
         *              Once we got a cert we again try to match cached credential handle if possible.
         *              This will not restart a session but helps minimizing the number of handles we create.
         *
         *      In the case of an error getting a Certificate or checking its private Key we fall back
         *      to the behavior of having no certs, case 1.
         *
         *  Returns: True if cached creds were used, false otherwise.
         *
         * --*/

        private bool AcquireClientCredentials(ref byte[] thumbPrint)
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials");

            // 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.
            ArrayList       filteredCerts     = new ArrayList(); // 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.

            if (_certSelectionDelegate != null)
            {
                issuers = GetRequestCertificateAuthorities();

                GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() calling CertificateSelectionCallback");

                X509Certificate2 remoteCert = null;
                try
                {
                    X509Certificate2Collection dummyCollection;
                    remoteCert        = CertificateValidationPal.GetRemoteCertificate(_securityContext, out dummyCollection);
                    clientCertificate = _certSelectionDelegate(_hostName, ClientCertificates, remoteCert, issuers);
                }
                finally
                {
                    if (remoteCert != null)
                    {
                        remoteCert.Dispose();
                    }
                }


                if (clientCertificate != null)
                {
                    if (_credentialsHandle == null)
                    {
                        sessionRestartAttempt = true;
                    }

                    filteredCerts.Add(clientCertificate);
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.net_log_got_certificate_from_delegate);
                    }
                }
                else
                {
                    if (ClientCertificates.Count == 0)
                    {
                        if (Logging.On)
                        {
                            Logging.PrintInfo(Logging.Web, this, SR.net_log_no_delegate_and_have_no_client_cert);
                        }

                        sessionRestartAttempt = true;
                    }
                    else
                    {
                        if (Logging.On)
                        {
                            Logging.PrintInfo(Logging.Web, this, SR.net_log_no_delegate_but_have_client_cert);
                        }
                    }
                }
            }
            else if (_credentialsHandle == null && _clientCertificates != null && _clientCertificates.Count > 0)
            {
                // This is where we attempt to restart a session by picking the FIRST cert from the collection.
                // Otherwise it is either server sending a client cert request or the session is renegotiated.
                clientCertificate     = ClientCertificates[0];
                sessionRestartAttempt = true;
                if (clientCertificate != null)
                {
                    filteredCerts.Add(clientCertificate);
                }

                if (Logging.On)
                {
                    Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_attempting_restart_using_cert, (clientCertificate == null ? "null" : clientCertificate.ToString(true))));
                }
            }
            else if (_clientCertificates != null && _clientCertificates.Count > 0)
            {
                //
                // This should be a server request for the client cert sent over currently anonymous sessions.
                //
                issuers = GetRequestCertificateAuthorities();

                if (Logging.On)
                {
                    if (issuers == null || issuers.Length == 0)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.net_log_no_issuers_try_all_certs);
                    }
                    else
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_server_issuers_look_for_matching_certs, issuers.Length));
                    }
                }

                for (int i = 0; i < _clientCertificates.Count; ++i)
                {
                    //
                    // Make sure we add only if the cert matches one of the issuers.
                    // If no issuers were sent and then try all client certs starting with the first one.
                    //
                    if (issuers != null && issuers.Length != 0)
                    {
                        X509Certificate2 certificateEx = null;
                        X509Chain        chain         = null;
                        try
                        {
                            certificateEx = MakeEx(_clientCertificates[i]);
                            if (certificateEx == null)
                            {
                                continue;
                            }

                            GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() root cert:" + certificateEx.Issuer);
                            chain = new X509Chain();

                            chain.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreInvalidName;
                            chain.Build(certificateEx);
                            bool found = false;

                            //
                            // We ignore any errors happened with chain.
                            //
                            if (chain.ChainElements.Count > 0)
                            {
                                for (int ii = 0; ii < chain.ChainElements.Count; ++ii)
                                {
                                    string issuer = chain.ChainElements[ii].Certificate.Issuer;
                                    found = Array.IndexOf(issuers, issuer) != -1;
                                    if (found)
                                    {
                                        GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() matched:" + issuer);
                                        break;
                                    }
                                    GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() no match:" + issuer);
                                }
                            }

                            if (!found)
                            {
                                continue;
                            }
                        }
                        finally
                        {
                            if (chain != null)
                            {
                                chain.Dispose();
                            }

                            if (certificateEx != null && (object)certificateEx != (object)_clientCertificates[i])
                            {
                                certificateEx.Dispose();
                            }
                        }
                    }

                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_selected_cert, _clientCertificates[i].ToString(true)));
                    }

                    filteredCerts.Add(_clientCertificates[i]);
                }
            }

            bool             cachedCred   = false;     // This is a return result from this method.
            X509Certificate2 selectedCert = null;      // This is a final selected cert (ensured that it does have private key with it).

            clientCertificate = null;

            if (Logging.On)
            {
                Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_n_certs_after_filtering, filteredCerts.Count));
                if (filteredCerts.Count != 0)
                {
                    Logging.PrintInfo(Logging.Web, this, SR.net_log_finding_matching_certs);
                }
            }

            //
            // ATTN: When the client cert was returned by the user callback OR it was guessed AND it has no private key,
            //       THEN anonymous (no client cert) credential will be used.
            //
            // 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)
            {
                clientCertificate = filteredCerts[i] as X509Certificate;
                if ((selectedCert = EnsurePrivateKey(clientCertificate)) != null)
                {
                    break;
                }

                clientCertificate = null;
                selectedCert      = null;
            }

            GlobalLog.Assert(((object)clientCertificate == (object)selectedCert) || clientCertificate.Equals(selectedCert), "AcquireClientCredentials()|'selectedCert' does not match 'clientCertificate'.");

            GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() Selected Cert = " + (selectedCert == null ? "null" : selectedCert.Subject));
            try
            {
                // Try to locate cached creds first.
                //
                // SECURITY: selectedCert ref if not null is a safe object that does not depend on possible **user** inherited X509Certificate type.
                //
                byte[] guessedThumbPrint = selectedCert == null ? null : selectedCert.GetCertHash();
                SafeFreeCredentials cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, _sslProtocols, _serverMode, _encryptionPolicy);

                // We can probably do some optimization here. If the selectedCert is returned by the delegate
                // we can always go ahead and use the certificate to create our credential
                // (instead of going anonymous as we do here).
                if (sessionRestartAttempt && cachedCredentialHandle == null && selectedCert != null)
                {
                    GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() Reset to anonymous session.");

                    // IIS does not renegotiate a restarted session if client cert is needed.
                    // So we don't want to reuse **anonymous** cached credential for a new SSL connection if the client has passed some certificate.
                    // The following block happens if client did specify a certificate but no cached creds were found in the cache.
                    // Since we don't restart a session the server side can still challenge for a client cert.
                    if ((object)clientCertificate != (object)selectedCert)
                    {
                        selectedCert.Dispose();
                    }

                    guessedThumbPrint = null;
                    selectedCert      = null;
                    clientCertificate = null;
                }

                if (cachedCredentialHandle != null)
                {
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, SR.net_log_using_cached_credential);
                    }

                    _credentialsHandle         = cachedCredentialHandle;
                    _selectedClientCertificate = clientCertificate;
                    cachedCred = true;
                }
                else
                {
                    _credentialsHandle = SslStreamPal.AcquireCredentialsHandle(selectedCert, _sslProtocols, _encryptionPolicy, _serverMode);

                    thumbPrint = guessedThumbPrint; // Delay until here in case something above threw.
                    _selectedClientCertificate = clientCertificate;
                }
            }
            finally
            {
                // An extra cert could have been created, dispose it now.
                if (selectedCert != null && (object)clientCertificate != (object)selectedCert)
                {
                    selectedCert.Dispose();
                }
            }

            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials, cachedCreds = " + cachedCred.ToString(), Logging.ObjectToString(_credentialsHandle));
            return(cachedCred);
        }
        //-------------------------------------------------------------------
        internal unsafe static int AcceptSecurityContext(
            ref SafeFreeCredentials inCredentials,
            ref SafeDeleteContext refContext,
            Interop.Secur32.ContextFlags inFlags,
            Interop.Secur32.Endianness endianness,
            SecurityBuffer inSecBuffer,
            SecurityBuffer[] inSecBuffers,
            SecurityBuffer outSecBuffer,
            ref Interop.Secur32.ContextFlags outFlags)
        {
#if TRACE_VERBOSE
            GlobalLog.Enter("SafeDeleteContext::AcceptSecurityContex");
            GlobalLog.Print("    credential       = " + inCredentials.ToString());
            GlobalLog.Print("    refContext       = " + Logging.ObjectToString(refContext));

            GlobalLog.Print("    inFlags          = " + inFlags);

            if (inSecBuffers == null)
            {
                GlobalLog.Print("    inSecBuffers     = (null)");
            }
            else
            {
                GlobalLog.Print("    inSecBuffers[]   = length:" + inSecBuffers.Length);
            }
#endif
            GlobalLog.Assert(outSecBuffer != null, "SafeDeleteContext::AcceptSecurityContext()|outSecBuffer != null");
            GlobalLog.Assert(inSecBuffer == null || inSecBuffers == null, "SafeDeleteContext::AcceptSecurityContext()|inSecBuffer == null || inSecBuffers == null");

            if (inCredentials == null)
            {
                throw new ArgumentNullException("inCredentials");
            }

            Interop.Secur32.SecurityBufferDescriptor inSecurityBufferDescriptor = null;
            if (inSecBuffer != null)
            {
                inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1);
            }
            else if (inSecBuffers != null)
            {
                inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length);
            }

            Interop.Secur32.SecurityBufferDescriptor outSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1);

            // Actually, this is returned in outFlags.
            bool isSspiAllocated = (inFlags & Interop.Secur32.ContextFlags.AllocateMemory) != 0 ? true : false;

            int errorCode = -1;

            Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle();
            if (refContext != null)
            {
                contextHandle = refContext._handle;
            }

            // 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.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor == null ? 1 : inSecurityBufferDescriptor.Count];
                fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer)
                {
                    if (inSecurityBufferDescriptor != null)
                    {
                        // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
                        inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr;
                        pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count];
                        SecurityBuffer securityBuffer;
                        for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index)
                        {
                            securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index];
                            if (securityBuffer != null)
                            {
                                // Copy the SecurityBuffer content into unmanaged place holder.
                                inUnmanagedBuffer[index].count = securityBuffer.size;
                                inUnmanagedBuffer[index].type  = securityBuffer.type;

                                // Use the unmanaged token if it's not null; otherwise use the managed buffer.
                                if (securityBuffer.unmanagedToken != null)
                                {
                                    inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle();
                                }
                                else if (securityBuffer.token == null || securityBuffer.token.Length == 0)
                                {
                                    inUnmanagedBuffer[index].token = IntPtr.Zero;
                                }
                                else
                                {
                                    pinnedInBytes[index]           = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned);
                                    inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset);
                                }
#if TRACE_VERBOSE
                                GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type);
#endif
                            }
                        }
                    }

                    var outUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[1];
                    fixed(void *outUnmanagedBufferPtr = outUnmanagedBuffer)
                    {
                        // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
                        outSecurityBufferDescriptor.UnmanagedPointer = outUnmanagedBufferPtr;
                        // Copy the SecurityBuffer content into unmanaged place holder.
                        outUnmanagedBuffer[0].count = outSecBuffer.size;
                        outUnmanagedBuffer[0].type  = outSecBuffer.type;

                        if (outSecBuffer.token == null || outSecBuffer.token.Length == 0)
                        {
                            outUnmanagedBuffer[0].token = IntPtr.Zero;
                        }
                        else
                        {
                            outUnmanagedBuffer[0].token = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset);
                        }

                        if (isSspiAllocated)
                        {
                            outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle();
                        }

                        if (refContext == null || refContext.IsInvalid)
                        {
                            refContext = new SafeDeleteContext_SECURITY();
                        }

                        errorCode = MustRunAcceptSecurityContext_SECURITY(
                            ref inCredentials,
                            contextHandle.IsZero ? null : &contextHandle,
                            inSecurityBufferDescriptor,
                            inFlags,
                            endianness,
                            refContext,
                            outSecurityBufferDescriptor,
                            ref outFlags,
                            outFreeContextBuffer);

                        GlobalLog.Print("SafeDeleteContext:AcceptSecurityContext  Marshalling OUT buffer");
                        // Get unmanaged buffer with index 0 as the only one passed into PInvoke.
                        outSecBuffer.size = outUnmanagedBuffer[0].count;
                        outSecBuffer.type = outUnmanagedBuffer[0].type;
                        if (outSecBuffer.size > 0)
                        {
                            outSecBuffer.token = new byte[outSecBuffer.size];
                            Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size);
                        }
                        else
                        {
                            outSecBuffer.token = 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();
                }
            }

            GlobalLog.Leave("SafeDeleteContext::AcceptSecurityContex() unmanaged AcceptSecurityContex()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + Logging.ObjectToString(refContext));

            return(errorCode);
        }
Esempio n. 58
0
 public static SecurityStatusPal AcceptSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context,
                                                       SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, bool remoteCertRequired)
 {
     return(HandshakeInternal(credential, ref context, inputBuffer, outputBuffer, true, remoteCertRequired));
 }
Esempio n. 59
0
        //
        // After PInvoke call the method will fix the handleTemplate.handle with the returned value.
        // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavor or null can be passed if no handle is returned.
        //
        private static unsafe int MustRunInitializeSecurityContext_SECURITY(
            ref SafeFreeCredentials inCredentials,
            void* inContextPtr,
            byte* targetName,
            Interop.SspiCli.ContextFlags inFlags,
            Interop.SspiCli.Endianness endianness,
            Interop.SspiCli.SecBufferDesc* inputBuffer,
            SafeDeleteContext outContext,
            ref Interop.SspiCli.SecBufferDesc outputBuffer,
            ref Interop.SspiCli.ContextFlags attributes,
            SafeFreeContextBuffer handleTemplate)
        {
            int errorCode = (int)Interop.SECURITY_STATUS.InvalidHandle;

            try
            {
                bool ignore = false;
                inCredentials.DangerousAddRef(ref ignore);
                outContext.DangerousAddRef(ref ignore);

                Interop.SspiCli.CredHandle credentialHandle = inCredentials._handle;

                long timeStamp;

                errorCode = Interop.SspiCli.InitializeSecurityContextW(
                                ref credentialHandle,
                                inContextPtr,
                                targetName,
                                inFlags,
                                0,
                                endianness,
                                inputBuffer,
                                0,
                                ref outContext._handle,
                                ref outputBuffer,
                                ref attributes,
                                out timeStamp);
            }
            finally
            {
                //
                // When a credential handle is first associated with the context we keep credential
                // ref count bumped up to ensure ordered finalization.
                // If the credential handle has been changed we de-ref the old one and associate the
                //  context with the new cred handle but only if the call was successful.
                if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0)
                {
                    // Disassociate the previous credential handle
                    if (outContext._EffectiveCredential != null)
                    {
                        outContext._EffectiveCredential.DangerousRelease();
                    }

                    outContext._EffectiveCredential = inCredentials;
                }
                else
                {
                    inCredentials.DangerousRelease();
                }

                outContext.DangerousRelease();
            }

            // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer.
            if (handleTemplate != null)
            {
                //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes
                handleTemplate.Set(((Interop.SspiCli.SecBuffer*)outputBuffer.pBuffers)->pvBuffer);
                if (handleTemplate.IsInvalid)
                {
                    handleTemplate.SetHandleAsInvalid();
                }
            }

            if (inContextPtr == null && (errorCode & 0x80000000) != 0)
            {
                // an error on the first call, need to set the out handle to invalid value
                outContext._handle.SetToInvalid();
            }

            return errorCode;
        }
Esempio n. 60
0
        /*++
            AcquireCredentials - Attempts to find Client Credential
            Information, that can be sent to the server.  In our case,
            this is only Client Certificates, that we have Credential Info.

            How it works:
                case 0: Cert Selection delegate is present
                        Always use its result as the client cert answer.
                        Try to use cached credential handle whenever feasible.
                        Do not use cached anonymous creds if the delegate has returned null
                        and the collection is not empty (allow responding with the cert later).

                case 1: Certs collection is empty
                        Always use the same statically acquired anonymous SSL Credential

                case 2: Before our Connection with the Server
                        If we have a cached credential handle keyed by first X509Certificate
                        **content** in the passed collection, then we use that cached
                        credential and hoping to restart a session.

                        Otherwise create a new anonymous (allow responding with the cert later).

                case 3: After our Connection with the Server (i.e. during handshake or re-handshake)
                        The server has requested that we send it a Certificate then
                        we Enumerate a list of server sent Issuers trying to match against
                        our list of Certificates, the first match is sent to the server.

                        Once we got a cert we again try to match cached credential handle if possible.
                        This will not restart a session but helps minimizing the number of handles we create.

                In the case of an error getting a Certificate or checking its private Key we fall back
                to the behavior of having no certs, case 1.

            Returns: True if cached creds were used, false otherwise.

        --*/

        private bool AcquireClientCredentials(ref byte[] thumbPrint)
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials");

            // 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.
            ArrayList filteredCerts = new ArrayList();  // 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.

            if (_certSelectionDelegate != null)
            {
                issuers = GetRequestCertificateAuthorities();

                GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() calling CertificateSelectionCallback");

                X509Certificate2 remoteCert = null;
                try
                {
                    X509Certificate2Collection dummyCollection;
                    remoteCert = GetRemoteCertificate(out dummyCollection);
                    clientCertificate = _certSelectionDelegate(_hostName, ClientCertificates, remoteCert, issuers);
                }
                finally
                {
                    if (remoteCert != null)
                    {
                        remoteCert.Dispose();
                    }
                }


                if (clientCertificate != null)
                {
                    if (_credentialsHandle == null)
                    {
                        sessionRestartAttempt = true;
                    }

                    filteredCerts.Add(clientCertificate);
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.net_log_got_certificate_from_delegate);
                    }
                }
                else
                {
                    if (ClientCertificates.Count == 0)
                    {
                        if (Logging.On)
                        {
                            Logging.PrintInfo(Logging.Web, this, SR.net_log_no_delegate_and_have_no_client_cert);
                        }

                        sessionRestartAttempt = true;
                    }
                    else
                    {
                        if (Logging.On)
                        {
                            Logging.PrintInfo(Logging.Web, this, SR.net_log_no_delegate_but_have_client_cert);
                        }
                    }
                }
            }
            else if (_credentialsHandle == null && _clientCertificates != null && _clientCertificates.Count > 0)
            {
                // This is where we attempt to restart a session by picking the FIRST cert from the collection.
                // Otherwise it is either server sending a client cert request or the session is renegotiated.
                clientCertificate = ClientCertificates[0];
                sessionRestartAttempt = true;
                if (clientCertificate != null)
                {
                    filteredCerts.Add(clientCertificate);
                }

                if (Logging.On)
                {
                    Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_attempting_restart_using_cert, (clientCertificate == null ? "null" : clientCertificate.ToString(true))));
                }
            }
            else if (_clientCertificates != null && _clientCertificates.Count > 0)
            {
                //
                // This should be a server request for the client cert sent over currently anonymous sessions.
                //
                issuers = GetRequestCertificateAuthorities();

                if (Logging.On)
                {
                    if (issuers == null || issuers.Length == 0)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.net_log_no_issuers_try_all_certs);
                    }
                    else
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_server_issuers_look_for_matching_certs, issuers.Length));
                    }
                }

                for (int i = 0; i < _clientCertificates.Count; ++i)
                {
                    //
                    // Make sure we add only if the cert matches one of the issuers.
                    // If no issuers were sent and then try all client certs starting with the first one.
                    //
                    if (issuers != null && issuers.Length != 0)
                    {
                        X509Certificate2 certificateEx = null;
                        X509Chain chain = null;
                        try
                        {
                            certificateEx = MakeEx(_clientCertificates[i]);
                            if (certificateEx == null)
                            {
                                continue;
                            }

                            GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() root cert:" + certificateEx.Issuer);
                            chain = new X509Chain();

                            chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreInvalidName;
                            chain.Build(certificateEx);
                            bool found = false;

                            //
                            // We ignore any errors happened with chain.
                            //
                            if (chain.ChainElements.Count > 0)
                            {
                                for (int ii = 0; ii < chain.ChainElements.Count; ++ii)
                                {
                                    string issuer = chain.ChainElements[ii].Certificate.Issuer;
                                    found = Array.IndexOf(issuers, issuer) != -1;
                                    if (found)
                                    {
                                        GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() matched:" + issuer);
                                        break;
                                    }
                                    GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() no match:" + issuer);
                                }
                            }

                            if (!found)
                            {
                                continue;
                            }
                        }
                        finally
                        {
                            if (chain != null)
                            {
                                chain.Dispose();
                            }

                            if (certificateEx != null && (object)certificateEx != (object)_clientCertificates[i])
                            {
                                certificateEx.Dispose();
                            }
                        }
                    }

                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_selected_cert, _clientCertificates[i].ToString(true)));
                    }

                    filteredCerts.Add(_clientCertificates[i]);
                }
            }

            bool cachedCred = false;                   // This is a return result from this method.
            X509Certificate2 selectedCert = null;      // This is a final selected cert (ensured that it does have private key with it).

            clientCertificate = null;

            if (Logging.On)
            {
                Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_n_certs_after_filtering, filteredCerts.Count));
                if (filteredCerts.Count != 0)
                {
                    Logging.PrintInfo(Logging.Web, this, SR.net_log_finding_matching_certs);
                }
            }

            //
            // ATTN: When the client cert was returned by the user callback OR it was guessed AND it has no private key,
            //       THEN anonymous (no client cert) credential will be used.
            //
            // 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)
            {
                clientCertificate = filteredCerts[i] as X509Certificate;
                if ((selectedCert = EnsurePrivateKey(clientCertificate)) != null)
                {
                    break;
                }

                clientCertificate = null;
                selectedCert = null;
            }

            GlobalLog.Assert(((object)clientCertificate == (object)selectedCert) || clientCertificate.Equals(selectedCert), "AcquireClientCredentials()|'selectedCert' does not match 'clientCertificate'.");

            GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() Selected Cert = " + (selectedCert == null ? "null" : selectedCert.Subject));
            try
            {
                // Try to locate cached creds first.
                //
                // SECURITY: selectedCert ref if not null is a safe object that does not depend on possible **user** inherited X509Certificate type.
                //
                byte[] guessedThumbPrint = selectedCert == null ? null : selectedCert.GetCertHash();
                SafeFreeCredentials cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, _protocolFlags, _encryptionPolicy);

                // We can probably do some optimization here. If the selectedCert is returned by the delegate
                // we can always go ahead and use the certificate to create our credential
                // (instead of going anonymous as we do here).
                if (sessionRestartAttempt && cachedCredentialHandle == null && selectedCert != null)
                {
                    GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() Reset to anonymous session.");

                    // IIS does not renegotiate a restarted session if client cert is needed.
                    // So we don't want to reuse **anonymous** cached credential for a new SSL connection if the client has passed some certificate.
                    // The following block happens if client did specify a certificate but no cached creds were found in the cache.
                    // Since we don't restart a session the server side can still challenge for a client cert.
                    if ((object)clientCertificate != (object)selectedCert)
                    {
                        selectedCert.Dispose();
                    }

                    guessedThumbPrint = null;
                    selectedCert = null;
                    clientCertificate = null;
                }

                if (cachedCredentialHandle != null)
                {
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, SR.net_log_using_cached_credential);
                    }

                    _credentialsHandle = cachedCredentialHandle;
                    _selectedClientCertificate = clientCertificate;
                    cachedCred = true;
                }
                else
                {
                    Interop.Secur32.SecureCredential.Flags flags = Interop.Secur32.SecureCredential.Flags.ValidateManual | Interop.Secur32.SecureCredential.Flags.NoDefaultCred;

                    // CoreFX: always opt-in SCH_USE_STRONG_CRYPTO except for SSL3.
                    if (((_protocolFlags & (Interop.SChannel.SP_PROT_TLS1_0 | Interop.SChannel.SP_PROT_TLS1_1 | Interop.SChannel.SP_PROT_TLS1_2)) != 0)
                         && (_encryptionPolicy != EncryptionPolicy.AllowNoEncryption) && (_encryptionPolicy != EncryptionPolicy.NoEncryption))
                    {
                        flags |= Interop.Secur32.SecureCredential.Flags.UseStrongCrypto;
                    }

                    Interop.Secur32.SecureCredential secureCredential = CreateSecureCredential(
                        Interop.Secur32.SecureCredential.CurrentVersion,
                        selectedCert,
                        flags,
                        _protocolFlags,
                        _encryptionPolicy);

                    _credentialsHandle = AcquireCredentialsHandle(Interop.Secur32.CredentialUse.Outbound, secureCredential);
                    thumbPrint = guessedThumbPrint; // Delay until here in case something above threw.
                    _selectedClientCertificate = clientCertificate;
                }
            }
            finally
            {
                // An extra cert could have been created, dispose it now.
                if (selectedCert != null && (object)clientCertificate != (object)selectedCert)
                {
                    selectedCert.Dispose();
                }
            }

            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials, cachedCreds = " + cachedCred.ToString(), Logging.ObjectToString(_credentialsHandle));
            return cachedCred;
        }