1

我有一个使用服务器证书的 WCF 服务。该证书由我们的内部证书颁发机构签署。根证书是自签名的,并通过AD分发给所有域计算机。我们已经构建并部署了许多附加到该服务的程序(大约 200 台 PC 上的大约 50 个应用程序),它们都按预期工作,除了一台服务器(我将其称为 BROKENHOST)。在这个特定的服务器(Windows Server 2003 标准服务器)上,每当程序尝试连接到该服务时,它都会抛出一个 SecurityNegotiationExeption,特别是(更改名称以保护公司):

System.ServiceModel.Security.SecurityNegotiationException:X.509 证书 CN=server.sub.domain.com、OU=sub、O=domain.com、L=Somewhere、S=California、C=US 链构建失败。使用的证书具有无法验证的信任链。更换证书或更改 certificateValidationMode。由于吊销服务器处于脱机状态,吊销功能无法检查吊销。
---> System.IdentityModel.Tokens.SecurityTokenValidationException: X.509 证书 CN=server.sub.domain.com, OU=sub, O=domain.com, L=Somewhere, S=California, C=US chain building失败的。使用的证书具有无法验证的信任链。更换证书或更改 certificateValidationMode。由于吊销服务器处于脱机状态,吊销功能无法检查吊销。

WCF 服务使用的证书也被 IIS 使用。这里奇怪的是,如果我在 BROKENHOST 上打开 IE 并输入https://server.sub.domain.com,页面打开就好了,证书链显示OK. 所以,我不确定为什么 IE 对证书很好,但是 Windows 应用程序失败了。

客户端连接本身是通过这样的通道工厂创建的:

System.ServiceModel.Channels.AddressHeader[] addressHeader = new System.ServiceModel.Channels.AddressHeader[] {
            System.ServiceModel.Channels.AddressHeader.CreateAddressHeader("CUSTOM_USER_ID", "CUSTOM", m_user_id),
            System.ServiceModel.Channels.AddressHeader.CreateAddressHeader("CUSTOM_SOURCE_NAME", "CUSTOM", m_source_name)
};

string strUri = string.Format("net.tcp://{0}:{1}/{2}", m_strServer[strRegKey], m_strPort[strRegKey], strAddress);
System.ServiceModel.EndpointAddress epa = new System.ServiceModel.EndpointAddress(new Uri(strUri), EndpointIdentity.CreateDnsIdentity(m_strServer[strRegKey]), addressHeader);

NetTcpBinding binding = new NetTcpBinding();
binding.OpenTimeout = TimeSpan.FromSeconds(15);
//binding.OpenTimeout = TimeSpan.FromTicks(1);
binding.ReaderQuotas.MaxArrayLength = Int32.MaxValue; // ChunkSizeSingleton.DOWNLOAD_CHUNK_MAX_SIZE;
binding.ReaderQuotas.MaxBytesPerRead = Int32.MaxValue;
binding.ReaderQuotas.MaxDepth = Int32.MaxValue;
binding.ReaderQuotas.MaxNameTableCharCount = Int32.MaxValue;
binding.ReaderQuotas.MaxStringContentLength = Int32.MaxValue;
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
binding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.ReliableSession.Enabled = true;
binding.ReliableSession.Ordered = true;
binding.ReliableSession.InactivityTimeout = TimeSpan.FromMinutes(10);

binding.MaxReceivedMessageSize = Int32.MaxValue; // (long)(ChunkSizeSingleton.DOWNLOAD_CHUNK_MAX_SIZE * 1.3);

ChannelFactory<T> channelFactory = new ChannelFactory<T>(binding, epa);

channelFactory.Credentials.UserName.UserName = m_user_name;
channelFactory.Credentials.UserName.Password = m_user_password;
channelFactory.Credentials.SupportInteractive = false;

foreach (OperationDescription od in channelFactory.Endpoint.Contract.Operations)
{
    DataContractSerializerOperationBehavior ser = od.Behaviors.Find<DataContractSerializerOperationBehavior>();

    ser.MaxItemsInObjectGraph = Int32.MaxValue;
}

同样,我们确信服务器设置是正确的,并且 BROKENHOST 存在问题。我试过用远程调试器运行代码,但这并没有给我任何我们不知道的东西。

如果有人有任何其他建议让我尝试,请告诉我。

PS如果有帮助,这里是堆栈跟踪:

at System.IdentityModel.Selectors.X509CertificateChain.Build(X509Certificate2 certificate)
at System.IdentityModel.Selectors.X509CertificateValidator.ChainTrustValidator.Validate(X509Certificate2 certificate)
at System.IdentityModel.Selectors.X509SecurityTokenAuthenticator.ValidateTokenCore(SecurityToken token)
at System.IdentityModel.Selectors.SecurityTokenAuthenticator.ValidateToken(SecurityToken token)
at System.ServiceModel.Channels.SslStreamSecurityUpgradeInitiator.ValidateRemoteCertificate(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
at System.Net.Security.SslStream.userCertValidationCallbackWrapper(String hostName, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
at System.Net.Security.SecureChannel.VerifyRemoteCertificate(RemoteCertValidationCallback remoteCertValidationCallback)
at System.Net.Security.SslState.CompleteHandshake()
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.Security.SslStream.AuthenticateAsClient(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation)
at System.ServiceModel.Channels.SslStreamSecurityUpgradeInitiator.OnInitiateUpgrade(Stream stream, SecurityMessageProperty& remoteSecurity)
   --- End of inner exception stack trace ---
服务器堆栈跟踪:
at System.ServiceModel.Channels.SslStreamSecurityUpgradeInitiator.OnInitiateUpgrade(Stream stream, SecurityMessageProperty& remoteSecurity)
at System.ServiceModel.Channels.StreamSecurityUpgradeInitiatorBase.InitiateUpgrade(Stream stream)
at System.ServiceModel.Channels.ConnectionUpgradeHelper.InitiateUpgrade(StreamUpgradeInitiator upgradeInitiator, IConnection& connection, ClientFramingDecoder decoder, IDefaultCommunicationTimeouts defaultTimeouts, TimeoutHelper& timeoutHelper)
at System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.SendPreamble(IConnection connection, ArraySegment`1 preamble, TimeoutHelper& timeoutHelper)
at System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.DuplexConnectionPoolHelper.AcceptPooledConnection(IConnection connection, TimeoutHelper& timeoutHelper)
at System.ServiceModel.Channels.ConnectionPoolHelper.EstablishConnection(TimeSpan timeout)
at System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
在 [0] 处重新抛出异常:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at System.ServiceModel.ICommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.SecurityChannelFactory`1.ClientSecurityChannel`1.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.DoOperation(SecuritySessionOperation operation, EndpointAddress target, Uri via, SecurityToken currentToken, TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.GetTokenCore(TimeSpan timeout)
at System.IdentityModel.Selectors.SecurityTokenProvider.GetToken(TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionClientSettings`1.ClientSecuritySessionChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.ReliableChannelBinder`1.ChannelSynchronizer.SyncWaiter.TryGetChannel()
at System.ServiceModel.Channels.ReliableChannelBinder`1.ChannelSynchronizer.SyncWaiter.TryWait(TChannel& channel)
at System.ServiceModel.Channels.ReliableChannelBinder`1.ChannelSynchronizer.TryGetChannel(Boolean canGetChannel, Boolean canCauseFault, TimeSpan timeout, MaskingMode maskingMode, TChannel& channel)
at System.ServiceModel.Channels.ReliableChannelBinder`1.Send(Message message, TimeSpan timeout, MaskingMode maskingMode)
at System.ServiceModel.Channels.SendReceiveReliableRequestor.OnRequest(Message request, TimeSpan timeout, Boolean last)
at System.ServiceModel.Channels.ReliableRequestor.Request(TimeSpan timeout)
at System.ServiceModel.Channels.ClientReliableSession.Open(TimeSpan timeout)
at System.ServiceModel.Channels.ClientReliableDuplexSessionChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open()
4

0 回答 0