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

schannel error for validating hosts with AltNames #3711

Closed
jeroen opened this issue Mar 27, 2019 · 6 comments
Closed

schannel error for validating hosts with AltNames #3711

jeroen opened this issue Mar 27, 2019 · 6 comments
Labels
TLS Windows Windows-specific

Comments

@jeroen
Copy link
Contributor

jeroen commented Mar 27, 2019

Trying to upgrade the R bindings on Windows from 7.59.1 to 7.64.1. The curl configuration is dual-ssl (openssl + schannel) with the latter being the default.

$version
[1] "7.64.1"

$ssl_version
[1] "(OpenSSL/1.1.1a) Schannel"

The bindings set CURLOPT_CAINFO to the path of our cert bundle. However, I think in libcurl 7.59.1 this option was only needed for the openssl back-end, because schannel would ignore it and use the Windows certificate store to validate certs? Not sure.

curl_easy_setopt(handle, CURLOPT_CAINFO, CA_BUNDLE);

Anyway, with the new version, trying to connect to e.g. www.github.com fails like this:

* Hostname in DNS cache was stale, zapped
*   Trying 140.82.118.4...
* TCP_NODELAY set
* Connected to www.github.com (140.82.118.4) port 443 (#3)
* schannel: added 143 certificate(s) from CA file 'C:/PROGRA~1/R/R-35~1.3/etc/curl-ca-bundle.crt'
* schannel: connection hostname (www.github.com) did not match against certificate name (github.com)
* schannel: CertGetNameString() failed to match connection hostname (www.github.com) against server certificate names
* Closing connection 3
* schannel: shutting down SSL/TLS connection with www.github.com port 443
Error in curl::curl_fetch_memory("https://www.github.com", handle = new_handle(verbose = T)) : 
  schannel: CertGetNameString() failed to match connection hostname (www.github.com) against server certificate names

The line below wasn't there in 7.59.1, I guess it is now using the bundle instead of windows certificate store for validating certs with schannel which was probably already added in 7.60.0.

schannel: added 143 certificate(s) from CA file 'C:/PROGRA~1/R/R-35~1.3/etc/curl-ca-bundle.crt'

However it doesn't seem to support AltName certs, which is why connecting to www.github.com fails. If we connect to github.com instead then it works, because github.com is the primary CN on the cert:

*   Trying 140.82.118.4...
* TCP_NODELAY set
* Connected to github.com (140.82.118.4) port 443 (#4)
* schannel: added 143 certificate(s) from CA file 'C:/PROGRA~1/R/R-35~1.3/etc/curl-ca-bundle.crt'
* schannel: connection hostname (github.com) validated against certificate name (github.com)
> GET / HTTP/1.1
Host: github.com
User-Agent: R (3.5.3 i386-w64-mingw32 i386 mingw32)
Accept: */*
Accept-Encoding: deflate, gzip

< HTTP/1.1 200 OK

The problem does not appear when using the openssl backend (so the bundle file is not the problem), or when using the schannel without setting CURLOPT_CAINFO (in which case I guess it uses the Windows certificate store).

@bagder bagder added TLS Windows Windows-specific labels Mar 27, 2019
@jay
Copy link
Member

jay commented Mar 29, 2019

CERT_NAME_SEARCH_ALL_NAMES_FLAG isn't available earlier than Windows 8 as discussed here.

#ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG
name_flags |= CERT_NAME_SEARCH_ALL_NAMES_FLAG;
#endif

curl tool doesn't set CAINFO for schannel, it does it like this:

curl/src/tool_operate.c

Lines 261 to 269 in 521bbbe

/* Set the CA cert locations specified in the environment. For Windows if
* no environment-specified filename is found then check for CA bundle
* default filename curl-ca-bundle.crt in the user's PATH.
*
* If Schannel is the selected SSL backend then these locations are
* ignored. We allow setting CA location for schannel only when explicitly
* specified by the user via CURLOPT_CAINFO / --cacert.
*/
if(tls_backend_info->backend != CURLSSLBACKEND_SCHANNEL) {

Likely you specified CAINFO and the CERT_NAME_SEARCH_ALL_NAMES_FLAG was not available at build time because you targeted < Windows 8. It's fixable but I've focused on other issues. It should be possible to fix by iterating through CERT_ALT_NAME_INFO instead of using that flag.

@jeroen
Copy link
Contributor Author

jeroen commented Mar 31, 2019

Likely you specified CAINFO and the CERT_NAME_SEARCH_ALL_NAMES_FLAG was not available at build time because you targeted < Windows 8.

Right this is the case. I will make sure to not set CAINFO icw/ CURLSSLBACKEND_SCHANNEL then.

Perhaps there should be a warning of some sort in the CURLOPT_CAINFO documentation because https really doesn't function without CERT_NAME_SEARCH_ALL_NAMES_FLAG in today's world (almost all certs from CDNs have many different domains in them).

@jeroen jeroen closed this as completed Mar 31, 2019
@jay
Copy link
Member

jay commented Apr 1, 2019

Perhaps there should be a warning of some sort in the CURLOPT_CAINFO documentation because https really doesn't function without CERT_NAME_SEARCH_ALL_NAMES_FLAG in today's world (almost all certs from CDNs have many different domains in them).

Yeah that's a fair point we'll try to fix it for the next release.

@jay jay reopened this Apr 1, 2019
@bagder
Copy link
Member

bagder commented Apr 13, 2019

Maybe turn that into a new separate issue with a description explaining it (I didn't follow it totally I think)? I fear it mostly gets lost here.

bagder added a commit that referenced this issue May 12, 2019
Clues-provided-by: Jay Satiro
Clues-provided-by: Jeroen Ooms
Fixes #3711
@bagder
Copy link
Member

bagder commented May 12, 2019

My attempt at documenting this is now in #3874.

@bagder bagder closed this as completed in 6123d71 May 14, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Aug 12, 2019
jay pushed a commit that referenced this issue Jan 12, 2020
- Support hostname verification via alternative names (SAN) in the
  peer certificate when CURLOPT_CAINFO is used in Windows 7 and earlier.

CERT_NAME_SEARCH_ALL_NAMES_FLAG doesn't exist before Windows 8. As a
result CertGetNameString doesn't quite work on those versions of
Windows. This change provides an alternative solution for
CertGetNameString by iterating through CERT_ALT_NAME_INFO for earlier
versions of Windows.

Prior to this change many certificates failed the hostname validation
when CURLOPT_CAINFO was used in Windows 7 and earlier. Most certificates
now represent multiple hostnames and rely on the alternative names field
exclusively to represent their hostnames.

Reported-by: Jeroen Ooms

Fixes #3711
Closes #4761
@jay
Copy link
Member

jay commented Jan 12, 2020

Fix landed in 29e40a6.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
TLS Windows Windows-specific
Development

Successfully merging a pull request may close this issue.

3 participants