private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, ContextFlagsPal requestedContextFlags, ChannelBinding channelBinding) { if (NetEventSource.IsEnabled) { NetEventSource.Enter(this, package, spn, requestedContextFlags); } _tokenSize = NegotiateStreamPal.QueryMaxTokenSize(package); _isServer = isServer; _spn = spn; _securityContext = null; _requestedContextFlags = requestedContextFlags; _package = package; _channelBinding = channelBinding; if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"Peer SPN-> '{_spn}'"); } // // Check if we're using DefaultCredentials. // Debug.Assert(CredentialCache.DefaultCredentials == CredentialCache.DefaultNetworkCredentials); if (credential == CredentialCache.DefaultCredentials) { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, "using DefaultCredentials"); } _credentialsHandle = NegotiateStreamPal.AcquireDefaultCredential(package, _isServer); } else { _credentialsHandle = NegotiateStreamPal.AcquireCredentialsHandle(package, _isServer, credential); } }
/// <summary> /// Generate SSPI context /// </summary> /// <param name="sspiClientContextStatus">SSPI client context status</param> /// <param name="receivedBuff">Receive buffer</param> /// <param name="sendBuff">Send buffer</param> /// <param name="serverName">Service Principal Name buffer</param> public void GenSspiClientContext(SspiClientContextStatus sspiClientContextStatus, byte[] receivedBuff, ref byte[] sendBuff, byte[] serverName) { SafeDeleteContext securityContext = sspiClientContextStatus.SecurityContext; ContextFlagsPal contextFlags = sspiClientContextStatus.ContextFlags; SafeFreeCredentials credentialsHandle = sspiClientContextStatus.CredentialsHandle; string securityPackage = NegotiationInfoClass.Negotiate; if (securityContext == null) { credentialsHandle = NegotiateStreamPal.AcquireDefaultCredential(securityPackage, false); } int tokenSize = NegotiateStreamPal.QueryMaxTokenSize(securityPackage); byte[] resultToken = new byte[tokenSize]; ContextFlagsPal requestedContextFlags = ContextFlagsPal.Connection | ContextFlagsPal.Confidentiality | ContextFlagsPal.Delegate | ContextFlagsPal.MutualAuth; string serverSPN = System.Text.Encoding.UTF8.GetString(serverName); SecurityStatusPal statusCode = NegotiateStreamPal.InitializeSecurityContext( ref credentialsHandle, ref securityContext, serverSPN, requestedContextFlags, receivedBuff, null, ref resultToken, ref contextFlags); if (statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded || statusCode.ErrorCode == SecurityStatusPalErrorCode.CompAndContinue) { statusCode = NegotiateStreamPal.CompleteAuthToken(ref securityContext, resultToken); resultToken = null; } sendBuff = resultToken; if (sendBuff == null) { sendBuff = Array.Empty <byte>(); } sspiClientContextStatus.SecurityContext = securityContext; sspiClientContextStatus.ContextFlags = contextFlags; sspiClientContextStatus.CredentialsHandle = credentialsHandle; if (IsErrorStatus(statusCode.ErrorCode)) { // Could not access Kerberos Ticket. // // SecurityStatusPalErrorCode.InternalError only occurs in Unix and always comes with a GssApiException, // so we don't need to check for a GssApiException here. if (statusCode.ErrorCode == SecurityStatusPalErrorCode.InternalError) { throw new InvalidOperationException(SQLMessage.KerberosTicketMissingError() + "\n" + statusCode); } else { throw new InvalidOperationException(SQLMessage.SSPIGenerateError() + "\n" + statusCode); } } }
/// <summary> /// Generate SSPI context /// </summary> /// <param name="sspiClientContextStatus">SSPI client context status</param> /// <param name="receivedBuff">Receive buffer</param> /// <param name="sendBuff">Send buffer</param> /// <param name="serverName">Service Principal Name buffer</param> /// <returns>SNI error code</returns> internal static void GenSspiClientContext(SspiClientContextStatus sspiClientContextStatus, byte[] receivedBuff, ref byte[] sendBuff, byte[][] serverName) { SafeDeleteContext securityContext = sspiClientContextStatus.SecurityContext; ContextFlagsPal contextFlags = sspiClientContextStatus.ContextFlags; SafeFreeCredentials credentialsHandle = sspiClientContextStatus.CredentialsHandle; string securityPackage = NegotiationInfoClass.Negotiate; if (securityContext == null) { credentialsHandle = NegotiateStreamPal.AcquireDefaultCredential(securityPackage, false); } SecurityBuffer[] inSecurityBufferArray; if (receivedBuff != null) { inSecurityBufferArray = new SecurityBuffer[] { new SecurityBuffer(receivedBuff, SecurityBufferType.SECBUFFER_TOKEN) }; } else { inSecurityBufferArray = Array.Empty <SecurityBuffer>(); } int tokenSize = NegotiateStreamPal.QueryMaxTokenSize(securityPackage); SecurityBuffer outSecurityBuffer = new SecurityBuffer(tokenSize, SecurityBufferType.SECBUFFER_TOKEN); ContextFlagsPal requestedContextFlags = ContextFlagsPal.Connection | ContextFlagsPal.Confidentiality | ContextFlagsPal.Delegate | ContextFlagsPal.MutualAuth; string[] serverSPNs = new string[serverName.Length]; for (int i = 0; i < serverName.Length; i++) { serverSPNs[i] = Encoding.UTF8.GetString(serverName[i]); } SecurityStatusPal statusCode = NegotiateStreamPal.InitializeSecurityContext( credentialsHandle, ref securityContext, serverSPNs, requestedContextFlags, inSecurityBufferArray, outSecurityBuffer, ref contextFlags); if (statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded || statusCode.ErrorCode == SecurityStatusPalErrorCode.CompAndContinue) { inSecurityBufferArray = new SecurityBuffer[] { outSecurityBuffer }; statusCode = NegotiateStreamPal.CompleteAuthToken(ref securityContext, inSecurityBufferArray); outSecurityBuffer.token = null; } sendBuff = outSecurityBuffer.token; if (sendBuff == null) { sendBuff = Array.Empty <byte>(); } sspiClientContextStatus.SecurityContext = securityContext; sspiClientContextStatus.ContextFlags = contextFlags; sspiClientContextStatus.CredentialsHandle = credentialsHandle; if (IsErrorStatus(statusCode.ErrorCode)) { // Could not access Kerberos Ticket. // // SecurityStatusPalErrorCode.InternalError only occurs in Unix and always comes with a GssApiException, // so we don't need to check for a GssApiException here. if (statusCode.ErrorCode == SecurityStatusPalErrorCode.InternalError) { throw new InvalidOperationException(SQLMessage.KerberosTicketMissingError() + "\n" + statusCode); } else { throw new InvalidOperationException(SQLMessage.SSPIGenerateError() + "\n" + statusCode); } } }