using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Vanara.Extensions;
using Vanara.InteropServices;
using static Vanara.PInvoke.AdvApi32;
using static Vanara.PInvoke.Crypt32;
using static Vanara.PInvoke.Schannel;
using TimeStamp = System.Runtime.InteropServices.ComTypes.FILETIME;

namespace Vanara.PInvoke
{
	/// <summary>Functions and definitions from Secur32.dll</summary>
	public static partial class Secur32
	{
		/// <summary>Undocumented.</summary>
		/// <param name="Arg">Argument passed in</param>
		/// <param name="Principal">Principal ID</param>
		/// <param name="KeyVer">Key Version</param>
		/// <param name="Key">Returned ptr to key.</param>
		/// <param name="Status">returned status.</param>
		[PInvokeData("sspi.h")]
		[UnmanagedFunctionPointer(CallingConvention.Winapi)]
		public delegate void SEC_GET_KEY_FN(IntPtr Arg, IntPtr Principal, uint KeyVer, out IntPtr Key, out int Status);

		/// <summary>Bit flags that specify the attributes required by the server to establish the context.</summary>
		[PInvokeData("sspi.h", MSDNShortId = "a53f733e-b646-4431-b021-a2c446308849")]
		[Flags]
		public enum ASC_REQ : uint
		{
			/// <summary>The server is allowed to impersonate the client. Ignore this flag for constrained delegation.</summary>
			ASC_REQ_DELEGATE = 0x00000001,

			/// <summary>The mutual authentication policy of the service will be satisfied.</summary>
			ASC_REQ_MUTUAL_AUTH = 0x00000002,

			/// <summary>Detect replayed packets.</summary>
			ASC_REQ_REPLAY_DETECT = 0x00000004,

			/// <summary>Detect messages received out of sequence.</summary>
			ASC_REQ_SEQUENCE_DETECT = 0x00000008,

			/// <summary>Encrypt messages by using the EncryptMessage function.</summary>
			ASC_REQ_CONFIDENTIALITY = 0x00000010,

			/// <summary>A new session key must be negotiated. This value is supported only by the Kerberos security package.</summary>
			ASC_REQ_USE_SESSION_KEY = 0x00000020,

			/// <summary/>
			ASC_REQ_SESSION_TICKET = 0x00000040,

			/// <summary>
			/// Credential Security Support Provider (CredSSP) will allocate output buffers. When you have finished using the output buffers,
			/// free them by calling the FreeContextBuffer function.
			/// </summary>
			ASC_REQ_ALLOCATE_MEMORY = 0x00000100,

			/// <summary/>
			ASC_REQ_USE_DCE_STYLE = 0x00000200,
			/// <summary/>
			ASC_REQ_DATAGRAM = 0x00000400,

			/// <summary>The security context will not handle formatting messages.</summary>
			ASC_REQ_CONNECTION = 0x00000800,

			/// <summary/>
			ASC_REQ_CALL_LEVEL = 0x00001000,
			/// <summary/>
			ASC_REQ_FRAGMENT_SUPPLIED = 0x00002000,

			/// <summary>When errors occur, the remote party will be notified.</summary>
			ASC_REQ_EXTENDED_ERROR = 0x00008000,

			/// <summary>Support a stream-oriented connection.</summary>
			ASC_REQ_STREAM = 0x00010000,

			/// <summary>Sign messages and verify signatures by using the EncryptMessage and MakeSignature functions.</summary>
			ASC_REQ_INTEGRITY = 0x00020000,

			/// <summary/>
			ASC_REQ_LICENSING = 0x00040000,
			/// <summary/>
			ASC_REQ_IDENTIFY = 0x00080000,
			/// <summary/>
			ASC_REQ_ALLOW_NULL_SESSION = 0x00100000,
			/// <summary/>
			ASC_REQ_ALLOW_NON_USER_LOGONS = 0x00200000,
			/// <summary/>
			ASC_REQ_ALLOW_CONTEXT_REPLAY = 0x00400000,
			/// <summary/>
			ASC_REQ_FRAGMENT_TO_FIT = 0x00800000,
			/// <summary/>
			ASC_REQ_NO_TOKEN = 0x01000000,
			/// <summary/>
			ASC_REQ_PROXY_BINDINGS = 0x04000000,
			/// <summary/>
			ASC_REQ_ALLOW_MISSING_BINDINGS = 0x10000000,
		}

		/// <summary>A set of bit flags that indicate the attributes of the established context.</summary>
		[PInvokeData("sspi.h", MSDNShortId = "a53f733e-b646-4431-b021-a2c446308849")]
		[Flags]
		public enum ASC_RET : uint
		{
			/// <summary>
			/// The server in the transport application can build new security contexts impersonating the client that will be accepted by
			/// other servers as the client's contexts. Delegate works only if MUTUAL_AUTH is set. DELEGATE is currently supported only by
			/// Kerberos. Further, Kerberos will delegate only to a server that has the flag TRUSTED_FOR_DELEGATION. Do not use this flag for
			/// constrained delegation.
			/// </summary>
			ASC_RET_DELEGATE = 0x00000001,

			/// <summary>
			/// The communicating parties must authenticate their identities to each other. Without MUTUAL_AUTH, the client authenticates its
			/// identity to the server. With MUTUAL_AUTH, the server also must authenticate its identity to the client.
			/// <para>
			/// When using the Schannel security package, the server sets the ASC_RET_MUTUAL_AUTH constant only in the last call to
			/// AcceptSecurityContext(Negotiate), after certificate mapping has successfully completed.
			/// </para>
			/// </summary>
			ASC_RET_MUTUAL_AUTH = 0x00000002,

			/// <summary>
			/// The security package detects replayed packets and notifies the caller if a packet has been replayed. The use of this flag
			/// implies all of the conditions specified by the INTEGRITY flag.
			/// </summary>
			ASC_RET_REPLAY_DETECT = 0x00000004,

			/// <summary>
			/// The context must be allowed to detect out-of-order delivery of packets later through the message support functions. Use of
			/// this flag implies all of the conditions specified by the INTEGRITY flag.
			/// </summary>
			ASC_RET_SEQUENCE_DETECT = 0x00000008,

			/// <summary>
			/// The context can protect data while in transit using the EncryptMessage (General) and DecryptMessage (General) functions. The
			/// CONFIDENTIALITY flag does not work if the generated context is for the Guest account.
			/// </summary>
			ASC_RET_CONFIDENTIALITY = 0x00000010,

			/// <summary>A new session key must be negotiated.</summary>
			ASC_RET_USE_SESSION_KEY = 0x00000020,

			/// <summary></summary>
			ASC_RET_SESSION_TICKET = 0x00000040,

			/// <summary>
			/// The security package must allocate memory. The caller must eventually call the FreeContextBuffer function to free memory
			/// allocated by the security package.
			/// </summary>
			ASC_RET_ALLOCATED_MEMORY = 0x00000100,

			/// <summary>The caller expects a three-leg authentication transaction.</summary>
			ASC_RET_USED_DCE_STYLE = 0x00000200,

			/// <summary>Datagram semantics must be used. For more information, see Datagram Contexts.</summary>
			ASC_RET_DATAGRAM = 0x00000400,

			/// <summary>Connection semantics must be used. For more information, see Connection-Oriented Contexts.</summary>
			ASC_RET_CONNECTION = 0x00000800,

			/// <summary></summary>
			ASC_RET_CALL_LEVEL = 0x00002000,

			/// <summary></summary>
			ASC_RET_THIRD_LEG_FAILED = 0x00004000,

			/// <summary>Error reply messages for the peer must be generated if the context fails.</summary>
			ASC_RET_EXTENDED_ERROR = 0x00008000,

			/// <summary>Stream semantics must be used. For more information, see Stream Contexts.</summary>
			ASC_RET_STREAM = 0x00010000,

			/// <summary>Buffer integrity can be verified but no sequencing or reply detection is enabled.</summary>
			ASC_RET_INTEGRITY = 0x00020000,

			/// <summary></summary>
			ASC_RET_LICENSING = 0x00040000,

			/// <summary>
			/// When a server impersonates a context that has this flag set, that impersonation yields extremely limited access.
			/// Impersonation with IDENTIFY set is used to verify the client's identity.
			/// </summary>
			ASC_RET_IDENTIFY = 0x00080000,

			/// <summary></summary>
			ASC_RET_NULL_SESSION = 0x00100000,

			/// <summary></summary>
			ASC_RET_ALLOW_NON_USER_LOGONS = 0x00200000,

			/// <summary></summary>
			ASC_RET_ALLOW_CONTEXT_REPLAY = 0x00400000,

			/// <summary></summary>
			ASC_RET_FRAGMENT_ONLY = 0x00800000,

			/// <summary></summary>
			ASC_RET_NO_TOKEN = 0x01000000,

			/// <summary></summary>
			ASC_RET_NO_ADDITIONAL_TOKEN = 0x02000000,
		}

		/// <summary>The data representation, such as byte ordering, on the target.</summary>
		[PInvokeData("sspi.h", MSDNShortId = "a53f733e-b646-4431-b021-a2c446308849")]
		[Flags]
		public enum DREP
		{
			/// <summary></summary>
			SECURITY_NATIVE_DREP = 0x00000010,

			/// <summary></summary>
			SECURITY_NETWORK_DREP = 0x00000000
		}

		/// <summary>Property to return from the SASL context.</summary>
		[PInvokeData("sspi.h", MSDNShortId = "c9c424d3-07e6-4ed0-9189-c932af0475d9")]
		public enum SASL_OPTION
		{
			/// <summary>
			/// Data type of buffer: ULONG
			/// <para>
			/// State of SASL processing of the Authz value provided by the SASL application. The valid states for processing are
			/// Sasl_AuthZIDForbidden and Sasl_AuthZIDProcessed.
			/// </para>
			/// </summary>
			SASL_OPTION_AUTHZ_PROCESSING = 4,

			/// <summary>
			/// Data type of buffer: Array of binary characters
			/// <para>
			/// String of characters passed from the SASL client to the server. If the AuthZ_Processing state is Sasl_AuthZIDForbidden, the
			/// return value SEC_E_UNSUPPORTED_FUNCTION is returned.
			/// </para>
			/// </summary>
			SASL_OPTION_AUTHZ_STRING = 3,

			/// <summary>
			/// Data type of buffer: ULONG
			/// <para>Maximum size of the receiving buffer on the local computer.</para>
			/// </summary>
			SASL_OPTION_RECV_SIZE = 2,

			/// <summary>
			/// Data type of buffer: ULONG
			/// <para>
			/// Maximum message data size that can be transmitted. This value is the maximum buffer size that can be transmitted to the
			/// remote SASL process minus the block size, the trailer size, and the maximum signature size.
			/// </para>
			/// </summary>
			SASL_OPTION_SEND_SIZE = 1,
		}

		/// <summary>En/Decryption options.</summary>
		[PInvokeData("sspi.h", MSDNShortId = "86598BAA-0E87-46A9-AA1A-BF04BF0CDAFA")]
		public enum SEC_WINNT_AUTH_IDENTITY_ENCRYPT
		{
			/// <summary>
			/// The encrypted structure can only be decrypted by a security context in the same logon session. This option is used to protect
			/// an identity buffer that is being sent over a local RPC.
			/// </summary>
			SEC_WINNT_AUTH_IDENTITY_ENCRYPT_SAME_LOGON = 0x1,

			/// <summary>
			/// The encrypted structure can only be decrypted by the same process. Calling the function with this option is equivalent to
			/// calling SspiEncryptAuthIdentity. This option is used to protect an identity buffer that is being persisted in a process's
			/// private memory for an extended period.
			/// </summary>
			SEC_WINNT_AUTH_IDENTITY_ENCRYPT_SAME_PROCESS = 0x2
		}

		/// <summary>The type used by negotiable security packages.</summary>
		[PInvokeData("sspi.h", MSDNShortId = "a6083d76-1774-428c-85ca-fea817827d6a")]
		[Flags]
		public enum SEC_WINNT_AUTH_IDENTITY_FLAGS
		{
			/// <summary>Credentials are in ANSI form.</summary>
			SEC_WINNT_AUTH_IDENTITY_ANSI = 0x1,

			/// <summary>Credentials are in Unicode form.</summary>
			SEC_WINNT_AUTH_IDENTITY_UNICODE = 0x2,

			/// <summary>All data is in one buffer.</summary>
			SEC_WINNT_AUTH_IDENTITY_MARSHALLED = 0x4,

			/// <summary>
			/// Used with the Kerberos security support provider (SSP). Credentials are for identity only. The Kerberos package is directed
			/// to not include authorization data in the ticket.
			/// </summary>
			SEC_WINNT_AUTH_IDENTITY_ONLY = 0x8,

			/// <summary>
			/// The structure is encrypted by the SspiEncryptAuthIdentity function or by the SspiEncryptAuthIdentityEx function with the
			/// SEC_WINNT_AUTH_IDENTITY_ENCRYPT_SAME_PROCESS option. It can only be decrypted by the same process.
			/// <para>Windows Server 2008 R2 and Windows 7: This flag is not supported.</para>
			/// </summary>
			SEC_WINNT_AUTH_IDENTITY_FLAGS_PROCESS_ENCRYPTED = 0x10,

			/// <summary>
			/// The structure is encrypted by the SspiEncryptAuthIdentityEx function with the SEC_WINNT_AUTH_IDENTITY_ENCRYPT_SAME_LOGON
			/// option under the SYSTEM security context. It can only be decrypted by a thread running as SYSTEM.
			/// <para>Windows Server 2008 R2 and Windows 7: This flag is not supported.</para>
			/// </summary>
			SEC_WINNT_AUTH_IDENTITY_FLAGS_SYSTEM_PROTECTED = 0x20,

			/// <summary>
			/// The structure is encrypted by the SspiEncryptAuthIdentityEx function with the SEC_WINNT_AUTH_IDENTITY_ENCRYPT_SAME_LOGON
			/// option under a non-SYSTEM security context. It can only be decrypted by a thread running in the same logon session in which
			/// it was encrypted.
			/// <para>Windows Server 2008 R2 and Windows 7: This flag is not supported.</para>
			/// </summary>
			SEC_WINNT_AUTH_IDENTITY_FLAGS_USER_PROTECTED = 0x40,

			/// <summary>
			/// The authentication identity buffer is cbStructureLength + 8 padding bytes that are necessary for in-place encryption or
			/// decryption of the identity.
			/// <para>
			/// The authentication identity buffer is cbStructureLength + 8 padding bytes that are necessary for in-place encryption or
			/// decryption of the identity.
			/// </para>
			/// </summary>
			SEC_WINNT_AUTH_IDENTITY_FLAGS_RESERVED = 0x10000,

			/// <summary>Undocumented.</summary>
			SEC_WINNT_AUTH_IDENTITY_FLAGS_NULL_USER = 0x20000,

			/// <summary>Undocumented.</summary>
			SEC_WINNT_AUTH_IDENTITY_FLAGS_NULL_DOMAIN = 0x40000,

			/// <summary>
			/// When the credential type is password, the presence of this flag specifies that the structure is an online ID credential. The
			/// DomainOffset and DomainLength members correspond to the online ID provider name.
			/// <para>Windows Server 2008 R2 and Windows 7: This flag is not supported.</para>
			/// </summary>
			SEC_WINNT_AUTH_IDENTITY_FLAGS_ID_PROVIDER = 0x80000,
		}

		/// <summary/>
		[Flags]
		public enum SecBufferType : uint
		{
			/// <summary>The buffer contains an alert message.</summary>
			SECBUFFER_ALERT = 0x11,

			/// <summary>The buffer contains a bitmask for a SECBUFFER_READONLY_WITH_CHECKSUM buffer.</summary>
			SECBUFFER_ATTRMASK = 0xF0000000,

			/// <summary>The buffer contains channel binding information.</summary>
			SECBUFFER_CHANNEL_BINDINGS = 0xE,

			/// <summary>The buffer contains a DOMAIN_PASSWORD_INFORMATION structure.</summary>
			//[CorrespondingType(typeof(DOMAIN_PASSWORD_INFORMATION))]
			SECBUFFER_CHANGE_PASS_RESPONSE = 0xF,

			/// <summary>
			/// The buffer contains common data. The security package can read and write this data, for example, to encrypt some or all of it.
			/// </summary>
			SECBUFFER_DATA = 0x1,

			/// <summary>
			/// The buffer contains the setting for the maximum transmission unit (MTU) size for DTLS only. The default value is 1096 and the
			/// valid configurable range is between 200 and 64*1024.
			/// </summary>
			SECBUFFER_DTLS_MTU = 0x18,

			/// <summary>
			/// This is a placeholder in the buffer array. The caller can supply several such entries in the array, and the security package
			/// can return information in them. For more information, see SSPI Context Semantics.
			/// </summary>
			SECBUFFER_EMPTY = 0x0,

			/// <summary>The security package uses this value to indicate the number of extra or unprocessed bytes in a message.</summary>
			SECBUFFER_EXTRA = 0x5,

			/// <summary>
			/// The buffer contains a protocol-specific list of object identifiers (OIDs). It is not usually of interest to callers.
			/// </summary>
			SECBUFFER_MECHLIST = 0xB,

			/// <summary>The buffer contains a signature of a SECBUFFER_MECHLIST buffer. It is not usually of interest to callers.</summary>
			SECBUFFER_MECHLIST_SIGNATURE = 0xC,

			/// <summary>
			/// The security package uses this value to indicate the number of missing bytes in a particular message. The pvBuffer member is
			/// ignored in this type.
			/// </summary>
			SECBUFFER_MISSING = 0x4,

			/// <summary>
			/// These are transport-to-package–specific parameters. For example, the NetWare redirector may supply the server object
			/// identifier, while DCE RPC can supply an association UUID, and so on.
			/// </summary>
			SECBUFFER_PKG_PARAMS = 0x3,

			/// <summary>The buffer contains the preshared key. The maximum allowed PSK buffer size is 256 bytes.</summary>
			SECBUFFER_PRESHARED_KEY = 0x16,

			/// <summary>The buffer contains the preshared key identity.</summary>
			SECBUFFER_PRESHARED_KEY_IDENTITY = 0x17,

			/// <summary>The buffer contains the SRTP master key identifier.</summary>
			SECBUFFER_SRTP_MASTER_KEY_IDENTIFIER = 0x14,

			/// <summary>The buffer contains the list of SRTP protection profiles, in descending order of preference.</summary>
			SECBUFFER_SRTP_PROTECTION_PROFILES = 0x13,

			/// <summary>The buffer contains a protocol-specific header for a particular record. It is not usually of interest to callers.</summary>
			SECBUFFER_STREAM_HEADER = 0x7,

			/// <summary>The buffer contains a protocol-specific trailer for a particular record. It is not usually of interest to callers.</summary>
			SECBUFFER_STREAM_TRAILER = 0x6,

			/// <summary>This flag is reserved. Do not use it.</summary>
			SECBUFFER_TARGET = 0xD,

			/// <summary>
			/// The buffer specifies the service principal name (SPN) of the target.
			/// <para>This value is supported by the Digest security package when used with channel bindings.</para>
			/// <para>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This value is not supported.</para>
			/// </summary>
			SECBUFFER_TARGET_HOST = 0x10,

			/// <summary>
			/// The buffer contains the security token portion of the message. This is read-only for input parameters or read/write for
			/// output parameters.
			/// </summary>
			SECBUFFER_TOKEN = 0x2,

			/// <summary>
			/// The buffer contains the supported token binding protocol version and key parameters, in descending order of preference.
			/// </summary>
			SECBUFFER_TOKEN_BINDING = 0x15,

			/// <summary>
			/// The buffer contains a list of application protocol IDs, one list per application protocol negotiation extension type to be enabled.
			/// </summary>
			SECBUFFER_APPLICATION_PROTOCOLS = 18,

			/// <summary>Undocumented.</summary>
			SECBUFFER_NEGOTIATION_INFO = 8,

			/// <summary>Undocumented.</summary>
			SECBUFFER_PADDING = 9,

			/// <summary>
			/// The buffer is read-only with no checksum. This flag is intended for sending header information to the security package for
			/// computing the checksum. The package can read this buffer, but cannot modify it.
			/// </summary>
			SECBUFFER_READONLY = 0x80000000,

			/// <summary>The buffer is read-only with a checksum.</summary>
			SECBUFFER_READONLY_WITH_CHECKSUM = 0x10000000,

			/// <summary>Undocumented.</summary>
			SECBUFFER_RESERVED = 0x60000000,

			/// <summary>Undocumented.</summary>
			SECBUFFER_STREAM = 10,
		}

		/// <summary>Specifies the attribute of the context to be returned.</summary>
		[PInvokeData("sspi.h", MSDNShortId = "FD91EE99-F94E-44CE-9331-933D0CAA5F75")]
		public enum SECPKG_ATTR : uint
		{
			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_AccessToken structure.
			/// <para>Returns a handle to the access token.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_AccessToken), CorrespondingAction.Get)]
			SECPKG_ATTR_ACCESS_TOKEN = 18,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_SessionAppData structure.
			/// <para>Returns or specifies application data for the session.</para>
			/// <para>This attribute is supported only by the Schannel security package.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_SessionAppData), CorrespondingAction.GetSet)]
			SECPKG_ATTR_APP_DATA = 0x5e,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_Authority structure.
			/// <para>Queries the name of the authenticating authority.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_Authority), CorrespondingAction.Get)]
			SECPKG_ATTR_AUTHORITY = 6,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_ClientSpecifiedTarget structure that represents the service
			/// principal name (SPN) of the initial target supplied by the client.
			/// <para>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This value is not supported.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_ClientSpecifiedTarget), CorrespondingAction.Get)]
			SECPKG_ATTR_CLIENT_SPECIFIED_TARGET = 27,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_ConnectionInfo structure.
			/// <para>Returns detailed information on the established connection.</para>
			/// <para>This attribute is supported only by the Schannel security package.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_ConnectionInfo), CorrespondingAction.Get)]
			SECPKG_ATTR_CONNECTION_INFO = 0x5a,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_ClientCreds structure that specifies client credentials.
			/// <para>If the client credential is user name and password, the buffer is a packed KERB_INTERACTIVE_LOGON structure.</para>
			/// <para>If the client credential is user name and smart card PIN, the buffer is a packed KERB_CERTIFICATE_LOGON structure.</para>
			/// <para>If the client credential is an online identity credential, the buffer is a marshaled SEC_WINNT_AUTH_IDENTITY_EX2 structure.</para>
			/// <para>This attribute is supported only on the CredSSP server.</para>
			/// <para>
			/// Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This value is not supported.
			/// </para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_ClientCreds), CorrespondingAction.Get)]
			SECPKG_ATTR_CREDS_2 = 0x80000086,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_DceInfo structure.
			/// <para>Queries for authorization data used by DCE services.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_DceInfo), CorrespondingAction.Get)]
			SECPKG_ATTR_DCE_INFO = 3,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_Bindings structure that specifies channel binding information.
			/// <para>This attribute is supported only by the Schannel security package.</para>
			/// <para>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This value is not supported.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_Bindings), CorrespondingAction.Get)]
			SECPKG_ATTR_ENDPOINT_BINDINGS = 26,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_EapKeyBlock structure.
			/// <para>Queries for key data used by the EAP TLS protocol.</para>
			/// <para>This attribute is supported only by the Schannel security package.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_EapKeyBlock), CorrespondingAction.Get)]
			SECPKG_ATTR_EAP_KEY_BLOCK = 0x5b,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_Flags structure.
			/// <para>Returns information about the negotiated context flags.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_Flags), CorrespondingAction.Get)]
			SECPKG_ATTR_FLAGS = 14,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_IssuerListInfoEx structure.
			/// <para>Returns a list of certificate issuers that are accepted by the server.</para>
			/// <para>This attribute is supported only by the Schannel security package.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_IssuerListInfoEx), CorrespondingAction.Get)]
			SECPKG_ATTR_ISSUER_LIST_EX = 0x59,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_KeyInfo structure.
			/// <para>Queries information about the keys used in a security context.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_KeyInfo), CorrespondingAction.Get)]
			SECPKG_ATTR_KEY_INFO = 5,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_LastClientTokenStatus structure that specifies whether the token
			/// from the most recent call to the InitializeSecurityContext function is the last token from the client.
			/// <para>This value is supported only by the Negotiate, Kerberos, and NTLM security packages.</para>
			/// <para>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This value is not supported.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_LastClientTokenStatus), CorrespondingAction.Get)]
			SECPKG_ATTR_LAST_CLIENT_TOKEN_STATUS = 30,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_Lifespan structure.
			/// <para>Queries the life span of the context.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_Lifespan), CorrespondingAction.Get)]
			SECPKG_ATTR_LIFESPAN = 2,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a PCCERT_CONTEXTstructure.
			/// <para>Finds a certificate context that contains a local end certificate.</para>
			/// <para>This attribute is supported only by the Schannel security package.</para>
			/// </summary>
			SECPKG_ATTR_LOCAL_CERT_CONTEXT = 0x54,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_Names structure.
			/// <para>Queries the name associated with the context.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_Names), CorrespondingAction.Get)]
			SECPKG_ATTR_NAMES = 1,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_NativeNames structure.
			/// <para>Returns the principal name (CNAME) from the outbound ticket.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_NativeNames), CorrespondingAction.Get)]
			SECPKG_ATTR_NATIVE_NAMES = 13,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_NegotiationInfo structure.
			/// <para>
			/// Returns information about the security package to be used with the negotiation process and the current state of the
			/// negotiation for the use of that package.
			/// </para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_NegotiationInfo), CorrespondingAction.Get)]
			SECPKG_ATTR_NEGOTIATION_INFO = 12,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_PackageInfostructure.
			/// <para>Returns information on the SSP in use.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_PackageInfo), CorrespondingAction.Get)]
			SECPKG_ATTR_PACKAGE_INFO = 10,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_PasswordExpiry structure.
			/// <para>Returns password expiration information.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_PasswordExpiry), CorrespondingAction.Get)]
			SECPKG_ATTR_PASSWORD_EXPIRY = 8,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a PCCERT_CONTEXTstructure.
			/// <para>Finds a certificate context that contains the end certificate supplied by the server.</para>
			/// <para>This attribute is supported only by the Schannel security package.</para>
			/// </summary>
			[CorrespondingType(typeof(CERT_CONTEXT), CorrespondingAction.Get)]
			SECPKG_ATTR_REMOTE_CERT_CONTEXT = 0x53,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a HCERTCONTEXT. Finds a certificate context that contains a certificate supplied
			/// by the Root store.
			/// </summary>
			SECPKG_ATTR_ROOT_STORE = 0x55,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_SessionKey structure.
			/// <para>Returns information about the session keys.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_SessionKey), CorrespondingAction.Get)]
			SECPKG_ATTR_SESSION_KEY = 9,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_SessionInfo structure.
			/// <para>Returns information about the session.</para>
			/// <para>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This value is not supported.</para>
			/// <para>This attribute is supported only by the Schannel security package.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_SessionInfo), CorrespondingAction.Get)]
			SECPKG_ATTR_SESSION_INFO = 0x5d,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_Sizes structure.
			/// <para>Queries the sizes of the structures used in the per-message functions.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_Sizes))]
			SECPKG_ATTR_SIZES = 0,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_StreamSizes structure.
			/// <para>Queries the sizes of the various parts of a stream used in the per-message functions.</para>
			/// <para>This attribute is supported only by the Schannel security package.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_StreamSizes), CorrespondingAction.Get)]
			SECPKG_ATTR_STREAM_SIZES = 4,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_SubjectAttributes structure.
			/// <para>This value returns information about the security attributes for the connection.</para>
			/// <para>This value is supported only on the CredSSP server.</para>
			/// <para>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This value is not supported.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_SubjectAttributes), CorrespondingAction.Get)]
			SECPKG_ATTR_SUBJECT_SECURITY_ATTRIBUTES = 124,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_SupportedSignatures structure.
			/// <para>This value returns information about the signature types that are supported for the connection.</para>
			/// <para>This value is supported only by the Schannel security package.</para>
			/// <para>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This value is not supported.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_SupportedSignatures), CorrespondingAction.Get)]
			SECPKG_ATTR_SUPPORTED_SIGNATURES = 0x66,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_TargetInformation structure.
			/// <para>Returns information about the name of the remote server.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_TargetInformation), CorrespondingAction.Get)]
			SECPKG_ATTR_TARGET_INFORMATION = 17,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_Bindings structure that specifies channel binding information.
			/// <para>This value is supported only by the Schannel security package.</para>
			/// <para>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This value is not supported.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_Bindings), CorrespondingAction.Get)]
			SECPKG_ATTR_UNIQUE_BINDINGS = 25,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_AccessToken structure that specifies the access token for the
			/// current security context.
			/// <para>This attribute is supported only on the server.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_AccessToken), CorrespondingAction.Get)]
			SECPKG_ATTR_C_ACCESS_TOKEN = 0x80000012,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_AccessToken structure that specifies the access token for the
			/// current security context.
			/// <para>This attribute is supported only on the server.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_AccessToken), CorrespondingAction.Get)]
			SECPKG_ATTR_C_FULL_ACCESS_TOKEN = 0x80000082,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a CERT_TRUST_STATUS structure that specifies trust information about the certificate.
			/// <para>This attribute is supported only on the client.</para>
			/// </summary>
			[CorrespondingType(typeof(CERT_TRUST_STATUS), CorrespondingAction.Get)]
			SECPKG_ATTR_CERT_TRUST_STATUS = 0x80000084,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_ClientCreds structure that specifies client credentials.
			/// <para>The client credentials can be either user name and password or user name and smart card PIN.</para>
			/// <para>This attribute is supported only on the server.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_ClientCreds), CorrespondingAction.Get)]
			SECPKG_ATTR_CREDS = 0x80000080,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_PackageInfo structure that specifies the name of the
			/// authentication package negotiated by the Microsoft Negotiate provider.
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_PackageInfo), CorrespondingAction.Get)]
			SECPKG_ATTR_NEGOTIATION_PACKAGE = 0x80000081,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_Flags structure that specifies information about the flags in the
			/// current security context.
			/// <para>This attribute is supported only on the client.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_Flags), CorrespondingAction.Get)]
			SECPKG_ATTR_SERVER_AUTH_FLAGS = 0x80000083,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_EapPrfInfo structure.
			/// <para>
			/// Sets the pseudo-random function (PRF) used by the Extensible Authentication Protocol (EAP). This is the value that is
			/// returned by a call to the QueryContextAttributes (Schannel) function when SECPKG_ATTR_EAP_KEY_BLOCK is passed as the value of
			/// the ulAttribute parameter.
			/// </para>
			/// <para>This attribute is supported only by the Schannel security package.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_EapPrfInfo), CorrespondingAction.Set)]
			SECPKG_ATTR_EAP_PRF_INFO = 101,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_EarlyStart structure.
			/// <para>Sets the False Start feature. See the Building a faster and more secure web blog post for information on this feature.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_EarlyStart), CorrespondingAction.Set)]
			SECPKG_ATTR_EARLY_START = 105,

			/// <summary>
			/// Sets and retrieves the MTU (maximum transmission unit) value for use with DTLS. If DTLS is not enabled in a security context,
			/// this attribute is not supported.
			/// <para>Valid values are between 200 bytes and 64 kilobytes. The default DTLS MTU value in Schannel is 1096 bytes.</para>
			/// </summary>
			[CorrespondingType(typeof(ushort), CorrespondingAction.Set)]
			SECPKG_ATTR_DTLS_MTU = 34,

			/// <summary>
			/// The pBuffer parameter contains a pointer to a SecPkgContext_KeyingMaterialInfo structure. The keying material export feature
			/// follows the RFC 5705 standard.
			/// <para>This attribute is supported only by the Schannel security package in Windows 10 and Windows Server 2016 or later versions.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgContext_KeyingMaterialInfo), CorrespondingAction.Set)]
			SECPKG_ATTR_KEYING_MATERIAL_INFO = 106,
		}

		/// <summary>
		/// <para>
		/// Indicates whether the token from the most recent call to the InitializeSecurityContext function is the last token from the client.
		/// </para>
		/// <para>This enumeration is used in the SecPkgContext_LastClientTokenStatus structure.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ne-sspi-secpkg_attr_lct_status typedef enum _SECPKG_ATTR_LCT_STATUS {
		// SecPkgAttrLastClientTokenYes, SecPkgAttrLastClientTokenNo, SecPkgAttrLastClientTokenMaybe } SECPKG_ATTR_LCT_STATUS, *PSECPKG_ATTR_LCT_STATUS;
		[PInvokeData("sspi.h", MSDNShortId = "b9067862-2339-4543-a8cd-610e6f921bfd")]
		public enum SECPKG_ATTR_LCT_STATUS
		{
			/// <summary>The token is the last token from the client.</summary>
			SecPkgAttrLastClientTokenYes,

			/// <summary>The token is not the last token from the client.</summary>
			SecPkgAttrLastClientTokenNo,

			/// <summary>It is not known whether the token is the last token from the client.</summary>
			SecPkgAttrLastClientTokenMaybe,
		}

		/// <summary>Bit flags that describe the capabilities of the security package.</summary>
		[PInvokeData("sspi.h", MSDNShortId = "d0bff3d8-63f1-4a4e-851f-177040af6bd2")]
		[Flags]
		public enum SECPKG_CALLFLAGS
		{
			/// <summary>The caller is an app container.</summary>
			SECPKG_CALLFLAGS_APPCONTAINER = 0x00000001,

			/// <summary>The caller can use default credentials.</summary>
			SECPKG_CALLFLAGS_AUTHCAPABLE = 0x00000002,

			/// <summary>The caller can only use supplied credentials.</summary>
			SECPKG_CALLFLAGS_FORCE_SUPPLIED = 0x00000004,

			/// <summary/>
			SECPKG_CALLFLAGS_APPCONTAINER_UPNCAPABLE = 0x00000008,
		}

		/// <summary>Flags for <c>ExportSecurityContext</c>.</summary>
		[PInvokeData("sspi.h", MSDNShortId = "4ebc7f37-b948-4c78-973f-0a74e55c7ee2")]
		[Flags]
		public enum SECPKG_CONTEXT_EXPORT
		{
			/// <summary>The new security context is reset to its initial state.</summary>
			SECPKG_CONTEXT_EXPORT_RESET_NEW = 1,

			/// <summary>The old security context is deleted.</summary>
			SECPKG_CONTEXT_EXPORT_DELETE_OLD = 2,

			/// <summary>
			/// This value is not supported.
			/// <para>
			/// Windows Server 2003 and Windows XP/2000: The security context is to be exported to the kernel.This value is supported only in
			/// Schannel kernel mode.
			/// </para>
			/// </summary>
			SECPKG_CONTEXT_EXPORT_TO_KERNEL = 4,
		}

		/// <summary>A flag that indicates how credentials will be used.</summary>
		[PInvokeData("sspi.h", MSDNShortId = "3b73decf-75d4-4bc4-b7ca-5f16aaadff29")]
		public enum SECPKG_CRED
		{
			/// <summary>Allow a local client credential to prepare an outgoing token.</summary>
			SECPKG_CRED_OUTBOUND = 0x2,

			/// <summary>
			/// Validate an incoming server credential. Inbound credentials might be validated by using an authenticating authority when
			/// InitializeSecurityContext (CredSSP) or AcceptSecurityContext (CredSSP) is called. If such an authority is not available, the
			/// function will fail and return SEC_E_NO_AUTHENTICATING_AUTHORITY. Validation is package specific.
			/// </summary>
			SECPKG_CRED_INBOUND = 0x1,

			/// <summary/>
			SECPKG_CRED_BOTH = 0x3,

			/// <summary/>
			SECPKG_CRED_DEFAULT = 0x4
		}

		/// <summary>Specifies the attribute to query.</summary>
		[PInvokeData("sspi.h", MSDNShortId = "a8ba6f73-8469-431b-b185-183b45b2c533")]
		public enum SECPKG_CRED_ATTR
		{
			/// <summary>
			/// Returns the certificate thumbprint in a pbuffer of type SecPkgCredentials_Cert.
			/// <para>This attribute is only supported by Kerberos.</para>
			/// <para>
			/// Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This attribute is
			/// not available.
			/// </para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgCredentials_Cert), CorrespondingAction.Get)]
			SECPKG_CRED_ATTR_CERT = 4,

			/// <summary>
			/// Returns the name of a credential in a pbuffer of type SecPkgCredentials_Names.
			/// <para>This attribute is not supported by Schannel in WOW64 mode.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgCredentials_Names))]
			SECPKG_CRED_ATTR_NAMES = 1,

			/// <summary>
			/// Returns the supported algorithms in a pbuffer of type SecPkgCred_SupportedAlgs. All supported algorithms are included,
			/// regardless of whether they are supported by the provided certificate or enabled on the local computer.
			/// <para>This attribute is supported only by Schannel.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgCred_SupportedAlgs))]
			SECPKG_ATTR_SUPPORTED_ALGS = 0x56,

			/// <summary>
			/// Returns the cipher strengths in a pbuffer of type SecPkgCred_CipherStrengths.
			/// <para>This attribute is supported only by Schannel.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgCred_CipherStrengths))]
			SECPKG_ATTR_CIPHER_STRENGTHS = 0x57,

			/// <summary>
			/// Returns the supported algorithms in a pbuffer of type SecPkgCred_SupportedProtocols. All supported protocols are included,
			/// regardless of whether they are supported by the provided certificate or enabled on the local computer.
			/// <para>This attribute is supported only by Schannel.</para>
			/// </summary>
			[CorrespondingType(typeof(SecPkgCred_SupportedProtocols))]
			SECPKG_ATTR_SUPPORTED_PROTOCOLS = 0x58,
		}

		/// <summary>
		/// Indicates the type of credential used in a client context. The <c>SECPKG_CRED_CLASS</c> enumeration is used in the
		/// SecPkgContext_CredInfo structure.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ne-sspi-_secpkg_cred_class typedef enum _SECPKG_CRED_CLASS {
		// SecPkgCredClass_None, SecPkgCredClass_Ephemeral, SecPkgCredClass_PersistedGeneric, SecPkgCredClass_PersistedSpecific,
		// SecPkgCredClass_Explicit } SECPKG_CRED_CLASS, *PSECPKG_CRED_CLASS;
		[PInvokeData("sspi.h", MSDNShortId = "2f5f9be2-e7b5-4d34-a2ad-89a99db78ad0")]
		public enum SECPKG_CRED_CLASS
		{
			/// <summary>No credentials are supplied.</summary>
			SecPkgCredClass_None = 0,

			/// <summary>Indicates the credentials used to log on to the system.</summary>
			SecPkgCredClass_Ephemeral = 10,

			/// <summary>Indicates saved credentials that are not target specific.</summary>
			SecPkgCredClass_PersistedGeneric = 20,

			/// <summary>Indicates saved credentials that are target specific.</summary>
			SecPkgCredClass_PersistedSpecific = 30,

			/// <summary>The sec PKG cred class explicit</summary>
			SecPkgCredClass_Explicit = 40,
		}

		/// <summary>Bit flags that describe the capabilities of the security package.</summary>
		[PInvokeData("sspi.h", MSDNShortId = "d0bff3d8-63f1-4a4e-851f-177040af6bd2")]
		[Flags]
		public enum SECPKG_FLAG : uint
		{
			/// <summary>The security package supports the MakeSignature and VerifySignature functions.</summary>
			SECPKG_FLAG_INTEGRITY = 0x1,

			/// <summary>The security package supports the EncryptMessage (General) and DecryptMessage (General) functions.</summary>
			SECPKG_FLAG_PRIVACY = 0x2,

			/// <summary>
			/// The package is interested only in the security-token portion of messages, and will ignore any other buffers. This is a
			/// performance-related issue.
			/// </summary>
			SECPKG_FLAG_TOKEN_ONLY = 0x4,

			/// <summary>
			/// Supports datagram-style authentication. For more information, see SSPI Context Semantics.
			/// <para>Important The Microsoft Kerberos package does not support datagram contexts in user-to-user mode.</para>
			/// </summary>
			SECPKG_FLAG_DATAGRAM = 0x8,

			/// <summary>Supports connection-oriented style authentication. For more information, see SSPI Context Semantics.</summary>
			SECPKG_FLAG_CONNECTION = 0x10,

			/// <summary>Multiple legs are required for authentication.</summary>
			SECPKG_FLAG_MULTI_REQUIRED = 0x20,

			/// <summary>Server authentication support is not provided.</summary>
			SECPKG_FLAG_CLIENT_ONLY = 0x40,

			/// <summary>Supports extended error handling. For more information, see Extended Error Information.</summary>
			SECPKG_FLAG_EXTENDED_ERROR = 0x80,

			/// <summary>Supports Windows impersonation in server contexts.</summary>
			SECPKG_FLAG_IMPERSONATION = 0x100,

			/// <summary>Understands Windows principal and target names.</summary>
			SECPKG_FLAG_ACCEPT_WIN32_NAME = 0x200,

			/// <summary>Supports stream semantics. For more information, see SSPI Context Semantics.</summary>
			SECPKG_FLAG_STREAM = 0x400,

			/// <summary>Can be used by the Microsoft Negotiate security package.</summary>
			SECPKG_FLAG_NEGOTIABLE = 0x800,

			/// <summary>Supports GSS compatibility.</summary>
			SECPKG_FLAG_GSS_COMPATIBLE = 0x1000,

			/// <summary>Supports LsaLogonUser.</summary>
			SECPKG_FLAG_LOGON = 0x2000,

			/// <summary>Token buffers are in ASCII characters format.</summary>
			SECPKG_FLAG_ASCII_BUFFERS = 0x4000,

			/// <summary>
			/// Supports separating large tokens into smaller buffers so that applications can make repeated calls to
			/// InitializeSecurityContext (General) and AcceptSecurityContext (General) with the smaller buffers to complete authentication.
			/// </summary>
			SECPKG_FLAG_FRAGMENT = 0x8000,

			/// <summary>Supports mutual authentication.</summary>
			SECPKG_FLAG_MUTUAL_AUTH = 0x10000,

			/// <summary>Supports delegation.</summary>
			SECPKG_FLAG_DELEGATION = 0x20000,

			/// <summary>
			/// The security package supports using a checksum instead of in-place encryption when calling the EncryptMessage function.
			/// </summary>
			SECPKG_FLAG_READONLY_WITH_CHECKSUM = 0x40000,

			/// <summary>Supports callers with restricted tokens.</summary>
			SECPKG_FLAG_RESTRICTED_TOKENS = 0x80000,

			/// <summary>
			/// The security package extends the Microsoft Negotiate security package. There can be at most one package of this type.
			/// </summary>
			SECPKG_FLAG_NEGO_EXTENDER = 0x00100000,

			/// <summary>This package is negotiated by the package of type SECPKG_FLAG_NEGO_EXTENDER.</summary>
			SECPKG_FLAG_NEGOTIABLE2 = 0x00200000,

			/// <summary>This package receives all calls from app container apps.</summary>
			SECPKG_FLAG_APPCONTAINER_PASSTHROUGH = 0x00400000,

			/// <summary>
			/// This package receives calls from app container apps if one of the following checks succeeds.
			/// <list type="bullet">
			/// <item>
			/// <term>Caller has default credentials capability.</term>
			/// </item>
			/// <item>
			/// <term>The target is a proxy server.</term>
			/// </item>
			/// <item>
			/// <term>The caller has supplied credentials.</term>
			/// </item>
			/// </list>
			/// </summary>
			SECPKG_FLAG_APPCONTAINER_CHECKS = 0x00800000,

			/// <summary>This package is running with Credential Guard enabled.</summary>
			SECPKG_FLAG_CREDENTIAL_ISOLATION_ENABLED = 0x01000000,

			/// <summary/>
			SECPKG_FLAG_UNDOCUMENTED1 = 0x02000000,
		}

		/// <summary>The type of security package.</summary>
		[PInvokeData("sspi.h", MSDNShortId = "2e9f65ec-72a5-4d6f-aa63-f83369f0dd07")]
		public enum SECPKG_OPTIONS_TYPE
		{
			/// <summary>The package type is not known.</summary>
			SECPKG_OPTIONS_TYPE_UNKNOWN = 0,

			/// <summary>The security package is an LSA authentication package.</summary>
			SECPKG_OPTIONS_TYPE_LSA = 1,

			/// <summary>The security package is a Security Support Provider Interface (SSPI) package.</summary>
			SECPKG_OPTIONS_TYPE_SSPI = 2,
		}

		/// <summary>Package-specific flags that indicate the quality of protection.</summary>
		[PInvokeData("Sspi.h", MSDNShortId = "aa375348")]
		[Flags]
		public enum SECQOP : uint
		{
			/// <summary>The message is not encrypted, but a header or trailer is present.</summary>
			SECQOP_WRAP_NO_ENCRYPT = 0x80000001,

			/// <summary>
			/// Send an Schannel alert message. In this case, the pMessage parameter must contain a standard two-byte SSL/TLS event code.
			/// This value is supported only by the Schannel SSP.
			/// </summary>
			SECQOP_WRAP_OOB_DATA = 0x40000000,
		}

		/// <summary>
		/// The <c>AcceptSecurityContext (CredSSP)</c> function lets the server component of a transport application establish a security
		/// context between the server and a remote client. The remote client calls the InitializeSecurityContext (CredSSP) function to start
		/// the process of establishing a security context. The server can require one or more reply tokens from the remote client to
		/// complete establishing the security context.
		/// </summary>
		/// <param name="phCredential">
		/// A handle to the server credentials. To retrieve this handle, the server calls the AcquireCredentialsHandle (CredSSP) function
		/// with either the SECPKG_CRED_INBOUND or SECPKG_CRED_BOTH flag set.
		/// </param>
		/// <param name="phContext">
		/// A pointer to a CtxtHandle structure. On the first call to <c>AcceptSecurityContext (CredSSP)</c>, this pointer is <c>NULL</c>. On
		/// subsequent calls, phContext specifies the partially formed context returned in the phNewContext parameter by the first call.
		/// </param>
		/// <param name="pInput">
		/// <para>
		/// A pointer to a SecBufferDesc structure generated by a client call to InitializeSecurityContext (CredSSP). The structure contains
		/// the input buffer descriptor.
		/// </para>
		/// <para>
		/// The first buffer must be of type <c>SECBUFFER_TOKEN</c> and contain the security token received from the client. The second
		/// buffer should be of type <c>SECBUFFER_EMPTY</c>.
		/// </para>
		/// </param>
		/// <param name="fContextReq">
		/// <para>
		/// -Bit flags that specify the attributes required by the server to establish the context. Bit flags can be combined by using
		/// bitwise- <c>OR</c> operations. This parameter can be one or more of the following values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>ASC_REQ_ALLOCATE_MEMORY</term>
		/// <term>
		/// Credential Security Support Provider (CredSSP) will allocate output buffers. When you have finished using the output buffers,
		/// free them by calling the FreeContextBuffer function.
		/// </term>
		/// </item>
		/// <item>
		/// <term>ASC_REQ_CONNECTION</term>
		/// <term>The security context will not handle formatting messages.</term>
		/// </item>
		/// <item>
		/// <term>ASC_REQ_DELEGATE</term>
		/// <term>The server is allowed to impersonate the client. Ignore this flag for constrained delegation.</term>
		/// </item>
		/// <item>
		/// <term>ASC_REQ_EXTENDED_ERROR</term>
		/// <term>When errors occur, the remote party will be notified.</term>
		/// </item>
		/// <item>
		/// <term>ASC_REQ_REPLAY_DETECT</term>
		/// <term>Detect replayed packets.</term>
		/// </item>
		/// <item>
		/// <term>ASC_REQ_SEQUENCE_DETECT</term>
		/// <term>Detect messages received out of sequence.</term>
		/// </item>
		/// <item>
		/// <term>ASC_REQ_STREAM</term>
		/// <term>Support a stream-oriented connection.</term>
		/// </item>
		/// </list>
		/// <para>
		/// For possible attribute flags and their meanings, see Context Requirements. Flags used for this parameter are prefixed with
		/// ASC_REQ, for example, ASC_REQ_DELEGATE.
		/// </para>
		/// <para>The requested attributes may not be supported by the client. For more information, see the pfContextAttr parameter.</para>
		/// </param>
		/// <param name="TargetDataRep">
		/// The data representation, such as byte ordering, on the target. This parameter can be either <c>SECURITY_NATIVE_DREP</c> or <c>SECURITY_NETWORK_DREP</c>.
		/// </param>
		/// <param name="phNewContext">
		/// A pointer to a CtxtHandle structure. On the first call to <c>AcceptSecurityContext (CredSSP)</c>, this pointer receives the new
		/// context handle. On subsequent calls, phNewContext can be the same as the handle specified in the phContext parameter.
		/// </param>
		/// <param name="pOutput">
		/// <para>
		/// A pointer to a SecBufferDesc structure that contains the output buffer descriptor. This buffer is sent to the client for input
		/// into additional calls to InitializeSecurityContext (CredSSP). An output buffer may be generated even if the function returns
		/// SEC_E_OK. Any buffer generated must be sent back to the client application.
		/// </para>
		/// <para>
		/// On output, this buffer receives a token for the security context. The token must be sent to the client. The function can also
		/// return a buffer of type SECBUFFER_EXTRA.
		/// </para>
		/// </param>
		/// <param name="pfContextAttr">
		/// <para>
		/// A pointer to a set of bit flags that indicate the attributes of the established context. For a description of the various
		/// attributes, see Context Requirements. Flags used for this parameter are prefixed with ASC_RET, for example, ASC_RET_DELEGATE.
		/// </para>
		/// <para>
		/// Do not check for security-related attributes until the final function call returns successfully. Attribute flags not related to
		/// security, such as the ASC_RET_ALLOCATED_MEMORY flag, can be checked before the final return.
		/// </para>
		/// </param>
		/// <param name="ptsTimeStamp">The PTS time stamp.</param>
		/// <returns>
		/// <para>This function returns one of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code/value</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INCOMPLETE_MESSAGE 0x80090318L</term>
		/// <term>
		/// The function succeeded. The data in the input buffer is incomplete. The application must read additional data from the client and
		/// call AcceptSecurityContext (CredSSP) again.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INSUFFICIENT_MEMORY 0x80090300L</term>
		/// <term>The function failed. There is not enough memory available to complete the requested action.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INTERNAL_ERROR 0x80090304L</term>
		/// <term>The function failed. An error occurred that did not map to an SSPI error code.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE 0x80100003L</term>
		/// <term>The function failed. The handle passed to the function is not valid.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_TOKEN 0x80090308L</term>
		/// <term>The function failed. The token passed to the function is not valid.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_LOGON_DENIED 0x8009030CL</term>
		/// <term>The logon failed.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_NO_AUTHENTICATING_AUTHORITY 0x80090311L</term>
		/// <term>The function failed. No authority could be contacted for authentication. This could be due to the following conditions:</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_NO_CREDENTIALS 0x8009030EL</term>
		/// <term>The function failed. The credentials handle specified in the phCredential parameter is not valid.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_OK 0x00000000L</term>
		/// <term>
		/// The function succeeded. The security context received from the client was accepted. If the function generated an output token,
		/// the token must be sent to the client process.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_UNSUPPORTED_FUNCTION 0x80090302L</term>
		/// <term>
		/// The function failed. The fContextReq parameter specified a context attribute flag (ASC_REQ_DELEGATE or ASC_REQ_PROMPT_FOR_CREDS)
		/// that was not valid.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_I_COMPLETE_AND_CONTINUE 0x00090314L</term>
		/// <term>
		/// The function succeeded. The server must call CompleteAuthToken and pass the output token to the client. The server must then wait
		/// for a return token from the client before making another call to AcceptSecurityContext (CredSSP).
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_I_COMPLETE_NEEDED 0x00090313L</term>
		/// <term>The function succeeded. The server must finish building the message from the client before calling CompleteAuthToken.</term>
		/// </item>
		/// <item>
		/// <term>SEC_I_CONTINUE_NEEDED 0x00090312L</term>
		/// <term>
		/// The function succeeded. The server must send the output token to the client and wait for a returned token. The returned token
		/// should be passed in pInput for another call to AcceptSecurityContext (CredSSP).
		/// </term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The <c>AcceptSecurityContext (CredSSP)</c> function is the server counterpart to the InitializeSecurityContext (CredSSP) function.
		/// </para>
		/// <para>
		/// When the server receives a request from a client, it uses the fContextReq parameter to specify what it requires of the session.
		/// In this fashion, a server can require that clients be capable of using a confidential or integrity-checked session; it can reject
		/// clients that cannot meet that demand. Alternatively, a server can require nothing; whatever the client requires or can provide is
		/// returned in the pfContextAttr parameter.
		/// </para>
		/// <para>
		/// The fContextReq and pfContextAttr parameters are bitmasks that represent various context attributes. For a description of the
		/// various attributes, see Context Requirements.
		/// </para>
		/// <para>
		/// <c>Note</c> While the pfContextAttr parameter is valid on any successful return, you should examine the flags pertaining to
		/// security aspects of the context only on the final successful return. Intermediate returns can set, for example, the
		/// ISC_RET_ALLOCATED_MEMORY flag.
		/// </para>
		/// <para>
		/// The caller is responsible for determining whether the final context attributes are sufficient. For example, if confidentiality
		/// (encryption) was requested but could not be established, some applications may choose to shut down the connection immediately. If
		/// the security context cannot be established, the server must free the partially created context by calling the
		/// DeleteSecurityContext function. For information about when to call the <c>DeleteSecurityContext</c> function, see <c>DeleteSecurityContext</c>.\
		/// </para>
		/// <para>
		/// After the security context has been established, the server application can use the QuerySecurityContextToken function to
		/// retrieve a handle to the user account to which the client certificate was mapped. Also, the server can use the
		/// ImpersonateSecurityContext function to impersonate the user.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-acceptsecuritycontext KSECDDDECLSPEC SECURITY_STATUS SEC_ENTRY
		// AcceptSecurityContext( PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, unsigned long fContextReq, unsigned
		// long TargetDataRep, PCtxtHandle phNewContext, PSecBufferDesc pOutput, unsigned long *pfContextAttr, PTimeStamp ptsExpiry );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "a53f733e-b646-4431-b021-a2c446308849")]
		public static unsafe extern HRESULT AcceptSecurityContext([Optional] CredHandle* phCredential, CtxtHandle* phContext, [In, Optional] SecBufferDesc* pInput, ASC_REQ fContextReq, DREP TargetDataRep,
			out CtxtHandle phNewContext, [Optional] SecBufferDesc* pOutput, out ASC_RET pfContextAttr, out TimeStamp ptsTimeStamp);

		/// <summary>
		/// <para>
		/// The <c>AcquireCredentialsHandle (CredSSP)</c> function acquires a handle to preexisting credentials of a security principal. This
		/// handle is required by the InitializeSecurityContext (CredSSP) and AcceptSecurityContext (CredSSP) functions. These can be either
		/// preexisting credentials, which are established through a system logon that is not described here, or the caller can provide
		/// alternative credentials.
		/// </para>
		/// <para><c>Note</c> This is not a "log on to the network" and does not imply gathering of credentials.</para>
		/// </summary>
		/// <param name="pszPrincipal">
		/// <para>A pointer to a null-terminated string that specifies the name of the principal whose credentials the handle will reference.</para>
		/// <para>
		/// <c>Note</c> If the process that requests the handle does not have access to the credentials, the function returns an error. A
		/// null string indicates that the process requires a handle to the credentials of the user under whose security context it is executing.
		/// </para>
		/// </param>
		/// <param name="pszPackage">
		/// A pointer to a null-terminated string that specifies the name of the security package with which these credentials will be used.
		/// This is a security package name returned in the <c>Name</c> member of a SecPkgInfo structure returned by the
		/// EnumerateSecurityPackages function. After a context is established, QueryContextAttributes (CredSSP) can be called with
		/// ulAttribute set to <c>SECPKG_ATTR_PACKAGE_INFO</c> to return information on the security package in use.
		/// </param>
		/// <param name="fCredentialUse">
		/// <para>A flag that indicates how these credentials will be used. This parameter can be one of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SECPKG_CRED_INBOUND 0x1</term>
		/// <term>
		/// Validate an incoming server credential. Inbound credentials might be validated by using an authenticating authority when
		/// InitializeSecurityContext (CredSSP) or AcceptSecurityContext (CredSSP) is called. If such an authority is not available, the
		/// function will fail and return SEC_E_NO_AUTHENTICATING_AUTHORITY. Validation is package specific.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_CRED_OUTBOUND 0x0</term>
		/// <term>Allow a local client credential to prepare an outgoing token.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pvLogonId">
		/// A pointer to a locally unique identifier (LUID) that identifies the user. This parameter is provided for file-system processes
		/// such as network redirectors. This parameter can be <c>NULL</c>.
		/// </param>
		/// <param name="pAuthData">
		/// A pointer to a CREDSSP_CRED structure that specifies authentication data for both Schannel and Negotiate packages.
		/// </param>
		/// <param name="pGetKeyFn">Reserved. This parameter is not used and should be set to <c>NULL</c>.</param>
		/// <param name="pvGetKeyArgument">Reserved. This parameter must be set to <c>NULL</c>.</param>
		/// <param name="phCredential">A pointer to the CredHandle structure that will receive the credential handle.</param>
		/// <param name="ptsExpiry">
		/// A pointer to a TimeStamp structure that receives the time at which the returned credentials expire. The structure value received
		/// depends on the security package, which must specify the value in local time.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns one of the following error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INSUFFICIENT_MEMORY</term>
		/// <term>There is insufficient memory available to complete the requested action.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INTERNAL_ERROR</term>
		/// <term>An error occurred that did not map to an SSPI error code.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_NO_CREDENTIALS</term>
		/// <term>No credentials are available in the security package.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_NOT_OWNER</term>
		/// <term>The caller of the function does not have the necessary credentials.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_SECPKG_NOT_FOUND</term>
		/// <term>The requested security package does not exist.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_UNKNOWN_CREDENTIALS</term>
		/// <term>The credentials supplied to the package were not recognized.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The <c>AcquireCredentialsHandle (CredSSP)</c> function returns a handle to the credentials of a principal, such as a user or
		/// client, as used by a specific security package. The function can return the handle to either preexisting credentials or newly
		/// created credentials and return it. This handle can be used in subsequent calls to the AcceptSecurityContext (CredSSP) and
		/// InitializeSecurityContext (CredSSP) functions.
		/// </para>
		/// <para>
		/// In general, <c>AcquireCredentialsHandle (CredSSP)</c> does not provide the credentials of other users logged on to the same
		/// computer. However, a caller with SE_TCB_NAME privilege can obtain the credentials of an existing logon session by specifying the
		/// logon identifier (LUID) of that session. Typically, this is used by kernel-mode modules that must act on behalf of a logged-on user.
		/// </para>
		/// <para>
		/// A package might call the function in pGetKeyFn provided by the RPC run-time transport. If the transport does not support the
		/// notion of callback to retrieve credentials, this parameter must be <c>NULL</c>.
		/// </para>
		/// <para>For kernel mode callers, the following differences must be noted:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>The two string parameters must be Unicode strings.</term>
		/// </item>
		/// <item>
		/// <term>The buffer values must be allocated in process virtual memory, not from the pool.</term>
		/// </item>
		/// </list>
		/// <para>
		/// When you have finished using the returned credentials, free the memory used by the credentials by calling the
		/// FreeCredentialsHandle function.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-acquirecredentialshandlea SECURITY_STATUS SEC_ENTRY
		// AcquireCredentialsHandleA( LPSTR pszPrincipal, LPSTR pszPackage, unsigned long fCredentialUse, void *pvLogonId, void *pAuthData,
		// SEC_GET_KEY_FN pGetKeyFn, void *pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "3b73decf-75d4-4bc4-b7ca-5f16aaadff29")]
		public static extern HRESULT AcquireCredentialsHandle([Optional] string pszPrincipal, string pszPackage, SECPKG_CRED fCredentialUse, [In, Optional] IntPtr pvLogonId, [In, Optional] IntPtr pAuthData, [In, Optional] IntPtr pGetKeyFn,
			[In, Optional] IntPtr pvGetKeyArgument, out CredHandle phCredential, out TimeStamp ptsExpiry);

		/// <summary>
		/// <para>
		/// The <c>AcquireCredentialsHandle (CredSSP)</c> function acquires a handle to preexisting credentials of a security principal. This
		/// handle is required by the InitializeSecurityContext (CredSSP) and AcceptSecurityContext (CredSSP) functions. These can be either
		/// preexisting credentials, which are established through a system logon that is not described here, or the caller can provide
		/// alternative credentials.
		/// </para>
		/// <para><c>Note</c> This is not a "log on to the network" and does not imply gathering of credentials.</para>
		/// </summary>
		/// <param name="pszPrincipal">
		/// <para>A pointer to a null-terminated string that specifies the name of the principal whose credentials the handle will reference.</para>
		/// <para>
		/// <c>Note</c> If the process that requests the handle does not have access to the credentials, the function returns an error. A
		/// null string indicates that the process requires a handle to the credentials of the user under whose security context it is executing.
		/// </para>
		/// </param>
		/// <param name="pszPackage">
		/// A pointer to a null-terminated string that specifies the name of the security package with which these credentials will be used.
		/// This is a security package name returned in the <c>Name</c> member of a SecPkgInfo structure returned by the
		/// EnumerateSecurityPackages function. After a context is established, QueryContextAttributes (CredSSP) can be called with
		/// ulAttribute set to <c>SECPKG_ATTR_PACKAGE_INFO</c> to return information on the security package in use.
		/// </param>
		/// <param name="fCredentialUse">
		/// <para>A flag that indicates how these credentials will be used. This parameter can be one of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SECPKG_CRED_INBOUND 0x1</term>
		/// <term>
		/// Validate an incoming server credential. Inbound credentials might be validated by using an authenticating authority when
		/// InitializeSecurityContext (CredSSP) or AcceptSecurityContext (CredSSP) is called. If such an authority is not available, the
		/// function will fail and return SEC_E_NO_AUTHENTICATING_AUTHORITY. Validation is package specific.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_CRED_OUTBOUND 0x0</term>
		/// <term>Allow a local client credential to prepare an outgoing token.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pvLogonId">
		/// A pointer to a locally unique identifier (LUID) that identifies the user. This parameter is provided for file-system processes
		/// such as network redirectors. This parameter can be <c>NULL</c>.
		/// </param>
		/// <param name="pAuthData">
		/// A pointer to a CREDSSP_CRED structure that specifies authentication data for both Schannel and Negotiate packages.
		/// </param>
		/// <param name="pGetKeyFn">Reserved. This parameter is not used and should be set to <c>NULL</c>.</param>
		/// <param name="pvGetKeyArgument">Reserved. This parameter must be set to <c>NULL</c>.</param>
		/// <param name="phCredential">A pointer to the CredHandle structure that will receive the credential handle.</param>
		/// <param name="ptsExpiry">
		/// A pointer to a TimeStamp structure that receives the time at which the returned credentials expire. The structure value received
		/// depends on the security package, which must specify the value in local time.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns one of the following error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INSUFFICIENT_MEMORY</term>
		/// <term>There is insufficient memory available to complete the requested action.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INTERNAL_ERROR</term>
		/// <term>An error occurred that did not map to an SSPI error code.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_NO_CREDENTIALS</term>
		/// <term>No credentials are available in the security package.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_NOT_OWNER</term>
		/// <term>The caller of the function does not have the necessary credentials.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_SECPKG_NOT_FOUND</term>
		/// <term>The requested security package does not exist.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_UNKNOWN_CREDENTIALS</term>
		/// <term>The credentials supplied to the package were not recognized.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The <c>AcquireCredentialsHandle (CredSSP)</c> function returns a handle to the credentials of a principal, such as a user or
		/// client, as used by a specific security package. The function can return the handle to either preexisting credentials or newly
		/// created credentials and return it. This handle can be used in subsequent calls to the AcceptSecurityContext (CredSSP) and
		/// InitializeSecurityContext (CredSSP) functions.
		/// </para>
		/// <para>
		/// In general, <c>AcquireCredentialsHandle (CredSSP)</c> does not provide the credentials of other users logged on to the same
		/// computer. However, a caller with SE_TCB_NAME privilege can obtain the credentials of an existing logon session by specifying the
		/// logon identifier (LUID) of that session. Typically, this is used by kernel-mode modules that must act on behalf of a logged-on user.
		/// </para>
		/// <para>
		/// A package might call the function in pGetKeyFn provided by the RPC run-time transport. If the transport does not support the
		/// notion of callback to retrieve credentials, this parameter must be <c>NULL</c>.
		/// </para>
		/// <para>For kernel mode callers, the following differences must be noted:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>The two string parameters must be Unicode strings.</term>
		/// </item>
		/// <item>
		/// <term>The buffer values must be allocated in process virtual memory, not from the pool.</term>
		/// </item>
		/// </list>
		/// <para>
		/// When you have finished using the returned credentials, free the memory used by the credentials by calling the
		/// FreeCredentialsHandle function.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-acquirecredentialshandlea SECURITY_STATUS SEC_ENTRY
		// AcquireCredentialsHandleA( LPSTR pszPrincipal, LPSTR pszPackage, unsigned long fCredentialUse, void *pvLogonId, void *pAuthData,
		// SEC_GET_KEY_FN pGetKeyFn, void *pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "3b73decf-75d4-4bc4-b7ca-5f16aaadff29")]
		public static extern HRESULT AcquireCredentialsHandle([Optional] string pszPrincipal, string pszPackage, SECPKG_CRED fCredentialUse, in LUID pvLogonId, in CREDSSP_CRED pAuthData, [In, Optional] SEC_GET_KEY_FN pGetKeyFn,
			[In, Optional] IntPtr pvGetKeyArgument, out CredHandle phCredential, out TimeStamp ptsExpiry);

		/// <summary>Adds a security support provider to the list of providers supported by Microsoft Negotiate.</summary>
		/// <param name="pszPackageName">The name of the package to add.</param>
		/// <param name="pOptions">
		/// A pointer to a SECURITY_PACKAGE_OPTIONS structure that specifies additional information about the security package.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-addsecuritypackagea SECURITY_STATUS SEC_ENTRY
		// AddSecurityPackageA( LPSTR pszPackageName, PSECURITY_PACKAGE_OPTIONS pOptions );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "35b993d2-87a0-46d0-991f-88358b0cc5e6")]
		public static extern HRESULT AddSecurityPackage(string pszPackageName, in SECURITY_PACKAGE_OPTIONS pOptions);

		/// <summary>Adds a security support provider to the list of providers supported by Microsoft Negotiate.</summary>
		/// <param name="pszPackageName">The name of the package to add.</param>
		/// <param name="pOptions">
		/// A pointer to a SECURITY_PACKAGE_OPTIONS structure that specifies additional information about the security package.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-addsecuritypackagea SECURITY_STATUS SEC_ENTRY
		// AddSecurityPackageA( LPSTR pszPackageName, PSECURITY_PACKAGE_OPTIONS pOptions );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "35b993d2-87a0-46d0-991f-88358b0cc5e6")]
		public static extern HRESULT AddSecurityPackage(string pszPackageName, [Optional] IntPtr pOptions);

		/// <summary>
		/// <para>
		/// The <c>ApplyControlToken</c> function provides a way to apply a control token to a security context. A token can be received when
		/// the security context is being established by a call to the InitializeSecurityContext (Schannel) function or with a per-message
		/// security service, such as verify or unseal.
		/// </para>
		/// <para>This function is supported only by the Schannel security support provider (SSP).</para>
		/// <para>This function is not supported in kernel mode.</para>
		/// <para>This function allows additional or replacement tokens to be applied to a context.</para>
		/// </summary>
		/// <param name="phContext">
		/// <para>A handle to the context to which the token is applied.</para>
		/// <para>
		/// For information about the way the Schannel SSP notifies the remote party of the shutdown, see the Remarks section of
		/// DecryptMessage (Schannel). For additional information on the use of this function, see Shutting Down an Schannel Connection.
		/// </para>
		/// </param>
		/// <param name="pInput">
		/// A pointer to a SecBufferDesc structure that contains a pointer to a SecBuffer structure that contains the input token to apply to
		/// the context.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns SEC_E_OK.</para>
		/// <para>
		/// If the function fails, it returns a nonzero error code. The following error code is one of the possible error codes that can be returned.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_UNSUPPORTED_FUNCTION</term>
		/// <term>This value is returned by Schannel kernel mode to indicate that this function is not supported.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The <c>ApplyControlToken</c> function can modify the context based on this token. Among the tokens that this function can add to
		/// the client context are SCHANNEL_ALERT_TOKEN and SCHANNEL_SESSION_TOKEN.
		/// </para>
		/// <para>
		/// This function can be used to shut down the security context that underlies an existing Schannel connection. For information about
		/// how to do this, see Shutting Down an Schannel Connection.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-applycontroltoken KSECDDDECLSPEC SECURITY_STATUS SEC_ENTRY
		// ApplyControlToken( PCtxtHandle phContext, PSecBufferDesc pInput );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "5ce13a05-874c-4e1a-9be8-aed98609791e")]
		public static extern HRESULT ApplyControlToken(in CtxtHandle phContext, in SecBufferDesc pInput);

		/// <summary>
		/// <para>
		/// The <c>ChangeAccountPassword</c> function changes the password for a Windows domain account by using the specified Security
		/// Support Provider.
		/// </para>
		/// <para>This function is supported only by the Microsoft Kerberos, Microsoft Negotiate, and Microsoft NTLM providers.</para>
		/// </summary>
		/// <param name="pszPackageName">
		/// The name of the provider to use. The value of this parameter must be either "Kerberos", "Negotiate", or "NTLM".
		/// </param>
		/// <param name="pszDomainName">The domain of the account for which to change the password.</param>
		/// <param name="pszAccountName">The user name of the account for which to change the password.</param>
		/// <param name="pszOldPassword">The old password to be changed.</param>
		/// <param name="pszNewPassword">The new password for the specified account.</param>
		/// <param name="bImpersonating"><c>TRUE</c> if the calling process is running as the client; otherwise, <c>FALSE</c>.</param>
		/// <param name="dwReserved">Reserved. Must be set to zero.</param>
		/// <param name="pOutput">
		/// On input, a pointer to a SecBufferDesc structure. The <c>SecBufferDesc</c> structure must contain a single buffer of type
		/// <c>SECBUFFER_CHANGE_PASS_RESPONSE</c>. On output, the <c>pvBuffer</c> member of that structure points to a
		/// DOMAIN_PASSWORD_INFORMATION structure.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns SEC_E_OK.</para>
		/// <para>If the function fails, it returns an error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-changeaccountpassworda SECURITY_STATUS SEC_ENTRY
		// ChangeAccountPasswordA( SEC_CHAR *pszPackageName, SEC_CHAR *pszDomainName, SEC_CHAR *pszAccountName, SEC_CHAR *pszOldPassword,
		// SEC_CHAR *pszNewPassword, BOOLEAN bImpersonating, unsigned long dwReserved, PSecBufferDesc pOutput );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "a1d1e315-d1a2-499a-b552-83180508271f")]
		public static extern HRESULT ChangeAccountPassword(string pszPackageName, string pszDomainName, string pszAccountName, string pszOldPassword, string pszNewPassword, [MarshalAs(UnmanagedType.U1)] bool bImpersonating,
			[Optional] uint dwReserved, ref SecBufferDesc pOutput);

		/// <summary>
		/// <para>
		/// The <c>CompleteAuthToken</c> function completes an authentication token. This function is used by protocols, such as DCE, that
		/// need to revise the security information after the transport application has updated some message parameters.
		/// </para>
		/// <para>This function is supported only by the Digest security support provider (SSP).</para>
		/// <para><c>CompleteAuthToken</c> is used on the server side only.</para>
		/// </summary>
		/// <param name="phContext">A handle of the context that needs to be completed.</param>
		/// <param name="pToken">A pointer to a SecBufferDesc structure that contains the buffer descriptor for the entire message.</param>
		/// <returns>
		/// <para>If the function succeeds, the function returns SEC_E_OK.</para>
		/// <para>If the function fails, it returns one of the following error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The handle that was passed to the function is not valid.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_TOKEN</term>
		/// <term>The token that was passed to the function is not valid.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_OUT_OF_SEQUENCE</term>
		/// <term>
		/// The client's security context was located, but the message number is incorrect. This return value is used with the Digest SSP.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_MESSAGE_ALTERED</term>
		/// <term>
		/// The client's security context was located, but the client's message has been tampered with. This return value is used with the
		/// Digest SSP.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INTERNAL_ERROR</term>
		/// <term>An error occurred that did not map to an SSPI error code.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// The client of a transport application calls the <c>CompleteAuthToken</c> function to allow the security package to update a
		/// checksum or similar operation after all the protocol headers have been updated by the transport application. The client calls
		/// this function only if the InitializeSecurityContext (Digest) call returned SEC_I_COMPLETE_NEEDED or SEC_I_COMPLETE_AND_CONTINUE.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-completeauthtoken SECURITY_STATUS SEC_ENTRY CompleteAuthToken(
		// PCtxtHandle phContext, PSecBufferDesc pToken );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "a404d0a3-d1ea-4708-87d7-2d216e9a5f5f")]
		public static extern HRESULT CompleteAuthToken(in CtxtHandle phContext, in SecBufferDesc pToken);

		/// <summary>
		/// <para>
		/// The <c>DecryptMessage (Digest)</c> function decrypts a message. Some packages do not encrypt and decrypt messages but rather
		/// perform and check an integrity hash.
		/// </para>
		/// <para>
		/// The Digest security support provider (SSP) provides encryption and decryption confidentiality for messages exchanged between
		/// client and server as a SASL mechanism only.
		/// </para>
		/// <para>
		/// <c>Note</c> EncryptMessage (Digest) and <c>DecryptMessage (Digest)</c> can be called at the same time from two different threads
		/// in a single Security Support Provider Interface (SSPI) context if one thread is encrypting and the other is decrypting. If more
		/// than one thread is encrypting, or more than one thread is decrypting, each thread should obtain a unique context.
		/// </para>
		/// </summary>
		/// <param name="phContext">A handle to the security context to be used to decrypt the message.</param>
		/// <param name="pMessage">
		/// <para>
		/// A pointer to a SecBufferDesc structure. On input, the structure references one or more SecBuffer structures. At least one of
		/// these must be of type SECBUFFER_DATA. That buffer contains the encrypted message. The encrypted message is decrypted in place,
		/// overwriting the original contents of its buffer.
		/// </para>
		/// <para>
		/// When using the Digest SSP, on input, the structure references one or more SecBuffer structures. One of these must be of type
		/// SECBUFFER_DATA or SECBUFFER_STREAM, and it must contain the encrypted message.
		/// </para>
		/// </param>
		/// <param name="MessageSeqNo">
		/// <para>
		/// The sequence number expected by the transport application, if any. If the transport application does not maintain sequence
		/// numbers, this parameter must be set to zero.
		/// </para>
		/// <para>When using the Digest SSP, this parameter must be set to zero. The Digest SSP manages sequence numbering internally.</para>
		/// </param>
		/// <param name="pfQOP">
		/// <para>A pointer to a variable of type <c>ULONG</c> that receives package-specific flags that indicate the quality of protection.</para>
		/// <para>This parameter can be one of the following flags.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SECQOP_WRAP_NO_ENCRYPT</term>
		/// <term>The message was not encrypted, but a header or trailer was produced.</term>
		/// </item>
		/// <item>
		/// <term>SIGN_ONLY</term>
		/// <term>
		/// When using the Digest SSP, use this flag when the security context is set to verify the signature only. For more information, see
		/// Quality of Protection.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <returns>
		/// <para>If the function verifies that the message was received in the correct sequence, the function returns SEC_E_OK.</para>
		/// <para>If the function fails to decrypt the message, it returns one of the following error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_BUFFER_TOO_SMALL</term>
		/// <term>The message buffer is too small. Used with the Digest SSP.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_CRYPTO_SYSTEM_INVALID</term>
		/// <term>The cipher chosen for the security context is not supported. Used with the Digest SSP.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INCOMPLETE_MESSAGE</term>
		/// <term>
		/// The data in the input buffer is incomplete. The application needs to read more data from the server and call DecryptMessage
		/// (Digest) again.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>A context handle that is not valid was specified in the phContext parameter. Used with the Digest SSP.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_MESSAGE_ALTERED</term>
		/// <term>The message has been altered. Used with the Digest SSP.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_OUT_OF_SEQUENCE</term>
		/// <term>The message was not received in the correct sequence.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_QOP_NOT_SUPPORTED</term>
		/// <term>Neither confidentiality nor integrity are supported by the security context. Used with the Digest SSP.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// Sometimes an application will read data from the remote party, attempt to decrypt it by using <c>DecryptMessage (Digest)</c>, and
		/// discover that <c>DecryptMessage (Digest)</c> succeeded but the output buffers are empty. This is normal behavior, and
		/// applications must be able to deal with it.
		/// </para>
		/// <para>
		/// <c>Windows XP:</c> This function was also known as <c>UnsealMessage</c>. Applications should now use <c>DecryptMessage
		/// (Digest)</c> only.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-decryptmessage SECURITY_STATUS SEC_ENTRY DecryptMessage(
		// PCtxtHandle phContext, PSecBufferDesc pMessage, unsigned long MessageSeqNo, unsigned long *pfQOP );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "46d45f59-33fa-434a-b329-20b6257c9a19")]
		public static extern HRESULT DecryptMessage(in CtxtHandle phContext, ref SecBufferDesc pMessage, uint MessageSeqNo, out SECQOP pfQOP);

		/// <summary>
		/// The <c>DeleteSecurityContext</c> function deletes the local data structures associated with the specified security context
		/// initiated by a previous call to the InitializeSecurityContext (General) function or the AcceptSecurityContext (General) function.
		/// </summary>
		/// <param name="phContext">Handle of the security context to delete.</param>
		/// <returns>
		/// <para>If the function succeeds or the handle has already been deleted, the return value is <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, the return value can be the following error code.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The handle passed to the function is not valid.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>The <c>DeleteSecurityContext</c> function terminates a security context and frees associated resources.</para>
		/// <para>
		/// The caller must call this function for a security context when that security context is no longer needed. This is true if the
		/// security context is partial, incomplete, rejected, or failed. After the security context is successfully deleted, further use of
		/// that security context is not permitted and the handle is no longer valid.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-deletesecuritycontext KSECDDDECLSPEC SECURITY_STATUS SEC_ENTRY
		// DeleteSecurityContext( PCtxtHandle phContext );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "2a4dd697-ef90-4c37-ab74-0e5ab92794cd")]
		public static extern HRESULT DeleteSecurityContext(in CtxtHandle phContext);

		/// <summary>Deletes a security support provider from the list of providers supported by Microsoft Negotiate.</summary>
		/// <param name="pszPackageName">The name of the security provider to delete.</param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-deletesecuritypackagea SECURITY_STATUS SEC_ENTRY
		// DeleteSecurityPackageA( LPSTR pszPackageName );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "7a9a2c64-92a4-419b-8b20-d0f5cba64147")]
		public static extern HRESULT DeleteSecurityPackage(string pszPackageName);

		/// <summary>
		/// <para>
		/// The <c>EncryptMessage (Digest)</c> function encrypts a message to provide privacy. <c>EncryptMessage (Digest)</c> allows the
		/// application to choose among cryptographic algorithms supported by the chosen mechanism. The <c>EncryptMessage (Digest)</c>
		/// function uses the security context referenced by the context handle. Some packages do not have messages to be encrypted or
		/// decrypted but rather provide an integrity hash that can be checked.
		/// </para>
		/// <para>This function is available as a SASL mechanism only.</para>
		/// <para>
		/// <c>Note</c><c>EncryptMessage (Digest)</c> and DecryptMessage (Digest) can be called at the same time from two different threads
		/// in a single Security Support Provider Interface (SSPI) context if one thread is encrypting and the other is decrypting. If more
		/// than one thread is encrypting, or more than one thread is decrypting, each thread should obtain a unique context.
		/// </para>
		/// </summary>
		/// <param name="phContext">A handle to the security context to be used to encrypt the message.</param>
		/// <param name="fQOP">
		/// <para>
		/// Package-specific flags that indicate the quality of protection. A security package can use this parameter to enable the selection
		/// of cryptographic algorithms.
		/// </para>
		/// <para>When using the Digest SSP, this parameter must be set to zero.</para>
		/// </param>
		/// <param name="pMessage">
		/// <para>
		/// A pointer to a SecBufferDesc structure. On input, the structure references one or more SecBuffer structures that can be of type
		/// SECBUFFER_DATA. That buffer contains the message to be encrypted. The message is encrypted in place, overwriting the original
		/// contents of the structure.
		/// </para>
		/// <para>The function does not process buffers with the SECBUFFER_READONLY attribute.</para>
		/// <para>
		/// The length of the SecBuffer structure that contains the message must be no greater than <c>cbMaximumMessage</c>, which is
		/// obtained from the QueryContextAttributes (Digest) (SECPKG_ATTR_STREAM_SIZES) function.
		/// </para>
		/// <para>
		/// When using the Digest SSP, there must be a second buffer of type SECBUFFER_PADDING or SEC_BUFFER_DATA to hold signature
		/// information. To get the size of the output buffer, call the QueryContextAttributes (Digest) function and specify
		/// SECPKG_ATTR_SIZES. The function will return a SecPkgContext_Sizes structure. The size of the output buffer is the sum of the
		/// values in the <c>cbMaxSignature</c> and <c>cbBlockSize</c> members.
		/// </para>
		/// <para>Applications that do not use SSL must supply a SecBuffer of type SECBUFFER_PADDING.</para>
		/// </param>
		/// <param name="MessageSeqNo">
		/// <para>
		/// The sequence number that the transport application assigned to the message. If the transport application does not maintain
		/// sequence numbers, this parameter must be zero.
		/// </para>
		/// <para>When using the Digest SSP, this parameter must be set to zero. The Digest SSP manages sequence numbering internally.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns SEC_E_OK.</para>
		/// <para>If the function fails, it returns one of the following error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_BUFFER_TOO_SMALL</term>
		/// <term>The output buffer is too small. For more information, see Remarks.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_CONTEXT_EXPIRED</term>
		/// <term>
		/// The application is referencing a context that has already been closed. A properly written application should not receive this error.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_CRYPTO_SYSTEM_INVALID</term>
		/// <term>The cipher chosen for the security context is not supported.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INSUFFICIENT_MEMORY</term>
		/// <term>There is not enough memory available to complete the requested action.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>A context handle that is not valid was specified in the phContext parameter.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_TOKEN</term>
		/// <term>No SECBUFFER_DATA type buffer was found.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_QOP_NOT_SUPPORTED</term>
		/// <term>Neither confidentiality nor integrity are supported by the security context.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The <c>EncryptMessage (Digest)</c> function encrypts a message based on the message and the session key from a security context.
		/// </para>
		/// <para>
		/// If the transport application created the security context to support sequence detection and the caller provides a sequence
		/// number, the function includes this information with the encrypted message. Including this information protects against replay,
		/// insertion, and suppression of messages. The security package incorporates the sequence number passed down from the transport application.
		/// </para>
		/// <para>
		/// When you use the Digest SSP, get the size of the output buffer by calling the QueryContextAttributes (Digest) function and
		/// specifying SECPKG_ATTR_SIZES. The function will return a SecPkgContext_Sizes structure. The size of the output buffer is the sum
		/// of the values in the <c>cbMaxSignature</c> and <c>cbBlockSize</c> members.
		/// </para>
		/// <para><c>Note</c> These buffers must be supplied in the order shown.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Buffer type</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SECBUFFER_STREAM_HEADER</term>
		/// <term>Used internally. No initialization required.</term>
		/// </item>
		/// <item>
		/// <term>SECBUFFER_DATA</term>
		/// <term>Contains the plaintext message to be encrypted.</term>
		/// </item>
		/// <item>
		/// <term>SECBUFFER_STREAM_TRAILER</term>
		/// <term>Used internally. No initialization required.</term>
		/// </item>
		/// <item>
		/// <term>SECBUFFER_EMPTY</term>
		/// <term>Used internally. No initialization required. Size can be zero.</term>
		/// </item>
		/// </list>
		/// <para>For optimal performance, the pMessage structures should be allocated from contiguous memory.</para>
		/// <para>
		/// <c>Windows XP:</c> This function was also known as <c>SealMessage</c>. Applications should now use <c>EncryptMessage (Digest)</c> only.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-encryptmessage SECURITY_STATUS SEC_ENTRY EncryptMessage(
		// PCtxtHandle phContext, unsigned long fQOP, PSecBufferDesc pMessage, unsigned long MessageSeqNo );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "0045e931-929b-40c4-a524-5664d2fc5170")]
		public static extern HRESULT EncryptMessage(in CtxtHandle phContext, SECQOP fQOP, ref SecBufferDesc pMessage, uint MessageSeqNo);

		/// <summary>
		/// The <c>EnumerateSecurityPackages</c> function returns an array of SecPkgInfo structures that provide information about the
		/// security packages available to the client.
		/// </summary>
		/// <param name="pcPackages">
		/// A pointer to a <c>ULONG</c> variable that receives the number of packages available on the system. This includes packages that
		/// are already loaded and packages available on demand.
		/// </param>
		/// <param name="ppPackageInfo">
		/// <para>
		/// A pointer to a variable that receives a pointer to an array of SecPkgInfo structures. Each structure contains information from
		/// the security support provider (SSP) that describes the capabilities of the security package available within that SSP.
		/// </para>
		/// <para>When you have finished using the array, free the memory by calling the FreeContextBuffer function.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns <c>SEC_E_OK</c>.</para>
		/// <para>
		/// If the function fails, it returns a nonzero error code. Possible values include, but are not limited to, those in the following table.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code/value</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INSUFFICIENT_MEMORY 0x80090300L</term>
		/// <term>There was not sufficient memory to allocate one or more of the buffers.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE 0x80090301L</term>
		/// <term>An invalid handle was specified.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_SECPKG_NOT_FOUND 0x80090305L</term>
		/// <term>The specified package was not found.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// The caller can use the <c>Name</c> member of a SecPkgInfo structure to specify a security package in a call to the
		/// AcquireCredentialsHandle (General) function.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-enumeratesecuritypackagesa SECURITY_STATUS SEC_ENTRY
		// EnumerateSecurityPackagesA( unsigned long *pcPackages, PSecPkgInfoA *ppPackageInfo );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "900790a6-111d-43f5-9316-e85aab03a3bc")]
		public static extern HRESULT EnumerateSecurityPackages(out uint pcPackages, out SafeContextBuffer ppPackageInfo);

		/// <summary>
		/// The <c>ExportSecurityContext</c> function creates a serialized representation of a security context that can later be imported
		/// into a different process by calling ImportSecurityContext. The process that imports the security context must be running on the
		/// same computer as the process that called <c>ExportSecurityContext</c>.
		/// </summary>
		/// <param name="phContext">A handle of the security context to be exported.</param>
		/// <param name="fFlags">
		/// <para>This parameter can be a bitwise- <c>OR</c> combination of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SECPKG_CONTEXT_EXPORT_RESET_NEW 1 (0x1)</term>
		/// <term>The new security context is reset to its initial state.</term>
		/// </item>
		/// <item>
		/// <term>SECPKG_CONTEXT_EXPORT_DELETE_OLD 2 (0x2)</term>
		/// <term>The old security context is deleted.</term>
		/// </item>
		/// <item>
		/// <term>SECPKG_CONTEXT_EXPORT_TO_KERNEL 4 (0x4)</term>
		/// <term>
		/// This value is not supported. Windows Server 2003 and Windows XP/2000: The security context is to be exported to the kernel.This
		/// value is supported only in Schannel kernel mode.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pPackedContext">
		/// A pointer to a buffer of type <c>SECBUFFER_EMPTY</c> that receives the serialized security context. When you have finished using
		/// this context, free it by calling the FreeContextBuffer function.
		/// </param>
		/// <param name="pToken">
		/// <para>A pointer to receive the handle of the context's token.</para>
		/// <para>When you have finished using the user token, release the handle by calling the CloseHandle function.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns SEC_E_OK.</para>
		/// <para>If the function fails, it returns one of the following error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INSUFFICIENT_MEMORY</term>
		/// <term>There is not enough memory available to complete the requested action.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The phContext parameter does not point to a valid handle.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_NOT_SUPPORTED</term>
		/// <term>Schannel kernel mode does not support this function.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-exportsecuritycontext KSECDDDECLSPEC SECURITY_STATUS SEC_ENTRY
		// ExportSecurityContext( PCtxtHandle phContext, ULONG fFlags, PSecBuffer pPackedContext, void **pToken );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "4ebc7f37-b948-4c78-973f-0a74e55c7ee2")]
		public static extern HRESULT ExportSecurityContext(in CtxtHandle phContext, SECPKG_CONTEXT_EXPORT fFlags, ref SecBuffer pPackedContext, out SafeHTOKEN pToken);

		/// <summary>
		/// The <c>FreeContextBuffer</c> function enables callers of security package functions to free memory buffers allocated by the
		/// security package.
		/// </summary>
		/// <param name="pvContextBuffer">A pointer to memory to be freed.</param>
		/// <returns>
		/// <para>If the function succeeds, the function returns SEC_E_OK.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// Memory buffers are typically allocated by the InitializeSecurityContext (General) and AcceptSecurityContext (General) functions.
		/// </para>
		/// <para>The <c>FreeContextBuffer</c> function can free any memory allocated by a security package.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-freecontextbuffer SECURITY_STATUS SEC_ENTRY FreeContextBuffer(
		// PVOID pvContextBuffer );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "3c3d27bb-4f9a-4979-b679-1e10fa1ff221")]
		public static extern HRESULT FreeContextBuffer(IntPtr pvContextBuffer);

		/// <summary>
		/// <para>
		/// The <c>FreeCredentialsHandle</c> function notifies the security system that the credentials are no longer needed. An application
		/// calls this function to free the credential handle acquired in the call to the AcquireCredentialsHandle (General) function after
		/// calling the DeleteSecurityContext function to free any context handles associated with the credential. When all references to
		/// this credential set have been removed, the credentials themselves can be removed.
		/// </para>
		/// <para>Failure to free credentials handles will result in memory leaks.</para>
		/// </summary>
		/// <param name="phCredential">A pointer to the CredHandle handle obtained by using the AcquireCredentialsHandle (General) function.</param>
		/// <returns>
		/// <para>If the function succeeds, the function returns SEC_E_OK.</para>
		/// <para>If the function fails, it returns the following error code.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The handle passed to the function is not valid.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-freecredentialshandle KSECDDDECLSPEC SECURITY_STATUS SEC_ENTRY
		// FreeCredentialsHandle( PCredHandle phCredential );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "e089618c-8233-475a-9725-39265c6427ab")]
		public static extern HRESULT FreeCredentialsHandle(ref CredHandle phCredential);

		/// <summary>
		/// The <c>ImpersonateSecurityContext</c> function allows a server to impersonate a client by using a token previously obtained by a
		/// call to AcceptSecurityContext (General) or QuerySecurityContextToken. This function allows the application server to act as the
		/// client, and thus all necessary access controls are enforced.
		/// </summary>
		/// <param name="phContext">
		/// The handle of the context to impersonate. This handle must have been obtained by a call to the AcceptSecurityContext (General) function.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns SEC_E_OK.</para>
		/// <para>If the function fails, it returns the following error code.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The handle passed to the function is not valid.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_NO_IMPERSONATION</term>
		/// <term>The client could not be impersonated.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_UNSUPPORTED_FUNCTION</term>
		/// <term>This value is returned by Schannel kernel mode to indicate that this function is not supported.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The server application calls the <c>ImpersonateSecurityContext</c> function when it needs to impersonate the client. Before doing
		/// so, the server must have obtained a valid context handle. To obtain the context handle, the server must call
		/// AcceptSecurityContext (General) to submit the client's incoming security token to the security system. The server gets a context
		/// handle if the inbound context is validated. The function creates an impersonation token and allows the thread or process to run
		/// with the impersonation context.
		/// </para>
		/// <para>
		/// When using the Schannel security support provider (SSP), the server application must pass the <c>ASC_REQ_MUTUAL_AUTH</c> flag
		/// when calling AcceptSecurityContext (General). This ensures that the client is asked for a client certificate during the SSL/TLS
		/// handshake. When a client certificate is received, the Schannel package verifies the client certificate and attempts to map it to
		/// a user account. When this mapping is successful, then a client user token is created and this function succeeds.
		/// </para>
		/// <para>
		/// The application server must call the RevertSecurityContext function when it finishes or when it needs to restore its own security context.
		/// </para>
		/// <para>
		/// <c>ImpersonateSecurityContext</c> is not available with all security packages on all platforms. Typically, it is implemented only
		/// on platforms and with security packages that support impersonation. To learn whether a security package supports impersonation,
		/// call the QuerySecurityPackageInfo function.
		/// </para>
		/// <para>
		/// <c>Note</c> If the <c>ImpersonateSecurityContext</c> function fails, the client is not impersonated, and all subsequent client
		/// requests are made in the security context of the process that called the function. If the calling process is running as a
		/// privileged account, it can perform actions that the client would not be allowed to perform. To avoid security risks, the calling
		/// process should always check the return value. If the return value indicates that the function call failed, no client requests
		/// should be executed.
		/// </para>
		/// <para>
		/// All impersonate functions, including <c>ImpersonateSecurityContext</c> allow the requested impersonation if one of the following
		/// is true:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>
		/// The requested impersonation level of the token is less than <c>SecurityImpersonation</c>, such as <c>SecurityIdentification</c>
		/// or <c>SecurityAnonymous</c>.
		/// </term>
		/// </item>
		/// <item>
		/// <term>The caller has the <c>SeImpersonatePrivilege</c> privilege.</term>
		/// </item>
		/// <item>
		/// <term>
		/// A process (or another process in the caller's logon session) created the token using explicit credentials through LogonUser or
		/// LsaLogonUser function.
		/// </term>
		/// </item>
		/// <item>
		/// <term>The authenticated identity is same as the caller.</term>
		/// </item>
		/// </list>
		/// <para><c>Windows XP with SP1 and earlier:</c> The <c>SeImpersonatePrivilege</c> privilege is not supported.</para>
		/// <para><c>Windows XP:</c> The SeImpersonatePrivilege privilege is not supported until Windows XP with Service Pack 2 (SP2).</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-impersonatesecuritycontext KSECDDDECLSPEC SECURITY_STATUS
		// SEC_ENTRY ImpersonateSecurityContext( PCtxtHandle phContext );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "167eaf3b-b794-4587-946d-fa596f1f9411")]
		public static extern HRESULT ImpersonateSecurityContext(in CtxtHandle phContext);

		/// <summary>
		/// The <c>ImportSecurityContext</c> function imports a security context. The security context must have been exported to the process
		/// calling <c>ImportSecurityContext</c> by a previous call to ExportSecurityContext.
		/// </summary>
		/// <param name="pszPackage">A string that contains the name of the security package to which the security context was exported.</param>
		/// <param name="pPackedContext">A pointer to a buffer that contains the serialized security context created by ExportSecurityContext.</param>
		/// <param name="Token">A handle to the context's token.</param>
		/// <param name="phContext">
		/// A handle of the new security context created from pPackedContext. When you have finished using the context, delete it by calling
		/// the DeleteSecurityContext function.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns SEC_E_OK.</para>
		/// <para>If the function fails, it returns one of the following error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_UNKNOWN_CREDENTIALS</term>
		/// <term>The credentials supplied to the package were not recognized.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_NO_CREDENTIALS</term>
		/// <term>No credentials are available in the security package.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_NOT_OWNER</term>
		/// <term>The caller of the function does not have the necessary credentials.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INSUFFICIENT_MEMORY</term>
		/// <term>There is not enough memory available to complete the requested action.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INTERNAL_ERROR</term>
		/// <term>An error occurred that did not map to an SSPI error code.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-importsecuritycontexta SECURITY_STATUS SEC_ENTRY
		// ImportSecurityContextA( LPSTR pszPackage, PSecBuffer pPackedContext, VOID *Token, PCtxtHandle phContext );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "0f8e65d0-69cf-42ba-a903-1922d731e5ec")]
		public static extern HRESULT ImportSecurityContext(string pszPackage, ref SecBuffer pPackedContext, HTOKEN Token, out SafeCtxtHandle phContext);

		/// <summary>
		/// <para>
		/// The <c>InitializeSecurityContext (General)</c> function initiates the client side, outbound security context from a credential
		/// handle. The function is used to build a security context between the client application and a remote peer.
		/// <c>InitializeSecurityContext (General)</c> returns a token that the client must pass to the remote peer, which the peer in turn
		/// submits to the local security implementation through the AcceptSecurityContext (General) call. The token generated should be
		/// considered opaque by all callers.
		/// </para>
		/// <para>
		/// Typically, the <c>InitializeSecurityContext (General)</c> function is called in a loop until a sufficient security context is established.
		/// </para>
		/// <para>For information about using this function with a specific security support provider (SSP), see the following topics.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Topic</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>InitializeSecurityContext (CredSSP)</term>
		/// <term>
		/// Initiates the client side, outbound security context from a credential handle by using the Credential Security Support Provider (CredSSP).
		/// </term>
		/// </item>
		/// <item>
		/// <term>InitializeSecurityContext (Digest)</term>
		/// <term>Initiates the client side, outbound security context from a credential handle by using the Digest security package.</term>
		/// </item>
		/// <item>
		/// <term>InitializeSecurityContext (Kerberos)</term>
		/// <term>Initiates the client side, outbound security context from a credential handle by using the Kerberos security package.</term>
		/// </item>
		/// <item>
		/// <term>InitializeSecurityContext (Negotiate)</term>
		/// <term>Initiates the client side, outbound security context from a credential handle by using the Negotiate security package.</term>
		/// </item>
		/// <item>
		/// <term>InitializeSecurityContext (NTLM)</term>
		/// <term>Initiates the client side, outbound security context from a credential handle by using the NTLM security package.</term>
		/// </item>
		/// <item>
		/// <term>InitializeSecurityContext (Schannel)</term>
		/// <term>Initiates the client side, outbound security context from a credential handle by using the Schannel security package.</term>
		/// </item>
		/// </list>
		/// </summary>
		/// <param name="phCredential">
		/// A handle to the credentials returned by AcquireCredentialsHandle (General). This handle is used to build the security context.
		/// The <c>InitializeSecurityContext (General)</c> function requires at least OUTBOUND credentials.
		/// </param>
		/// <param name="phContext">
		/// <para>
		/// A pointer to a CtxtHandle structure. On the first call to <c>InitializeSecurityContext (General)</c>, this pointer is
		/// <c>NULL</c>. On the second call, this parameter is a pointer to the handle to the partially formed context returned in the
		/// phNewContext parameter by the first call.
		/// </para>
		/// <para>This parameter is optional with the Microsoft Digest SSP and can be set to <c>NULL</c>.</para>
		/// <para>
		/// When using the Schannel SSP, on the first call to <c>InitializeSecurityContext (General)</c>, specify <c>NULL</c>. On future
		/// calls, specify the token received in the phNewContext parameter after the first call to this function.
		/// </para>
		/// </param>
		/// <param name="pszTargetName">TBD</param>
		/// <param name="fContextReq">
		/// <para>
		/// Bit flags that indicate requests for the context. Not all packages can support all requirements. Flags used for this parameter
		/// are prefixed with ISC_REQ_, for example, ISC_REQ_DELEGATE. This parameter can be one or more of the following attributes flags.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>ISC_REQ_ALLOCATE_MEMORY</term>
		/// <term>
		/// The security package allocates output buffers for you. When you have finished using the output buffers, free them by calling the
		/// FreeContextBuffer function.
		/// </term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_CONFIDENTIALITY</term>
		/// <term>Encrypt messages by using the EncryptMessage function.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_CONNECTION</term>
		/// <term>
		/// The security context will not handle formatting messages. This value is the default for the Kerberos, Negotiate, and NTLM
		/// security packages.
		/// </term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_DELEGATE</term>
		/// <term>
		/// The server can use the context to authenticate to other servers as the client. The ISC_REQ_MUTUAL_AUTH flag must be set for this
		/// flag to work. Valid for Kerberos. Ignore this flag for constrained delegation.
		/// </term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_EXTENDED_ERROR</term>
		/// <term>When errors occur, the remote party will be notified.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_HTTP</term>
		/// <term>Use Digest for HTTP. Omit this flag to use Digest as a SASL mechanism.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_INTEGRITY</term>
		/// <term>Sign messages and verify signatures by using the EncryptMessage and MakeSignature functions.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_MANUAL_CRED_VALIDATION</term>
		/// <term>Schannel must not authenticate the server automatically.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_MUTUAL_AUTH</term>
		/// <term>The mutual authentication policy of the service will be satisfied.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_NO_INTEGRITY</term>
		/// <term>
		/// If this flag is set, the ISC_REQ_INTEGRITY flag is ignored. This value is supported only by the Negotiate and Kerberos security packages.
		/// </term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_REPLAY_DETECT</term>
		/// <term>Detect replayed messages that have been encoded by using the EncryptMessage or MakeSignature functions.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_SEQUENCE_DETECT</term>
		/// <term>Detect messages received out of sequence.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_STREAM</term>
		/// <term>Support a stream-oriented connection.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_USE_SESSION_KEY</term>
		/// <term>A new session key must be negotiated. This value is supported only by the Kerberos security package.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_USE_SUPPLIED_CREDS</term>
		/// <term>Schannel must not attempt to supply credentials for the client automatically.</term>
		/// </item>
		/// </list>
		/// <para>The requested attributes may not be supported by the client. For more information, see the pfContextAttr parameter.</para>
		/// <para>For further descriptions of the various attributes, see Context Requirements.</para>
		/// </param>
		/// <param name="Reserved1">This parameter is reserved and must be set to zero.</param>
		/// <param name="TargetDataRep">
		/// <para>The data representation, such as byte ordering, on the target. This parameter can be either SECURITY_NATIVE_DREP or SECURITY_NETWORK_DREP.</para>
		/// <para>This parameter is not used with Digest or Schannel. Set it to zero.</para>
		/// </param>
		/// <param name="pInput">
		/// A pointer to a SecBufferDesc structure that contains pointers to the buffers supplied as input to the package. Unless the client
		/// context was initiated by the server, the value of this parameter must be <c>NULL</c> on the first call to the function. On
		/// subsequent calls to the function or when the client context was initiated by the server, the value of this parameter is a pointer
		/// to a buffer allocated with enough memory to hold the token returned by the remote computer.
		/// </param>
		/// <param name="Reserved2">This parameter is reserved and must be set to zero.</param>
		/// <param name="phNewContext">
		/// <para>
		/// A pointer to a CtxtHandle structure. On the first call to <c>InitializeSecurityContext (General)</c>, this pointer receives the
		/// new context handle. On the second call, phNewContext can be the same as the handle specified in the phContext parameter.
		/// </para>
		/// <para>
		/// When using the Schannel SSP, on calls after the first call, pass the handle returned here as the phContext parameter and specify
		/// <c>NULL</c> for phNewContext.
		/// </para>
		/// </param>
		/// <param name="pOutput">
		/// <para>
		/// A pointer to a SecBufferDesc structure that contains pointers to the SecBuffer structure that receives the output data. If a
		/// buffer was typed as SEC_READWRITE in the input, it will be there on output. The system will allocate a buffer for the security
		/// token if requested (through ISC_REQ_ALLOCATE_MEMORY) and fill in the address in the buffer descriptor for the security token.
		/// </para>
		/// <para>When using the Microsoft Digest SSP, this parameter receives the challenge response that must be sent to the server.</para>
		/// <para>
		/// When using the Schannel SSP, if the ISC_REQ_ALLOCATE_MEMORY flag is specified, the Schannel SSP will allocate memory for the
		/// buffer and put the appropriate information in the SecBufferDesc. In addition, the caller must pass in a buffer of type
		/// <c>SECBUFFER_ALERT</c>. On output, if an alert is generated, this buffer contains information about that alert, and the function fails.
		/// </para>
		/// </param>
		/// <param name="pfContextAttr">
		/// <para>
		/// A pointer to a variable to receive a set of bit flags that indicate the attributes of the established context. For a description
		/// of the various attributes, see Context Requirements.
		/// </para>
		/// <para>Flags used for this parameter are prefixed with ISC_RET, such as ISC_RET_DELEGATE.</para>
		/// <para>For a list of valid values, see the fContextReq parameter.</para>
		/// <para>
		/// Do not check for security-related attributes until the final function call returns successfully. Attribute flags that are not
		/// related to security, such as the ASC_RET_ALLOCATED_MEMORY flag, can be checked before the final return.
		/// </para>
		/// <para><c>Note</c> Particular context attributes can change during negotiation with a remote peer.</para>
		/// </param>
		/// <param name="ptsExpiry">
		/// <para>
		/// A pointer to a TimeStamp structure that receives the expiration time of the context. It is recommended that the security package
		/// always return this value in local time. This parameter is optional and <c>NULL</c> should be passed for short-lived clients.
		/// </para>
		/// <para>There is no expiration time for Microsoft Digest SSP security contexts or credentials.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns one of the following success codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_I_COMPLETE_AND_CONTINUE</term>
		/// <term>
		/// The client must call CompleteAuthToken and then pass the output to the server. The client then waits for a returned token and
		/// passes it, in another call, to InitializeSecurityContext (General).
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_I_COMPLETE_NEEDED</term>
		/// <term>The client must finish building the message and then call the CompleteAuthToken function.</term>
		/// </item>
		/// <item>
		/// <term>SEC_I_CONTINUE_NEEDED</term>
		/// <term>
		/// The client must send the output token to the server and wait for a return token. The returned token is then passed in another
		/// call to InitializeSecurityContext (General). The output token can be empty.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_I_INCOMPLETE_CREDENTIALS</term>
		/// <term>
		/// Use with Schannel. The server has requested client authentication, and the supplied credentials either do not include a
		/// certificate or the certificate was not issued by a certification authority that is trusted by the server. For more information,
		/// see Remarks.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INCOMPLETE_MESSAGE</term>
		/// <term>
		/// Use with Schannel. Data for the whole message was not read from the wire. When this value is returned, the pInput buffer contains
		/// a SecBuffer structure with a BufferType member of SECBUFFER_MISSING. The cbBuffer member of SecBuffer contains a value that
		/// indicates the number of additional bytes that the function must read from the client before this function succeeds. While this
		/// number is not always accurate, using it can help improve performance by avoiding multiple calls to this function.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_OK</term>
		/// <term>
		/// The security context was successfully initialized. There is no need for another InitializeSecurityContext (General) call. If the
		/// function returns an output token, that is, if the SECBUFFER_TOKEN in pOutput is of nonzero length, that token must be sent to the server.
		/// </term>
		/// </item>
		/// </list>
		/// <para>If the function fails, the function returns one of the following error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INSUFFICIENT_MEMORY</term>
		/// <term>There is not enough memory available to complete the requested action.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INTERNAL_ERROR</term>
		/// <term>An error occurred that did not map to an SSPI error code.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The handle passed to the function is not valid.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_TOKEN</term>
		/// <term>
		/// The error is due to a malformed input token, such as a token corrupted in transit, a token of incorrect size, or a token passed
		/// into the wrong security package. Passing a token to the wrong package can happen if the client and server did not negotiate the
		/// proper security package.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_LOGON_DENIED</term>
		/// <term>The logon failed.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_NO_AUTHENTICATING_AUTHORITY</term>
		/// <term>
		/// No authority could be contacted for authentication. The domain name of the authenticating party could be wrong, the domain could
		/// be unreachable, or there might have been a trust relationship failure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_NO_CREDENTIALS</term>
		/// <term>No credentials are available in the security package.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_TARGET_UNKNOWN</term>
		/// <term>The target was not recognized.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_UNSUPPORTED_FUNCTION</term>
		/// <term>
		/// A context attribute flag that is not valid (ISC_REQ_DELEGATE or ISC_REQ_PROMPT_FOR_CREDS) was specified in the fContextReq parameter.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_WRONG_PRINCIPAL</term>
		/// <term>
		/// The principal that received the authentication request is not the same as the one passed into the pszTargetName parameter. This
		/// indicates a failure in mutual authentication.
		/// </term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The caller is responsible for determining whether the final context attributes are sufficient. If, for example, confidentiality
		/// was requested, but could not be established, some applications may choose to shut down the connection immediately.
		/// </para>
		/// <para>
		/// If attributes of the security context are not sufficient, the client must free the partially created context by calling the
		/// DeleteSecurityContext function.
		/// </para>
		/// <para>The <c>InitializeSecurityContext (General)</c> function is used by a client to initialize an outbound context.</para>
		/// <para>For a two-leg security context, the calling sequence is as follows:</para>
		/// <list type="number">
		/// <item>
		/// <term>The client calls the function with phContext set to <c>NULL</c> and fills in the buffer descriptor with the input message.</term>
		/// </item>
		/// <item>
		/// <term>
		/// The security package examines the parameters and constructs an opaque token, placing it in the TOKEN element in the buffer array.
		/// If the fContextReq parameter includes the ISC_REQ_ALLOCATE_MEMORY flag, the security package allocates the memory and returns the
		/// pointer in the TOKEN element.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// The client sends the token returned in the pOutput buffer to the target server. The server then passes the token as an input
		/// argument in a call to the AcceptSecurityContext (General) function.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// AcceptSecurityContext (General) may return a token, which the server sends to the client for a second call to
		/// <c>InitializeSecurityContext (General)</c> if the first call returned SEC_I_CONTINUE_NEEDED.
		/// </term>
		/// </item>
		/// </list>
		/// <para>For multiple-leg security contexts, such as mutual authentication, the calling sequence is as follows:</para>
		/// <list type="number">
		/// <item>
		/// <term>The client calls the function as described earlier, but the package returns the SEC_I_CONTINUE_NEEDED success code.</term>
		/// </item>
		/// <item>
		/// <term>The client sends the output token to the server and waits for the server's reply.</term>
		/// </item>
		/// <item>
		/// <term>
		/// Upon receipt of the server's response, the client calls <c>InitializeSecurityContext (General)</c> again, with phContext set to
		/// the handle that was returned from the last call. The token received from the server is supplied in the pInput parameter.
		/// </term>
		/// </item>
		/// </list>
		/// <para>If the server has successfully responded, the security package returns SEC_E_OK and a secure session is established.</para>
		/// <para>If the function returns one of the error responses, the server's response is not accepted, and the session is not established.</para>
		/// <para>
		/// If the function returns SEC_I_CONTINUE_NEEDED, SEC_I_COMPLETE_NEEDED, or SEC_I_COMPLETE_AND_CONTINUE, steps 2 and 3 are repeated.
		/// </para>
		/// <para>
		/// To initialize a security context, more than one call to this function may be required, depending on the underlying authentication
		/// mechanism as well as the choices specified in the fContextReq parameter.
		/// </para>
		/// <para>
		/// The fContextReq and pfContextAttributes parameters are bitmasks that represent various context attributes. For a description of
		/// the various attributes, see Context Requirements. The pfContextAttributes parameter is valid on any successful return, but only
		/// on the final successful return should you examine the flags that pertain to security aspects of the context. Intermediate returns
		/// can set, for example, the ISC_RET_ALLOCATED_MEMORY flag.
		/// </para>
		/// <para>
		/// If the ISC_REQ_USE_SUPPLIED_CREDS flag is set, the security package must look for a SECBUFFER_PKG_PARAMS buffer type in the
		/// pInput input buffer. This is not a generic solution, but it allows for a strong pairing of security package and application when appropriate.
		/// </para>
		/// <para>If ISC_REQ_ALLOCATE_MEMORY was specified, the caller must free the memory by calling the FreeContextBuffer function.</para>
		/// <para>
		/// For example, the input token could be the challenge from a LAN Manager. In this case, the output token would be the
		/// NTLM-encrypted response to the challenge.
		/// </para>
		/// <para>
		/// The action the client takes depends on the return code from this function. If the return code is SEC_E_OK, there will be no
		/// second <c>InitializeSecurityContext (General)</c> call, and no response from the server is expected. If the return code is
		/// SEC_I_CONTINUE_NEEDED, the client expects a token in response from the server and passes it in a second call to
		/// <c>InitializeSecurityContext (General)</c>. The SEC_I_COMPLETE_NEEDED return code indicates that the client must finish building
		/// the message and call the CompleteAuthToken function. The SEC_I_COMPLETE_AND_CONTINUE code incorporates both of these actions.
		/// </para>
		/// <para>
		/// If <c>InitializeSecurityContext (General)</c> returns success on the first (or only) call, then the caller must eventually call
		/// the DeleteSecurityContext function on the returned handle, even if the call fails on a later leg of the authentication exchange.
		/// </para>
		/// <para>
		/// The client may call <c>InitializeSecurityContext (General)</c> again after it has completed successfully. This indicates to the
		/// security package that a reauthentication is wanted.
		/// </para>
		/// <para>
		/// Kernel mode callers have the following differences: the target name is a Unicode string that must be allocated in virtual memory
		/// by using VirtualAlloc; it must not be allocated from the pool. Buffers passed and supplied in pInput and pOutput must be in
		/// virtual memory, not in the pool.
		/// </para>
		/// <para>
		/// When using the Schannel SSP, if the function returns SEC_I_INCOMPLETE_CREDENTIALS, check that you specified a valid and trusted
		/// certificate in your credentials. The certificate is specified when calling the AcquireCredentialsHandle (General) function. The
		/// certificate must be a client authentication certificate issued by a certification authority (CA) trusted by the server. To obtain
		/// a list of the CAs trusted by the server, call the QueryContextAttributes (General) function and specify the
		/// SECPKG_ATTR_ISSUER_LIST_EX attribute.
		/// </para>
		/// <para>
		/// When using the Schannel SSP, after a client application receives an authentication certificate from a CA that is trusted by the
		/// server, the application creates a new credential by calling the AcquireCredentialsHandle (General) function and then calling
		/// <c>InitializeSecurityContext (General)</c> again, specifying the new credential in the phCredential parameter.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-initializesecuritycontexta SECURITY_STATUS SEC_ENTRY
		// InitializeSecurityContextA( PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName, unsigned long fContextReq,
		// unsigned long Reserved1, unsigned long TargetDataRep, PSecBufferDesc pInput, unsigned long Reserved2, PCtxtHandle phNewContext,
		// PSecBufferDesc pOutput, unsigned long *pfContextAttr, PTimeStamp ptsExpiry );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "21d965d4-3c03-4e29-a70d-4538c5c366b0")]
		public static unsafe extern HRESULT InitializeSecurityContext([In, Optional] CredHandle* phCredential, [In, Optional] CtxtHandle* phContext, [Optional] string pszTargetName, ASC_REQ fContextReq, [Optional] uint Reserved1, DREP TargetDataRep,
			[In, Optional] SecBufferDesc* pInput, [Optional] uint Reserved2, ref CtxtHandle phNewContext, [Optional] SecBufferDesc* pOutput, out ASC_RET pfContextAttr, out TimeStamp ptsExpiry);

		/// <summary>
		/// <para>
		/// The <c>InitializeSecurityContext (General)</c> function initiates the client side, outbound security context from a credential
		/// handle. The function is used to build a security context between the client application and a remote peer.
		/// <c>InitializeSecurityContext (General)</c> returns a token that the client must pass to the remote peer, which the peer in turn
		/// submits to the local security implementation through the AcceptSecurityContext (General) call. The token generated should be
		/// considered opaque by all callers.
		/// </para>
		/// <para>
		/// Typically, the <c>InitializeSecurityContext (General)</c> function is called in a loop until a sufficient security context is established.
		/// </para>
		/// <para>For information about using this function with a specific security support provider (SSP), see the following topics.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Topic</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>InitializeSecurityContext (CredSSP)</term>
		/// <term>
		/// Initiates the client side, outbound security context from a credential handle by using the Credential Security Support Provider (CredSSP).
		/// </term>
		/// </item>
		/// <item>
		/// <term>InitializeSecurityContext (Digest)</term>
		/// <term>Initiates the client side, outbound security context from a credential handle by using the Digest security package.</term>
		/// </item>
		/// <item>
		/// <term>InitializeSecurityContext (Kerberos)</term>
		/// <term>Initiates the client side, outbound security context from a credential handle by using the Kerberos security package.</term>
		/// </item>
		/// <item>
		/// <term>InitializeSecurityContext (Negotiate)</term>
		/// <term>Initiates the client side, outbound security context from a credential handle by using the Negotiate security package.</term>
		/// </item>
		/// <item>
		/// <term>InitializeSecurityContext (NTLM)</term>
		/// <term>Initiates the client side, outbound security context from a credential handle by using the NTLM security package.</term>
		/// </item>
		/// <item>
		/// <term>InitializeSecurityContext (Schannel)</term>
		/// <term>Initiates the client side, outbound security context from a credential handle by using the Schannel security package.</term>
		/// </item>
		/// </list>
		/// </summary>
		/// <param name="phCredential">
		/// A handle to the credentials returned by AcquireCredentialsHandle (General). This handle is used to build the security context.
		/// The <c>InitializeSecurityContext (General)</c> function requires at least OUTBOUND credentials.
		/// </param>
		/// <param name="phContext">
		/// <para>
		/// A pointer to a CtxtHandle structure. On the first call to <c>InitializeSecurityContext (General)</c>, this pointer is
		/// <c>NULL</c>. On the second call, this parameter is a pointer to the handle to the partially formed context returned in the
		/// phNewContext parameter by the first call.
		/// </para>
		/// <para>This parameter is optional with the Microsoft Digest SSP and can be set to <c>NULL</c>.</para>
		/// <para>
		/// When using the Schannel SSP, on the first call to <c>InitializeSecurityContext (General)</c>, specify <c>NULL</c>. On future
		/// calls, specify the token received in the phNewContext parameter after the first call to this function.
		/// </para>
		/// </param>
		/// <param name="pszTargetName">TBD</param>
		/// <param name="fContextReq">
		/// <para>
		/// Bit flags that indicate requests for the context. Not all packages can support all requirements. Flags used for this parameter
		/// are prefixed with ISC_REQ_, for example, ISC_REQ_DELEGATE. This parameter can be one or more of the following attributes flags.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>ISC_REQ_ALLOCATE_MEMORY</term>
		/// <term>
		/// The security package allocates output buffers for you. When you have finished using the output buffers, free them by calling the
		/// FreeContextBuffer function.
		/// </term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_CONFIDENTIALITY</term>
		/// <term>Encrypt messages by using the EncryptMessage function.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_CONNECTION</term>
		/// <term>
		/// The security context will not handle formatting messages. This value is the default for the Kerberos, Negotiate, and NTLM
		/// security packages.
		/// </term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_DELEGATE</term>
		/// <term>
		/// The server can use the context to authenticate to other servers as the client. The ISC_REQ_MUTUAL_AUTH flag must be set for this
		/// flag to work. Valid for Kerberos. Ignore this flag for constrained delegation.
		/// </term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_EXTENDED_ERROR</term>
		/// <term>When errors occur, the remote party will be notified.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_HTTP</term>
		/// <term>Use Digest for HTTP. Omit this flag to use Digest as a SASL mechanism.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_INTEGRITY</term>
		/// <term>Sign messages and verify signatures by using the EncryptMessage and MakeSignature functions.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_MANUAL_CRED_VALIDATION</term>
		/// <term>Schannel must not authenticate the server automatically.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_MUTUAL_AUTH</term>
		/// <term>The mutual authentication policy of the service will be satisfied.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_NO_INTEGRITY</term>
		/// <term>
		/// If this flag is set, the ISC_REQ_INTEGRITY flag is ignored. This value is supported only by the Negotiate and Kerberos security packages.
		/// </term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_REPLAY_DETECT</term>
		/// <term>Detect replayed messages that have been encoded by using the EncryptMessage or MakeSignature functions.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_SEQUENCE_DETECT</term>
		/// <term>Detect messages received out of sequence.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_STREAM</term>
		/// <term>Support a stream-oriented connection.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_USE_SESSION_KEY</term>
		/// <term>A new session key must be negotiated. This value is supported only by the Kerberos security package.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_USE_SUPPLIED_CREDS</term>
		/// <term>Schannel must not attempt to supply credentials for the client automatically.</term>
		/// </item>
		/// </list>
		/// <para>The requested attributes may not be supported by the client. For more information, see the pfContextAttr parameter.</para>
		/// <para>For further descriptions of the various attributes, see Context Requirements.</para>
		/// </param>
		/// <param name="Reserved1">This parameter is reserved and must be set to zero.</param>
		/// <param name="TargetDataRep">
		/// <para>The data representation, such as byte ordering, on the target. This parameter can be either SECURITY_NATIVE_DREP or SECURITY_NETWORK_DREP.</para>
		/// <para>This parameter is not used with Digest or Schannel. Set it to zero.</para>
		/// </param>
		/// <param name="pInput">
		/// A pointer to a SecBufferDesc structure that contains pointers to the buffers supplied as input to the package. Unless the client
		/// context was initiated by the server, the value of this parameter must be <c>NULL</c> on the first call to the function. On
		/// subsequent calls to the function or when the client context was initiated by the server, the value of this parameter is a pointer
		/// to a buffer allocated with enough memory to hold the token returned by the remote computer.
		/// </param>
		/// <param name="Reserved2">This parameter is reserved and must be set to zero.</param>
		/// <param name="phNewContext">
		/// <para>
		/// A pointer to a CtxtHandle structure. On the first call to <c>InitializeSecurityContext (General)</c>, this pointer receives the
		/// new context handle. On the second call, phNewContext can be the same as the handle specified in the phContext parameter.
		/// </para>
		/// <para>
		/// When using the Schannel SSP, on calls after the first call, pass the handle returned here as the phContext parameter and specify
		/// <c>NULL</c> for phNewContext.
		/// </para>
		/// </param>
		/// <param name="pOutput">
		/// <para>
		/// A pointer to a SecBufferDesc structure that contains pointers to the SecBuffer structure that receives the output data. If a
		/// buffer was typed as SEC_READWRITE in the input, it will be there on output. The system will allocate a buffer for the security
		/// token if requested (through ISC_REQ_ALLOCATE_MEMORY) and fill in the address in the buffer descriptor for the security token.
		/// </para>
		/// <para>When using the Microsoft Digest SSP, this parameter receives the challenge response that must be sent to the server.</para>
		/// <para>
		/// When using the Schannel SSP, if the ISC_REQ_ALLOCATE_MEMORY flag is specified, the Schannel SSP will allocate memory for the
		/// buffer and put the appropriate information in the SecBufferDesc. In addition, the caller must pass in a buffer of type
		/// <c>SECBUFFER_ALERT</c>. On output, if an alert is generated, this buffer contains information about that alert, and the function fails.
		/// </para>
		/// </param>
		/// <param name="pfContextAttr">
		/// <para>
		/// A pointer to a variable to receive a set of bit flags that indicate the attributes of the established context. For a description
		/// of the various attributes, see Context Requirements.
		/// </para>
		/// <para>Flags used for this parameter are prefixed with ISC_RET, such as ISC_RET_DELEGATE.</para>
		/// <para>For a list of valid values, see the fContextReq parameter.</para>
		/// <para>
		/// Do not check for security-related attributes until the final function call returns successfully. Attribute flags that are not
		/// related to security, such as the ASC_RET_ALLOCATED_MEMORY flag, can be checked before the final return.
		/// </para>
		/// <para><c>Note</c> Particular context attributes can change during negotiation with a remote peer.</para>
		/// </param>
		/// <param name="ptsExpiry">
		/// <para>
		/// A pointer to a TimeStamp structure that receives the expiration time of the context. It is recommended that the security package
		/// always return this value in local time. This parameter is optional and <c>NULL</c> should be passed for short-lived clients.
		/// </para>
		/// <para>There is no expiration time for Microsoft Digest SSP security contexts or credentials.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns one of the following success codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_I_COMPLETE_AND_CONTINUE</term>
		/// <term>
		/// The client must call CompleteAuthToken and then pass the output to the server. The client then waits for a returned token and
		/// passes it, in another call, to InitializeSecurityContext (General).
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_I_COMPLETE_NEEDED</term>
		/// <term>The client must finish building the message and then call the CompleteAuthToken function.</term>
		/// </item>
		/// <item>
		/// <term>SEC_I_CONTINUE_NEEDED</term>
		/// <term>
		/// The client must send the output token to the server and wait for a return token. The returned token is then passed in another
		/// call to InitializeSecurityContext (General). The output token can be empty.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_I_INCOMPLETE_CREDENTIALS</term>
		/// <term>
		/// Use with Schannel. The server has requested client authentication, and the supplied credentials either do not include a
		/// certificate or the certificate was not issued by a certification authority that is trusted by the server. For more information,
		/// see Remarks.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INCOMPLETE_MESSAGE</term>
		/// <term>
		/// Use with Schannel. Data for the whole message was not read from the wire. When this value is returned, the pInput buffer contains
		/// a SecBuffer structure with a BufferType member of SECBUFFER_MISSING. The cbBuffer member of SecBuffer contains a value that
		/// indicates the number of additional bytes that the function must read from the client before this function succeeds. While this
		/// number is not always accurate, using it can help improve performance by avoiding multiple calls to this function.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_OK</term>
		/// <term>
		/// The security context was successfully initialized. There is no need for another InitializeSecurityContext (General) call. If the
		/// function returns an output token, that is, if the SECBUFFER_TOKEN in pOutput is of nonzero length, that token must be sent to the server.
		/// </term>
		/// </item>
		/// </list>
		/// <para>If the function fails, the function returns one of the following error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INSUFFICIENT_MEMORY</term>
		/// <term>There is not enough memory available to complete the requested action.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INTERNAL_ERROR</term>
		/// <term>An error occurred that did not map to an SSPI error code.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The handle passed to the function is not valid.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_TOKEN</term>
		/// <term>
		/// The error is due to a malformed input token, such as a token corrupted in transit, a token of incorrect size, or a token passed
		/// into the wrong security package. Passing a token to the wrong package can happen if the client and server did not negotiate the
		/// proper security package.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_LOGON_DENIED</term>
		/// <term>The logon failed.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_NO_AUTHENTICATING_AUTHORITY</term>
		/// <term>
		/// No authority could be contacted for authentication. The domain name of the authenticating party could be wrong, the domain could
		/// be unreachable, or there might have been a trust relationship failure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_NO_CREDENTIALS</term>
		/// <term>No credentials are available in the security package.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_TARGET_UNKNOWN</term>
		/// <term>The target was not recognized.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_UNSUPPORTED_FUNCTION</term>
		/// <term>
		/// A context attribute flag that is not valid (ISC_REQ_DELEGATE or ISC_REQ_PROMPT_FOR_CREDS) was specified in the fContextReq parameter.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_WRONG_PRINCIPAL</term>
		/// <term>
		/// The principal that received the authentication request is not the same as the one passed into the pszTargetName parameter. This
		/// indicates a failure in mutual authentication.
		/// </term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The caller is responsible for determining whether the final context attributes are sufficient. If, for example, confidentiality
		/// was requested, but could not be established, some applications may choose to shut down the connection immediately.
		/// </para>
		/// <para>
		/// If attributes of the security context are not sufficient, the client must free the partially created context by calling the
		/// DeleteSecurityContext function.
		/// </para>
		/// <para>The <c>InitializeSecurityContext (General)</c> function is used by a client to initialize an outbound context.</para>
		/// <para>For a two-leg security context, the calling sequence is as follows:</para>
		/// <list type="number">
		/// <item>
		/// <term>The client calls the function with phContext set to <c>NULL</c> and fills in the buffer descriptor with the input message.</term>
		/// </item>
		/// <item>
		/// <term>
		/// The security package examines the parameters and constructs an opaque token, placing it in the TOKEN element in the buffer array.
		/// If the fContextReq parameter includes the ISC_REQ_ALLOCATE_MEMORY flag, the security package allocates the memory and returns the
		/// pointer in the TOKEN element.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// The client sends the token returned in the pOutput buffer to the target server. The server then passes the token as an input
		/// argument in a call to the AcceptSecurityContext (General) function.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// AcceptSecurityContext (General) may return a token, which the server sends to the client for a second call to
		/// <c>InitializeSecurityContext (General)</c> if the first call returned SEC_I_CONTINUE_NEEDED.
		/// </term>
		/// </item>
		/// </list>
		/// <para>For multiple-leg security contexts, such as mutual authentication, the calling sequence is as follows:</para>
		/// <list type="number">
		/// <item>
		/// <term>The client calls the function as described earlier, but the package returns the SEC_I_CONTINUE_NEEDED success code.</term>
		/// </item>
		/// <item>
		/// <term>The client sends the output token to the server and waits for the server's reply.</term>
		/// </item>
		/// <item>
		/// <term>
		/// Upon receipt of the server's response, the client calls <c>InitializeSecurityContext (General)</c> again, with phContext set to
		/// the handle that was returned from the last call. The token received from the server is supplied in the pInput parameter.
		/// </term>
		/// </item>
		/// </list>
		/// <para>If the server has successfully responded, the security package returns SEC_E_OK and a secure session is established.</para>
		/// <para>If the function returns one of the error responses, the server's response is not accepted, and the session is not established.</para>
		/// <para>
		/// If the function returns SEC_I_CONTINUE_NEEDED, SEC_I_COMPLETE_NEEDED, or SEC_I_COMPLETE_AND_CONTINUE, steps 2 and 3 are repeated.
		/// </para>
		/// <para>
		/// To initialize a security context, more than one call to this function may be required, depending on the underlying authentication
		/// mechanism as well as the choices specified in the fContextReq parameter.
		/// </para>
		/// <para>
		/// The fContextReq and pfContextAttributes parameters are bitmasks that represent various context attributes. For a description of
		/// the various attributes, see Context Requirements. The pfContextAttributes parameter is valid on any successful return, but only
		/// on the final successful return should you examine the flags that pertain to security aspects of the context. Intermediate returns
		/// can set, for example, the ISC_RET_ALLOCATED_MEMORY flag.
		/// </para>
		/// <para>
		/// If the ISC_REQ_USE_SUPPLIED_CREDS flag is set, the security package must look for a SECBUFFER_PKG_PARAMS buffer type in the
		/// pInput input buffer. This is not a generic solution, but it allows for a strong pairing of security package and application when appropriate.
		/// </para>
		/// <para>If ISC_REQ_ALLOCATE_MEMORY was specified, the caller must free the memory by calling the FreeContextBuffer function.</para>
		/// <para>
		/// For example, the input token could be the challenge from a LAN Manager. In this case, the output token would be the
		/// NTLM-encrypted response to the challenge.
		/// </para>
		/// <para>
		/// The action the client takes depends on the return code from this function. If the return code is SEC_E_OK, there will be no
		/// second <c>InitializeSecurityContext (General)</c> call, and no response from the server is expected. If the return code is
		/// SEC_I_CONTINUE_NEEDED, the client expects a token in response from the server and passes it in a second call to
		/// <c>InitializeSecurityContext (General)</c>. The SEC_I_COMPLETE_NEEDED return code indicates that the client must finish building
		/// the message and call the CompleteAuthToken function. The SEC_I_COMPLETE_AND_CONTINUE code incorporates both of these actions.
		/// </para>
		/// <para>
		/// If <c>InitializeSecurityContext (General)</c> returns success on the first (or only) call, then the caller must eventually call
		/// the DeleteSecurityContext function on the returned handle, even if the call fails on a later leg of the authentication exchange.
		/// </para>
		/// <para>
		/// The client may call <c>InitializeSecurityContext (General)</c> again after it has completed successfully. This indicates to the
		/// security package that a reauthentication is wanted.
		/// </para>
		/// <para>
		/// Kernel mode callers have the following differences: the target name is a Unicode string that must be allocated in virtual memory
		/// by using VirtualAlloc; it must not be allocated from the pool. Buffers passed and supplied in pInput and pOutput must be in
		/// virtual memory, not in the pool.
		/// </para>
		/// <para>
		/// When using the Schannel SSP, if the function returns SEC_I_INCOMPLETE_CREDENTIALS, check that you specified a valid and trusted
		/// certificate in your credentials. The certificate is specified when calling the AcquireCredentialsHandle (General) function. The
		/// certificate must be a client authentication certificate issued by a certification authority (CA) trusted by the server. To obtain
		/// a list of the CAs trusted by the server, call the QueryContextAttributes (General) function and specify the
		/// SECPKG_ATTR_ISSUER_LIST_EX attribute.
		/// </para>
		/// <para>
		/// When using the Schannel SSP, after a client application receives an authentication certificate from a CA that is trusted by the
		/// server, the application creates a new credential by calling the AcquireCredentialsHandle (General) function and then calling
		/// <c>InitializeSecurityContext (General)</c> again, specifying the new credential in the phCredential parameter.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-initializesecuritycontexta SECURITY_STATUS SEC_ENTRY
		// InitializeSecurityContextA( PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName, unsigned long fContextReq,
		// unsigned long Reserved1, unsigned long TargetDataRep, PSecBufferDesc pInput, unsigned long Reserved2, PCtxtHandle phNewContext,
		// PSecBufferDesc pOutput, unsigned long *pfContextAttr, PTimeStamp ptsExpiry );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "21d965d4-3c03-4e29-a70d-4538c5c366b0")]
		public static extern HRESULT InitializeSecurityContext(in CredHandle phCredential, [In, Optional] IntPtr phContext, string pszTargetName, [In] ASC_REQ fContextReq, [Optional] int Reserved1, [In] DREP TargetDataRep,
			[In, Optional] IntPtr pInput, [Optional] int Reserved2, ref CtxtHandle phNewContext, ref SecBufferDesc pOutput, out ASC_RET pfContextAttr, out TimeStamp ptsExpiry);

		/// <summary>
		/// <para>
		/// The <c>InitializeSecurityContext (General)</c> function initiates the client side, outbound security context from a credential
		/// handle. The function is used to build a security context between the client application and a remote peer.
		/// <c>InitializeSecurityContext (General)</c> returns a token that the client must pass to the remote peer, which the peer in turn
		/// submits to the local security implementation through the AcceptSecurityContext (General) call. The token generated should be
		/// considered opaque by all callers.
		/// </para>
		/// <para>
		/// Typically, the <c>InitializeSecurityContext (General)</c> function is called in a loop until a sufficient security context is established.
		/// </para>
		/// <para>For information about using this function with a specific security support provider (SSP), see the following topics.</para>
		/// <list type="table">
		///   <listheader>
		///     <term>Topic</term>
		///     <term>Description</term>
		///   </listheader>
		///   <item>
		///     <term>InitializeSecurityContext (CredSSP)</term>
		///     <term>
		/// Initiates the client side, outbound security context from a credential handle by using the Credential Security Support Provider (CredSSP).
		/// </term>
		///   </item>
		///   <item>
		///     <term>InitializeSecurityContext (Digest)</term>
		///     <term>Initiates the client side, outbound security context from a credential handle by using the Digest security package.</term>
		///   </item>
		///   <item>
		///     <term>InitializeSecurityContext (Kerberos)</term>
		///     <term>Initiates the client side, outbound security context from a credential handle by using the Kerberos security package.</term>
		///   </item>
		///   <item>
		///     <term>InitializeSecurityContext (Negotiate)</term>
		///     <term>Initiates the client side, outbound security context from a credential handle by using the Negotiate security package.</term>
		///   </item>
		///   <item>
		///     <term>InitializeSecurityContext (NTLM)</term>
		///     <term>Initiates the client side, outbound security context from a credential handle by using the NTLM security package.</term>
		///   </item>
		///   <item>
		///     <term>InitializeSecurityContext (Schannel)</term>
		///     <term>Initiates the client side, outbound security context from a credential handle by using the Schannel security package.</term>
		///   </item>
		/// </list>
		/// </summary>
		/// <param name="phCredential">A handle to the credentials returned by AcquireCredentialsHandle (General). This handle is used to build the security context.
		/// The <c>InitializeSecurityContext (General)</c> function requires at least OUTBOUND credentials.</param>
		/// <param name="phContext"><para>
		/// A pointer to a CtxtHandle structure. On the first call to <c>InitializeSecurityContext (General)</c>, this pointer is
		/// <c>NULL</c>. On the second call, this parameter is a pointer to the handle to the partially formed context returned in the
		/// phNewContext parameter by the first call.
		/// </para>
		/// <para>This parameter is optional with the Microsoft Digest SSP and can be set to <c>NULL</c>.</para>
		/// <para>
		/// When using the Schannel SSP, on the first call to <c>InitializeSecurityContext (General)</c>, specify <c>NULL</c>. On future
		/// calls, specify the token received in the phNewContext parameter after the first call to this function.
		/// </para></param>
		/// <param name="pszTargetName">TBD</param>
		/// <param name="fContextReq"><para>
		/// Bit flags that indicate requests for the context. Not all packages can support all requirements. Flags used for this parameter
		/// are prefixed with ISC_REQ_, for example, ISC_REQ_DELEGATE. This parameter can be one or more of the following attributes flags.
		/// </para>
		/// <list type="table">
		///   <listheader>
		///     <term>Value</term>
		///     <term>Meaning</term>
		///   </listheader>
		///   <item>
		///     <term>ISC_REQ_ALLOCATE_MEMORY</term>
		///     <term>
		/// The security package allocates output buffers for you. When you have finished using the output buffers, free them by calling the
		/// FreeContextBuffer function.
		/// </term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_CONFIDENTIALITY</term>
		///     <term>Encrypt messages by using the EncryptMessage function.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_CONNECTION</term>
		///     <term>
		/// The security context will not handle formatting messages. This value is the default for the Kerberos, Negotiate, and NTLM
		/// security packages.
		/// </term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_DELEGATE</term>
		///     <term>
		/// The server can use the context to authenticate to other servers as the client. The ISC_REQ_MUTUAL_AUTH flag must be set for this
		/// flag to work. Valid for Kerberos. Ignore this flag for constrained delegation.
		/// </term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_EXTENDED_ERROR</term>
		///     <term>When errors occur, the remote party will be notified.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_HTTP</term>
		///     <term>Use Digest for HTTP. Omit this flag to use Digest as a SASL mechanism.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_INTEGRITY</term>
		///     <term>Sign messages and verify signatures by using the EncryptMessage and MakeSignature functions.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_MANUAL_CRED_VALIDATION</term>
		///     <term>Schannel must not authenticate the server automatically.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_MUTUAL_AUTH</term>
		///     <term>The mutual authentication policy of the service will be satisfied.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_NO_INTEGRITY</term>
		///     <term>
		/// If this flag is set, the ISC_REQ_INTEGRITY flag is ignored. This value is supported only by the Negotiate and Kerberos security packages.
		/// </term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_REPLAY_DETECT</term>
		///     <term>Detect replayed messages that have been encoded by using the EncryptMessage or MakeSignature functions.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_SEQUENCE_DETECT</term>
		///     <term>Detect messages received out of sequence.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_STREAM</term>
		///     <term>Support a stream-oriented connection.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_USE_SESSION_KEY</term>
		///     <term>A new session key must be negotiated. This value is supported only by the Kerberos security package.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_USE_SUPPLIED_CREDS</term>
		///     <term>Schannel must not attempt to supply credentials for the client automatically.</term>
		///   </item>
		/// </list>
		/// <para>The requested attributes may not be supported by the client. For more information, see the pfContextAttr parameter.</para>
		/// <para>For further descriptions of the various attributes, see Context Requirements.</para></param>
		/// <param name="TargetDataRep"><para>The data representation, such as byte ordering, on the target. This parameter can be either SECURITY_NATIVE_DREP or SECURITY_NETWORK_DREP.</para>
		/// <para>This parameter is not used with Digest or Schannel. Set it to zero.</para></param>
		/// <param name="pInput">A pointer to a SecBufferDesc structure that contains pointers to the buffers supplied as input to the package. Unless the client
		/// context was initiated by the server, the value of this parameter must be <c>NULL</c> on the first call to the function. On
		/// subsequent calls to the function or when the client context was initiated by the server, the value of this parameter is a pointer
		/// to a buffer allocated with enough memory to hold the token returned by the remote computer.</param>
		/// <param name="outputType">Type of the output.</param>
		/// <param name="pOutput"><para>
		/// A pointer to a SecBufferDesc structure that contains pointers to the SecBuffer structure that receives the output data. If a
		/// buffer was typed as SEC_READWRITE in the input, it will be there on output. The system will allocate a buffer for the security
		/// token if requested (through ISC_REQ_ALLOCATE_MEMORY) and fill in the address in the buffer descriptor for the security token.
		/// </para>
		/// <para>When using the Microsoft Digest SSP, this parameter receives the challenge response that must be sent to the server.</para>
		/// <para>
		/// When using the Schannel SSP, if the ISC_REQ_ALLOCATE_MEMORY flag is specified, the Schannel SSP will allocate memory for the
		/// buffer and put the appropriate information in the SecBufferDesc. In addition, the caller must pass in a buffer of type
		/// <c>SECBUFFER_ALERT</c>. On output, if an alert is generated, this buffer contains information about that alert, and the function fails.
		/// </para></param>
		/// <param name="pfContextAttr"><para>
		/// A pointer to a variable to receive a set of bit flags that indicate the attributes of the established context. For a description
		/// of the various attributes, see Context Requirements.
		/// </para>
		/// <para>Flags used for this parameter are prefixed with ISC_RET, such as ISC_RET_DELEGATE.</para>
		/// <para>For a list of valid values, see the fContextReq parameter.</para>
		/// <para>
		/// Do not check for security-related attributes until the final function call returns successfully. Attribute flags that are not
		/// related to security, such as the ASC_RET_ALLOCATED_MEMORY flag, can be checked before the final return.
		/// </para>
		/// <para>
		///   <c>Note</c> Particular context attributes can change during negotiation with a remote peer.</para></param>
		/// <param name="ptsExpiry"><para>
		/// A pointer to a TimeStamp structure that receives the expiration time of the context. It is recommended that the security package
		/// always return this value in local time. This parameter is optional and <c>NULL</c> should be passed for short-lived clients.
		/// </para>
		/// <para>There is no expiration time for Microsoft Digest SSP security contexts or credentials.</para></param>
		/// <returns>
		/// <para>If the function succeeds, the function returns one of the following success codes.</para>
		/// <list type="table">
		///   <listheader>
		///     <term>Return code</term>
		///     <term>Description</term>
		///   </listheader>
		///   <item>
		///     <term>SEC_I_COMPLETE_AND_CONTINUE</term>
		///     <term>
		/// The client must call CompleteAuthToken and then pass the output to the server. The client then waits for a returned token and
		/// passes it, in another call, to InitializeSecurityContext (General).
		/// </term>
		///   </item>
		///   <item>
		///     <term>SEC_I_COMPLETE_NEEDED</term>
		///     <term>The client must finish building the message and then call the CompleteAuthToken function.</term>
		///   </item>
		///   <item>
		///     <term>SEC_I_CONTINUE_NEEDED</term>
		///     <term>
		/// The client must send the output token to the server and wait for a return token. The returned token is then passed in another
		/// call to InitializeSecurityContext (General). The output token can be empty.
		/// </term>
		///   </item>
		///   <item>
		///     <term>SEC_I_INCOMPLETE_CREDENTIALS</term>
		///     <term>
		/// Use with Schannel. The server has requested client authentication, and the supplied credentials either do not include a
		/// certificate or the certificate was not issued by a certification authority that is trusted by the server. For more information,
		/// see Remarks.
		/// </term>
		///   </item>
		///   <item>
		///     <term>SEC_E_INCOMPLETE_MESSAGE</term>
		///     <term>
		/// Use with Schannel. Data for the whole message was not read from the wire. When this value is returned, the pInput buffer contains
		/// a SecBuffer structure with a BufferType member of SECBUFFER_MISSING. The cbBuffer member of SecBuffer contains a value that
		/// indicates the number of additional bytes that the function must read from the client before this function succeeds. While this
		/// number is not always accurate, using it can help improve performance by avoiding multiple calls to this function.
		/// </term>
		///   </item>
		///   <item>
		///     <term>SEC_E_OK</term>
		///     <term>
		/// The security context was successfully initialized. There is no need for another InitializeSecurityContext (General) call. If the
		/// function returns an output token, that is, if the SECBUFFER_TOKEN in pOutput is of nonzero length, that token must be sent to the server.
		/// </term>
		///   </item>
		/// </list>
		/// <para>If the function fails, the function returns one of the following error codes.</para>
		/// <list type="table">
		///   <listheader>
		///     <term>Return code</term>
		///     <term>Description</term>
		///   </listheader>
		///   <item>
		///     <term>SEC_E_INSUFFICIENT_MEMORY</term>
		///     <term>There is not enough memory available to complete the requested action.</term>
		///   </item>
		///   <item>
		///     <term>SEC_E_INTERNAL_ERROR</term>
		///     <term>An error occurred that did not map to an SSPI error code.</term>
		///   </item>
		///   <item>
		///     <term>SEC_E_INVALID_HANDLE</term>
		///     <term>The handle passed to the function is not valid.</term>
		///   </item>
		///   <item>
		///     <term>SEC_E_INVALID_TOKEN</term>
		///     <term>
		/// The error is due to a malformed input token, such as a token corrupted in transit, a token of incorrect size, or a token passed
		/// into the wrong security package. Passing a token to the wrong package can happen if the client and server did not negotiate the
		/// proper security package.
		/// </term>
		///   </item>
		///   <item>
		///     <term>SEC_E_LOGON_DENIED</term>
		///     <term>The logon failed.</term>
		///   </item>
		///   <item>
		///     <term>SEC_E_NO_AUTHENTICATING_AUTHORITY</term>
		///     <term>
		/// No authority could be contacted for authentication. The domain name of the authenticating party could be wrong, the domain could
		/// be unreachable, or there might have been a trust relationship failure.
		/// </term>
		///   </item>
		///   <item>
		///     <term>SEC_E_NO_CREDENTIALS</term>
		///     <term>No credentials are available in the security package.</term>
		///   </item>
		///   <item>
		///     <term>SEC_E_TARGET_UNKNOWN</term>
		///     <term>The target was not recognized.</term>
		///   </item>
		///   <item>
		///     <term>SEC_E_UNSUPPORTED_FUNCTION</term>
		///     <term>
		/// A context attribute flag that is not valid (ISC_REQ_DELEGATE or ISC_REQ_PROMPT_FOR_CREDS) was specified in the fContextReq parameter.
		/// </term>
		///   </item>
		///   <item>
		///     <term>SEC_E_WRONG_PRINCIPAL</term>
		///     <term>
		/// The principal that received the authentication request is not the same as the one passed into the pszTargetName parameter. This
		/// indicates a failure in mutual authentication.
		/// </term>
		///   </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The caller is responsible for determining whether the final context attributes are sufficient. If, for example, confidentiality
		/// was requested, but could not be established, some applications may choose to shut down the connection immediately.
		/// </para>
		/// <para>
		/// If attributes of the security context are not sufficient, the client must free the partially created context by calling the
		/// DeleteSecurityContext function.
		/// </para>
		/// <para>The <c>InitializeSecurityContext (General)</c> function is used by a client to initialize an outbound context.</para>
		/// <para>For a two-leg security context, the calling sequence is as follows:</para>
		/// <list type="number">
		///   <item>
		///     <term>The client calls the function with phContext set to <c>NULL</c> and fills in the buffer descriptor with the input message.</term>
		///   </item>
		///   <item>
		///     <term>
		/// The security package examines the parameters and constructs an opaque token, placing it in the TOKEN element in the buffer array.
		/// If the fContextReq parameter includes the ISC_REQ_ALLOCATE_MEMORY flag, the security package allocates the memory and returns the
		/// pointer in the TOKEN element.
		/// </term>
		///   </item>
		///   <item>
		///     <term>
		/// The client sends the token returned in the pOutput buffer to the target server. The server then passes the token as an input
		/// argument in a call to the AcceptSecurityContext (General) function.
		/// </term>
		///   </item>
		///   <item>
		///     <term>
		/// AcceptSecurityContext (General) may return a token, which the server sends to the client for a second call to
		/// <c>InitializeSecurityContext (General)</c> if the first call returned SEC_I_CONTINUE_NEEDED.
		/// </term>
		///   </item>
		/// </list>
		/// <para>For multiple-leg security contexts, such as mutual authentication, the calling sequence is as follows:</para>
		/// <list type="number">
		///   <item>
		///     <term>The client calls the function as described earlier, but the package returns the SEC_I_CONTINUE_NEEDED success code.</term>
		///   </item>
		///   <item>
		///     <term>The client sends the output token to the server and waits for the server's reply.</term>
		///   </item>
		///   <item>
		///     <term>
		/// Upon receipt of the server's response, the client calls <c>InitializeSecurityContext (General)</c> again, with phContext set to
		/// the handle that was returned from the last call. The token received from the server is supplied in the pInput parameter.
		/// </term>
		///   </item>
		/// </list>
		/// <para>If the server has successfully responded, the security package returns SEC_E_OK and a secure session is established.</para>
		/// <para>If the function returns one of the error responses, the server's response is not accepted, and the session is not established.</para>
		/// <para>
		/// If the function returns SEC_I_CONTINUE_NEEDED, SEC_I_COMPLETE_NEEDED, or SEC_I_COMPLETE_AND_CONTINUE, steps 2 and 3 are repeated.
		/// </para>
		/// <para>
		/// To initialize a security context, more than one call to this function may be required, depending on the underlying authentication
		/// mechanism as well as the choices specified in the fContextReq parameter.
		/// </para>
		/// <para>
		/// The fContextReq and pfContextAttributes parameters are bitmasks that represent various context attributes. For a description of
		/// the various attributes, see Context Requirements. The pfContextAttributes parameter is valid on any successful return, but only
		/// on the final successful return should you examine the flags that pertain to security aspects of the context. Intermediate returns
		/// can set, for example, the ISC_RET_ALLOCATED_MEMORY flag.
		/// </para>
		/// <para>
		/// If the ISC_REQ_USE_SUPPLIED_CREDS flag is set, the security package must look for a SECBUFFER_PKG_PARAMS buffer type in the
		/// pInput input buffer. This is not a generic solution, but it allows for a strong pairing of security package and application when appropriate.
		/// </para>
		/// <para>If ISC_REQ_ALLOCATE_MEMORY was specified, the caller must free the memory by calling the FreeContextBuffer function.</para>
		/// <para>
		/// For example, the input token could be the challenge from a LAN Manager. In this case, the output token would be the
		/// NTLM-encrypted response to the challenge.
		/// </para>
		/// <para>
		/// The action the client takes depends on the return code from this function. If the return code is SEC_E_OK, there will be no
		/// second <c>InitializeSecurityContext (General)</c> call, and no response from the server is expected. If the return code is
		/// SEC_I_CONTINUE_NEEDED, the client expects a token in response from the server and passes it in a second call to
		/// <c>InitializeSecurityContext (General)</c>. The SEC_I_COMPLETE_NEEDED return code indicates that the client must finish building
		/// the message and call the CompleteAuthToken function. The SEC_I_COMPLETE_AND_CONTINUE code incorporates both of these actions.
		/// </para>
		/// <para>
		/// If <c>InitializeSecurityContext (General)</c> returns success on the first (or only) call, then the caller must eventually call
		/// the DeleteSecurityContext function on the returned handle, even if the call fails on a later leg of the authentication exchange.
		/// </para>
		/// <para>
		/// The client may call <c>InitializeSecurityContext (General)</c> again after it has completed successfully. This indicates to the
		/// security package that a reauthentication is wanted.
		/// </para>
		/// <para>
		/// Kernel mode callers have the following differences: the target name is a Unicode string that must be allocated in virtual memory
		/// by using VirtualAlloc; it must not be allocated from the pool. Buffers passed and supplied in pInput and pOutput must be in
		/// virtual memory, not in the pool.
		/// </para>
		/// <para>
		/// When using the Schannel SSP, if the function returns SEC_I_INCOMPLETE_CREDENTIALS, check that you specified a valid and trusted
		/// certificate in your credentials. The certificate is specified when calling the AcquireCredentialsHandle (General) function. The
		/// certificate must be a client authentication certificate issued by a certification authority (CA) trusted by the server. To obtain
		/// a list of the CAs trusted by the server, call the QueryContextAttributes (General) function and specify the
		/// SECPKG_ATTR_ISSUER_LIST_EX attribute.
		/// </para>
		/// <para>
		/// When using the Schannel SSP, after a client application receives an authentication certificate from a CA that is trusted by the
		/// server, the application creates a new credential by calling the AcquireCredentialsHandle (General) function and then calling
		/// <c>InitializeSecurityContext (General)</c> again, specifying the new credential in the phCredential parameter.
		/// </para>
		/// </remarks>
		public static HRESULT InitializeSecurityContext(in CredHandle phCredential, [In, Out] SafeCtxtHandle phContext, string pszTargetName, ASC_REQ fContextReq, DREP TargetDataRep,
			[In, Optional] SecBufferDesc? pInput, SecBufferType outputType, out SafeSecBufferDesc pOutput, out ASC_RET pfContextAttr, out TimeStamp ptsExpiry)
		{
			pOutput = new SafeSecBufferDesc(outputType);
			return InitializeSecurityContext(phCredential, phContext, pszTargetName, fContextReq, TargetDataRep, pInput, pOutput, out pfContextAttr, out ptsExpiry);
		}

		/// <summary>
		/// <para>
		/// The <c>InitializeSecurityContext (General)</c> function initiates the client side, outbound security context from a credential
		/// handle. The function is used to build a security context between the client application and a remote peer.
		/// <c>InitializeSecurityContext (General)</c> returns a token that the client must pass to the remote peer, which the peer in turn
		/// submits to the local security implementation through the AcceptSecurityContext (General) call. The token generated should be
		/// considered opaque by all callers.
		/// </para>
		/// <para>
		/// Typically, the <c>InitializeSecurityContext (General)</c> function is called in a loop until a sufficient security context is established.
		/// </para>
		/// <para>For information about using this function with a specific security support provider (SSP), see the following topics.</para>
		/// <list type="table">
		///   <listheader>
		///     <term>Topic</term>
		///     <term>Description</term>
		///   </listheader>
		///   <item>
		///     <term>InitializeSecurityContext (CredSSP)</term>
		///     <term>
		/// Initiates the client side, outbound security context from a credential handle by using the Credential Security Support Provider (CredSSP).
		/// </term>
		///   </item>
		///   <item>
		///     <term>InitializeSecurityContext (Digest)</term>
		///     <term>Initiates the client side, outbound security context from a credential handle by using the Digest security package.</term>
		///   </item>
		///   <item>
		///     <term>InitializeSecurityContext (Kerberos)</term>
		///     <term>Initiates the client side, outbound security context from a credential handle by using the Kerberos security package.</term>
		///   </item>
		///   <item>
		///     <term>InitializeSecurityContext (Negotiate)</term>
		///     <term>Initiates the client side, outbound security context from a credential handle by using the Negotiate security package.</term>
		///   </item>
		///   <item>
		///     <term>InitializeSecurityContext (NTLM)</term>
		///     <term>Initiates the client side, outbound security context from a credential handle by using the NTLM security package.</term>
		///   </item>
		///   <item>
		///     <term>InitializeSecurityContext (Schannel)</term>
		///     <term>Initiates the client side, outbound security context from a credential handle by using the Schannel security package.</term>
		///   </item>
		/// </list>
		/// </summary>
		/// <param name="phCredential">A handle to the credentials returned by AcquireCredentialsHandle (General). This handle is used to build the security context.
		/// The <c>InitializeSecurityContext (General)</c> function requires at least OUTBOUND credentials.</param>
		/// <param name="phContext"><para>
		/// A pointer to a CtxtHandle structure. On the first call to <c>InitializeSecurityContext (General)</c>, this pointer is
		/// <c>NULL</c>. On the second call, this parameter is a pointer to the handle to the partially formed context returned in the
		/// phNewContext parameter by the first call.
		/// </para>
		/// <para>This parameter is optional with the Microsoft Digest SSP and can be set to <c>NULL</c>.</para>
		/// <para>
		/// When using the Schannel SSP, on the first call to <c>InitializeSecurityContext (General)</c>, specify <c>NULL</c>. On future
		/// calls, specify the token received in the phNewContext parameter after the first call to this function.
		/// </para></param>
		/// <param name="pszTargetName">TBD</param>
		/// <param name="fContextReq"><para>
		/// Bit flags that indicate requests for the context. Not all packages can support all requirements. Flags used for this parameter
		/// are prefixed with ISC_REQ_, for example, ISC_REQ_DELEGATE. This parameter can be one or more of the following attributes flags.
		/// </para>
		/// <list type="table">
		///   <listheader>
		///     <term>Value</term>
		///     <term>Meaning</term>
		///   </listheader>
		///   <item>
		///     <term>ISC_REQ_ALLOCATE_MEMORY</term>
		///     <term>
		/// The security package allocates output buffers for you. When you have finished using the output buffers, free them by calling the
		/// FreeContextBuffer function.
		/// </term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_CONFIDENTIALITY</term>
		///     <term>Encrypt messages by using the EncryptMessage function.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_CONNECTION</term>
		///     <term>
		/// The security context will not handle formatting messages. This value is the default for the Kerberos, Negotiate, and NTLM
		/// security packages.
		/// </term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_DELEGATE</term>
		///     <term>
		/// The server can use the context to authenticate to other servers as the client. The ISC_REQ_MUTUAL_AUTH flag must be set for this
		/// flag to work. Valid for Kerberos. Ignore this flag for constrained delegation.
		/// </term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_EXTENDED_ERROR</term>
		///     <term>When errors occur, the remote party will be notified.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_HTTP</term>
		///     <term>Use Digest for HTTP. Omit this flag to use Digest as a SASL mechanism.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_INTEGRITY</term>
		///     <term>Sign messages and verify signatures by using the EncryptMessage and MakeSignature functions.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_MANUAL_CRED_VALIDATION</term>
		///     <term>Schannel must not authenticate the server automatically.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_MUTUAL_AUTH</term>
		///     <term>The mutual authentication policy of the service will be satisfied.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_NO_INTEGRITY</term>
		///     <term>
		/// If this flag is set, the ISC_REQ_INTEGRITY flag is ignored. This value is supported only by the Negotiate and Kerberos security packages.
		/// </term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_REPLAY_DETECT</term>
		///     <term>Detect replayed messages that have been encoded by using the EncryptMessage or MakeSignature functions.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_SEQUENCE_DETECT</term>
		///     <term>Detect messages received out of sequence.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_STREAM</term>
		///     <term>Support a stream-oriented connection.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_USE_SESSION_KEY</term>
		///     <term>A new session key must be negotiated. This value is supported only by the Kerberos security package.</term>
		///   </item>
		///   <item>
		///     <term>ISC_REQ_USE_SUPPLIED_CREDS</term>
		///     <term>Schannel must not attempt to supply credentials for the client automatically.</term>
		///   </item>
		/// </list>
		/// <para>The requested attributes may not be supported by the client. For more information, see the pfContextAttr parameter.</para>
		/// <para>For further descriptions of the various attributes, see Context Requirements.</para></param>
		/// <param name="TargetDataRep"><para>The data representation, such as byte ordering, on the target. This parameter can be either SECURITY_NATIVE_DREP or SECURITY_NETWORK_DREP.</para>
		/// <para>This parameter is not used with Digest or Schannel. Set it to zero.</para></param>
		/// <param name="pInput">A pointer to a SecBufferDesc structure that contains pointers to the buffers supplied as input to the package. Unless the client
		/// context was initiated by the server, the value of this parameter must be <c>NULL</c> on the first call to the function. On
		/// subsequent calls to the function or when the client context was initiated by the server, the value of this parameter is a pointer
		/// to a buffer allocated with enough memory to hold the token returned by the remote computer.</param>
		/// <param name="pOutput"><para>
		/// A pointer to a SecBufferDesc structure that contains pointers to the SecBuffer structure that receives the output data. If a
		/// buffer was typed as SEC_READWRITE in the input, it will be there on output. The system will allocate a buffer for the security
		/// token if requested (through ISC_REQ_ALLOCATE_MEMORY) and fill in the address in the buffer descriptor for the security token.
		/// </para>
		/// <para>When using the Microsoft Digest SSP, this parameter receives the challenge response that must be sent to the server.</para>
		/// <para>
		/// When using the Schannel SSP, if the ISC_REQ_ALLOCATE_MEMORY flag is specified, the Schannel SSP will allocate memory for the
		/// buffer and put the appropriate information in the SecBufferDesc. In addition, the caller must pass in a buffer of type
		/// <c>SECBUFFER_ALERT</c>. On output, if an alert is generated, this buffer contains information about that alert, and the function fails.
		/// </para></param>
		/// <param name="pfContextAttr"><para>
		/// A pointer to a variable to receive a set of bit flags that indicate the attributes of the established context. For a description
		/// of the various attributes, see Context Requirements.
		/// </para>
		/// <para>Flags used for this parameter are prefixed with ISC_RET, such as ISC_RET_DELEGATE.</para>
		/// <para>For a list of valid values, see the fContextReq parameter.</para>
		/// <para>
		/// Do not check for security-related attributes until the final function call returns successfully. Attribute flags that are not
		/// related to security, such as the ASC_RET_ALLOCATED_MEMORY flag, can be checked before the final return.
		/// </para>
		/// <para>
		///   <c>Note</c> Particular context attributes can change during negotiation with a remote peer.</para></param>
		/// <param name="ptsExpiry"><para>
		/// A pointer to a TimeStamp structure that receives the expiration time of the context. It is recommended that the security package
		/// always return this value in local time. This parameter is optional and <c>NULL</c> should be passed for short-lived clients.
		/// </para>
		/// <para>There is no expiration time for Microsoft Digest SSP security contexts or credentials.</para></param>
		/// <returns>
		/// <para>If the function succeeds, the function returns one of the following success codes.</para>
		/// <list type="table">
		///   <listheader>
		///     <term>Return code</term>
		///     <term>Description</term>
		///   </listheader>
		///   <item>
		///     <term>SEC_I_COMPLETE_AND_CONTINUE</term>
		///     <term>
		/// The client must call CompleteAuthToken and then pass the output to the server. The client then waits for a returned token and
		/// passes it, in another call, to InitializeSecurityContext (General).
		/// </term>
		///   </item>
		///   <item>
		///     <term>SEC_I_COMPLETE_NEEDED</term>
		///     <term>The client must finish building the message and then call the CompleteAuthToken function.</term>
		///   </item>
		///   <item>
		///     <term>SEC_I_CONTINUE_NEEDED</term>
		///     <term>
		/// The client must send the output token to the server and wait for a return token. The returned token is then passed in another
		/// call to InitializeSecurityContext (General). The output token can be empty.
		/// </term>
		///   </item>
		///   <item>
		///     <term>SEC_I_INCOMPLETE_CREDENTIALS</term>
		///     <term>
		/// Use with Schannel. The server has requested client authentication, and the supplied credentials either do not include a
		/// certificate or the certificate was not issued by a certification authority that is trusted by the server. For more information,
		/// see Remarks.
		/// </term>
		///   </item>
		///   <item>
		///     <term>SEC_E_INCOMPLETE_MESSAGE</term>
		///     <term>
		/// Use with Schannel. Data for the whole message was not read from the wire. When this value is returned, the pInput buffer contains
		/// a SecBuffer structure with a BufferType member of SECBUFFER_MISSING. The cbBuffer member of SecBuffer contains a value that
		/// indicates the number of additional bytes that the function must read from the client before this function succeeds. While this
		/// number is not always accurate, using it can help improve performance by avoiding multiple calls to this function.
		/// </term>
		///   </item>
		///   <item>
		///     <term>SEC_E_OK</term>
		///     <term>
		/// The security context was successfully initialized. There is no need for another InitializeSecurityContext (General) call. If the
		/// function returns an output token, that is, if the SECBUFFER_TOKEN in pOutput is of nonzero length, that token must be sent to the server.
		/// </term>
		///   </item>
		/// </list>
		/// <para>If the function fails, the function returns one of the following error codes.</para>
		/// <list type="table">
		///   <listheader>
		///     <term>Return code</term>
		///     <term>Description</term>
		///   </listheader>
		///   <item>
		///     <term>SEC_E_INSUFFICIENT_MEMORY</term>
		///     <term>There is not enough memory available to complete the requested action.</term>
		///   </item>
		///   <item>
		///     <term>SEC_E_INTERNAL_ERROR</term>
		///     <term>An error occurred that did not map to an SSPI error code.</term>
		///   </item>
		///   <item>
		///     <term>SEC_E_INVALID_HANDLE</term>
		///     <term>The handle passed to the function is not valid.</term>
		///   </item>
		///   <item>
		///     <term>SEC_E_INVALID_TOKEN</term>
		///     <term>
		/// The error is due to a malformed input token, such as a token corrupted in transit, a token of incorrect size, or a token passed
		/// into the wrong security package. Passing a token to the wrong package can happen if the client and server did not negotiate the
		/// proper security package.
		/// </term>
		///   </item>
		///   <item>
		///     <term>SEC_E_LOGON_DENIED</term>
		///     <term>The logon failed.</term>
		///   </item>
		///   <item>
		///     <term>SEC_E_NO_AUTHENTICATING_AUTHORITY</term>
		///     <term>
		/// No authority could be contacted for authentication. The domain name of the authenticating party could be wrong, the domain could
		/// be unreachable, or there might have been a trust relationship failure.
		/// </term>
		///   </item>
		///   <item>
		///     <term>SEC_E_NO_CREDENTIALS</term>
		///     <term>No credentials are available in the security package.</term>
		///   </item>
		///   <item>
		///     <term>SEC_E_TARGET_UNKNOWN</term>
		///     <term>The target was not recognized.</term>
		///   </item>
		///   <item>
		///     <term>SEC_E_UNSUPPORTED_FUNCTION</term>
		///     <term>
		/// A context attribute flag that is not valid (ISC_REQ_DELEGATE or ISC_REQ_PROMPT_FOR_CREDS) was specified in the fContextReq parameter.
		/// </term>
		///   </item>
		///   <item>
		///     <term>SEC_E_WRONG_PRINCIPAL</term>
		///     <term>
		/// The principal that received the authentication request is not the same as the one passed into the pszTargetName parameter. This
		/// indicates a failure in mutual authentication.
		/// </term>
		///   </item>
		/// </list>
		/// </returns>
		/// <exception cref="System.ArgumentNullException">phContext</exception>
		/// <remarks>
		/// <para>
		/// The caller is responsible for determining whether the final context attributes are sufficient. If, for example, confidentiality
		/// was requested, but could not be established, some applications may choose to shut down the connection immediately.
		/// </para>
		/// <para>
		/// If attributes of the security context are not sufficient, the client must free the partially created context by calling the
		/// DeleteSecurityContext function.
		/// </para>
		/// <para>The <c>InitializeSecurityContext (General)</c> function is used by a client to initialize an outbound context.</para>
		/// <para>For a two-leg security context, the calling sequence is as follows:</para>
		/// <list type="number">
		///   <item>
		///     <term>The client calls the function with phContext set to <c>NULL</c> and fills in the buffer descriptor with the input message.</term>
		///   </item>
		///   <item>
		///     <term>
		/// The security package examines the parameters and constructs an opaque token, placing it in the TOKEN element in the buffer array.
		/// If the fContextReq parameter includes the ISC_REQ_ALLOCATE_MEMORY flag, the security package allocates the memory and returns the
		/// pointer in the TOKEN element.
		/// </term>
		///   </item>
		///   <item>
		///     <term>
		/// The client sends the token returned in the pOutput buffer to the target server. The server then passes the token as an input
		/// argument in a call to the AcceptSecurityContext (General) function.
		/// </term>
		///   </item>
		///   <item>
		///     <term>
		/// AcceptSecurityContext (General) may return a token, which the server sends to the client for a second call to
		/// <c>InitializeSecurityContext (General)</c> if the first call returned SEC_I_CONTINUE_NEEDED.
		/// </term>
		///   </item>
		/// </list>
		/// <para>For multiple-leg security contexts, such as mutual authentication, the calling sequence is as follows:</para>
		/// <list type="number">
		///   <item>
		///     <term>The client calls the function as described earlier, but the package returns the SEC_I_CONTINUE_NEEDED success code.</term>
		///   </item>
		///   <item>
		///     <term>The client sends the output token to the server and waits for the server's reply.</term>
		///   </item>
		///   <item>
		///     <term>
		/// Upon receipt of the server's response, the client calls <c>InitializeSecurityContext (General)</c> again, with phContext set to
		/// the handle that was returned from the last call. The token received from the server is supplied in the pInput parameter.
		/// </term>
		///   </item>
		/// </list>
		/// <para>If the server has successfully responded, the security package returns SEC_E_OK and a secure session is established.</para>
		/// <para>If the function returns one of the error responses, the server's response is not accepted, and the session is not established.</para>
		/// <para>
		/// If the function returns SEC_I_CONTINUE_NEEDED, SEC_I_COMPLETE_NEEDED, or SEC_I_COMPLETE_AND_CONTINUE, steps 2 and 3 are repeated.
		/// </para>
		/// <para>
		/// To initialize a security context, more than one call to this function may be required, depending on the underlying authentication
		/// mechanism as well as the choices specified in the fContextReq parameter.
		/// </para>
		/// <para>
		/// The fContextReq and pfContextAttributes parameters are bitmasks that represent various context attributes. For a description of
		/// the various attributes, see Context Requirements. The pfContextAttributes parameter is valid on any successful return, but only
		/// on the final successful return should you examine the flags that pertain to security aspects of the context. Intermediate returns
		/// can set, for example, the ISC_RET_ALLOCATED_MEMORY flag.
		/// </para>
		/// <para>
		/// If the ISC_REQ_USE_SUPPLIED_CREDS flag is set, the security package must look for a SECBUFFER_PKG_PARAMS buffer type in the
		/// pInput input buffer. This is not a generic solution, but it allows for a strong pairing of security package and application when appropriate.
		/// </para>
		/// <para>If ISC_REQ_ALLOCATE_MEMORY was specified, the caller must free the memory by calling the FreeContextBuffer function.</para>
		/// <para>
		/// For example, the input token could be the challenge from a LAN Manager. In this case, the output token would be the
		/// NTLM-encrypted response to the challenge.
		/// </para>
		/// <para>
		/// The action the client takes depends on the return code from this function. If the return code is SEC_E_OK, there will be no
		/// second <c>InitializeSecurityContext (General)</c> call, and no response from the server is expected. If the return code is
		/// SEC_I_CONTINUE_NEEDED, the client expects a token in response from the server and passes it in a second call to
		/// <c>InitializeSecurityContext (General)</c>. The SEC_I_COMPLETE_NEEDED return code indicates that the client must finish building
		/// the message and call the CompleteAuthToken function. The SEC_I_COMPLETE_AND_CONTINUE code incorporates both of these actions.
		/// </para>
		/// <para>
		/// If <c>InitializeSecurityContext (General)</c> returns success on the first (or only) call, then the caller must eventually call
		/// the DeleteSecurityContext function on the returned handle, even if the call fails on a later leg of the authentication exchange.
		/// </para>
		/// <para>
		/// The client may call <c>InitializeSecurityContext (General)</c> again after it has completed successfully. This indicates to the
		/// security package that a reauthentication is wanted.
		/// </para>
		/// <para>
		/// Kernel mode callers have the following differences: the target name is a Unicode string that must be allocated in virtual memory
		/// by using VirtualAlloc; it must not be allocated from the pool. Buffers passed and supplied in pInput and pOutput must be in
		/// virtual memory, not in the pool.
		/// </para>
		/// <para>
		/// When using the Schannel SSP, if the function returns SEC_I_INCOMPLETE_CREDENTIALS, check that you specified a valid and trusted
		/// certificate in your credentials. The certificate is specified when calling the AcquireCredentialsHandle (General) function. The
		/// certificate must be a client authentication certificate issued by a certification authority (CA) trusted by the server. To obtain
		/// a list of the CAs trusted by the server, call the QueryContextAttributes (General) function and specify the
		/// SECPKG_ATTR_ISSUER_LIST_EX attribute.
		/// </para>
		/// <para>
		/// When using the Schannel SSP, after a client application receives an authentication certificate from a CA that is trusted by the
		/// server, the application creates a new credential by calling the AcquireCredentialsHandle (General) function and then calling
		/// <c>InitializeSecurityContext (General)</c> again, specifying the new credential in the phCredential parameter.
		/// </para>
		/// </remarks>
		public static HRESULT InitializeSecurityContext(in CredHandle phCredential, [In, Out] SafeCtxtHandle phContext, string pszTargetName, ASC_REQ fContextReq, DREP TargetDataRep,
			SecBufferDesc? pInput, [In, Out] SafeSecBufferDesc pOutput, out ASC_RET pfContextAttr, out TimeStamp ptsExpiry)
		{
			if (phContext is null) throw new ArgumentNullException(nameof(phContext));
			unsafe
			{
				using (var pinnedInput = PinnedObject.FromNullable(pInput))
				{
					var hCtxt = CtxtHandle.Null;
					HRESULT hr = 0;
					fixed (CredHandle* pphCred = &phCredential)
						hr = InitializeSecurityContext(pphCred, phContext, pszTargetName, fContextReq | ASC_REQ.ASC_REQ_ALLOCATE_MEMORY, 0, TargetDataRep, (SecBufferDesc*)(IntPtr)pinnedInput, 0, ref hCtxt, pOutput, out pfContextAttr, out ptsExpiry);
					if (hr.Succeeded)
					{
						if (phContext.DangerousGetHandle().IsNull)
							phContext.SetHandle(hCtxt);
					}
					return hr;
				}
			}
		}

		/// <summary>
		/// The <c>InitSecurityInterface</c> function returns a pointer to an SSPI dispatch table. This function enables clients to use SSPI
		/// without binding directly to an implementation of the interface.
		/// </summary>
		/// <returns>
		/// <para>If the function succeeds, the return value is a pointer to a SecurityFunctionTable structure.</para>
		/// <para>If the function fails, the return value is <c>NULL</c>.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-initsecurityinterfacea PSecurityFunctionTableA SEC_ENTRY
		// InitSecurityInterfaceA( );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "1026eeab-e2d6-45f2-9677-82d6cfbf4e12")]
		public static unsafe extern SecurityFunctionTable* InitSecurityInterface();

		/// <summary>
		/// <para>
		/// The <c>MakeSignature</c> function generates a cryptographic checksum of the message, and also includes sequencing information to
		/// prevent message loss or insertion. <c>MakeSignature</c> allows the application to choose between several cryptographic
		/// algorithms, if supported by the chosen mechanism. The <c>MakeSignature</c> function uses the security context referenced by the
		/// context handle.
		/// </para>
		/// <para>This function is not supported by the Schannel security support provider (SSP).</para>
		/// </summary>
		/// <param name="phContext">A handle to the security context to use to sign the message.</param>
		/// <param name="fQOP">
		/// <para>
		/// Package-specific flags that indicate the quality of protection. A security package can use this parameter to enable the selection
		/// of cryptographic algorithms.
		/// </para>
		/// <para>When using the Digest SSP, this parameter must be set to zero.</para>
		/// </param>
		/// <param name="pMessage">
		/// <para>
		/// A pointer to a SecBufferDesc structure. On input, the structure references one or more SecBuffer structures that contain the
		/// message to be signed. The function does not process buffers with the SECBUFFER_READONLY_WITH_CHECKSUM attribute.
		/// </para>
		/// <para>The SecBufferDesc structure also references a SecBuffer structure of type SECBUFFER_TOKEN that receives the signature.</para>
		/// <para>When the Digest SSP is used as an HTTP authentication protocol, the buffers should be configured as follows.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Buffer #/buffer type</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>0 SECBUFFER_TOKEN</term>
		/// <term>Empty.</term>
		/// </item>
		/// <item>
		/// <term>1 SECBUFFER_PKG_PARAMS</term>
		/// <term>Method.</term>
		/// </item>
		/// <item>
		/// <term>2 SECBUFFER_PKG_PARAMS</term>
		/// <term>URL.</term>
		/// </item>
		/// <item>
		/// <term>3 SECBUFFER_PKG_PARAMS</term>
		/// <term>HEntity. For more information, see Input Buffers for the Digest Challenge Response.</term>
		/// </item>
		/// <item>
		/// <term>4 SECBUFFER_PADDING</term>
		/// <term>Empty. Receives the signature.</term>
		/// </item>
		/// </list>
		/// <para>When the Digest SSP is used as an SASL mechanism, the buffers should be configured as follows.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Buffer #/buffer type</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>0 SECBUFFER_TOKEN</term>
		/// <term>
		/// Empty. Receives the signature. This buffer must be large enough to hold the largest possible signature. Determine the size
		/// required by calling the QueryContextAttributes (General) function and specifying SECPKG_ATTR_SIZES. Check the returned
		/// SecPkgContext_Sizes structure member cbMaxSignature.
		/// </term>
		/// </item>
		/// <item>
		/// <term>1 SECBUFFER_DATA</term>
		/// <term>Message to be signed.</term>
		/// </item>
		/// <item>
		/// <term>2 SECBUFFER_PADDING</term>
		/// <term>Empty.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="MessageSeqNo">
		/// <para>
		/// The sequence number that the transport application assigned to the message. If the transport application does not maintain
		/// sequence numbers, this parameter is zero.
		/// </para>
		/// <para>When using the Digest SSP, this parameter must be set to zero. The Digest SSP manages sequence numbering internally.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns SEC_E_OK.</para>
		/// <para>If the function fails, it returns one of the following error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_I_RENEGOTIATE</term>
		/// <term>
		/// The remote party requires a new handshake sequence or the application has just initiated a shutdown. Return to the negotiation
		/// loop and call AcceptSecurityContext (General) or InitializeSecurityContext (General) again. An empty input buffer is passed in
		/// the first call.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The context handle specified by phContext is not valid.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_TOKEN</term>
		/// <term>pMessage did not contain a valid SECBUFFER_TOKEN buffer or contained too few buffers.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_OUT_OF_SEQUENCE</term>
		/// <term>The nonce count is out of sequence.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_NO_AUTHENTICATING_AUTHORITY</term>
		/// <term>The security context (phContext) must be revalidated.</term>
		/// </item>
		/// <item>
		/// <term>STATUS_INVALID_PARAMETER</term>
		/// <term>The nonce count is not numeric.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_QOP_NOT_SUPPORTED</term>
		/// <term>The quality of protection negotiated between the client and server did not include integrity checking.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>The <c>MakeSignature</c> function generates a signature that is based on the message and the session key for the context.</para>
		/// <para>The VerifySignature function verifies the messages signed by the <c>MakeSignature</c> function.</para>
		/// <para>
		/// If the transport application created the security context to support sequence detection and the caller provides a sequence
		/// number, the function includes this information in the signature. This protects against reply, insertion, and suppression of
		/// messages. The security package incorporates the sequence number passed down from the transport application.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-makesignature KSECDDDECLSPEC SECURITY_STATUS SEC_ENTRY
		// MakeSignature( PCtxtHandle phContext, unsigned long fQOP, PSecBufferDesc pMessage, unsigned long MessageSeqNo );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "d17824b0-6121-48a3-b19b-d4fae3e1348e")]
		public static extern HRESULT MakeSignature(in CtxtHandle phContext, SECQOP fQOP, ref SecBufferDesc pMessage, uint MessageSeqNo);

		/// <summary>
		/// The <c>QueryContextAttributes (CredSSP)</c> function lets a transport application query the Credential Security Support Provider
		/// (CredSSP) security package for certain attributes of a security context.
		/// </summary>
		/// <param name="phContext">A handle to the security context to be queried.</param>
		/// <param name="ulAttribute">
		/// <para>
		/// The attribute of the context to be returned. This parameter can be one of the following values. Unless otherwise specified, the
		/// attributes are applicable to both client and server.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SECPKG_ATTR_C_ACCESS_TOKEN 0x80000012</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_AccessToken structure that specifies the access token for the current
		/// security context. This attribute is supported only on the server.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_C_FULL_ACCESS_TOKEN 0x80000082</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_AccessToken structure that specifies the access token for the current
		/// security context. This attribute is supported only on the server.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_CERT_TRUST_STATUS 0x80000084</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a CERT_TRUST_STATUS structure that specifies trust information about the certificate.
		/// This attribute is supported only on the client.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_CREDS 0x80000080</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_ClientCreds structure that specifies client credentials. The client
		/// credentials can be either user name and password or user name and smart card PIN. This attribute is supported only on the server.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_CREDS_2 0x80000086</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_ClientCreds structure that specifies client credentials. If the
		/// client credential is user name and password, the buffer is a packed KERB_INTERACTIVE_LOGON structure. If the client credential is
		/// user name and smart card PIN, the buffer is a packed KERB_CERTIFICATE_LOGON structure. If the client credential is an online
		/// identity credential, the buffer is a marshaled SEC_WINNT_AUTH_IDENTITY_EX2 structure. This attribute is supported only on the
		/// CredSSP server. Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This
		/// value is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_NEGOTIATION_PACKAGE 0x80000081</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_PackageInfo structure that specifies the name of the authentication
		/// package negotiated by the Microsoft Negotiate provider.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_PACKAGE_INFO 10</term>
		/// <term>The pBuffer parameter contains a pointer to a SecPkgContext_PackageInfostructure. Returns information on the SSP in use.</term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SERVER_AUTH_FLAGS 0x80000083</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_Flags structure that specifies information about the flags in the
		/// current security context. This attribute is supported only on the client.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SIZES 0x0</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_Sizes structure. Queries the sizes of the structures used in the
		/// per-message functions and authentication exchanges.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SUBJECT_SECURITY_ATTRIBUTES 124</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_SubjectAttributes structure. This value returns information about the
		/// security attributes for the connection. This value is supported only on the CredSSP server. Windows Server 2008, Windows Vista,
		/// Windows Server 2003 and Windows XP: This value is not supported.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pBuffer">
		/// A pointer to a structure that receives the attributes. The structure type depends on the value of the ulAttribute parameter.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns SEC_E_OK.</para>
		/// <para>If the function fails, it can return the following error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code/value</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE 0x80100003</term>
		/// <term>The function failed. The phContext parameter specifies a handle to an incomplete context.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_UNSUPPORTED_FUNCTION 0x80090302</term>
		/// <term>The function failed. The value of the ulAttribute parameter is not valid.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>The structure pointed to by the pBuffer parameter varies depending on the attribute being queried.</para>
		/// <para>
		/// While the caller must allocate the pBuffer structure itself, the SSP allocates any memory required to hold variable-sized members
		/// of the pBuffer structure. Memory allocated by the SSP must be freed by calling the FreeContextBuffer function.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-querycontextattributesw KSECDDDECLSPEC SECURITY_STATUS SEC_ENTRY
		// QueryContextAttributesW( PCtxtHandle phContext, unsigned long ulAttribute, void *pBuffer );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "4956c4ab-b71e-4960-b750-f3a79b87baac")]
		public static extern HRESULT QueryContextAttributes(in CtxtHandle phContext, SECPKG_ATTR ulAttribute, IntPtr pBuffer);

		/// <summary>
		/// The <c>QueryContextAttributes (CredSSP)</c> function lets a transport application query the Credential Security Support Provider
		/// (CredSSP) security package for certain attributes of a security context.
		/// </summary>
		/// <param name="phContext">A handle to the security context to be queried.</param>
		/// <param name="ulAttribute">
		/// <para>
		/// The attribute of the context to be returned. This parameter can be one of the following values. Unless otherwise specified, the
		/// attributes are applicable to both client and server.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SECPKG_ATTR_C_ACCESS_TOKEN 0x80000012</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_AccessToken structure that specifies the access token for the current
		/// security context. This attribute is supported only on the server.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_C_FULL_ACCESS_TOKEN 0x80000082</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_AccessToken structure that specifies the access token for the current
		/// security context. This attribute is supported only on the server.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_CERT_TRUST_STATUS 0x80000084</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a CERT_TRUST_STATUS structure that specifies trust information about the certificate.
		/// This attribute is supported only on the client.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_CREDS 0x80000080</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_ClientCreds structure that specifies client credentials. The client
		/// credentials can be either user name and password or user name and smart card PIN. This attribute is supported only on the server.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_CREDS_2 0x80000086</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_ClientCreds structure that specifies client credentials. If the
		/// client credential is user name and password, the buffer is a packed KERB_INTERACTIVE_LOGON structure. If the client credential is
		/// user name and smart card PIN, the buffer is a packed KERB_CERTIFICATE_LOGON structure. If the client credential is an online
		/// identity credential, the buffer is a marshaled SEC_WINNT_AUTH_IDENTITY_EX2 structure. This attribute is supported only on the
		/// CredSSP server. Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This
		/// value is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_NEGOTIATION_PACKAGE 0x80000081</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_PackageInfo structure that specifies the name of the authentication
		/// package negotiated by the Microsoft Negotiate provider.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_PACKAGE_INFO 10</term>
		/// <term>The pBuffer parameter contains a pointer to a SecPkgContext_PackageInfostructure. Returns information on the SSP in use.</term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SERVER_AUTH_FLAGS 0x80000083</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_Flags structure that specifies information about the flags in the
		/// current security context. This attribute is supported only on the client.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SIZES 0x0</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_Sizes structure. Queries the sizes of the structures used in the
		/// per-message functions and authentication exchanges.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SUBJECT_SECURITY_ATTRIBUTES 124</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_SubjectAttributes structure. This value returns information about the
		/// security attributes for the connection. This value is supported only on the CredSSP server. Windows Server 2008, Windows Vista,
		/// Windows Server 2003 and Windows XP: This value is not supported.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <returns>A structure that receives the attributes. The structure type depends on the value of the ulAttribute parameter.</returns>
		/// <remarks>
		/// <para>The structure pointed to by the pBuffer parameter varies depending on the attribute being queried.</para>
		/// <para>
		/// While the caller must allocate the pBuffer structure itself, the SSP allocates any memory required to hold variable-sized members
		/// of the pBuffer structure. Memory allocated by the SSP must be freed by calling the FreeContextBuffer function.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-querycontextattributesw KSECDDDECLSPEC SECURITY_STATUS SEC_ENTRY
		// QueryContextAttributesW( PCtxtHandle phContext, unsigned long ulAttribute, void *pBuffer );
		[PInvokeData("sspi.h", MSDNShortId = "4956c4ab-b71e-4960-b750-f3a79b87baac")]
		public static T QueryContextAttributes<T>(in CtxtHandle phContext, SECPKG_ATTR ulAttribute) where T : struct
		{
			if (!CorrespondingTypeAttribute.CanGet(ulAttribute, typeof(T))) throw new ArgumentException($"{typeof(T).GetType().Name} cannot be retrieved using {ulAttribute}.");
			using (var mem = SafeHGlobalHandle.CreateFromStructure<T>())
			{
				if (Environment.OSVersion.Version > new Version(6, 0))
					QueryContextAttributesEx(phContext, ulAttribute, (IntPtr)mem, (uint)mem.Size).ThrowIfFailed();
				else
					QueryContextAttributes(phContext, ulAttribute, (IntPtr)mem).ThrowIfFailed();
				return mem.ToStructure<T>();
			}
		}

		/// <summary>Enables a transport application to query a security package for certain attributes of a security context.</summary>
		/// <param name="phContext">A handle to the security context to be queried.</param>
		/// <param name="ulAttribute">
		/// <para>Specifies the attribute of the context to be returned. This parameter can be one of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SECPKG_ATTR_ACCESS_TOKEN 18</term>
		/// <term>The pBuffer parameter contains a pointer to a SecPkgContext_AccessToken structure. Returns a handle to the access token.</term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_APP_DATA 0x5e</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_SessionAppData structure. Returns or specifies application data for
		/// the session. This attribute is supported only by the Schannel security package.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_AUTHORITY 6</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_Authority structure. Queries the name of the authenticating authority.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_CLIENT_SPECIFIED_TARGET 27</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_ClientSpecifiedTarget structure that represents the service principal
		/// name (SPN) of the initial target supplied by the client. Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP:
		/// This value is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_CONNECTION_INFO 0x5a</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_ConnectionInfo structure. Returns detailed information on the
		/// established connection. This attribute is supported only by the Schannel security package.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_CREDS_2 0x80000086</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_ClientCreds structure that specifies client credentials. If the
		/// client credential is user name and password, the buffer is a packed KERB_INTERACTIVE_LOGON structure. If the client credential is
		/// user name and smart card PIN, the buffer is a packed KERB_CERTIFICATE_LOGON structure. If the client credential is an online
		/// identity credential, the buffer is a marshaled SEC_WINNT_AUTH_IDENTITY_EX2 structure. This attribute is supported only on the
		/// CredSSP server. Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This
		/// value is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_DCE_INFO 3</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_DceInfo structure. Queries for authorization data used by DCE services.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_ENDPOINT_BINDINGS 26</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_Bindings structure that specifies channel binding information. This
		/// attribute is supported only by the Schannel security package. Windows Server 2008, Windows Vista, Windows Server 2003 and Windows
		/// XP: This value is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_EAP_KEY_BLOCK 0x5b</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_EapKeyBlock structure. Queries for key data used by the EAP TLS
		/// protocol. This attribute is supported only by the Schannel security package.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_FLAGS 14</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_Flags structure. Returns information about the negotiated context flags.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_ISSUER_LIST_EX 0x59</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_IssuerListInfoEx structure. Returns a list of certificate issuers
		/// that are accepted by the server. This attribute is supported only by the Schannel security package.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_KEY_INFO 5</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_KeyInfo structure. Queries information about the keys used in a
		/// security context.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_LAST_CLIENT_TOKEN_STATUS 30</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_LastClientTokenStatus structure that specifies whether the token from
		/// the most recent call to the InitializeSecurityContext function is the last token from the client. This value is supported only by
		/// the Negotiate, Kerberos, and NTLM security packages. Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This
		/// value is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_LIFESPAN 2</term>
		/// <term>The pBuffer parameter contains a pointer to a SecPkgContext_Lifespan structure. Queries the life span of the context.</term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_LOCAL_CERT_CONTEXT 0x54</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a PCCERT_CONTEXTstructure. Finds a certificate context that contains a local end
		/// certificate. This attribute is supported only by the Schannel security package.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_LOCAL_CRED</term>
		/// <term>The pBuffer parameter contains a pointer to a SecPkgContext_LocalCredentialInfo structure. (obsolete) Superseded by SECPKG_ATTR_LOCAL_CERT_CONTEXT.</term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_NAMES 1</term>
		/// <term>The pBuffer parameter contains a pointer to a SecPkgContext_Names structure. Queries the name associated with the context.</term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_NATIVE_NAMES 13</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_NativeNames structure. Returns the principal name (CNAME) from the
		/// outbound ticket.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_NEGOTIATION_INFO 12</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_NegotiationInfo structure. Returns information about the security
		/// package to be used with the negotiation process and the current state of the negotiation for the use of that package.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_PACKAGE_INFO 10</term>
		/// <term>The pBuffer parameter contains a pointer to a SecPkgContext_PackageInfostructure. Returns information on the SSP in use.</term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_PASSWORD_EXPIRY 8</term>
		/// <term>The pBuffer parameter contains a pointer to a SecPkgContext_PasswordExpiry structure. Returns password expiration information.</term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_REMOTE_CERT_CONTEXT 0x53</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a PCCERT_CONTEXTstructure. Finds a certificate context that contains the end
		/// certificate supplied by the server. This attribute is supported only by the Schannel security package.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_ROOT_STORE 0x55</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a HCERTCONTEXT. Finds a certificate context that contains a certificate supplied by
		/// the Root store.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SESSION_KEY 9</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_SessionKey structure. Returns information about the session keys.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SESSION_INFO 0x5d</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_SessionInfo structure. Returns information about the session. Windows
		/// Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This value is not supported. This attribute is supported only by
		/// the Schannel security package.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SIZES 0</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_Sizes structure. Queries the sizes of the structures used in the
		/// per-message functions.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_STREAM_SIZES 4</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_StreamSizes structure. Queries the sizes of the various parts of a
		/// stream used in the per-message functions. This attribute is supported only by the Schannel security package.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SUBJECT_SECURITY_ATTRIBUTES 124</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_SubjectAttributes structure. This value returns information about the
		/// security attributes for the connection. This value is supported only on the CredSSP server. Windows Server 2008, Windows Vista,
		/// Windows Server 2003 and Windows XP: This value is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SUPPORTED_SIGNATURES 0x66</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_SupportedSignatures structure. This value returns information about
		/// the signature types that are supported for the connection. This value is supported only by the Schannel security package. Windows
		/// Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This value is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_TARGET_INFORMATION 17</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_TargetInformation structure. Returns information about the name of
		/// the remote server.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_UNIQUE_BINDINGS 25</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_Bindings structure that specifies channel binding information. This
		/// value is supported only by the Schannel security package. Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP:
		/// This value is not supported.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pBuffer">
		/// A pointer to a structure that receives the attributes. The type of structure pointed to depends on the value specified in the
		/// ulAttribute parameter.
		/// </param>
		/// <param name="cbBuffer">The size, in bytes, of the pBuffer parameter.</param>
		/// <returns>
		/// <para>If the function succeeds, the return value is SEC_E_OK.</para>
		/// <para>If the function fails, the return value is a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-querycontextattributesexw SECURITY_STATUS SEC_ENTRY
		// QueryContextAttributesExW( PCtxtHandle phContext, unsigned long ulAttribute, void *pBuffer, unsigned long cbBuffer );
		[DllImport(Lib.SspiCli, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "FD91EE99-F94E-44CE-9331-933D0CAA5F75", MinClient = PInvokeClient.Windows7)]
		public static extern HRESULT QueryContextAttributesEx(in CtxtHandle phContext, SECPKG_ATTR ulAttribute, IntPtr pBuffer, uint cbBuffer);

		/// <summary>
		/// Retrieves the attributes of a credential, such as the name associated with the credential. The information is valid for any
		/// security context created with the specified credential.
		/// </summary>
		/// <param name="phCredential">A handle of the credentials to be queried.</param>
		/// <param name="ulAttribute">
		/// <para>Specifies the attribute to query. This parameter can be any of the following attributes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SECPKG_CRED_ATTR_CERT</term>
		/// <term>
		/// Returns the certificate thumbprint in a pbuffer of type SecPkgCredentials_Cert. This attribute is only supported by Kerberos.
		/// Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This attribute is not available.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_CRED_ATTR_NAMES</term>
		/// <term>
		/// Returns the name of a credential in a pbuffer of type SecPkgCredentials_Names. This attribute is not supported by Schannel in
		/// WOW64 mode.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SUPPORTED_ALGS</term>
		/// <term>
		/// Returns the supported algorithms in a pbuffer of type SecPkgCred_SupportedAlgs. All supported algorithms are included, regardless
		/// of whether they are supported by the provided certificate or enabled on the local computer. This attribute is supported only by Schannel.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_CIPHER_STRENGTHS</term>
		/// <term>Returns the cipher strengths in a pbuffer of type SecPkgCred_CipherStrengths. This attribute is supported only by Schannel.</term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SUPPORTED_PROTOCOLS</term>
		/// <term>
		/// Returns the supported algorithms in a pbuffer of type SecPkgCred_SupportedProtocols. All supported protocols are included,
		/// regardless of whether they are supported by the provided certificate or enabled on the local computer. This attribute is
		/// supported only by Schannel.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pBuffer">
		/// A pointer to a buffer that receives the requested attribute. The type of structure returned depends on the value of ulAttribute.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is SEC_E_OK.</para>
		/// <para>If the function fails, the return value may be one of the following error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The handle passed to the function is not valid.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_UNSUPPORTED_FUNCTION</term>
		/// <term>
		/// The specified attribute is not supported by Schannel. This return value will only be returned when the Schannel SSP is being used.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INSUFFICIENT_MEMORY</term>
		/// <term>The memory that is available is not sufficient to complete the request.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The <c>QueryCredentialsAttributes</c> function allows an application to determine several characteristics of a credential,
		/// including the name associated with the specified credentials.
		/// </para>
		/// <para>
		/// Querying the SECPKG_ATTR_CIPHER_STRENGTHS attribute returns a SecPkgCred_CipherStrengths structure. The cipher strength in this
		/// structure is the same as the cipher strength in the SCHANNEL_CRED structure used when a credential was created.
		/// </para>
		/// <para>
		/// <c>Note</c> An application can find the system default cipher strength by querying this attribute with a default credential. A
		/// default credential is created by calling AcquireCredentialsHandle with a <c>NULL</c> pAuthData parameter.
		/// </para>
		/// <para>
		/// Querying the SECPKG_ATTR_SUPPORTED_ALGS attribute returns a SecPkgCred_SupportedAlgs structure. The algorithms in this structure
		/// are compatible with those indicated in the SCHANNEL_CRED structure used when a credential was created.
		/// </para>
		/// <para>
		/// Querying the SECPKG_ATTR_SUPPORTED_PROTOCOLS attribute returns a SecPkgCred_SupportedProtocols structure that contains a bit
		/// array compatible with the grbitEnabledProtocols field of the SCHANNEL_CRED structure.
		/// </para>
		/// <para>
		/// The caller must allocate the structure pointed to by the pBuffer parameter. The security package allocates the buffer for any
		/// pointer returned in the pBuffer structure. The caller can call the FreeContextBuffer function to free any pointers allocated by
		/// the security package.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-querycredentialsattributesa SECURITY_STATUS SEC_ENTRY
		// QueryCredentialsAttributesA( PCredHandle phCredential, unsigned long ulAttribute, void *pBuffer );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "a8ba6f73-8469-431b-b185-183b45b2c533")]
		public static extern HRESULT QueryCredentialsAttributes(in CredHandle phCredential, SECPKG_CRED_ATTR ulAttribute, IntPtr pBuffer);

		/// <summary>
		/// Retrieves the attributes of a credential, such as the name associated with the credential. The information is valid for any
		/// security context created with the specified credential.
		/// </summary>
		/// <param name="phCredential">A handle of the credentials to be queried.</param>
		/// <param name="ulAttribute">
		/// <para>Specifies the attribute to query. This parameter can be any of the following attributes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SECPKG_CRED_ATTR_CERT</term>
		/// <term>
		/// Returns the certificate thumbprint in a pbuffer of type SecPkgCredentials_Cert. This attribute is only supported by Kerberos.
		/// Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This attribute is not available.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_CRED_ATTR_NAMES</term>
		/// <term>
		/// Returns the name of a credential in a pbuffer of type SecPkgCredentials_Names. This attribute is not supported by Schannel in
		/// WOW64 mode.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SUPPORTED_ALGS</term>
		/// <term>
		/// Returns the supported algorithms in a pbuffer of type SecPkgCred_SupportedAlgs. All supported algorithms are included, regardless
		/// of whether they are supported by the provided certificate or enabled on the local computer. This attribute is supported only by Schannel.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_CIPHER_STRENGTHS</term>
		/// <term>Returns the cipher strengths in a pbuffer of type SecPkgCred_CipherStrengths. This attribute is supported only by Schannel.</term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SUPPORTED_PROTOCOLS</term>
		/// <term>
		/// Returns the supported algorithms in a pbuffer of type SecPkgCred_SupportedProtocols. All supported protocols are included,
		/// regardless of whether they are supported by the provided certificate or enabled on the local computer. This attribute is
		/// supported only by Schannel.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pBuffer">
		/// A pointer to a buffer that receives the requested attribute. The type of structure returned depends on the value of ulAttribute.
		/// </param>
		/// <param name="cbBuffer">The size, in bytes, of the pBuffer parameter.</param>
		/// <returns>
		/// <para>If the function succeeds, the return value is SEC_E_OK.</para>
		/// <para>If the function fails, the return value may be one of the following error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The handle passed to the function is not valid.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_UNSUPPORTED_FUNCTION</term>
		/// <term>
		/// The specified attribute is not supported by Schannel. This return value will only be returned when the Schannel SSP is being used.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INSUFFICIENT_MEMORY</term>
		/// <term>The memory that is available is not sufficient to complete the request.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The <c>QueryCredentialsAttributes</c> function allows an application to determine several characteristics of a credential,
		/// including the name associated with the specified credentials.
		/// </para>
		/// <para>
		/// Querying the SECPKG_ATTR_CIPHER_STRENGTHS attribute returns a SecPkgCred_CipherStrengths structure. The cipher strength in this
		/// structure is the same as the cipher strength in the SCHANNEL_CRED structure used when a credential was created.
		/// </para>
		/// <para>
		/// <c>Note</c> An application can find the system default cipher strength by querying this attribute with a default credential. A
		/// default credential is created by calling AcquireCredentialsHandle with a <c>NULL</c> pAuthData parameter.
		/// </para>
		/// <para>
		/// Querying the SECPKG_ATTR_SUPPORTED_ALGS attribute returns a SecPkgCred_SupportedAlgs structure. The algorithms in this structure
		/// are compatible with those indicated in the SCHANNEL_CRED structure used when a credential was created.
		/// </para>
		/// <para>
		/// Querying the SECPKG_ATTR_SUPPORTED_PROTOCOLS attribute returns a SecPkgCred_SupportedProtocols structure that contains a bit
		/// array compatible with the grbitEnabledProtocols field of the SCHANNEL_CRED structure.
		/// </para>
		/// <para>
		/// The caller must allocate the structure pointed to by the pBuffer parameter. The security package allocates the buffer for any
		/// pointer returned in the pBuffer structure. The caller can call the FreeContextBuffer function to free any pointers allocated by
		/// the security package.
		/// </para>
		/// </remarks>
		[DllImport(Lib.SspiCli, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MinClient = PInvokeClient.Windows7)]
		public static extern HRESULT QueryCredentialsAttributesEx(in CredHandle phCredential, SECPKG_CRED_ATTR ulAttribute, IntPtr pBuffer, uint cbBuffer);

		/// <summary>Obtains the access token for a client security context and uses it directly.</summary>
		/// <param name="phContext">Handle of the context to query.</param>
		/// <param name="Token">Returned handle to the access token.</param>
		/// <returns>
		/// <para>If the function succeeds, the function returns SEC_E_OK.</para>
		/// <para>If the function fails, it returns a nonzero error code. One possible error code return is SEC_E_INVALID_HANDLE.</para>
		/// </returns>
		/// <remarks>
		/// This function is called by a server application to control impersonation outside the SSPI layer, such as when launching a child
		/// process. The handle returned must be closed with CloseHandle when the handle is no longer needed.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-querysecuritycontexttoken KSECDDDECLSPEC SECURITY_STATUS
		// SEC_ENTRY QuerySecurityContextToken( PCtxtHandle phContext, void **Token );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "5dc23608-9ce3-4fee-8161-2e409cef4063")]
		public static extern HRESULT QuerySecurityContextToken(in CtxtHandle phContext, out SafeHTOKEN Token);

		/// <summary>
		/// Retrieves information about a specified security package. This information includes the bounds on sizes of authentication
		/// information, credentials, and contexts.
		/// </summary>
		/// <param name="pszPackageName">Pointer to a null-terminated string that specifies the name of the security package.</param>
		/// <param name="ppPackageInfo">
		/// Pointer to a variable that receives a pointer to a SecPkgInfo structure containing information about the specified security package.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is SEC_E_OK.</para>
		/// <para>If the function fails, the return value is a nonzero error code.</para>
		/// </returns>
		/// <remarks>The caller must call the FreeContextBuffer function to free the buffer returned in ppPackageInfo.</remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-querysecuritypackageinfoa SECURITY_STATUS SEC_ENTRY
		// QuerySecurityPackageInfoA( LPSTR pszPackageName, PSecPkgInfoA *ppPackageInfo );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "130ef0fe-bb13-4a65-b476-cd25ed234da1")]
		public static extern HRESULT QuerySecurityPackageInfo(string pszPackageName, out SafeContextBuffer ppPackageInfo);

		/// <summary>Allows a security package to discontinue the impersonation of the caller and restore its own security context.</summary>
		/// <param name="phContext">
		/// Handle of the security context being impersonated. This handle must have been obtained in the call to the AcceptSecurityContext
		/// (General) function and used in the call to the ImpersonateSecurityContext function.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is SEC_E_OK.</para>
		/// <para>If the function fails, the return value can be one of the following error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The handle passed to the function is not valid.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <c>RevertSecurityContext</c> is not available with all security packages on all platforms. Typically, it is implemented only on
		/// platforms and with security packages for which a call to the QuerySecurityPackageInfo function indicates impersonation support.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-revertsecuritycontext KSECDDDECLSPEC SECURITY_STATUS SEC_ENTRY
		// RevertSecurityContext( PCtxtHandle phContext );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "d4ed1fe9-2e0a-4648-a010-1eae49ba03ee")]
		public static extern HRESULT RevertSecurityContext(in CtxtHandle phContext);

		/// <summary>
		/// The <c>SaslAcceptSecurityContext</c> function wraps a standard call to the Security Support Provider Interface
		/// AcceptSecurityContext (General) function and includes creation of SASL server cookies.
		/// </summary>
		/// <param name="phCredential">
		/// A handle to the server's credentials. The server calls the AcquireCredentialsHandle function with the INBOUND flag set to
		/// retrieve this handle.
		/// </param>
		/// <param name="phContext">
		/// Pointer to a CtxtHandle structure. On the first call to AcceptSecurityContext (General), this pointer is <c>NULL</c>. On
		/// subsequent calls, phContext is the handle to the partially formed context that was returned in the phNewContext parameter by the
		/// first call.
		/// </param>
		/// <param name="pInput">
		/// <para>
		/// Pointer to a SecBufferDesc structure generated by a client call to the InitializeSecurityContext (General) function that contains
		/// the input buffer descriptor.
		/// </para>
		/// <para>
		/// SASL requires a single buffer of type <c>SECBUFFER_TOKEN</c>. The buffer is empty for the first call to the AcceptSecurityContext
		/// (General) function and contains the challenge response received from the client for the second call.
		/// </para>
		/// </param>
		/// <param name="fContextReq">
		/// <para>
		/// Bit flags that specify the attributes required by the server to establish the context. Bit flags can be combined using bitwise-
		/// <c>OR</c> operations. The following table shows the possible values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>ASC_REQ_CONFIDENTIALITY</term>
		/// <term>Encrypt and decrypt messages. Valid with the Digest SSP for SASL only.</term>
		/// </item>
		/// <item>
		/// <term>ASC_REQ_HTTP</term>
		/// <term>Use Digest for HTTP. Omit this flag to use Digest as an SASL mechanism.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="TargetDataRep">
		/// Indicates the data representation, such as byte ordering, on the target. This value can be either SECURITY_NATIVE_DREP or SECURITY_NETWORK_DREP.
		/// </param>
		/// <param name="phNewContext">
		/// Pointer to a CtxtHandle structure. On the first call to AcceptSecurityContext (General), this pointer receives the new context
		/// handle. On subsequent calls, phNewContext can be the same as the handle specified in the phContext parameter.
		/// </param>
		/// <param name="pOutput">
		/// Pointer to a SecBufferDesc structure that contains the output buffer descriptor. This buffer is sent to the client for input into
		/// additional calls to InitializeSecurityContext (General). An output buffer may be generated even if the function returns SEC_E_OK.
		/// Any buffer generated must be sent back to the client application.
		/// </param>
		/// <param name="pfContextAttr">
		/// <para>
		/// Pointer to a variable that receives a set of bit flags indicating the attributes of the established context. For a description of
		/// the various attributes, see Context Requirements. Flags used for this parameter are prefixed with ASC_RET, such as ASC_RET_DELEGATE.
		/// </para>
		/// <para>
		/// Do not check for security-related attributes until the final function call returns successfully. Attribute flags not related to
		/// security, such as the ASC_RET_ALLOCATED_MEMORY flag, can be checked before the final return.
		/// </para>
		/// </param>
		/// <param name="ptsExpiry">
		/// <para>
		/// Pointer to a <c>TimeStamp</c> structure that receives the expiration time of the context. It is recommended that the security
		/// package always return this value in local time.
		/// </para>
		/// <para>
		/// <c>Note</c> Until the last call of the authentication process, the expiration time for the context can be incorrect because more
		/// information will be provided during later stages of the negotiation. Therefore, ptsTimeStamp must be <c>NULL</c> until the last
		/// call to the function.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>
		/// If the call is completed successfully, this function returns SEC_E_OK. The following table shows some possible failure return values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_ALGORITHM_MISMATCH</term>
		/// <term>Authz processing is not permitted.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INSUFFICIENT_MEMORY</term>
		/// <term>Not enough memory is available to complete the request.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_TOKEN</term>
		/// <term>No Token buffer is located in the pOutput parameter, or the message failed to decrypt.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// The final call of the AcceptSecurityContext (General) function that returns SEC_E_OK is identified. If a return token is
		/// produced, SASL processing is suspended for one round trip back to the client to allow the final token to be processed. After the
		/// exchange is completed, SEC_E_CONTINUE_NEEDED is returned to the application with an additional SASL server cookie encrypted with
		/// SSPI message functions. The initial server cookie indicates if INTEGRITY and PRIVACY are supported. This initial server cookie is
		/// processed by the client, and the client returns a client cookie to indicate which services the client requests. The client cookie
		/// is then decrypted by the server and the final services are determined for the following message traffic.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-saslacceptsecuritycontext SECURITY_STATUS SEC_ENTRY
		// SaslAcceptSecurityContext( PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, unsigned long fContextReq,
		// unsigned long TargetDataRep, PCtxtHandle phNewContext, PSecBufferDesc pOutput, unsigned long *pfContextAttr, PTimeStamp ptsExpiry );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "39ef6522-ff70-4066-a34d-f2af2174f6ee")]
		public static unsafe extern HRESULT SaslAcceptSecurityContext([In, Optional] CredHandle* phCredential, [In, Optional] CtxtHandle* phContext, [In, Optional] SecBufferDesc* pInput, ASC_REQ fContextReq, DREP TargetDataRep,
			out CtxtHandle phNewContext, [Optional] SecBufferDesc* pOutput, out ASC_RET pfContextAttr, out TimeStamp ptsExpiry);

		/// <summary>The <c>SaslEnumerateProfiles</c> function lists the packages that provide a SASL interface.</summary>
		/// <param name="ProfileList">
		/// Pointer to a list of Unicode or ANSI strings that contain the names of the packages with SASL wrapper support.
		/// </param>
		/// <param name="ProfileCount">
		/// Pointer to an unsigned <c>LONG</c> value that contains the number of packages with SASL wrapper support.
		/// </param>
		/// <returns>
		/// <para>If the call is completed successfully, this function returns SEC_E_OK.</para>
		/// <para>If the function fails, the return value is a nonzero error code.</para>
		/// </returns>
		/// <remarks>
		/// <para>The current list is maintained in the registry under</para>
		/// <para>A terminating <c>NULL</c> character is appended to the end of the list.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-saslenumerateprofilesa SECURITY_STATUS SEC_ENTRY
		// SaslEnumerateProfilesA( LPSTR *ProfileList, ULONG *ProfileCount );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "0c11e0e3-2538-4703-bc32-31c73d65a498")]
		public static extern HRESULT SaslEnumerateProfiles([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NullTermStringArrayMarshaler), MarshalCookie = "Auto")] out string[] ProfileList, out uint ProfileCount);

		/// <summary>The <c>SaslGetContextOption</c> function retrieves the specified property of the specified SASL context.</summary>
		/// <param name="ContextHandle">Handle of the SASL context.</param>
		/// <param name="Option">
		/// <para>Property to return from the SASL context. The following table lists the possible values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SASL_OPTION_AUTHZ_PROCESSING</term>
		/// <term>
		/// Data type of buffer: ULONG State of SASL processing of the Authz value provided by the SASL application. The valid states for
		/// processing are Sasl_AuthZIDForbidden and Sasl_AuthZIDProcessed.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SASL_OPTION_AUTHZ_STRING</term>
		/// <term>
		/// Data type of buffer: Array of binary characters String of characters passed from the SASL client to the server. If the
		/// AuthZ_Processing state is Sasl_AuthZIDForbidden, the return value SEC_E_UNSUPPORTED_FUNCTION is returned.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SASL_OPTION_RECV_SIZE</term>
		/// <term>Data type of buffer: ULONG Maximum size of the receiving buffer on the local computer.</term>
		/// </item>
		/// <item>
		/// <term>SASL_OPTION_SEND_SIZE</term>
		/// <term>
		/// Data type of buffer: ULONG Maximum message data size that can be transmitted. This value is the maximum buffer size that can be
		/// transmitted to the remote SASL process minus the block size, the trailer size, and the maximum signature size.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="Value">
		/// A pointer to a buffer that receives the requested property. For the data type of the buffer for each value of the Option
		/// parameter, see the Option parameter.
		/// </param>
		/// <param name="Size">The size, in bytes, of the buffer specified by the Value parameter.</param>
		/// <param name="Needed">
		/// A pointer to an unsigned <c>LONG</c> value that returns the value if the buffer specified by the Value parameter is not large
		/// enough to contain the data value of the property specified by the Option parameter.
		/// </param>
		/// <returns>
		/// <para>
		/// If the call is completed successfully, this function returns SEC_E_OK. The following table shows some possible error return values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_BUFFER_TOO_SMALL</term>
		/// <term>
		/// The buffer specified by the Value parameter is not large enough to contain the data value of the property specified by the Option parameter.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The SASL context handle specified by the ContextHandle parameter was not found in the SASL list.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_UNSUPPORTED_FUNCTION</term>
		/// <term>The option specified in the Option parameter is not valid.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-saslgetcontextoption SECURITY_STATUS SEC_ENTRY
		// SaslGetContextOption( PCtxtHandle ContextHandle, ULONG Option, PVOID Value, ULONG Size, PULONG Needed );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "c9c424d3-07e6-4ed0-9189-c932af0475d9")]
		public static extern HRESULT SaslGetContextOption(in CtxtHandle ContextHandle, SASL_OPTION Option, [Out] IntPtr Value, uint Size, out uint Needed);

		/// <summary>The <c>SaslGetProfilePackage</c> function returns the package information for the specified package.</summary>
		/// <param name="ProfileName">Unicode or ANSI string that contains the name of the SASL package.</param>
		/// <param name="PackageInfo">
		/// Pointer to a pointer to a SecPkgInfo structure that returns the package information for the package specified by the ProfileName parameter.
		/// </param>
		/// <returns>
		/// <para>
		/// If the call is completed successfully, this function returns SEC_E_OK. The following table shows some possible failure return values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_SECPKG_NOT_FOUND</term>
		/// <term>The SASL profile specified by the ProfileName parameter could not be found.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INSUFFICIENT_MEMORY</term>
		/// <term>Memory could not be allocated for the SecPkgInfo structure.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-saslgetprofilepackagew SECURITY_STATUS SEC_ENTRY
		// SaslGetProfilePackageW( LPWSTR ProfileName, PSecPkgInfoW *PackageInfo );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "b7cecc5f-775f-40ba-abfc-27d51b3f5395")]
		public static extern HRESULT SaslGetProfilePackage(string ProfileName, out SafeContextBuffer PackageInfo);

		/// <summary>
		/// The <c>SaslIdentifyPackage</c> function returns the negotiate prefix that matches the specified SASL negotiation buffer.
		/// </summary>
		/// <param name="pInput">
		/// Pointer to a SecBufferDesc structure that specifies the SASL negotiation buffer for which to find the negotiate prefix.
		/// </param>
		/// <param name="PackageInfo">
		/// Pointer to a pointer to a SecPkgInfo structure that returns the negotiate prefix for the negotiation buffer specified by the
		/// pInput parameter.
		/// </param>
		/// <returns>
		/// <para>If the call is completed successfully, this function returns SEC_E_OK.</para>
		/// <para>If the function fails, the return value is a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-saslidentifypackagea SECURITY_STATUS SEC_ENTRY
		// SaslIdentifyPackageA( PSecBufferDesc pInput, PSecPkgInfoA *PackageInfo );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "df6f4749-8f28-4ee5-8165-f7aeb3bea7ab")]
		public static extern HRESULT SaslIdentifyPackage(ref SecBufferDesc pInput, out SafeContextBuffer PackageInfo);

		/// <summary>
		/// The <c>SaslInitializeSecurityContext</c> function wraps a standard call to the Security Support Provider Interface
		/// InitializeSecurityContext (General) function and processes SASL server cookies from the server.
		/// </summary>
		/// <param name="phCredential">
		/// A handle to the credentials returned by the AcquireCredentialsHandle function used to build the security context. Using the
		/// <c>SaslInitializeSecurityContext</c> function requires at least OUTBOUND credentials.
		/// </param>
		/// <param name="phContext">
		/// Pointer to a <c>CtxtHandle</c> structure. On the first call to the <c>SaslInitializeSecurityContext</c> function, this pointer is
		/// <c>NULL</c>. On the second call, this parameter is a pointer to the handle to the partially formed context returned in the
		/// phNewContext parameter by the first call.
		/// </param>
		/// <param name="pszTargetName">Pointer to a Unicode or ANSI string that indicates the target of the context.</param>
		/// <param name="fContextReq">
		/// <para>
		/// Bit flags that indicate the requirements of the context. Flags used for this parameter are prefixed with ISC_REQ_; for example:
		/// ISC_REQ_DELEGATE. Specify combinations of the following attributes flags.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>ISC_REQ_REPLAY_DETECT</term>
		/// <term>Detect replayed packets.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_SEQUENCE_DETECT</term>
		/// <term>Detect messages received out of sequence.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_CONFIDENTIALITY</term>
		/// <term>Encrypt messages.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_STREAM</term>
		/// <term>Support a stream-oriented connection.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_EXTENDED_ERROR</term>
		/// <term>When errors occur, the remote party will be notified.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_CONNECTION</term>
		/// <term>The security context will not handle formatting messages.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_MUTUAL_AUTH</term>
		/// <term>Client and server will be authenticated.</term>
		/// </item>
		/// <item>
		/// <term>ISC_REQ_INTEGRITY</term>
		/// <term>Sign messages and verify signatures.</term>
		/// </item>
		/// </list>
		/// <para>For further descriptions of the various attributes, see Context Requirements.</para>
		/// </param>
		/// <param name="Reserved1">Reserved value; must be zero.</param>
		/// <param name="TargetDataRep">
		/// Indicates the data representation, such as byte ordering, on the target. Can be either SECURITY_NATIVE_DREP or SECURITY_NETWORK_DREP.
		/// </param>
		/// <param name="pInput">
		/// <para>
		/// Pointer to a SecBufferDesc structure that contains pointers to the buffers supplied as input to the package. The pointer must be
		/// <c>NULL</c> on the first call to the function. On subsequent calls to the function, it is a pointer to a buffer allocated with
		/// enough memory to hold the token returned by the remote peer.
		/// </para>
		/// <para>SASL requires a single buffer of type <c>SECBUFFER_TOKEN</c> that contains the challenge received from the server.</para>
		/// </param>
		/// <param name="Reserved2">Reserved value; must be zero.</param>
		/// <param name="phNewContext">
		/// Pointer to a CtxtHandle structure. On the first call to the <c>SaslInitializeSecurityContext</c> function, this pointer receives
		/// the new context handle. On the second call, phNewContext can be the same as the handle specified in the phContext parameter.
		/// </param>
		/// <param name="pOutput">
		/// Pointer to a SecBufferDesc structure that contains pointers to the SecBuffer structure that receives the output data. If a buffer
		/// was typed as SEC_READWRITE in the input, it will be there on output. The system will allocate a buffer for the security token if
		/// requested (through ISC_REQ_ALLOCATE_MEMORY) and fill in the address in the buffer descriptor for the security token.
		/// </param>
		/// <param name="pfContextAttr">
		/// <para>
		/// Pointer to a variable to receive a set of bit flags that indicate the attributes of the established context. For a description of
		/// the various attributes, see Context Requirements.
		/// </para>
		/// <para>Flags used for this parameter are prefixed with ISC_RET_, such as ISC_RET_DELEGATE.</para>
		/// <para>For a list of valid values, see the fContextReq parameter.</para>
		/// <para>
		/// Do not check for security-related attributes until the final function call returns successfully. Attribute flags not related to
		/// security, such as the ASC_RET_ALLOCATED_MEMORY flag, can be checked before the final return.
		/// </para>
		/// <para><c>Note</c> Particular context attributes can change during a negotiation with a remote peer.</para>
		/// </param>
		/// <param name="ptsExpiry">
		/// Pointer to a <c>TimeStamp</c> structure that receives the expiration time of the context. It is recommended that the security
		/// package always return this value in local time. This parameter is optional and <c>NULL</c> should be passed for short-lived clients.
		/// </param>
		/// <returns>
		/// <para>
		/// If the call is completed successfully, this function returns SEC_E_OK. The following table shows some possible failure return values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_ALGORITHM_MISMATCH</term>
		/// <term>Authz processing is not permitted.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INSUFFICIENT_MEMORY</term>
		/// <term>Not enough memory is available to complete the request.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_TOKEN</term>
		/// <term>No Token buffer is located in the pOutput parameter, or the message failed to decrypt.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-saslinitializesecuritycontextw SECURITY_STATUS SEC_ENTRY
		// SaslInitializeSecurityContextW( PCredHandle phCredential, PCtxtHandle phContext, LPWSTR pszTargetName, unsigned long fContextReq,
		// unsigned long Reserved1, unsigned long TargetDataRep, PSecBufferDesc pInput, unsigned long Reserved2, PCtxtHandle phNewContext,
		// PSecBufferDesc pOutput, unsigned long *pfContextAttr, PTimeStamp ptsExpiry );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "9cc661b7-f1b0-4fb1-b799-5b318d87fd4d")]
		public static unsafe extern HRESULT SaslInitializeSecurityContext([In, Optional] CredHandle* phCredential, [In, Optional] CtxtHandle* phContext, [Optional] string pszTargetName, ASC_REQ fContextReq, [Optional] uint Reserved1, DREP TargetDataRep,
			[In, Optional] SecBufferDesc* pInput, [Optional] uint Reserved2, out SafeCtxtHandle phNewContext, [Optional] SecBufferDesc* pOutput, out ASC_RET pfContextAttr, out TimeStamp ptsExpiry);

		/// <summary>The <c>SaslSetContextOption</c> function sets the value of the specified property for the specified SASL context.</summary>
		/// <param name="ContextHandle">Handle of the SASL context.</param>
		/// <param name="Option">
		/// <para>Property to set for the SASL context. The following table lists the possible values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SASL_OPTION_AUTHZ_PROCESSING</term>
		/// <term>
		/// Data type of buffer: ULONG State of SASL processing of the Authz value provided by the SASL application. The valid states for
		/// processing are Sasl_AuthZIDForbidden and Sasl_AuthZIDProcessed. The default value is Sasl_AuthZIDProcessed.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SASL_OPTION_AUTHZ_STRING</term>
		/// <term>
		/// Data type of buffer: Array of binary characters String of characters passed from the SASL client to the server. If the
		/// AuthZ_Processing state is Sasl_AuthZIDForbidden, the return value SEC_E_UNSUPPORTED_FUNCTION is returned.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SASL_OPTION_RECV_SIZE</term>
		/// <term>Data type of buffer: ULONG Maximum size of the receiving buffer on the local computer. The default value is 0x0FFFF bytes.</term>
		/// </item>
		/// <item>
		/// <term>SASL_OPTION_SEND_SIZE</term>
		/// <term>
		/// Data type of buffer: ULONG Maximum message data size that can be transmitted. This value is the maximum buffer size that can be
		/// transmitted to the remote SASL process minus the block size, the trailer size, and the maximum signature size. The default value
		/// is 0x0FFFF bytes.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="Value">
		/// A pointer to a buffer that contains the value to set to the requested property. For the data type of the buffer for each value of
		/// the Option parameter, see the Option parameter.
		/// </param>
		/// <param name="Size">The size, in bytes, of the buffer specified by the Value parameter.</param>
		/// <returns>
		/// <para>
		/// If the call is completed successfully, this function returns SEC_E_OK. The following table shows some possible error return values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_BUFFER_TOO_SMALL</term>
		/// <term>
		/// The buffer specified by the Value parameter is not large enough to contain the data value of the property specified by the Option parameter.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The SASL context handle specified by the ContextHandle parameter was not found in the SASL list.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_UNSUPPORTED_FUNCTION</term>
		/// <term>The option specified in the Option parameter is not valid.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-saslsetcontextoption SECURITY_STATUS SEC_ENTRY
		// SaslSetContextOption( PCtxtHandle ContextHandle, ULONG Option, PVOID Value, ULONG Size );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "3c3b1209-b0de-4100-8dfe-53ea314b790b")]
		public static extern HRESULT SaslSetContextOption(in CtxtHandle ContextHandle, SASL_OPTION Option, [MarshalAs(UnmanagedType.LPWStr)] string Value, uint Size);

		/// <summary>The <c>SaslSetContextOption</c> function sets the value of the specified property for the specified SASL context.</summary>
		/// <param name="ContextHandle">Handle of the SASL context.</param>
		/// <param name="Option">
		/// <para>Property to set for the SASL context. The following table lists the possible values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SASL_OPTION_AUTHZ_PROCESSING</term>
		/// <term>
		/// Data type of buffer: ULONG State of SASL processing of the Authz value provided by the SASL application. The valid states for
		/// processing are Sasl_AuthZIDForbidden and Sasl_AuthZIDProcessed. The default value is Sasl_AuthZIDProcessed.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SASL_OPTION_AUTHZ_STRING</term>
		/// <term>
		/// Data type of buffer: Array of binary characters String of characters passed from the SASL client to the server. If the
		/// AuthZ_Processing state is Sasl_AuthZIDForbidden, the return value SEC_E_UNSUPPORTED_FUNCTION is returned.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SASL_OPTION_RECV_SIZE</term>
		/// <term>Data type of buffer: ULONG Maximum size of the receiving buffer on the local computer. The default value is 0x0FFFF bytes.</term>
		/// </item>
		/// <item>
		/// <term>SASL_OPTION_SEND_SIZE</term>
		/// <term>
		/// Data type of buffer: ULONG Maximum message data size that can be transmitted. This value is the maximum buffer size that can be
		/// transmitted to the remote SASL process minus the block size, the trailer size, and the maximum signature size. The default value
		/// is 0x0FFFF bytes.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="Value">
		/// A pointer to a buffer that contains the value to set to the requested property. For the data type of the buffer for each value of
		/// the Option parameter, see the Option parameter.
		/// </param>
		/// <param name="Size">The size, in bytes, of the buffer specified by the Value parameter.</param>
		/// <returns>
		/// <para>
		/// If the call is completed successfully, this function returns SEC_E_OK. The following table shows some possible error return values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_BUFFER_TOO_SMALL</term>
		/// <term>
		/// The buffer specified by the Value parameter is not large enough to contain the data value of the property specified by the Option parameter.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The SASL context handle specified by the ContextHandle parameter was not found in the SASL list.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_UNSUPPORTED_FUNCTION</term>
		/// <term>The option specified in the Option parameter is not valid.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-saslsetcontextoption SECURITY_STATUS SEC_ENTRY
		// SaslSetContextOption( PCtxtHandle ContextHandle, ULONG Option, PVOID Value, ULONG Size );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "3c3b1209-b0de-4100-8dfe-53ea314b790b")]
		public static extern HRESULT SaslSetContextOption(in CtxtHandle ContextHandle, SASL_OPTION Option, in uint Value, uint Size = 4);

		/// <summary>
		/// Enables a transport application to set attributes of a security context for a security package. This function is supported only
		/// by the Schannel security package.
		/// </summary>
		/// <param name="phContext">A handle to the security context to be set.</param>
		/// <param name="ulAttribute">
		/// <para>The attribute of the context to be set. This parameter can be one of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SECPKG_ATTR_APP_DATA 94</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_SessionAppData structure. Sets application data for the session. This
		/// attribute is supported only by the Schannel security package.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_EAP_PRF_INFO 101</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_EapPrfInfo structure. Sets the pseudo-random function (PRF) used by
		/// the Extensible Authentication Protocol (EAP). This is the value that is returned by a call to the QueryContextAttributes
		/// (Schannel) function when SECPKG_ATTR_EAP_KEY_BLOCK is passed as the value of the ulAttribute parameter. This attribute is
		/// supported only by the Schannel security package.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_EARLY_START 105</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_EarlyStart structure. Sets the False Start feature. See the Building
		/// a faster and more secure web blog post for information on this feature.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_DTLS_MTU 34</term>
		/// <term>
		/// Sets and retrieves the MTU (maximum transmission unit) value for use with DTLS. If DTLS is not enabled in a security context,
		/// this attribute is not supported. Valid values are between 200 bytes and 64 kilobytes. The default DTLS MTU value in Schannel is
		/// 1096 bytes.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_KEYING_MATERIAL_INFO 106</term>
		/// <term>
		/// The pBuffer parameter contains a pointer to a SecPkgContext_KeyingMaterialInfo structure. The keying material export feature
		/// follows the RFC 5705 standard. This attribute is supported only by the Schannel security package in Windows 10 and Windows Server
		/// 2016 or later versions.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pBuffer">
		/// A pointer to a structure that contains values to set the attributes to. The type of structure pointed to depends on the value
		/// specified in the ulAttribute parameter.
		/// </param>
		/// <param name="cbBuffer">The size, in bytes, of the pBuffer parameter.</param>
		/// <returns>
		/// <para>If the function succeeds, the function returns SEC_E_OK.</para>
		/// <para>If the function fails, it returns a nonzero error code. The following error code is one of the possible error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_UNSUPPORTED_FUNCTION</term>
		/// <term>This value is returned by Schannel kernel mode to indicate that this function is not supported.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-setcontextattributesa SECURITY_STATUS SEC_ENTRY
		// SetContextAttributesA( PCtxtHandle phContext, unsigned long ulAttribute, void *pBuffer, unsigned long cbBuffer );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "e3246c3e-3e8c-49fe-99d8-dfff1a10ab83")]
		public static extern HRESULT SetContextAttributes(in CtxtHandle phContext, SECPKG_ATTR ulAttribute, IntPtr pBuffer, uint cbBuffer);

		/// <summary>
		/// Sets the attributes of a credential, such as the name associated with the credential. The information is valid for any security
		/// context created with the specified credential.
		/// </summary>
		/// <param name="phCredential">A handle of the credentials to be set.</param>
		/// <param name="ulAttribute">
		/// <para>Specifies the attribute to set. This parameter can be any of the following attributes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SECPKG_CRED_ATTR_NAMES</term>
		/// <term>
		/// Sets the name of a credential in a pBuffer parameter of type SecPkgCredentials_Names. This attribute is not supported by Schannel
		/// in WOW64 mode.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_CRED_ATTR_KDC_PROXY_SETTINGS</term>
		/// <term>
		/// Sets the Kerberos proxy setting in a pBuffer parameter of type SecPkgCredentials_KdcProxySettings. This attribute is only
		/// supported by Kerberos.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SUPPORTED_ALGS</term>
		/// <term>
		/// Sets the supported algorithms in a pBuffer parameter of type SecPkgCred_SupportedAlgs. All supported algorithms are included,
		/// regardless of whether they are supported by the provided certificate or enabled on the local computer. This attribute is
		/// supported only by Schannel.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_CIPHER_STRENGTHS</term>
		/// <term>
		/// Sets the cipher strengths in a pBuffer parameter of type SecPkgCred_CipherStrengths. This attribute is supported only by Schannel.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SECPKG_ATTR_SUPPORTED_PROTOCOLS</term>
		/// <term>
		/// Sets the supported algorithms in a pBuffer parameter of type SecPkgCred_SupportedProtocols. All supported protocols are included,
		/// regardless of whether they are supported by the provided certificate or enabled on the local computer. This attribute is
		/// supported only by Schannel.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pBuffer">
		/// A pointer to a buffer that contains the new attribute value. The type of structure returned depends on the value of ulAttribute.
		/// </param>
		/// <param name="cbBuffer">The size, in bytes, of the pBuffer buffer.</param>
		/// <returns>
		/// <para>If the function succeeds, the return value is SEC_E_OK.</para>
		/// <para>If the function fails, the return value may be one of the following error codes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The handle passed to the function is not valid.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_UNSUPPORTED_FUNCTION</term>
		/// <term>
		/// The specified attribute is not supported by Schannel. This return value will only be returned when the Schannel SSP is being used.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INSUFFICIENT_MEMORY</term>
		/// <term>Not enough memory is available to complete the request.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-setcredentialsattributesa SECURITY_STATUS SEC_ENTRY
		// SetCredentialsAttributesA( PCredHandle phCredential, unsigned long ulAttribute, void *pBuffer, unsigned long cbBuffer );
		[DllImport(Lib.Secur32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("sspi.h", MSDNShortId = "419fb4f0-3dd1-4473-aeb2-8024355e0c1c")]
		public static extern HRESULT SetCredentialsAttributes(in CredHandle phCredential, SECPKG_CRED_ATTR ulAttribute, IntPtr pBuffer, uint cbBuffer);

		/// <summary>
		/// <para>Compares the two specified credentials.</para>
		/// </summary>
		/// <param name="AuthIdentity1">
		/// <para>A pointer to an opaque structure that specifies the first credential to compare.</para>
		/// </param>
		/// <param name="AuthIdentity2">
		/// <para>A pointer to an opaque structure that specifies the second credential to compare.</para>
		/// </param>
		/// <param name="SameSuppliedUser">
		/// <para>
		/// <c>TRUE</c> if the user account specified by the AuthIdentity1 parameter is the same as the user account specified by the
		/// AuthIdentity2 parameter; otherwise, <c>FALSE</c>.
		/// </para>
		/// </param>
		/// <param name="SameSuppliedIdentity">
		/// <para>
		/// <c>TRUE</c> if the identity specified by the AuthIdentity1 parameter is the same as the identity specified by the AuthIdentity2
		/// parameter; otherwise, <c>FALSE</c>.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspicompareauthidentities SECURITY_STATUS SEC_ENTRY
		// SspiCompareAuthIdentities( PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthIdentity1, PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthIdentity2, PBOOLEAN
		// SameSuppliedUser, PBOOLEAN SameSuppliedIdentity );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "d2c4f363-3d86-48f0-bae1-4f9240d68bab")]
		public static extern Win32Error SspiCompareAuthIdentities(PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthIdentity1, PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthIdentity2,
			[MarshalAs(UnmanagedType.U1)] out bool SameSuppliedUser, [MarshalAs(UnmanagedType.U1)] out bool SameSuppliedIdentity);

		/// <summary>
		/// <para>Creates a copy of the specified opaque credential structure.</para>
		/// </summary>
		/// <param name="AuthData">
		/// <para>The credential structure to be copied.</para>
		/// </param>
		/// <param name="AuthDataCopy">
		/// <para>The structure that receives the copy of the structure specified by the AuthData parameter.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspicopyauthidentity SECURITY_STATUS SEC_ENTRY
		// SspiCopyAuthIdentity( PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthData, PSEC_WINNT_AUTH_IDENTITY_OPAQUE *AuthDataCopy );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "e53807bf-b5a1-4479-a73b-dd85c5da173e")]
		public static extern Win32Error SspiCopyAuthIdentity(PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthData, out SafePSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthDataCopy);

		/// <summary>
		/// <para>Decrypts the specified encrypted credential.</para>
		/// </summary>
		/// <param name="EncryptedAuthData">
		/// <para>
		/// On input, a pointer to the encrypted credential structure to be decrypted. On output, a pointer to the decrypted credential structure.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspidecryptauthidentity SECURITY_STATUS SEC_ENTRY
		// SspiDecryptAuthIdentity( PSEC_WINNT_AUTH_IDENTITY_OPAQUE EncryptedAuthData );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "aef0206c-c376-4877-b1a6-5e86d2e35dea")]
		public static extern Win32Error SspiDecryptAuthIdentity(PSEC_WINNT_AUTH_IDENTITY_OPAQUE EncryptedAuthData);

		/// <summary>Decrypts a <c>SEC_WINNT_AUTH_IDENTITY_OPAQUE</c> structure.</summary>
		/// <param name="Options">
		/// <para>
		/// Decryption options. This parameter should be the same value as the value passed to the SspiEncryptAuthIdentityEx function, which
		/// can be one of the following values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_WINNT_AUTH_IDENTITY_ENCRYPT_SAME_LOGON</term>
		/// <term>
		/// The encrypted structure can only be decrypted by a security context in the same logon session. This option is used to protect an
		/// identity buffer that is being sent over a local RPC.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_WINNT_AUTH_IDENTITY_ENCRYPT_SAME_PROCESS</term>
		/// <term>
		/// The encrypted structure can only be decrypted by the same process. Calling the function with this option is equivalent to calling
		/// SspiEncryptAuthIdentity. This option is used to protect an identity buffer that is being persisted in a process's private memory
		/// for an extended period.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="EncryptedAuthData">This buffer is the output of the SspiEncryptAuthIdentityEx function.</param>
		/// <returns>
		/// <para>If the function succeeds, it returns SEC_E_OK.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspidecryptauthidentityex SECURITY_STATUS SEC_ENTRY
		// SspiDecryptAuthIdentityEx( ULONG Options, PSEC_WINNT_AUTH_IDENTITY_OPAQUE EncryptedAuthData );
		[DllImport(Lib.SspiCli, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "86598BAA-0E87-46A9-AA1A-BF04BF0CDAFA")]
		public static extern HRESULT SspiDecryptAuthIdentityEx(SEC_WINNT_AUTH_IDENTITY_ENCRYPT Options, PSEC_WINNT_AUTH_IDENTITY_OPAQUE EncryptedAuthData);

		/// <summary>
		/// <para>Encodes the specified authentication identity as three strings.</para>
		/// </summary>
		/// <param name="pAuthIdentity">
		/// <para>The credential structure to be encoded.</para>
		/// </param>
		/// <param name="ppszUserName">
		/// <para>The marshaled user name of the identity specified by the pAuthIdentity parameter.</para>
		/// <para>When you have finished using this string, free it by calling the SspiFreeAuthIdentity function.</para>
		/// </param>
		/// <param name="ppszDomainName">
		/// <para>The marshaled domain name of the identity specified by the pAuthIdentity parameter.</para>
		/// <para>When you have finished using this string, free it by calling the SspiFreeAuthIdentity function.</para>
		/// </param>
		/// <param name="ppszPackedCredentialsString">
		/// <para>An encoded string version of a SEC_WINNT_AUTH_IDENTITY_EX2 structure that specifies the users credentials.</para>
		/// <para>When you have finished using this string, free it by calling the SspiFreeAuthIdentity function.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>
		/// If the function fails, it returns a nonzero error code. Possible values include, but are not limited to, those in the following table.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code/value</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>STATUS_INVALID_PARAMETER 0xC000000D</term>
		/// <term>
		/// The SEC_WINNT_AUTH_IDENTITY_FLAGS_PROCESS_ENCRYPTED flag is set in the identity structure specified by the pAuthIdentity parameter.
		/// </term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspiencodeauthidentityasstrings SECURITY_STATUS SEC_ENTRY
		// SspiEncodeAuthIdentityAsStrings( PSEC_WINNT_AUTH_IDENTITY_OPAQUE pAuthIdentity, PCWSTR *ppszUserName, PCWSTR *ppszDomainName,
		// PCWSTR *ppszPackedCredentialsString );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "0610a7b8-67e9-4c01-893f-da579eeea2f8")]
		public static extern Win32Error SspiEncodeAuthIdentityAsStrings([In] PSEC_WINNT_AUTH_IDENTITY_OPAQUE pAuthIdentity,
			[Out, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(SspiStringMarshaler))] out string ppszUserName,
			[Out, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(SspiStringMarshaler))] out string ppszDomainName,
			[Out, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(SspiStringMarshaler))] out string ppszPackedCredentialsString);

		/// <summary>
		/// <para>Encodes a set of three credential strings as an authentication identity structure.</para>
		/// </summary>
		/// <param name="pszUserName">
		/// <para>The user name associated with the identity to encode.</para>
		/// </param>
		/// <param name="pszDomainName">
		/// <para>The domain name associated with the identity to encode.</para>
		/// </param>
		/// <param name="pszPackedCredentialsString">
		/// <para>An encoded string version of a SEC_WINNT_AUTH_IDENTITY_EX2 structure that specifies the user's credentials.</para>
		/// </param>
		/// <param name="ppAuthIdentity">
		/// <para>A pointer to the encoded identity structure.</para>
		/// <para>When you have finished using this structure, free it by calling the SspiFreeAuthIdentity function.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspiencodestringsasauthidentity SECURITY_STATUS SEC_ENTRY
		// SspiEncodeStringsAsAuthIdentity( PCWSTR pszUserName, PCWSTR pszDomainName, PCWSTR pszPackedCredentialsString,
		// PSEC_WINNT_AUTH_IDENTITY_OPAQUE *ppAuthIdentity );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "0aea2f00-fcf1-4c4e-a22f-a669dd4fb294")]
		public static extern Win32Error SspiEncodeStringsAsAuthIdentity([MarshalAs(UnmanagedType.LPWStr)] string pszUserName, [MarshalAs(UnmanagedType.LPWStr)] string pszDomainName,
			[MarshalAs(UnmanagedType.LPWStr)] string pszPackedCredentialsString, out SafePSEC_WINNT_AUTH_IDENTITY_OPAQUE ppAuthIdentity);

		/// <summary>
		/// <para>Encrypts the specified identity structure.</para>
		/// </summary>
		/// <param name="AuthData">
		/// <para>On input, the identity structure to encrypt. On output, the encrypted identity structure.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspiencryptauthidentity SECURITY_STATUS SEC_ENTRY
		// SspiEncryptAuthIdentity( PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthData );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "4460f7ec-35fd-4ad1-8c20-dda9f4d3477a")]
		public static extern Win32Error SspiEncryptAuthIdentity(PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthData);

		/// <summary>Encrypts a <c>SEC_WINNT_AUTH_IDENTITY_OPAQUE</c> structure.</summary>
		/// <param name="Options">
		/// <para>Encryption options. This can be one or more of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_WINNT_AUTH_IDENTITY_ENCRYPT_SAME_LOGON</term>
		/// <term>
		/// The encrypted structure can only be decrypted by a security context in the same logon session. This option is used to protect an
		/// identity buffer that is being sent over a local RPC.
		/// </term>
		/// </item>
		/// <item>
		/// <term>SEC_WINNT_AUTH_IDENTITY_ENCRYPT_SAME_PROCESS</term>
		/// <term>
		/// The encrypted structure can only be decrypted by the same process. Calling the function with this option is equivalent to calling
		/// SspiEncryptAuthIdentity. This option is used to protect an identity buffer that is being persisted in a process's private memory
		/// for an extended period.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="AuthData">
		/// On input, a pointer to an identity buffer to encrypt. This buffer must be prepared for encryption prior to the call to this
		/// function. This can be done by calling the function SspiEncryptAuthIdentity. On output, the encrypted identity buffer.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns SEC_E_OK.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		/// <remarks>
		/// To transfer credentials securely across processes, applications typically call this function with the
		/// SEC_WINNT_AUTH_IDENTITY_ENCRYPT_SAME_LOGON option, followed by SspiMarshalAuthIdentity to obtain a marshaled authentication
		/// buffer and its length. For example, Online Identity Credential Provider does this to return the authentication buffer from their
		/// ICredentialProviderCredential::GetSerialization method.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspiencryptauthidentityex SECURITY_STATUS SEC_ENTRY
		// SspiEncryptAuthIdentityEx( ULONG Options, PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthData );
		[DllImport(Lib.SspiCli, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "9290BEF8-24C9-47F0-B258-56ED7D67620B")]
		public static extern HRESULT SspiEncryptAuthIdentityEx(SEC_WINNT_AUTH_IDENTITY_ENCRYPT Options, PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthData);

		/// <summary>
		/// <para>
		/// Creates a new identity structure that is a copy of the specified identity structure modified to exclude the specified security
		/// support provider (SSP).
		/// </para>
		/// </summary>
		/// <param name="AuthIdentity">
		/// <para>The identity structure to modify.</para>
		/// </param>
		/// <param name="pszPackageName">
		/// <para>The SSP to exclude.</para>
		/// </param>
		/// <param name="ppNewAuthIdentity">
		/// <para>The modified identity structure.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspiexcludepackage SECURITY_STATUS SEC_ENTRY SspiExcludePackage(
		// PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthIdentity, PCWSTR pszPackageName, PSEC_WINNT_AUTH_IDENTITY_OPAQUE *ppNewAuthIdentity );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "2f85bb13-b72a-4c26-a328-9424a33a63b8")]
		public static extern Win32Error SspiExcludePackage(PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthIdentity, [MarshalAs(UnmanagedType.LPWStr)] string pszPackageName, out SafePSEC_WINNT_AUTH_IDENTITY_OPAQUE ppNewAuthIdentity);

		/// <summary>
		/// <para>Frees the memory allocated for the specified identity structure.</para>
		/// </summary>
		/// <param name="AuthData">
		/// <para>The identity structure to free.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspifreeauthidentity VOID SEC_ENTRY SspiFreeAuthIdentity(
		// PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthData );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "6199f66e-7adb-4bb9-8e77-a735e31dd5f6")]
		public static extern void SspiFreeAuthIdentity(IntPtr AuthData);

		/// <summary>
		/// <para>Gets the host name associated with the specified target.</para>
		/// </summary>
		/// <param name="pszTargetName">
		/// <para>The target for which to get the host name.</para>
		/// </param>
		/// <param name="pszHostName">
		/// <para>The name of the host associated with the target specified by the pszTargetName parameter.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspigettargethostname SECURITY_STATUS SEC_ENTRY
		// SspiGetTargetHostName( PCWSTR pszTargetName, PWSTR *pszHostName );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "84570dfc-1890-4b82-b411-1f9eaa75537b")]
		public static extern Win32Error SspiGetTargetHostName([MarshalAs(UnmanagedType.LPWStr)] string pszTargetName, [MarshalAs(UnmanagedType.LPWStr)] out string pszHostName);

		/// <summary>
		/// <para>Indicates whether the specified identity structure is encrypted.</para>
		/// </summary>
		/// <param name="EncryptedAuthData">
		/// <para>The identity structure to test.</para>
		/// </param>
		/// <returns>
		/// <para><c>TRUE</c> if the identity structure specified by the EncryptedAuthData parameter is encrypted; otherwise, <c>FALSE</c>.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspiisauthidentityencrypted BOOLEAN SEC_ENTRY
		// SspiIsAuthIdentityEncrypted( PSEC_WINNT_AUTH_IDENTITY_OPAQUE EncryptedAuthData );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "b85095f5-0ca5-4d75-866d-9b756404c1d9")]
		[return: MarshalAs(UnmanagedType.U1)]
		public static extern bool SspiIsAuthIdentityEncrypted(PSEC_WINNT_AUTH_IDENTITY_OPAQUE EncryptedAuthData);

		/// <summary>
		/// <para>Frees the memory associated with the specified buffer.</para>
		/// </summary>
		/// <param name="DataBuffer">
		/// <para>The buffer to free.</para>
		/// </param>
		/// <returns>
		/// <para>This function does not return a value.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspilocalfree VOID SEC_ENTRY SspiLocalFree( PVOID DataBuffer );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "afb890a8-a2c3-4c35-ba76-758b047ababb")]
		public static extern void SspiLocalFree(IntPtr DataBuffer);

		/// <summary>
		/// <para>Serializes the specified identity structure into a byte array.</para>
		/// </summary>
		/// <param name="AuthIdentity">
		/// <para>The identity structure to serialize.</para>
		/// </param>
		/// <param name="AuthIdentityLength">
		/// <para>The length, in bytes, of the AuthIdentityByteArray array.</para>
		/// </param>
		/// <param name="AuthIdentityByteArray">
		/// <para>A pointer to an array of byte values that represents the identity specified by the AuthIdentity parameter.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspimarshalauthidentity SECURITY_STATUS SEC_ENTRY
		// SspiMarshalAuthIdentity( PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthIdentity, unsigned long *AuthIdentityLength, char
		// **AuthIdentityByteArray );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "e43135ad-7fcd-4da6-a4e4-c91c41eeb865")]
		public static extern Win32Error SspiMarshalAuthIdentity(PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthIdentity, out uint AuthIdentityLength, out SafeSspiLocalMem AuthIdentityByteArray);

		/// <summary>
		/// <para>Generates a target name and credential type from the specified identity structure.</para>
		/// <para>
		/// The values that this function generates can be passed as the values of the TargetName and Type parameters in a call to the
		/// CredRead function.
		/// </para>
		/// </summary>
		/// <param name="AuthIdentity">
		/// <para>The identity structure from which to generate the credentials to be passed to the CredRead function.</para>
		/// </param>
		/// <param name="pszTargetName">
		/// <para>A target name that can be modified by this function depending on the value of the AuthIdentity parameter.</para>
		/// </param>
		/// <param name="pCredmanCredentialType">
		/// <para>The credential type to pass to the CredRead function.</para>
		/// </param>
		/// <param name="ppszCredmanTargetName">
		/// <para>The target name to pass to the CredRead function.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspiprepareforcredread SECURITY_STATUS SEC_ENTRY
		// SspiPrepareForCredRead( PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthIdentity, PCWSTR pszTargetName, PULONG pCredmanCredentialType, PCWSTR
		// *ppszCredmanTargetName );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Unicode)]
		[PInvokeData("sspi.h", MSDNShortId = "f473fd7a-5c0f-4a77-829b-28a82ad0d28d")]
		public static extern Win32Error SspiPrepareForCredRead(PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthIdentity, string pszTargetName, out CRED_TYPE pCredmanCredentialType, out string ppszCredmanTargetName);

		/// <summary>
		/// <para>
		/// Generates values from an identity structure that can be passed as the values of parameters in a call to the CredWrite function.
		/// </para>
		/// </summary>
		/// <param name="AuthIdentity">
		/// <para>The identity structure from which to generate the credentials to be passed to the CredWrite function.</para>
		/// </param>
		/// <param name="pszTargetName">
		/// <para>A target name that can be modified by this function depending on the value of the AuthIdentity parameter.</para>
		/// <para>Set the value of this parameter to <c>NULL</c> to use the user name as the target.</para>
		/// </param>
		/// <param name="pCredmanCredentialType">
		/// <para>The credential type to pass to the CredWrite function.</para>
		/// </param>
		/// <param name="ppszCredmanTargetName">
		/// <para>The target name to pass to the CredWrite function.</para>
		/// </param>
		/// <param name="ppszCredmanUserName">
		/// <para>The user name to pass to the CredWrite function.</para>
		/// </param>
		/// <param name="ppCredentialBlob">
		/// <para>The credential BLOB to send to the CredWrite function.</para>
		/// </param>
		/// <param name="pCredentialBlobSize">
		/// <para>The size, in bytes, of the ppCredentialBlob buffer.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspiprepareforcredwrite SECURITY_STATUS SEC_ENTRY
		// SspiPrepareForCredWrite( PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthIdentity, PCWSTR pszTargetName, PULONG pCredmanCredentialType, PCWSTR
		// *ppszCredmanTargetName, PCWSTR *ppszCredmanUserName, PUCHAR *ppCredentialBlob, PULONG pCredentialBlobSize );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Unicode)]
		[PInvokeData("sspi.h", MSDNShortId = "4db92042-38f2-42c2-9c94-b24e0eaafdf9")]
		public static extern Win32Error SspiPrepareForCredWrite(PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthIdentity, string pszTargetName, out CRED_TYPE pCredmanCredentialType, out string ppszCredmanTargetName, out string ppszCredmanUserName,
			[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 6)] out byte[] ppCredentialBlob, out uint pCredentialBlobSize);

		/// <summary>
		/// <para>Deserializes the specified array of byte values into an identity structure.</para>
		/// </summary>
		/// <param name="AuthIdentityLength">
		/// <para>The size, in bytes, of the AuthIdentityByteArray array.</para>
		/// </param>
		/// <param name="AuthIdentityByteArray">
		/// <para>The array of byte values to deserialize.</para>
		/// </param>
		/// <param name="ppAuthIdentity">
		/// <para>The deserialized identity structure.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspiunmarshalauthidentity SECURITY_STATUS SEC_ENTRY
		// SspiUnmarshalAuthIdentity( unsigned long AuthIdentityLength, char *AuthIdentityByteArray, PSEC_WINNT_AUTH_IDENTITY_OPAQUE
		// *ppAuthIdentity );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "89798b37-808a-4174-8362-a2dc4ee1b460")]
		public static extern Win32Error SspiUnmarshalAuthIdentity(uint AuthIdentityLength, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] byte[] AuthIdentityByteArray, out SafePSEC_WINNT_AUTH_IDENTITY_OPAQUE ppAuthIdentity);

		/// <summary>
		/// <para>Indicates whether the specified identity structure is valid.</para>
		/// </summary>
		/// <param name="AuthData">
		/// <para>The identity structure to test.</para>
		/// </param>
		/// <returns>
		/// <para>
		/// If the function succeeds, it returns <c>SEC_E_OK</c>, which indicates that the identity structure specified by the AuthData
		/// parameter is valid.
		/// </para>
		/// <para>
		/// If the function fails, it returns a nonzero error code that indicates that the identity structure specified by the AuthData
		/// parameter is not valid.
		/// </para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspivalidateauthidentity SECURITY_STATUS SEC_ENTRY
		// SspiValidateAuthIdentity( PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthData );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "82733abd-d984-4902-b6e4-c3809171ad51")]
		public static extern Win32Error SspiValidateAuthIdentity(PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthData);

		/// <summary>
		/// <para>Fills the block of memory associated with the specified identity structure with zeros.</para>
		/// </summary>
		/// <param name="AuthData">
		/// <para>The identity structure to fill with zeros.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns <c>SEC_E_OK</c>.</para>
		/// <para>If the function fails, it returns a nonzero error code.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-sspizeroauthidentity VOID SEC_ENTRY SspiZeroAuthIdentity(
		// PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthData );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "50b1f24a-c802-4691-a450-316cb31bf44d")]
		public static extern void SspiZeroAuthIdentity(PSEC_WINNT_AUTH_IDENTITY_OPAQUE AuthData);

		/// <summary>
		/// Verifies that a message signed by using the MakeSignature function was received in the correct sequence and has not been modified.
		/// </summary>
		/// <param name="phContext">A handle to the security context to use for the message.</param>
		/// <param name="pMessage">
		/// Pointer to a SecBufferDesc structure that references a set of SecBuffer structures that contain the message and signature to
		/// verify. The signature is in a <c>SecBuffer</c> structure of type SECBUFFER_TOKEN.
		/// </param>
		/// <param name="MessageSeqNo">
		/// Specifies the sequence number expected by the transport application, if any. If the transport application does not maintain
		/// sequence numbers, this parameter is zero.
		/// </param>
		/// <param name="pfQOP">
		/// <para>Pointer to a <c>ULONG</c> variable that receives package-specific flags that indicate the quality of protection.</para>
		/// <para>Some security packages ignore this parameter.</para>
		/// </param>
		/// <returns>
		/// <para>
		/// If the function verifies that the message was received in the correct sequence and has not been modified, the return value is SEC_E_OK.
		/// </para>
		/// <para>
		/// If the function determines that the message is not correct according to the information in the signature, the return value can be
		/// one of the following error codes.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>SEC_E_OUT_OF_SEQUENCE</term>
		/// <term>The message was not received in the correct sequence.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_MESSAGE_ALTERED</term>
		/// <term>The message has been altered.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_HANDLE</term>
		/// <term>The context handle specified by phContext is not valid.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_INVALID_TOKEN</term>
		/// <term>pMessage did not contain a valid SECBUFFER_TOKEN buffer, or contained too few buffers.</term>
		/// </item>
		/// <item>
		/// <term>SEC_E_QOP_NOT_SUPPORTED</term>
		/// <term>The quality of protection negotiated between the client and server did not include integrity checking.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <c>Warning</c> The <c>VerifySignature</c> function will fail if the message was signed using the RsaSignPssSha512 algorithm on a
		/// different version of Windows. For example, a message that was signed by calling the MakeSignature function on Windows 8 will
		/// cause the <c>VerifySignature</c> function on Windows 8.1 to fail.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/nf-sspi-verifysignature KSECDDDECLSPEC SECURITY_STATUS SEC_ENTRY
		// VerifySignature( PCtxtHandle phContext, PSecBufferDesc pMessage, unsigned long MessageSeqNo, unsigned long *pfQOP );
		[DllImport(Lib.Secur32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("sspi.h", MSDNShortId = "bebeef92-1d6e-4879-846f-12d706db0653")]
		public static extern HRESULT VerifySignature(in CtxtHandle phContext, in SecBufferDesc pMessage, uint MessageSeqNo, out SECQOP pfQOP);

		/// <summary>Provides a handle to a auth identity.</summary>
		[StructLayout(LayoutKind.Sequential)]
		public struct PSEC_WINNT_AUTH_IDENTITY_OPAQUE : IHandle
		{
			private IntPtr handle;

			/// <summary>Initializes a new instance of the <see cref="PSEC_WINNT_AUTH_IDENTITY_OPAQUE"/> struct.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			public PSEC_WINNT_AUTH_IDENTITY_OPAQUE(IntPtr preexistingHandle) => handle = preexistingHandle;

			/// <summary>Returns an invalid handle by instantiating a <see cref="PSEC_WINNT_AUTH_IDENTITY_OPAQUE"/> object with <see cref="IntPtr.Zero"/>.</summary>
			public static PSEC_WINNT_AUTH_IDENTITY_OPAQUE NULL => new PSEC_WINNT_AUTH_IDENTITY_OPAQUE(IntPtr.Zero);

			/// <summary>Gets a value indicating whether this instance is a null handle.</summary>
			public bool IsNull => handle == IntPtr.Zero;

			/// <summary>Performs an explicit conversion from <see cref="PSEC_WINNT_AUTH_IDENTITY_OPAQUE"/> to <see cref="IntPtr"/>.</summary>
			/// <param name="h">The handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static explicit operator IntPtr(PSEC_WINNT_AUTH_IDENTITY_OPAQUE h) => h.handle;

			/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="PSEC_WINNT_AUTH_IDENTITY_OPAQUE"/>.</summary>
			/// <param name="h">The pointer to a handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator PSEC_WINNT_AUTH_IDENTITY_OPAQUE(IntPtr h) => new PSEC_WINNT_AUTH_IDENTITY_OPAQUE(h);

			/// <summary>Implements the operator !=.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator !=(PSEC_WINNT_AUTH_IDENTITY_OPAQUE h1, PSEC_WINNT_AUTH_IDENTITY_OPAQUE h2) => !(h1 == h2);

			/// <summary>Implements the operator ==.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator ==(PSEC_WINNT_AUTH_IDENTITY_OPAQUE h1, PSEC_WINNT_AUTH_IDENTITY_OPAQUE h2) => h1.Equals(h2);

			/// <inheritdoc/>
			public override bool Equals(object obj) => obj is PSEC_WINNT_AUTH_IDENTITY_OPAQUE h ? handle == h.handle : false;

			/// <inheritdoc/>
			public override int GetHashCode() => handle.GetHashCode();

			/// <inheritdoc/>
			public IntPtr DangerousGetHandle() => handle;
		}

		/// <summary>Allows you to pass a particular user name and password to the run-time library for the purpose of authentication.</summary>
		/// <remarks>
		/// <para>When this structure is used with RPC, the structure must remain valid for the lifetime of the binding handle.</para>
		/// <para>The strings may be ANSI or Unicode, depending on the value you assign to the <c>Flags</c> member.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_sec_winnt_auth_identity_a typedef struct
		// _SEC_WINNT_AUTH_IDENTITY_A { unsigned char *User; unsigned long UserLength; unsigned char *Domain; unsigned long DomainLength;
		// unsigned char *Password; unsigned long PasswordLength; unsigned long Flags; } SEC_WINNT_AUTH_IDENTITY_A, *PSEC_WINNT_AUTH_IDENTITY_A;
		[PInvokeData("sspi.h", MSDNShortId = "a9c9471b-2134-4173-af86-18b277627d2a")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct SEC_WINNT_AUTH_IDENTITY
		{
			/// <summary>A string that contains the user name.</summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string User;

			/// <summary>The length, in characters, of the user string, not including the terminating null character.</summary>
			public int UserLength;

			/// <summary>A string that contains the domain name or the workgroup name.</summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string Domain;

			/// <summary>The length, in characters, of the domain string, not including the terminating null character.</summary>
			public int DomainLength;

			/// <summary>
			/// A string that contains the password of the user in the domain or workgroup. When you have finished using the password, remove
			/// the sensitive information from memory by calling SecureZeroMemory. For more information about protecting the password, see
			/// Handling Passwords.
			/// </summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string Password;

			/// <summary>The length, in characters, of the password string, not including the terminating null character.</summary>
			public int PasswordLength;

			/// <summary>
			/// <para>This member can be one of the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>SEC_WINNT_AUTH_IDENTITY_ANSI</term>
			/// <term>The strings in this structure are in ANSI format.</term>
			/// </item>
			/// <item>
			/// <term>SEC_WINNT_AUTH_IDENTITY_UNICODE</term>
			/// <term>The strings in this structure are in Unicode format.</term>
			/// </item>
			/// </list>
			/// </summary>
			public int Flags;

			/// <summary>Initializes a new instance of the <see cref="SEC_WINNT_AUTH_IDENTITY"/> struct.</summary>
			/// <param name="user">The user name.</param>
			/// <param name="domain">The domain name or the workgroup name.</param>
			/// <param name="password">The password of the user in the domain or workgroup.</param>
			public SEC_WINNT_AUTH_IDENTITY(string user, string domain, string password)
			{
				User = user;
				UserLength = user?.Length ?? 0;
				Domain = domain;
				DomainLength = domain?.Length ?? 0;
				Password = password;
				PasswordLength = password?.Length ?? 0;
				Flags = StringHelper.GetCharSize();
			}
		}

		/// <summary>
		/// The <c>SEC_WINNT_AUTH_IDENTITY_EX</c> structure contains information about a user. Both an ANSI and Unicode form of this
		/// structure are provided.
		/// </summary>
		/// <remarks>
		/// Note that when this structure is used with RPC, the structure must remain valid for the lifetime of the binding handle.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_sec_winnt_auth_identity_exa typedef struct
		// _SEC_WINNT_AUTH_IDENTITY_EXA { unsigned long Version; unsigned long Length; unsigned char *User; unsigned long UserLength;
		// unsigned char *Domain; unsigned long DomainLength; unsigned char *Password; unsigned long PasswordLength; unsigned long Flags;
		// unsigned char *PackageList; unsigned long PackageListLength; } SEC_WINNT_AUTH_IDENTITY_EXA, *PSEC_WINNT_AUTH_IDENTITY_EXA;
		[PInvokeData("sspi.h", MSDNShortId = "6b95bce8-5613-4403-9bda-16262596bb1b")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct SEC_WINNT_AUTH_IDENTITY_EX
		{
			/// <summary>An unsigned long that indicates the version number of the structure.</summary>
			public uint Version;

			/// <summary>An unsigned long that indicates the length, in bytes, of the structure.</summary>
			public uint Length;

			/// <summary>A Unicode or ANSI string that contains the name of the user account.</summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string User;

			/// <summary>The length, in characters, of the <c>User</c> string.</summary>
			public uint UserLength;

			/// <summary>A Unicode or ANSI string that contains the name of the domain for the user account.</summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string Domain;

			/// <summary>The length, in characters, of the <c>Domain</c> string.</summary>
			public uint DomainLength;

			/// <summary>
			/// A Unicode or ANSI string that contains the user password in plaintext. When you have finished using the password, remove the
			/// sensitive information from memory by calling the SecureZeroMemory function. For more information about protecting the
			/// password, see Handling Passwords.
			/// </summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string Password;

			/// <summary>The length, in characters, of the <c>Password</c> string.</summary>
			public uint PasswordLength;

			/// <summary>
			/// <para>An unsigned long flag that indicates the type used by negotiable security packages.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>SEC_WINNT_AUTH_IDENTITY_MARSHALLED</term>
			/// <term>All data is in one buffer.</term>
			/// </item>
			/// <item>
			/// <term>SEC_WINNT_AUTH_IDENTITY_ONLY</term>
			/// <term>
			/// Used with the Kerberos security support provider (SSP). Credentials are for identity only. The Kerberos package is directed
			/// to not include authorization data in the ticket.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SEC_WINNT_AUTH_IDENTITY_ANSI</term>
			/// <term>Credentials are in ANSI form.</term>
			/// </item>
			/// <item>
			/// <term>SEC_WINNT_AUTH_IDENTITY_UNICODE</term>
			/// <term>Credentials are in Unicode form.</term>
			/// </item>
			/// </list>
			/// </summary>
			public SEC_WINNT_AUTH_IDENTITY_FLAGS Flags;

			/// <summary>
			/// <para>
			/// A Unicode or ANSI string that contains a comma-separated list of names of security packages that are available when using the
			/// Microsoft Negotiate provider.
			/// </para>
			/// <para>Set this to "!ntlm" to specify that the NTLM package is not to be used.</para>
			/// </summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string PackageList;

			/// <summary>The length, in characters, of the <c>PackageList</c> string.</summary>
			public uint PackageListLength;
		}

		/// <summary>
		/// Contains information about an authentication identity. The <c>SEC_WINNT_AUTH_IDENTITY_EX2</c> structure contains authentication
		/// data that is provided to the AcquireCredentialsHandle function.
		/// </summary>
		/// <remarks>
		/// <para>
		/// This authentication identity buffer can be returned from several credential APIs, for example, the GetSerialization method and
		/// the CredUIPromptForWindowsCredential and SspiPromptForCredentials functions.
		/// </para>
		/// <para>
		/// The structure describes a header of the authentication identity buffer and the data is appended at the end of the structure.
		/// Although the buffer size is specified by the <c>cbStructureLength</c> member, the actual buffer size can be larger or smaller
		/// than <c>cbStructureLength</c>. Some functions, such as SspiValidateAuthIdentity, take a pointer, but not the buffer size, to the
		/// identity structure as input. As a result, those functions can validate the internal buffer data but cannot verify the buffer
		/// size. This can result in reading or writing data outside of the buffer range. To avoid buffer overruns when handling an untrusted
		/// identity buffer, applications should call SspiUnmarshalAuthIdentity to obtain a pointer to an identity structure with a validated
		/// size and then pass that pointer to the functions.
		/// </para>
		/// <para>
		/// The <c>SEC_WINNT_AUTH_IDENTITY_EX2</c> structure can be returned by QueryContextAttributes(CredSSP) and consumed by
		/// AcquireCredentialsHandle(CredSSP), LsaLogonUser, and other identity provider interfaces.
		/// </para>
		/// <para>
		/// SEC_WINNT_AUTH_PACKED_CREDENTIALS can contain a password credential type, defined as SEC_WINNT_AUTH_DATA_TYPE_PASSWORD. This
		/// credential type describes password credentials of a domain user as well as other online identities. Applications must define
		/// _SEC_WINNT_AUTH_TYPES to compile code that references this credential type as well as other definitions of the
		/// <c>SEC_WINNT_AUTH_PACKED_CREDENTIALS</c> structure.
		/// </para>
		/// <para>
		/// Applications should not query or set the <c>Flags</c> member directly. Use the SspiIsAuthIdentityEncrypted,
		/// SspiEncryptAuthIdentityEx, and SspiDecryptAuthIdentityEx functions to manage the encryption and decryption of the
		/// <c>SEC_WINNT_AUTH_IDENTITY_EX2</c> structure.
		/// </para>
		/// <para>
		/// Identity providers must explicitly check or set SEC_WINNT_AUTH_IDENTITY_FLAGS_ID_PROVIDER and the domain name fields to
		/// differentiate their password credential from a domain password and another identity provider's password.
		/// </para>
		/// <para>
		/// The CredPackAuthenticationBuffer function can be called with the CRED_PACK_ID_PROVIDER_CREDENTIALS option to create a
		/// <c>SEC_WINNT_AUTH_IDENTITY_EX2</c> structure with the authentication data of SEC_WINNT_AUTH_DATA_TYPE_PASSWORD credential type, a
		/// <c>Flags</c> member that contains the SEC_WINNT_AUTH_IDENTITY_FLAGS_ID_PROVIDER value, and a <c>DomainOffset</c> member set to
		/// the provider name.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-sec_winnt_auth_identity_ex2 typedef struct
		// _SEC_WINNT_AUTH_IDENTITY_EX2 { unsigned long Version; unsigned short cbHeaderLength; unsigned long cbStructureLength; unsigned
		// long UserOffset; unsigned short UserLength; unsigned long DomainOffset; unsigned short DomainLength; unsigned long
		// PackedCredentialsOffset; unsigned short PackedCredentialsLength; unsigned long Flags; unsigned long PackageListOffset; unsigned
		// short PackageListLength; } SEC_WINNT_AUTH_IDENTITY_EX2, *PSEC_WINNT_AUTH_IDENTITY_EX2;
		[PInvokeData("sspi.h", MSDNShortId = "a6083d76-1774-428c-85ca-fea817827d6a")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct SEC_WINNT_AUTH_IDENTITY_EX2
		{
			/// <summary>The version number of the structure. This must be <c>SEC_WINNT_AUTH_IDENTITY_VERSION_2</c>.</summary>
			public uint Version;

			/// <summary>The size, in bytes, of the structure header.</summary>
			public ushort cbHeaderLength;

			/// <summary>The size, in bytes, of the structure.</summary>
			public uint cbStructureLength;

			/// <summary>The offset from the beginning of the structure to the beginning of the user name string.</summary>
			public uint UserOffset;

			/// <summary>The size, in bytes, of the user name string.</summary>
			public ushort UserLength;

			/// <summary>
			/// <para>The offset from the beginning of the structure to the beginning of the domain name string.</para>
			/// <para>An identity credential should contain the identity provider name instead of the domain name.</para>
			/// </summary>
			public uint DomainOffset;

			/// <summary>The size, in bytes, of the domain name string.</summary>
			public ushort DomainLength;

			/// <summary>
			/// <para>The offset from the beginning of the structure to the beginning of the packed credentials.</para>
			/// <para>
			/// The packed credential is a SEC_WINNT_AUTH_PACKED_CREDENTIALS structure that contains a credential type that uniquely
			/// specifies the credential type.
			/// </para>
			/// </summary>
			public uint PackedCredentialsOffset;

			/// <summary>The size, in bytes, of the packed credentials string.</summary>
			public ushort PackedCredentialsLength;

			/// <summary>
			/// <para>An <c>unsigned long</c> flag that indicates the type used by negotiable security packages.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>SEC_WINNT_AUTH_IDENTITY_MARSHALLED 4 (0x4)</term>
			/// <term>All data is in one buffer.</term>
			/// </item>
			/// <item>
			/// <term>SEC_WINNT_AUTH_IDENTITY_ONLY 8 (0x8)</term>
			/// <term>
			/// Used with the Kerberos security support provider (SSP). Credentials are for identity only. The Kerberos package is directed
			/// to not include authorization data in the ticket.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SEC_WINNT_AUTH_IDENTITY_ANSI 1 (0x1)</term>
			/// <term>Credentials are in ANSI form.</term>
			/// </item>
			/// <item>
			/// <term>SEC_WINNT_AUTH_IDENTITY_UNICODE 2 (0x2)</term>
			/// <term>Credentials are in Unicode form.</term>
			/// </item>
			/// <item>
			/// <term>SEC_WINNT_AUTH_IDENTITY_FLAGS_ID_PROVIDER 524288 (0x80000)</term>
			/// <term>
			/// When the credential type is password, the presence of this flag specifies that the structure is an online ID credential. The
			/// DomainOffset and DomainLength members correspond to the online ID provider name. Windows Server 2008 R2 and Windows 7: This
			/// flag is not supported.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SEC_WINNT_AUTH_IDENTITY_FLAGS_PROCESS_ENCRYPTED 16 (0x10)</term>
			/// <term>
			/// The structure is encrypted by the SspiEncryptAuthIdentity function or by the SspiEncryptAuthIdentityEx function with the
			/// SEC_WINNT_AUTH_IDENTITY_ENCRYPT_SAME_PROCESS option. It can only be decrypted by the same process. Windows Server 2008 R2 and
			/// Windows 7: This flag is not supported.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SEC_WINNT_AUTH_IDENTITY_FLAGS_SYSTEM_PROTECTED 32 (0x20)</term>
			/// <term>
			/// The structure is encrypted by the SspiEncryptAuthIdentityEx function with the SEC_WINNT_AUTH_IDENTITY_ENCRYPT_SAME_LOGON
			/// option under the SYSTEM security context. It can only be decrypted by a thread running as SYSTEM. Windows Server 2008 R2 and
			/// Windows 7: This flag is not supported.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SEC_WINNT_AUTH_IDENTITY_FLAGS_USER_PROTECTED 64 (0x40)</term>
			/// <term>
			/// The structure is encrypted by the SspiEncryptAuthIdentityEx function with the SEC_WINNT_AUTH_IDENTITY_ENCRYPT_SAME_LOGON
			/// option under a non-SYSTEM security context. It can only be decrypted by a thread running in the same logon session in which
			/// it was encrypted. Windows Server 2008 R2 and Windows 7: This flag is not supported.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SEC_WINNT_AUTH_IDENTITY_FLAGS_RESERVED 65536 (0x10000)</term>
			/// <term>
			/// The authentication identity buffer is cbStructureLength + 8 padding bytes that are necessary for in-place encryption or
			/// decryption of the identity.
			/// </term>
			/// </item>
			/// </list>
			/// </summary>
			public SEC_WINNT_AUTH_IDENTITY_FLAGS Flags;

			/// <summary>The offset from the beginning of the structure to the beginning of the list of supported packages.</summary>
			public uint PackageListOffset;

			/// <summary>The size, in bytes, of the supported package list.</summary>
			public ushort PackageListLength;
		}

		/// <summary>The SecBuffer structure describes a buffer allocated by a transport application to pass to a security package.</summary>
		[StructLayout(LayoutKind.Sequential)]
		public struct SecBuffer
		{
			/// <summary>Specifies the size, in bytes, of the buffer pointed to by the pvBuffer member.</summary>
			public int cbBuffer;

			/// <summary>Bit flags that indicate the type of buffer. Must be one of the values of the SecBufferType enumeration.</summary>
			public SecBufferType BufferType;

			/// <summary>A pointer to a buffer.</summary>
			public IntPtr pvBuffer;

			/// <summary>Initializes a new instance of the <see cref="SecBuffer"/> struct.</summary>
			/// <param name="type">The type of buffer.</param>
			/// <param name="buffer">A pointer to an allocated buffer.</param>
			/// <param name="bufferSize">Size of the allocated buffer.</param>
			public SecBuffer(SecBufferType type, IntPtr buffer = default, int bufferSize = 0)
			{
				cbBuffer = bufferSize;
				BufferType = type;
				pvBuffer = buffer;
			}
		}

		/// <summary>
		/// The <c>SecBufferDesc</c> structure describes an array of SecBuffer structures to pass from a transport application to a security package.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secbufferdesc typedef struct _SecBufferDesc { unsigned long
		// ulVersion; unsigned long cBuffers; PSecBuffer pBuffers; } SecBufferDesc, *PSecBufferDesc;
		[PInvokeData("sspi.h", MSDNShortId = "fc6ef09c-3ba9-4bcb-a3c2-07422af8eaa9")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecBufferDesc
		{
			/// <summary>Current structure version.</summary>
			public const uint SECBUFFER_VERSION = 0;

			/// <summary>
			/// <para>Specifies the version number of this structure. This member must be SECBUFFER_VERSION.</para>
			/// </summary>
			public uint ulVersion;

			/// <summary>
			/// <para>Indicates the number of SecBuffer structures in the <c>pBuffers</c> array.</para>
			/// </summary>
			public uint cBuffers;

			/// <summary>
			/// <para>Pointer to an array of SecBuffer structures.</para>
			/// </summary>
			public IntPtr pBuffers;

			/// <summary>The default structure with the ulVersion field set correctly.</summary>
			public static readonly SecBufferDesc Default = new SecBufferDesc { ulVersion = SECBUFFER_VERSION };
		}

		/// <summary>A security handle.</summary>
		[PInvokeData("sspi.h")]
		[StructLayout(LayoutKind.Sequential)]
		public struct CredHandle : IEquatable<CredHandle>
		{
			/// <summary>Represents the invalid handle value.</summary>
			public static readonly CredHandle Invalid = new CredHandle() { dwLower = UIntPtr.Zero, dwUpper = MaxValue };

			/// <summary>Represents a NULL handle value.</summary>
			public static readonly CredHandle Null = new CredHandle();

			/// <summary>Lower value.</summary>
			public UIntPtr dwLower;

			/// <summary>Upper value.</summary>
			public UIntPtr dwUpper;

			private static readonly UIntPtr MaxValue = UIntPtr.Size == 4 ? new UIntPtr(uint.MaxValue) : new UIntPtr(ulong.MaxValue);

			/// <summary>Gets a value indicating whether this instance is invalid.</summary>
			/// <value><c>true</c> if this instance is invalid; otherwise, <c>false</c>.</value>
			public bool IsInvalid => dwLower == MaxValue || dwUpper == MaxValue;

			/// <summary>Gets a value indicating whether this instance is NULL.</summary>
			/// <value><c>true</c> if this instance is NULL; otherwise, <c>false</c>.</value>
			public bool IsNull => dwLower == UIntPtr.Zero && dwUpper == UIntPtr.Zero;

			/// <summary>Implements the operator !=.</summary>
			/// <param name="value1">The left value.</param>
			/// <param name="value2">The right value.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator !=(CredHandle value1, CredHandle value2) => !value1.Equals(value2);

			/// <summary>Implements the operator ==.</summary>
			/// <param name="value1">The left value.</param>
			/// <param name="value2">The right value.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator ==(CredHandle value1, CredHandle value2) => value1.Equals(value2);

			/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
			/// <param name="other">An object to compare with this object.</param>
			/// <returns>true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.</returns>
			public bool Equals(CredHandle other) => other.dwUpper == dwUpper && other.dwLower == dwLower;

			/// <summary>Determines whether the specified <see cref="object"/>, is equal to this instance.</summary>
			/// <param name="obj">The <see cref="object"/> to compare with this instance.</param>
			/// <returns><c>true</c> if the specified <see cref="object"/> is equal to this instance; otherwise, <c>false</c>.</returns>
			public override bool Equals(object obj) => obj is CredHandle h ? Equals(h) : base.Equals(obj);

			/// <summary>Returns a hash code for this instance.</summary>
			/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
			public override int GetHashCode() => base.GetHashCode();

			/// <summary>Invalidates this instance.</summary>
			public void Invalidate() { dwLower = UIntPtr.Zero; dwUpper = MaxValue; }
		}

		/// <summary>A security handle.</summary>
		[PInvokeData("sspi.h")]
		[StructLayout(LayoutKind.Sequential)]
		public struct CtxtHandle : IEquatable<CtxtHandle>
		{
			/// <summary>Represents the invalid handle value.</summary>
			public static readonly CtxtHandle Invalid = new CtxtHandle() { dwLower = UIntPtr.Zero, dwUpper = MaxValue };

			/// <summary>Represents a NULL handle value.</summary>
			public static readonly CtxtHandle Null = new CtxtHandle();

			/// <summary>Lower value.</summary>`
			public UIntPtr dwLower;

			/// <summary>Upper value.</summary>
			public UIntPtr dwUpper;

			private static readonly UIntPtr MaxValue = UIntPtr.Size == 4 ? new UIntPtr(uint.MaxValue) : new UIntPtr(ulong.MaxValue);

			/// <summary>Gets a value indicating whether this instance is invalid.</summary>
			/// <value><c>true</c> if this instance is invalid; otherwise, <c>false</c>.</value>
			public bool IsInvalid => dwLower == MaxValue || dwUpper == MaxValue;

			/// <summary>Gets a value indicating whether this instance is NULL.</summary>
			/// <value><c>true</c> if this instance is NULL; otherwise, <c>false</c>.</value>
			public bool IsNull => dwLower == UIntPtr.Zero && dwUpper == UIntPtr.Zero;

			/// <summary>Implements the operator !=.</summary>
			/// <param name="value1">The left value.</param>
			/// <param name="value2">The right value.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator !=(CtxtHandle value1, CtxtHandle value2) => !value1.Equals(value2);

			/// <summary>Implements the operator ==.</summary>
			/// <param name="value1">The left value.</param>
			/// <param name="value2">The right value.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator ==(CtxtHandle value1, CtxtHandle value2) => value1.Equals(value2);

			/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
			/// <param name="other">An object to compare with this object.</param>
			/// <returns>true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.</returns>
			public bool Equals(CtxtHandle other) => other.dwUpper == dwUpper && other.dwLower == dwLower;

			/// <summary>Determines whether the specified <see cref="object"/>, is equal to this instance.</summary>
			/// <param name="obj">The <see cref="object"/> to compare with this instance.</param>
			/// <returns><c>true</c> if the specified <see cref="object"/> is equal to this instance; otherwise, <c>false</c>.</returns>
			public override bool Equals(object obj) => obj is CtxtHandle h ? Equals(h) : base.Equals(obj);

			/// <summary>Returns a hash code for this instance.</summary>
			/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
			public override int GetHashCode() => base.GetHashCode();

			/// <summary>Invalidates this instance.</summary>
			public void Invalidate() { dwLower = UIntPtr.Zero; dwUpper = MaxValue; }
		}

		/// <summary>
		/// The <c>SecPkgContext_AccessToken</c> structure returns a handle to the access token for the current security context. The
		/// returned handle can be used by the ImpersonateLoggedOnUser and GetTokenInformation functions. This structure is returned by the
		/// QueryContextAttributes (General) function.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_accesstoken typedef struct
		// _SecPkgContext_AccessToken { void *AccessToken; } SecPkgContext_AccessToken, *PSecPkgContext_AccessToken;
		[PInvokeData("sspi.h", MSDNShortId = "4dc11cbd-7f28-4cb9-aaea-6e5a89ac91f0")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgContext_AccessToken
		{
			/// <summary>
			/// <para>Pointer to a <c>void</c> that receives the handle to the access token that represents the authenticated user.</para>
			/// <para>The returned handle is not duplicated, so the calling process must not call CloseHandle on the returned handle.</para>
			/// <para>
			/// If the security context is for a server or is incomplete, the returned handle may be <c>NULL</c>. Depending on the security
			/// package, QueryContextAttributes (General) may return SEC_E_NO_IMPERSONATION for these cases.
			/// </para>
			/// </summary>
			public IntPtr AccessToken;
		}

		/// <summary>
		/// The <c>SecPkgContext_Authority</c> structure contains the name of the authenticating authority if one is available. It can be a
		/// certification authority (CA) or the name of a server or domain that authenticated the connection. The QueryContextAttributes
		/// (General) function uses this structure.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_authoritya typedef struct
		// _SecPkgContext_AuthorityA { SEC_CHAR *sAuthorityName; } SecPkgContext_AuthorityA, *PSecPkgContext_AuthorityA;
		[PInvokeData("sspi.h", MSDNShortId = "619bf16b-c439-48e7-b013-3622e2f3bbc4")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct SecPkgContext_Authority
		{
			/// <summary>Pointer to a null-terminated string containing the name of the authenticating authority, if available.</summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string sAuthorityName;
		}

		/// <summary>Specifies a structure that contains channel binding information for a security context.</summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_bindings typedef struct _SecPkgContext_Bindings {
		// unsigned long BindingsLength; SEC_CHANNEL_BINDINGS *Bindings; } SecPkgContext_Bindings, *PSecPkgContext_Bindings;
		[PInvokeData("sspi.h", MSDNShortId = "6823cc31-acd3-4d67-92c6-65ff4d1c6aed")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgContext_Bindings
		{
			/// <summary>The size, in bytes, of the structure specified by the <c>Bindings</c> member</summary>
			public uint BindingsLength;

			/// <summary>A pointer to a SEC_CHANNEL_BINDINGS structure that specifies channel binding information.</summary>
			public IntPtr Bindings;
		}

		/// <summary>
		/// The <c>SecPkgContext_ClientSpecifiedTarget</c> structure specifies the service principal name (SPN) of the initial target when
		/// calling the QueryContextAttributes (Digest) function.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_clientspecifiedtarget typedef struct
		// _SecPkgContext_ClientSpecifiedTarget { SEC_WCHAR *sTargetName; } SecPkgContext_ClientSpecifiedTarget, *PSecPkgContext_ClientSpecifiedTarget;
		[PInvokeData("sspi.h", MSDNShortId = "67536f69-a1fc-4f26-84dc-872635bafa3b")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgContext_ClientSpecifiedTarget
		{
			/// <summary>The SPN of the initial target.</summary>
			[MarshalAs(UnmanagedType.LPWStr)]
			public string sTargetName;
		}

		/// <summary>Specifies the type of credentials used to create a client context.</summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_credinfo typedef struct _SecPkgContext_CredInfo {
		// SECPKG_CRED_CLASS CredClass; unsigned long IsPromptingNeeded; } SecPkgContext_CredInfo, *PSecPkgContext_CredInfo;
		[PInvokeData("sspi.h", MSDNShortId = "5c2c6d01-5de3-4dd1-9fa2-cce9eadd6902")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgContext_CredInfo
		{
			/// <summary>A value of the SECPKG_CRED_CLASS enumeration that indicates the type of credentials.</summary>
			public SECPKG_CRED_CLASS CredClass;

			/// <summary>
			/// A nonzero value indicates that the application must prompt the user for credentials. All other values indicate that the
			/// application does not need to prompt the user.
			/// </summary>
			[MarshalAs(UnmanagedType.Bool)]
			public bool IsPromptingNeeded;
		}

		/// <summary>
		/// The <c>SecPkgContext_DceInfo</c> structure contains authorization data used by DCE services. The QueryContextAttributes (General)
		/// function uses this structure.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_dceinfo typedef struct _SecPkgContext_DceInfo {
		// unsigned long AuthzSvc; void *pPac; } SecPkgContext_DceInfo, *PSecPkgContext_DceInfo;
		[PInvokeData("sspi.h", MSDNShortId = "490688d0-efdd-4a40-88b9-eb53ff592d2a")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgContext_DceInfo
		{
			/// <summary>Specifies the authorization service used. For DCE use only.</summary>
			public uint AuthzSvc;

			/// <summary>Pointer to package-specific authorization data.</summary>
			public IntPtr pPac;
		}

		/// <summary>
		/// The <c>SecPkgContext_Flags</c> structure contains information about the flags in the current security context. This structure is
		/// returned by QueryContextAttributes (General).
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-secpkgcontext_flags typedef struct _SecPkgContext_Flags {
		// unsigned long Flags; } SecPkgContext_Flags, *PSecPkgContext_Flags;
		[PInvokeData("sspi.h", MSDNShortId = "0be0e945-4048-4748-a9fd-15d08fb7ff3e")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgContext_Flags
		{
			/// <summary>
			/// Flag values for the current security context. These values correspond to the flags negotiated by the
			/// InitializeSecurityContext (General) and AcceptSecurityContext (General) functions.
			/// </summary>
			public uint Flags;
		}

		/// <summary>
		/// <para>
		/// The <c>SecPkgContext_KeyInfo</c> structure contains information about the session keys used in a security context. The
		/// QueryContextAttributes (General) function uses this structure.
		/// </para>
		/// <para>
		/// Applications using the Schannel security support provider (SSP) should not use the <c>SecPkgContext_KeyInfo</c> structure.
		/// Instead, use the SecPkgContext_ConnectionInfo structure.
		/// </para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_keyinfoa typedef struct _SecPkgContext_KeyInfoA {
		// SEC_CHAR *sSignatureAlgorithmName; SEC_CHAR *sEncryptAlgorithmName; unsigned long KeySize; unsigned long SignatureAlgorithm;
		// unsigned long EncryptAlgorithm; } SecPkgContext_KeyInfoA, *PSecPkgContext_KeyInfoA;
		[PInvokeData("sspi.h", MSDNShortId = "ec146329-6789-460c-ae62-629a1765a4c1")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct SecPkgContext_KeyInfo
		{
			/// <summary>
			/// Pointer to a null-terminated string that contains the name, if available, of the algorithm used for generating signatures,
			/// for example "MD5" or "SHA-2".
			/// </summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string sSignatureAlgorithmName;

			/// <summary>
			/// Pointer to a null-terminated string that contains the name, if available, of the algorithm used for encrypting messages.
			/// Reserved for future use.
			/// </summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string sEncryptAlgorithmName;

			/// <summary>Specifies the effective key length, in bits, for the session key. This is typically 40, 56, or 128 bits.</summary>
			public uint KeySize;

			/// <summary>Specifies the algorithm identifier (ALG_ID) used for generating signatures, if available.</summary>
			public ALG_ID SignatureAlgorithm;

			/// <summary>Specifies the algorithm identifier (ALG_ID) used for encrypting messages. Reserved for future use.</summary>
			public ALG_ID EncryptAlgorithm;
		}

		/// <summary>
		/// Specifies whether the token from the most recent call to the InitializeSecurityContext function is the last token from the client.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_lastclienttokenstatus typedef struct
		// _SecPkgContext_LastClientTokenStatus { SECPKG_ATTR_LCT_STATUS LastClientTokenStatus; } SecPkgContext_LastClientTokenStatus, *PSecPkgContext_LastClientTokenStatus;
		[PInvokeData("sspi.h", MSDNShortId = "ccb2bb4e-3c65-4305-95ad-b9111f3936b5")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgContext_LastClientTokenStatus
		{
			/// <summary>
			/// A value of the SECPKG_ATTR_LCT_STATUS enumeration that indicates the status of the token returned by the most recent call to InitializeSecurityContext.
			/// </summary>
			public SECPKG_ATTR_LCT_STATUS LastClientTokenStatus;
		}

		/// <summary>
		/// The <c>SecPkgContext_Lifespan</c> structure indicates the life span of a security context. The QueryContextAttributes (General)
		/// function uses this structure.
		/// </summary>
		/// <remarks>It is recommended that the security package always return these values in local time.</remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_lifespan typedef struct _SecPkgContext_Lifespan {
		// TimeStamp tsStart; TimeStamp tsExpiry; } SecPkgContext_Lifespan, *PSecPkgContext_Lifespan;
		[PInvokeData("sspi.h", MSDNShortId = "7ef45795-f6af-4dac-a498-c6f8c915a168")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgContext_Lifespan
		{
			/// <summary>Time at which the context was established.</summary>
			public TimeStamp tsStart;

			/// <summary>Time at which the context will expire.</summary>
			public TimeStamp tsExpiry;
		}

		/// <summary>
		/// The <c>SecPkgContext_Names</c> structure indicates the name of the user associated with a security context. The
		/// QueryContextAttributes (General) function uses this structure.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_namesa typedef struct _SecPkgContext_NamesA {
		// SEC_CHAR *sUserName; } SecPkgContext_NamesA, *PSecPkgContext_NamesA;
		[PInvokeData("sspi.h", MSDNShortId = "9df0bf7c-ad5f-4cb8-8934-76062789735f")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct SecPkgContext_Names
		{
			/// <summary>
			/// Pointer to a null-terminated string containing the name of the user represented by the context. If the security package has
			/// set the SECPKG_FLAG_ACCEPT_WIN32_NAME flag, this name can be used in other Windows calls.
			/// </summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string sUserName;
		}

		/// <summary>
		/// The <c>SecPkgContext_NativeNames</c> structure returns the client and server principal names from the outbound ticket. This
		/// structure is valid only for client outbound tickets. This structure is returned by QueryContextAttributes (General).
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_nativenamesa typedef struct
		// _SecPkgContext_NativeNamesA { SEC_CHAR *sClientName; SEC_CHAR *sServerName; } SecPkgContext_NativeNamesA, *PSecPkgContext_NativeNamesA;
		[PInvokeData("sspi.h", MSDNShortId = "f935093f-5661-4ced-94f1-c4b21c3b9f69")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct SecPkgContext_NativeNames
		{
			/// <summary>
			/// Pointer to a null-terminated string that represents the principal name for the client in the outbound ticket. This string
			/// should never be <c>NULL</c> when querying a security context negotiated with Kerberos.
			/// </summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string sClientName;

			/// <summary>
			/// Pointer to a null-terminated string that represents the principal name for the server in the outbound ticket. This string
			/// should never be <c>NULL</c> when querying a security context negotiated with Kerberos.
			/// </summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string sServerName;
		}

		/// <summary>Specifies the error status of the last attempt to create a client context.</summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_negostatus typedef struct
		// _SecPkgContext_NegoStatus { unsigned long LastStatus; } SecPkgContext_NegoStatus, *PSecPkgContext_NegoStatus;
		[PInvokeData("sspi.h", MSDNShortId = "09201338-4743-44a2-b84f-35b26116976d")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgContext_NegoStatus
		{
			/// <summary>The error status of the last attempt to create a client context.</summary>
			public uint LastStatus;
		}

		/// <summary>
		/// The <c>SecPkgContext_NegotiationInfo</c> structure contains information on the security package that is being set up or has been
		/// set up, and also gives the status on the negotiation to set up the security package.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_negotiationinfoa typedef struct
		// _SecPkgContext_NegotiationInfoA { PSecPkgInfoA PackageInfo; unsigned long NegotiationState; } SecPkgContext_NegotiationInfoA, *PSecPkgContext_NegotiationInfoA;
		[PInvokeData("sspi.h", MSDNShortId = "3af724b8-fbe5-4a75-b128-9efe65381f2f")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct SecPkgContext_NegotiationInfo
		{
			/// <summary>
			/// Pointer to a SecPkgInfo structure that provides general information about the security package chosen in the negotiate
			/// process, such as the name and capabilities of the package.
			/// </summary>
			public IntPtr PackageInfo;

			/// <summary>
			/// <para>
			/// Indicator of the state of the negotiation for the security package identified in the <c>PackageInfo</c> member. This
			/// attribute can be queried from the context handle before the setup is complete, such as when ISC returns SEC_I_CONTINUE_NEEDED.
			/// </para>
			/// <para>The following table shows values returned in this member.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>SECPKG_NEGOTIATION_COMPLETE</term>
			/// <term>Negotiation has been completed.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_NEGOTIATION_OPTIMISTIC</term>
			/// <term>Negotiations not yet completed.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_NEGOTIATION_IN_PROGRESS</term>
			/// <term>Negotiations in progress.</term>
			/// </item>
			/// </list>
			/// </summary>
			public uint NegotiationState;
		}

		/// <summary>
		/// The <c>SecPkgContext_PackageInfo</c> structure contains the name of a security support provider (SSP). This structure is returned
		/// by the QueryContextAttributes (General) function. It would most often be used when the SSP in use was established using the
		/// Negotiate security package.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_packageinfoa typedef struct
		// _SecPkgContext_PackageInfoA { PSecPkgInfoA PackageInfo; } SecPkgContext_PackageInfoA, *PSecPkgContext_PackageInfoA;
		[PInvokeData("sspi.h", MSDNShortId = "94c21f22-d974-4ae5-beef-d4567e6ea7e1")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct SecPkgContext_PackageInfo
		{
			/// <summary>Pointer to a SecPkgInfo structure containing the name of the SSP in use.</summary>
			public IntPtr PackageInfo;
		}

		/// <summary>
		/// The <c>SecPkgContext_PasswordExpiry</c> structure contains information about the expiration of a password or other credential
		/// used for the security context. This structure is returned by QueryContextAttributes (General).
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-secpkgcontext_passwordexpiry typedef struct
		// _SecPkgContext_PasswordExpiry { TimeStamp tsPasswordExpires; } SecPkgContext_PasswordExpiry, *PSecPkgContext_PasswordExpiry;
		[PInvokeData("sspi.h", MSDNShortId = "f45dde88-1520-4e65-8fae-8407dfaa0850")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgContext_PasswordExpiry
		{
			/// <summary>
			/// A TimeStamp variable that indicates when the credentials for the security context expire. For password-based packages, this
			/// variable indicates when the password expires. For Kerberos, this variable indicates when the ticket expires.
			/// </summary>
			public TimeStamp tsPasswordExpires;
		}

		/// <summary>
		/// <para>
		/// [The <c>SecPkgContext_ProtoInfo</c> structure is available for use in the operating systems specified in the Requirements
		/// section. It may be altered or unavailable in subsequent versions. Instead, use the SecPkgContext_ConnectionInfo structure.]
		/// </para>
		/// <para>The <c>SecPkgContext_ProtoInfo</c> structure holds information about the protocol in use.</para>
		/// <para>This attribute is supported only by the Schannel security support provider (SSP).</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-secpkgcontext_protoinfoa typedef struct
		// _SecPkgContext_ProtoInfoA { SEC_CHAR *sProtocolName; unsigned long majorVersion; unsigned long minorVersion; }
		// SecPkgContext_ProtoInfoA, *PSecPkgContext_ProtoInfoA;
		[PInvokeData("sspi.h", MSDNShortId = "c10eb1fc-b957-4853-86c1-070749488bb9")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct SecPkgContext_ProtoInfo
		{
			/// <summary>Pointer to a string containing the name of the protocol.</summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string sProtocolName;

			/// <summary>Major version number.</summary>
			public uint majorVersion;

			/// <summary>Minor version number.</summary>
			public uint minorVersion;
		}

		/// <summary>
		/// The <c>SecPkgContext_SessionKey</c> structure contains information about the session key used for the security context. This
		/// structure is returned by the QueryContextAttributes (General) function.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_sessionkey typedef struct
		// _SecPkgContext_SessionKey { unsigned long SessionKeyLength; unsigned char *SessionKey; } SecPkgContext_SessionKey, *PSecPkgContext_SessionKey;
		[PInvokeData("sspi.h", MSDNShortId = "88cf437e-3be0-4f12-9058-ad078deed6a1")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgContext_SessionKey
		{
			/// <summary>Size, in bytes, of the session key.</summary>
			public uint SessionKeyLength;

			/// <summary>The session key for the security context.</summary>
			public IntPtr SessionKey;
		}

		/// <summary>
		/// The <c>SecPkgContext_Sizes</c> structure indicates the sizes of important structures used in the message support functions. The
		/// QueryContextAttributes (General) function uses this structure.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_sizes typedef struct _SecPkgContext_Sizes {
		// unsigned long cbMaxToken; unsigned long cbMaxSignature; unsigned long cbBlockSize; unsigned long cbSecurityTrailer; }
		// SecPkgContext_Sizes, *PSecPkgContext_Sizes;
		[PInvokeData("sspi.h", MSDNShortId = "46b6a155-8855-4aa0-a513-aa5b3760fcd4")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgContext_Sizes
		{
			/// <summary>Specifies the maximum size of the security token used in the authentication exchanges.</summary>
			public uint cbMaxToken;

			/// <summary>
			/// Specifies the maximum size of the signature created by the MakeSignature function. This member must be zero if integrity
			/// services are not requested or available.
			/// </summary>
			public uint cbMaxSignature;

			/// <summary>
			/// Specifies the preferred integral size of the messages. For example, eight indicates that messages should be of size zero mod
			/// eight for optimal performance. Messages other than this block size can be padded.
			/// </summary>
			public uint cbBlockSize;

			/// <summary>
			/// Size of the security trailer to be appended to messages. This member should be zero if the relevant services are not
			/// requested or available.
			/// </summary>
			public uint cbSecurityTrailer;
		}

		/// <summary>
		/// The <c>SecPkgContext_StreamSizes</c> structure indicates the sizes of the various parts of a stream for use with the message
		/// support functions. The QueryContextAttributes (General) function uses this structure.
		/// </summary>
		/// <remarks>
		/// Applications calling EncryptMessage (General) should check the values of the <c>cbHeader</c>, <c>cbTrailer</c>, and
		/// <c>cbMaximumMessage</c> members to determine the size of the encrypted packet.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_streamsizes typedef struct
		// _SecPkgContext_StreamSizes { unsigned long cbHeader; unsigned long cbTrailer; unsigned long cbMaximumMessage; unsigned long
		// cBuffers; unsigned long cbBlockSize; } SecPkgContext_StreamSizes, *PSecPkgContext_StreamSizes;
		[PInvokeData("sspi.h", MSDNShortId = "75e5fc96-56cc-4713-a34f-fca687798ad6")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgContext_StreamSizes
		{
			/// <summary>Specifies the size, in bytes, of the header portion. If zero, no header is used.</summary>
			public uint cbHeader;

			/// <summary>Specifies the maximum size, in bytes, of the trailer portion. If zero, no trailer is used.</summary>
			public uint cbTrailer;

			/// <summary>Specifies the size, in bytes, of the largest message that can be encapsulated.</summary>
			public uint cbMaximumMessage;

			/// <summary>Specifies the number of buffers to pass.</summary>
			public uint cBuffers;

			/// <summary>
			/// Specifies the preferred integral size of the messages. For example, eight indicates that messages should be of size zero mod
			/// eight for optimal performance. Messages other than this block size can be padded.
			/// </summary>
			public uint cbBlockSize;
		}

		/// <summary>The <c>SecPkgContext_SubjectAttributes</c> structure returns the security attribute information.</summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcontext_subjectattributes typedef struct
		// _SecPkgContext_SubjectAttributes { void *AttributeInfo; } SecPkgContext_SubjectAttributes, *PSecPkgContext_SubjectAttributes;
		[PInvokeData("sspi.h", MSDNShortId = "548E972F-EB94-4BBD-94F2-FA38184D179A")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgContext_SubjectAttributes
		{
			/// <summary>
			/// Pointer to a <c>void</c> that receives the attribute information stored in a AUTHZ_SECURITY_ATTRIBUTES_INFORMATION structure.
			/// </summary>
			public IntPtr AttributeInfo;
		}

		/// <summary>
		/// The <c>SecPkgContext_TargetInformation</c> structure returns information about the credential used for the security context. This
		/// structure is returned by the QueryContextAttributes (General) function.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-secpkgcontext_targetinformation typedef struct
		// _SecPkgContext_TargetInformation { unsigned long MarshalledTargetInfoLength; unsigned char *MarshalledTargetInfo; }
		// SecPkgContext_TargetInformation, *PSecPkgContext_TargetInformation;
		[PInvokeData("sspi.h", MSDNShortId = "8a5a6bd6-8678-4544-a631-5ee4347bc685")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgContext_TargetInformation
		{
			/// <summary>Size, in bytes, of <c>MarshalledTargetInfo</c>.</summary>
			public uint MarshalledTargetInfoLength;

			/// <summary>Array of bytes that represent the credential, if a credential is provided by a credential manager.</summary>
			public IntPtr MarshalledTargetInfo;
		}

		/// <summary>Specifies the certificate credentials. The QueryCredentialsAttributes function uses this structure.</summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcredentials_cert typedef struct _SecPkgCredentials_Cert {
		// unsigned long EncodedCertSize; unsigned char *EncodedCert; } SecPkgCredentials_Cert, *PSecPkgCredentials_Cert;
		[PInvokeData("sspi.h", MSDNShortId = "9EEE6E98-D45C-4929-9C9C-F344972D186F")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SecPkgCredentials_Cert
		{
			/// <summary>Size of the encoded certificate.</summary>
			public uint EncodedCertSize;

			/// <summary>The encoded certificate.</summary>
			public IntPtr EncodedCert;
		}

		/// <summary>Specifies the Kerberos proxy settings for the credentials.</summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcredentials_kdcproxysettingsw typedef struct
		// _SecPkgCredentials_KdcProxySettingsW { ULONG Version; ULONG Flags; USHORT ProxyServerOffset; USHORT ProxyServerLength; USHORT
		// ClientTlsCredOffset; USHORT ClientTlsCredLength; } SecPkgCredentials_KdcProxySettingsW, *PSecPkgCredentials_KdcProxySettingsW;
		[PInvokeData("sspi.h", MSDNShortId = "42BC75B8-6392-4FD4-95BC-266B3AFDDC62")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
		public struct SecPkgCredentials_KdcProxySettingsW
		{
			/// <summary>Version for the Kerberos proxy settings where KDC_PROXY_SETTINGS_V1 is defined as 1.</summary>
			public uint Version;

			/// <summary>Flags for the Kerberos proxy settings.</summary>
			public uint Flags;

			/// <summary>The offset of the proxy server. This member is optional.</summary>
			public ushort ProxyServerOffset;

			/// <summary>Length of the proxy server.</summary>
			public ushort ProxyServerLength;

			/// <summary>The offset of the client credentials. This member is optional.</summary>
			public ushort ClientTlsCredOffset;

			/// <summary>Length of the client credentials.</summary>
			public ushort ClientTlsCredLength;
		}

		/// <summary>
		/// The <c>SecPkgCredentials_Names</c> structure holds the name of the user associated with a context. The QueryCredentialsAttributes
		/// function uses this structure.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkgcredentials_namesa typedef struct
		// _SecPkgCredentials_NamesA { SEC_CHAR *sUserName; } SecPkgCredentials_NamesA, *PSecPkgCredentials_NamesA;
		[PInvokeData("sspi.h", MSDNShortId = "38123a10-72a4-46eb-974b-3c01142dfc74")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct SecPkgCredentials_Names
		{
			/// <summary>
			/// Pointer to a null-terminated string containing the name of the user represented by the credential. If the security package
			/// sets the SECPKG_FLAG_ACCEPT_WIN32_NAME flag to indicate that it can process Windows names, this name can be used in other
			/// Windows calls.
			/// </summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string sUserName;
		}

		/// <summary>
		/// The <c>SecPkgCredentials_SSIProvider</c> structure holds the SSI provider information associated with a context. The
		/// QueryCredentialsAttributes function uses this structure.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-secpkgcredentials_ssiprovidera typedef struct
		// _SecPkgCredentials_SSIProviderA { SEC_CHAR *sProviderName; unsigned long ProviderInfoLength; char *ProviderInfo; }
		// SecPkgCredentials_SSIProviderA, *PSecPkgCredentials_SSIProviderA;
		[PInvokeData("sspi.h", MSDNShortId = "0C6D6217-3A97-40B5-A7FB-B9D49C5FBC7C")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct SecPkgCredentials_SSIProvider
		{
			/// <summary>Pointer to a null-terminated string that contains the name of the provider represented by the credential.</summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string sProviderName;

			/// <summary>Length of the provider information.</summary>
			public uint ProviderInfoLength;

			/// <summary>The provider information.</summary>
			public IntPtr ProviderInfo;
		}

		/// <summary>The <c>SecPkgInfo</c> structure provides general information about a security package, such as its name and capabilities.</summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_secpkginfoa typedef struct _SecPkgInfoA { unsigned long
		// fCapabilities; unsigned short wVersion; unsigned short wRPCID; unsigned long cbMaxToken; SEC_CHAR *Name; SEC_CHAR *Comment; }
		// SecPkgInfoA, *PSecPkgInfoA;
		[PInvokeData("sspi.h", MSDNShortId = "d0bff3d8-63f1-4a4e-851f-177040af6bd2")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct SecPkgInfo
		{
			/// <summary>
			/// <para>
			/// Set of bit flags that describes the capabilities of the security package. This member can be a combination of the following flags.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>SECPKG_FLAG_INTEGRITY 0x1</term>
			/// <term>The security package supports the MakeSignature and VerifySignature functions.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_PRIVACY 0x2</term>
			/// <term>The security package supports the EncryptMessage (General) and DecryptMessage (General) functions.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_TOKEN_ONLY 0x4</term>
			/// <term>
			/// The package is interested only in the security-token portion of messages, and will ignore any other buffers. This is a
			/// performance-related issue.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_DATAGRAM 0x8</term>
			/// <term>Supports datagram-style authentication. For more information, see SSPI Context Semantics.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_CONNECTION 0x10</term>
			/// <term>Supports connection-oriented style authentication. For more information, see SSPI Context Semantics.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_MULTI_REQUIRED 0x20</term>
			/// <term>Multiple legs are required for authentication.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_CLIENT_ONLY 0x40</term>
			/// <term>Server authentication support is not provided.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_EXTENDED_ERROR 0x80</term>
			/// <term>Supports extended error handling. For more information, see Extended Error Information.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_IMPERSONATION 0x100</term>
			/// <term>Supports Windows impersonation in server contexts.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_ACCEPT_WIN32_NAME 0x200</term>
			/// <term>Understands Windows principal and target names.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_STREAM 0x400</term>
			/// <term>Supports stream semantics. For more information, see SSPI Context Semantics.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_NEGOTIABLE 0X800</term>
			/// <term>Can be used by the Microsoft Negotiate security package.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_GSS_COMPATIBLE 0x1000</term>
			/// <term>Supports GSS compatibility.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_LOGON 0x2000</term>
			/// <term>Supports LsaLogonUser.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_ASCII_BUFFERS 0x4000</term>
			/// <term>Token buffers are in ASCII characters format.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_FRAGMENT 0x8000</term>
			/// <term>
			/// Supports separating large tokens into smaller buffers so that applications can make repeated calls to
			/// InitializeSecurityContext (General) and AcceptSecurityContext (General) with the smaller buffers to complete authentication.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_MUTUAL_AUTH 0x10000</term>
			/// <term>Supports mutual authentication.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_DELEGATION 0x20000</term>
			/// <term>Supports delegation.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_READONLY_WITH_CHECKSUM 0x40000</term>
			/// <term>The security package supports using a checksum instead of in-place encryption when calling the EncryptMessage function.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_RESTRICTED_TOKENS 0x80000</term>
			/// <term>Supports callers with restricted tokens.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_NEGO_EXTENDER 0x00100000</term>
			/// <term>The security package extends the Microsoft Negotiate security package. There can be at most one package of this type.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_NEGOTIABLE2 0x00200000</term>
			/// <term>This package is negotiated by the package of type SECPKG_FLAG_NEGO_EXTENDER.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_APPCONTAINER_PASSTHROUGH 0x00400000</term>
			/// <term>This package receives all calls from app container apps.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_FLAG_APPCONTAINER_CHECKS 0x00800000</term>
			/// <term>This package receives calls from app container apps if one of the following checks succeeds.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_CALLFLAGS_APPCONTAINER 0x00000001</term>
			/// <term>The caller is an app container.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_CALLFLAGS_AUTHCAPABLE 0x00000002</term>
			/// <term>The caller can use default credentials.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_CALLFLAGS_FORCE_SUPPLIED 0x00000004</term>
			/// <term>The caller can only use supplied credentials.</term>
			/// </item>
			/// </list>
			/// </summary>
			public SECPKG_FLAG fCapabilities;

			/// <summary>Specifies the version of the package protocol. Must be 1.</summary>
			public ushort wVersion;

			/// <summary>
			/// Specifies a DCE RPC identifier, if appropriate. If the package does not implement one of the DCE registered security systems,
			/// the reserved value SECPKG_ID_NONE is used.
			/// </summary>
			public ushort wRPCID;

			/// <summary>Specifies the maximum size, in bytes, of the token.</summary>
			public uint cbMaxToken;

			/// <summary>Pointer to a null-terminated string that contains the name of the security package.</summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string Name;

			/// <summary>Pointer to a null-terminated string. This can be any additional string passed back by the package.</summary>
			[MarshalAs(UnmanagedType.LPTStr)]
			public string Comment;
		}

		/// <summary>Specifies information about a security package. This structure is used by the AddSecurityPackage function.</summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-security_package_options typedef struct
		// _SECURITY_PACKAGE_OPTIONS { unsigned long Size; unsigned long Type; unsigned long Flags; unsigned long SignatureSize; void
		// *Signature; } SECURITY_PACKAGE_OPTIONS, *PSECURITY_PACKAGE_OPTIONS;
		[PInvokeData("sspi.h", MSDNShortId = "2e9f65ec-72a5-4d6f-aa63-f83369f0dd07")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct SECURITY_PACKAGE_OPTIONS
		{
			/// <summary>The size, in bytes, of this structure.</summary>
			public uint Size;

			/// <summary>
			/// <para>The type of security package. This can be one of the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>SECPKG_OPTIONS_TYPE_UNKNOWN 0</term>
			/// <term>The package type is not known.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_OPTIONS_TYPE_LSA 1</term>
			/// <term>The security package is an LSA authentication package.</term>
			/// </item>
			/// <item>
			/// <term>SECPKG_OPTIONS_TYPE_SSPI 2</term>
			/// <term>The security package is a Security Support Provider Interface (SSPI) package.</term>
			/// </item>
			/// </list>
			/// </summary>
			public SECPKG_OPTIONS_TYPE Type;

			/// <summary>This member is reserved. Do not use it.</summary>
			public uint Flags;

			/// <summary>The size, in bytes, of a digital signature for this security package.</summary>
			public uint SignatureSize;

			/// <summary>A digital signature for this security package.</summary>
			public IntPtr Signature;
		}

		/// <summary>
		/// The <c>SecurityFunctionTable</c> structure is a dispatch table that contains pointers to the functions defined in SSPI.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/sspi/ns-sspi-_security_function_table_w typedef struct
		// _SECURITY_FUNCTION_TABLE_W { unsigned long dwVersion; ENUMERATE_SECURITY_PACKAGES_FN_W EnumerateSecurityPackagesW;
		// QUERY_CREDENTIALS_ATTRIBUTES_FN_W QueryCredentialsAttributesW; ACQUIRE_CREDENTIALS_HANDLE_FN_W AcquireCredentialsHandleW;
		// FREE_CREDENTIALS_HANDLE_FN FreeCredentialsHandle; void *Reserved2; INITIALIZE_SECURITY_CONTEXT_FN_W InitializeSecurityContextW;
		// ACCEPT_SECURITY_CONTEXT_FN AcceptSecurityContext; COMPLETE_AUTH_TOKEN_FN CompleteAuthToken; DELETE_SECURITY_CONTEXT_FN
		// DeleteSecurityContext; APPLY_CONTROL_TOKEN_FN ApplyControlToken; QUERY_CONTEXT_ATTRIBUTES_FN_W QueryContextAttributesW;
		// IMPERSONATE_SECURITY_CONTEXT_FN ImpersonateSecurityContext; REVERT_SECURITY_CONTEXT_FN RevertSecurityContext; MAKE_SIGNATURE_FN
		// MakeSignature; VERIFY_SIGNATURE_FN VerifySignature; FREE_CONTEXT_BUFFER_FN FreeContextBuffer; QUERY_SECURITY_PACKAGE_INFO_FN_W
		// QuerySecurityPackageInfoW; void *Reserved3; void *Reserved4; EXPORT_SECURITY_CONTEXT_FN ExportSecurityContext;
		// IMPORT_SECURITY_CONTEXT_FN_W ImportSecurityContextW; ADD_CREDENTIALS_FN_W AddCredentialsW; void *Reserved8;
		// QUERY_SECURITY_CONTEXT_TOKEN_FN QuerySecurityContextToken; ENCRYPT_MESSAGE_FN EncryptMessage; DECRYPT_MESSAGE_FN DecryptMessage;
		// SET_CONTEXT_ATTRIBUTES_FN_W SetContextAttributesW; SET_CREDENTIALS_ATTRIBUTES_FN_W SetCredentialsAttributesW; CHANGE_PASSWORD_FN_W
		// ChangeAccountPasswordW; void *Reserved9; QUERY_CONTEXT_ATTRIBUTES_EX_FN_W QueryContextAttributesExW;
		// QUERY_CREDENTIALS_ATTRIBUTES_EX_FN_W QueryCredentialsAttributesExW; } SecurityFunctionTableW, *PSecurityFunctionTableW;
		[PInvokeData("sspi.h", MSDNShortId = "6315e8d6-b40a-4dd6-b6a6-598a965f93dc")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct SecurityFunctionTable
		{
			/// <summary>Version number of the table.</summary>
			public uint dwVersion;

			/// <summary>Pointer to the EnumerateSecurityPackages function.</summary>
			public IntPtr EnumerateSecurityPackages;

			/// <summary>Pointer to the QueryCredentialsAttributes function.</summary>
			public IntPtr QueryCredentialsAttributes;

			/// <summary>Pointer to the AcquireCredentialsHandle function.</summary>
			public IntPtr AcquireCredentialsHandle;

			/// <summary>Pointer to the FreeCredentialsHandle function.</summary>
			public IntPtr FreeCredentialHandl;

			/// <summary>Reserved for future use.</summary>
			public IntPtr Reserved1;

			/// <summary>Pointer to the InitializeSecurityContext (General) function.</summary>
			public IntPtr InitializeSecurityContext;

			/// <summary>Pointer to the AcceptSecurityContext (General) function.</summary>
			public IntPtr AcceptSecurityContex;

			/// <summary>Pointer to the CompleteAuthToken function.</summary>
			public IntPtr CompleteAuthToke;

			/// <summary>Pointer to the DeleteSecurityContext function.</summary>
			public IntPtr DeleteSecurityContex;

			/// <summary>Pointer to the ApplyControlToken function.</summary>
			public IntPtr ApplyControlToke;

			/// <summary>Pointer to the QueryContextAttributes (General) function.</summary>
			public IntPtr QueryContextAttributes;

			/// <summary>Pointer to the ImpersonateSecurityContext function.</summary>
			public IntPtr ImpersonateSecurityContex;

			/// <summary>Pointer to the RevertSecurityContext function.</summary>
			public IntPtr RevertSecurityContex;

			/// <summary>Pointer to the MakeSignature function.</summary>
			public IntPtr MakeSignatur;

			/// <summary>Pointer to the VerifySignature function.</summary>
			public IntPtr VerifySignatur;

			/// <summary>Pointer to the FreeContextBuffer function.</summary>
			public IntPtr FreeContextBuffe;

			/// <summary>Pointer to the QuerySecurityPackageInfo function.</summary>
			public IntPtr QuerySecurityPackageInfo;

			/// <summary>Reserved for future use.</summary>
			public IntPtr Reserved2;

			/// <summary>Reserved for future use.</summary>
			public IntPtr Reserved3;

			/// <summary>Pointer to the ExportSecurityContext function.</summary>
			public IntPtr ExportSecurityContex;

			/// <summary>Pointer to the ImportSecurityContext function.</summary>
			public IntPtr ImportSecurityContext;

			/// <summary>Pointer to the AddCredential function.</summary>
			public IntPtr AddCredentials;

			/// <summary>Reserved for future use.</summary>
			public IntPtr Reserved4;

			/// <summary>Pointer to the QuerySecurityContextToken function.</summary>
			public IntPtr QuerySecurityContextToke;

			/// <summary>Pointer to the EncryptMessage (General) function.</summary>
			public IntPtr EncryptMessag;

			/// <summary>Pointer to the DecryptMessage (General) function.</summary>
			public IntPtr DecryptMessag;

			/// <summary>Pointer to the SetContextAttributes function.</summary>
			public IntPtr SetContextAttributes;

			/// <summary>Pointer to the SetCredentialsAttributes function.</summary>
			public IntPtr SetCredentialsAttributes;

			/// <summary>Pointer to the ChangeAccountPassword function.</summary>
			public IntPtr ChangeAccountPassword;

			/// <summary>Pointer to the AddCredential function.</summary>
			public IntPtr Reserved5;

			/// <summary>Pointer to the QueryContextAttributesEx function.</summary>
			public IntPtr QueryContextAttributesEx;

			/// <summary>Pointer to the QueryCredentialsAttributesEx function.</summary>
			public IntPtr QueryCredentialsAttributesEx;
		}

		/// <summary>Provides a <see cref="SafeHandle"/> for a context buffer that is disposed using <see cref="FreeContextBuffer"/>.</summary>
		public class SafeContextBuffer : SafeHANDLE
		{
			/// <summary>Initializes a new instance of the <see cref="SafeContextBuffer"/> class and assigns an existing handle.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			/// <param name="ownsHandle">
			/// <see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).
			/// </param>
			public SafeContextBuffer(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

			/// <summary>Initializes a new instance of the <see cref="SafeContextBuffer"/> class.</summary>
			private SafeContextBuffer() : base() { }

			/// <summary>
			/// Extracts an array of structures of <typeparamref name="T"/> containing <paramref name="count"/> items. <note type="note">This
			/// call can cause memory exceptions if the pointer does not have sufficient allocated memory to retrieve all the structures.</note>
			/// </summary>
			/// <typeparam name="T">The type of the structures to retrieve.</typeparam>
			/// <param name="count">The number of structures to retrieve.</param>
			/// <param name="prefixBytes">The number of bytes to skip before reading the structures.</param>
			/// <returns>An array of structures of <typeparamref name="T"/>.</returns>
			public T[] ToArray<T>(int count, int prefixBytes = 0)
			{
				if (IsInvalid) return null;
				//if (Size < Marshal.SizeOf(typeof(T)) * count + prefixBytes)
				//	throw new InsufficientMemoryException("Requested array is larger than the memory allocated.");
				if (!typeof(T).IsBlittable()) throw new ArgumentException(@"Structure layout is not sequential or explicit.");
				return handle.ToArray<T>(count, prefixBytes);
			}

			/// <summary>
			/// Marshals data from this block of memory to a newly allocated managed object of the type specified by a generic type parameter.
			/// </summary>
			/// <typeparam name="T">The type of the object to which the data is to be copied. This must be a structure.</typeparam>
			/// <returns>A managed object that contains the data that this <see cref="SafeMemoryHandleExt{T}"/> holds.</returns>
			public T ToStructure<T>()
			{
				if (IsInvalid) return default;
				return handle.ToStructure<T>();
			}

			/// <inheritdoc/>
			protected override bool InternalReleaseHandle() => FreeContextBuffer(handle).Succeeded;
		}

		/// <summary>Provides a safe version of <see cref="CredHandle"/> that is disposed using <see cref="FreeCredentialsHandle"/>.</summary>
		[StructLayout(LayoutKind.Sequential)]
		public sealed class SafeCredHandle : IDisposable
		{
			private CredHandle handle;

			/// <summary>Initializes a new instance of the <see cref="SafeCredHandle"/> class and assigns an existing handle.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			public SafeCredHandle(CredHandle preexistingHandle) => handle = preexistingHandle;

			/// <summary>Initializes a new instance of the <see cref="SafeCredHandle"/> class.</summary>
			private SafeCredHandle() { }

			/// <summary>Performs an implicit conversion from <see cref="SafeCredHandle"/> to <see cref="CredHandle"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator CredHandle(SafeCredHandle h) => h.handle;

			/// <summary>Performs an implicit conversion from <see cref="SafeCredHandle"/> to <see cref="CredHandle"/>.</summary>
			/// <param name="h">The safe handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static unsafe implicit operator CredHandle* (SafeCredHandle h)
			{
				fixed (CredHandle* hp = &h.handle)
					return hp;
			}

			/// <summary>Get a NULL reference to CredHandle.</summary>
			public readonly static SafeCredHandle Null = new SafeCredHandle(CredHandle.Null);

			/// <summary>
			/// <para>
			/// The <c>AcquireCredentialsHandle (CredSSP)</c> function acquires a handle to preexisting credentials of a security principal.
			/// This handle is required by the InitializeSecurityContext (CredSSP) and AcceptSecurityContext (CredSSP) functions. These can
			/// be either preexisting credentials, which are established through a system logon that is not described here, or the caller
			/// can provide alternative credentials.
			/// </para>
			/// <note type="note">This is not a "log on to the network" and does not imply gathering of credentials.</note>
			/// </summary>
			/// <param name="pszPackage">
			/// A string that specifies the name of the security package with which these credentials will be used. This is a security
			/// package name returned in the <c>Name</c> member of a SecPkgInfo structure returned by the EnumerateSecurityPackages
			/// function. After a context is established, QueryContextAttributes (CredSSP) can be called with ulAttribute set to
			/// <c>SECPKG_ATTR_PACKAGE_INFO</c> to return information on the security package in use.
			/// </param>
			/// <param name="fCredentialUse">A flag that indicates how these credentials will be used.</param>
			/// <returns>On success, this function returns a credential handle.</returns>
			/// <remarks>
			/// <para>
			/// The <c>AcquireCredentialsHandle (CredSSP)</c> function returns a handle to the credentials of a principal, such as a user or
			/// client, as used by a specific security package. The function can return the handle to either preexisting credentials or
			/// newly created credentials and return it. This handle can be used in subsequent calls to the AcceptSecurityContext (CredSSP)
			/// and InitializeSecurityContext (CredSSP) functions.
			/// </para>
			/// <para>
			/// In general, <c>AcquireCredentialsHandle (CredSSP)</c> does not provide the credentials of other users logged on to the same
			/// computer. However, a caller with SE_TCB_NAME privilege can obtain the credentials of an existing logon session by specifying
			/// the logon identifier (LUID) of that session. Typically, this is used by kernel-mode modules that must act on behalf of a
			/// logged-on user.
			/// </para>
			/// </remarks>
			public static SafeCredHandle Acquire(string pszPackage, SECPKG_CRED fCredentialUse) => Acquire<int>(pszPackage, fCredentialUse, null, null, null, out _);

			/// <summary>
			/// <para>
			/// The <c>AcquireCredentialsHandle (CredSSP)</c> function acquires a handle to preexisting credentials of a security principal. This
			/// handle is required by the InitializeSecurityContext (CredSSP) and AcceptSecurityContext (CredSSP) functions. These can be either
			/// preexisting credentials, which are established through a system logon that is not described here, or the caller can provide
			/// alternative credentials.
			/// </para>
			/// <para>
			///   <c>Note</c> This is not a "log on to the network" and does not imply gathering of credentials.</para>
			/// </summary>
			/// <typeparam name="TAuthData">The type of the authentication data structure.</typeparam>
			/// <param name="pszPackage">A string that specifies the name of the security package with which these credentials will be used.
			/// This is a security package name returned in the <c>Name</c> member of a SecPkgInfo structure returned by the
			/// EnumerateSecurityPackages function. After a context is established, QueryContextAttributes (CredSSP) can be called with
			/// ulAttribute set to <c>SECPKG_ATTR_PACKAGE_INFO</c> to return information on the security package in use.</param>
			/// <param name="fCredentialUse">A flag that indicates how these credentials will be used.</param>
			/// <param name="pAuthData">The optional authentication data structure.</param>
			/// <returns>
			/// On success, this function returns a credential handle.
			/// </returns>
			/// <remarks>
			/// <para>
			/// The <c>AcquireCredentialsHandle (CredSSP)</c> function returns a handle to the credentials of a principal, such as a user or
			/// client, as used by a specific security package. The function can return the handle to either preexisting credentials or newly
			/// created credentials and return it. This handle can be used in subsequent calls to the AcceptSecurityContext (CredSSP) and
			/// InitializeSecurityContext (CredSSP) functions.
			/// </para>
			/// <para>
			/// In general, <c>AcquireCredentialsHandle (CredSSP)</c> does not provide the credentials of other users logged on to the same
			/// computer. However, a caller with SE_TCB_NAME privilege can obtain the credentials of an existing logon session by specifying the
			/// logon identifier (LUID) of that session. Typically, this is used by kernel-mode modules that must act on behalf of a logged-on user.
			/// </para>
			/// </remarks>
			public static SafeCredHandle Acquire<TAuthData>(string pszPackage, SECPKG_CRED fCredentialUse, TAuthData? pAuthData) where TAuthData : struct =>
				Acquire(pszPackage, fCredentialUse, pAuthData, null, null, out _);

			/// <summary>
			/// <para>
			/// The <c>AcquireCredentialsHandle (CredSSP)</c> function acquires a handle to preexisting credentials of a security principal. This
			/// handle is required by the InitializeSecurityContext (CredSSP) and AcceptSecurityContext (CredSSP) functions. These can be either
			/// preexisting credentials, which are established through a system logon that is not described here, or the caller can provide
			/// alternative credentials.
			/// </para>
			/// <para>
			///   <c>Note</c> This is not a "log on to the network" and does not imply gathering of credentials.</para>
			/// </summary>
			/// <typeparam name="TAuthData">The type of the authentication data.</typeparam>
			/// <param name="pszPackage">A string that specifies the name of the security package with which these credentials will be used.
			/// This is a security package name returned in the <c>Name</c> member of a SecPkgInfo structure returned by the
			/// EnumerateSecurityPackages function. After a context is established, QueryContextAttributes (CredSSP) can be called with
			/// ulAttribute set to <c>SECPKG_ATTR_PACKAGE_INFO</c> to return information on the security package in use.</param>
			/// <param name="fCredentialUse">A flag that indicates how these credentials will be used.</param>
			/// <param name="pAuthData">An optional structure that specifies authentication data. The structure allowed depends on the type of protocol.</param>
			/// <param name="pszPrincipal"><para>An optional string that specifies the name of the principal whose credentials the handle will reference.</para>
			/// <para>
			///   <c>Note</c> If the process that requests the handle does not have access to the credentials, the function returns an error. A
			/// null string indicates that the process requires a handle to the credentials of the user under whose security context it is executing.
			/// </para></param>
			/// <param name="pvLogonId">A locally unique identifier (LUID) that identifies the user. This parameter is provided for file-system processes
			/// such as network redirectors. This parameter can be <c>NULL</c>.</param>
			/// <param name="ptsExpiry">A TimeStamp structure that receives the time at which the returned credentials expire. The structure value received
			/// depends on the security package, which must specify the value in local time.</param>
			/// <returns>On success, this function returns a credential handle.</returns>
			/// <remarks>
			/// <para>
			/// The <c>AcquireCredentialsHandle (CredSSP)</c> function returns a handle to the credentials of a principal, such as a user or
			/// client, as used by a specific security package. The function can return the handle to either preexisting credentials or newly
			/// created credentials and return it. This handle can be used in subsequent calls to the AcceptSecurityContext (CredSSP) and
			/// InitializeSecurityContext (CredSSP) functions.
			/// </para>
			/// <para>
			/// In general, <c>AcquireCredentialsHandle (CredSSP)</c> does not provide the credentials of other users logged on to the same
			/// computer. However, a caller with SE_TCB_NAME privilege can obtain the credentials of an existing logon session by specifying the
			/// logon identifier (LUID) of that session. Typically, this is used by kernel-mode modules that must act on behalf of a logged-on user.
			/// </para>
			/// </remarks>
			public static SafeCredHandle Acquire<TAuthData>(string pszPackage, SECPKG_CRED fCredentialUse, TAuthData? pAuthData, string pszPrincipal,
				LUID? pvLogonId, out TimeStamp ptsExpiry) where TAuthData : struct
			{
				using (var pinnedLuid = new PinnedObject(pvLogonId))
				using (var pinnedAuthData = pAuthData.HasValue ? SafeHGlobalHandle.CreateFromStructure(pAuthData) : SafeHGlobalHandle.Null)
				{
					AcquireCredentialsHandle(pszPrincipal, pszPackage, fCredentialUse, pinnedLuid, (IntPtr)pinnedAuthData, IntPtr.Zero, IntPtr.Zero, out var hCred, out ptsExpiry).ThrowIfFailed();
					return new SafeCredHandle(hCred);
				}
			}

			/// <summary>
			/// Get a dangerous reference to the underlying CredHandle. This value is mutable and may be invalid after this
			/// <see cref="SafeCredHandle"/> instance is disposed.
			/// </summary>
			public CredHandle DangerousGetHandle() => handle;

			void IDisposable.Dispose()
			{
				if (handle.IsInvalid || handle.IsNull) return;
				FreeCredentialsHandle(ref handle);
				handle = CredHandle.Null;
			}
		}

		/// <summary>Provides a safe version of <see cref="CtxtHandle"/> that is disposed using <see cref="DeleteSecurityContext"/>.</summary>
		[StructLayout(LayoutKind.Sequential)]
		public sealed class SafeCtxtHandle : IDisposable
		{
			private CtxtHandle handle;

			/// <summary>Initializes a new instance of the <see cref="SafeCtxtHandle"/> class.</summary>
			public SafeCtxtHandle() => handle = CtxtHandle.Null;

			/// <summary>Initializes a new instance of the <see cref="SafeCtxtHandle"/> class and assigns an existing handle.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			public SafeCtxtHandle(CtxtHandle preexistingHandle) => handle = preexistingHandle;

			/// <summary>Performs an implicit conversion from <see cref="SafeCtxtHandle"/> to <see cref="CtxtHandle"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator CtxtHandle(SafeCtxtHandle h) => h.handle;

			/// <summary>Performs an implicit conversion from <see cref="SafeCtxtHandle"/> to <see cref="CtxtHandle"/>.</summary>
			/// <param name="h">The safe handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static unsafe implicit operator CtxtHandle* (SafeCtxtHandle h)
			{
				if (h.handle.IsNull)
					return null;
				fixed (CtxtHandle* hp = &h.handle)
					return hp;
			}

			/// <summary>Get a NULL reference to CredHandle.</summary>
			public readonly static SafeCtxtHandle Null = new SafeCtxtHandle(CtxtHandle.Null);

			/// <summary>
			/// Get a dangerous reference to the underlying CtxtHandle. This value is mutable and may be invalid after this
			/// <see cref="SafeCtxtHandle"/> instance is disposed.
			/// </summary>
			public CtxtHandle DangerousGetHandle() => handle;

			void IDisposable.Dispose()
			{
				if (!handle.IsInvalid && !handle.IsNull) DeleteSecurityContext(handle);
			}

			internal void SetHandle(CtxtHandle h)
			{
				if (handle.IsNull) handle = h; else throw new InvalidOperationException();
			}
		}

		/// <summary>Provides a <see cref="SafeHandle"/> for <see cref="PSEC_WINNT_AUTH_IDENTITY_OPAQUE"/> that is disposed using <see cref="SspiFreeAuthIdentity"/>.</summary>
		public class SafePSEC_WINNT_AUTH_IDENTITY_OPAQUE : SafeHANDLE
		{
			/// <summary>
			/// Represents a null instance.
			/// </summary>
			public static readonly SafePSEC_WINNT_AUTH_IDENTITY_OPAQUE Null = new SafePSEC_WINNT_AUTH_IDENTITY_OPAQUE();

			/// <summary>
			/// Initializes a new instance of the <see cref="SafePSEC_WINNT_AUTH_IDENTITY_OPAQUE"/> class and assigns an existing handle.
			/// </summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			/// <param name="ownsHandle">
			/// <see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).
			/// </param>
			public SafePSEC_WINNT_AUTH_IDENTITY_OPAQUE(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

			/// <summary>Initializes a new instance of the <see cref="SafePSEC_WINNT_AUTH_IDENTITY_OPAQUE"/> class.</summary>
			private SafePSEC_WINNT_AUTH_IDENTITY_OPAQUE() : base() { }

			/// <summary>Performs an implicit conversion from <see cref="SafePSEC_WINNT_AUTH_IDENTITY_OPAQUE"/> to <see cref="PSEC_WINNT_AUTH_IDENTITY_OPAQUE"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator PSEC_WINNT_AUTH_IDENTITY_OPAQUE(SafePSEC_WINNT_AUTH_IDENTITY_OPAQUE h) => h.handle;

			/// <inheritdoc/>
			protected override bool InternalReleaseHandle() { SspiZeroAuthIdentity(handle); SspiFreeAuthIdentity(handle); return true; }
		}

		/// <summary>
		/// The <c>SafeSecBufferDesc</c> structure describes an array of SecBuffer structures to pass from a transport application to a
		/// security package. It handles cleaning up allocated memory.
		/// </summary>
		/// <remarks>
		/// This is a drop in replacement for anywhere a "SecBufferDesc*" or "ref SecBufferDesc" is required. This class will free all 
		/// allocated memory and will also free any memory created by Sspi methods that require a call to <see cref="FreeContextBuffer"/>.
		/// <para>Sample code:</para><code>using (var edesc = new SafeSecBufferDesc())
		/// {
		///   edesc.Add(SecBufferType.SECBUFFER_TOKEN); // Add SecBuffer with type, but no values
		///   edesc.Add(SecBufferType.SECBUFFER_EMPTY); // Add SecBuffer with empty type
		///   edesc.Add(SecBufferType.SECBUFFER_DATA, msgStruct); // Add SecBuffer with type set and buffer filled with value of 'msgStruct'
		///   edesc.Add(blockSize, SecBufferType.SECBUFFER_PADDING); // Add SecBuffer with type and allocated memory of size 'blockSize'
		///
		///   // Call method with ref
		///   EncryptMessage(hCtx, 0, ref edesc.GetRef(), 0); // Use GetRef() method to get a reference to the internal SecBufferDesc structure
		///
		///   // Call method with *
		///   unsafe
		///   {
		///      AcceptSecurityContext(hCred, hCtxt2, edesc, ...); // An implicit operator will cast to a SecBufferDesc*
		///   }
		/// }</code></remarks>
		[PInvokeData("sspi.h", MSDNShortId = "fc6ef09c-3ba9-4bcb-a3c2-07422af8eaa9")]
		public class SafeSecBufferDesc : SafeNativeArrayBase<SecBuffer, HGlobalMemoryMethods>
		{
			private static readonly uint HdrSize = (uint)Marshal.SizeOf(typeof(SecBufferDesc));

			private readonly List<SafeAllocatedMemoryHandle> items = new List<SafeAllocatedMemoryHandle>();
			private SecBufferDesc desc = SecBufferDesc.Default;

			/// <summary>Initializes a new instance of the <see cref="SafeSecBufferDesc"/> class.</summary>
			public SafeSecBufferDesc() : base(null, HdrSize) { }

			/// <summary>Initializes a new instance of the <see cref="SafeSecBufferDesc"/> class.</summary>
			public SafeSecBufferDesc(SecBufferType type) : base(new[] { new SecBuffer(type) }, HdrSize) { }

			/// <summary>Performs an implicit conversion from <see cref="SafeSecBufferDesc"/> to <see cref="SecBufferDesc"/>.</summary>
			/// <param name="sbd">The <see cref="SafeSecBufferDesc"/> instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static unsafe implicit operator SecBufferDesc* (SafeSecBufferDesc sbd) => (SecBufferDesc*)sbd.handle;

			/// <summary>Performs an implicit conversion from <see cref="SafeSecBufferDesc"/> to <see cref="SecBufferDesc"/>.</summary>
			/// <param name="sbd">The <see cref="SafeSecBufferDesc"/> instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator SecBufferDesc? (SafeSecBufferDesc sbd) => (SecBufferDesc)sbd.handle.ToNullableStructure<SecBufferDesc>();

			/// <summary>Adds the specified type with an empty value as a new SecBuffer item.</summary>
			/// <param name="type">The type of the SecBuffer.</param>
			public virtual void Add(SecBufferType type) => Add(new SecBuffer(type));

			/// <summary>Adds the specified type and value as a new SecBuffer item.</summary>
			/// <typeparam name="T">The type of the value to add</typeparam>
			/// <param name="type">The type of the SecBuffer.</param>
			/// <param name="value">The value to add.</param>
			public virtual void Add<T>(SecBufferType type, T value = default) where T : struct
			{
				var mem = SafeHGlobalHandle.CreateFromStructure(value);
				items.Add(mem);
				Add(new SecBuffer(type, (IntPtr)mem, mem.Size));
			}

			/// <summary>Adds the specified type and value as a new SecBuffer item.</summary>
			/// <typeparam name="T">The type of the element to add</typeparam>
			/// <param name="type">The type of the SecBuffer.</param>
			/// <param name="value">The list to add.</param>
			public virtual void Add<T>(SecBufferType type, IEnumerable<T> value) where T : struct
			{
				var mem = SafeHGlobalHandle.CreateFromList(value);
				items.Add(mem);
				Add(new SecBuffer(type, (IntPtr)mem, mem.Size));
			}

			/// <summary>Adds the specified type and value as a new SecBuffer item.</summary>
			/// <param name="type">The type of the SecBuffer.</param>
			/// <param name="value">The list to add.</param>
			public virtual void Add(SecBufferType type, string value)
			{
				var mem = new SafeHGlobalHandle(value);
				items.Add(mem);
				Add(new SecBuffer(type, (IntPtr)mem, mem.Size));
			}

			/// <summary>Adds the specified type with an allocated buffer of the specified size as a new SecBuffer item.</summary>
			/// <param name="bufferSize">Size of the buffer.</param>
			/// <param name="type">The type of the SecBuffer.</param>
			public virtual void Add(int bufferSize, SecBufferType type)
			{
				var mem = new SafeHGlobalHandle(bufferSize);
				items.Add(mem);
				Add(new SecBuffer(type, (IntPtr)mem, mem.Size));
			}

			/// <summary>Performs an implicit conversion from <see cref="SafeSecBufferDesc"/> to <see cref="SecBufferDesc"/>.</summary>
			/// <returns>A reference to a <see cref="SecBufferDesc"/> struct.</returns>
			public ref SecBufferDesc GetRef() => ref desc;

			/// <inheritdoc/>
			protected override void OnCountChanged() => OnUpdateHeader();

			/// <inheritdoc/>
			protected override void OnUpdateHeader()
			{
				desc.cBuffers = (uint)Count;
				desc.pBuffers = handle.Offset((int)HdrSize);
				Marshal.StructureToPtr(desc, handle, false);
			}

			/// <inheritdoc/>
			protected override bool ReleaseHandle()
			{
				var hash = new HashSet<IntPtr>(items.Select(i => i.DangerousGetHandle()));
				foreach (var buf in this.Where(b => !hash.Contains(b.pvBuffer)))
					FreeContextBuffer(buf.pvBuffer);
				Clear();
				foreach (var i in items)
					i.Dispose();
				items.Clear();
				desc = SecBufferDesc.Default;
				return base.ReleaseHandle();
			}
		}

		/// <summary>Provides a <see cref="SafeHandle"/> for Sspi allocated memory that is disposed using <see cref="SspiLocalFree"/>.</summary>
		public class SafeSspiLocalMem : SafeHANDLE
		{
			/// <summary>Initializes a new instance of the <see cref="SafeSspiLocalMem"/> class and assigns an existing handle.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			/// <param name="ownsHandle"><see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).</param>
			public SafeSspiLocalMem(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

			/// <summary>Initializes a new instance of the <see cref="SafeSspiLocalMem"/> class.</summary>
			private SafeSspiLocalMem() : base() { }

			/// <summary>Gets the bytes associated with this memory.</summary>
			/// <param name="count">The count of bytes to get.</param>
			/// <returns>A byte array.</returns>
			public byte[] GetBytes(uint count) => handle.ToArray<byte>((int)count);

			/// <inheritdoc/>
			protected override bool InternalReleaseHandle() { SspiLocalFree(handle); return true; }
		}

		internal class SspiStringMarshaler : ICustomMarshaler
		{
			public static ICustomMarshaler GetInstance(string _) => new SspiStringMarshaler();

			public void CleanUpManagedData(object ManagedObj)
			{
			}

			public void CleanUpNativeData(IntPtr pNativeData)
			{
				if (pNativeData == IntPtr.Zero) return;
				SspiFreeAuthIdentity(pNativeData);
			}

			public int GetNativeDataSize() => -1;

			public IntPtr MarshalManagedToNative(object _) => IntPtr.Zero;

			public object MarshalNativeToManaged(IntPtr pNativeData)
			{
				var ret = StringHelper.GetString(pNativeData, CharSet.Unicode);
				System.Diagnostics.Debug.WriteLine($"SspiStringMarshaler: {ret ?? "null"}");
				return ret.Clone();
			}
		}
	}
}