1

我有以下代码

var factory = new ChannelFactory<INewsClient>();
factory.Credentials.ClientCertificate.Certificate = GetCertificate();
factory.Endpoint.Address = new EndpointAddress("https://blabla.com/myservice/");
var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
factory.Endpoint.Binding = binding;
var channel = factory.CreateChannel();
channel.GetNews();

它适用于 .NET 3.5,但不适用于 .NET4.0。怪异吧?我使用的证书不在本地机器上验证(无链)。在 3.5 中,客户端证书的有效性与建立 SSL 无关,但是在迁移到 4.0 时,证书在用于 SSL 之前是经过验证的。(我可以在 CAPI2 事件日志中看到错误)。导致丑陋的 SecurityNegotiationException ...

堆栈跟踪:

System.ServiceModel.Security.SecurityNegotiationException:无法为具有权限“pep.uat.dialectpayments.com”的 SSL/TLS 建立安全通道。---> System.Net.WebException:请求被中止:无法创建 SSL/TLS 安全通道。
   在 System.Net.HttpWebRequest.GetResponse()
   在 System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(时间跨度超时)
   --- 内部异常堆栈跟踪结束 ---

服务器堆栈跟踪:
   在 System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException,HttpWebRequest 请求,HttpAbortReason abortReason)
   在 System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(时间跨度超时)
   在 System.ServiceModel.Channels.RequestChannel.Request(消息消息,TimeSpan 超时)
   在 System.ServiceModel.Dispatcher.RequestChannelBinder.Request(消息消息,TimeSpan 超时)
   在 System.ServiceModel.Channels.ServiceChannel.Call(字符串操作,布尔单向,ProxyOperationRuntime 操作,Object[] 输入,Object[] 输出,TimeSpan 超时)
   在 System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime 操作)
   在 System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage 消息)

在 [0] 处重新抛出异常:
   在 System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg,IMessage retMsg)
   在 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData,Int32 类型)
   在 ConsoleApplication2.Program.INewsClient.Get()
   在 d:\dev\ConsoleApplication2\Program.cs:line 44 中的 ConsoleApplication2.Program.Main(String[] args)

在我们的安全架构中,证书是针对服务器上的 LDAP 目录进行验证的,因此客户端不需要知道完整的链。

问题是,我如何禁用这种新行为?

4

1 回答 1

1

好的,我将在这里提供我自己的答案...

简而言之:对于 X509,您似乎不能将非持久 CSP 与 .NET 4 一起使用。即你的 CSP 必须有一个 KeyContainerName 才能工作。

我的 GetCertificate() 方法正在执行以下操作:(即非持久性)

var certificate = new X509Certificate2(@"C:\public.cer");
var rsa = RSA.Create();
rsa.FromXmlString("<RSAKeyValue>......</RSAKeyValue>");
certificate.PrivateKey = rsa;
return certificate;

将其更改为此使我的示例在 3.5 和 4.0 中工作:(设置 KeyContainerName 将在您的加密文件夹中创建一个物理条目)

var certificate = new X509Certificate2(@"C:\public.cer");
CspParameters parameters = new CspParameters { KeyContainerName = "KeyContainer" };
var rsa = new RSACryptoServiceProvider(parameters);
rsa.FromXmlString("<RSAKeyValue>......</RSAKeyValue>");
certificate.PrivateKey = rsa;
return certificate;

为简单起见,我试图将私钥导出到 .pfx 文件中,但无法使用 .NET 4.0 中的第一种方法,但可以使用 .NET 3.5。无论如何,私钥在 .NET 4.0 中是不可导出的。该链接帮助我修复了它。

不过,很高兴知道这里 3.5 和 4.0 之间发生了什么变化。

于 2011-09-04T22:59:06.440 回答