Я работаю над созданием новой привязки для службы Wcf, размещенной в IIS, я думал, что у меня все работает, но оказывается, что клиент работает только тогда, когда он нацелен на .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 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, сделанные в 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 ведет себя по-другому?
РЕДАКТИРОВАТЬ - Я создал небольшой проект образца который демонстрирует ошибку, шаги воспроизведения:
- (Использование VS 2015) Откройте решение WcfSelfHostedServer
- Добавьте сертификат IdentityFail.pfx на свой локальный компьютер, личное хранилище, используя mmc
- Запустите проект WcfSelfHostedServer (вероятно, щелчок на брандмауэре да разрешает порт 30000)
- Откройте решение WcfClient
- Щелкните правой кнопкой мыши по объектам проектa > , обратите внимание, что он нацелен на 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, которая выбрасывается из этой строки