Add preverify_ok and X509_STORE_CTX to verify_peer#956
Conversation
fbe9b7d to
c6e63f6
Compare
|
Thank you! |
c6e63f6 to
39e1a5d
Compare
|
FYI: I just force-pushed a tiny fix to tests. Replaced a |
|
@nevans I think |
|
@MSP-Greg yeah, you're right. I hadn't checked to see how far back EM is maintaining support! Although the last time tried, I wasn't even able to compile some of the older versions, specifically because of OpenSSL library versions (IIRC). I see the gemspec is set to 2.0.0, maybe that should be updated to 2.2 to match CI? And I just now looked into the gh action repo to see if I could just grab one of those images and put it into docker, and I saw this:
IMO, that might be a good reason to drop support for older rubies! 😉 |
The main people involved in I'm not the best person to ask about 'old Ruby support', but if it currently works, I've always been inclined to leave it included. I'll see if it works in my fork... I'm aware of the OpenSSL EOL issue, and I do wonder why people don't want to/can't update their apps. I suppose it does support TLS 1.2, sort of... |
|
I'd like to make some other changes to the API, to give access to error (Integer), error_string, depth, maybe even IMO, it's a real pain in the neck to debug issues if you don't have all of that. I'll update this PR hopefully some time later this week or weekend with my proposed API. In the meantime, I have an bigger experimental branch that I'm interested in feedback on. I'll post a draft PR later today (I want to do a few rebase cleanups to make it easier to read first) |
|
Okay, I'll update this PR to work with different versions of ruby, but please also see #957 |
39e1a5d to
77a311e
Compare
|
FYI: that last commit updated the API to be closer to how I'd prefer it. What do you think? (still waiting for the various tests to run). |
|
I haven't added tests for the new StoreContext object, yet. I'll update the existing ssl_verify tests to look at that too. |
|
haha, I swear I'm not pushing until it passes for me locally. I suppose I shouldn't be surprised that the behavior here is slightly different, but I am a bit puzzled. I'm running I think the behavior that's different is that, when you override errors, sometimes openssl calls the verify callback once per error and then a final time per certificate with no error, and other times it only calls once per error. These test failures are all displaying "once per error, w/o a non-error" behavior, but locally I get that final non-error (as shown in the tests). If you know anywhere that it's documented why this happens, or some way to regularize the behavior, that'd be great. Otherwise, I'll just relax the tests to not care about that final non-error callback. |
9afcc72 to
9979411
Compare
|
FYI: this is passing all jobs on my branch now: https://github.com/nevans/eventmachine/actions/runs/1457505841 |
9979411 to
5f5864f
Compare
210551c to
ea180ae
Compare
b5ef36c to
bf6efcd
Compare
| return rb_str_new(NULL, (long)size); | ||
| } | ||
|
|
||
| // adapted from stdlib openssl's ossl_str_new |
There was a problem hiding this comment.
Would it be possible to use those method directly (if they are part of the public API?)
There was a problem hiding this comment.
For the most part, yes, and I would love to just use the methods directly. Even better, I'd love to just use OpenSSL::X509::StoreContext directly, and skip all of the re-implementation.
The problem (as I understand it) is that there's no mechanism for a ruby gem to publish C header files that can safely be used (not even for bundled or default gems, like openssl). And even then, we'd also need the openssl gem to commit to a public API for any C funcs that we used... many of the functions I want access to are static and not exported. There's at least one b.r-l.org conversation about this issue: https://bugs.ruby-lang.org/issues/17760, but it didn't really come to any resolution, AFAICT.
That said, it should be possible to find the gem's install dir and use ext/openssl/ossl.h. And the most important functions that we might want to access are exported. I just don't have any idea how brittle that would be... and when it breaks, how hard to debug will it be?
There was a problem hiding this comment.
What you've done makes sense given that these are internal methods that aren't being intentionally exported with a stable API. Someone put the idea in my head ages ago to move all of the TLS work up into Ruby space and implement it using the ruby/openssl standard library gem, and just rip out all of the C++ TLS bits. That's not something I've had any time in years to think much about, but would seem to be the right move.
There was a problem hiding this comment.
Adding a few more links I found:
- https://bugs.ruby-lang.org/issues/17760
- https://bugs.ruby-lang.org/issues/17761 (Fixed by: ruby/ruby@5cdf99f6)
- https://bugs.ruby-lang.org/issues/15156
- Have a 'includedir' specifier in Gem::Specification. ruby/rubygems#2408
- Safe to link against gem extension? ruby/openssl#475
I created this issue on the openssl gem back when I first worked on this current eventmachine PR.
4c7ccb4 to
d9a2abe
Compare
e631c0e to
93384c8
Compare
09a8624 to
282c39c
Compare
|
Let me know if you're still working on this PR? I think it looks good |
| elsif opcode == SslVerify | ||
| c = @conns[conn_binding] or raise ConnectionNotBound, "received SslVerify for unknown signature: #{conn_binding}" | ||
| result = c.ssl_verify_peer(data) or c.close_connection | ||
| result = (c.original_method(:ssl_verify_peer).arity == 1) ? |
There was a problem hiding this comment.
Suggest to add a comment here that arity == 1 is for backwards compatibility
Thanks! Not quite yet. I should have it ready some time tomorrow. |
|
For what it's worth, I did find quite a few examples of gems that link against other gem extensions:
But I have questions and concerns about stability. Is this a safe thing to do? Under what circumstances can they break? Some of these gems have millions of downloads, so the pattern does seem to have some resilience. Is there a way for a gem to signal that all of the exported methods in a particular header file will be ABI backward compatible within a version range (besides just asking in their discussion forums or issue trackers or adding it to their README or other docs)? |
ea43d2f to
75c0112
Compare
For backward compatibility, this will continue sending only the current certificate when ssl_verify_peer takes only a single argument. Otherwise, the arguments will match stdlib's `verify_callback`. The certificate PEM is still easily obtained through `x509_store_ctx.current_cert.to_pem`. Also, the default implementation for `EM::Connection#ssl_verify_peer` has been updated to log errors and return `preverify_ok` unchanged. To support this, a new EM::SSL::X509::StoreContext class has been added, with similar semantics to stdlib's OpenSSL::SSL::X509::StoreContext. Unlike stdlib, this X509 store context is not a wrapper around X509_STORE_CTX. It simply contains copies of the most useful data from X509_STORE_CTX. The biggest difference from stdlib: * It is frozen, and has none of the attr writer methods. * It does not have `#chain` (array of X509::Certificate objects). * It cannot return the `#current_crl`. * It cannot perform the certificate verfication using `#verify`. Most of the new code was copied directly from the `openssl` gem, and modified only where needed, in order to work with eventmachine. The functions are placed in files named after their files of origin. This is still missing significant features, which will be fixed in subsequent PRs: * This still defaults to _not_ verify peers. * This still requires extra code to verify the peer's identity. * This still can't configure the X509_STORE.
75c0112 to
7fcb81f
Compare

This isn't complete by itself, because EM hasn't properly configured an
X509_STOREto go with itsSSL_CTXandSSL, nor does it verify thepeer's identity (
verify_hostnamein stdlib). Unlike stdlib, the"store_context" is merely a read-only data structure, containing a copy
of the most useful data from the
X509_STORE_CTX.Also, the default implementation for
EM::Connection#ssl_verify_peerhas been updated to log errors and returns
preverify_okunchanged.