WCF SslStreamSecurity DNS Identity Check仅在4.6框架中失败

本文关键字:框架 失败 仅在 SslStreamSecurity DNS Identity Check WCF | 更新日期: 2023-09-27 18:31:16

我正在努力为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 中的一个错误,我知道在 4.6 中进行了 Wcf ssl 更改

打开第一次机会异常后,我看到以下异常在系统服务模型中内部引发

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 行为不同的原因?

编辑-我创建了一个演示错误的小型示例项目,重现步骤如下:

  • (使用 VS 2015) 打开 WcfSelfHostedServer 解决方案
  • 使用 mmc 将 IdentityFail.pfx 证书添加到本地计算机、个人存储
  • 运行 WcfSelfHostedServer 项目(可能单击防火墙是允许端口 30000)
  • 打开 WcfClient 解决方案
  • 右键单击项目>属性,请注意它的目标是 4.6.1
  • 运行项目,它将抛出上述异常
  • 现在将客户端切换到目标 4.5.2,它将运行良好,没有错误

更新-我发现以下内容似乎相关:https://support.microsoft.com/en-us/kb/3069494https://msdn.microsoft.com/en-us/library/mt298998(v=vs.110).aspx

但是在服务器和客户端上指定 Tls12 并不能解决问题,即使添加 DontEnableSchUseStrongCrypto=true 标志也不会影响 DNS 身份检查错误,即使它绕过了从此行引发的 Enum.Parse 内部错误

WCF SslStreamSecurity DNS Identity Check仅在4.6框架中失败

我需要查看 .NET Framework 4.6.1 中的延迟更改,因为该版本中的证书验证逻辑发生了变化。(导致我问题的 X509CertificateClaimSet.FindClaims 的行为更改)

解决方法是编辑我的 app.config 以添加:

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

您可以在 referencesource 上看到更改的代码,并且自然 makecert.exe 似乎不支持生成带有"主题备用名称"字段的证书

您可以在代码中添加一行进行修复。

喜欢这个。

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

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

Brandon。

如果标志为"假"并且证书不包含 SAN 条目,则我们不会添加 dns 条目。