-
-
Notifications
You must be signed in to change notification settings - Fork 6.4k
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: add support for CURLOPT_CAINFO. #1325
Conversation
@mcnulty, thanks for your PR! By analyzing the history of the files in this pull request, we identified @masali-hp, @mback2k and @bagder to be potential reviewers. |
The failed CI test is test 2033, which is yet another pipelining test we probably need to disable due to its flakiness. |
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.
Thanks for your hard work on this feature and pull-request, I really appreciate it since I never had the time to implement this myself. I hope that you will find the time to address my review comments, thanks!
Thanks for your comments @mback2k! I hope to be able to address them within a week or so. |
Just checking in on this PR. I think I addressed all of @mback2k's comments. Is there anything more I can do to help shepherd this change along? |
Can you please squash the commits (and rebase them) so that they are the minimum set of logical changes required to provide this feature? It makes them easier for a final review and the rebase/ṕush will make them run through the (now) updated CI tests. (and I too would like @mback2k's ack on this) |
@mcnulty the conflicts are most likely due to my recent changes to support switching the SSL backend at runtime. Would you like me to help you resolving them? |
84ba86f
to
884c1cf
Compare
This PR has been rebased on a master. @dscho: Thanks for the offer to help resolve the conflicts. I think I was successfully able to resolve the conflicts. It appears all that needed to be done was to define backend-specific data in the |
Yes, it does! Thanks! |
Looks like the Travis T=normal C=--enable-ares build failed on test 1208:
|
- make verify_certificate functionality in curl_schannel.c available on all versions of Windows instead of just Windows CE. verify_certificate will only be invoked on Windows CE or when the user specifies CURLOPT_CAINFO and CURLOPT_SSL_VERIFYPEER. - In verify_certificate, create a custom certificate chain engine that exclusively trusts the certificate store backed by the CURLOPT_CAINFO file. - HAVE_EXCLUSIVE_TRUST_MODE macro defined in config-win32.h for Windows 7+ to control enabling this feature that relies on Windows 7+ functionality. - doc updates of --cacert/CAINFO support for schannel - Use CERT_NAME_SEARCH_ALL_NAMES_FLAG when invoking CertGetNameString when available. This implements a TODO in schannel.c to improve handling of multiple SANs in a certificate. In particular, all SANs will now be searched instead of just the first name. - Add new test cases 316 and 317. These test cases check that the first and last SAN, respectively, matches the connection hostname. New test certificates have been added for these cases. For 316, the certificate prefix is Server-localhost-firstSAN and for 317, the certificate prefix is Server-localhost-secondSAN. - Remove TODO 15.2 (Add support for custom server certificate validation), this commit addresses it. Closes curl#1325
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.
In addition to the comments I made in the review one more thing concerns me, the behavior of the curl tool currently is set to auto-detect certificate bundles on windows and prior to this change when curl w/WinSSL was used nothing would happen, the default certificate bundle would still be used Edit: The default certificate store in Windows would still be used is more correct to say. With this change however the curl tool would prefer the bundle instead. I think we should consider making it so that the curl tool only passes the CAINFO option in the case of schannel when the user has explicitly requested it, and not use autodetect, that way we could still preserve backwards compatibility. Thoughts?
lib/config-win32.h
Outdated
* option for Schannel. | ||
*/ | ||
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0601) | ||
#define HAVE_EXCLUSIVE_TRUST_MODE 1 |
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 possible I would like for us to handle this at runtime, it seems that in CERT_CHAIN_ENGINE_CONFIG the flag is available in the struct even in earlier versions though it doesn't do anything. Can't we do it like Curl_verify_windows_version(6, 1, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL);
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.
Interesting. Perhaps the CERT_CHAIN_ENGINE_CONFIG definition has changed in more recent versions of the Windows SDK?
Here's what the definition looks like in the 8.0 SDK:
typedef struct _CERT_CHAIN_ENGINE_CONFIG {
DWORD cbSize;
HCERTSTORE hRestrictedRoot;
HCERTSTORE hRestrictedTrust;
HCERTSTORE hRestrictedOther;
DWORD cAdditionalStore;
HCERTSTORE* rghAdditionalStore;
DWORD dwFlags;
DWORD dwUrlRetrievalTimeout; // milliseconds
DWORD MaximumCachedCertificates;
DWORD CycleDetectionModulus;
#if (NTDDI_VERSION >= NTDDI_WIN7)
HCERTSTORE hExclusiveRoot;
HCERTSTORE hExclusiveTrustedPeople;
#endif
#if (NTDDI_VERSION >= NTDDI_WIN8)
DWORD dwExclusiveFlags;
#endif
} CERT_CHAIN_ENGINE_CONFIG, *PCERT_CHAIN_ENGINE_CONFIG;
When I explicitly set _WIN32_WINNT to 0x0600 (Windows Server 2008), the hExclusiveRoot field is not present in the structure. Given this, I don't think this check can be done at runtime.
But, I do notice that other ifdef checks specific to Schannel are in the schannel.c file, for example, HAS_ALPN. Given that, I can move this check into schannel.c (or schannel_verify.c) instead of having it live in config-win32.h.
lib/vtls/schannel.c
Outdated
}; | ||
|
||
#define BACKEND connssl->backend | ||
|
||
static Curl_recv schannel_recv; | ||
static Curl_send schannel_send; | ||
|
||
#ifdef _WIN32_WCE | ||
#define MAX_CAFILE_SIZE 67108864 /* 64 MB */ |
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 seems like a large size to read into memory for a certificate bundle. I have a full mozilla certificate bundle that's like 256k
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.
Good point. Would a smaller value like 512k or 1M work? I'll go with 1M unless there are objections to that.
lib/vtls/schannel.c
Outdated
if(BACKEND->use_manual_cred_validation) { | ||
schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | | ||
SCH_CRED_IGNORE_NO_REVOCATION_CHECK | | ||
SCH_CRED_IGNORE_REVOCATION_OFFLINE; |
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 I'm not fond of, windows users have the expectation that revocation checks are enabled by default. wouldn't we want to do the same for the certificate bundle they supply for consistency? (I'm assuming here that is what will happen since manual cred is now used for the bundle)
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.
Great catch! Looks like revocation checks were being unconditionally disabled for CE, regardless of the setting of the no_revoke flag.
Interestingly enough, it looks like the call to CertGetCertificateChain overrides these flags by setting the CERT_CHAIN_REVOCATION_CHECK_CHAIN flag in the flags for that function if the no_revoke flag is set.
That said, I'll still update this code to set dwFlags based on the no_revoke flag.
tests/data/Makefile.inc
Outdated
@@ -55,7 +55,7 @@ test280 test281 test282 test283 test284 test285 test286 test287 test288 \ | |||
test289 test290 test291 test292 test293 test294 test295 test296 test297 \ | |||
test298 test299 test300 test301 test302 test303 test304 test305 test306 \ | |||
test307 test308 test309 test310 test311 test312 test313 test314 test315 \ | |||
test320 test321 test322 test323 test324 \ | |||
test316 test317 test320 test321 test322 test323 test324 \ |
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 rebased this and renamed the tests to avoid conflicts 314 => 316 and 315 => 317
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.
Cool, thanks!
228f50c
to
e083939
Compare
- Move verify_certificate functionality in schannel.c into a new file called schannel_verify.c. Additionally, some structure defintions from schannel.c have been moved to schannel.h to allow them to be used in schannel_verify.c. - Make verify_certificate functionality for Schannel available on all versions of Windows instead of just Windows CE. verify_certificate will be invoked on Windows CE or when the user specifies CURLOPT_CAINFO and CURLOPT_SSL_VERIFYPEER. - In verify_certificate, create a custom certificate chain engine that exclusively trusts the certificate store backed by the CURLOPT_CAINFO file. - HAVE_EXCLUSIVE_TRUST_MODE macro defined in schannel.h for Windows 7+ to control enabling this feature that relies on Windows 7+ functionality. - doc updates of --cacert/CAINFO support for schannel - Use CERT_NAME_SEARCH_ALL_NAMES_FLAG when invoking CertGetNameString when available. This implements a TODO in schannel.c to improve handling of multiple SANs in a certificate. In particular, all SANs will now be searched instead of just the first name. - Update tool_operate.c to not search for the curl-ca-bundle.crt file when using Schannel to maintain backward compatibility. Previously, any curl-ca-bundle.crt file found in that search would have been ignored by Schannel. But, with CAINFO support, the file found by that search would have been used as the certificate store and could cause issues for any users that have curl-ca-bundle.crt in the search path. - Add new test cases 317 and 318. These test cases check that the first and last SAN, respectively, matches the connection hostname. New test certificates have been added for these cases. For 317, the certificate prefix is Server-localhost-firstSAN and for 318, the certificate prefix is Server-localhost-secondSAN. - Remove TODO 15.2 (Add support for custom server certificate validation), this commit addresses it. Closes curl#1325
e083939
to
a8a2c14
Compare
- Move verify_certificate functionality in schannel.c into a new file called schannel_verify.c. Additionally, some structure defintions from schannel.c have been moved to schannel.h to allow them to be used in schannel_verify.c. - Make verify_certificate functionality for Schannel available on all versions of Windows instead of just Windows CE. verify_certificate will be invoked on Windows CE or when the user specifies CURLOPT_CAINFO and CURLOPT_SSL_VERIFYPEER. - In verify_certificate, create a custom certificate chain engine that exclusively trusts the certificate store backed by the CURLOPT_CAINFO file. - HAVE_EXCLUSIVE_TRUST_MODE macro defined in schannel.h for Windows 7+ to control enabling this feature that relies on Windows 7+ functionality. - doc updates of --cacert/CAINFO support for schannel - Use CERT_NAME_SEARCH_ALL_NAMES_FLAG when invoking CertGetNameString when available. This implements a TODO in schannel.c to improve handling of multiple SANs in a certificate. In particular, all SANs will now be searched instead of just the first name. - Update tool_operate.c to not search for the curl-ca-bundle.crt file when using Schannel to maintain backward compatibility. Previously, any curl-ca-bundle.crt file found in that search would have been ignored by Schannel. But, with CAINFO support, the file found by that search would have been used as the certificate store and could cause issues for any users that have curl-ca-bundle.crt in the search path. - Add new test cases 317 and 318. These test cases check that the first and last SAN, respectively, matches the connection hostname. New test certificates have been added for these cases. For 317, the certificate prefix is Server-localhost-firstSAN and for 318, the certificate prefix is Server-localhost-secondSAN. - Remove TODO 15.2 (Add support for custom server certificate validation), this commit addresses it. Closes curl#1325
Thanks for your review @jay! I think I've addressed all of your comments with my most recent push.
I added some code to tool_operate.c in the operate_do function to skip the autodetect search if the SSL backend is Schannel. I used the CURLINFO_TLS_SSL_PTR option for curl_easy_getinfo to determine the SSL backend in use. I'm not sure if this was the best way to determine the SSL backend, but it seemed to do the trick. |
a8a2c14
to
46831c5
Compare
- Move verify_certificate functionality in schannel.c into a new file called schannel_verify.c. Additionally, some structure defintions from schannel.c have been moved to schannel.h to allow them to be used in schannel_verify.c. - Make verify_certificate functionality for Schannel available on all versions of Windows instead of just Windows CE. verify_certificate will be invoked on Windows CE or when the user specifies CURLOPT_CAINFO and CURLOPT_SSL_VERIFYPEER. - In verify_certificate, create a custom certificate chain engine that exclusively trusts the certificate store backed by the CURLOPT_CAINFO file. - HAVE_EXCLUSIVE_TRUST_MODE macro defined in schannel.h for Windows 7+ to control enabling this feature that relies on Windows 7+ functionality. - doc updates of --cacert/CAINFO support for schannel - Use CERT_NAME_SEARCH_ALL_NAMES_FLAG when invoking CertGetNameString when available. This implements a TODO in schannel.c to improve handling of multiple SANs in a certificate. In particular, all SANs will now be searched instead of just the first name. - Update tool_operate.c to not search for the curl-ca-bundle.crt file when using Schannel to maintain backward compatibility. Previously, any curl-ca-bundle.crt file found in that search would have been ignored by Schannel. But, with CAINFO support, the file found by that search would have been used as the certificate store and could cause issues for any users that have curl-ca-bundle.crt in the search path. - Add new test cases 3000 and 3001. These test cases check that the first and last SAN, respectively, matches the connection hostname. New test certificates have been added for these cases. For 3000, the certificate prefix is Server-localhost-firstSAN and for 3001, the certificate prefix is Server-localhost-secondSAN. - Remove TODO 15.2 (Add support for custom server certificate validation), this commit addresses it. Closes curl#1325
I went ahead and rebased this PR on master. Any chance these changes could be considered for inclusion in 7.60.0? |
- Move verify_certificate functionality in schannel.c into a new file called schannel_verify.c. Additionally, some structure defintions from schannel.c have been moved to schannel.h to allow them to be used in schannel_verify.c. - Make verify_certificate functionality for Schannel available on all versions of Windows instead of just Windows CE. verify_certificate will be invoked on Windows CE or when the user specifies CURLOPT_CAINFO and CURLOPT_SSL_VERIFYPEER. - In verify_certificate, create a custom certificate chain engine that exclusively trusts the certificate store backed by the CURLOPT_CAINFO file. - HAVE_EXCLUSIVE_TRUST_MODE macro defined in schannel.h for Windows 7+ to control enabling this feature that relies on Windows 7+ functionality. - doc updates of --cacert/CAINFO support for schannel - Use CERT_NAME_SEARCH_ALL_NAMES_FLAG when invoking CertGetNameString when available. This implements a TODO in schannel.c to improve handling of multiple SANs in a certificate. In particular, all SANs will now be searched instead of just the first name. - Update tool_operate.c to not search for the curl-ca-bundle.crt file when using Schannel to maintain backward compatibility. Previously, any curl-ca-bundle.crt file found in that search would have been ignored by Schannel. But, with CAINFO support, the file found by that search would have been used as the certificate store and could cause issues for any users that have curl-ca-bundle.crt in the search path. - Add new test cases 3000 and 3001. These test cases check that the first and last SAN, respectively, matches the connection hostname. New test certificates have been added for these cases. For 3000, the certificate prefix is Server-localhost-firstSAN and for 3001, the certificate prefix is Server-localhost-secondSAN. - Remove TODO 15.2 (Add support for custom server certificate validation), this commit addresses it. Closes curl#1325
46831c5
to
53b61cb
Compare
Thanks Dan I will review again when I can. edit 4-16 I will review this week before the feature window closes, |
Thanks. I changed the OS check from a build time check to a runtime check since it's common to build libcurl targeting an OS earlier than Windows 7, and yet we would still like this ability on Windows 7+ for those builds. |
Modifications:
available on all versions of Windows instead of just
Windows CE. verify_certificate will only be invoked on
Windows CE or when the user specifies CURLOPT_CAINFO and
CURLOPT_SSL_VERIFYPEER
engine that exclusively trusts the certificate store backed
by the CURLOPT_CAINFO file
Windows 7+ to control enabling this feature that relies on
Windows 7+ functionality
when available. This implements a TODO in schannel.c to improve
handling of multiple SANs in a certificate. In particular, all SANs
will now be searched instead of just the first name.
the first and last SAN, respectively, matches the connection
hostname. New test certificates have been added for these
cases. For 314, the certificate prefix is Server-localhost-firstSAN
and for 315, the certificate prefix is Server-localhost-secondSAN
validation), this commit addresses it.
Testing
I didn't have any luck running the test suite for this particular platform/lib configuration so I validated the following test cases by hand:
All the tests I validated (except for test305) required specifying --ssl-no-revoke because the test CA (EdelCurlRoot-ca) does not have any revocation checking data in its cert and SChannel requires revocation checking by default.
I also ran the testsuite (for good measure) on Ubuntu 16.04.2/x86_64, using ./configure without args (built against OpenSSL) and didn't see any test failures.