예제 #1
0
        private static X509Certificate2 GetRemoteCertificate(
            SafeDeleteContext securityContext, bool retrieveCollection, out X509Certificate2Collection remoteCertificateCollection)
        {
            remoteCertificateCollection = null;

            if (securityContext == null)
            {
                return(null);
            }

            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Enter(securityContext);
            }

            X509Certificate2    result        = null;
            SafeFreeCertContext remoteContext = null;

            try
            {
                remoteContext = SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CONTEXT(GlobalSSPI.SSPISecureChannel, securityContext);
                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    result = new X509Certificate2(remoteContext.DangerousGetHandle());
                }
            }
            finally
            {
                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    if (retrieveCollection)
                    {
                        remoteCertificateCollection = UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext);
                    }

                    remoteContext.Dispose();
                }
            }

            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Log.RemoteCertificate(result);
                NetEventSource.Exit(null, result, securityContext);
            }
            return(result);
        }
예제 #2
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.Native,
                inputBuffers,
                outputBuffer,
                ref unusedAttributes);

            return(GetSecurityStatusPalFromWin32Int(errorCode));
        }
예제 #3
0
 //
 // Security: we temporarily reset thread token to open the handle under process account.
 //
 private static SafeFreeCredentials AcquireCredentialsHandle(Interop.Secur32.CredentialUse credUsage, Interop.Secur32.SecureCredential secureCredential)
 {
     // First try without impersonation, if it fails, then try the process account.
     // I.E. We don't know which account the certificate context was created under.
     try
     {
         //
         // For app-compat we want to ensure the credential are accessed under >>process<< acount.
         //
         return(WindowsIdentity.RunImpersonated <SafeFreeCredentials>(SafeAccessTokenHandle.InvalidHandle, () => {
             return SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPISecureChannel, SecurityPackage, credUsage, secureCredential);
         }));
     }
     catch
     {
         return(SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPISecureChannel, SecurityPackage, credUsage, secureCredential));
     }
 }
        internal int MakeSignature(byte[] buffer, int offset, int count, ref byte[] output)
        {
            SecSizes sizes = this.Sizes;
            int      num   = count + sizes.MaxSignature;

            if ((output == null) || (output.Length < num))
            {
                output = new byte[num];
            }
            Buffer.BlockCopy(buffer, offset, output, sizes.MaxSignature, count);
            SecurityBuffer[] input = new SecurityBuffer[] { new SecurityBuffer(output, 0, sizes.MaxSignature, BufferType.Token), new SecurityBuffer(output, sizes.MaxSignature, count, BufferType.Data) };
            int error = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, this.m_SecurityContext, input, 0);

            if (error != 0)
            {
                throw new Win32Exception(error);
            }
            return(input[0].size + input[1].size);
        }
예제 #5
0
        private string GetClientSpecifiedSpn()
        {
            if ((IsValidContext && IsCompleted))
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("NTAuthentication: Trying to get the client SPN before handshaking is done!");
                }
                Debug.Fail("NTAuthentication: Trying to get the client SPN before handshaking is done!");
            }

            string spn = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, _securityContext,
                                                            Interop.SspiCli.ContextAttribute.ClientSpecifiedSpn) as string;

            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Print("NTAuthentication: The client specified SPN is [" + spn + "]");
            }
            return(spn);
        }
        //
        // Used only by client SSL code, never returns null.
        //
        internal static string[] GetRequestCertificateAuthorities(SafeDeleteContext securityContext)
        {
            Interop.SspiCli.SecPkgContext_IssuerListInfoEx issuerList = default;
            bool success = SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_ISSUER_LIST_EX(GlobalSSPI.SSPISecureChannel, securityContext, ref issuerList, out SafeHandle sspiHandle);

            string[] issuers = Array.Empty <string>();
            try
            {
                if (success && issuerList.cIssuers > 0)
                {
                    unsafe
                    {
                        issuers = new string[issuerList.cIssuers];
                        var elements = new Span <Interop.SspiCli.CERT_CHAIN_ELEMENT>((void *)sspiHandle.DangerousGetHandle(), issuers.Length);
                        for (int i = 0; i < elements.Length; ++i)
                        {
                            if (elements[i].cbSize <= 0)
                            {
                                NetEventSource.Fail(securityContext, $"Interop.SspiCli._CERT_CHAIN_ELEMENT size is not positive: {elements[i].cbSize}");
                            }
                            if (elements[i].cbSize > 0)
                            {
                                byte[] x = new Span <byte>((byte *)elements[i].pCertContext, checked ((int)elements[i].cbSize)).ToArray();
                                var    x500DistinguishedName = new X500DistinguishedName(x);
                                issuers[i] = x500DistinguishedName.Name;
                                if (NetEventSource.IsEnabled)
                                {
                                    NetEventSource.Info(securityContext, "IssuerListEx[{issuers[i]}]");
                                }
                            }
                        }
                    }
                }
            }
            finally
            {
                sspiHandle?.Dispose();
            }

            return(issuers);
        }
예제 #7
0
        //
        // Extracts a remote certificate upon request.
        //
        internal override X509Certificate2 GetRemoteCertificate(SafeDeleteContext securityContext, out X509Certificate2Collection remoteCertificateStore)
        {
            remoteCertificateStore = null;

            if (securityContext == null)
            {
                return(null);
            }

            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::RemoteCertificate{get;}");
            X509Certificate2    result        = null;
            SafeFreeCertContext remoteContext = null;

            try
            {
                int errorCode = SSPIWrapper.QueryContextRemoteCertificate(GlobalSSPI.SSPISecureChannel, securityContext, out remoteContext);
                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    result = new X509Certificate2(remoteContext.DangerousGetHandle());
                }
            }
            finally
            {
                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    remoteCertificateStore = UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext);

                    remoteContext.Dispose();
                }
            }

            if (Logging.On)
            {
                Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_remote_certificate, (result == null ? "null" : result.ToString(true))));
            }

            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::RemoteCertificate{get;}", (result == null ? "null" : result.Subject));

            return(result);
        }
        //
        // Extracts a remote certificate upon request.
        //
        internal static X509Certificate2 GetRemoteCertificate(SafeDeleteContext securityContext, out X509Certificate2Collection remoteCertificateStore)
        {
            remoteCertificateStore = null;

            if (securityContext == null)
            {
                return(null);
            }

            GlobalLog.Enter("CertificateValidationPal.Windows SecureChannel#" + Logging.HashString(securityContext) + "::GetRemoteCertificate()");
            X509Certificate2    result        = null;
            SafeFreeCertContext remoteContext = null;

            try
            {
                remoteContext = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, securityContext, Interop.Secur32.ContextAttribute.RemoteCertificate) as SafeFreeCertContext;
                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    result = new X509Certificate2(remoteContext.DangerousGetHandle());
                }
            }
            finally
            {
                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    remoteCertificateStore = UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext);

                    remoteContext.Dispose();
                }
            }

            if (Logging.On)
            {
                Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_remote_certificate, (result == null ? "null" : result.ToString(true))));
            }

            GlobalLog.Leave("CertificateValidationPal.Windows SecureChannel#" + Logging.HashString(securityContext) + "::GetRemoteCertificate()", (result == null ? "null" : result.Subject));

            return(result);
        }
예제 #9
0
        //
        // Extracts a remote certificate upon request.
        //
        internal static X509Certificate2 GetRemoteCertificate(SafeDeleteContext securityContext, out X509Certificate2Collection remoteCertificateCollection)
        {
            remoteCertificateCollection = null;

            if (securityContext == null)
            {
                return(null);
            }

            GlobalLog.Enter("CertificateValidationPal.Windows SecureChannel#" + LoggingHash.HashString(securityContext) + "::GetRemoteCertificate()");
            X509Certificate2    result        = null;
            SafeFreeCertContext remoteContext = null;

            try
            {
                remoteContext = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, securityContext, Interop.SspiCli.ContextAttribute.RemoteCertificate) as SafeFreeCertContext;
                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    result = new X509Certificate2(remoteContext.DangerousGetHandle());
                }
            }
            finally
            {
                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    remoteCertificateCollection = UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext);

                    remoteContext.Dispose();
                }
            }

            if (SecurityEventSource.Log.IsEnabled())
            {
                SecurityEventSource.Log.RemoteCertificate(result == null ? "null" : result.ToString(true));
            }

            GlobalLog.Leave("CertificateValidationPal.Windows SecureChannel#" + LoggingHash.HashString(securityContext) + "::GetRemoteCertificate()", (result == null ? "null" : result.Subject));

            return(result);
        }
        internal int VerifySignature(byte[] buffer, int offset, int count)
        {
            if ((offset < 0) || (offset > ((buffer == null) ? 0 : buffer.Length)))
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if ((count < 0) || (count > ((buffer == null) ? 0 : (buffer.Length - offset))))
            {
                throw new ArgumentOutOfRangeException("count");
            }
            SecurityBuffer[] input = new SecurityBuffer[] { new SecurityBuffer(buffer, offset, count, BufferType.Stream), new SecurityBuffer(0, BufferType.Data) };
            int error = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, this.m_SecurityContext, input, 0);

            if (error != 0)
            {
                throw new Win32Exception(error);
            }
            if (input[1].type != BufferType.Data)
            {
                throw new InternalException();
            }
            return(input[1].size);
        }
 private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags, System.Security.Authentication.ExtendedProtection.ChannelBinding channelBinding)
 {
     this.m_TokenSize             = SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPIAuth, package, true).MaxToken;
     this.m_IsServer              = isServer;
     this.m_Spn                   = spn;
     this.m_SecurityContext       = null;
     this.m_RequestedContextFlags = requestedContextFlags;
     this.m_Package               = package;
     this.m_ChannelBinding        = channelBinding;
     if (credential is SystemNetworkCredential)
     {
         this.m_CredentialsHandle = SSPIWrapper.AcquireDefaultCredential(GlobalSSPI.SSPIAuth, package, this.m_IsServer ? CredentialUse.Inbound : CredentialUse.Outbound);
         this.m_UniqueUserId      = "/S";
     }
     else
     {
         string       userName = credential.InternalGetUserName();
         string       domain   = credential.InternalGetDomain();
         AuthIdentity authdata = new AuthIdentity(userName, credential.InternalGetPassword(), ((package == "WDigest") && ((domain == null) || (domain.Length == 0))) ? null : domain);
         this.m_UniqueUserId      = domain + "/" + userName + "/U";
         this.m_CredentialsHandle = SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPIAuth, package, this.m_IsServer ? CredentialUse.Inbound : CredentialUse.Outbound, ref authdata);
     }
 }
        internal int Decrypt(byte[] payload, int offset, int count, out int newOffset, uint expectedSeqNumber)
        {
            int num;

            if ((offset < 0) || (offset > ((payload == null) ? 0 : payload.Length)))
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if ((count < 0) || (count > ((payload == null) ? 0 : (payload.Length - offset))))
            {
                throw new ArgumentOutOfRangeException("count");
            }
            if (this.IsNTLM)
            {
                return(this.DecryptNtlm(payload, offset, count, out newOffset, expectedSeqNumber));
            }
            SecurityBuffer[] input = new SecurityBuffer[] { new SecurityBuffer(payload, offset, count, BufferType.Stream), new SecurityBuffer(0, BufferType.Data) };
            if (this.IsConfidentialityFlag)
            {
                num = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, this.m_SecurityContext, input, expectedSeqNumber);
            }
            else
            {
                num = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, this.m_SecurityContext, input, expectedSeqNumber);
            }
            if (num != 0)
            {
                throw new Win32Exception(num);
            }
            if (input[1].type != BufferType.Data)
            {
                throw new InternalException();
            }
            newOffset = input[1].offset;
            return(input[1].size);
        }
예제 #13
0
        // This will return a client token when conducted authentication on server side.
        // This token can be used for impersonation. We use it to create a WindowsIdentity and hand it out to the server app.
        internal SecurityContextTokenHandle GetContextToken(out Interop.SecurityStatus status)
        {
            if (!(IsCompleted && IsValidContext))
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.AssertFormat("NTAuthentication#{0}::GetContextToken|Should be called only when completed with success, currently is not!", LoggingHash.HashString(this));
                }

                Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::GetContextToken |Should be called only when completed with success, currently is not!");
            }

            if (!IsServer)
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.AssertFormat("NTAuthentication#{0}::GetContextToken|The method must not be called by the client side!", LoggingHash.HashString(this));
                }

                Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::GetContextToken |The method must not be called by the client side!");
            }

            if (!IsValidContext)
            {
                throw new Win32Exception((int)Interop.SecurityStatus.InvalidHandle);
            }

            SecurityContextTokenHandle token = null;

            status = (Interop.SecurityStatus)SSPIWrapper.QuerySecurityContextToken(
                GlobalSSPI.SSPIAuth,
                _securityContext,
                out token);

            return(token);
        }
        internal int Encrypt(byte[] buffer, int offset, int count, ref byte[] output, uint sequenceNumber)
        {
            int      num3;
            SecSizes sizes = this.Sizes;

            try
            {
                int num = (0x7ffffffb - sizes.BlockSize) - sizes.SecurityTrailer;
                if ((count > num) || (count < 0))
                {
                    throw new ArgumentOutOfRangeException("count", SR.GetString("net_io_out_range", new object[] { num }));
                }
            }
            catch (Exception exception)
            {
                NclUtilities.IsFatal(exception);
                throw;
            }
            int size = (count + sizes.SecurityTrailer) + sizes.BlockSize;

            if ((output == null) || (output.Length < (size + 4)))
            {
                output = new byte[size + 4];
            }
            Buffer.BlockCopy(buffer, offset, output, 4 + sizes.SecurityTrailer, count);
            SecurityBuffer[] input = new SecurityBuffer[] { new SecurityBuffer(output, 4, sizes.SecurityTrailer, BufferType.Token), new SecurityBuffer(output, 4 + sizes.SecurityTrailer, count, BufferType.Data), new SecurityBuffer(output, (4 + sizes.SecurityTrailer) + count, sizes.BlockSize, BufferType.Padding) };
            if (this.IsConfidentialityFlag)
            {
                num3 = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPIAuth, this.m_SecurityContext, input, sequenceNumber);
            }
            else
            {
                if (this.IsNTLM)
                {
                    SecurityBuffer buffer1 = input[1];
                    buffer1.type |= BufferType.ReadOnlyFlag;
                }
                num3 = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, this.m_SecurityContext, input, 0);
            }
            if (num3 != 0)
            {
                throw new Win32Exception(num3);
            }
            size = input[0].size;
            bool flag = false;

            if (size != sizes.SecurityTrailer)
            {
                flag = true;
                Buffer.BlockCopy(output, input[1].offset, output, 4 + size, input[1].size);
            }
            size += input[1].size;
            if ((input[2].size != 0) && (flag || (size != (count + sizes.SecurityTrailer))))
            {
                Buffer.BlockCopy(output, input[2].offset, output, 4 + size, input[2].size);
            }
            size     += input[2].size;
            output[0] = (byte)(size & 0xff);
            output[1] = (byte)((size >> 8) & 0xff);
            output[2] = (byte)((size >> 0x10) & 0xff);
            output[3] = (byte)((size >> 0x18) & 0xff);
            return(size + 4);
        }
예제 #15
0
        //
        // Extracts a remote certificate upon request.
        //
        internal override X509Certificate2 GetRemoteCertificate(SafeDeleteContext securityContext, out X509Certificate2Collection remoteCertificateStore)
        {
            remoteCertificateStore = null;
            bool gotReference = false;

            if (securityContext == null)
            {
                return(null);
            }

            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::RemoteCertificate{get;}");
            X509Certificate2    result        = null;
            SafeFreeCertContext remoteContext = null;

            try
            {
                int errorCode = SSPIWrapper.QueryContextRemoteCertificate(GlobalSSPI.SSPISecureChannel, securityContext, out remoteContext);

                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    remoteContext.DangerousAddRef(ref gotReference);
                    result = new X509Certificate2(remoteContext.DangerousGetHandle());
                }

                remoteCertificateStore = new X509Certificate2Collection();

                using (SafeSharedX509StackHandle chainStack =
                           Interop.OpenSsl.GetPeerCertificateChain(securityContext.SslContext))
                {
                    if (!chainStack.IsInvalid)
                    {
                        int count = Interop.Crypto.GetX509StackFieldCount(chainStack);

                        for (int i = 0; i < count; i++)
                        {
                            IntPtr certPtr = Interop.Crypto.GetX509StackField(chainStack, i);

                            if (certPtr != IntPtr.Zero)
                            {
                                // X509Certificate2(IntPtr) calls X509_dup, so the reference is appropriately tracked.
                                X509Certificate2 chainCert = new X509Certificate2(certPtr);
                                remoteCertificateStore.Add(chainCert);
                            }
                        }
                    }
                }
            }
            finally
            {
                if (gotReference)
                {
                    remoteContext.DangerousRelease();
                }

                if (remoteContext != null)
                {
                    remoteContext.Dispose();
                }
            }

            if (Logging.On)
            {
                Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_remote_certificate, (result == null ? "null" : result.ToString(true))));
            }

            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::RemoteCertificate{get;}", (result == null ? "null" : result.Subject));

            return(result);
        }
예제 #16
0
        internal int Encrypt(byte[] buffer, int offset, int count, ref byte[] output, uint sequenceNumber)
        {
            SecSizes sizes = Sizes;

            try
            {
                int maxCount = checked (Int32.MaxValue - 4 - sizes.BlockSize - sizes.SecurityTrailer);

                if (count > maxCount || count < 0)
                {
                    throw new ArgumentOutOfRangeException("count", SR.Format(SR.net_io_out_range, maxCount));
                }
            }
            catch (Exception e)
            {
                if (!ExceptionCheck.IsFatal(e) && GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(this) + "::Encrypt", "Arguments out of range.");
                }

                throw;
            }

            int resultSize = count + sizes.SecurityTrailer + sizes.BlockSize;

            if (output == null || output.Length < resultSize + 4)
            {
                output = new byte[resultSize + 4];
            }

            // Make a copy of user data for in-place encryption.
            Buffer.BlockCopy(buffer, offset, output, 4 + sizes.SecurityTrailer, count);

            // Prepare buffers TOKEN(signature), DATA and Padding.
            var securityBuffer = new SecurityBuffer[3];

            securityBuffer[0] = new SecurityBuffer(output, 4, sizes.SecurityTrailer, SecurityBufferType.Token);
            securityBuffer[1] = new SecurityBuffer(output, 4 + sizes.SecurityTrailer, count, SecurityBufferType.Data);
            securityBuffer[2] = new SecurityBuffer(output, 4 + sizes.SecurityTrailer + count, sizes.BlockSize, SecurityBufferType.Padding);

            int errorCode;

            if (IsConfidentialityFlag)
            {
                errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPIAuth, _securityContext, securityBuffer, sequenceNumber);
            }
            else
            {
                if (IsNTLM)
                {
                    securityBuffer[1].type |= SecurityBufferType.ReadOnlyFlag;
                }

                errorCode = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, _securityContext, securityBuffer, 0);
            }

            if (errorCode != 0)
            {
                GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::Encrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo));
                throw new Win32Exception(errorCode);
            }

            // Compacting the result.
            resultSize = securityBuffer[0].size;
            bool forceCopy = false;

            if (resultSize != sizes.SecurityTrailer)
            {
                forceCopy = true;
                Buffer.BlockCopy(output, securityBuffer[1].offset, output, 4 + resultSize, securityBuffer[1].size);
            }

            resultSize += securityBuffer[1].size;
            if (securityBuffer[2].size != 0 && (forceCopy || resultSize != (count + sizes.SecurityTrailer)))
            {
                Buffer.BlockCopy(output, securityBuffer[2].offset, output, 4 + resultSize, securityBuffer[2].size);
            }

            resultSize += securityBuffer[2].size;

            unchecked
            {
                output[0] = (byte)((resultSize) & 0xFF);
                output[1] = (byte)(((resultSize) >> 8) & 0xFF);
                output[2] = (byte)(((resultSize) >> 16) & 0xFF);
                output[3] = (byte)(((resultSize) >> 24) & 0xFF);
            }

            return(resultSize + 4);
        }
예제 #17
0
        // Accepts an incoming binary security blob and returns an outgoing binary security blob.
        internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out Interop.SecurityStatus statusCode)
        {
            GlobalLog.Enter("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", ((incomingBlob == null) ? "0" : incomingBlob.Length.ToString(NumberFormatInfo.InvariantInfo)) + " bytes");

            var list = new List <SecurityBuffer>(2);

            if (incomingBlob != null)
            {
                list.Add(new SecurityBuffer(incomingBlob, SecurityBufferType.Token));
            }

            if (_channelBinding != null)
            {
                list.Add(new SecurityBuffer(_channelBinding));
            }

            SecurityBuffer[] inSecurityBufferArray = null;
            if (list.Count > 0)
            {
                inSecurityBufferArray = list.ToArray();
            }

            var outSecurityBuffer = new SecurityBuffer(_tokenSize, SecurityBufferType.Token);

            bool firstTime = _securityContext == null;

            try
            {
                if (!_isServer)
                {
                    // client session
                    statusCode = (Interop.SecurityStatus)SSPIWrapper.InitializeSecurityContext(
                        GlobalSSPI.SSPIAuth,
                        _credentialsHandle,
                        ref _securityContext,
                        _spn,
                        _requestedContextFlags,
                        Interop.SspiCli.Endianness.Network,
                        inSecurityBufferArray,
                        outSecurityBuffer,
                        ref _contextFlags);

                    GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");

                    if (statusCode == Interop.SecurityStatus.CompleteNeeded)
                    {
                        var inSecurityBuffers = new SecurityBuffer[1];
                        inSecurityBuffers[0] = outSecurityBuffer;

                        statusCode = (Interop.SecurityStatus)SSPIWrapper.CompleteAuthToken(
                            GlobalSSPI.SSPIAuth,
                            ref _securityContext,
                            inSecurityBuffers);

                        GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.CompleteAuthToken() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
                        outSecurityBuffer.token = null;
                    }
                }
                else
                {
                    // Server session.
                    statusCode = (Interop.SecurityStatus)SSPIWrapper.AcceptSecurityContext(
                        GlobalSSPI.SSPIAuth,
                        _credentialsHandle,
                        ref _securityContext,
                        _requestedContextFlags,
                        Interop.SspiCli.Endianness.Network,
                        inSecurityBufferArray,
                        outSecurityBuffer,
                        ref _contextFlags);

                    GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.AcceptSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
                }
            }
            finally
            {
                //
                // Assuming the ISC or ASC has referenced the credential on the first successful call,
                // we want to decrement the effective ref count by "disposing" it.
                // The real dispose will happen when the security context is closed.
                // Note if the first call was not successful the handle is physically destroyed here.
                //
                if (firstTime && _credentialsHandle != null)
                {
                    _credentialsHandle.Dispose();
                }
            }


            if (((int)statusCode & unchecked ((int)0x80000000)) != 0)
            {
                CloseContext();
                _isCompleted = true;
                if (throwOnError)
                {
                    var exception = new Win32Exception((int)statusCode);
                    GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "Win32Exception:" + exception);
                    throw exception;
                }

                GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "null statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
                return(null);
            }
            else if (firstTime && _credentialsHandle != null)
            {
                // Cache until it is pushed out by newly incoming handles.
                SSPIHandleCache.CacheCredential(_credentialsHandle);
            }

            // The return value from SSPI will tell us correctly if the
            // handshake is over or not: http://msdn.microsoft.com/library/psdk/secspi/sspiref_67p0.htm
            // we also have to consider the case in which SSPI formed a new context, in this case we're done as well.
            if (statusCode == Interop.SecurityStatus.OK)
            {
                // Success.
                if ((statusCode == Interop.SecurityStatus.OK) && GlobalLog.IsEnabled)
                {
                    GlobalLog.AssertFormat("NTAuthentication#{0}::GetOutgoingBlob()|statusCode:[0x{1:x8}] ({2}) m_SecurityContext#{3}::Handle:[{4}] [STATUS != OK]", LoggingHash.HashString(this), (int)statusCode, statusCode, LoggingHash.HashString(_securityContext), LoggingHash.ObjectToString(_securityContext));
                }

                _isCompleted = true;
            }
            else
            {
                // We need to continue.
                GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() need continue statusCode:[0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + "] (" + statusCode.ToString() + ") m_SecurityContext#" + LoggingHash.HashString(_securityContext) + "::Handle:" + LoggingHash.ObjectToString(_securityContext) + "]");
            }

            GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "IsCompleted:" + IsCompleted.ToString());
            return(outSecurityBuffer.token);
        }
예제 #18
0
        private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, Interop.SspiCli.ContextFlags requestedContextFlags, ChannelBinding channelBinding)
        {
            GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::.ctor() package:" + LoggingHash.ObjectToString(package) + " spn:" + LoggingHash.ObjectToString(spn) + " flags :" + requestedContextFlags.ToString());
            _tokenSize             = SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPIAuth, package, true).MaxToken;
            _isServer              = isServer;
            _spn                   = spn;
            _securityContext       = null;
            _requestedContextFlags = requestedContextFlags;
            _package               = package;
            _channelBinding        = channelBinding;

            GlobalLog.Print("Peer SPN-> '" + _spn + "'");

            //
            // Check if we're using DefaultCredentials.
            //

            Debug.Assert(CredentialCache.DefaultCredentials == CredentialCache.DefaultNetworkCredentials);
            if (credential == CredentialCache.DefaultCredentials)
            {
                GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::.ctor(): using DefaultCredentials");
                _credentialsHandle = SSPIWrapper.AcquireDefaultCredential(
                    GlobalSSPI.SSPIAuth,
                    package,
                    (_isServer ? Interop.SspiCli.CredentialUse.Inbound : Interop.SspiCli.CredentialUse.Outbound));
            }
            else
            {
                unsafe
                {
                    SafeSspiAuthDataHandle authData = null;
                    try
                    {
                        Interop.SecurityStatus result = Interop.SspiCli.SspiEncodeStringsAsAuthIdentity(
                            credential.UserName, credential.Domain,
                            credential.Password, out authData);

                        if (result != Interop.SecurityStatus.OK)
                        {
                            if (NetEventSource.Log.IsEnabled())
                            {
                                NetEventSource.PrintError(
                                    NetEventSource.ComponentType.Security,
                                    SR.Format(
                                        SR.net_log_operation_failed_with_error,
                                        "SspiEncodeStringsAsAuthIdentity()",
                                        String.Format(CultureInfo.CurrentCulture, "0x{0:X}", (int)result)));
                            }

                            throw new Win32Exception((int)result);
                        }

                        _credentialsHandle = SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPIAuth,
                                                                                  package, (_isServer ? Interop.SspiCli.CredentialUse.Inbound : Interop.SspiCli.CredentialUse.Outbound), ref authData);
                    }
                    finally
                    {
                        if (authData != null)
                        {
                            authData.Dispose();
                        }
                    }
                }
            }
        }
        internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatus statusCode)
        {
            List <SecurityBuffer> list = new List <SecurityBuffer>(2);

            if (incomingBlob != null)
            {
                list.Add(new SecurityBuffer(incomingBlob, BufferType.Token));
            }
            if (this.m_ChannelBinding != null)
            {
                list.Add(new SecurityBuffer(this.m_ChannelBinding));
            }
            SecurityBuffer[] inputBuffers = null;
            if (list.Count > 0)
            {
                inputBuffers = list.ToArray();
            }
            SecurityBuffer outputBuffer = new SecurityBuffer(this.m_TokenSize, BufferType.Token);
            bool           flag         = this.m_SecurityContext == null;

            try
            {
                if (!this.m_IsServer)
                {
                    statusCode = (SecurityStatus)SSPIWrapper.InitializeSecurityContext(GlobalSSPI.SSPIAuth, this.m_CredentialsHandle, ref this.m_SecurityContext, this.m_Spn, this.m_RequestedContextFlags, Endianness.Network, inputBuffers, outputBuffer, ref this.m_ContextFlags);
                    if (statusCode == SecurityStatus.CompleteNeeded)
                    {
                        SecurityBuffer[] bufferArray2 = new SecurityBuffer[] { outputBuffer };
                        statusCode         = (SecurityStatus)SSPIWrapper.CompleteAuthToken(GlobalSSPI.SSPIAuth, ref this.m_SecurityContext, bufferArray2);
                        outputBuffer.token = null;
                    }
                }
                else
                {
                    statusCode = (SecurityStatus)SSPIWrapper.AcceptSecurityContext(GlobalSSPI.SSPIAuth, this.m_CredentialsHandle, ref this.m_SecurityContext, this.m_RequestedContextFlags, Endianness.Network, inputBuffers, outputBuffer, ref this.m_ContextFlags);
                }
            }
            finally
            {
                if (flag && (this.m_CredentialsHandle != null))
                {
                    this.m_CredentialsHandle.Close();
                }
            }
            if ((statusCode & ((SecurityStatus)(-2147483648))) != SecurityStatus.OK)
            {
                this.CloseContext();
                this.m_IsCompleted = true;
                if (throwOnError)
                {
                    Win32Exception exception = new Win32Exception((int)statusCode);
                    throw exception;
                }
                return(null);
            }
            if (flag && (this.m_CredentialsHandle != null))
            {
                SSPIHandleCache.CacheCredential(this.m_CredentialsHandle);
            }
            if (statusCode == SecurityStatus.OK)
            {
                this.m_IsCompleted = true;
            }
            return(outputBuffer.token);
        }
        //
        // Extracts a remote certificate upon request.
        //

        private static X509Certificate2?GetRemoteCertificate(
            SafeDeleteContext?securityContext,
            bool retrieveChainCertificates,
            ref X509Chain?chain,
            X509ChainPolicy?chainPolicy)
        {
            if (securityContext == null)
            {
                return(null);
            }

            X509Certificate2?   result        = null;
            SafeFreeCertContext?remoteContext = null;

            try
            {
                // SECPKG_ATTR_REMOTE_CERT_CONTEXT will not succeed before TLS handshake completes. Inside the handshake,
                // we need to use (more expensive) SECPKG_ATTR_REMOTE_CERT_CHAIN. That one may be unsupported on older
                // versions of windows. In that case, we have no option than to return null.
                //
                // We can use retrieveCollection to distinguish between in-handshake and after-handshake calls, because
                // the collection is retrieved for cert validation purposes after the handshake completes.
                if (retrieveChainCertificates) // handshake completed
                {
                    SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CONTEXT(GlobalSSPI.SSPISecureChannel, securityContext, out remoteContext);
                }
                else // in handshake
                {
                    SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CHAIN(GlobalSSPI.SSPISecureChannel, securityContext, out remoteContext);
                }

                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    result = new X509Certificate2(remoteContext.DangerousGetHandle());
                }
            }
            finally
            {
                if (remoteContext != null)
                {
                    if (!remoteContext.IsInvalid)
                    {
                        if (retrieveChainCertificates)
                        {
                            chain ??= new X509Chain();
                            if (chainPolicy != null)
                            {
                                chain.ChainPolicy = chainPolicy;
                            }

                            UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext, chain.ChainPolicy.ExtraStore);
                        }
                    }

                    remoteContext.Dispose();
                }
            }

            if (NetEventSource.Log.IsEnabled())
            {
                NetEventSource.Log.RemoteCertificate(result);
            }
            return(result);
        }
 public unsafe static SafeFreeContextBufferChannelBinding QueryContextChannelBinding(SafeDeleteContext securityContext, ChannelBindingKind attribute)
 {
     return(SSPIWrapper.QueryContextChannelBinding(GlobalSSPI.SSPISecureChannel, securityContext, (Interop.SspiCli.ContextAttribute)attribute));
 }
        //
        // NTAuth::GetOutgoingBlob()
        // Created:   12-01-1999: L.M.
        // Description:
        // Accepts an incoming binary security blob  and returns
        // an outgoing binary security blob
        //
        private byte[] GetOutgoingBlob(byte[] incomingBlob, out bool handshakeComplete)
        {
            GlobalLog.Enter("NTAuthentication::GetOutgoingBlob", ((incomingBlob == null) ? "0" : incomingBlob.Length.ToString()) + " bytes");

            // default to true in case of failure
            handshakeComplete = true;

            if (m_SecurityContext.Handle != -1 && incomingBlob == null)
            {
                // we tried auth previously, now we got a null blob, we're done. this happens
                // with Kerberos & valid credentials on the domain but no ACLs on the resource
                // the handle for m_SecurityContext will be collected at GC time.
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() null blob AND m_SecurityContext#" + ValidationHelper.HashString(m_SecurityContext) + "::Handle:[0x" + m_SecurityContext.Handle.ToString("x8") + "]");
                m_SecurityContext.Close();
                IsCompleted = true;
                return(null);
            }

            int requestedFlags =
                (int)ContextFlags.Delegate |
                (int)ContextFlags.MutualAuth |
                (int)ContextFlags.ReplayDetect |
                (int)ContextFlags.SequenceDetect |
                (int)ContextFlags.Confidentiality |
                (int)ContextFlags.Connection;

            SecurityBufferClass inSecurityBuffer = null;

            if (incomingBlob != null)
            {
                GlobalLog.Print("in blob = ");
                GlobalLog.Dump(incomingBlob);
                inSecurityBuffer = new SecurityBufferClass(incomingBlob, BufferType.Token);
            }

            SecurityBufferClass outSecurityBuffer = new SecurityBufferClass(m_TokenSize, BufferType.Token);

            int status;

#if SERVER_SIDE_SSPI
            if (m_SecureSessionType == SecureSessionType.ClientSession)
            {
#endif
            //
            // client session
            //
            requestedFlags |= (int)ContextFlags.ClientIntegrity;

            status = SSPIWrapper.InitializeSecurityContext(
                GlobalSSPI.SSPIAuth,
                m_CredentialsHandle.Handle,
                m_SecurityContext.Handle,
                m_RemotePeerId,
                requestedFlags,
                m_Endianness,
                inSecurityBuffer,
                ref m_SecurityContext.Handle,
                outSecurityBuffer,
                ref m_ContextFlags,
                ref m_SecurityContext.TimeStamp
                );

            GlobalLog.Print("SSPIWrapper.InitializeSecurityContext() returns 0x" + string.Format("{0:x}", status));
#if SERVER_SIDE_SSPI
        }

        else
        {
            //
            // server session
            //
            requestedFlags |= (int)ContextFlags.ServerIntegrity;

            status = SSPIWrapper.AcceptSecurityContext(
                GlobalSSPI.SSPIAuth,
                m_CredentialsHandle.Handle,
                m_SecurityContext.Handle,
                requestedFlags,
                m_Endianness,
                inSecurityBuffer,
                ref m_SecurityContext.Handle,
                outSecurityBuffer,
                out m_ContextFlags,
                out m_SecurityContext.TimeStamp
                );

            GlobalLog.Print("SSPIWrapper.AcceptSecurityContext() returns 0x" + string.Format("{0:x}", status));
        }
#endif // SERVER_SIDE_SSPI

            int errorCode = status & unchecked ((int)0x80000000);
            if (errorCode != 0)
            {
                throw new Win32Exception(status);
            }

            //
            // the return value from SSPI will tell us correctly if the
            // handshake is over or not: http://msdn.microsoft.com/library/psdk/secspi/sspiref_67p0.htm
            // we also have to consider the case in which SSPI formed a new context, in this case we're done as well.
            //
            if (status != (int)SecurityStatus.OK && m_SecurityContext.Handle != -1)
            {
                // we need to continue
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() need continue status:[0x" + status.ToString("x8") + "] m_SecurityContext#" + ValidationHelper.HashString(m_SecurityContext) + "::Handle:[0x" + m_SecurityContext.Handle.ToString("x8") + "]");
                handshakeComplete = false;
            }
            else
            {
                // we're done, cleanup
                GlobalLog.Assert(status == (int)SecurityStatus.OK, "NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() status:[0x" + status.ToString("x8") + "] m_SecurityContext#" + ValidationHelper.HashString(m_SecurityContext) + "::Handle:[0x" + m_SecurityContext.Handle.ToString("x8") + "]", "[STATUS != OK]");
                m_SecurityContext.Close();
                IsCompleted = true;
            }

#if TRAVE
            if (handshakeComplete)
            {
                //
                // Kevin Damour says:
                // You should not query the securitycontext until you have actually formed one (
                // with a success return form ISC).  It is only a partially formed context and
                // no info is available to user applications (at least for digest).
                //
                SecurityPackageInfoClass securityPackageInfo = (SecurityPackageInfoClass)SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, m_SecurityContext, ContextAttribute.PackageInfo);
                GlobalLog.Print("SecurityPackageInfoClass: using:[" + ((securityPackageInfo == null)?"null":securityPackageInfo.ToString()) + "]");
            }
#endif // #if TRAVE

            GlobalLog.Print("out token = " + m_TokenSize.ToString());
            GlobalLog.Dump(outSecurityBuffer.token);

            GlobalLog.Leave("NTAuthentication::GetOutgoingBlob", "handshakeComplete:" + handshakeComplete.ToString());

            return(outSecurityBuffer.token);
        }
        internal string GetOutgoingDigestBlob(string incomingBlob, string requestMethod, string requestedUri, string realm, bool isClientPreAuth, bool throwOnError, out SecurityStatus statusCode)
        {
            SecurityBuffer[] inputBuffers = null;
            SecurityBuffer   outputBuffer = new SecurityBuffer(this.m_TokenSize, isClientPreAuth ? BufferType.Parameters : BufferType.Token);
            bool             flag         = this.m_SecurityContext == null;

            try
            {
                if (!this.m_IsServer)
                {
                    if (!isClientPreAuth)
                    {
                        if (incomingBlob != null)
                        {
                            List <SecurityBuffer> list = new List <SecurityBuffer>(5)
                            {
                                new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(incomingBlob), 2),
                                new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestMethod), 3),
                                new SecurityBuffer(null, 3),
                                new SecurityBuffer(Encoding.Unicode.GetBytes(this.m_Spn), 0x10)
                            };
                            if (this.m_ChannelBinding != null)
                            {
                                list.Add(new SecurityBuffer(this.m_ChannelBinding));
                            }
                            inputBuffers = list.ToArray();
                        }
                        statusCode = (SecurityStatus)SSPIWrapper.InitializeSecurityContext(GlobalSSPI.SSPIAuth, this.m_CredentialsHandle, ref this.m_SecurityContext, requestedUri, this.m_RequestedContextFlags, Endianness.Network, inputBuffers, outputBuffer, ref this.m_ContextFlags);
                    }
                    else
                    {
                        statusCode = SecurityStatus.OK;
                    }
                }
                else
                {
                    List <SecurityBuffer> list2 = new List <SecurityBuffer>(6)
                    {
                        (incomingBlob == null) ? new SecurityBuffer(0, BufferType.Token) : new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(incomingBlob), BufferType.Token),
                        (requestMethod == null) ? new SecurityBuffer(0, BufferType.Parameters) : new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters),
                        (requestedUri == null) ? new SecurityBuffer(0, BufferType.Parameters) : new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestedUri), BufferType.Parameters),
                        new SecurityBuffer(0, BufferType.Parameters),
                        (realm == null) ? new SecurityBuffer(0, BufferType.Parameters) : new SecurityBuffer(Encoding.Unicode.GetBytes(realm), BufferType.Parameters)
                    };
                    if (this.m_ChannelBinding != null)
                    {
                        list2.Add(new SecurityBuffer(this.m_ChannelBinding));
                    }
                    inputBuffers = list2.ToArray();
                    statusCode   = (SecurityStatus)SSPIWrapper.AcceptSecurityContext(GlobalSSPI.SSPIAuth, this.m_CredentialsHandle, ref this.m_SecurityContext, this.m_RequestedContextFlags, Endianness.Network, inputBuffers, outputBuffer, ref this.m_ContextFlags);
                    if (statusCode == SecurityStatus.CompleteNeeded)
                    {
                        inputBuffers[4]    = outputBuffer;
                        statusCode         = (SecurityStatus)SSPIWrapper.CompleteAuthToken(GlobalSSPI.SSPIAuth, ref this.m_SecurityContext, inputBuffers);
                        outputBuffer.token = null;
                    }
                }
            }
            finally
            {
                if (flag && (this.m_CredentialsHandle != null))
                {
                    this.m_CredentialsHandle.Close();
                }
            }
            if ((statusCode & ((SecurityStatus)(-2147483648))) != SecurityStatus.OK)
            {
                this.CloseContext();
                if (throwOnError)
                {
                    Win32Exception exception = new Win32Exception((int)statusCode);
                    throw exception;
                }
                return(null);
            }
            if (flag && (this.m_CredentialsHandle != null))
            {
                SSPIHandleCache.CacheCredential(this.m_CredentialsHandle);
            }
            if (statusCode == SecurityStatus.OK)
            {
                this.m_IsCompleted = true;
            }
            byte[] token = outputBuffer.token;
            string str   = null;

            if ((token != null) && (token.Length > 0))
            {
                str = WebHeaderCollection.HeaderEncoding.GetString(token, 0, outputBuffer.size);
            }
            return(str);
        }
        //
        // NTAuthentication::NTAuthentication()
        // Created:   12-01-1999: L.M.
        // Parameters:
        //     package - security package to use (kerberos/ntlm/negotiate)
        //     networkCredential - credentials we're using for authentication
        //     remotePeerId - for a server session:
        //                       ignored (except when delegating, in which case this has the same rules as the client session.)
        //                    for a client session:
        //                        for kerberos: specifies the expected account under which the server
        //                                 is supposed to be running (KDC).  If the server runs under a
        //                                 different account an exception is thrown during the blob
        //                                 exchange. (this allows mutual authentication.)
        //                                 One can specify a fully qualified account name (domain\userName)
        //                                 or just a username, in which case the domain is assumed
        //                                 to be the same as the client.
        //                    for ntlm: ignored
        //
        // Description: Initializes SSPI
        //
        public NTAuthentication(string package, NetworkCredential networkCredential, string remotePeerId, DelegationFix delegationFix)
        {
            GlobalLog.Print("NTAuthentication::.ctor() package:" + package);

#if SERVER_SIDE_SSPI
            m_SecureSessionType = SecureSessionType.ClientSession;
#endif
            m_RemotePeerId    = remotePeerId; // only needed for Kerberos, it's the KDC
            m_Endianness      = Endianness.Network;
            m_SecurityContext = new SecurityContext(GlobalSSPI.SSPIAuth);

            bool found = false;

            GlobalLog.Print("NTAuthentication::.ctor() searching for name: " + package);

            if (m_SupportedSecurityPackages != null)
            {
                for (int i = 0; i < m_SupportedSecurityPackages.Length; i++)
                {
                    GlobalLog.Print("NTAuthentication::.ctor() supported name: " + m_SupportedSecurityPackages[i].Name);
                    if (string.Compare(m_SupportedSecurityPackages[i].Name, package, true, CultureInfo.InvariantCulture) == 0)
                    {
                        GlobalLog.Print("NTAuthentication::.ctor(): found SecurityPackage(" + package + ")");
                        m_TokenSize    = m_SupportedSecurityPackages[i].MaxToken;
                        m_Capabilities = m_SupportedSecurityPackages[i].Capabilities;
                        found          = true;
                        break;
                    }
                }
            }
            if (!found)
            {
                GlobalLog.Print("NTAuthentication::.ctor(): initialization failed: SecurityPackage(" + package + ") NOT FOUND");
                throw new WebException(SR.GetString(SR.net_securitypackagesupport), WebExceptionStatus.SecureChannelFailure);
            }

            //
            //  In order to prevent a race condition where one request could
            //  steal a connection from another request, before a handshake is
            //  complete, we create a new Group for each authentication request.
            //

            if (package == NtlmClient.AuthType || package == NegotiateClient.AuthType)
            {
                m_UniqueUserId = (Interlocked.Increment(ref s_UniqueGroupId)).ToString();
            }

            //
            // check if we're using DefaultCredentials
            //
            if (networkCredential is SystemNetworkCredential)
            {
                //
                // we're using DefaultCredentials
                //
                GlobalLog.Print("NTAuthentication::.ctor(): using DefaultCredentials");

                m_UniqueUserId += "/S"; // save off for unique connection marking

                // DELEGATION:
                // The fix is implemented in cooperation with HttpWebRequest class
                // Remove from both places and change the constructor of NTAuthentication class
                // once the Common Language Runtime will start propagating the Thread token with their stack
                // compression stuff.
                //

                GlobalLog.Assert(delegationFix != null, "DelegationFix ==NULL -> request Credentials has been changed after the request submission!", "");

                if (delegationFix != null)
                {
                    delegationFix.SetToken();
                }
                GlobalLog.Print("DELEGATION for peer-> '" + m_RemotePeerId + "', SetToken = " + delegationFix.Token.ToString());
                try {
                    m_CredentialsHandle =
                        SSPIWrapper.AcquireCredentialsHandle(
                            GlobalSSPI.SSPIAuth,
                            package,
                            CredentialUse.Outgoing);
                }
                finally {
                    if (delegationFix != null)
                    {
                        delegationFix.RevertToken();
                    }
                    GlobalLog.Print("DELEGATION for peer-> '" + m_RemotePeerId + "', UNSetToken = " + delegationFix.Token.ToString());
                }

                return;
            }

            //
            // we're not using DefaultCredentials, we need a
            // AuthIdentity struct to contain credentials
            // SECREVIEW:
            // we'll save username/domain in temp strings, to avoid decrypting multiple times.
            // password is only used once
            //
            string username = networkCredential.UserName;
            string domain   = networkCredential.Domain;

            m_UniqueUserId += domain + "/" + username + "/U"; // save off for unique connection marking
            AuthIdentity authIdentity = new AuthIdentity(username, networkCredential.Password, domain);

            GlobalLog.Print("NTAuthentication::.ctor(): using authIdentity:" + authIdentity.ToString());

            m_CredentialsHandle = SSPIWrapper.AcquireCredentialsHandle(
                GlobalSSPI.SSPIAuth,
                package,
                CredentialUse.Outgoing,
                authIdentity
                );
        }
예제 #25
0
        internal int Decrypt(byte[] payload, int offset, int count, out int newOffset, uint expectedSeqNumber)
        {
            if (offset < 0 || offset > (payload == null ? 0 : payload.Length))
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(this) + "::Decrypt", "Argument 'offset' out of range.");
                }

                Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::Decrypt", "Argument 'offset' out of range.");

                throw new ArgumentOutOfRangeException(nameof(offset));
            }

            if (count < 0 || count > (payload == null ? 0 : payload.Length - offset))
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Assert("NTAuthentication#" + LoggingHash.HashString(this) + "::Decrypt", "Argument 'count' out of range.");
                }

                Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::Decrypt", "Argument 'count' out of range.");

                throw new ArgumentOutOfRangeException(nameof(count));
            }

            if (IsNTLM)
            {
                return(DecryptNtlm(payload, offset, count, out newOffset, expectedSeqNumber));
            }

            //
            // Kerberos and up
            //
            var securityBuffer = new SecurityBuffer[2];

            securityBuffer[0] = new SecurityBuffer(payload, offset, count, SecurityBufferType.Stream);
            securityBuffer[1] = new SecurityBuffer(0, SecurityBufferType.Data);

            int errorCode;

            if (IsConfidentialityFlag)
            {
                errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, _securityContext, securityBuffer, expectedSeqNumber);
            }
            else
            {
                errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, _securityContext, securityBuffer, expectedSeqNumber);
            }

            if (errorCode != 0)
            {
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::Decrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo));
                }
                throw new Win32Exception(errorCode);
            }

            if (securityBuffer[1].type != SecurityBufferType.Data)
            {
                throw new InternalException();
            }

            newOffset = securityBuffer[1].offset;
            return(securityBuffer[1].size);
        }
예제 #26
0
        //
        // Used only by client SSL code, never returns null.
        //
        internal static string[] GetRequestCertificateAuthorities(SafeDeleteContext securityContext)
        {
            Interop.SspiCli.IssuerListInfoEx issuerList =
                (Interop.SspiCli.IssuerListInfoEx)SSPIWrapper.QueryContextAttributes(
                    GlobalSSPI.SSPISecureChannel,
                    securityContext,
                    Interop.SspiCli.ContextAttribute.IssuerListInfoEx);

            string[] issuers = Array.Empty <string>();

            try
            {
                if (issuerList.cIssuers > 0)
                {
                    unsafe
                    {
                        uint count = issuerList.cIssuers;
                        issuers = new string[issuerList.cIssuers];
                        Interop.SspiCli._CERT_CHAIN_ELEMENT *pIL = (Interop.SspiCli._CERT_CHAIN_ELEMENT *)issuerList.aIssuers.DangerousGetHandle();
                        for (int i = 0; i < count; ++i)
                        {
                            Interop.SspiCli._CERT_CHAIN_ELEMENT *pIL2 = pIL + i;
                            if (pIL2->cbSize <= 0)
                            {
                                if (GlobalLog.IsEnabled)
                                {
                                    GlobalLog.Assert("SecureChannel::GetIssuers()", "Interop.SspiCli._CERT_CHAIN_ELEMENT size is not positive: " + pIL2->cbSize.ToString());
                                }

                                Debug.Fail("SecureChannel::GetIssuers()", "Interop.SspiCli._CERT_CHAIN_ELEMENT size is not positive: " + pIL2->cbSize.ToString());
                            }

                            if (pIL2->cbSize > 0)
                            {
                                uint   size = pIL2->cbSize;
                                byte * ptr  = (byte *)(pIL2->pCertContext);
                                byte[] x    = new byte[size];
                                for (int j = 0; j < size; j++)
                                {
                                    x[j] = *(ptr + j);
                                }

                                X500DistinguishedName x500DistinguishedName = new X500DistinguishedName(x);
                                issuers[i] = x500DistinguishedName.Name;
                                if (GlobalLog.IsEnabled)
                                {
                                    GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(securityContext) + "::GetIssuers() IssuerListEx[" + i + "]:" + issuers[i]);
                                }
                            }
                        }
                    }
                }
            }
            finally
            {
                if (issuerList.aIssuers != null)
                {
                    issuerList.aIssuers.Dispose();
                }
            }

            return(issuers);
        }
 private string GetClientSpecifiedSpn()
 {
     return(SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, this.m_SecurityContext, ContextAttribute.ClientSpecifiedSpn) as string);
 }
 public static void VerifyPackageInfo()
 {
     SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPISecureChannel, SecurityPackage, true);
 }
        //
        // for Digest, the server will send us the blob immediately, so we need to make sure we
        // call InitializeSecurityContext() a first time with a null input buffer, otherwise
        // the next call will fail. do so here:
        // WDigest.dll requires us to pass in 3 security buffers here
        // 1) BufferType: SECBUFFER_TOKEN, Content: server's challenge (incoming)
        // 2) BufferType: SECBUFFER_PKG_PARAMS, Content: request's HTTP Method
        // 3) BufferType: SECBUFFER_PKG_PARAMS, Content: the HEntity (this would be the MD5 footprint of the request entity
        //                                                             body, we can pass in NULL as this is not required)
        //
        public string GetOutgoingDigestBlob(string incomingBlob, string requestMethod, out bool handshakeComplete)
        {
            GlobalLog.Enter("NTAuthentication::GetOutgoingDigestBlob", incomingBlob);
            //
            // first time call with null incoming buffer to initialize.
            // we should get back a 0x90312 and a null outgoingBlob.
            //
            byte[] decodedOutgoingBlob = GetOutgoingBlob(null, out handshakeComplete);
            GlobalLog.Assert(!handshakeComplete, "NTAuthentication::GetOutgoingDigestBlob() handshakeComplete==true", "");
            GlobalLog.Assert(decodedOutgoingBlob == null, "NTAuthentication::GetOutgoingDigestBlob() decodedOutgoingBlob!=null", "");
            //
            // second time call with 3 incoming buffers to select HTTP client.
            // we should get back a SecurityStatus.OK and a non null outgoingBlob.
            //
            byte[] decodedIncomingBlob  = Encoding.Default.GetBytes(incomingBlob);
            byte[] decodedRequestMethod = Encoding.Default.GetBytes(requestMethod);

            int requestedFlags =
                (int)ContextFlags.Delegate |
                (int)ContextFlags.MutualAuth |
                (int)ContextFlags.ReplayDetect |
                (int)ContextFlags.SequenceDetect |
                // (int)ContextFlags.Confidentiality | // this would only work if the server provided a qop="auth-conf" directive
                // (int)ContextFlags.ClientIntegrity | // this would only work if the server provided a qop="auth-int" directive
                (int)ContextFlags.Connection;

            SecurityBufferClass[] inSecurityBuffers = new SecurityBufferClass[] {
                new SecurityBufferClass(decodedIncomingBlob, BufferType.Token),
                new SecurityBufferClass(decodedRequestMethod, BufferType.Parameters),
                new SecurityBufferClass(null, BufferType.Parameters),
            };

            SecurityBufferClass[] outSecurityBuffers = new SecurityBufferClass[] {
                new SecurityBufferClass(m_TokenSize, BufferType.Token),
            };

            SecurityContext newSecurityContext = new SecurityContext(GlobalSSPI.SSPIAuth);

            //
            // this call is still returning an error. fix together with Kevin Damour
            //
            int status =
                SSPIWrapper.InitializeSecurityContext(
                    GlobalSSPI.SSPIAuth,
                    m_CredentialsHandle.Handle,
                    m_SecurityContext.Handle,
                    m_RemotePeerId, // this must match the Uri in the HTTP status line for the current request
                    requestedFlags,
                    m_Endianness,
                    inSecurityBuffers,
                    ref newSecurityContext.Handle,
                    outSecurityBuffers,
                    ref m_ContextFlags,
                    ref newSecurityContext.TimeStamp);

            GlobalLog.Print("NTAuthentication::GetOutgoingDigestBlob() SSPIWrapper.InitializeSecurityContext() returns 0x" + string.Format("{0:x}", status));

            int errorCode = status & unchecked ((int)0x80000000);

            if (errorCode != 0)
            {
                throw new Win32Exception(status);
            }

            //
            // the return value from SSPI will tell us correctly if the
            // handshake is over or not: http://msdn.microsoft.com/library/psdk/secspi/sspiref_67p0.htm
            // we also have to consider the case in which SSPI formed a new context, in this case we're done as well.
            //
            IsCompleted = (status == (int)SecurityStatus.OK) || (m_SecurityContext.Handle != -1 && m_SecurityContext.Handle != newSecurityContext.Handle);
            if (IsCompleted)
            {
                // ... if we're done, clean the handle up or the call to UpdateHandle() might leak it.
                SSPIWrapper.DeleteSecurityContext(m_SecurityContext.m_SecModule, m_SecurityContext.Handle);
            }
            handshakeComplete = IsCompleted;
            m_Authenticated   = m_SecurityContext.Handle != -1;
            m_SecurityContext.UpdateHandle(newSecurityContext);

#if TRAVE
            if (handshakeComplete)
            {
                //
                // Kevin Damour says:
                // You should not query the securitycontext until you have actually formed one (
                // with a success return form ISC).  It is only a partially formed context and
                // no info is available to user applications (at least for digest).
                //
                SecurityPackageInfoClass securityPackageInfo = (SecurityPackageInfoClass)SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, m_SecurityContext, ContextAttribute.PackageInfo);
                GlobalLog.Print("SecurityPackageInfoClass: using:[" + ((securityPackageInfo == null)?"null":securityPackageInfo.ToString()) + "]");
            }
#endif // #if TRAVE

            GlobalLog.Assert(outSecurityBuffers.Length == 1, "NTAuthentication::GetOutgoingDigestBlob() outSecurityBuffers.Length==" + outSecurityBuffers.Length.ToString(), "");

            GlobalLog.Print("out token = " + m_TokenSize.ToString() + " size = " + outSecurityBuffers[0].size.ToString());
            GlobalLog.Dump(outSecurityBuffers[0].token);

            GlobalLog.Print("NTAuthentication::GetOutgoingDigestBlob() handshakeComplete:" + handshakeComplete.ToString());

            decodedOutgoingBlob = outSecurityBuffers[0].token;

            string outgoingBlob = null;
            if (decodedOutgoingBlob != null && decodedOutgoingBlob.Length > 0)
            {
                // CONSIDER V.NEXT
                // review Encoding.Default.GetString usage here because it might
                // end up creating non ANSI characters in the string
                outgoingBlob = Encoding.Default.GetString(decodedOutgoingBlob, 0, outSecurityBuffers[0].size);
            }

            GlobalLog.Leave("NTAuthentication::GetOutgoingDigestBlob", outgoingBlob);

            return(outgoingBlob);
        }