I've been give a .p12 file to connect to a web service over SSL using client certificate authentication. I have this successfully working in PHP, using cURL. These are the options I'm using when perform the request:
$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);
I'm now trying to do the same task using C# and .NET, but I keep getting the error "Could not establish secure channel for SSL/TLS with authority ':'.".
I don't seem to have an issue with locating the key, and there don't appear to be any trust issues. Still, something isn't right, somewhere along the line.
I've made a test program, just so I can test that a basic call will work.
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);
}
When I view the certificate in the Personal/Certificates for Current User, it does not report any issues, with regards to trust. In the certificate information, it says that the certificate in intended for the following purposes: All issuance policies and all application policies. The Certification Path only has one entry, and the Certificate status reports that "This certificate is OK."
I'm at a loss for what the issue is. Perhaps there is a trust issue, since I have PEER and HOST verification off for the PHP call. I'm not sure if that is an option for C#.
Update: (9 August 2013) I set up some verbose tracing for System.Net and System.Net.Socket. This is the start of the output.
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
The line System.Net Information: 0 : [16124] TlsStream#29695768::.ctor(host=dsl-wholesale-testing.iinet.net.au, #certs=0)
suggests that no certificates have been picked up for use, even though I've attached the certificate to the client.ClientCredentials.ClientCertificate, but I'm not sure why this is happening or how to make it stick. Do any properties of the certificate have to match the hostname that I'm connecting to?
It appears that the server did not understand TLS.
I had to specify SSLv3, via
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3;
As @ajeh mentioned in the comments "transport clientCredentialType=..." worked for me!
<binding name=".....">
<security mode="Transport" >
<transport clientCredentialType="Certificate"></transport>
</security>
</binding>
Also, you need to make sure that your IIS application pool user has permission to read private key of your certificate.
来源:https://stackoverflow.com/questions/18049845/connecting-to-a-web-service-using-client-certificate-authentication