Reputation: 4775
I'm developing simple Windows Service sending and receiving data from remote web service. I decided to use WebClient class for it's simplicity and enhanced it to include certificate in request, like this:
class MyWebClient : WebClient
{
public X509Certificate cert { set; get; }
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest req = (HttpWebRequest)base.GetWebRequest(address);
req.ClientCertificates.Clear();
req.ClientCertificates.Add(cert);
return req;
}
}
This is how i prepare and make requests:
try {
//...
string qry = "Some xml query...";
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate(object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors) { return true; };
X509Certificate cert = X509Certificate.CreateFromCertFile(appPath + @"\data\cert.der");
MyWebClient cl = new MyWebClient();
cl.cert = cert;
string xmlReq = qry;
cl.Headers[HttpRequestHeader.ContentType] = "text/xml";
var data = Encoding.UTF8.GetBytes(xmlReq);
byte[] res = cl.UploadData(apiUrl, data);
cl.Dispose();
string result = Encoding.UTF8.GetString(res);
} catch (Exception ex) {
//...
}
//...
Now, i know that loading certificate from file is not the best idea, but that's not the point. The point is that above code works perfectly in desktop application, but throws "Could not establish secure channel for SSL/TLS" exception in Windows Service. I tried to install the service under "localService" and "networkService" account and it makes no diffirence.
UPDATE: installing under "user" didn't help also. Am I missing something?
Upvotes: 0
Views: 1835
Reputation: 122739
When you load a certificate with this:
X509Certificate cert = X509Certificate.CreateFromCertFile(appPath + @"\data\cert.der");
You're only loading the certificate. However, for client-certificate authentication to work, you need to provide the private key too (otherwise, anyone could use any certificate).
Following the discussion in the chat room, you've indicated you also have a .p12
(PKCS#12), a .key
and .pem
file, as will as the .der
file you were trying to load.
Usually, these extensions are used in this way:
.der
for the certificate itself in DER encoding (binary)..pem
for the certificate itself in PEM encoding (base64-encoding of DER, within ---BEGIN....--- ... --- END ---
delimiters)..key
for the private key..p12
(or .pfx
) for the PKCS#12 file, which will contain both the certificate (and possibly the CA chain) and the private key.In .Net, the base X509Certificate
will not allow you to load a private key along with the certificate. You should look into loading the p12 file into a X509Certificate2
instance: it's essentially a convenience class that not only models certificates, but can associate a private key to the object too.
I'm not sure why this worked as a desktop application and not as a service. My guess is that it would have picked up a cert+private key from the user or machine store automatically in one of the situations. Either way, your desktop application was not authenticating simply with the DER file anyway.
Upvotes: 2