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

Respect git conventions when validating certs #2408

Closed
wants to merge 1 commit into from

Conversation

alexcrichton
Copy link
Member

Git supports the http.sslVerify option as well as the GIT_SSL_NO_VERIFY
environment variable for disabling validation of SSL certificates. This was
removed from libgit2 in libgit2/libgit2@41698f22 citing bad security practice
and how applications now had enough information to decide for themselves.

There seems to be enough corporate environments (as mentioned in #1180) where
certificate validation won't work that this seems prudent for Cargo to support.

Closes #1180

Git supports the `http.sslVerify` option as well as the `GIT_SSL_NO_VERIFY`
environment variable for disabling validation of SSL certificates. This was
removed from libgit2 in libgit2/libgit2@41698f22 citing bad security practice
and how applications now had enough information to decide for themselves.

There seems to be enough corporate environments (as mentioned in rust-lang#1180) where
certificate validation won't work that this seems prudent for Cargo to support.

Closes rust-lang#1180
@rust-highfive
Copy link

r? @wycats

(rust_highfive has picked a reviewer for you, use r? to override)

@alexcrichton
Copy link
Member Author

r? @brson

@guillon
Copy link

guillon commented Feb 24, 2016

vWhen testing the pull request on an untrusted https git source, it seems that nor the GIT_SSL_NO_VERIFY, nor the http.sslVerify git config work.

I've never built Cargo before, though it may be a mistake of mine:

Reproduce with:
Builds the pull request version
$ git clone https://github.com/alexcrichton/cargo
$ cd cargo && git checkout 879766a
$ ./configure
$ make
/usr/local/bin/rustc -V
rustc 1.5.0 (3d7cd77e4 2015-12-04)
target/snapshot/bin/cargo --version
cargo 0.9.0-nightly (c4c6f39 2016-01-30)
target/snapshot/bin/cargo build --target x86_64-unknown-linux-gnu --release
....

Set cargo PATH to the fresh build
$ PATH=$PWD/target/x86_64-unknown-linux-gnu/release:$PATH
$ cargo --version
cargo 0.9.0 (879766a 2016-02-23)

Make a fake Cargo.toml that refers an untrusted https git repository (actually it's not a rust repo, just for testing the git clone):
$ mkdir -p test-git && cd test-git
$ cat >Cargo.toml <<EOF
[package]
name = "test-git"
version = "0.0.1"
[dependencies]
hello = { git = "https://repo.or.cz/helloworld.git" }
EOF
$ mkdir -p src && touch src/main.rs

Test cargo build that should attempt to fetch the git repo (should fail as no ssl verify bypass is set):
$ cargo --version
cargo 0.9.0 (879766a 2016-02-23)
$ cargo build --verbose
Updating git repository https://repo.or.cz/helloworld.git
Unable to update https://repo.or.cz/helloworld.git
Caused by:
failed to fetch into /local/build/.cargo/git/db/helloworld-57d49a015623795b
Caused by:
[12/-2] Peer certificate cannot be authenticated with given CA certificates

Test again with gitconfig, unexpectedly fails on my side:
$ git config --global http.sslVerify false
$ cargo build --verbose
cargo build --verbose
Updating git repository https://repo.or.cz/helloworld.git
Unable to update https://repo.or.cz/helloworld.git
Caused by:
failed to fetch into /local/build/.cargo/git/db/helloworld-57d49a015623795b
Caused by:
[12/-2] Peer certificate cannot be authenticated with given CA certificates

Test also with GIT_SSL_NO_VERIFY=1, unexpectedly fails also on my side:
$ env GIT_SSL_NO_VERIFY=1 cargo build --verbose
Updating git repository https://repo.or.cz/helloworld.git
Unable to update https://repo.or.cz/helloworld.git
Caused by:
failed to fetch into /local/build/.cargo/git/db/helloworld-57d49a015623795b
Caused by:
[12/-2] Peer certificate cannot be authenticated with given CA certificates

Note that a bare git clone works in both cases and fails with no config:
$ git config --global --unset-all http.sslVerify
$ rm -rf helloworld && git clone https://repo.or.cz/helloworld.git
Cloning into 'helloworld'...
fatal: unable to access 'https://repo.or.cz/helloworld.git/': server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none

$ git config --global http.sslVerify false
$ rm -rf helloworld && git clone https://repo.or.cz/helloworld.git
... done.

$ git config --global --unset-all http.sslVerify
$ rm -rf helloworld && env GIT_SSL_NO_VERIFY=1 git clone https://repo.or.cz/helloworld.git
... done.

@alexcrichton
Copy link
Member Author

@guillon thanks for giving this a spin! The first time you used gitconfig, the option was spelled "http.sslVerfify", but was that just a copy-paste typo?

Also, do you have an HTTP proxy set? Cargo will use libcurl to fetch git repositories when a proxy is set, but I'm not sure if the certificate callback is handled in that case in libgit2.

@guillon
Copy link

guillon commented Feb 24, 2016

Inded for the "sslVerfify" it was a typo. I rechecked with same conclusion (updated comment).

@guillon
Copy link

guillon commented Feb 24, 2016

Indeed I have a http proxy set. Probably means thus that libcurl2 will also have to honor this.

I will recheck my use case on a machine without a proxy to complete the report.

@alexcrichton
Copy link
Member Author

Ok, it's probably the case that git2-curl isn't respecting the certificate callback in that case. As a data point, I verified this manually to ensure that it worked as expected, and it does work without git2-curl in play

@guillon
Copy link

guillon commented Feb 24, 2016

Right.
I verified also on a network without HTTP proxy, the patch works fine!

Thus for the HTTP proxy case, it's less obvious than expected...
First, looking at curl/libcurl (https://github.com/curl/curl) some remarks:

  • neither curl, nor libcurl do have an env. var. equivalent to the curl option --insecure
  • curl can have this option set through --insecure or through the ~/.curlrc file
  • libcurl does not provide an API for parsing the ~/.curlrc file unfortunately, and do not parse it implicitly. I.e. only the command line curl parses the ~/.curlrc.
  • the parsing of ~/.curlrc file is not trivial, one option per line, but comments to handle, optional dash, etc... For instance insecure or --insecure or -k (but not k) work in the ~/.curlrc file as an equivalent to --insecure option). Ref to https://github.com/curl/curl/blob/master/src/tool_parsecfg.c
  • actually the insecure option unsets both SSL_VERIFYPEER and SSL_VERIFYHOST libcurl options. Ref to https://github.com/curl/curl/blob/master/src/tool_operate.c#L1026

I guess thus that for supporting curl insecure configuration the choices are:

  • either augment rust libcurl with an API for parsing ~/.curlrc which mimics curl tool behavior and configures the libcurl options,
  • or the same with a subset of supported options,
  • or a specific API for setting insecure mode which unsets the corresponding libcurl options
  • or/and a cargo specific env. var. that would activate these options.

@guillon
Copy link

guillon commented Feb 24, 2016

For https protocol the libcurl option CURLOPT_SSL_VERIFYPEER is sufficient I guess, CURLOPT_SSL_VERIFYHOST is, I suppose, required only for the the ssh/scp protocols.

My guess is that you'd better propose a cargo specific option and/or env. var. that deactivates the cert check callback in rust libgit and unset the CURLOPT_SSL_VERIFYPEER in rust libcurl instead of trying to parse .gitconfig and .curlrc.

@alexcrichton
Copy link
Member Author

Got a chance to talk about this with @wycats today and the conclusion was that we want to hold off on this for now. It's unclear whether we want to add this to Cargo as it really is such a bad security practice. @wycats was going to gather some more information.

@the-shank
Copy link

This is really sad. Its good that Rust takes the security thing seriously but not allowing this, even after legitimate use case, is disheartening. If the user is already specifying that he is not validating SSL for git, for example, why cant Cargo consider users to be adults and allow them to use it, albeit with a warning that this is a _very_ bad security practice.
I have been trying to get the other IT guys to try out Rust at my company (and no, we are not a software development company. I happen to be in the IT section of a manufacturing behemoth). But looks like it wont be possible in the near future. Disappointed.

@alexcrichton
Copy link
Member Author

Ok, been talking with @wycats and we may not want to do this just yet, so closing.

@apaprocki
Copy link

This PR was for disabling cert verification. What about the options for passing a local cert store to the underlying libraries? When you're in an environment where certificates are not installed in the default location on the system, there doesn't seem to be a way to get around this. You can't disable checking and you can't pass it the proper certs to verify against. (e.g. the git http.sslCAInfo option) Re-inventing the wheel here just causes headache. These options are configurable on other tools for good reasons.

@alexcrichton alexcrichton deleted the noverify branch March 23, 2016 17:32
@alexcrichton
Copy link
Member Author

@apaprocki the problem might be that we're using libgit2 and curl which have different configurations, but if there's standard methods to configure where certificates are located then we should definitely respect that! Do you know if there's documentation about these options that we could follow?

@apaprocki
Copy link

@alexcrichton libgit2 can be configured by setting GIT_OPT_SET_SSL_CERT_LOCATIONS to the certificate store the user configures. In git this is done by setting http.sslCAInfo to the file name. libcurl can similarly be configured by setting CURLOPT_CAINFO. The "path" variants that allow you to set a directory name containing individual certificates (instead of a bundle) are http.sslCAPath (git), GIT_OPT_SET_SSL_CERT_LOCATIONS (libgit2, 2nd parameter), and CURLOPT_CAPATH. In order to keep things consistent with git, I'd highly recommend using the same http.sslCAInfo/http.sslCAPath configuration options.

@apaprocki
Copy link

libgit2 header documentation: https://github.com/libgit2/libgit2/blob/ff5a39678b77d1ccb65119314ee518b019add7aa/include/git2/common.h#L238
CURLOPT_CAINFO: https://curl.haxx.se/libcurl/c/CURLOPT_CAINFO.html
CURLOPT_CAPATH: https://curl.haxx.se/libcurl/c/CURLOPT_CAPATH.html

git documentation is here: https://git-scm.com/docs/git-config and documents them as accepting environment variable overrides as well:

http.sslCAInfo
File containing the certificates to verify the peer with when fetching or pushing over HTTPS. Can be overridden by the GIT_SSL_CAINFO environment variable.

http.sslCAPath
Path containing files with the CA certificates to verify the peer with when fetching or pushing over HTTPS. Can be overridden by the GIT_SSL_CAPATH environment variable.

@alexcrichton
Copy link
Member Author

Awesome, thanks! I'll add that to the issue.

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

7 participants