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: CA file and memory blob cache #12261

Closed
wants to merge 10 commits into from

Conversation

ajax16384
Copy link
Contributor

add schannel CA file and memory blob cache support
add schannel CURLOPT_CA_CACHE_TIMEOUT support

add schannel CURLOPT_CA_CACHE_TIMEOUT support
@github-actions github-actions bot added TLS Windows Windows-specific labels Nov 3, 2023
const struct Curl_easy *data)
{
struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;

Copy link
Member

@bagder bagder Nov 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
DEBUGASSERT(multi);
DEBUGASSERT(multi->ssl_backend_data);

As from what I understand something is terribly wrong if either one is NULL here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

used same pattern from

if(multi &&

as it checked multi for null without assert.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is now!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

return mbackend->cert_store;
}

bool schannel_set_cached_cert_store(struct Curl_cfilter *cf,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a static function, then it needs to be prefixed with Curl_.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

@@ -2754,6 +2754,148 @@ static void *schannel_get_internals(struct ssl_connect_data *connssl,
return &backend->ctxt->ctxt_handle;
}

HCERTSTORE schannel_get_cached_cert_store(struct Curl_cfilter *cf,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is not a static function, then it needs to be prefixed with Curl_.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

return NULL;
}

struct schannel_multi_ssl_backend_data *mbackend;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We write C89 code, so we prefer the variable declarations at the top of every code block. Even for this code, I presume there is no compiler that is going to warn about it in this windows specific section.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

if(memcmp(mbackend->CAinfo_blob_digest,
info_blob_digest,
CURL_SHA256_DIGEST_LENGTH)) {
return NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memcmp compares hash of previous mem block with current, if it's not equal then cert_store is invalid

{
struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;

if(!multi) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose a DEBUGASSERT() here as well for the same reason. This should not be possible to happen.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

if(conn_config->CAfile) {
CAfile = strdup(conn_config->CAfile);
if(!CAfile) {
return false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this and the other early returns, do they not leak memory allocated previously in this function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all possible allocations will be freed at backend free method (free_multi_ssl_backend_data)

consolidate var declaration at block start
add DEBUGASSERT
bagder added a commit that referenced this pull request Nov 3, 2023
... so add the asserts now and consider removing the dynamic checks in a
future.

Ref: #12261
bagder added a commit that referenced this pull request Nov 4, 2023
... so add the asserts now and consider removing the dynamic checks in a
future.

Ref: #12261
Closes #12264
@bagder
Copy link
Member

bagder commented Nov 4, 2023

warnings

C:\projects\curl\lib\vtls\schannel.c(2802,50): warning C4057: 'function': 'const unsigned char *' differs in indirection to slightly different base types from 'const char *' [C:\projects\curl\lib\libcurl_object.vcxproj]
C:\projects\curl\lib\vtls\schannel.c(2861,50): warning C4057: 'function': 'const unsigned char *' differs in indirection to slightly different base types from 'const char *' [C:\projects\curl\lib\libcurl_object.vcxproj]

@ajax16384
Copy link
Contributor Author

warnings

C:\projects\curl\lib\vtls\schannel.c(2802,50): warning C4057: 'function': 'const unsigned char *' differs in indirection to slightly different base types from 'const char *' [C:\projects\curl\lib\libcurl_object.vcxproj]
C:\projects\curl\lib\vtls\schannel.c(2861,50): warning C4057: 'function': 'const unsigned char *' differs in indirection to slightly different base types from 'const char *' [C:\projects\curl\lib\libcurl_object.vcxproj]

thanks, fixed

schannel_sha256sum((const unsigned char *)ca_info_blob->data,
ca_info_blob->len,
CAinfo_blob_digest,
CURL_SHA256_DIGEST_LENGTH);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this really faster than storing the original blob and comparing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blob might be memory expensive
(like https://curl.se/docs/caextract.html - 200KB)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a release configuration in an average of over 100 runs a memcmp of the 200k memory takes 24us and a sha256sum comparison takes 3200us (1600us x 2). That is basically 3 ms difference between the two. I did not account for the memdup time in the first case though I forgot about that. So first case might actually be slower because of crt locks needed to copy the memory. My conclusion is it's not worth copying the entire blob.

lib/vtls/schannel.c Outdated Show resolved Hide resolved
free(mbackend->CAfile);

mbackend->time = Curl_now();
mbackend->cert_store = cert_store;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice that unlike openssl code there's no increase to a reference count when this is added

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here(schannnel*.c) HCERTSTORE resource use non refcount contructor/destrctor pattern. Just after successfull Curl_schannel_set_cached_cert_store call from Curl_verify_certificate - cache record became this resource owner. Lifetime of cert_store do not exceed get/store* methods.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tlsa do you happen to remember why you used ref counting for the openssl store

Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
/* try cache */
trust_store = Curl_schannel_get_cached_cert_store(cf, data);
Copy link
Member

@jay jay Nov 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

openssl get/set of cert store has more conditionals, see cache_criteria_met. it looks like most? of those don't apply here but what about data->set.general_ssl.ca_cache_timeout

curl/lib/vtls/openssl.c

Lines 3439 to 3460 in 3e6254f

/* Consider the X509 store cacheable if it comes exclusively from a CAfile,
or no source is provided and we are falling back to openssl's built-in
default. */
cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
conn_config->verifypeer &&
!conn_config->CApath &&
!conn_config->ca_info_blob &&
!ssl_config->primary.CRLfile &&
!ssl_config->native_ca_store;
cached_store = get_cached_x509_store(cf, data);
if(cached_store && cache_criteria_met && X509_STORE_up_ref(cached_store)) {
SSL_CTX_set_cert_store(ssl_ctx, cached_store);
}
else {
X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx);
result = populate_x509_store(cf, data, store);
if(result == CURLE_OK && cache_criteria_met) {
set_cached_x509_store(cf, data, store);
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Zero cache timeout should skip cache usage at all. Will fix with next commit.

@jay jay closed this in 1af46f2 Nov 11, 2023
@jay
Copy link
Member

jay commented Nov 11, 2023

Thanks

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

Successfully merging this pull request may close these issues.

None yet

3 participants