WCF SslStreamSecurity DNS 身份检查仅针对 4.6 框架失败
WCF SslStreamSecurity DNS Identity Check failing for just 4.6 framework
我正在为托管在 IIS 中的 Wcf 服务开发一个新的绑定,我以为我的一切正常,但事实证明客户端只在它以 .Net Framework 4.5 为目标时工作,如果我将其更改为目标 4.6 然后在尝试打开连接时出现以下错误:
System.ServiceModel.Security.MessageSecurityException occurred
HResult=-2146233087
Message=The Identity check failed for the outgoing message. The remote endpoint did not provide a domain name system (DNS) claim and therefore did not satisfied DNS identity 'xxx.domain.local'. This may be caused by lack of DNS or CN name in the remote endpoint X.509 certificate's distinguished name.
Source=System.ServiceModel
StackTrace:
at System.ServiceModel.Security.IdentityVerifier.EnsureIdentity(EndpointAddress serviceReference, AuthorizationContext authorizationContext, String errorString)
如果我除了将测试代码中的目标框架改回 4.5 之外什么都不做,那么它工作正常。这让我觉得它可能是 .Net 4.6 中的一个错误,我知道有 Wcf ssl changes made in 4.6
打开第一次机会异常后,我在 System.ServiceModel
中看到内部引发的以下异常
System.ArgumentNullException occurred
HResult=-2147467261
Message=Value cannot be null.
Parameter name: value
ParamName=value
Source=mscorlib
StackTrace:
at System.Enum.TryParseEnum(Type enumType, String value, Boolean ignoreCase, EnumResult& parseResult)
InnerException:
System.ServiceModel.dll!System.ServiceModel.Security.IssuanceTokenProviderBase<System.ServiceModel.Security.Tokens.IssuedSecurityTokenProvider.FederatedTokenProviderState>.DoNegotiation(System.TimeSpan timeout) Unknown System.ServiceModel.dll!System.ServiceModel.Security.IssuanceTokenProviderBase<System.ServiceModel.Security.Tokens.IssuedSecurityTokenProvider.FederatedTokenProviderState>.GetTokenCore(System.TimeSpan timeout) Unknown
System.IdentityModel.dll!System.IdentityModel.Selectors.SecurityTokenProvider.GetToken(System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Security.Tokens.IssuedSecurityTokenProvider.GetTokenCore(System.TimeSpan timeout) Unknown
System.IdentityModel.dll!System.IdentityModel.Selectors.SecurityTokenProvider.GetToken(System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Security.SecurityProtocol.TryGetSupportingTokens(System.ServiceModel.Security.SecurityProtocolFactory factory, System.ServiceModel.EndpointAddress target, System.Uri via, System.ServiceModel.Channels.Message message, System.TimeSpan timeout, bool isBlockingCall, out System.Collections.Generic.IList<System.ServiceModel.Security.SupportingTokenSpecification> supportingTokens) Unknown
System.ServiceModel.dll!System.ServiceModel.Security.TransportSecurityProtocol.SecureOutgoingMessageAtInitiator(ref System.ServiceModel.Channels.Message message, string actor, System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Security.TransportSecurityProtocol.SecureOutgoingMessage(ref System.ServiceModel.Channels.Message message, System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Security.SecurityProtocol.SecureOutgoingMessage(ref System.ServiceModel.Channels.Message message, System.TimeSpan timeout, System.ServiceModel.Security.SecurityProtocolCorrelationState correlationState) Unknown
System.ServiceModel.dll!System.ServiceModel.Channels.SecurityChannelFactory<System.ServiceModel.Channels.IRequestChannel>.SecurityRequestChannel.Request(System.ServiceModel.Channels.Message message, System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Channels.TransactionRequestChannelGeneric<System.ServiceModel.Channels.IRequestChannel>.Request(System.ServiceModel.Channels.Message message, System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Dispatcher.RequestChannelBinder.Request(System.ServiceModel.Channels.Message message, System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannel.Call(string action, bool oneway, System.ServiceModel.Dispatcher.ProxyOperationRuntime operation, object[] ins, object[] outs, System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(System.Runtime.Remoting.Messaging.IMethodCallMessage methodCall, System.ServiceModel.Dispatcher.ProxyOperationRuntime operation) Unknown
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannelProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage message) Unknown
mscorlib.dll!System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(ref System.Runtime.Remoting.Proxies.MessageData msgData, int type) Unknown
正在与之通信的 wcf 服务的目标是 4.6,据我所知,我正在指定 dns 身份,它确实作为 CN= 存在于证书主题中。该绑定是自定义绑定,因此我可以执行联合 net.tcp,客户端在代码中创建所有内容,我不使用 visual studio 中的添加服务引用功能,客户端代码正在创建绑定:
var binding = new CustomBinding(new BindingElement[] {
new TransactionFlowBindingElement(),
security,
new SslStreamSecurityBindingElement(),
new BinaryMessageEncodingBindingElement() {
ReaderQuotas = { MaxDepth = maxReceivedSizeBytes, MaxStringContentLength = maxReceivedSizeBytes, MaxArrayLength = maxReceivedSizeBytes, MaxBytesPerRead = maxReceivedSizeBytes, MaxNameTableCharCount = maxReceivedSizeBytes },
},
new TcpTransportBindingElement {
TransferMode = TransferMode.StreamedResponse,
MaxReceivedMessageSize = maxReceivedSizeBytes,
},
}) {
SendTimeout = sendTimeout,
};
var channelFactory = new ChannelFactory<T>(binding, new EndpointAddress(new Uri(url), EndpointIdentity.CreateDnsIdentity("xxx.domain.local"), new AddressHeader[0]));
这可能是 4.6 框架中导致不同行为的错误吗?接下来的步骤是否只是尝试逐步调试框架代码以尝试找出 4.6 行为不同的原因?
编辑 -
我创建了一个small sample project that demonstrates the error,重现步骤是:
- (使用VS 2015)打开WcfSelfHostedServer解决方案
- 将 IdentityFail.pfx 证书添加到您的本地计算机,使用 mmc 的个人商店
- 运行 WcfSelfHostedServer 项目(可能点击防火墙是允许端口 30000)
- 打开WcfClient解决方案
- 右键项目>属性,注意是针对4.6.1
- 运行项目,会抛出上述异常
- 现在将客户端切换到目标 4.5.2,它将 运行 没有错误
更新-
我发现以下内容似乎相关:
https://support.microsoft.com/en-us/kb/3069494
https://msdn.microsoft.com/en-us/library/mt298998(v=vs.110).aspx
但是在服务器和客户端指定 Tls12 并没有解决问题,即使添加 DontEnableSchUseStrongCrypto=true 标志也不会影响 DNS 身份检查错误,即使它绕过了 Enum.Parse 内部错误was being thrown from this line
我需要查看导致我的问题的 Retargetting Changes in the .NET Framework 4.6.1, as certificate validation logic changed in that release. (change in behavior for X509CertificateClaimSet.FindClaims)
修复正在编辑我的 app.config 添加:
<runtime>
<AppContextSwitchOverrides value="Switch.System.IdentityModel.DisableMultipleDNSEntriesInSANCertificate=true" />
</runtime>
您可以看到 changed code on referencesource, and naturally makecert.exe doesn't appear to support generating certificates with "Subject Alternative Name" fields
布兰登。
看起来如果标志是 'false' 并且证书不包含 SAN 条目,我们不会添加 dns 条目。
您可以在代码中添加一行来修复。
像这样。
AppContext.SetSwitch("Switch.System.IdentityModel.DisableMultipleDNSEntriesInSANCertificate",true);
在服务器上安装 .net 4.7 解决了我的问题。
我正在为托管在 IIS 中的 Wcf 服务开发一个新的绑定,我以为我的一切正常,但事实证明客户端只在它以 .Net Framework 4.5 为目标时工作,如果我将其更改为目标 4.6 然后在尝试打开连接时出现以下错误:
System.ServiceModel.Security.MessageSecurityException occurred
HResult=-2146233087
Message=The Identity check failed for the outgoing message. The remote endpoint did not provide a domain name system (DNS) claim and therefore did not satisfied DNS identity 'xxx.domain.local'. This may be caused by lack of DNS or CN name in the remote endpoint X.509 certificate's distinguished name.
Source=System.ServiceModel
StackTrace:
at System.ServiceModel.Security.IdentityVerifier.EnsureIdentity(EndpointAddress serviceReference, AuthorizationContext authorizationContext, String errorString)
如果我除了将测试代码中的目标框架改回 4.5 之外什么都不做,那么它工作正常。这让我觉得它可能是 .Net 4.6 中的一个错误,我知道有 Wcf ssl changes made in 4.6
打开第一次机会异常后,我在 System.ServiceModel
中看到内部引发的以下异常System.ArgumentNullException occurred
HResult=-2147467261
Message=Value cannot be null.
Parameter name: value
ParamName=value
Source=mscorlib
StackTrace:
at System.Enum.TryParseEnum(Type enumType, String value, Boolean ignoreCase, EnumResult& parseResult)
InnerException:
System.ServiceModel.dll!System.ServiceModel.Security.IssuanceTokenProviderBase<System.ServiceModel.Security.Tokens.IssuedSecurityTokenProvider.FederatedTokenProviderState>.DoNegotiation(System.TimeSpan timeout) Unknown System.ServiceModel.dll!System.ServiceModel.Security.IssuanceTokenProviderBase<System.ServiceModel.Security.Tokens.IssuedSecurityTokenProvider.FederatedTokenProviderState>.GetTokenCore(System.TimeSpan timeout) Unknown
System.IdentityModel.dll!System.IdentityModel.Selectors.SecurityTokenProvider.GetToken(System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Security.Tokens.IssuedSecurityTokenProvider.GetTokenCore(System.TimeSpan timeout) Unknown
System.IdentityModel.dll!System.IdentityModel.Selectors.SecurityTokenProvider.GetToken(System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Security.SecurityProtocol.TryGetSupportingTokens(System.ServiceModel.Security.SecurityProtocolFactory factory, System.ServiceModel.EndpointAddress target, System.Uri via, System.ServiceModel.Channels.Message message, System.TimeSpan timeout, bool isBlockingCall, out System.Collections.Generic.IList<System.ServiceModel.Security.SupportingTokenSpecification> supportingTokens) Unknown
System.ServiceModel.dll!System.ServiceModel.Security.TransportSecurityProtocol.SecureOutgoingMessageAtInitiator(ref System.ServiceModel.Channels.Message message, string actor, System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Security.TransportSecurityProtocol.SecureOutgoingMessage(ref System.ServiceModel.Channels.Message message, System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Security.SecurityProtocol.SecureOutgoingMessage(ref System.ServiceModel.Channels.Message message, System.TimeSpan timeout, System.ServiceModel.Security.SecurityProtocolCorrelationState correlationState) Unknown
System.ServiceModel.dll!System.ServiceModel.Channels.SecurityChannelFactory<System.ServiceModel.Channels.IRequestChannel>.SecurityRequestChannel.Request(System.ServiceModel.Channels.Message message, System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Channels.TransactionRequestChannelGeneric<System.ServiceModel.Channels.IRequestChannel>.Request(System.ServiceModel.Channels.Message message, System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Dispatcher.RequestChannelBinder.Request(System.ServiceModel.Channels.Message message, System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannel.Call(string action, bool oneway, System.ServiceModel.Dispatcher.ProxyOperationRuntime operation, object[] ins, object[] outs, System.TimeSpan timeout) Unknown
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(System.Runtime.Remoting.Messaging.IMethodCallMessage methodCall, System.ServiceModel.Dispatcher.ProxyOperationRuntime operation) Unknown
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannelProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage message) Unknown
mscorlib.dll!System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(ref System.Runtime.Remoting.Proxies.MessageData msgData, int type) Unknown
正在与之通信的 wcf 服务的目标是 4.6,据我所知,我正在指定 dns 身份,它确实作为 CN= 存在于证书主题中。该绑定是自定义绑定,因此我可以执行联合 net.tcp,客户端在代码中创建所有内容,我不使用 visual studio 中的添加服务引用功能,客户端代码正在创建绑定:
var binding = new CustomBinding(new BindingElement[] {
new TransactionFlowBindingElement(),
security,
new SslStreamSecurityBindingElement(),
new BinaryMessageEncodingBindingElement() {
ReaderQuotas = { MaxDepth = maxReceivedSizeBytes, MaxStringContentLength = maxReceivedSizeBytes, MaxArrayLength = maxReceivedSizeBytes, MaxBytesPerRead = maxReceivedSizeBytes, MaxNameTableCharCount = maxReceivedSizeBytes },
},
new TcpTransportBindingElement {
TransferMode = TransferMode.StreamedResponse,
MaxReceivedMessageSize = maxReceivedSizeBytes,
},
}) {
SendTimeout = sendTimeout,
};
var channelFactory = new ChannelFactory<T>(binding, new EndpointAddress(new Uri(url), EndpointIdentity.CreateDnsIdentity("xxx.domain.local"), new AddressHeader[0]));
这可能是 4.6 框架中导致不同行为的错误吗?接下来的步骤是否只是尝试逐步调试框架代码以尝试找出 4.6 行为不同的原因?
编辑 - 我创建了一个small sample project that demonstrates the error,重现步骤是:
- (使用VS 2015)打开WcfSelfHostedServer解决方案
- 将 IdentityFail.pfx 证书添加到您的本地计算机,使用 mmc 的个人商店
- 运行 WcfSelfHostedServer 项目(可能点击防火墙是允许端口 30000)
- 打开WcfClient解决方案
- 右键项目>属性,注意是针对4.6.1
- 运行项目,会抛出上述异常
- 现在将客户端切换到目标 4.5.2,它将 运行 没有错误
更新- 我发现以下内容似乎相关: https://support.microsoft.com/en-us/kb/3069494 https://msdn.microsoft.com/en-us/library/mt298998(v=vs.110).aspx
但是在服务器和客户端指定 Tls12 并没有解决问题,即使添加 DontEnableSchUseStrongCrypto=true 标志也不会影响 DNS 身份检查错误,即使它绕过了 Enum.Parse 内部错误was being thrown from this line
我需要查看导致我的问题的 Retargetting Changes in the .NET Framework 4.6.1, as certificate validation logic changed in that release. (change in behavior for X509CertificateClaimSet.FindClaims)
修复正在编辑我的 app.config 添加:
<runtime>
<AppContextSwitchOverrides value="Switch.System.IdentityModel.DisableMultipleDNSEntriesInSANCertificate=true" />
</runtime>
您可以看到 changed code on referencesource, and naturally makecert.exe doesn't appear to support generating certificates with "Subject Alternative Name" fields
布兰登。
看起来如果标志是 'false' 并且证书不包含 SAN 条目,我们不会添加 dns 条目。
您可以在代码中添加一行来修复。
像这样。
AppContext.SetSwitch("Switch.System.IdentityModel.DisableMultipleDNSEntriesInSANCertificate",true);
在服务器上安装 .net 4.7 解决了我的问题。