Wrapper for security functions that implement SSPI
Beispiel #1
0
        /// <summary>
        /// Dispose the instance
        /// </summary>
        /// <param name="bIsDisposing"></param>
        protected void Dispose(bool bIsDisposing)
        {
            // Check if we have an inbound credential
            if (_inboundCredential.IsValid())
            {
                // Call into security API to release the credentials
                if (SecurityWrapper.FreeCredentialsHandle(ref _inboundCredential) != (int)SecResult.Ok)
                {
                    // Throw an exception
                    throw new Exception("Failed to release inbound credentials handle");
                }

                // Reset inbound credential
                _inboundCredential = new SecurityHandle();
            }

            // Check if we have an outbound credential
            if (_outboundCredential.IsValid())
            {
                // Call into security API to release the credentials
                if (SecurityWrapper.FreeCredentialsHandle(ref _outboundCredential) != (int)SecResult.Ok)
                {
                    // Throw an exception
                    throw new Exception("Failed to release outbound credentials handle");
                }

                // Reset inbound credential
                _outboundCredential = new SecurityHandle();
            }
        }
Beispiel #2
0
        /// <summary>
        /// Initialize authentication sequence for the client
        /// </summary>
        /// <param name="clientToken">Payload received from the server</param>
        /// <returns>Token to be sent to the server</returns>
        public SSPIResponse ContinueClientAuthentication(byte[] clientToken)
        {
            // Wrap client token with the security buffer
            SecBufferDesc serverSecBuffer = new SecBufferDesc(clientToken);

            try
            {
                // Allocate a new instance of the client security buffer of the specified size
                SecBufferDesc clientSecBuffer = new SecBufferDesc(_maxTokenBufferSize);

                try
                {
                    // Return code from the security API call
                    int secReturnCode = 0;

                    // New context attribute
                    uint contextAttribute = 0;

                    // Initialize token lifetime container
                    SecurityInteger lifeTime = new SecurityInteger();

                    // Delegate into security API
                    secReturnCode = SecurityWrapper.InitializeSecurityContext(ref _outboundCredential,
                                                                              ref _clientContext,
                                                                              _targetMachineSPN,
                                                                              (int)(SecContextRequirements.MutualAuthentication | SecContextRequirements.Delegate | SecContextRequirements.ExtendedError),
                                                                              0,
                                                                              (int)SecDataRepresentation.Native,
                                                                              ref serverSecBuffer,
                                                                              0,
                                                                              out _clientContext,
                                                                              out clientSecBuffer,
                                                                              out contextAttribute,
                                                                              out lifeTime);

                    // Check the return code
                    if (secReturnCode != (int)SecResult.Ok && secReturnCode != (int)SecResult.ContinueNeeded && secReturnCode != (int)SecResult.CompleteAndContinue)
                    {
                        // Operation failed
                        throw new Win32Exception(secReturnCode, "Failed to generate security context");
                    }

                    // NOTE: Digest SSP call to "CompleteAuthToken" is intentionally omitted because we don't support Digest today.

                    // Convert to byte array and indication whether this is a last call
                    return(new SSPIResponse(clientSecBuffer.ToArray(), secReturnCode != (int)SecResult.ContinueNeeded && secReturnCode != (int)SecResult.CompleteAndContinue));
                }
                finally
                {
                    // Dispose client security buffer
                    clientSecBuffer.Dispose();
                }
            }
            finally
            {
                // Dispose server security buffer
                serverSecBuffer.Dispose();
            }
        }
Beispiel #3
0
        /// <summary>
        /// Continue authentication sequence for the server
        /// </summary>
        /// <param name="clientToken">Token received from the client</param>
        /// <returns>Token to be sent to the client in response</returns>
        public SSPIResponse ContinueServerAuthentication(byte[] clientToken)
        {
            // Wrap client token with the security buffer
            SecBufferDesc clientSecBuffer = new SecBufferDesc(clientToken);

            try
            {
                // Allocate a new instance of the server security buffer of the specified size
                SecBufferDesc serverSecBuffer = new SecBufferDesc(_maxTokenBufferSize);

                try
                {
                    // Return code from the security API call
                    int secReturnCode = 0;

                    // New context attribute
                    uint contextAttribute = 0;

                    // Initialize token lifetime container
                    SecurityInteger lifeTime = new SecurityInteger();

                    // Delegate into security API
                    secReturnCode = SecurityWrapper.AcceptSecurityContext(ref _inboundCredential,
                                                                          ref _serverContext,
                                                                          ref clientSecBuffer,
                                                                          (int)SecContextRequirements.MutualAuthentication,
                                                                          (int)SecDataRepresentation.Native,
                                                                          out _serverContext,
                                                                          out serverSecBuffer,
                                                                          out contextAttribute,
                                                                          out lifeTime);

                    // Check the return code
                    if (secReturnCode != (int)SecResult.Ok && secReturnCode != (int)SecResult.ContinueNeeded)
                    {
                        // Operation failed
                        throw new Win32Exception(secReturnCode, "Failed to accept security context");
                    }

                    // Convert to byte array and indication whether this is a last call
                    return(new SSPIResponse(serverSecBuffer.ToArray(), secReturnCode != (int)SecResult.ContinueNeeded));
                }
                finally
                {
                    // Dispose server security buffer
                    serverSecBuffer.Dispose();
                }
            }
            finally
            {
                // Dispose client security buffer
                clientSecBuffer.Dispose();
            }
        }
Beispiel #4
0
        /// <summary>
        /// Initialize authentication sequence for the client
        /// </summary>
        /// <returns>Token to be sent to the server</returns>
        public SSPIResponse StartClientAuthentication(string targetMachine, uint targetPort)
        {
            // Save the server we're authenticating against
            _targetMachineSPN = string.Format("MSSQLSvc/{0}:{1}", targetMachine, targetPort);

            // Allocate a new instance of the client security buffer of the specified size
            SecBufferDesc clientSecBuffer = new SecBufferDesc(_maxTokenBufferSize);

            try
            {
                // Return code from the security API call
                int secReturnCode = 0;

                // New context attribute
                uint contextAttribute = 0;

                // Initialize token lifetime container
                SecurityInteger lifeTime = new SecurityInteger();

                // Delegate into security API
                secReturnCode = SecurityWrapper.InitializeSecurityContext(ref _outboundCredential,
                                                                          IntPtr.Zero,
                                                                          _targetMachineSPN,
                                                                          (int)(SecContextRequirements.MutualAuthentication | SecContextRequirements.Delegate | SecContextRequirements.ExtendedError),
                                                                          0,
                                                                          (int)SecDataRepresentation.Native,
                                                                          IntPtr.Zero,
                                                                          0,
                                                                          out _clientContext,
                                                                          out clientSecBuffer,
                                                                          out contextAttribute,
                                                                          out lifeTime);

                // Check the return code
                if (secReturnCode != (int)SecResult.Ok && secReturnCode != (int)SecResult.ContinueNeeded)
                {
                    // Operation failed
                    throw new Win32Exception(secReturnCode, "Failed to generate initial security context");
                }

                // Convert to byte array and indication whether this is a last call
                return(new SSPIResponse(clientSecBuffer.ToArray(), secReturnCode != (int)SecResult.ContinueNeeded && secReturnCode != (int)SecResult.CompleteAndContinue));
            }
            finally
            {
                // Dispose server security buffer
                clientSecBuffer.Dispose();
            }
        }
Beispiel #5
0
        /// <summary>
        /// Return identity of the party on the other end
        /// </summary>
        /// <returns></returns>
        public IIdentity GetRemoteIdentity()
        {
            IntPtr token = IntPtr.Zero;

            // Delegate into security API
            int secReturnCode = SecurityWrapper.QuerySecurityContextToken(ref _serverContext, ref token);

            // Check if we succeeded
            if (secReturnCode != (int)SecResult.Ok)
            {
                // We couldn't obtain token identity
                throw new Win32Exception(secReturnCode, "Failed to obtain security context token");
            }

            return(new WindowsIdentity(token));
        }
Beispiel #6
0
        /// <summary>
        /// Create SSPI context for client
        /// </summary>
        public static SSPIContext CreateClient()
        {
            // Create an instance of the context
            SSPIContext context = new SSPIContext();

            // Initialize token lifetime container
            SecurityInteger lifeTime = new SecurityInteger();

            // Delegate into security API
            int secReturnCode = SecurityWrapper.AcquireCredentialsHandle(null, SecConstants.Negotiate, (int)SecPgkCredentials.Outbound, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, ref context._outboundCredential, ref lifeTime);

            // Check if we succeeded
            if (secReturnCode != (int)SecResult.Ok)
            {
                // We couldn't obtain server credentials handle
                throw new Win32Exception(secReturnCode, "Failed to acquire client credentials handle");
            }

            return(context);
        }
Beispiel #7
0
        /// <summary>
        /// Default constructor
        /// </summary>
        private SSPIContext()
        {
            // Prepare a list of packages
            IList <string> packages = new List <string>();

            packages.Add(SecConstants.Negotiate);
            packages.Add(SecConstants.Kerberos);
            packages.Add(SecConstants.NTLM);

            // Try each package
            foreach (string package in packages)
            {
                IntPtr packagePtr = IntPtr.Zero;

                // Query security package
                int secReturnCode = SecurityWrapper.QuerySecurityPackageInfo(package, ref packagePtr);

                // Check if package was found
                if (secReturnCode == unchecked ((int)SecResult.PackageNotFound))
                {
                    // Move to the next package
                    continue;
                }

                // Check if we succeeded
                if (secReturnCode != (int)SecResult.Ok)
                {
                    // Security package qury failed
                    throw new Win32Exception(secReturnCode, "Failed to query security package");
                }

                try
                {
                    // Map unmanaged structure pointer to managed
                    SecPkgInfo info = (SecPkgInfo)Marshal.PtrToStructure(packagePtr, typeof(SecPkgInfo));

                    // Check if buffer size is larger than what we have
                    if (info.MaxToken > _maxTokenBufferSize)
                    {
                        // Use the token size
                        _maxTokenBufferSize = info.MaxToken;
                    }
                }
                finally
                {
                    // Release security package
                    secReturnCode = SecurityWrapper.FreeContextBuffer(packagePtr);

                    // Check if we succeeded
                    if (secReturnCode != (int)SecResult.Ok)
                    {
                        // Security package qury failed
                        throw new Win32Exception(secReturnCode, "Failed to free security package");
                    }
                }
            }

            // Check if buffer size is valid
            if (_maxTokenBufferSize == 0)
            {
                throw new Exception("Either no security packages found or none of them reported a valid maximum token length");
            }
        }