summaryrefslogtreecommitdiffstats
path: root/lib/vtls/schannel_verify.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vtls/schannel_verify.c')
-rw-r--r--lib/vtls/schannel_verify.c285
1 files changed, 165 insertions, 120 deletions
diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c
index 2ef39cc..25d47b8 100644
--- a/lib/vtls/schannel_verify.c
+++ b/lib/vtls/schannel_verify.c
@@ -77,21 +77,156 @@ static int is_cr_or_lf(char c)
return c == '\r' || c == '\n';
}
-static CURLcode add_certs_to_store(HCERTSTORE trust_store,
- const char *ca_file,
- struct Curl_easy *data)
+/* Search the substring needle,needlelen into string haystack,haystacklen
+ * Strings don't need to be terminated by a '\0'.
+ * Similar of OSX/Linux memmem (not available on Visual Studio).
+ * Return position of beginning of first occurence or NULL if not found
+ */
+static const char *c_memmem(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen)
+{
+ const char *p;
+ char first;
+ const char *str_limit = (const char *)haystack + haystacklen;
+ if(!needlelen || needlelen > haystacklen)
+ return NULL;
+ first = *(const char *)needle;
+ for(p = (const char *)haystack; p <= (str_limit - needlelen); p++)
+ if(((*p) == first) && (memcmp(p, needle, needlelen) == 0))
+ return p;
+
+ return NULL;
+}
+
+static CURLcode add_certs_data_to_store(HCERTSTORE trust_store,
+ const char *ca_buffer,
+ size_t ca_buffer_size,
+ const char *ca_file_text,
+ struct Curl_easy *data)
+{
+ const size_t begin_cert_len = strlen(BEGIN_CERT);
+ const size_t end_cert_len = strlen(END_CERT);
+ CURLcode result = CURLE_OK;
+ int num_certs = 0;
+ bool more_certs = 1;
+ const char *current_ca_file_ptr = ca_buffer;
+ const char *ca_buffer_limit = ca_buffer + ca_buffer_size;
+
+ while(more_certs && (current_ca_file_ptr<ca_buffer_limit)) {
+ const char *begin_cert_ptr = c_memmem(current_ca_file_ptr,
+ ca_buffer_limit-current_ca_file_ptr,
+ BEGIN_CERT,
+ begin_cert_len);
+ if(!begin_cert_ptr || !is_cr_or_lf(begin_cert_ptr[begin_cert_len])) {
+ more_certs = 0;
+ }
+ else {
+ const char *end_cert_ptr = c_memmem(begin_cert_ptr,
+ ca_buffer_limit-begin_cert_ptr,
+ END_CERT,
+ end_cert_len);
+ if(!end_cert_ptr) {
+ failf(data,
+ "schannel: CA file '%s' is not correctly formatted",
+ ca_file_text);
+ result = CURLE_SSL_CACERT_BADFILE;
+ more_certs = 0;
+ }
+ else {
+ CERT_BLOB cert_blob;
+ CERT_CONTEXT *cert_context = NULL;
+ BOOL add_cert_result = FALSE;
+ DWORD actual_content_type = 0;
+ DWORD cert_size = (DWORD)
+ ((end_cert_ptr + end_cert_len) - begin_cert_ptr);
+
+ cert_blob.pbData = (BYTE *)begin_cert_ptr;
+ cert_blob.cbData = cert_size;
+ if(!CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
+ &cert_blob,
+ CERT_QUERY_CONTENT_FLAG_CERT,
+ CERT_QUERY_FORMAT_FLAG_ALL,
+ 0,
+ NULL,
+ &actual_content_type,
+ NULL,
+ NULL,
+ NULL,
+ (const void **)&cert_context)) {
+ char buffer[STRERROR_LEN];
+ failf(data,
+ "schannel: failed to extract certificate from CA file "
+ "'%s': %s",
+ ca_file_text,
+ Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ result = CURLE_SSL_CACERT_BADFILE;
+ more_certs = 0;
+ }
+ else {
+ current_ca_file_ptr = begin_cert_ptr + cert_size;
+
+ /* Sanity check that the cert_context object is the right type */
+ if(CERT_QUERY_CONTENT_CERT != actual_content_type) {
+ failf(data,
+ "schannel: unexpected content type '%d' when extracting "
+ "certificate from CA file '%s'",
+ actual_content_type, ca_file_text);
+ result = CURLE_SSL_CACERT_BADFILE;
+ more_certs = 0;
+ }
+ else {
+ add_cert_result =
+ CertAddCertificateContextToStore(trust_store,
+ cert_context,
+ CERT_STORE_ADD_ALWAYS,
+ NULL);
+ CertFreeCertificateContext(cert_context);
+ if(!add_cert_result) {
+ char buffer[STRERROR_LEN];
+ failf(data,
+ "schannel: failed to add certificate from CA file '%s' "
+ "to certificate store: %s",
+ ca_file_text,
+ Curl_winapi_strerror(GetLastError(), buffer,
+ sizeof(buffer)));
+ result = CURLE_SSL_CACERT_BADFILE;
+ more_certs = 0;
+ }
+ else {
+ num_certs++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(result == CURLE_OK) {
+ if(!num_certs) {
+ infof(data,
+ "schannel: did not add any certificates from CA file '%s'\n",
+ ca_file_text);
+ }
+ else {
+ infof(data,
+ "schannel: added %d certificate(s) from CA file '%s'\n",
+ num_certs, ca_file_text);
+ }
+ }
+ return result;
+}
+
+static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
+ const char *ca_file,
+ struct Curl_easy *data)
{
CURLcode result;
HANDLE ca_file_handle = INVALID_HANDLE_VALUE;
LARGE_INTEGER file_size;
char *ca_file_buffer = NULL;
- char *current_ca_file_ptr = NULL;
TCHAR *ca_file_tstr = NULL;
size_t ca_file_bufsize = 0;
DWORD total_bytes_read = 0;
- bool more_certs = 0;
- int num_certs = 0;
- size_t END_CERT_LEN;
ca_file_tstr = curlx_convert_UTF8_to_tchar((char *)ca_file);
if(!ca_file_tstr) {
@@ -181,106 +316,10 @@ static CURLcode add_certs_to_store(HCERTSTORE trust_store,
if(result != CURLE_OK) {
goto cleanup;
}
-
- END_CERT_LEN = strlen(END_CERT);
-
- more_certs = 1;
- current_ca_file_ptr = ca_file_buffer;
- while(more_certs && *current_ca_file_ptr != '\0') {
- char *begin_cert_ptr = strstr(current_ca_file_ptr, BEGIN_CERT);
- if(!begin_cert_ptr || !is_cr_or_lf(begin_cert_ptr[strlen(BEGIN_CERT)])) {
- more_certs = 0;
- }
- else {
- char *end_cert_ptr = strstr(begin_cert_ptr, END_CERT);
- if(!end_cert_ptr) {
- failf(data,
- "schannel: CA file '%s' is not correctly formatted",
- ca_file);
- result = CURLE_SSL_CACERT_BADFILE;
- more_certs = 0;
- }
- else {
- CERT_BLOB cert_blob;
- CERT_CONTEXT *cert_context = NULL;
- BOOL add_cert_result = FALSE;
- DWORD actual_content_type = 0;
- DWORD cert_size = (DWORD)
- ((end_cert_ptr + END_CERT_LEN) - begin_cert_ptr);
-
- cert_blob.pbData = (BYTE *)begin_cert_ptr;
- cert_blob.cbData = cert_size;
- if(!CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
- &cert_blob,
- CERT_QUERY_CONTENT_FLAG_CERT,
- CERT_QUERY_FORMAT_FLAG_ALL,
- 0,
- NULL,
- &actual_content_type,
- NULL,
- NULL,
- NULL,
- (const void **)&cert_context)) {
- char buffer[STRERROR_LEN];
- failf(data,
- "schannel: failed to extract certificate from CA file "
- "'%s': %s",
- ca_file,
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
- result = CURLE_SSL_CACERT_BADFILE;
- more_certs = 0;
- }
- else {
- current_ca_file_ptr = begin_cert_ptr + cert_size;
-
- /* Sanity check that the cert_context object is the right type */
- if(CERT_QUERY_CONTENT_CERT != actual_content_type) {
- failf(data,
- "schannel: unexpected content type '%d' when extracting "
- "certificate from CA file '%s'",
- actual_content_type, ca_file);
- result = CURLE_SSL_CACERT_BADFILE;
- more_certs = 0;
- }
- else {
- add_cert_result =
- CertAddCertificateContextToStore(trust_store,
- cert_context,
- CERT_STORE_ADD_ALWAYS,
- NULL);
- CertFreeCertificateContext(cert_context);
- if(!add_cert_result) {
- char buffer[STRERROR_LEN];
- failf(data,
- "schannel: failed to add certificate from CA file '%s' "
- "to certificate store: %s",
- ca_file,
- Curl_winapi_strerror(GetLastError(), buffer,
- sizeof(buffer)));
- result = CURLE_SSL_CACERT_BADFILE;
- more_certs = 0;
- }
- else {
- num_certs++;
- }
- }
- }
- }
- }
- }
-
- if(result == CURLE_OK) {
- if(!num_certs) {
- infof(data,
- "schannel: did not add any certificates from CA file '%s'\n",
- ca_file);
- }
- else {
- infof(data,
- "schannel: added %d certificate(s) from CA file '%s'\n",
- num_certs, ca_file);
- }
- }
+ result = add_certs_data_to_store(trust_store,
+ ca_file_buffer, ca_file_bufsize,
+ ca_file,
+ data);
cleanup:
if(ca_file_handle != INVALID_HANDLE_VALUE) {
@@ -389,7 +428,7 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
if(entry->dwAltNameChoice != CERT_ALT_NAME_DNS_NAME) {
continue;
}
- if(entry->pwszDNSName == NULL) {
+ if(!entry->pwszDNSName) {
infof(data, "schannel: Empty DNS name.");
continue;
}
@@ -536,27 +575,22 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
const CERT_CHAIN_CONTEXT *pChainContext = NULL;
HCERTCHAINENGINE cert_chain_engine = NULL;
HCERTSTORE trust_store = NULL;
-#ifndef CURL_DISABLE_PROXY
- const char * const conn_hostname = SSL_IS_PROXY() ?
- conn->http_proxy.host.name :
- conn->host.name;
-#else
- const char * const conn_hostname = conn->host.name;
-#endif
+ const char * const conn_hostname = SSL_HOST_NAME();
sspi_status =
s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
&pCertContextServer);
- if((sspi_status != SEC_E_OK) || (pCertContextServer == NULL)) {
+ if((sspi_status != SEC_E_OK) || !pCertContextServer) {
char buffer[STRERROR_LEN];
failf(data, "schannel: Failed to read remote certificate context: %s",
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
result = CURLE_PEER_FAILED_VERIFICATION;
}
- if(result == CURLE_OK && SSL_CONN_CONFIG(CAfile) &&
+ if(result == CURLE_OK &&
+ (SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) &&
BACKEND->use_manual_cred_validation) {
/*
* Create a chain engine that uses the certificates in the CA file as
@@ -582,8 +616,19 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
result = CURLE_SSL_CACERT_BADFILE;
}
else {
- result = add_certs_to_store(trust_store, SSL_CONN_CONFIG(CAfile),
- data);
+ const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
+ if(ca_info_blob) {
+ result = add_certs_data_to_store(trust_store,
+ (const char *)ca_info_blob->data,
+ ca_info_blob->len,
+ "(memory blob)",
+ data);
+ }
+ else {
+ result = add_certs_file_to_store(trust_store,
+ SSL_CONN_CONFIG(CAfile),
+ data);
+ }
}
}
@@ -624,7 +669,7 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
NULL,
pCertContextServer->hCertStore,
&ChainPara,
- (data->set.ssl.no_revoke ? 0 :
+ (SSL_SET_OPTION(no_revoke) ? 0 :
CERT_CHAIN_REVOCATION_CHECK_CHAIN),
NULL,
&pChainContext)) {