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

Set session id context while creating SSLContext #2633

Merged
merged 1 commit into from Jun 4, 2021

Conversation

onlined
Copy link
Contributor

@onlined onlined commented May 21, 2021

When using client certificates, session id context needs to be set. OpenSSL documentation covers it like this:

If the session id context is not set on an SSL/TLS server and client
certificates are used, stored sessions will not be reused but a fatal
error will be flagged and the handshake will fail.

Details: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_session_id_context.html

Ruby OpenSSL wrapper conforms to this by setting the session id context to a random sequence of bytes whenever a context is created:
http://github.com/ruby/openssl/blob/master/lib/openssl/ssl.rb#L493

I am open to suggestions about generating random bytes. I feel like there can be a better way than this.

  • I have reviewed the guidelines for contributing to this repository.
  • I have added (or updated) appropriate tests if this PR fixes a bug or adds a feature.
  • My pull request is 100 lines added/removed or less so that it can be easily reviewed.
  • If this PR doesn't need tests (docs change), I added [ci skip] to the title of the PR.
  • If this closes any issues, I have added "Closes #issue" to the PR description or my commit messages.
  • I have updated the documentation accordingly.
  • All new and existing tests passed, including Rubocop.

@nateberkopec nateberkopec added ssl waiting-for-review Waiting on review from anyone labels May 21, 2021
@onlined onlined force-pushed the set-session-id-context branch 3 times, most recently from c45bccf to ddc2115 Compare May 23, 2021 08:06
When using client certificates, session id context needs to be set.
OpenSSL documentation covers it like this:

If the session id context is not set on an SSL/TLS server and client
certificates are used, stored sessions will not be reused but a fatal
error will be flagged and the handshake will fail. Details:
https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_session_id_context.html

Ruby OpenSSL wrapper conforms to this by setting the session id context
to a random sequence of bytes whenever a context is created:
http://github.com/ruby/openssl/blob/master/lib/openssl/ssl.rb#L493

I am open to suggestions about generating random bytes. I feel like
there can be a better way than this.
@nateberkopec
Copy link
Member

Probably should just generate the randomness in C rather than get Ruby involved at all.

Fancy taking a stab at fixing this in the Java extension as well?

@nateberkopec nateberkopec added waiting-for-changes Waiting on changes from the requestor and removed waiting-for-review Waiting on review from anyone labels May 27, 2021
@onlined
Copy link
Contributor Author

onlined commented May 27, 2021

I had thought about generating the randomness in C, but using rand wouldn't be a good way IMO. rand uses a global seed, which can be set by srand (not setting the seed is equivalent to setting it 1). If I set the seed with srand, that's mutating global state of Ruby interpreter and can cause problems (now or in the future). If I don't set it, rand will always give the same random numbers, which is not that different than setting the bytes to a constant value.

A useful option could have been using RAND_bytes from OpenSSL, but success isn't guaranteed with it, so we'd need to handle the failure case.

I can see two ways after eliminating these:

  1. Calling BCryptGenRandom on Windows and reading /dev/urandom on Linux or macOS. An alternative to using /dev/urandom on Linux or macOS is using POSIX (more general than Linux or macOS) rand_r which takes its own seed and modifies it (so no messing with global state). This solution will require maintenance when a new platform is introduced.
  2. Using Ruby for generating random numbers, and that's what I did exactly.

@onlined
Copy link
Contributor Author

onlined commented May 28, 2021

For Java implementation, I checked jruby-openssl, but I saw that we cannot set session id context from Java: https://github.com/jruby/jruby-openssl/blob/master/src/main/java/org/jruby/ext/openssl/SSLContext.java#L447. I'm not sure, but I think it probably happens automatically with Java SSL library. Even if it's not, it should be fixed at Java SSL library or Puma should switch to another SSL implementation for JRuby. So, I think the Java part, which is either nothing or great effort, is out of scope of this PR.

Copy link
Member

@evanphx evanphx left a comment

Choose a reason for hiding this comment

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

Could we clarify which versions of ruby Random::DEFAULT.bytes was first introduced?

@MSP-Greg
Copy link
Member

Works in ruby 2.0.0p648 (2015-12-16) [x64-mingw32]

@nateberkopec nateberkopec added waiting-for-review Waiting on review from anyone and removed waiting-for-changes Waiting on changes from the requestor labels May 28, 2021
@nateberkopec nateberkopec merged commit ef1a9f5 into puma:master Jun 4, 2021
@MSP-Greg
Copy link
Member

MSP-Greg commented Jun 9, 2021

@onlined

This is messy. I recall that TLSv1.3 may handle session reuse differently that older protocols. I haven't had time to review docs to see if that is correct.

the handshake will fail

Have you seen that happen with Puma? I don't think there are any tests dealing with multiple requests from one client connection where 'client certificates are used'... Haven't had time to create one locally...

@onlined
Copy link
Contributor Author

onlined commented Jun 11, 2021

@MSP-Greg It happened with our backend using Puma and client cert authentication. This fixed solved the problem.

@nateberkopec
Copy link
Member

It's in the docs on that ssl context id function @MSP-Greg - will hold on a release until you review though

@MSP-Greg
Copy link
Member

MSP-Greg commented Jun 11, 2021

@onlined Thanks. I suspected as much, as you wouldn't really have a reason for the PR...

@nateberkopec This is fine, but it will need to change to fix the deprecated warnings in Ruby 3.

I haven't had time to look at it, maybe set the value (instance variable) in the Ruby code in Puma::MiniSSL::Server#initialize, and then set it in the real Context in the c code in Puma::MiniSSL::SSLContext#initialize. That would leave the 'random' code as ruby, not c.

This only happens when the server sockets/listeners are created, so 'ruby vs c' probably isn't critical.

@onlined
Copy link
Contributor Author

onlined commented Jun 11, 2021

Replacing rb_const_get(rb_cRandom, rb_intern_const("DEFAULT")) with rb_funcall(rb_cRandom, rb_intern_const("new"), 0) can be a quick win (it works on all supported versions and is not deprecated on Ruby 3) instead of assigning a global variable in Ruby code and accessing it in C. BTW, I would have preferred (actually I tried it first) Random.bytes instead Random::DEFAULT.bytes but the former doesn't exist in former Ruby versions.

@nateberkopec
Copy link
Member

Oh this will actually warn on Ruby 3? Didn't realize that... we do need to fix that.

@MSP-Greg
Copy link
Member

@onlined & @nateberkopec

Please have a look at PR #2642, which removes the warnings...

@MSP-Greg MSP-Greg added bug and removed waiting-for-review Waiting on review from anyone labels Jun 11, 2021
MSP-Greg added a commit to MSP-Greg/puma that referenced this pull request Feb 13, 2022
MSP-Greg added a commit to MSP-Greg/puma that referenced this pull request Feb 13, 2022
nateberkopec pushed a commit that referenced this pull request Feb 16, 2022
* Actions - add Ruby 3.0 and 3.1

* .gitignore - add entry for local use

* test_puma_server_ssl.rb - backport fix

888b0213f11

* minissl.c and extconf.rb - backport fixes

Fixes from PR's:
#2535
#2633
#2642
JuanitoFatas pushed a commit to JuanitoFatas/puma that referenced this pull request Sep 9, 2022
When using client certificates, session id context needs to be set.
OpenSSL documentation covers it like this:

If the session id context is not set on an SSL/TLS server and client
certificates are used, stored sessions will not be reused but a fatal
error will be flagged and the handshake will fail. Details:
https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_session_id_context.html

Ruby OpenSSL wrapper conforms to this by setting the session id context
to a random sequence of bytes whenever a context is created:
http://github.com/ruby/openssl/blob/master/lib/openssl/ssl.rb#L493

I am open to suggestions about generating random bytes. I feel like
there can be a better way than this.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants