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
Conversation
add schannel CURLOPT_CA_CACHE_TIMEOUT support
const struct Curl_easy *data) | ||
{ | ||
struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi; | ||
|
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.
DEBUGASSERT(multi); | |
DEBUGASSERT(multi->ssl_backend_data); |
As from what I understand something is terribly wrong if either one is NULL 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.
used same pattern from
Line 3377 in 3e6254f
if(multi && |
as it checked multi for null without assert.
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.
it is now!
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.
OK
lib/vtls/schannel.c
Outdated
return mbackend->cert_store; | ||
} | ||
|
||
bool schannel_set_cached_cert_store(struct Curl_cfilter *cf, |
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 is not a static function, then it needs to be prefixed with Curl_
.
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.
OK
lib/vtls/schannel.c
Outdated
@@ -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, |
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.
As this is not a static function, then it needs to be prefixed with Curl_
.
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.
OK
lib/vtls/schannel.c
Outdated
return NULL; | ||
} | ||
|
||
struct schannel_multi_ssl_backend_data *mbackend; |
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.
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.
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.
OK
if(memcmp(mbackend->CAinfo_blob_digest, | ||
info_blob_digest, | ||
CURL_SHA256_DIGEST_LENGTH)) { | ||
return NULL; |
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.
What is the purpose of this check?
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.
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) { |
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 propose a DEBUGASSERT() here as well for the same reason. This should not be possible to happen.
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.
OK
if(conn_config->CAfile) { | ||
CAfile = strdup(conn_config->CAfile); | ||
if(!CAfile) { | ||
return false; |
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 this and the other early returns, do they not leak memory allocated previously in this function?
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.
all possible allocations will be freed at backend free method (free_multi_ssl_backend_data)
consolidate var declaration at block start add DEBUGASSERT
... so add the asserts now and consider removing the dynamic checks in a future. Ref: #12261
|
thanks, fixed |
schannel_sha256sum((const unsigned char *)ca_info_blob->data, | ||
ca_info_blob->len, | ||
CAinfo_blob_digest, | ||
CURL_SHA256_DIGEST_LENGTH); |
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 this really faster than storing the original blob and comparing?
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.
blob might be memory expensive
(like https://curl.se/docs/caextract.html - 200KB)
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 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.
free(mbackend->CAfile); | ||
|
||
mbackend->time = Curl_now(); | ||
mbackend->cert_store = cert_store; |
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 notice that unlike openssl code there's no increase to a reference count when this is added
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.
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.
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.
@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); |
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.
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
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); | |
} | |
} |
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. Zero cache timeout should skip cache usage at all. Will fix with next commit.
Thanks |
... so add the asserts now and consider removing the dynamic checks in a future. Ref: curl#12261 Closes curl#12264
- Support CA bundle and blob caching. Cache timeout is 24 hours or can be set via CURLOPT_CA_CACHE_TIMEOUT. Closes curl#12261
add schannel CA file and memory blob cache support
add schannel CURLOPT_CA_CACHE_TIMEOUT support