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

OpenSSL additions + HTTP::Client support for more ssl options #2343

Closed
wants to merge 2 commits into from

Conversation

jeromegn
Copy link
Contributor

  • Added LibSSL functions for CA and certificate files
  • Added OpenSSL::SSL::Method from @datanoise with added SSLv3 and TLSv1
  • Allow setting OpenSSL::SSL::Method on OpenSSL::SSL::Context constructor
  • Added ssl_ methods to HTTP::Client for specifying:
    • CA file path
    • Private key file path
    • Certificate file path
    • SSL method to use

I'm in need of these changes to SSL for my Docker API client (https://github.com/jeromegn/docker.cr). For now, I've extended the various libs and classes within the shard, but I think these small changes could be beneficial to a lot of people.

I'm not entirely sure how to test these, for now I've just tested that it's possible to set ssl options on the HTTP::Client and since OpenSSL was vastly untested, I didn't bother adding more there.

I did some manual testing, with a slightly modified version of my shard and using this version of crystal's binaries and it worked.

I inspired from Ruby's Net::HTTP methods for ssl, but I don't think they were quite right and I don't think this syntax I created is quite right either. I was debating adding a lot of initialization options, but then I would've had to add them on every method initializing or calling an initializer (there are 3 of them, that got quite verbose.) So I decided to let users set the SSL options after initialization.

I also had to explicitly require "openssl" in HTTP::Client due to the property. This could probably be avoided by not specifying the type there.

My goal is to make this mergeable, so if there's anything, please let me know and I'll be happy to discuss and fix :)

  - Added LibSSL functions for CA and certificate files
  - Added OpenSSL::SSL::Method from @datanoise with added
    SSLv3 and TLSv1
  - Added ssl methods to HTTP::Client for specifying:
    - CA file path
    - Private key file path
    - Certificate file path
    - SSL method to use
@asterite
Copy link
Member

Thank you for this! We'll probably take a look at this the next week.

(Just to let you know that we saw this, just didn't have time yet because of the new releases :-))

@jeromegn
Copy link
Contributor Author

What's happening with this? I'd be happy to rebase to fix the potential merge conflicts.

However, I won't put the time if this won't be accepted. I'm not expecting this to be accepted as-is, I'm trying to raise de awareness of the OpenSSL issues in the standard library.

SSL is a very important feature.

cl.ssl_method = OpenSSL::SSL::Method::TLSv1
cl.ssl_cert_file = "/path/to/cert"
cl.ssl_key_file = "/path/to/key"
cl.ssl_ca_file = "/path/to/ca"
Copy link
Contributor

@ysbaddaden ysbaddaden Apr 16, 2016

Choose a reason for hiding this comment

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

I think this calls for a ssl accessor. Or just having: Client.new(uri, ssl_context: ctx) that can then be tweaked through client.ssl_context?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

One that allows passing an OpenSSL::SSL::Context to use for requests? I think that would make sense. I have that in my experimental docker lib: https://github.com/jeromegn/docker.cr/blob/master/src/core_ext/http/client.cr#L3-L5

@ysbaddaden
Copy link
Contributor

The current state of OpenSSL integration is very basic. It works, but should be improved, mostly to comply with better security and options.

Please see https://github.com/ysbaddaden/http2/blob/master/src/core_ext/openssl.cr for the HTTP server counterpart needed for HTTP2. It's awaiting a proper pull request.

BTW: shouldn't we default to TLS 1.2, instead of the long deprecated SSL2 and SSL3 ?

@@ -0,0 +1,18 @@
enum OpenSSL::SSL::Method
Copy link
Contributor

Choose a reason for hiding this comment

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

I"m not sure we need an enum. LibSSL::SSLMethod is already a type. Also, there are a lot more methods in OpenSSL, thought I'm sure why there are so many.

@asterite
Copy link
Member

@jeromegn Sorry, didn't have time, and I don't know much about OpenSSL to decide what's good or bad.

@ysbaddaden Since you are reviewing this, if you find these additions/changes OK, and possibly others that come in the future, you are free to merge them even without my consent because, well, you seem to know this subject very well :-)

@ysbaddaden
Copy link
Contributor

If only I knew OpenSSL very well 😭

As far as I understand: we should default to a TLS1 handshake. SSL2 is long deprecated, and SSL3 is deprecated too. I believe only TLS 1.2 is really secure, but TLS1 is still acceptable.

@jeromegn
Copy link
Contributor Author

I also believe we should not default to a deprecated SSL method :) That might fix most issues.

I'm by no means an expert with OpenSSL either. I'm learning though. I opened this to fix a very specific issue with my own library.

@ysbaddaden regarding the OpenSSL::SSL::Method enum, I thought it was preferable to hide the libs' implementation as best as possible, abstract them away into more Crystal-idiomatic ways. I've only added a few SSL methods in there because I didn't want to include much more code to support the other methods. I tried to keep this PR contained and simple.

@@ -41,4 +44,7 @@ lib LibSSL
fun ssl_ctx_use_certificate_chain_file = SSL_CTX_use_certificate_chain_file(ctx : SSLContext, file : UInt8*) : Int
fun ssl_ctx_use_privatekey_file = SSL_CTX_use_PrivateKey_file(ctx : SSLContext, file : UInt8*, filetype : SSLFileType) : Int
fun ssl_set_bio = SSL_set_bio(handle : SSL, rbio : LibCrypto::Bio*, wbio : LibCrypto::Bio*)
fun ssl_ctx_load_verify_locations = SSL_CTX_load_verify_locations(ctx: SSLContext, ca_file: UInt8*, ca_path: UInt8*) : Int32
fun ssl_ctx_use_certificate_file = SSL_CTX_use_certificate_file(ctx: SSLContext, file: UInt8*, type: Int32) : Int32
Copy link
Member

Choose a reason for hiding this comment

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

Why Int32 over Int?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No particular reason. It's been copy pasted.

@jeromegn
Copy link
Contributor Author

This code contains a lot of copy/paste from @datanoise's datanoise/openssl.cr library.

I'm not particularly well-versed in SSL stuff. I needed parts of it for my own use (that docker library,) but I only took enough to make it work.

I think Crystal needs to seriously consider a more robust SSL offering. I'm happy if anybody wants to tackle this. I'm pretty sure I'm not the person that should do it :)

@ysbaddaden
Copy link
Contributor

Closing in favor to #2671 (merged) and #2689 (soon to be merged) that are doing just that: always validate the certificates, propose good defaults (good ciphers, only enable TLS protocols), ability to set CA certificates, etc.

The approach will be a little different. Instead of having properties for the certificates, we prefer to build a OpenSSL::SSL::Context with all that information and pass it to HTTP::Client.

There is no Enum for LibSSL::SSLMethod because we (almost) always want the sslv23_method which is the OpenSSL way to say "negotiate the SSL or TLS protocol" and then disable SSLv2 and SSLv3 through options. If someone needs to specifically enable only a single protocol (I don't know why), then she may just call LibSSL.tlv1_method or another method.

@ysbaddaden ysbaddaden closed this May 30, 2016
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.

None yet

4 participants