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

Implement a cURL stream #3183

Merged
merged 10 commits into from Jun 24, 2015
Merged

Implement a cURL stream #3183

merged 10 commits into from Jun 24, 2015

Conversation

carlosmn
Copy link
Member

@carlosmn carlosmn commented Jun 5, 2015

cURL has a mode in which it provides TLS and proxy setup but otherwise allows us to use one of its handles very much like our own streams, so it's fairly simple to make the library use libcurl for talking to the server.


What we'll do here is use libcurl as the underlying stream and then build our own TLS streams on top of that. This allows us to keep doing what we do with certificates while letting libcurl take care of the proxy.

@carlosmn carlosmn force-pushed the cmn/curl-stream branch 3 times, most recently from 77a286e to 923014a Compare June 7, 2015 12:55
@carlosmn
Copy link
Member Author

carlosmn commented Jun 7, 2015

Extracting certificate information out of the curl handle is rather obtuse. It is only implemented for some crypto libraries, and it's in the form of a list of "key:value" strings so on the libcurl which comes with OSX, we're not able to get any information about the certificate, just whether SecureTransport figured it was valid or not.

This is way below the standard which we've set for ourselves with the other crypto backends, but there's no other way we're going to get proxy support.

@carlosmn carlosmn changed the title [WIP] Implement a cURL stream Implement a cURL stream Jun 9, 2015
@carlosmn
Copy link
Member Author

carlosmn commented Jun 9, 2015

This should be about ready to go in, though the proxy code is still untested. Testing that is going to be a barrel of laughs.

There's also the question of how do we test this stream. We shouldn't replace all the builds with a liburl one, so do we add an extra entry to the matrix asking the build system to install libcurl-dev?

@carlosmn
Copy link
Member Author

As a way to work around libcurl not quite giving us the information from the certificate, I think it'd be worth considering using libcurl only for the proxying capabilities, and send our TLS stream though it. The SecureTransport stream should be ready to take this on, as it sends data over to the socket stream, but having OpenSSL use a user-defined channel is not something on which I've found much information.

@dirkhh
Copy link

dirkhh commented Jun 11, 2015

Have you looked at CURLOPT_HTTPPROXYTUNNEL mode to use libcurl to ONLY provide a tunnel and do all the https negotiation / certificate extraction / etc from the libgit2 side?
For my use case that isn't critical, but since you brought it up... :-)

This is an extremely timely addition as lack of https proxy support was turning into a major headache for me. Thanks.

@carlosmn
Copy link
Member Author

Yeah, using libcurl solely as a tunnel is the current plan due to the differences in cert reporting across its crypto backends. Maybe I can get away with grabbing its socket descriptor and feeding it into OpenSSL, otherwise I'll have to figure out how to create a BIO.

@carlosmn carlosmn force-pushed the cmn/curl-stream branch 2 times, most recently from 4a44a13 to 00225f9 Compare June 12, 2015 05:35
@carlosmn
Copy link
Member Author

I'm not sure if there's a reliable[0] way to make CI test the proxy bits, but I have just tested locally and it does work, both by setting http.proxy and by exporting http_proxy, the latter is taken up by libcurl without us having to do anything other than set the option for tunneling. Setting this option unfortunately seems to make socks proxies not work, but this is still a win.

The Mac builds automatically have libcurl available, though I think the Ubuntu VMs don't have libcurl-dev installed, which means we won't exercise that path there, and always installing it would make us not use the plain socket stream. Maybe we can install it on the debug builds?

Regardless, I'd like to see this get merged soon so it gets some testing in the wild before we make the next release with it.

[0] Emphasis on "reliable". We can install tinyproxy and grep its logs, but that's yet another thing that can go wrong.

@dirkhh
Copy link

dirkhh commented Jun 12, 2015

I tried it yesterday with my corporsate environment and couldn't get it to work at all.
I tried both setting http.proxy in my application as well as setting http_proxy in my environment.
What I didn't do is "set the option for tunneling" which might explain my issue. I guess I don't know how/where to do that.
It might be nice to have an example or some documentation how to use this somewhere :-)
I'll be happy to try again if you can point me in the right direction.

@carlosmn
Copy link
Member Author

You use this the same way you use it with git, you set http.proxy or remote.<name>.proxy to select a particular proxy, or you specify http_proxy to let libcurl automagically set the proxy.

I don't know where you expect to specify the tunneling mode, it is an option we pass to libcurl when we set up the handle.

@dirkhh
Copy link

dirkhh commented Jun 12, 2015

The comment to tunneling mode was in response to what you wrote :-)
With just setting http.proxy (or http_proxy) it didn't work for me. And I verified in the debugger that libcurl was indeed used. And the SSL_Connect(st->ssl) in line 329 of openssl_stream.c fails.

@carlosmn
Copy link
Member Author

The code for tunneling TLS over it was only working early this morning, so whatever you used last night probably didn't have the tunneling on.

The "us" in the comment is libgit2. Users of the library are explicitly called out as such.

@dirkhh
Copy link

dirkhh commented Jun 12, 2015

Duh. The pull request didn't show new commits so I didn't realize you had added more code. Apologies. I just tried with the latest of the cmn/curl-stream branch and it works perfectly.
+1 merging this into master
Thanks for your great work!

cURL has a mode in which it acts a lot like our streams, providing send
and recv functions and taking care of the TLS and proxy setup for us.

Implement a new stream which uses libcurl instead of raw sockets or the
TLS libraries directly. This version does not support reporting
certificates or proxies yet.
If the stream claims to support this feature, we can let the transport
set the proxy.

We also set HTTPPROXYTUNNEL option so curl can create a tunnel through
the proxy which lets us create our own TLS session (if needed).
Of the built-in ones, only cURL support it, but there's no reason a
user-provided stream wouldn't support it.
The information is exposed by curl for some crypto libraries in the form
of name:content strings. We can't do much more than return this
information.
When linking against libcurl, use it as the underlying transport instead
of straight sockets. We can't quite just give over the file descriptor,
as curl puts it into non-blocking mode, so we build a custom BIO so
OpenSSL sends the data through our stream, be it the socket or curl
streams.
The TLS streams talk over the curl stream themselves, so we don't need
to ask for it explicitly. Do so in the case of the non-encrypted one so
we can still make use proxies in that case.
We do not want libcurl to perform the TLS negotiation for us, so we
don't need to pass this option.
If the libcurl stream is available, use that as the underlying stream
instead of the socket stream. This allows us to set a proxy for HTTPS
connections.
carlosmn added a commit that referenced this pull request Jun 24, 2015
@carlosmn carlosmn merged commit e1f434f into master Jun 24, 2015
@carlosmn carlosmn deleted the cmn/curl-stream branch June 24, 2015 21:33
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

2 participants