Replace Mono SslClientStream with .NET SslStream to fix SSL-related errors #27

Merged
merged 1 commit into from Jul 17, 2013

Conversation

Projects
None yet
2 participants

This change fixes an issue when connecting to a PostgreSQL database
configured to accept connections only with a valid client certificate.
With Mono's SslClientStream, an encryption error would occur when trying
to connect. WIth .NET's SslStream, the connection can be successfully
opened. The Mono-based callbacks have been marked "Obsolete". The newer
ValidateRemoteCertificateCallback is used automatically if it is
provided.

Dave Geering Replaced SslClientStream with .NET SslStream
This change fixes an issue when connecting to a PostgreSQL database
configured to accept connections only with a valid client certificate.
With Mono's SslClientStream, an encryption error would occur when trying
to connect. WIth .NET's SslStream, the connection can be successfully
opened. The Mono-based callbacks have been marked "Obsolete". The newer
ValidateRemoteCertificateCallback is used automatically if it is
provided.
1015859

Take 2: this pull request contains code to automatically switch between the new and old methods and also marking the old callbacks obsolete.

Owner

franciscojunior commented Jun 28, 2013

Great, @dreamlax ! I liked very much your idea of doing the switch based on if the developer assigned or not a callback for the system.net.security. I'll do some tests and then merge it. Thank you!

Owner

franciscojunior commented Jul 3, 2013

Hi, @dreamlax I'm playing with your patch doing some tests, but I got stuck in the client certificate stuff. I'm following this how to: http://www.howtoforge.com/postgresql-ssl-certificates and I could create the certificates for the server and the client and configure everything in postgresql.conf and pg_hba.conf. When I try to use the client certificate, postgresql server always returns an error saying the client certificate isn't valid. To check if I did everything correctly, I tested it with psql. When I tried to connect it asked for the certificate password and could connect ok.

Could you give me some code samples so I can test it and then add the instructions to npgsql user manual?

Thanks in advance!

Owner

franciscojunior commented Jul 3, 2013

I used this code as a starting point:
http://fxjr.blogspot.com.br/2010/04/using-ssl-client-certificates-with.html

I also added a delegate for the new validation callback your patch adds, but neither way worked.

Note that I could get the ssl connection working only with no client certificate.

Thanks for any tip.

Owner

franciscojunior commented Jul 4, 2013

Hi @dreamlax . Today I tried to do make it work on Windows. I could pass past the invalid certificate error, but I still get errors when reading data from the stream.

This gist contains the program I'm using to test: https://gist.github.com/franciscojunior/5930034
It also contains the pg_hba.conf I'm using.
I also added the stacktrace of the error I'm getting. It is in portuguese because the windows I use is in portuguese. But it says: the connection has been forcibly closed.

Note that if I don't configure the server to use the client certificate, everything works ok.

Owner

franciscojunior commented Jul 4, 2013

I think there is something strange with BufferedStream in ms.net. When I changed the line:

context.Stream = new BufferedStream(stream);

to

context.Stream = stream;

Which removes the buffered stream, I got the same error I was getting in Mono on Linux:

Npgsql.NpgsqlException:
connection requires a valid client certificate
Severity: FATAL
Code: 28000
em Npgsql.NpgsqlState.<ProcessBackendResponses_Ver_3>d__b.MoveNext() na C:\Us
ers\FranciscoJunior\Desenvolvimento\GitHub\dreamlax\Npgsql2\src\Npgsql\NpgsqlSta
te.cs:linha 725

So, I'm doing something wrong with this client certificate and I don't know what it is. :(

The odd thing is that this certificate works ok when I connect to postgresql using psql client.

Owner

franciscojunior commented Jul 5, 2013

Another thing I noticed is that when I connect through psql, this is logged on the server:

DEBUG:  SSL connection from "npgsql_tests"

But when I connect through Npgsql, this is what I get:

DEBUG:  SSL connection from "(anonymous)"

"npgsql_tests" seems to be the CN I put when I created the certificate. According to the how to I got, the CN name should be the same name of the database I'm trying to connect to.

@dreamlax , do you get something like that in your server logs?

dreamlax commented Jul 6, 2013

@franciscojunior sorry for the delay getting back to you, I haven't had a lot of spare time this week. Basically, I have three certificates involved, one is the client key/cert (in PFX format) installed on the client. This is loaded into an X509Certificate object and given to Npgsql to pass to the .NET's SslStream. This client cert is signed by my server.crt (this is the database cluster's cert), which in turn is signed by my trusted root CA, but I'm quite certain that the cluster's cert doesn't need to be signed by a trusted CA.

The CN of the client cert is definitely the user you are connecting as, not the database you're connecting to, but it shouldn't matter if they are the same name. I've found that the CN in your client cert must match the username you're trying to connect as in the connection string, otherwise I get pg_hba.conf errors.

One difference I have is that my pg_hba.conf uses cert for the authentication method rather than trust. I too have the clientcert=1 option but I can't find any documentation for this option.

If necessary, I can set up a separate database on my VPS that we can both use to test.

Sorry for my slowness, please let me know if you'd like to sort this out more urgently and I will try to allocate some more time for it. 😄

dreamlax commented Jul 6, 2013

Ah, here we are, here's the documentation describing clientcert. It seems this option is suitable for any hostssl line, but the cert authentication method is the one which uses the certificate for both security and authentication (and I'm guessing this is when it uses the CN of the certificate).

I have a feeling it could be to do with the X509Certificate object not containing both public and private keys (unless your .cer file does actually contain both).

Owner

franciscojunior commented Jul 8, 2013

Hi, @dreamlax . No problem about the delay. :)

Well, this is my first experience with client certificates, and so, I may be doing something wrong.

I also think the problem is about the private key. I know that when I used the psql command line utility, it asked for a private key. I simply put the key file in the same folder of the certificate and it worked ok.

So, I started my quest looking for an answer... :)

It WAS indeed a private key problem. I could confirm that when I checked X509Certificate2.HasPrivateKey and it was returning false.

After searching a lot, I found this[1] reference which talks (that) "[...] Various encryption routines in .NET require public and private key to be in Personal Information Exchange (.pfx) format.[...]"

Then, I found this stackoverflow reference[2] which has the following command to generate the pfx file:

openssl pkcs12 -inkey bob_key.pem -in bob_cert.cert -export -out bob_pfx.pfx

And it worked perfectly!

So, based on the how to I was following[3], the last part needed to make it work was the transformation to pfx above.

I'll make a post about that so others can use the step by step when working with client certificates.

Thank you very much for your feedback, @dreamlax .

[1] http://www.sparxeng.com/blog/software/x-509-self-signed-certificate-for-cryptography-in-net
[2] http://stackoverflow.com/questions/808669/convert-a-cert-pem-certificate-to-a-pfx-certificate
[3] http://www.howtoforge.com/postgresql-ssl-certificates

@franciscojunior franciscojunior added a commit that referenced this pull request Jul 17, 2013

@franciscojunior franciscojunior Merge pull request #27 from dreamlax/master
Replace Mono SslClientStream with .NET SslStream to fix SSL-related errors

Initial fix of the feature requests: 

[#1000445] Single npgsql.dll
http://pgfoundry.org/tracker/index.php?func=detail&aid=1000445&group_id=1000140&atid=593 

and

[#1005312] Remove dependency toward Mono.Security.dll
http://pgfoundry.org/tracker/index.php?func=detail&aid=1005312&group_id=1000140&atid=593
ca3e4dc

@franciscojunior franciscojunior merged commit ca3e4dc into npgsql:master Jul 17, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment