WCF SslStreamSecurity仅对4.6框架进行DNS身份检查失败

时间:2016-01-20 20:57:13

标签: c# .net wcf .net-4.5 .net-4.6

我正在为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解决方案
  • 使用mmc
  • 将IdentityFail.pfx证书添加到您的本地计算机,个人商店
  • 运行WcfSelfHostedServer项目(可能单击防火墙是允许端口30000)
  • 打开WcfClient解决方案
  • 右键点击项目&gt;属性,请注意它的目标是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身份检查错误,即使它绕过了{{3的Enum.Parse内部错误}}

4 个答案:

答案 0 :(得分:18)

我需要查看Retargetting Changes in the .NET Framework 4.6.1,因为该版本中的证书验证逻辑已更改。 (change in behavior for X509CertificateClaimSet.FindClaims导致我的问题)

修复程序正在编辑我的app.config以添加:

<runtime>
    <AppContextSwitchOverrides value="Switch.System.IdentityModel.DisableMultipleDNSEntriesInSANCertificate=true" /> 
</runtime>

您可以看到changed code on referencesource,自然makecert.exe似乎不支持generating certificates with "Subject Alternative Name" fields

答案 1 :(得分:4)

您可以修改代码添加一行。

像这样。

        AppContext.SetSwitch("Switch.System.IdentityModel.DisableMultipleDNSEntriesInSANCertificate",true);

答案 2 :(得分:2)

在服务器上安装.net 4.7解决了我的问题。

答案 3 :(得分:1)

布兰登。

看来,如果旗帜是“假”&#39;并且证书不包含SAN条目,我们不会添加dns条目。