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

feat: implement support for SSL connection #24

Closed
wants to merge 2 commits into from

Conversation

thibaultcha
Copy link
Contributor

Hi,

A stab at SSL connections (#9).

Implements client-server SSL connection. We assume to be in an ngx_lua
environment, where 'tcpsock:sslhandshake()' is available. ngx_lua only
supports server authentication via 'lua_ssl_trusted_certificate'.

In plain Lua/JIT, we rely on LuaSec (the same way we rely on LuaSocket
already) and a fallback method is provided which follows the ngx_lua
method signature, plus accept LuaSec options. LuaSec allows for server
and client authentication.

An option is provided to require that the server supports SSL,
otherwise, aborts the connection, as suggested in section 43.2.9 of the
protocol flow.

New options (defaults):

{
  ssl = false,
  ssl_verify = false,
  ssl_required = false,
  cafile = nil, -- LuaSec
  cert = nil, -- LuaSec
  key = nil -- LuaSec
}

From those options, only ssl is included as a class attribute for simplicity
(is ssl is false, none of those options make sense), not sure if they should
all be there or not.

Caveats:

  • One change had to be done: the LuaSocket proxy metatable does not
    cache its original methods anymore. If it does, the old socket is
    retained from previous calls to 'send()' or 'receive()', and since
    LuaSec closes the socket when wrapping it, further calls do not
    succeed anymore.
  • Not easily testable in CI and test suite. I added a simple test,
    but ssl_required and other options are harder to test on Travis. I
    tested all options manually with Lua and ngx_lua, on a server that
    does not accept non-SSL connections.

Usage:

local pgmoon = require "pgmoon"
local pg = pgmoon.new {
  ssl = true,
  ssl_verify = true,
  ssl_required = true,
  cafile = "/path/to/ca.pem"
  -- cert
  -- key
}

assert(pg:connect())

pg:disconnect()

Let me know!

@thibaultcha
Copy link
Contributor Author

(waiting on API validation before updating the docs)

@thibaultcha
Copy link
Contributor Author

Hey @leafo, did you get any chance to take a look at this? If you have any feedback I would make the necessary changes. I hope not to be pushy! Thanks :)

@leafo
Copy link
Owner

leafo commented Mar 8, 2016

Didn't get a chance to look yet, was sick last week. Hope to do so soon, thanks.

@ahmadnassri
Copy link

hey @leafo, hope you're feeling better, let us know if there's anything we can help with on our end ;)

@leafo
Copy link
Owner

leafo commented Mar 28, 2016

sorry for the delay! (I had a confernece and got sick again...) will check this out ASAP

@thibaultcha
Copy link
Contributor Author

Sure, no problem!

I feel you, I too got sick twice this winter 😡 😷


connect: =>
@sock = socket.new!
ok, err = @sock\connect @host, @port
return nil, err unless ok

if @sock\getreusedtimes! == 0
if @ssl
success, err = @send_ssl_message!
return nil, err unless success
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when ssl_required is false and ssl is true, then send_ssl_message returns nil with no error message when the ssl connection can't be established. Probably not what you intended?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes we should return true! I added this just before submitting the patching without testing it, totally guilty.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also probably want to disconnect too if the server does not support SSL connections:

elseif @ssl_required
    @disconnect!
    nil, "the server does not support SSL connections"

Additionally, we are missing the handling of ErrorMessage responses:

The frontend should also be prepared to handle an ErrorMessage response to SSLRequest from the server. This would only occur if the server predates the addition of SSL support to PostgreSQL. In this case the connection must be closed, but the frontend might choose to open a fresh connection and proceed without requesting SSL.

Implements client-server SSL connection. We assume to be in an ngx_lua
environment, where 'tcpsock:sslhandshake()' is available. ngx_lua only
supports server authentication via 'lua_ssl_trusted_certificate'.

In plain Lua/JIT, we rely on LuaSec (the same way we rely on LuaSocket
already) and a fallback method is provided which follows the ngx_lua
method signature, plus accept LuaSec options. LuaSec allows for server
and client authentication.

An option is provided to require that the server supports SSL,
otherwise, aborts the connection.

New options (defaults):

```
{
  ssl = false,
  ssl_verify = false,
  ssl_required = false,
  cafile = nil, -- LuaSec
  cert = nil, -- LuaSec,
  key = nil -- LuaSec
}
```

Caveats:

- One change had to be done: the LuaSocket proxy metatable does not
  cache its original methods anymore. If it does, the old socket is
  retained from previous calls to 'send()' or 'receive()', and since
  LuaSec closes the socket when wrapping it, further calls do not
  succeed anymore.
- Not easily testable in CI and test suite. I added a simple test,
  but `ssl_required` and other options are harder to test on Travis. I
  tested all options manually with Lua and ngx_lua, on a server that
  does not accept non-SSL connections.
@thibaultcha
Copy link
Contributor Author

I just updated the patch, thanks for the review.

Changes:

  • Restore memoization of socket's closures. I figured the safest is to set every attached function to nil except those we override in proxy_mt. There were other ways but I think this is the cleanest/safest.
  • Handle ErrorMessage in response of an SSLRequest. As per the spec, we disconnect on such.
  • Handle the edge-case with ssl true and ssl_required false.
  • Fix a stack overflow that could occur in the proxied sslhandshake when the handshake failed and we tried to access @sock which was nil.
  • Fix the SSL test + added a new one for ssl_required. We expect a server with ssl = off for those.

When/if you're ok with this, let me know and I'll push some documentation!

@forkfork
Copy link

@thibaultcha I'm happy to write some docs if it helps to progress this PR - let me know if you want a hand.

@subnetmarco
Copy link

Any update on this PR?

@aduwadi
Copy link

aduwadi commented Jun 24, 2016

any update on this PR?

@thibaultcha
Copy link
Contributor Author

Happy to wrap this up if @leafo has any more suggestions. If everything looks good code-wise, I'll quickly provide the documentation for this!

@leafo
Copy link
Owner

leafo commented Jun 29, 2016

sorry for being MIA for so long, I got caught up with a bunch of work and have been neglecting my opensource projects.

I just tested it out and it appears to be working fine.

I wrote a basic test suite for the luasocket implementation:

https://github.com/leafo/pgmoon/blob/leafo/ssl/spec/postgres.sh
https://github.com/leafo/pgmoon/blob/leafo/ssl/spec/pgmoon_ssl_spec.moon

Everything looks good:

https://travis-ci.org/leafo/pgmoon/jobs/140978776

Only strange thing I noticed is when the socket is closed postgres prints this to the log

LOG:  could not receive data from client: Connection reset by peer

And google tells me this: https://devcenter.heroku.com/articles/postgres-logs-errors#log-unexpected-eof-on-client-connection

I'm not sure if it's worth trying to figure out, I didn't see anything obvious that might have caused it.

Anyway, I'm planning on merging everything in unless you want to look into the log message. If you want to add some docs to the readme too that would be great.

@thibaultcha
Copy link
Contributor Author

I just pushed a commit which adds some documentation about SSL connections. Trying to keep it as simple as possible yet still mention the semi-optional LuaSec dependency.

@thibaultcha
Copy link
Contributor Author

thibaultcha commented Jun 29, 2016

About the improperly-closed connection issue, I really have no clue what could be causing this and I'm not sure if this could come from LuaSec either... Nothing changed in disconnect() and we are properly using LuaSec's close()...

@leafo
Copy link
Owner

leafo commented Jul 13, 2016

Documentation changed merged, new version deployed to luarocks.org: https://luarocks.org/modules/leafo/pgmoon

Thanks for the patch, once again, sorry about being so slow. Hope it didn't interrupt anything.

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

Successfully merging this pull request may close these issues.

6 participants