使用客户端证书认证连接Web服务

7

我被给予了一个.p12文件,用于使用客户端证书身份验证连接到支持SSL的web服务。 我已成功在PHP中使用cURL实现此功能。 在执行请求时,我使用以下选项:

$headers = array(
    'Method: POST',
    'Connection: Keep-Alive',
    'User-Agent: PHP-SOAP-CURL',
    'Content-Type: text/xml; charset=utf-8',
    'SOAPAction: "'.$action.'"',
);

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $location);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
curl_setopt($ch, CURLOPT_SSLCERT, $this->clientcert);
curl_setopt($ch, CURLOPT_SSLKEYTYPE, $this->clientcerttype);
curl_setopt($ch, CURLOPT_SSLKEY, $this->keyfile);
curl_setopt($ch, CURLOPT_SSLKEYPASSWD, $this->keypassword);
curl_setopt($ch, CURLOPT_SSLVERSION, 3);

$response = curl_exec($ch);

我现在正在使用C#和.NET尝试完成相同的任务,但是我一直收到错误信息“无法与':'建立SSL/TLS的安全通道。”。
我似乎没有找不到密钥的问题,并且也没有任何信任问题。 但是,在某个地方出了问题。
我制作了一个测试程序,以便可以测试基本调用是否有效。
public void StartviaWSHttp()
{
    var binding = new WSHttpBinding();
    binding.Security.Mode = SecurityMode.Transport;
    binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
    binding.Security.Message.NegotiateServiceCredential = false;
    binding.Security.Message.ClientCredentialType = MessageCredentialType.None;

    var baseAddress = new Uri("https://<host>:<port>/LineEndpoint1");
    var endpointAddress = new EndpointAddress(baseAddress);

    var client = new LinePortTypeClient(binding, endpointAddress);

    client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySerialNumber, "00d48a233bf4b77523");

    Debug.Assert(client.ClientCredentials.ClientCertificate.Certificate.SerialNumber.ToLower() == "00d48a233bf4b77523");

    var header = new ctSoapHeaderMsg();
    var response = new object();
    client.Open();
    var responseCode = client.PerformFunction(ref header, "0893411111", out response);
    client.Close();

    Console.WriteLine("Response Code :" + responseCode);
    Console.WriteLine("Response :" + response);
}

在个人/当前用户证书中查看证书时,没有报告任何关于信任方面的问题。在证书信息中,它说证书适用于以下目的:所有签发策略和所有应用程序策略。认证路径只有一个条目,并且证书状态报告为“此证书状态良好”。 我不知道问题出在哪里。也许存在信任问题,因为我关闭了PHP调用的PEER和HOST验证。我不确定C#是否有这个选项。
更新:(2013年8月9日) 我设置了一些系统.Net和System.Net.Socket的详细跟踪。这是输出的开头。
System.Net Verbose: 0 : [16124] WebRequest::Create(https://dsl-wholesale-testing.iinet.net.au:50500/LineEndpoint1)
System.Net Verbose: 0 : [16124] HttpWebRequest#58508234::HttpWebRequest(https://dsl-wholesale-testing.iinet.net.au:50500/LineEndpoint1#128335743)
System.Net Information: 0 : [16124] Current OS installation type is 'Client'.
System.Net Information: 0 : [16124] RAS supported: True
System.Net Verbose: 0 : [16124] Exiting HttpWebRequest#58508234::HttpWebRequest() 
System.Net Verbose: 0 : [16124] Exiting WebRequest::Create()    -> HttpWebRequest#58508234
System.Net Verbose: 0 : [16124] ServicePoint#36898364::ServicePoint(dsl-wholesale-testing.iinet.net.au:50500)
System.Net Information: 0 : [16124] Associating HttpWebRequest#58508234 with ServicePoint#36898364
System.Net Verbose: 0 : [16124] HttpWebRequest#58508234::GetRequestStream()
System.Net Information: 0 : [16124] Associating Connection#47995487 with HttpWebRequest#58508234
System.Net.Sockets Verbose: 0 : [16124] Socket#31002555::Socket(AddressFamily#2)
System.Net.Sockets Verbose: 0 : [16124] Exiting Socket#31002555::Socket() 
System.Net.Sockets Verbose: 0 : [16124] Socket#6243847::Socket(AddressFamily#23)
System.Net.Sockets Verbose: 0 : [16124] Exiting Socket#6243847::Socket() 
System.Net.Sockets Verbose: 0 : [16124] DNS::TryInternalResolve(dsl-wholesale-testing.iinet.net.au)
System.Net.Sockets Verbose: 0 : [16124] Socket#31002555::Connect(203.173.51.130:50500#-2110560113)
System.Net.Sockets Information: 0 : [16124] Socket#31002555 - Created connection from 192.168.190.202:55397 to 203.173.51.130:50500.
System.Net.Sockets Verbose: 0 : [16124] Exiting Socket#31002555::Connect() 
System.Net.Sockets Verbose: 0 : [16124] Socket#6243847::Close()
System.Net.Sockets Verbose: 0 : [16124] Socket#6243847::Dispose()
System.Net.Sockets Verbose: 0 : [16124] Exiting Socket#6243847::Close() 
System.Net Information: 0 : [16124] Connection#47995487 - Created connection from 192.168.190.202:55397 to 203.173.51.130:50500.
System.Net Information: 0 : [16124] TlsStream#29695768::.ctor(host=dsl-wholesale-testing.iinet.net.au, #certs=0)
System.Net Information: 0 : [16124] Associating HttpWebRequest#58508234 with ConnectStream#25001628
System.Net Verbose: 0 : [16124] Exiting HttpWebRequest#58508234::GetRequestStream()     -> ConnectStream#25001628
System.Net Verbose: 0 : [16124] ConnectStream#25001628::Write()
System.Net Verbose: 0 : [16124] Data from ConnectStream#25001628::Write
System.Net Verbose: 0 : [16124] (printing 1024 out of 1206)
System.Net Verbose: 0 : [16124] 00000000 : 3C 73 3A 45 6E 76 65 6C-6F 70 65 20 78 6D 6C 6E : <s:Envelope xmln

这行代码 System.Net Information: 0 : [16124] TlsStream#29695768::.ctor(host=dsl-wholesale-testing.iinet.net.au, #certs=0) 表明没有选择要使用的证书,即使我已经将证书附加到了 client.ClientCredentials.ClientCertificate,但我不确定为什么会出现这种情况或者如何让它生效。证书的任何属性是否必须与我连接的主机名匹配?
2个回答

5

看起来服务器无法理解TLS。

我必须通过指定SSLv3来解决,方法如下:

System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3;

有趣。我用完全相同的代码和相同的TLS证书#0,也遇到了完全相同的错误,但我确定服务器确实支持TLS 1.2。我已经束手无策了。 - ajeh
System.Net.ServicePointManager.SecurityProtocol是一个标志,因此您可以通过按位OR指定其他SecurityProtocolTypes。如果您只有Ssl13,则任何Tls都将被忽略(假设您正在引用c#代码而不是PHP Curl)。 - Reuben
1
Web服务绑定的安全元素需要一个额外的元素 <transport clientCredentialType="Certificate" />,但是它缺失了。添加上去后一切正常了。 - ajeh

3

如评论中的@ajeh所提到的,“transport clientCredentialType=…”对我有用!

<binding name=".....">
    <security mode="Transport" >
        <transport clientCredentialType="Certificate"></transport>
    </security>
</binding> 

此外,您需要确保您的IIS应用程序池用户具有读取证书私钥的权限。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接