summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/vtls/schannel_verify.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/vtls/schannel_verify.c')
-rw-r--r--libs/libcurl/src/vtls/schannel_verify.c166
1 files changed, 124 insertions, 42 deletions
diff --git a/libs/libcurl/src/vtls/schannel_verify.c b/libs/libcurl/src/vtls/schannel_verify.c
index ee960ed2c5..b4d7241790 100644
--- a/libs/libcurl/src/vtls/schannel_verify.c
+++ b/libs/libcurl/src/vtls/schannel_verify.c
@@ -29,7 +29,7 @@
* only be invoked by code in schannel.c.
*/
-#include "curl_setup.h"
+#include "../curl_setup.h"
#ifdef USE_SCHANNEL
#ifndef USE_WINDOWS_SSPI
@@ -39,24 +39,41 @@
#include "schannel.h"
#include "schannel_int.h"
-#include "inet_pton.h"
+#include "../curlx/inet_pton.h"
#include "vtls.h"
#include "vtls_int.h"
-#include "sendf.h"
-#include "strerror.h"
-#include "curl_multibyte.h"
-#include "curl_printf.h"
+#include "../sendf.h"
+#include "../strerror.h"
+#include "../curlx/winapi.h"
+#include "../curlx/multibyte.h"
+#include "../curl_printf.h"
#include "hostcheck.h"
-#include "version_win32.h"
+#include "../curlx/version_win32.h"
/* The last #include file should be: */
-#include "curl_memory.h"
-#include "memdebug.h"
+#include "../curl_memory.h"
+#include "../memdebug.h"
#define BACKEND ((struct schannel_ssl_backend_data *)connssl->backend)
#ifdef HAS_MANUAL_VERIFY_API
+#ifdef __MINGW32CE__
+#define CERT_QUERY_OBJECT_BLOB 0x00000002
+#define CERT_QUERY_CONTENT_CERT 1
+#define CERT_QUERY_CONTENT_FLAG_CERT (1 << CERT_QUERY_CONTENT_CERT)
+#define CERT_QUERY_FORMAT_BINARY 1
+#define CERT_QUERY_FORMAT_BASE64_ENCODED 2
+#define CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED 3
+#define CERT_QUERY_FORMAT_FLAG_ALL \
+ (1 << CERT_QUERY_FORMAT_BINARY) | \
+ (1 << CERT_QUERY_FORMAT_BASE64_ENCODED) | \
+ (1 << CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED)
+#define CERT_CHAIN_REVOCATION_CHECK_CHAIN 0x20000000
+#define CERT_NAME_DISABLE_IE4_UTF8_FLAG 0x00010000
+#define CERT_TRUST_IS_OFFLINE_REVOCATION 0x01000000
+#endif /* __MINGW32CE__ */
+
#define MAX_CAFILE_SIZE 1048576 /* 1 MiB */
#define BEGIN_CERT "-----BEGIN CERTIFICATE-----"
#define END_CERT "\n-----END CERTIFICATE-----"
@@ -76,6 +93,7 @@ struct cert_chain_engine_config_win7 {
HCERTSTORE hExclusiveTrustedPeople;
};
+#ifndef UNDER_CE
static int is_cr_or_lf(char c)
{
return c == '\r' || c == '\n';
@@ -138,13 +156,13 @@ static CURLcode add_certs_data_to_store(HCERTSTORE trust_store,
}
else {
CERT_BLOB cert_blob;
- CERT_CONTEXT *cert_context = NULL;
+ const 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.pbData = (BYTE *)CURL_UNCONST(begin_cert_ptr);
cert_blob.cbData = cert_size;
if(!CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
&cert_blob,
@@ -157,12 +175,12 @@ static CURLcode add_certs_data_to_store(HCERTSTORE trust_store,
NULL,
NULL,
(const void **)&cert_context)) {
- char buffer[STRERROR_LEN];
+ char buffer[WINAPI_ERROR_LEN];
failf(data,
"schannel: failed to extract certificate from CA file "
"'%s': %s",
ca_file_text,
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
more_certs = 0;
}
@@ -186,13 +204,13 @@ static CURLcode add_certs_data_to_store(HCERTSTORE trust_store,
NULL);
CertFreeCertificateContext(cert_context);
if(!add_cert_result) {
- char buffer[STRERROR_LEN];
+ char buffer[WINAPI_ERROR_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)));
+ curlx_winapi_strerror(GetLastError(), buffer,
+ sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
more_certs = 0;
}
@@ -232,13 +250,13 @@ static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
size_t ca_file_bufsize = 0;
DWORD total_bytes_read = 0;
- ca_file_tstr = curlx_convert_UTF8_to_tchar((char *)ca_file);
+ ca_file_tstr = curlx_convert_UTF8_to_tchar(ca_file);
if(!ca_file_tstr) {
- char buffer[STRERROR_LEN];
+ char buffer[WINAPI_ERROR_LEN];
failf(data,
"schannel: invalid path name for CA file '%s': %s",
ca_file,
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
@@ -256,21 +274,21 @@ static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(ca_file_handle == INVALID_HANDLE_VALUE) {
- char buffer[STRERROR_LEN];
+ char buffer[WINAPI_ERROR_LEN];
failf(data,
"schannel: failed to open CA file '%s': %s",
ca_file,
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
if(!GetFileSizeEx(ca_file_handle, &file_size)) {
- char buffer[STRERROR_LEN];
+ char buffer[WINAPI_ERROR_LEN];
failf(data,
"schannel: failed to determine size of CA file '%s': %s",
ca_file,
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
@@ -296,11 +314,11 @@ static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
if(!ReadFile(ca_file_handle, ca_file_buffer + total_bytes_read,
bytes_to_read, &bytes_read, NULL)) {
- char buffer[STRERROR_LEN];
+ char buffer[WINAPI_ERROR_LEN];
failf(data,
"schannel: failed to read from CA file '%s': %s",
ca_file,
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
@@ -313,7 +331,7 @@ static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
}
}
- /* Null terminate the buffer */
+ /* null-terminate the buffer */
ca_file_buffer[ca_file_bufsize] = '\0';
result = add_certs_data_to_store(trust_store,
@@ -330,9 +348,11 @@ cleanup:
return result;
}
+#endif
#endif /* HAS_MANUAL_VERIFY_API */
+#ifndef UNDER_CE
/*
* Returns the number of characters necessary to populate all the host_names.
* If host_names is not NULL, populate it with all the hostnames. Each string
@@ -380,6 +400,9 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
(void)Win8_compat;
#endif
+ if(!alt_name_info)
+ return 0;
+
compute_content = host_names != NULL && length != 0;
/* Initialize default return values. */
@@ -442,14 +465,14 @@ static bool get_num_host_info(struct num_ip_data *ip_blob,
struct in6_addr ia6;
bool result = FALSE;
- int res = Curl_inet_pton(AF_INET, hostname, &ia);
+ int res = curlx_inet_pton(AF_INET, hostname, &ia);
if(res) {
ip_blob->size = sizeof(struct in_addr);
memcpy(&ip_blob->bData.ia, &ia, sizeof(struct in_addr));
result = TRUE;
}
else {
- res = Curl_inet_pton(AF_INET6, hostname, &ia6);
+ res = curlx_inet_pton(AF_INET6, hostname, &ia6);
if(res) {
ip_blob->size = sizeof(struct in6_addr);
memcpy(&ip_blob->bData.ia6, &ia6, sizeof(struct in6_addr));
@@ -511,15 +534,68 @@ static bool get_alt_name_info(struct Curl_easy *data,
#endif
return result;
}
+#endif /* !UNDER_CE */
/* Verify the server's hostname */
CURLcode Curl_verify_host(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = cf->ctx;
- SECURITY_STATUS sspi_status;
CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
+ struct ssl_connect_data *connssl = cf->ctx;
CERT_CONTEXT *pCertContextServer = NULL;
+#ifdef UNDER_CE
+ TCHAR cert_hostname_buff[256];
+ DWORD len;
+
+ /* This code does not support certificates with multiple alternative names.
+ * Right now we are only asking for the first preferred alternative name.
+ * Instead we would need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG
+ * (If Windows CE supports that?) and run this section in a loop for each.
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx
+ * curl: (51) schannel: CertGetNameString() certificate hostname
+ * (.google.com) did not match connection (google.com)
+ */
+ len = CertGetNameString(pCertContextServer,
+ CERT_NAME_DNS_TYPE,
+ CERT_NAME_DISABLE_IE4_UTF8_FLAG,
+ NULL,
+ cert_hostname_buff,
+ 256);
+ if(len > 0) {
+ /* Comparing the cert name and the connection hostname encoded as UTF-8
+ * is acceptable since both values are assumed to use ASCII
+ * (or some equivalent) encoding
+ */
+ char *cert_hostname = curlx_convert_tchar_to_UTF8(cert_hostname_buff);
+ if(!cert_hostname) {
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else{
+ const char *conn_hostname = connssl->peer.hostname;
+ if(Curl_cert_hostcheck(cert_hostname, strlen(cert_hostname),
+ conn_hostname, strlen(conn_hostname))) {
+ infof(data,
+ "schannel: connection hostname (%s) validated "
+ "against certificate name (%s)\n",
+ conn_hostname, cert_hostname);
+ result = CURLE_OK;
+ }
+ else{
+ failf(data,
+ "schannel: connection hostname (%s) "
+ "does not match certificate name (%s)",
+ conn_hostname, cert_hostname);
+ }
+ Curl_safefree(cert_hostname);
+ }
+ }
+ else {
+ failf(data,
+ "schannel: CertGetNameString did not provide any "
+ "certificate name information");
+ }
+#else
+ SECURITY_STATUS sspi_status;
TCHAR *cert_hostname_buff = NULL;
size_t cert_hostname_buff_index = 0;
const char *conn_hostname = connssl->peer.hostname;
@@ -539,7 +615,7 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf,
&pCertContextServer);
if((sspi_status != SEC_E_OK) || !pCertContextServer) {
- char buffer[STRERROR_LEN];
+ char buffer[WINAPI_ERROR_LEN];
failf(data, "schannel: Failed to read remote certificate context: %s",
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
goto cleanup;
@@ -554,7 +630,7 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf,
}
}
- if(p->size) {
+ if(p->size && alt_name_info) {
for(i = 0; i < alt_name_info->cAltEntry; ++i) {
PCERT_ALT_NAME_ENTRY entry = &alt_name_info->rgAltEntry[i];
if(entry->dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS) {
@@ -571,7 +647,6 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf,
}
}
}
-
else {
/* Determine the size of the string needed for the cert hostname */
len = cert_get_name_string(data, pCertContextServer,
@@ -665,6 +740,7 @@ cleanup:
if(pCertContextServer)
CertFreeCertificateContext(pCertContextServer);
+#endif /* !UNDER_CE */
return result;
}
@@ -682,23 +758,26 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
CERT_CONTEXT *pCertContextServer = NULL;
const CERT_CHAIN_CONTEXT *pChainContext = NULL;
HCERTCHAINENGINE cert_chain_engine = NULL;
+#ifndef UNDER_CE
HCERTSTORE trust_store = NULL;
HCERTSTORE own_trust_store = NULL;
+#endif /* !UNDER_CE */
DEBUGASSERT(BACKEND);
sspi_status =
Curl_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
- SECPKG_ATTR_REMOTE_CERT_CONTEXT,
- &pCertContextServer);
+ SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+ &pCertContextServer);
if((sspi_status != SEC_E_OK) || !pCertContextServer) {
- char buffer[STRERROR_LEN];
+ char buffer[WINAPI_ERROR_LEN];
failf(data, "schannel: Failed to read remote certificate context: %s",
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
result = CURLE_PEER_FAILED_VERIFICATION;
}
+#ifndef UNDER_CE
if(result == CURLE_OK &&
(conn_config->CAfile || conn_config->ca_info_blob) &&
BACKEND->use_manual_cred_validation) {
@@ -728,9 +807,9 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
CERT_STORE_CREATE_NEW_FLAG,
NULL);
if(!trust_store) {
- char buffer[STRERROR_LEN];
+ char buffer[WINAPI_ERROR_LEN];
failf(data, "schannel: failed to create certificate store: %s",
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
}
else {
@@ -775,14 +854,15 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
CertCreateCertificateChainEngine(
(CERT_CHAIN_ENGINE_CONFIG *)&engine_config, &cert_chain_engine);
if(!create_engine_result) {
- char buffer[STRERROR_LEN];
+ char buffer[WINAPI_ERROR_LEN];
failf(data,
"schannel: failed to create certificate chain engine: %s",
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
}
}
}
+#endif /* !UNDER_CE */
if(result == CURLE_OK) {
CERT_CHAIN_PARA ChainPara;
@@ -799,9 +879,9 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
CERT_CHAIN_REVOCATION_CHECK_CHAIN),
NULL,
&pChainContext)) {
- char buffer[STRERROR_LEN];
+ char buffer[WINAPI_ERROR_LEN];
failf(data, "schannel: CertGetCertificateChain failed: %s",
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
pChainContext = NULL;
result = CURLE_PEER_FAILED_VERIFICATION;
}
@@ -849,6 +929,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
}
}
+#ifndef UNDER_CE
if(cert_chain_engine) {
CertFreeCertificateChainEngine(cert_chain_engine);
}
@@ -856,6 +937,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
if(own_trust_store) {
CertCloseStore(own_trust_store, 0);
}
+#endif /* !UNDER_CE */
if(pChainContext)
CertFreeCertificateChain(pChainContext);