免责声明:像这样标题的问题很常见,但没有答案为我提供解决方案,所以无论如何我都需要问它(使用一组新参数)。
问题
Web 服务客户端端点在 web.config 中声明如下:
<behaviors>
<endpointBehaviors>
<behavior name="bankid">
<clientCredentials>
<clientCertificate findValue="FP Testcert 2"
storeLocation="LocalMachine"
storeName="Root"
x509FindType="FindBySubjectName"/>
<serviceCertificate>
<defaultCertificate findValue="Test BankID SSL Root CA v1 Test"
storeLocation="LocalMachine"
storeName="Root"
x509FindType="FindBySubjectName"/>
<authentication certificateValidationMode="None"
revocationMode="NoCheck"
trustedStoreLocation="LocalMachine"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
证书(客户端和服务器证书)是使用“管理计算机证书”应用程序安装的。它们分别存储在 .cer 文件(服务器证书)和 .pfx 文件(客户端证书)中。它们都存储在“受信任的根证书颁发机构”中。
成功
使用 Visual Studio 调试网络服务器 (IIS Express) 运行客户端成功。
失败
但是,当我尝试在 IIS 中运行它时,出现错误消息
Could not establish secure channel for SSL/TLS with authority 'site.com'
问题解决方法
我尝试创建一个 Web API 函数,让我知道服务器是否找到了有问题的证书。确实如此。代码看起来像
[HttpGet]
[Route("Debug/certs")]
public CertsOutput certs()
{
var certStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
certStore.Open(OpenFlags.ReadOnly);
var config = System.Web.Configuration.WebConfigurationManager
.OpenWebConfiguration("~");
var group = ServiceModelSectionGroup.GetSectionGroup(config);
var endPointBehaviors = group.Behaviors.EndpointBehaviors;
var endpointBehavior = endPointBehaviors[0];
var ClientCredential = (ClientCredentialsElement) endpointBehavior[0];
var clientCert = ClientCredential.ClientCertificate;
var serverCert = ClientCredential.ServiceCertificate.DefaultCertificate;
var result = new CertsOutput
{
clientCert = new CertsOutput.Cert
{
FindValue = clientCert.FindValue,
StoreName = clientCert.StoreName.ToString(),
StoreLocation = clientCert.StoreLocation.ToString(),
FindType = clientCert.X509FindType.ToString()
},
serverCert = new CertsOutput.Cert
{
FindValue = serverCert.FindValue,
StoreName = serverCert.StoreName.ToString(),
StoreLocation = serverCert.StoreLocation.ToString(),
FindType = serverCert.X509FindType.ToString()
}
};
return result;
}
public class CertsOutput
{
public Cert clientCert { get; set; }
public Cert serverCert { get; set; }
public class Cert
{
public string FindValue { get; set; }
public string StoreName { get; set; }
public string StoreLocation { get; set; }
public string FindType { get; set; }
public string Expiration => Certificate?.GetExpirationDateString()
?? "Cant find cert";
X509Certificate _certificate = null;
private X509Certificate Certificate
{
get
{
if (_certificate != null)
return _certificate;
StoreName storeNameEnum;
switch(StoreName)
{
case "My":
storeNameEnum = System_StoreName.My;
break;
case "Root":
storeNameEnum = System_StoreName.Root;
break;
default:
throw new Exception("Unknown store name: " + StoreName);
}
StoreLocation storeLocationEnum;
switch(StoreLocation)
{
case "LocalMachine":
storeLocationEnum = System_StoreLocation.LocalMachine;
break;
case "CurrentUser":
storeLocationEnum = System_StoreLocation.CurrentUser;
break;
default:
throw new Exception("Unknown store location: " + StoreLocation);
}
var certStore = new X509Store(storeNameEnum, storeLocationEnum);
certStore.Open(OpenFlags.ReadOnly);
var certCollection = certStore.Certificates.Find
(X509FindType.FindBySubjectName, FindValue, validOnly:false);
certStore.Close();
var result = certCollection[0];
_certificate = result;
return result;
}
}
}
}
即使我在 IIS 上运行它,我也会得到这样的输出(在 chrome 中使用 console.log):
因此 IIS 可以清楚地看到证书,尽管它们存储在“受信任的根证书颁发机构”中。检索过期日期的唯一方法是使用商店。
最佳答案
在事件日志中启用 CAPI2 日志可能会告诉您为什么它无法创建 SSL/TLS 安全通道。
CAPI2 日志默认情况下处于禁用状态。当您启用它时,请尝试再次发出请求。应该有一些错误事件,其中包含有关原因的有用信息。
我还会检查(并可能更改)一些内容:
- 在 IE 中打开 WCF 端点并检查该站点是否受 IS 信任。如果不是找出原因。这是你应该做的第一件事。
- 客户端证书 (pfx) 应放在
LocalMachine/My
(个人)存储中。根 CA 证书应放在受信任的根证书颁发机构存储中(你没看错),中间 CA 证书应放在中间证书颁发机构存储中 - 应将私钥的权利授予运行 WCF 客户端的 IIS 应用程序池。可以使用
certlm.msc
工具来完成。 - 检查私钥是否可用于 web api 方法。所以检查
PrivateKey
属性,用它签署一些 hello world 数据等。
关于asp.net - 无法使用权限 'site.com' 为 SSL/TLS 建立安全通道,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47183063/