Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Several issues related to SSL/TLS #493

Closed
roji opened this issue Feb 19, 2015 · 42 comments
Closed

Several issues related to SSL/TLS #493

roji opened this issue Feb 19, 2015 · 42 comments
Milestone

Comments

@roji
Copy link
Member

roji commented Feb 19, 2015

This issue summarizes open questions on SSL, following conversations on gitter with @Emill and other existing issues.

  1. Mono's SslStream implementation isn't amazing security-wise: lack of ciphers, perfect forward security, etc.
  2. Mono's SslStream implementation does not support SSL renegotiation well, causing an IOException after a while (see Remove set ssl_renegotiation_limit to 0? #380).
  3. The SslStream API (Microsoft or mono) does not have a DataAvailable property like NetworkStream, but our current async notifications depend on this.

One (extreme?) option to address the above, is to drop the built-in SslStream and move to another implementation.

Following the open sourcing of .NET, Mono seem to be actively working on replacing their SslStream implementation with Microsoft's. If and when that happens, problems 1 and 2 will go away.

Unless I've missed other problems/concerns, my vote would be to keep SslStream as is. We would need to find a solution for problem 3, but aside from that I see the 1 and 2 as outside of Npgsql's problem field (and probable to go away soon anyway).

If we do decide to keep SslStream, we need to do two things:

@roji roji added this to the 3.0 milestone Feb 19, 2015
@franciscojunior
Copy link
Member

One (extreme?) option to address the above, is to drop the built-in SslStream and move to another implementation.

My only concern about this option would be the added dependency.

Unless I've missed other problems/concerns, my vote would be to keep SslStream as is. We would need to find a solution for problem 3, but aside from that I see the 1 and 2 as outside of Npgsql's problem field (and probable to go away soon anyway).

+1

#380: Send ssl_renegotiation_limit only if using SSL, and only if running on mono (runtime check).

We already have a partial patch for that: #453. I'll rebase it and add the runtime check for mono.

#127: Remove Mono.Security (which is mono's SslStream) as a dependency of Npgsql. We simply use SslStream everywhere, and get the Microsoft or mono implementation.

+1 That's the idea for release 3.0

@Emill
Copy link
Contributor

Emill commented Feb 21, 2015

Since this commit: postgres/postgres@272923a, Microsoft's SslStream also breaks on renegotiation.

@roji
Copy link
Member Author

roji commented Feb 22, 2015

IMHO PostgreSQL should be aware that this breaks SslStream and possibly revert this change?

@Emill
Copy link
Contributor

Emill commented Feb 22, 2015

I sent a mail to pgsql-hackers about that yesterday. Due to a bug in openssl, jdbc renegotiation doesn't work currently either.

@Emill
Copy link
Contributor

Emill commented Feb 24, 2015

Hi guys, I created a branch at https://github.com/Emill/Npgsql/tree/tls-client-stream containing my implementation. It should fix all the problems mentioned above...

It supports a quite comprehensive collection of cipher suites: https://github.com/Emill/Npgsql/blob/tls-client-stream/Npgsql/TlsClientStream/CipherSuiteInfo.cs, much more than I had thought of before I started this :)

It uses Microsoft's crypto API as much as possible, but you can't imagine how old that is by almost only supporting old ciphers.

It currently has no async support, but should be very easy to add using the AsyncGenerator.

I know it's kind of strange to include a full-blown TLS client implementation in a database driver, but what the heck ;)
It only takes up about 14% of the resulting Npgsql.dll.

Try it out and see if it works.

@franciscojunior
Copy link
Member

That's awesome, @Emill ! You rock!
I'll give it a try and let you know.
Thank you very much for your contribution!

I think you should definitely create a project to host this gem. I'm sure a lot of people out there would like to use your tls library. Another option would be to contribute it to the .net core so everybody in the ms.net and mono platforms can use it. ;)

@roji
Copy link
Member Author

roji commented Feb 25, 2015

Wow @Emill, you really went ahead with it...! :)

I'll try to take a look soon (am a bit busy lately with other things). @franciscojunior's suggestion makes sense to me, about creating it as a separate project.

Unless I'm mistaken, there's no way to cover the different ciphers with tests, right? I mean, there's one test that connects with SSL, but actually testing different ciphers requires backend-side configuration?

@Emill
Copy link
Contributor

Emill commented Feb 25, 2015

Correct. You must configure the server and set certificate. You can only have one certificate at a time so you have to restart the server to change cert. There can be both rsa, dsa and ecdsa certs. There is also the possibility for client certificate requests, which you can set a CA cert for in postgresql config.

@Emill
Copy link
Contributor

Emill commented Feb 25, 2015

I think it's easier to test it against a separate raw SslStream in server mode where one can specify different certificates programmatically.

@franciscojunior
Copy link
Member

Hi @Emill !

I just tried it here but I got a problem when connecting:

Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance of an object
  at TlsClientStream.ConnectionState.get_IvLen () [0x00002] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/ConnectionState.cs:33 
  at TlsClientStream.TlsClientStream.WriteAlertFatal (AlertDescription description) [0x0002a] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:1426 
  at TlsClientStream.TlsClientStream.PerformInitialHandshake (System.String hostName, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Net.Security.RemoteCertificateValidationCallback remoteCertificateValidationCallback) [0x000c2] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:1560 
  at (wrapper remoting-invoke-with-check) TlsClientStream.TlsClientStream:PerformInitialHandshake (string,System.Security.Cryptography.X509Certificates.X509CertificateCollection,System.Net.Security.RemoteCertificateValidationCallback)
  at Npgsql.NpgsqlConnector.RawOpen (Int32 timeout) [0x001fb] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/NpgsqlConnector.cs:516 
  at Npgsql.NpgsqlConnector.Open () [0x00045] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/NpgsqlConnector.cs:346 
  at Npgsql.NpgsqlConnectorPool.GetPooledConnector (Npgsql.NpgsqlConnection Connection) [0x0019a] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/NpgsqlConnectorPool.cs:330 
[ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException: Object reference not set to an instance of an object
  at TlsClientStream.ConnectionState.get_IvLen () [0x00002] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/ConnectionState.cs:33 
  at TlsClientStream.TlsClientStream.WriteAlertFatal (AlertDescription description) [0x0002a] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:1426 
  at TlsClientStream.TlsClientStream.PerformInitialHandshake (System.String hostName, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Net.Security.RemoteCertificateValidationCallback remoteCertificateValidationCallback) [0x000c2] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:1560 
  at (wrapper remoting-invoke-with-check) TlsClientStream.TlsClientStream:PerformInitialHandshake (string,System.Security.Cryptography.X509Certificates.X509CertificateCollection,System.Net.Security.RemoteCertificateValidationCallback)
  at Npgsql.NpgsqlConnector.RawOpen (Int32 timeout) [0x001fb] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/NpgsqlConnector.cs:516 
  at Npgsql.NpgsqlConnector.Open () [0x00045] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/NpgsqlConnector.cs:346 
  at Npgsql.NpgsqlConnectorPool.GetPooledConnector (Npgsql.NpgsqlConnection Connection) [0x0019a] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/NpgsqlConnectorPool.cs:330 

I even tried to add a check for null in this accessor and return 0 and then 8. After doing this change, I got this error:

Unhandled Exception:
System.IO.IOException: ProtocolVersion ---> TlsClientStream.ClientAlertException: ProtocolVersion
  at TlsClientStream.TlsClientStream.SendAlertFatal (AlertDescription description, System.String message) [0x00003] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:1418 
  at TlsClientStream.TlsClientStream.ParseServerHelloMessage (System.Byte[] buf, System.Int32& pos, Int32 endPos) [0x00046] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:716 
  at TlsClientStream.TlsClientStream.TraverseHandshakeMessages () [0x00083] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:361 
  at TlsClientStream.TlsClientStream.GetInitialHandshakeMessages (Boolean allowApplicationData) [0x000c0] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:335 
  at TlsClientStream.TlsClientStream.PerformInitialHandshake (System.String hostName, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Net.Security.RemoteCertificateValidationCallback remoteCertificateValidationCallback) [0x0007f] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:1548 
  --- End of inner exception stack trace ---
  at TlsClientStream.TlsClientStream.PerformInitialHandshake (System.String hostName, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Net.Security.RemoteCertificateValidationCallback remoteCertificateValidationCallback) [0x000dc] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:1561 
  at (wrapper remoting-invoke-with-check) TlsClientStream.TlsClientStream:PerformInitialHandshake (string,System.Security.Cryptography.X509Certificates.X509CertificateCollection,System.Net.Security.RemoteCertificateValidationCallback)
  at Npgsql.NpgsqlConnector.RawOpen (Int32 timeout) [0x001fb] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/NpgsqlConnector.cs:516 
  at Npgsql.NpgsqlConnector.Open () [0x00045] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/NpgsqlConnector.cs:346 
  at Npgsql.NpgsqlConnectorPool.GetPooledConnector (Npgsql.NpgsqlConnection Connection) [0x0019a] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/NpgsqlConnectorPool.cs:330 
[ERROR] FATAL UNHANDLED EXCEPTION: System.IO.IOException: ProtocolVersion ---> TlsClientStream.ClientAlertException: ProtocolVersion
  at TlsClientStream.TlsClientStream.SendAlertFatal (AlertDescription description, System.String message) [0x00003] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:1418 
  at TlsClientStream.TlsClientStream.ParseServerHelloMessage (System.Byte[] buf, System.Int32& pos, Int32 endPos) [0x00046] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:716 
  at TlsClientStream.TlsClientStream.TraverseHandshakeMessages () [0x00083] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:361 
  at TlsClientStream.TlsClientStream.GetInitialHandshakeMessages (Boolean allowApplicationData) [0x000c0] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:335 
  at TlsClientStream.TlsClientStream.PerformInitialHandshake (System.String hostName, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Net.Security.RemoteCertificateValidationCallback remoteCertificateValidationCallback) [0x0007f] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:1548 
  --- End of inner exception stack trace ---
  at TlsClientStream.TlsClientStream.PerformInitialHandshake (System.String hostName, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Net.Security.RemoteCertificateValidationCallback remoteCertificateValidationCallback) [0x000dc] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/TlsClientStream/TlsClientStream.cs:1561 
  at (wrapper remoting-invoke-with-check) TlsClientStream.TlsClientStream:PerformInitialHandshake (string,System.Security.Cryptography.X509Certificates.X509CertificateCollection,System.Net.Security.RemoteCertificateValidationCallback)
  at Npgsql.NpgsqlConnector.RawOpen (Int32 timeout) [0x001fb] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/NpgsqlConnector.cs:516 
  at Npgsql.NpgsqlConnector.Open () [0x00045] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/NpgsqlConnector.cs:346 
  at Npgsql.NpgsqlConnectorPool.GetPooledConnector (Npgsql.NpgsqlConnection Connection) [0x0019a] in /Users/fxjr/Desenvolvimento/ProjetosOpenSource/Npgsql/Tests/NpgsqlSimpleTests/SSL/RenegotiationProblem/test2/githubemill/Npgsql/Npgsql/NpgsqlConnectorPool.cs:330 

I hope those stacktraces can be helpful.

@Emill
Copy link
Contributor

Emill commented Feb 25, 2015

Hi. It seems you are using an old version of openssl that does not support TLS 1.2 for your postgresql server?
TLS 1.2 was released in 2008 so I assumed most distros supported that ...
I think openssl supports tls 1.2 since openssl 1.0.1.

@franciscojunior
Copy link
Member

I'm using openssl from osx.

Indeed, from this log I get when I use an old Npgsql.dll library which connects to the server, it seems to be using tlsv1:

LOG:  connection authorized: user=npgsql_tests database=npgsql_tests SSL enabled (protocol=TLSv1, cipher=AES256-SHA, compression=off)

This is the openssl version I'm using:

openssl 
OpenSSL> version
OpenSSL 0.9.8za 5 Jun 2014
OpenSSL> 

@franciscojunior
Copy link
Member

According to this post:
http://apple.stackexchange.com/questions/126830/how-to-upgrade-openssl-in-os-x

It seems the 0.9.8za is the official openssl version in osx which doesn't contain the heartbleed bug.

@Emill
Copy link
Contributor

Emill commented Feb 25, 2015

Hmm. I have no idea why Apple bundle such an old version (0.9.8 was released in 2005) in their OS...
Maybe I could make it TLS 1.0 compatible as well, I don't think there are that big changes.

@franciscojunior
Copy link
Member

Hmm. I have no idea why Apple bundle such an old version (0.9.8 was released in 2005) in their OS...
According to this link: www.eweek.com/security/apple-os-x-10.10.2-bashes-bugs.html
latest apple update 10.10.2 (which I don't have. I'm still using 10.10), openssl is updated to 0.9.8zc.

Maybe I could make it TLS 1.0 compatible as well, I don't think there are that big changes.

Great! This will make it even better for osx users. :)

@Emill
Copy link
Contributor

Emill commented Feb 25, 2015

I wonder however how many people there are running postgresql on their osx computer and wants to use encrypted connection. Probably those people run Npgsql over localhost anyway ...

@franciscojunior
Copy link
Member

I wonder however how many people there are running postgresql on their osx computer and wants to use encrypted connection. Probably those people run Npgsql over localhost anyway ...

Good point! :)

I think you can leave it as it is for now. I'll test it now connecting from my windows vm.
I'll let you know how it works.

@franciscojunior
Copy link
Member

This is what I get when running on windows:


Unhandled Exception: System.IO.IOException: Unable to write data to the transpor
t connection: An existing connection was forcibly closed by the remote host. ---
> System.Net.Sockets.SocketException: An existing connection was forcibly closed
 by the remote host
   at System.Net.Sockets.Socket.Send(Byte[] buffer, Int32 offset, Int32 size, So
cketFlags socketFlags)
   at System.Net.Sockets.NetworkStream.Write(Byte[] buffer, Int32 offset, Int32
size)
   --- End of inner exception stack trace ---
   at System.Net.Sockets.NetworkStream.Write(Byte[] buffer, Int32 offset, Int32
size)
   at TlsClientStream.TlsClientStream.Flush()
   at Npgsql.NpgsqlBuffer.Flush()
   at Npgsql.NpgsqlConnector.Open()
   at Npgsql.NpgsqlConnectorPool.GetPooledConnector(NpgsqlConnection Connection)

   at Npgsql.NpgsqlConnectorPool.RequestConnector(NpgsqlConnection Connection)
   at Npgsql.NpgsqlConnection.Open()
   at npgsqltest.NpgsqlTest.Main(String[] args) in z:\sslrenegotiationtest\temp\
teste.cs:line 31

And this is what the server logs:

DEBUG:  forked new backend, pid=16452 socket=1280
LOG:  connection received: host=::1 port=1958
LOG:  could not accept SSL connection: decryption failed or bad record mac`

I even recreated the server certificate in the windows server thinking this could be the problem cause.

@Emill
Copy link
Contributor

Emill commented Feb 25, 2015

Hmm.. Could you add this:

Console.Out.WriteLine(cipherSuite);

to TlsClientStream.cs line 735
to get what Cipher suite is used?

@franciscojunior
Copy link
Member

TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

Note that when I use the old version of Npgsql.dll which connects to the host, it also says it is using tlsv1. I don't know if this is relevant though. I hope it helps.

@Emill
Copy link
Contributor

Emill commented Feb 25, 2015

Ahh.. Found the problem. I thought I had double-checked the cipher suite definition list...
Try the latest pushed revision.

@franciscojunior
Copy link
Member

Success!! :)

LOG:  connection received: host=::1 port=1965
DEBUG:  SSL connection from "(anonymous)"
LOG:  connection authorized: user=npgsql_tests database=npgsql_tests SSL enabled
 (protocol=TLSv1.2, cipher=ECDHE-RSA-AES256-GCM-SHA384, compression=off)

I also can confirm that the ssl renegotiation error doesn't occur.

You rock, @Emill !! :)

@Emill
Copy link
Contributor

Emill commented Feb 25, 2015

Yeah, nice :)

@franciscojunior
Copy link
Member

I remember when I was in my graduation course and EC were something theoretical and now, more than a decade and a half later, Npgsql is able to use it to cipher its communications... :)

@Emill
Copy link
Contributor

Emill commented Feb 26, 2015

It seems to be a bit more complicated to add support for TLS 1.0 than I thought. TLS 1.0 uses the concatenation of an MD5-hash and a SHA1-hash when verifying or signing data with RSA, but the .NET RSACryptoServiceProvider does not support that.

@franciscojunior
Copy link
Member

I've made some more tests with npgsql to check how the notifications problem #270 is going with the current code.

I can confirm that current master npgsql code indeed fixes the problem.
Notifications are being properly handled.
I used the code in this old bug report:
http://pgfoundry.org/tracker/index.php?func=detail&aid=1011374&group_id=1000140&atid=590

I also could test if it is working in when SSL is on and using @Emill branch, it worked perfectly. Which means support for checking if there is data in the SSL stream implemented by @Emill is working as intended.

Note that current master branch has problems with SSL code. It doesn't connect :-(

@roji
Copy link
Member Author

roji commented Feb 28, 2015

Hey guys, sorry but I was out of the loop for a while...

@Emill, that's pretty amazing work. Here are some thoughts:

  • I still think it's worth thinking hard before actually switching to an alternative SSL/TLS implementation. With Microsoft's SslStream entering into mono soon, the only actual issue we have is the lack of a DataAvailable-like feature, and that could actually be contributed to .NET Core. Admittedly that's still a long way off, and in the meanwhile we'd need a workaround for async notifications - and unfortunately I don't have much time to contribute on that. But if you guys think this is the way to go I'm also good with that...
  • I still think it makes sense to take your code out of Npgsql and setting it up as an external project, with its own nuget and everything. It's true that it would mean an external dependency for Npgsql, but it's not worse than the current situation (with Mono.Security) and would allow other projects to use it etc.
  • IMHO The OSX bundling such an old version of openssl is very disappointing, but not allowing Npgsql to connect securely to OSX-hosted Postgresql seems like a blocker to me.
  • Another comment is that it's worth setting up a serious test suite against, say, openssl, testing the various ciphers etc.

@franciscojunior
Copy link
Member

Hi, @roji !

I still think it's worth thinking hard before actually switching to an alternative SSL/TLS implementation. With Microsoft's SslStream entering into mono soon, the only actual issue we have is the lack of a DataAvailable-like feature, and that could actually be contributed to .NET Core. Admittedly that's still a long way off, and in the meanwhile we'd need a workaround for async notifications - and unfortunately I don't have much time to contribute on that. But if you guys think this is the way to go I'm also good with that...

The only issue I see with that would be regarding the maintenance of the code. If later someone points out the code has an error or something like that, what would we do if @Emill isn't around? :)

On the other side, it would be very nice if sslstream could have something like the dataavailable feature. I don't know how easy this would be to implement in microsoft's sslstream and if they would accept a patch for this.

I still think it makes sense to take your code out of Npgsql and setting it up as an external project, with its own nuget and everything. It's true that it would mean an external dependency for Npgsql, but it's not worse than the current situation (with Mono.Security) and would allow other projects to use it etc.

I'm still more inclined to include the code inside Npgsql for the only reason of removing the dependency of Mono.Security or any other library. In fact, Npgsql already contains md5 code for authentication we got from Mono project. If Mono.Security code was easily "importable", I think today we would have it inside Npgsql as well. :)

I also have to admit that I don't know very well how is the current deploying scenario. I'm basing myself in the past where developers and administrators would have to install the libraries manually and also on the reports we received to remove the dependency on other libraries to facilitate Npgsql deployment.
Maybe today things are much simpler and if they can simple type a single command and forget about it and in the end they have Npgsql and everything setup, I think there wouldn't be any problem.
I think the most complex scenario would be users having to install the assemblies in the GAC and configuring Npgsql to run DDEX in visual studio. But I think this can be solved with @kenjiuno's installer. :)

IMHO The OSX bundling such an old version of openssl is very disappointing, but not allowing Npgsql to connect securely to OSX-hosted Postgresql seems like a blocker to me.

I also think this is very critical. I think @Emill has a very good point as I think very few users would have osx as hosts for postgresql connecting with ssl. But I also think it wouldn't be nice to release a version lacking this support. :(
Maybe @Emill can make his library work with tls1.1 ;) ;)

@Emill
Copy link
Contributor

Emill commented Feb 28, 2015

Actually I set up a copy here: https://github.com/Emill/TlsClientStream

I also think this is very critical. I think @Emill has a very good point as I think very few users would have osx as hosts for postgresql connecting with ssl. But I also think it wouldn't be nice to release a version lacking this support. :(
Maybe @Emill can make its library work with tls1.1 ;) ;)

Ok, I'll add support for TLS 1.0 (OpenSSL implemented 1.1 and 1.2 at the same time).
Just have to do the RSA-math myself instead of using RSACryptoProvider.

@Emill
Copy link
Contributor

Emill commented Mar 1, 2015

Ok, I have now implemented support for TLS 1.0 and 1.1 in my branch :)
@franciscojunior, could you try it out on Mac OS X?

@franciscojunior
Copy link
Member

Hi, @Emill !

Just tested it here and it gives me this error:

Unhandled Exception:
System.IO.EndOfStreamException: Failed to read past end of stream.
  at Npgsql.NpgsqlBuffer.Ensure (Int32 count) [0x00000] in <filename unknown>:0 
  at Npgsql.NpgsqlBuffer.EnsureOrAllocateTemp (Int32 count) [0x00000] in <filename unknown>:0 
  at Npgsql.NpgsqlConnector.DoReadSingleMessage (DataRowLoadingMode dataRowLoadingMode, Boolean ignoreNotifications) [0x00000] in <filename unknown>:0 
  at Npgsql.NpgsqlConnector.ReadSingleMessage (DataRowLoadingMode dataRowLoadingMode, Boolean ignoreNotifications) [0x00000] in <filename unknown>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.IO.EndOfStreamException: Failed to read past end of stream.
  at Npgsql.NpgsqlBuffer.Ensure (Int32 count) [0x00000] in <filename unknown>:0 
  at Npgsql.NpgsqlBuffer.EnsureOrAllocateTemp (Int32 count) [0x00000] in <filename unknown>:0 
  at Npgsql.NpgsqlConnector.DoReadSingleMessage (DataRowLoadingMode dataRowLoadingMode, Boolean ignoreNotifications) [0x00000] in <filename unknown>:0 
  at Npgsql.NpgsqlConnector.ReadSingleMessage (DataRowLoadingMode dataRowLoadingMode, Boolean ignoreNotifications) [0x00000] in <filename unknown>:0 

And this is what I get in the server logs:

LOG:  connection received: host=127.0.0.1 port=57110
DEBUG:  SSL connection from "(anonymous)"
LOG:  SSL error: wrong version number
LOG:  could not receive data from client: Connection reset by peer

I hope this information is useful.

@Emill
Copy link
Contributor

Emill commented Mar 2, 2015

Hmm. It worked on all servers using tls 1.0 at least that I tested...
Could you possibly change at the top of the TlsClientStream.cs file change
the constant maximum supported tls version to TLSv1_0? But that would be
very strange if that works. I'll try to find a Macintosh to test on.
Den 2 mar 2015 03:35 skrev "Francisco Figueiredo Jr." <
notifications@github.com>:

Hi, @Emill https://github.com/Emill !

Just tested it here and it gives me this error:

Unhandled Exception:
System.IO.EndOfStreamException: Failed to read past end of stream.
at Npgsql.NpgsqlBuffer.Ensure (Int32 count) [0x00000] in :0
at Npgsql.NpgsqlBuffer.EnsureOrAllocateTemp (Int32 count) [0x00000] in :0
at Npgsql.NpgsqlConnector.DoReadSingleMessage (DataRowLoadingMode dataRowLoadingMode, Boolean ignoreNotifications) [0x00000] in :0
at Npgsql.NpgsqlConnector.ReadSingleMessage (DataRowLoadingMode dataRowLoadingMode, Boolean ignoreNotifications) [0x00000] in :0
[ERROR] FATAL UNHANDLED EXCEPTION: System.IO.EndOfStreamException: Failed to read past end of stream.
at Npgsql.NpgsqlBuffer.Ensure (Int32 count) [0x00000] in :0
at Npgsql.NpgsqlBuffer.EnsureOrAllocateTemp (Int32 count) [0x00000] in :0
at Npgsql.NpgsqlConnector.DoReadSingleMessage (DataRowLoadingMode dataRowLoadingMode, Boolean ignoreNotifications) [0x00000] in :0
at Npgsql.NpgsqlConnector.ReadSingleMessage (DataRowLoadingMode dataRowLoadingMode, Boolean ignoreNotifications) [0x00000] in :0

And this is what I get in the server logs:

LOG: connection received: host=127.0.0.1 port=57110
DEBUG: SSL connection from "(anonymous)"
LOG: SSL error: wrong version number
LOG: could not receive data from client: Connection reset by peer

I hope this information is useful.


Reply to this email directly or view it on GitHub
#493 (comment).

@Emill
Copy link
Contributor

Emill commented Mar 2, 2015

Hi again. I downloaded both the EnterpriseDB installer version of
PostgreSQL and Postgres.app, both seems to bundle a version of an ssl
library that supports TLS 1.2 (which works).
What bundling are you using? Or did you compile from source?

@Emill
Copy link
Contributor

Emill commented Mar 2, 2015

I also tried to compile from source, and it indeed used the system version of openssl then (that only supports TLS 1.0). However, it worked perfectly...
My OpenSSL version is 0.9.8y.

@franciscojunior
Copy link
Member

Hi, @Emill !

I compile from source downloading the source code from postgresql.org. I pass the option --with-ssl to ./configure when compiling.

I'll try again when I get back home and let you know what I get.
I'll double check that I'm using a correct Npgsql.dll assembly with your latest fixes.

@Emill
Copy link
Contributor

Emill commented Mar 2, 2015

I found two other problems with how the ssl/tls stream is managed by Npgsql.

  1. By registering a callback that validates server certificates to the ssl stream, the internal checks (certificate validity) are ignored but passed on to the callback. Now we simply return true if the user didn't specify any validation callback. (so there are totally two callbacks involved here, one in npgsql code and one in user code. The one in npgsql code calls the user's). So if the certificate is invalid for some reason, for example expired, bad hostname or is not trusted, we accept it anyway, which might be bad. If the user didn't specify a callback, we should check the policy errors argument.
  2. Renegotiations might happen while the connection is closed but the connector is in the connector pool (happened for me when I was testing around by accident). But we have unregistered the user's callbacks before sending the "DISCARD ALL" query. So if a renegotiations happen at that time and a certificate is to be validated, we currently just return false (do not accept certificate), so the connection will be closed. That might not be a problem since an exception will be thrown and the connector pool simply marks such a connection as broken. Is there a better way, like unregister the callback after DISCARD ALL has been sent?

@franciscojunior
Copy link
Member

Hi, @Emill .
As I suspected, I did something wrong :) I had to clone your repository again and forgot to change to the tls-client-stream branch :)

I tested it here and it worked perfectly!
I also tested the synchronous notification and it worked ok too.

@franciscojunior
Copy link
Member

By registering a callback that validates server certificates to the ssl stream, the internal checks (certificate validity) are ignored but passed on to the callback. Now we simply return true if the user didn't specify any validation callback. (so there are totally two callbacks involved here, one in npgsql code and one in user code. The one in npgsql code calls the user's). So if the certificate is invalid for some reason, for example expired, bad hostname or is not trusted, we accept it anyway, which might be bad. If the user didn't specify a callback, we should check the policy errors argument.

Agreed.

Renegotiations might happen while the connection is closed but the connector is in the connector pool (happened for me when I was testing around by accident). But we have unregistered the user's callbacks before sending the "DISCARD ALL" query. So if a renegotiations happen at that time and a certificate is to be validated, we currently just return false (do not accept certificate), so the connection will be closed. That might not be a problem since an exception will be thrown and the connector pool simply marks such a connection as broken. Is there a better way, like unregister the callback after DISCARD ALL has been sent?

I think there is no problem with this inversion.

@roji
Copy link
Member Author

roji commented Mar 22, 2015

@Emill pretty much finished this.

Keeping open since we want to move the setting of ssl_renegotiation_limit=0 to the startup packet, this way DISCARD ALL won't reset it to 512MB. This also has the performance advantage of eliminating an additional roundtrip on connection.

The only issue is older databases which don't support this parameter (e.g. redshift), meaning we have no choice but to go back to a CompatibilityMode=redshift connection string parameter.

@roji
Copy link
Member Author

roji commented Mar 23, 2015

Moved ssl_renegotiation_limit to the startup packet in de716be.

@roji roji closed this as completed Mar 23, 2015
@roji roji modified the milestones: 3.0, 3.0-beta1 Mar 30, 2015
@roji roji modified the milestones: 3.0-beta1, 3.0 Aug 7, 2015
@JoeStrout
Copy link

Could all this be behind the troubles I'm having with CngKeyBlobFormat.cs (#962)? (Sorry for the dumb questions — you all understand this stuff far better than I do.)

@roji
Copy link
Member Author

roji commented Apr 4, 2016

@JoeStrout nope, this is totally unrelated to your issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants