HttpWebRequest failure with TLS

S

Sholto Douglas

I am using HttpWebRequest to access a WebLogic web servce. It is currently
in a console app, but will be 'elevated' to a service.
The code is pretty standard, but I get the dreaded WebException:
The underlying connection was closed: Could not establish secure channel
for SSL/TLS
It uses 2-way SSL/TLS. I am adding the client certificate to the
ClientCertificates property. I have added the server certificate to my
CurrentUser store. The server has my (client) certificate. What more can I
do, for heavens sake?
The WebLogic log shows that we complete the first 3 stages of the handshake,
namely up to here:

*** ServerHelloDone
HttpProcessor[8082][4], WRITE: TLSv1 Handshake, length = 4972
HttpProcessor[8082][4], received EOFException: error
HttpProcessor[8082][4], handling
exception:javax.net.ssl.SSLHandshakeException: Remote host closed connection
during handshake
HttpProcessor[8082][4], SEND TLSv1 ALERT: fatal, description =
unexpected_message
HttpProcessor[8082][4], WRITE: TLSv1 Alert, length = 2
...
...

At this point the client should send the client certificate to the server,
but it doesn't.
For what it's worth, here is the code:

HttpWebRequest webRequest =
(HttpWebRequest)WebRequest.Create(sUri);
webRequest.Method = "POST";
webRequest.KeepAlive = false;
webRequest.ContentType = "text/xml";
webRequest.ContentLength = in_sXml.Length;
// Add the authentication certificates
if (m_x509ClientCert != null)
webRequest.ClientCertificates.Add(m_x509ClientCert);

StreamWriter SW = new StreamWriter(webRequest.GetRequestStream());
SW.Write(in_sXml);
SW.Close();

// Wait for response...
HttpWebResponse webResponse =
(HttpWebResponse)webRequest.GetResponse();

It throws the exception at the webRequest.GetRequestStream() call.

In the class constructor I have set the ServicePointManager.SecurityProtocol
to
SecurityProtocolType.Tls, and the CertificatePolicy to accept all
certificates.

Can anyone tell me what I have missed?
 
J

Joe Kaplan \(MVP - ADSI\)

This generally means that your client code doesn't have access to the
private key for the certificate in question, although it could be an issue
with certificate trust as well.

Debugging these issues is notoriously difficult I'm afraid.

The first thing I would do is make sure the certificate in question has a
private key associated with it. Then, make sure you can navigate to the
page in question with the browser and that IE will prompt you for the client
certificate.

After that, using regmon and filemon while the program is running is often
very helpful for determining where Windows is looking for the private key
file and who is getting denied access.

There are also some kbase articles on this issue.

Joe K.

Sholto Douglas said:
I am using HttpWebRequest to access a WebLogic web servce. It is currently
in a console app, but will be 'elevated' to a service.
The code is pretty standard, but I get the dreaded WebException:
The underlying connection was closed: Could not establish secure channel
for SSL/TLS
It uses 2-way SSL/TLS. I am adding the client certificate to the
ClientCertificates property. I have added the server certificate to my
CurrentUser store. The server has my (client) certificate. What more can
I
do, for heavens sake?
The WebLogic log shows that we complete the first 3 stages of the
handshake,
namely up to here:

*** ServerHelloDone
HttpProcessor[8082][4], WRITE: TLSv1 Handshake, length = 4972
HttpProcessor[8082][4], received EOFException: error
HttpProcessor[8082][4], handling
exception:javax.net.ssl.SSLHandshakeException: Remote host closed
connection
during handshake
HttpProcessor[8082][4], SEND TLSv1 ALERT: fatal, description =
unexpected_message
HttpProcessor[8082][4], WRITE: TLSv1 Alert, length = 2
...
...

At this point the client should send the client certificate to the server,
but it doesn't.
For what it's worth, here is the code:

HttpWebRequest webRequest =
(HttpWebRequest)WebRequest.Create(sUri);
webRequest.Method = "POST";
webRequest.KeepAlive = false;
webRequest.ContentType = "text/xml";
webRequest.ContentLength = in_sXml.Length;
// Add the authentication certificates
if (m_x509ClientCert != null)
webRequest.ClientCertificates.Add(m_x509ClientCert);

StreamWriter SW = new StreamWriter(webRequest.GetRequestStream());
SW.Write(in_sXml);
SW.Close();

// Wait for response...
HttpWebResponse webResponse =
(HttpWebResponse)webRequest.GetResponse();

It throws the exception at the webRequest.GetRequestStream() call.

In the class constructor I have set the
ServicePointManager.SecurityProtocol
to
SecurityProtocolType.Tls, and the CertificatePolicy to accept all
certificates.

Can anyone tell me what I have missed?
 
S

Sholto Douglas

Thanks for answering, Joe,
Debugging these issues is notoriously difficult I'm afraid.
Tell me about it..... What is annoying is that whatever the problem, I
always get the same exception message. The .NET error messages should be
more explicit.
This generally means that your client code doesn't have access to the
private key for the certificate in question, although it could be an issue
with certificate trust as well.
I put both keys (client and server) into the Personal 'folder' of the
CurrentUser store. Do they need to be in the LocalMachine store? If so,
which folder? Personal, Trusted People? I imagine the CurrentUser store
would be less prone to permission problems, which is why I put them there.
How can I be sure I do have the required access?
The first thing I would do is make sure the certificate in question has a
private key associated with it. Then, make sure you can navigate to the
page in question with the browser and that IE will prompt you for the client
certificate.
I am confident there is a private key, because I was asked if I wanted to
export it (I didn't, of course!). I am actually going through a colleague's
laptop with Tomcat installed, then to a proxy, before the actual web service.
So I have never been able to bring up the page in IE (they aren't making it
easy for me).

Thanks again, Joe,
Sholto Douglas
His Nerdship Pty Ltd (Australia)
 
J

Joe Kaplan \(MVP - ADSI\)

My guess is that you are going to want it in the machine store as the
account your web service client is running under will eventually change to
the service process' account, but it should work in either for the console
app as your user profile will be loaded.

The MMC snap-in will tell you for sure if the client certificate has a
private key associated with it in the cert properties dialog. The client
certificate should go in the personal store.

You probably don't need the server's certificate on your machine at all as
long as your machine trusts it.

If you can't bring up the page in IE, that might mean that the underlying
Wininet goo can't get to it either. Be careful with that as this might not
be a client certificate issue at all.

Another useful thing is to play with the schannel logging level to see
detailed log messages on the certificate exchange stuff in the event log:
http://support.microsoft.com/?id=260729

Joe K.
 
S

Sholto Douglas

Hi Joe,
Still no progress.... However I do have a couple of pointers.
Firstly when I try to bring up the web service in IE, I just get "The page
cannot be displayed". On the Tomcat server they get exactly the same log
message as when it fails from my app, and it dies at the same point
(ServerHelloDone). Apparently the server is waiting for a certificate, which
it doesn't get (either from my app, or from IE). I get no message prompting
me for a client certificate.
I have added the client key to the Personal folders of both the Local
Machine store, and the Current User one. As I said, there is definitely a
private key because when I try to export the certificate (in MMC), it prompts
me if I want to export the private key.
I have also added the root certificate to the Trusted Root Certification
Authority in both stores. As you said, given that it is a console app, it
should always have access to the Current User store.

I activated the SCHANNEL logging, setting the value to 7 (i.e everything).
However I only got one (Information) line - it just said "Creating an SSL
client credential." There were no error messages, suggesting it bombed out
early.

Finally to see if the problem was TLS related, I removed the code that
forced a TLS handshake (so it would default to SSLv3). Still failed.

I appreciate your help Joe. This whole business is making me look very
incompetent!
 
J

Joe Kaplan \(MVP - ADSI\)

Interesting. No Schannel error on the client credential creation? It
sounds like it is actually creating the client certificate part of the
handshake. Is it possible that the server side implementation doesn't
properly trust the client certificate or there is a configuration issue on
their side?

I have no idea how to suggest to troubleshoot that as I only know IIS, but
they probably use OpenSSL and I think it has some good logging facilities.

Best of luck on this one...

Joe K.
 
P

Peter Jakab

Hi Sholto,

I already told you in an email, that we were in the same situation, and the
problem was with the server certificate, that we used on the weblogic, re
creating it with the keytool solved the problem.

One more thing iwould like to add:

In case you want to access the weblogic web service from a web application,
for the process to have access to the client certificate, the client
certificate must be placed into the LOCAL_MACHINE store, and the account,
with whose identity the application pool of the app is running, must have
access to the cert.

If the app pool was running with NEtwork service identity, you should have
to grant access to it using the

C:\Program Files\Windows Resource Kits\Tools>winhttpcertcfg -g -a "NETWORK
SERVICE" -s "pannongsm.hu" -c LOCAL_MACHINE\MY

command (after downloading and installing the winhttpcertconfig tool from MS
from

http://www.microsoft.com/downloads/...ac-3409-40e9-8667-c748e422833f&displaylang=en

and importing the client certificate to the LOCAL_MACHINE\Personal
store.

In case we imported the client cert to the current_user store of the service
account, it worked fine until the first reboot of the server, after that the
worker process couldn't access the cert stored in the users store.
This is NOT mentioned in the MS Article...

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetHT13.asp

On the other hand, this article is great, I think.

Best regards

Peter Jakab
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,737
Latest member
Georgeengab

Latest Threads

Top