在调用 ServerCertificateValidationCallback 之前远程证书无效错误

Remote Certificate invalid error Before ServerCertificateValidationCallback is called

我在尝试连接到 SOAP 1.1 服务器时遇到异常。我从其他组织收到了 WSDL,并使用 .net 将其作为服务参考引入我的项目。

要求我们使用包括 MTOM 附件和 HTTP gzip 压缩。它还需要 Web 服务安全 (WS-Security) 1.0 版(使用 OASIS 标准)以使用 X.509 身份验证框架实现端到端安全。

我正在使用 4.5.2 .Net 框架在 c# 中工作。

这是我的 app.config 的相关部分,其中包含已编辑的潜在敏感信息:

  <basicHttpBinding>
    <binding name="customHttpBinding" allowCookies="true" messageEncoding="Mtom">
      <security mode="TransportWithMessageCredential">
        <transport clientCredentialType="Certificate" />
        <message clientCredentialType="Certificate" />
      </security>
    </binding>
  </basicHttpBinding>

[snip]

<client>
  <endpoint address="YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
    binding="basicHttpBinding" bindingConfiguration="customHttpBinding"
    contract="SERVICENAME.BulkRequestTransmitterPortType"
    name="BulkRequestTransmitterPort">
    <identity>
      <certificateReference storeLocation="CurrentUser" x509FindType="FindBySerialNumber"
        findValue="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" />
    </identity>
  </endpoint>
</client>

Xs 是我的密钥的序列号(确认在我的计算机商店中),Y 是端点

这是我创建和调用服务的部分(Xs 是同一个证书):

  var transmitter = new BulkRequestTransmitterPortTypeClient();

  transmitter.ClientCredentials?.ClientCertificate.SetCertificate(
      StoreLocation.CurrentUser, 
      StoreName.My, 
      X509FindType.FindBySerialNumber, 
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");

  var response = transmitter.BulkRequestTransmitter(
      securityHeader, 
      security, 
      ref businessHeader, 
      transmitterManifestReqDtl, 
      transmitterType);

它在最后一行爆炸并出现以下错误:

ex  {"Could not establish trust relationship for the SSL/TLS secure channel with authority 'YYYYYYYYYYYY'."}    System.Exception {System.ServiceModel.Security.SecurityNegotiationException}
    +InnerException {"The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel."}    System.Exception {System.Net.WebException}
        +InnerException {"The remote certificate is invalid according to the validation procedure."}    System.Exception {System.Security.Authentication.AuthenticationException}

每当我进行搜索时,我都会找到两个建议,第一个是确保服务器证书在我信任的存储中并且第三方机构是可信的。我已经确认两者都在我本地计算机的商店中并且是可信的。第二个也是最常见的建议是用 return true 覆盖 ServicePointManager.ServerCertificateValidationCallback,如下所示:

ServicePointManager.ServerCertificateValidationCallback = delegate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    return true;
};

尽管我在尝试这个时犹豫不决(即使在开发环境中我也不喜欢使用不良做法)但我认为在调试中使用它是值得的。遗憾的是,断点 从未命中 。在 ServerCertificateValidationCallback 触发之前 我收到错误消息。

我现在很茫然。我不确定我做错了什么,因为我对配置所做的每一次更改都会在更早的时候产生错误,所以我认为我走在正确的道路上,但我不确定为什么验证过程失败以及如何解决它。如果能提供任何帮助,我将不胜感激。

不幸的是,我不是心灵感应者,我可以告诉你到底是什么导致了你的问题。不过,我可以提供一些见解。

仅用于调试目的,您可以了解连接失败的确切原因。使用此回调委托:

ServicePointManager.ServerCertificateValidationCallback = delegate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    return true;
};

并在委托调用上设置断点。触发后,使用调试器检查 chain 参数。有 ChainElements 属性 持有 X509ChainElement objects. Each object is associated with a particular certificate in the chain and status of each certificate in the chain and certificate status (via ChainElementStatus) 的集合。请注意,链元素状态是累积的,这意味着错误从最顶层的证书向下传播。换句话说,ChainElementStatus 成员将包含与特定 ChainElement 相关的错误以及来自上层的组合错误。

确定并解决问题后,删除此委托。

另一种选择是将远程服务器的证书文件(仅 public 证书)传递给 certutil:

certutil -verify -urlfetch path\remoteserver.cer

输出可能有点复杂,但它会提供 X509Chain 调试无法获得的额外信息。最常见的问题(在不受信任的根之后)是 RevocationOffline 并且 certutil 将显示吊销检查详细信息,包括每个 URL 可用性和有效性。

这是因为有问题的服务器没有使用证书。如果您通知 .net 期望从服务器获得一个,它会在到达 ServerCertificateValidationCallback 之前失败并显示此错误消息。