-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
242 respect ssl ca info #411
Conversation
Whitespace cleanup
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of questions and changes regarding validation and what ISettings
should return.
Should this check whether the sslCAInfo file exists, or let the program fail?
HttpClientFactory
should probably test if the file exists before setting the callback. It should then either warn or die (throw an exception), depending on what Git's behaviour is when http.sslCAInfo
points to an invalid path.
Should the other X509ChainStatusFlags be allowed to continue on to the cert match check?
We should be conservative and fail for any certificate error we encounter (and manually check the root matches the supplied one.
Because the HTTP client first validates the cert against your local root store (and I didn't remove GitHub's actual root CA from my System Roots when testing), I wasn't able to verify that the Untrusted Root error is the only one to come through with an otherwise-valid self-signed cert
This is an interesting behaviour. So setting that callback means the "normal" .NET validation still happens before us? That probably deserves a comment in the code for future readers.
src/shared/Microsoft.Git.CredentialManager/HttpClientFactory.cs
Outdated
Show resolved
Hide resolved
{ | ||
// First, verify that, if schannel is the HTTP backend, sslCaInfo must be explicitly enabled to be used | ||
if (TryGetSetting(null, KnownGitCfg.Http.SectionName, KnownGitCfg.Http.SslBackend, out string backend) && | ||
StringComparer.OrdinalIgnoreCase.Equals(backend, "schannel") && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these constants ("schannel"
and "openssl"
) be const string
s in Constants.cs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes for schannel
, but would you also want openssl
included (even though it's not used anywhere here)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd add openssl
too for good measure, it doesn't hurt anyone :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because this setting is just a passthrough to libcurl, there are more options than schannel
and openssl
(depending on platform). If schannel
is the only one used here (so far, at least), I think I'd prefer to only include that for now (it keeps us from needing to keep up with mirroring all of libcurl's available options).
EDIT: I ended up creating a (nullable) enum anyway - it looks like schannel
and openssl
are the most commonly used, so they're included in that. I included an "Other" value as well (to handle the rest and to distinguish from the "not specified" case - if there's a better way to handle that, I'm happy to change it).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If openssl
is the default backend used by Git, would it be more appropriate to use a non-nullable TlsBackend
for the setting, setting the value to openssl
if it's unspecified in the user's config? I've updated the implementation to do this, but I can revert if you'd like.
src/shared/Microsoft.Git.CredentialManager/HttpClientFactory.cs
Outdated
Show resolved
Hide resolved
src/shared/Microsoft.Git.CredentialManager/HttpClientFactory.cs
Outdated
Show resolved
Hide resolved
The official documentation is pretty unclear, but I think the .NET source code confirms it (assuming I traced the through it properly). I'll add a comment explicitly mentioning that in the callback. |
// First, verify that, if schannel is the HTTP backend, sslCaInfo must be explicitly enabled to be used | ||
if (TryGetSetting(null, KnownGitCfg.Http.SectionName, KnownGitCfg.Http.SslBackend, out string backend) && | ||
StringComparer.OrdinalIgnoreCase.Equals(backend, "schannel") && | ||
(!TryGetSetting(null, KnownGitCfg.Http.SectionName, KnownGitCfg.Http.SchannelUseSslCaInfo, out string schannelUseSslCaInfo) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any chance that we can call git config --type=path http.sslCAInfo
? The --type=path
option would ensure that we benefit from Git's own path interpolation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would involve some changes to GitConfiguration.cs (like adding an optional isPath
argument to TryGet(...)
or creating a TryGetPath(...)
method), but I really like the benefits of using Git's path interpolation logic (and not replicating it here). @mjcheetham what do you think?
Does this handle the environment variable version of the config as well (in this case, GIT_SSL_CAINFO
)? Or is %(prefix)
(and any other "magic" path interpolation) not supported with environment variables?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not handle the environment variables (but neither does Git interpolate prefix-relative paths in environment variables, so I think we're good).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mjcheetham what do you think?
I think this should be discussed in a separate PR/issue, so let's leave this as is today for this change.
8778c15
to
8a7b46e
Compare
e87c754
to
36fd743
Compare
I figured out a way to test this more accurately on Ubuntu (manually disabling the root certificate used by GitHub, then copying that cert to a custom location to use it as a "self-signed" cert) - results have been updated in the "Testing" section of the PR description. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/shared/Microsoft.Git.CredentialManager/HttpClientFactory.cs
Outdated
Show resolved
Hide resolved
Replicate the behavior of `http.sslCAInfo` (internally, cURL's `cainfo`/ OpenSSL's `cafile` arguments). Implemented by manually comparing the server certificate with the config-specified CA file.
d7f77c4
to
d58bf23
Compare
Implements #242
Changes
sslCAInfo
git config parameter (and corresponding environment variable)sslBackend
isschannel
andschannelUseSSLCAInfo
is false or not setsslCAInfo
is set, custom cert validation callback is called for HTTP clientRemoteCertificateNameMismatch
andRemoteCertificateNotAvailable
here)sslCAInfo
, successsslCAInfo
settingTesting
For all tests, ran the
get
command as described in "Development and Debugging" (changing the protocol from "http" to "https" forgithub.aaakk.us.kg
)sudo dpkg-reconfigure ca-certificates
to interactively (and temporarily) disable the root cert used bygithub.aaakk.us.kg
GIT_SSL_CAINFO
GIT_SSL_CAINFO
to path to trusted root certificateget
executionGIT_SSL_CAINFO
to path to an unrelated trusted root certificate for GitHubGIT_SSL_CAINFO
to path to a non-existent fileQuestions
sslCAInfo
file exists, or let the program fail?X509ChainStatusFlags
be allowed to continue on to the cert match check?