public byte[] GetOutgoingBlob(byte[] incomingBlob, ChannelBinding channelbinding, ExtendedProtectionPolicy protectionPolicy) { ThrowIfDisposed(); int statusCode = 0; // use the confidentiality option to ensure we can encrypt messages SspiContextFlags requestedFlags = SspiContextFlags.Confidentiality | SspiContextFlags.ReplayDetect | SspiContextFlags.SequenceDetect; if (this.doMutualAuth) { requestedFlags |= SspiContextFlags.MutualAuth; } if (this.impersonationLevel == TokenImpersonationLevel.Delegation) { requestedFlags |= SspiContextFlags.Delegate; } else if (this.isServer == false && this.impersonationLevel == TokenImpersonationLevel.Identification) { requestedFlags |= SspiContextFlags.InitIdentify; } else if (this.isServer == false && this.impersonationLevel == TokenImpersonationLevel.Anonymous) { requestedFlags |= SspiContextFlags.InitAnonymous; } ExtendedProtectionPolicyHelper policyHelper = new ExtendedProtectionPolicyHelper(channelbinding, protectionPolicy); if (isServer) { if (policyHelper.PolicyEnforcement == PolicyEnforcement.Always && policyHelper.ChannelBinding == null && policyHelper.ProtectionScenario != ProtectionScenario.TrustedProxy) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SecurityChannelBindingMissing))); } if (policyHelper.PolicyEnforcement == PolicyEnforcement.WhenSupported) { requestedFlags |= SspiContextFlags.ChannelBindingAllowMissingBindings; } if (policyHelper.ProtectionScenario == ProtectionScenario.TrustedProxy) { requestedFlags |= SspiContextFlags.ChannelBindingProxyBindings; } } List<SecurityBuffer> list = new List<SecurityBuffer>(2); if (incomingBlob != null) { list.Add(new SecurityBuffer(incomingBlob, BufferType.Token)); } // when deciding if the channel binding should be added to the security buffer // it is necessary to differentiate between client and server. // Server rules were added to policyHelper as they are shared with Kerb and I want them consistent // Client adds if not null. if (this.isServer) { if (policyHelper.ShouldAddChannelBindingToASC()) { list.Add(new SecurityBuffer(policyHelper.ChannelBinding)); } } else { if (policyHelper.ChannelBinding != null) { list.Add(new SecurityBuffer(policyHelper.ChannelBinding)); } } SecurityBuffer[] inSecurityBuffer = null; if (list.Count > 0) { inSecurityBuffer = list.ToArray(); } SecurityBuffer outSecurityBuffer = new SecurityBuffer(this.tokenSize, BufferType.Token); if (!this.isServer) { //client session statusCode = SspiWrapper.InitializeSecurityContext(this.credentialsHandle, ref this.securityContext, this.servicePrincipalName, requestedFlags, Endianness.Network, inSecurityBuffer, outSecurityBuffer, ref this.contextFlags); } else { // server session //This check is to save an unnecessary ASC call. bool isServerSecurityContextNull = this.securityContext == null; SspiContextFlags serverContextFlags = this.contextFlags; statusCode = SspiWrapper.AcceptSecurityContext(this.credentialsHandle, ref this.securityContext, requestedFlags, Endianness.Network, inSecurityBuffer, outSecurityBuffer, ref this.contextFlags); if (statusCode == (int)SecurityStatus.InvalidToken && !isServerSecurityContextNull) { // Call again into ASC after deleting the Securitycontext. If this securitycontext is not deleted // then when the client sends NTLM blob the service will treat it as Nego2blob and will fail to authenticate the client. this.contextFlags = serverContextFlags; CloseContext(); statusCode = SspiWrapper.AcceptSecurityContext(this.credentialsHandle, ref this.securityContext, requestedFlags, Endianness.Network, inSecurityBuffer, outSecurityBuffer, ref this.contextFlags); } } if (DiagnosticUtility.ShouldTraceInformation) { IMD.SecurityTraceRecordHelper.TraceChannelBindingInformation(policyHelper, this.isServer, channelbinding); } if ((statusCode & unchecked((int)0x80000000)) != 0) { if (!this.isServer && this.interactiveNegoLogonEnabled && SecurityUtils.IsOSGreaterThanOrEqualToWin7() && SspiWrapper.IsSspiPromptingNeeded((uint)statusCode) && SspiWrapper.IsNegotiateExPackagePresent()) { // If we have prompted enough number of times (DefaultMaxPromptAttempts) with wrong credentials, then we do not prompt again and throw. if (MaxPromptAttempts >= DefaultMaxPromptAttempts) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(statusCode, SR.GetString(SR.InvalidClientCredentials))); } IntPtr ppAuthIdentity = IntPtr.Zero; uint errorCode = SspiWrapper.SspiPromptForCredential(this.servicePrincipalName, this.clientPackageName, out ppAuthIdentity, ref this.saveClientCredentialsOnSspiUi); if (errorCode == (uint)CredentialStatus.Success) { IntPtr ppNewAuthIdentity = IntPtr.Zero; if (!this.allowNtlm) { // When Ntlm is explicitly disabled we don't want the collected //creds from the Kerb/NTLM tile to be used for NTLM auth. uint status = UnsafeNativeMethods.SspiExcludePackage(ppAuthIdentity, "NTLM", out ppNewAuthIdentity); } else { ppNewAuthIdentity = ppAuthIdentity; } this.credentialsHandle = SspiWrapper.AcquireCredentialsHandle(this.clientPackageName, CredentialUse.Outbound, ref ppNewAuthIdentity); if (IntPtr.Zero != ppNewAuthIdentity) { UnsafeNativeMethods.SspiFreeAuthIdentity(ppNewAuthIdentity); } CloseContext(); MaxPromptAttempts++; return this.GetOutgoingBlob(null, channelbinding, protectionPolicy); } else { // Call into SspiPromptForCredential had an error. Time to throw. if (IntPtr.Zero != ppAuthIdentity) { UnsafeNativeMethods.SspiFreeAuthIdentity(ppAuthIdentity); } CloseContext(); this.isCompleted = true; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception((int)errorCode, SR.GetString(SR.SspiErrorOrInvalidClientCredentials))); } } CloseContext(); this.isCompleted = true; if (!this.isServer && (statusCode == (int)SecurityStatus.TargetUnknown || statusCode == (int)SecurityStatus.WrongPrincipal)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(statusCode, SR.GetString(SR.IncorrectSpnOrUpnSpecified, this.servicePrincipalName))); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(statusCode, SR.GetString(SR.InvalidSspiNegotiation))); } } if (DiagnosticUtility.ShouldTraceInformation) { if (this.isServer) { SecurityTraceRecordHelper.TraceServiceOutgoingSpnego(this); } else { SecurityTraceRecordHelper.TraceClientOutgoingSpnego(this); } } if (statusCode == (int)SecurityStatus.OK) { // we're done this.isCompleted = true; // These must all be true to check service binding // 1. we are the service (listener) // 2. caller is not anonymous // 3. protocol is not Kerberos // 4. policy is set to check service binding // if (isServer && ((this.contextFlags & SspiContextFlags.AcceptAnonymous) == 0) && (string.Compare(this.ProtocolName, NegotiationInfoClass.Kerberos, StringComparison.OrdinalIgnoreCase) != 0) && policyHelper.ShouldCheckServiceBinding) { // in the server case the servicePrincipalName is the defaultServiceBinding if (DiagnosticUtility.ShouldTraceInformation) { string serviceBindingNameSentByClient; SspiWrapper.QuerySpecifiedTarget(securityContext, out serviceBindingNameSentByClient); IMD.SecurityTraceRecordHelper.TraceServiceNameBindingOnServer( serviceBindingNameSentByClient, this.servicePrincipalName, policyHelper.ServiceNameCollection); } policyHelper.CheckServiceBinding(this.securityContext, this.servicePrincipalName); } } else { // we need to continue } return outSecurityBuffer.token; }
public byte[] GetOutgoingBlob(byte[] incomingBlob, ChannelBinding channelbinding, ExtendedProtectionPolicy protectionPolicy) { this.ThrowIfDisposed(); int error = 0; SspiContextFlags inFlags = SspiContextFlags.Confidentiality | SspiContextFlags.SequenceDetect | SspiContextFlags.ReplayDetect; if (this.doMutualAuth) { inFlags |= SspiContextFlags.MutualAuth; } if (this.impersonationLevel == TokenImpersonationLevel.Delegation) { inFlags |= SspiContextFlags.Delegate; } else if (!this.isServer && (this.impersonationLevel == TokenImpersonationLevel.Identification)) { inFlags |= SspiContextFlags.InitIdentify; } else if (!this.isServer && (this.impersonationLevel == TokenImpersonationLevel.Anonymous)) { inFlags |= SspiContextFlags.InitAnonymous; } ExtendedProtectionPolicyHelper helper = new ExtendedProtectionPolicyHelper(channelbinding, protectionPolicy); if (this.isServer) { if (((helper.PolicyEnforcement == PolicyEnforcement.Always) && (helper.ChannelBinding == null)) && (helper.ProtectionScenario != ProtectionScenario.TrustedProxy)) { throw System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(System.ServiceModel.SR.GetString("SecurityChannelBindingMissing"))); } if (helper.PolicyEnforcement == PolicyEnforcement.WhenSupported) { inFlags |= SspiContextFlags.ChannelBindingAllowMissingBindings; } if (helper.ProtectionScenario == ProtectionScenario.TrustedProxy) { inFlags |= SspiContextFlags.ChannelBindingProxyBindings; } } List<SecurityBuffer> list = new List<SecurityBuffer>(2); if (incomingBlob != null) { list.Add(new SecurityBuffer(incomingBlob, BufferType.Token)); } if (this.isServer) { if (helper.ShouldAddChannelBindingToASC()) { list.Add(new SecurityBuffer(helper.ChannelBinding)); } } else if (helper.ChannelBinding != null) { list.Add(new SecurityBuffer(helper.ChannelBinding)); } SecurityBuffer[] inputBuffers = null; if (list.Count > 0) { inputBuffers = list.ToArray(); } SecurityBuffer outputBuffer = new SecurityBuffer(this.tokenSize, BufferType.Token); if (!this.isServer) { error = SspiWrapper.InitializeSecurityContext(this.credentialsHandle, ref this.securityContext, this.servicePrincipalName, inFlags, Endianness.Network, inputBuffers, outputBuffer, ref this.contextFlags); } else { bool flag = this.securityContext == null; SspiContextFlags contextFlags = this.contextFlags; error = SspiWrapper.AcceptSecurityContext(this.credentialsHandle, ref this.securityContext, inFlags, Endianness.Network, inputBuffers, outputBuffer, ref this.contextFlags); if ((error == -2146893048) && !flag) { this.contextFlags = contextFlags; this.CloseContext(); error = SspiWrapper.AcceptSecurityContext(this.credentialsHandle, ref this.securityContext, inFlags, Endianness.Network, inputBuffers, outputBuffer, ref this.contextFlags); } } if ((error & -2147483648) != 0) { if (((!this.isServer && this.interactiveNegoLogonEnabled) && (System.ServiceModel.Security.SecurityUtils.IsOSGreaterThanOrEqualToWin7() && SspiWrapper.IsSspiPromptingNeeded((uint) error))) && SspiWrapper.IsNegotiateExPackagePresent()) { if (this.MaxPromptAttempts >= 1) { throw System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error, System.ServiceModel.SR.GetString("InvalidClientCredentials"))); } IntPtr zero = IntPtr.Zero; uint num2 = SspiWrapper.SspiPromptForCredential(this.servicePrincipalName, this.clientPackageName, out zero, ref this.saveClientCredentialsOnSspiUi); if (num2 == 0) { IntPtr ppNewAuthIdentity = IntPtr.Zero; if (!this.allowNtlm) { UnsafeNativeMethods.SspiExcludePackage(zero, "NTLM", out ppNewAuthIdentity); } else { ppNewAuthIdentity = zero; } this.credentialsHandle = SspiWrapper.AcquireCredentialsHandle(this.clientPackageName, CredentialUse.Outbound, ref ppNewAuthIdentity); if (IntPtr.Zero != ppNewAuthIdentity) { UnsafeNativeMethods.SspiFreeAuthIdentity(ppNewAuthIdentity); } this.CloseContext(); this.MaxPromptAttempts++; return this.GetOutgoingBlob(null, channelbinding, protectionPolicy); } if (IntPtr.Zero != zero) { UnsafeNativeMethods.SspiFreeAuthIdentity(zero); } this.CloseContext(); this.isCompleted = true; throw System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception((int) num2, System.ServiceModel.SR.GetString("SspiErrorOrInvalidClientCredentials"))); } this.CloseContext(); this.isCompleted = true; if (this.isServer || (((error != -2146893042) && (error != -2146893053)) && (error != -2146893022))) { throw System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error, System.ServiceModel.SR.GetString("InvalidSspiNegotiation"))); } throw System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error, System.ServiceModel.SR.GetString("IncorrectSpnOrUpnSpecified", new object[] { this.servicePrincipalName }))); } if (System.ServiceModel.DiagnosticUtility.ShouldTraceInformation) { if (this.isServer) { SecurityTraceRecordHelper.TraceServiceOutgoingSpnego(this); } else { SecurityTraceRecordHelper.TraceClientOutgoingSpnego(this); } } if (error == 0) { this.isCompleted = true; if ((this.isServer && ((this.contextFlags & SspiContextFlags.AcceptAnonymous) == SspiContextFlags.Zero)) && ((string.Compare(this.ProtocolName, "Kerberos", StringComparison.OrdinalIgnoreCase) != 0) && helper.ShouldCheckServiceBinding)) { helper.CheckServiceBinding(this.securityContext, this.servicePrincipalName); } } return outputBuffer.token; }